Base URL
POST /cards, GET /wallets) are relative to this base URL. The full URL for POST /cards is therefore https://api.cartevo.co/api/v1/cards.
The same base URL serves both preproduction and production. Which environment you reach is determined by the credentials (client_id / client_key) you use to obtain your access token. See Environments.
Authentication
Every endpoint exceptPOST /auth/token requires a Bearer access token in the Authorization header:
POST /auth/token and expire after 1 hour. There is no refresh token endpoint — when a token expires, call POST /auth/token again.
Tokens are scoped to one company in one mode (preproduction or production). Treat them as secrets: never expose them to browsers, mobile apps, or anything client-side.
Request encoding
| Endpoint type | Encoding |
|---|---|
| All endpoints by default | application/json (UTF-8) |
POST /customers (file upload variant) | multipart/form-data |
Content-Type: application/json header.
Response envelope
Successful responses are wrapped in a standard envelope:meta object:
| Field | Type | Description |
|---|---|---|
success | boolean | true for any 2xx response |
statusCode | integer | The HTTP status code, repeated in the body for client convenience |
message | string | Human-readable status message. May be localized (English or French) |
data | any | Endpoint-specific payload. null for endpoints that return no body |
meta | object | Present only on paginated responses |
/auth/login, /auth/logout, /auth/verify-otp, /auth/forgot-password, /auth/reset-password) and POST /company/register/* — return raw responses without this envelope. Each affected endpoint flags this on its own reference page.
Field naming convention
All request bodies, query parameters, and response payloads usesnake_case (e.g. customer_id, phone_number, created_at).
A small number of legacy webhook event payloads still emit a few camelCase keys (e.g. cardId, transactionId); each affected webhook event flags this in its field table. New endpoints and webhook events will always use snake_case.
Money
- Amounts are sent and returned as JSON numbers in the major currency unit (e.g.
100.50USD = one hundred dollars and fifty cents). Cartevo does not use minor units (cents). - Currencies are identified by ISO 4217 codes:
USD,XAF,XOF,CDF,GNF. - Wherever an
amountfield appears, an accompanyingcurrencyfield describes the unit. - For collections and payouts, the
currencyyou provide must match the currency of the wallet associated with that country.
Dates and times
All timestamps are returned as ISO 8601 strings in UTC, including milliseconds:date_of_birth) use YYYY-MM-DD.
Date-range query parameters (from_date, to_date) accept either format; if you omit the time, midnight UTC is assumed.
Phone numbers
Phone numbers are sent and returned in E.164 format with a leading+:
country_phone_code (digits only, e.g. 237) and the local number as phone_number. The reference pages for those endpoints show worked examples per country.
Pagination
List endpoints accept two query parameters:| Parameter | Type | Default | Max | Description |
|---|---|---|---|---|
page | integer | 1 | — | 1-indexed page number |
limit | integer | 10 | 100 | Number of items per page |
meta block with page, limit, total, and totalPages.
Inconsistency to be aware of:GET /wallet/transactions(the unfiltered listing) currently useslimit/offsetinstead ofpage/limit. This is being aligned with the rest of the API.
Idempotency
Mutating endpoints accept an idempotency key on a per-endpoint basis:- Payments (
POST /payment/collect,POST /payment/payout): supply a uniqueexternal_idin the request body. Replays with the sameexternal_idare rejected with400(after the first call succeeds, subsequent calls return the original transaction in the response). - Card actions (
POST /cards,POST /cards/{id}/fund,POST /cards/{id}/withdraw): no idempotency key is supported today. Implement your own deduplication keyed on the responseid.
external_id (or the resulting transaction_id) in your own database before making the call, so that if the network drops you can safely retry with the same key.
Webhooks vs. polling
Most asynchronous outcomes (card funding settlement, payment collection result, cross-border charges, fee debits) are delivered to your server as webhooks. See the Webhooks reference for the full event catalogue, payload shapes, retry policy, and security guidance. If you cannot receive webhooks, you can poll status endpoints (e.g.GET /payment/transactions/{transactionId}/status) instead. Recommended cadence: poll at most once every 5 seconds, with exponential backoff after the first 30 seconds.
Errors
Error responses use a flat shape (they are not wrapped in the success envelope):error_code, details) — see the per-endpoint reference for specifics.
HTTP status codes
| Code | Meaning |
|---|---|
200 | Request succeeded |
201 | Resource created |
400 | Validation error or business-rule violation (e.g. insufficient balance, duplicate external_id) |
401 | Missing, invalid, or expired Bearer token; or invalid client_id/client_key |
403 | Authenticated but not authorized for this resource (e.g. wrong company) |
404 | Resource not found |
409 | Conflict (e.g. customer already exists with that email) |
422 | Upstream provider rejected the request (KYC failure, operator unavailable) |
429 | Rate limit exceeded — see Rate limits |
500 | Server error — safe to retry with exponential backoff |
Recommended client behavior
| Status | Retry? | Action |
|---|---|---|
2xx | n/a | Continue |
400 | No | Fix the request — do not retry as-is |
401 | Once | Refresh the access token, then retry |
403 | No | Verify the resource belongs to your company |
404 | No | Verify the ID |
409 | No | The resource already exists — fetch it instead |
422 | Maybe | Inspect message; some upstream errors are transient |
429 | Yes | Wait, then retry with exponential backoff (start at 1s) |
5xx | Yes | Retry with exponential backoff (start at 1s, max 60s, cap 5 retries) |
Rate limits
By default, Cartevo applies a per-IP rate limit of 10 requests per 60 seconds across the whole API surface. Custom limits can be agreed on a per-account basis — contact support if your integration needs a higher allowance. When you exceed the limit, the API returns429 Too Many Requests. Back off and retry; the limit window is sliding, so waiting ~60 seconds restores full quota.
IDs
| ID type | Format | Where it comes from |
|---|---|---|
| Cartevo internal IDs (customer, card, wallet, transaction) | UUID v4 | Returned by Cartevo on resource creation |
external_id (payment idempotency key) | Any string ≤ 255 chars | Supplied by you |
| Provider reference (upstream operator) | Provider-defined | Returned in webhook payloads |
Modes (preproduction vs. production)
Each set of API credentials is bound to one mode:- Preproduction — limited wallet balances (max 50,000 XAF / ~80 USD), no real money movement, suitable for end-to-end testing.
- Production — real money, real KYC, no balance ceiling beyond your account configuration.
See also
- Environments — preproduction vs. production limits
- Authentication — how to obtain and use a Bearer token
- Webhooks — outbound event catalogue and signature verification
- Glossary — definitions of wallet, customer, transaction, etc.