Concepts

Errors

One envelope, stable codes, and why a send failed.

{
  "error": {
    "type": "insufficient_credit",
    "code": "insufficient_credit",
    "message": "Not enough Jusa Credit: US$3.50 available.",
    "param": null,
    "doc_url": "https://jusa.localhost.co.zw/developers/docs/errors#insufficient_credit",
    "request_id": "req_4f0c…"
  }
}

Every error under /dev/v1 is this envelope. code is stable: a code always has the same HTTP status, and new codes only add. message is ours, written for a person; it never repeats a provider's words. param names the field at fault. Quote request_id to support. The SDKs raise one class per type.

Retry or not? A 429, a 5xx and 409 idempotency_in_progress can be retried with the same Idempotency-Key. A 4xx otherwise is the answer: change the request. A refusal before anything was written (almost every 4xx) charged nothing.

400 · The request is wrong

codetype
amount_out_of_rangeinvalid_request
attestation_requiredinvalid_request
bundle_not_foundinvalid_request
bundle_requiredinvalid_request
challenge_requiredinvalid_request
choice_not_allowedinvalid_request
code_invalidinvalid_request
code_requiredinvalid_request
idempotency_key_invalidinvalid_request
idempotency_key_requiredinvalid_request
invalid_api_versioninvalid_request
invalid_jsoninvalid_request
invalid_modeinvalid_request
invalid_requestinvalid_request
invalid_targetinvalid_request
location_too_impreciseinvalid_request
meter_blockedinvalid_request
meter_not_foundinvalid_request
network_mismatchinvalid_request
parameter_invalidinvalid_request
parameter_missinginvalid_request
parameter_unknowninvalid_request
product_unavailableinvalid_request
quote_expiredinvalid_request
quote_mismatchinvalid_request
referral_invalidinvalid_request
token_phone_requiredinvalid_request
topup_method_unavailableinvalid_request
url_invalidinvalid_request
url_not_allowedinvalid_request
url_not_httpsinvalid_request
webhook_endpoint_limitinvalid_request

401 · No key, or not a valid one

codetype
invalid_api_keyauthentication
invalid_signatureauthentication
legacy_signature_retiredauthentication
missing_api_keyauthentication
signature_expiredauthentication

402 · Not enough Jusa Credit

codetype
insufficient_creditinsufficient_credit

403 · Not allowed

codetype
account_frozenpermission
agent_live_mode_offpermission
approval_requiredpermission
approval_requires_another_personpermission
cap_exceededpermission
feature_not_enabledpermission
geofence_window_closedpermission
insufficient_scopepermission
ip_not_allowedpermission
key_controls_escalationpermission
key_controls_not_enforcedpermission
key_not_for_browserspermission
key_spend_cap_reachedpermission
live_mode_not_allowedpermission
live_mode_onlypermission
not_a_developer_orgpermission
not_allowed_for_agent_keyspermission
origin_not_allowedpermission
outside_geofencepermission
phone_not_allowedpermission
pin_not_setpermission
pin_requiredpermission
product_not_allowedpermission
recipient_blockedpermission
role_not_allowedpermission
sensitive_data_not_enabledpermission
source_not_allowedpermission
target_blockedpermission
terms_not_acceptedpermission
test_mode_onlypermission

404 · Not found

codetype
resource_missingnot_found
unknown_routenot_found

405 · Method not allowed

codetype
method_not_allowedinvalid_request

409 · The state does not allow it

codetype
activity_id_conflictconflict
already_cancelledconflict
already_memberconflict
already_referredconflict
already_rewardedconflict
already_sentconflict
approval_not_pendingconflict
batch_not_awaiting_approvalconflict
batch_not_cancellableconflict
batch_not_terminalconflict
blocklist_entry_existsconflict
checkin_requiredconflict
checkout_session_not_heldconflict
checkout_session_not_openconflict
client_reference_conflictconflict
completion_id_conflictconflict
conflictconflict
cost_center_takenconflict
dispute_existsconflict
erasure_deferredconflict
funding_mismatchconflict
group_in_useconflict
idempotency_in_progressidempotency
insufficient_program_fundsconflict
invite_existsconflict
invite_expiredconflict
key_inactiveconflict
last_ownerconflict
meter_not_editableconflict
name_takenconflict
no_geofenceconflict
nothing_to_advanceconflict
nothing_to_retryconflict
nothing_to_sendconflict
occurrence_already_firedconflict
occurrence_not_runnableconflict
program_cap_reachedconflict
program_closedconflict
program_exhaustedconflict
program_inactiveconflict
program_transition_invalidconflict
receipt_not_availableconflict
recipient_conflictconflict
recipient_erasedconflict
referral_not_configuredconflict
referral_not_pendingconflict
review_not_openconflict
reward_not_releasableconflict
reward_not_voidableconflict
schedule_inactiveconflict
send_delivered_lateconflict
send_not_disputableconflict
send_not_retryableconflict
send_transition_invalidconflict
token_not_availableconflict
webhook_endpoint_deletedconflict
webhook_endpoint_disabledconflict
webhook_endpoint_legacyconflict

415 · Not JSON

codetype
unsupported_media_typeinvalid_request

422 · Idempotency key reused with another body

codetype
idempotency_mismatchidempotency

423 · Locked

codetype
pin_lockedpermission

429 · Too many requests

codetype
lookup_quota_exceededrate_limit
otp_limitedrate_limit
rate_limitedrate_limit
token_resend_limitedrate_limit

500 · Our fault

codetype
internal_errorapi_error

501 · Not available yet

codetype
not_yet_availableinvalid_request

503 · A provider cannot answer, or live sends are paused

codetype
live_api_disabledapi_error
live_dispatch_disabledapi_error
provider_capacity_exceededprovider_unavailable
provider_unavailableprovider_unavailable
zesa_unavailableprovider_unavailable

Why a send failed: failure_code

A send, reward or batch line that did not go through says why in failure_code, with our words for it in failure_message. These are states of an object, not errors of a request.

failure_codeMeans
amount_out_of_rangeThe amount is outside the product's range.
cancelledThe send was cancelled before it went out.
insufficient_creditThere was not enough Jusa Credit.
invalid_targetThe number or account is not valid for this product.
meter_blockedThis meter is blocked or inactive at ZESA.
meter_not_foundZESA does not recognise this meter number.
network_mismatchThe number belongs to a different network from the product.
product_unavailableThis product cannot be sent right now.
provider_float_emptyHeld while the provider tops up its float. It will be retried.
provider_outage_window_expiredThe provider was down for the whole retry window.
provider_rejectedThe network declined the send.
reviewed_failedJusa reviewed the send and confirmed it was not delivered.
zesa_hold_expiredZESA stayed down past the send's max_hold.

A batch line that never became a send

Refused before anything was charged, for a reason a single send answers as an error.

failure_codeMeans
account_frozenSends are frozen on this account.
bundle_not_foundThat data bundle is not offered.
bundle_requiredA data send names its bundle.
cap_exceededIt would take the recipient past one of their caps.
duplicate_client_referenceIts client_reference was already used by another send.
internal_errorSomething went wrong on our side before it was sent. Nothing was charged.
key_spend_cap_reachedIt would take the API key past one of its spend caps.
live_dispatch_disabledLive sends are switched off here.
product_not_allowedThe API key may not send this product or network.
recipient_blockedThe recipient is blocked, or being erased.
target_blockedThe number or meter is on a blocklist.
token_phone_requiredA ZESA send needs a Zimbabwean mobile for the token.
zesa_unavailableZESA could not confirm the meter, so nothing was sent or charged.