API reference (Swagger)
Every endpoint with its request, responses and errors. Try requests right in the browser.
Postman collection
Download and import. Sign-in requests save the token, so the rest are authenticated.
OpenAPI 3 document
For code generators and API clients (Dart, Swift, Kotlin, TypeScript…).
Health
MySQL up 0.9 ms·Redis up 0.5 ms
Request logs
Recent requests with their body, response, SQL and timing. Look up a failing call by its X-Request-Id.
Background jobs
Queued and scheduled jobs (file cleanup and video posters now; ad expiry and notifications later), with failures and retries.
Base paths
| Path | Used by | Signs in with | Token |
|---|---|---|---|
/v1/user | Mobile app (guests, buyers and sellers: one account) | Mobile number + 4-digit SMS code | bk_usr_… |
/v1/admin | Control panelcoming soon | Email + password | bk_adm_… |
Send the token as Authorization: Bearer <token>. A token only works in its own app's path. Guests call public routes without one.
Test servers
Signing in
SMS is simulated on test servers: every number gets the code 1234. With SEED_DEMO_DATA=true, the demo build's two accounts are seeded: the seller 0559876543 and the buyer 0501234567. Or register any 05… number.
Nafath
The fake Nafath answers on its own after a few seconds, by the ID's last digit: 1 is declined, 2 doesn't match, 3 is never answered (it expires after 2 minutes), any other digit is approved, e.g. 1012345678.
Payments coming soon
Packages, boosts and contributions will use a fake gateway that can succeed, fail, cancel or stay pending, so every result screen can be tried.
Uploading files
Photos and videos upload first, one per request, as multipart/form-data to POST /v1/user/files?purpose=…; the ad then sends the returned ids, so the app can show progress and retry one file. The type is read from the file's bytes and each kind has its own limit: ad photos PNG or JPG up to 5 MB (10 per ad), or one ad video MP4 or MOV up to 20 MB, which gets a poster image. Forms without files are JSON.
Conventions
Language
Send Accept-Language: ar or en (or ?lang=). Arabic is the default; a signed-in account's saved language is used when the request names none.
Errors
Always { code, message, details?, requestId }. Branch on code; show message. details lists field problems with their own message.
Request IDs
Every response has an X-Request-Id header. Include it when reporting a problem.
Mobile numbers
Saudi numbers as typed (05…, 5…, +9665…, Arabic digits too); responses use +9665….
Dates
Times are ISO 8601 in UTC, for example 2026-10-07T09:30:00.000Z.
Lists
App lists scroll with { items, nextCursor }; control panel tables page with { items, page, limit, total }.
Error codes
All 37 codes with their HTTP status and English message
| Code | Status | Message |
|---|---|---|
VALIDATION_FAILED | 400 | The request data is invalid |
INVALID_JSON | 400 | The request body could not be read |
UNAUTHORIZED | 401 | Please log in to complete this action. |
FORBIDDEN | 403 | You don't have permission to do this |
ACCOUNT_DISABLED | 403 | This user is disabled, please contact the administration. |
NOT_FOUND | 404 | The requested item was not found |
CONFLICT | 409 | The request conflicts with existing data |
PAYLOAD_TOO_LARGE | 413 | The request is larger than allowed |
TOO_MANY_REQUESTS | 429 | Too many requests, please try again shortly |
MOBILE_NOT_REGISTERED | 404 | No account is registered with this number. Please make sure the mobile number is correct. |
MOBILE_ALREADY_REGISTERED | 409 | The mobile number is already in use, please verify the number. |
MOBILE_UNCHANGED | 400 | This is already your number |
ALREADY_VERIFIED | 409 | Your identity is already verified. |
IDENTITY_ALREADY_USED | 409 | This ID number has already verified another account. |
TOO_MANY_ATTEMPTS | 429 | Too many attempts. You can try again in {minutes} minutes. |
AD_ACTION_NOT_ALLOWED | 409 | You can't do this. |
AD_UNAVAILABLE | 410 | This ad is no longer available. |
ADVERTISER_UNAVAILABLE | 410 | This advertiser's page isn't available. |
ALREADY_REPORTED | 409 | You have already reported this ad. |
NO_CREDIT | 402 | You have used all your free ads for this month. Subscribe to a package to post more, or wait for next month. |
PACKAGE_EXPIRED | 402 | Your package has ended and this month's free ads are used up. Renew a package to post more, or wait for next month. |
REGION_NOT_AVAILABLE | 400 | This region is not available. Please choose another. |
CITY_NOT_AVAILABLE | 400 | This city is not available. Please choose another. |
NEIGHBORHOOD_NOT_AVAILABLE | 400 | This neighbourhood is not available. Please choose another. |
EMAIL_ALREADY_REGISTERED | 409 | This email is already in use. |
OTP_INVALID | 400 | The verification code is incorrect. |
OTP_EXPIRED | 400 | The verification code is invalid or expired. Please request a new one. |
OTP_TOO_MANY_ATTEMPTS | 429 | Too many incorrect attempts. Please request a new code. |
OTP_RESEND_TOO_SOON | 429 | You can request a new code in {seconds} seconds. |
VERIFICATION_INVALID | 400 | This verification is no longer valid. Please request a new code. |
SMS_SEND_FAILED | 503 | The verification code could not be sent. Please try again. |
EMAIL_SEND_FAILED | 503 | The verification code could not be sent to this email. Please try again. |
FILE_REQUIRED | 400 | No file was attached. |
FILE_TOO_LARGE | 413 | File size exceeds the allowed limit ({maxMb} MB). |
FILE_TYPE_NOT_ALLOWED | 415 | Unsupported file type. Allowed: {allowed} |
FILE_NOT_AVAILABLE | 400 | This file can't be used. Please upload it again. |
INTERNAL_ERROR | 500 | Something went wrong, please try again |