Errors
Every error.code: its status, what it means, when it happens and how to fix it.
An error is about your request: the key, the shape, a missing upload, a file. Nothing is recorded. Anything about the consumer's code, phone or receipt is not an error; it is a 200 with a message_key (Outcomes).
{
"error": {
"code": "idempotency_key_required",
"message": "The Idempotency-Key header is required.",
"fix": "Mint one key per attempt in the browser (16 to 128 characters) and forward it unchanged.",
"docs_url": "https://<manager>/docs/errors#idempotency_key_required",
"request_id": "req_4f9a1c2b7d3e"
}
}Branch on code. message and fix are written for a developer, not for the consumer. field is present when one request field is at fault. docs_url points at the entry below. Quote request_id (also in the X-Request-Id header) when asking about a request.
All codes
- key_malformedHTTP 401
The API key is not in a recognised format.
When: The header is not
Bearer <key>, or the key is not in theutc_test_…/utc_live_…format.Fix: Keys start with utc_test_ or utc_live_. Check for truncation or whitespace.
Returned by: Every call.
Send the same request again: no, change the request first
- key_missingHTTP 401
No API key was sent.
When: No
Authorizationheader was sent.Fix: Send
Authorization: Bearer <key>from your server.Returned by: Every call.
Send the same request again: no, change the request first
- key_unknownHTTP 401
The API key is not recognised.
When: The key is well formed but is not one of ours.
Fix: Check the key was copied in full and belongs to this environment; ask ops for a new one if it was lost.
Returned by: Every call.
Send the same request again: no, change the request first
- key_wrong_environmentHTTP 401
A test key was used where a live key is required, or the reverse.
When: A live key was used on a deployment that is not production. Test keys work on every deployment, production included.
Fix: Use a utc_live_ key in production and a utc_test_ key everywhere else.
Returned by: Every call.
Send the same request again: no, change the request first
- session_expiredHTTP 401not yet returned
The agent session has expired.
When: A BA agent's session has expired. BA sessions arrive with the BA portal cutover.
Fix: Sign in again with the agent PIN; keep the typed submission and resend it with the same Idempotency-Key.
Returned by: No call yet.
Send the same request again: no, change the request first
- campaign_not_assignedHTTP 403not yet returned
This agent is not assigned to that campaign.
When: A BA agent named a campaign they are not assigned to. BA sessions arrive with the BA portal cutover.
Fix: Send a
UTC-Campaignheader naming one of the campaigns from GET /api/v1/agent/me.Returned by: No call yet.
Send the same request again: no, change the request first
- key_revokedHTTP 403
This API key has been revoked.
When: The key has been revoked.
Fix: Ask ops for a new key, or switch to the campaign's second live key.
Returned by: Every call.
Send the same request again: no, change the request first
- not_foundHTTP 404
No such record for this campaign.
When: The id is not a uuid, or names nothing in this key's campaign and environment. Also a
receipt_idthat does not exist, and a key whose campaign is not in the database.Fix: Check the id, and that it was created with a key for the same campaign and environment.
Returned by: Every call.
Send the same request again: no, change the request first
- idempotency_in_progressHTTP 409
A request with this Idempotency-Key is still being processed.
When: A receipt submission with this
Idempotency-Keyis still being processed. WaitRetry-Afterseconds. Past the time budget the stored pending submission is returned instead.Fix: Wait for the Retry-After seconds, then resend the same request or poll the submission.
Returned by:
POST /api/v1/submissionsSend the same request again: yes, it can succeed
- file_too_largeHTTP 413
The file is larger than the limit.
When:
size_bytesis over 5 MB, or the stored file is.Fix: Downsize the photo in the browser (longest side 2,000 px, JPEG) before uploading.
Returned by:
POST /api/v1/submissions,POST /api/v1/receiptsSend the same request again: no, change the request first
- file_wrong_typeHTTP 415
The file is not a JPEG, PNG or WebP image.
When: The stored file is not a JPEG, PNG or WebP. A wrong
content_typeon POST /api/v1/receipts is 422validation_failed; this is the file itself, found at submission.Fix: Send one of the
accepted_typesfrom the upload response.Returned by:
POST /api/v1/submissionsSend the same request again: no, change the request first
- campaign_mismatchHTTP 422
The UTC-Campaign header does not match the key's campaign.
When: A
UTC-Campaignheader names a campaign other than the key's.Fix: Omit the header when using a campaign key.
Returned by: Every call.
Send the same request again: no, change the request first
- consent_requiredHTTP 422
Consent must be true.
When:
consentis missing or nottrue.Fix: Collect the consumer's consent and send
consent: true.Returned by:
POST /api/v1/submissionsSend the same request again: no, change the request first
- idempotency_key_invalidHTTP 422
The Idempotency-Key must be 16 to 128 characters.
When: The
Idempotency-Keyis shorter than 16 or longer than 128 characters.Fix: Use a UUID or another random string of that length.
Returned by:
POST /api/v1/submissions,POST /api/v1/receiptsSend the same request again: no, change the request first
- idempotency_key_requiredHTTP 422
The Idempotency-Key header is required.
When: POST /api/v1/submissions was sent without an
Idempotency-Key.Fix: Mint one key per attempt in the browser (16 to 128 characters) and forward it unchanged.
Returned by:
POST /api/v1/submissionsSend the same request again: no, change the request first
- idempotency_key_reusedHTTP 422
This Idempotency-Key was already used with a different request body.
When: The
Idempotency-Keywas used before with a different body.Fix: Mint a new key for a new attempt; resend the same key only with the same body.
Returned by:
POST /api/v1/submissions,POST /api/v1/receiptsSend the same request again: no, change the request first
- phone_invalidHTTP 422
The phone number is not a valid Tanzanian mobile number.
When: The phone is not a Tanzanian mobile number. Validate in the form first; this is the caller's request, so no row is written.
Fix: Send +255XXXXXXXXX, 255XXXXXXXXX or 0XXXXXXXXX.
Returned by:
POST /api/v1/submissions,POST /api/v1/submissions/lookupSend the same request again: no, change the request first
- receipt_already_attachedHTTP 422
This receipt already belongs to another submission.
When: The receipt already belongs to a submission.
Fix: Create a new receipt for a new submission.
Returned by:
POST /api/v1/submissions,POST /api/v1/receipts/{id}/upload-urlSend the same request again: no, change the request first
- receipt_not_uploadedHTTP 422
The receipt photo has not been uploaded.
When: The receipt's photo is not in storage. After the PUT succeeds, with the same Idempotency-Key.
Fix: PUT the file to the upload URL, or request a fresh one with POST /api/v1/receipts/:id/upload-url.
Returned by:
POST /api/v1/submissionsSend the same request again: yes, it can succeed
- receipt_requiredHTTP 422
This campaign needs a receipt with every submission.
When: The campaign needs a receipt and the submission has no
receipt_id.Fix: Create one with POST /api/v1/receipts and send its id as
receipt_id.Returned by:
POST /api/v1/submissionsSend the same request again: no, change the request first
- sentinel_with_live_keyHTTP 422
A test sentinel was sent with a live key.
When: A
TEST-0-…code orTEST0…receipt was sent with a live key.Fix: Sentinel codes and receipts only work with utc_test_ keys.
Returned by:
POST /api/v1/codes/check,POST /api/v1/submissions,POST /api/v1/receiptsSend the same request again: no, change the request first
- typed_receipt_unsupportedHTTP 422
This campaign does not accept typed receipt codes.
When: A typed receipt was sent to a campaign that takes no receipts.
Fix: Check
capabilities.typed_receipton GET /api/v1/campaign.Returned by:
POST /api/v1/receiptsSend the same request again: no, change the request first
- validation_failedHTTP 422
The request body is not valid.
When: The body is not JSON, or a field is missing or has the wrong shape.
error.fieldnames the first problem. Also: nocodewhere the campaign needs one; a receipt for a campaign that takes none.Fix: See
fieldfor the first problem and the reference for the expected shape.Returned by:
POST /api/v1/codes/check,POST /api/v1/submissions,POST /api/v1/submissions/lookup,POST /api/v1/receipts,POST /api/v1/receipts/{id}/upload-urlSend the same request again: no, change the request first
- rate_limitedHTTP 429
Too many requests.
When: The key is over its requests-per-minute ceiling, or the lookup or code-check limit was reached. After
Retry-Afterseconds.Fix: Slow down and retry after the Retry-After seconds.
Returned by: Every call.
Send the same request again: yes, it can succeed
- internal_errorHTTP 500
Something went wrong on our side.
When: Something failed on our side. With the same Idempotency-Key. Quote the request id if it keeps failing.
Fix: Retry with the same Idempotency-Key, and quote the request id if it keeps failing.
Returned by: Every call.
Send the same request again: yes, it can succeed
26 codes.