Error Response Format

Every error response has the same shape:

Error response structure
{
  "success": false,
  "error": {
    "code": "wallet.insufficient_funds",
    "message": "Wallet balance is too low for this transaction."
  },
  "request_id": "abc-123"
}

Always log the request_id — include it in support tickets for instant lookup.

HTTP Status Codes

CodeMeaning
200OK — request succeeded
201Created — resource created (purchases, keys)
400Bad Request — validation failed or malformed request
401Unauthorized — missing, invalid, or expired API key
403Forbidden — valid key but insufficient permissions or IP blocked
404Not Found — resource doesn't exist or doesn't belong to your account
422Unprocessable — request is valid but cannot be completed (e.g. low balance)
429Too Many Requests — rate limit exceeded
500Server Error — something went wrong on our end

Error Code Reference

Authentication

CodeHTTPDescription
auth.invalid_key401Authorization header missing or not in Bearer format
auth.key_not_found401API key not found or has been revoked
auth.key_expired401API key has expired
auth.ip_not_allowed403Request IP is not in the key's allowlist

Wallet

wallet.insufficient_funds422Wallet balance too low for this transaction
wallet.not_found404Wallet not found for this account
wallet.limit_exceeded422Daily wallet limit exceeded for your KYC level

Transactions

transaction.failed422Transaction failed. Wallet automatically refunded.
transaction.not_found404Transaction reference not found
transaction.provider_unavailable503Service provider temporarily unavailable. Retry in 60s.

Services

service.plan_not_found422Data plan not found or disabled
service.invalid_meter422Meter number not found on DISCO system
service.invalid_smartcard422Smartcard / IUC number not found
service.amount_mismatch422Amount doesn't match plan price

PIN

pin.incorrect403Transaction PIN is incorrect
pin.locked429Too many wrong PIN attempts. Account temporarily locked.
pin.not_set403Transaction PIN not set. Set it from your profile.

API Keys

keys.limit_reached422Maximum of 5 active API keys per account
keys.not_found404API key ID not found or doesn't belong to your account

Rate Limiting

rate_limit.exceeded429Too many requests. Check Retry-After header.

Retries

Use the X-Idempotency-Key header on all POST requests so retries never create duplicate transactions:

Safe retry pattern
curl -X POST https://api.betavend.com/v1/services/data/purchase \
  -H "Authorization: Bearer bv_live_your_key" \
  -H "Content-Type: application/json" \
  -H "X-Idempotency-Key: order-ref-001" \
  -d '{ "network": "mtn", "plan_code": "mtn-1gb-30days", ... }'

# If network times out — retry with the SAME idempotency key.
# Betavend will return the original response without re-processing.

For 5xx and 429 errors, retry with exponential backoff: 1s, 2s, 4s, 8s. For 4xx errors, fix the request — retrying won't help.