API documentation
The Isokan African platform API is a JSON HTTP API. Every request is authenticated with a developer API key created in the developer portal.
Manage my API keysAPI playground
Run live requests against the posts endpoint with your own key. Scope checks, rate limits and audit logging apply exactly as they do from your server.
Leave empty to see the exact 401 response an unauthenticated call returns.
Equivalent curl
curl "https://isokanafrican.com/api/public/v1/posts?limit=5" \ -H "Authorization: Bearer isokan_xxxxxxxx"
Base URLs
All endpoints are versioned under /api/public/v1.
Production: https://isokanafrican.com/api/public/v1
Mirror: https://isokanafrican.lovable.app/api/public/v1
Authorization
Send your key as a bearer token on every request. Keys are shown once at creation — store them securely on your server and never in client-side code.
Authorization: Bearer isokan_xxxxxxxxxxxxxxxxxxxxxxxx
A missing, unknown or disabled key returns 401 with { "error": "Invalid or inactive API Key" }.
Scopes
Each key carries one or more scopes.
Calling an endpoint without the required scope returns 403.
Rate limits
Limits are applied per API key.
Default allowance: 60 requests per minute per key.
Responses include x-ratelimit-limit and x-ratelimit-remaining. When the allowance is exhausted the API returns 429 with a retry-after header.
HTTP/1.1 429 Too Many Requests
retry-after: 60
{
"error": "Rate limit exceeded. This key allows 60 requests per minute.",
"retry_after_seconds": 60
}GET /posts
Scope: read · Query: limit (1–50, default 20)
curl "https://isokanafrican.com/api/public/v1/posts?limit=2" \ -H "Authorization: Bearer isokan_xxxxxxxx"
{
"message": "Posts fetched successfully",
"data": [
{
"id": "6f6c1f2e-...",
"content": "Unity is strength #Isokan",
"image_url": null,
"image_urls": [],
"video_url": null,
"created_at": "2026-08-09T10:12:31.000Z"
}
]
}POST /posts
Scope: write · Body: content (max 5000 chars)
curl -X POST "https://isokanafrican.com/api/public/v1/posts" \
-H "Authorization: Bearer isokan_xxxxxxxx" \
-H "Content-Type: application/json" \
-d '{"content":"Unity is strength #Isokan"}'HTTP/1.1 201 Created
{
"message": "Post created successfully",
"data": {
"id": "0b2b8f10-...",
"content": "Unity is strength #Isokan",
"created_at": "2026-08-09T10:14:02.000Z"
}
}GET /users/{id}
Scope: read · id is the user UUID
curl "https://isokanafrican.com/api/public/v1/users/00000000-0000-0000-0000-000000000000" \ -H "Authorization: Bearer isokan_xxxxxxxx"
{
"id": "00000000-0000-0000-0000-000000000000",
"username": "ade",
"name": "Ade Okafor",
"avatar_url": "https://...",
"bio": "Building in Lagos",
"followers": 128
}OAuth 2.0 for third-party apps
Use OAuth when your app acts on behalf of an Isokan African member instead of your own account. Authorization code flow with PKCE; refresh tokens rotate on use.
Register your application in the developer portal to get a client_id and a one-time client_secret, and declare your redirect URIs.
Discovery document: https://isokanafrican.com/.well-known/oauth-authorization-server
1. Send the member to the consent screen
https://isokanafrican.com/oauth/authorize ?client_id=YOUR_CLIENT_ID &redirect_uri=https://yourapp.com/callback &response_type=code &scope=read%20profile &state=RANDOM_STATE &code_challenge=BASE64URL_S256_OF_VERIFIER &code_challenge_method=S256
2. Exchange the code for tokens
curl -X POST "https://isokanafrican.com/api/public/v1/oauth/token" \
-H "Content-Type: application/json" \
-d '{
"grant_type": "authorization_code",
"code": "AUTH_CODE",
"client_id": "YOUR_CLIENT_ID",
"client_secret": "YOUR_CLIENT_SECRET",
"redirect_uri": "https://yourapp.com/callback",
"code_verifier": "ORIGINAL_VERIFIER"
}'{
"access_token": "isokat_xxxxxxxx",
"token_type": "Bearer",
"expires_in": 3600,
"refresh_token": "isokrt_xxxxxxxx",
"scope": "read profile"
}3. Call the API with the access token
curl "https://isokanafrican.com/api/public/v1/oauth/userinfo" \ -H "Authorization: Bearer isokat_xxxxxxxx"
Refresh and revoke
# refresh (old refresh token is invalidated)
curl -X POST "https://isokanafrican.com/api/public/v1/oauth/token" \
-H "Content-Type: application/json" \
-d '{"grant_type":"refresh_token","refresh_token":"isokrt_xxxxxxxx","client_id":"YOUR_CLIENT_ID","client_secret":"YOUR_CLIENT_SECRET"}'
# revoke
curl -X POST "https://isokanafrican.com/api/public/v1/oauth/revoke" \
-H "Content-Type: application/json" \
-d '{"token":"isokat_xxxxxxxx","client_id":"YOUR_CLIENT_ID","client_secret":"YOUR_CLIENT_SECRET"}'OAuth scopes: read, write, analytics and profile (basic account details). Members can revoke any connected app from Settings, which immediately invalidates its tokens.
Errors
Platform API errors always return the same envelope: a human-readable error plus a stable machine-readable code. Branch on code, never on the message text.
{
"error": "This credential does not have write permission",
"code": "insufficient_scope",
"required_scope": "write",
"granted_scopes": ["read"]
}400 invalid_request — malformed JSON or an invalid field (the offending field is returned as field).
401 invalid_token — missing, unknown, disabled or expired API key / OAuth access token.
403 insufficient_scope — the credential lacks the scope the endpoint requires.
404 not_found — the requested resource does not exist or is not public.
429 rate_limited — per-minute allowance exhausted; see retry_after_seconds and the retry-after header.
500 server_error — unexpected failure; safe to retry with backoff.
Common failures, verbatim
# no key at all
HTTP/1.1 401 Unauthorized
{
"error": "Invalid or inactive API key or access token. Send it as Authorization: Bearer <token> or x-api-key: <key>.",
"code": "invalid_token"
}
# empty or oversized content on POST /posts
HTTP/1.1 400 Bad Request
{ "error": "content is required and must be 1–5000 characters", "code": "invalid_request", "field": "content" }
# too many calls
HTTP/1.1 429 Too Many Requests
retry-after: 60
{ "error": "Rate limit exceeded. This credential allows 60 requests per minute.", "code": "rate_limited", "retry_after_seconds": 60 }OAuth error responses
The OAuth endpoints follow RFC 6749: an error code plus error_description.
400 invalid_request — a required parameter is missing.
400 invalid_grant — code or refresh token unknown, used, expired, revoked, issued to another client, redirect_uri mismatch, or PKCE verification failed.
400 unsupported_grant_type — only authorization_code and refresh_token are supported.
401 invalid_client — unknown client_id or wrong client_secret.
401 invalid_token — access token expired or revoked by the member.
403 insufficient_scope — the consent granted did not include the required scope.
HTTP/1.1 400 Bad Request
{ "error": "invalid_grant", "error_description": "PKCE verification failed" }
HTTP/1.1 401 Unauthorized
{ "error": "invalid_client", "error_description": "Unknown client_id" }
HTTP/1.1 403 Forbidden
{ "error": "insufficient_scope", "error_description": "This access token was not granted the profile scope.", "required": "profile" }