Appearance
API contract
Base URL: https://dtone.fluxr.co.za/api/v1. JSON field names use snake_case. Money charged to the vendor is in ZAR cents (charge_minor); decimal provider and destination values are strings. Credentials, wholesale breakdowns and other vendors' records are excluded from ordinary responses.
Successful responses:
json
{"success":true,"message":"OK","data":{}}Errors:
json
{"success":false,"message":"DAILY_CAP_EXCEEDED","error":{"code":"DAILY_CAP_EXCEEDED","remaining_minor":475}}Endpoints and abilities
| Method / endpoint | Ability | Purpose |
|---|---|---|
GET /services, /countries, /operators | catalogue:read | Discovery within your enabled products |
GET /products, /products/{id} | catalogue:read | Vendor prices, benefits and delivery requirements |
POST /lookups/mobile-number | lookups:read | Mobile operator discovery |
POST /lookups/statement | lookups:read | Bill inquiry |
POST /lookups/account, /lookups/esim-benefits | lookups:read | Remaining benefits |
POST /lookups/esim-status | lookups:read | Installation and activation dates |
POST /quotes | quotes:write | Five-minute immutable quote |
GET /quotes/{id} | quotes:write | Retrieve your immutable quote |
POST /transactions | transactions:write | Durable purchase acceptance; HTTP 202 |
GET /transactions | transactions:read | Your transactions |
GET /transactions/{id} | transactions:read | One transaction |
GET /transactions/by-reference/{reference} | transactions:read | Recover your original request |
GET /transactions/{id}/fulfilment | fulfilment:read | Encrypted delivery payload, restricted and audited |
GET /limits | limits:read | Provider-spend allowance and velocity settings |
GET /reports/summary | reports:read | Gross completed and reversed selling values |
Tokens are attached to the vendor, not the dashboard user. Token abilities must also remain enabled on the vendor. Dashboard sessions cannot authenticate as vendor API tokens. Token rotation never resets allowance.
GET /products accepts search, ISO3 country, operator_id, service_id, page and per_page (1–100). It returns items, page, total and last_page. Ranged products list the price at their minimum amount; always request a quote for the desired amount.
GET /transactions accepts status, exact reference, product_id, date_from, date_to, page and per_page. Dates use YYYY-MM-DD and include the full Africa/Johannesburg calendar day, filtered by admission time.
GET /reports/summary accepts date_from and date_to. Sales and reversals use the original verified completion date; pending and review counts use admission date. Reversals do not reopen daily allowance. Omitted dates leave that end of the period unbounded.
Quotes
json
{
"product_id": 101,
"destination_amount": "20",
"credit_party_identifier": {"mobile_number": "+27820000000"}
}For ranged products use either destination_amount or budget_minor. Fixed products do not need an amount. Required groups are discovered from the product: credit_party_identifier, debit_party_identifier, sender, beneficiary, statement_identifier, additional_identifier. Each nested array of provider requirements is an alternative complete field set.
A quote returns id, product_id, pricing_version_id, charge_minor, currency, destination_amount, destination_unit, benefits, unused_budget_minor, expires_at. Quotes never create provider transactions.
Purchase
Header: Idempotency-Key: platform-order-123
json
{"quote_id":"019…","reference":"platform-order-123"}Use a real UUID quote ID. References and keys allow letters, numbers, _, ., :, -, up to 128 characters. An exact replay returns the existing transaction even after a pause or quote expiry. Changing the quote, key or reference conflicts. A quote may fund only one transaction.
The response contains the gateway ID, reference, status, product ID, charge, currency, safe error code, timestamps and fulfilment_available.
Lookups
Mobile lookup requires only mobile_number; returned operators are restricted to the vendor's enabled catalogue. Other lookups require an enabled product_id to establish vendor catalogue scope. Statement inquiry needs account_number, with optional account_qualifier. Account/eSIM lookups use credit_party_identifier with an account or mobile number. Paginated lookups accept page and per_page (1–100).
Only statement and benefit/status information is returned. PINs and activation codes are never returned by these endpoints. Product/account-specific support must be verified during account acceptance.
Stable errors
| Code | HTTP | Client behaviour |
|---|---|---|
DAILY_CAP_EXCEEDED | 409 | Wait for allowance or contact staff |
TRANSACTION_MAXIMUM_EXCEEDED | 409 | Do not split automatically; contact staff |
PURCHASES_PAUSED | 409 | Continue polling existing purchases |
SPEND_CONTROLS_NOT_CONFIGURED | 409 | Staff setup required |
PRICING_UNPUBLISHED | 409 | Staff must publish pricing |
VELOCITY_LIMIT_EXCEEDED | 429 | Respect Retry-After |
API_RATE_LIMITED | 429 | General API throttle; reads and writes use separate buckets |
IDEMPOTENCY_CONFLICT, QUOTE_ALREADY_USED, QUOTE_EXPIRED | 409 | Recover the original request or quote again as appropriate |
VALIDATION_FAILED | 422 | Correct the reported field errors |
PRODUCT_UNAVAILABLE, DESTINATION_AMOUNT_INVALID, BUDGET_INSUFFICIENT | 422 | Refresh catalogue or change requested benefit |
PROVIDER_NOT_CONFIGURED, PROVIDER_HTTP_ERROR, PROVIDER_OUTCOME_UNKNOWN | 503 | Preserve the original reference; inspect status before any new request |
Unconfigured production credentials, infrastructure or account acceptance fail closed. Production release errors use HTTP 409.
Provider callback
DT One posts to /api/v1/provider/callback/{token}. Configure a random 64-character lowercase hexadecimal DTONE_CALLBACK_TOKEN and the HTTPS base callback URL without the token. The gateway appends the token when creating provider transactions. Keep the full URL out of logs. Invalid or missing tokens cannot schedule a provider lookup. Authenticated callbacks remain hints; only a provider GET can change transaction outcomes. A durable callback marker allows late reversal verification after the ordinary reversal watch has ended.

