Concepts
Conventions
Rules that apply to every endpoint.
Base URL and versioning
https://api.byteverseafrica.com/v1The version is in the path. Within /v1 we only make backwards-compatible changes: new endpoints, new optional fields and new event types. Ignore fields you do not recognise so additions never break you. Breaking changes ship as /v2 with plenty of notice.
Format
- Requests and responses are JSON (
Content-Type: application/json), UTF-8, up to 64 KB. - Money is in Nigerian naira (NGN) as whole numbers, e.g.
5250means ₦5,250. - Timestamps are ISO 8601 in UTC (
2026-10-22T09:14:03Z). Eventcreatedis Unix seconds. Report dates use Africa/Lagos. - IDs are opaque strings with a prefix:
cmp_campaigns,sub_submissions,evt_events,req_requests. - Every response includes
x-request-id. Quote it to support.
Idempotency
Networks fail. Idempotency keys make retries safe: send the same Idempotency-Key with the same request and you get the same result instead of a duplicate.
| Situation | Result |
|---|---|
| First request with a key | Processed normally. Success responses are stored for 24 hours. |
| Retry with the same key and body | The stored response is returned with Idempotent-Replayed: true. No second charge. |
| Same key, different body or path | 422 idempotency_key_reuse |
| Retry while the first is still running | 409 request_in_progress with Retry-After |
| First request failed (4xx/5xx) | The key is released, so you can fix the request and reuse it |
Use a fresh UUID per logical operation. Required on POST /v1/campaigns; optional on pause, resume and cancel.
Pagination
List endpoints are cursor-based and return newest first.
{
"object": "list",
"data": [
"..."
],
"has_more": true,
"next_cursor": "WyIyMDI2LTEwLTIyVDA5OjE0OjAzWiIsIjVlMGMuLi4iXQ"
}Pass limit (1-100, default 20) and, for the next page, starting_after=<next_cursor>. Stop when has_more is false. Cursors are opaque; do not parse them.
Rate limits
Each key gets 60 requests per minute by default (raisable on request). Every response includes:
| Header | Meaning |
|---|---|
X-RateLimit-Limit | Requests allowed per window |
X-RateLimit-Remaining | Requests left in this window |
X-RateLimit-Reset | Unix time the window resets |
Over the limit you get 429 rate_limited and a Retry-After header (seconds). Wait that long, then retry. Prefer webhooks to polling to stay well under the limit.
Which errors to retry
| Status | Retry? |
|---|---|
| 400, 401, 402, 403, 404, 409, 413, 415, 422 | No. Fix the request, the key, the balance or the state first. |
| 429 | Yes, after Retry-After. |
| 500, 502, 503, 504, network timeout | Yes, with exponential backoff and the same Idempotency-Key. |
