Error Codes

Complete reference of API error responses with recovery steps

Error Response Format

All errors follow a consistent JSON structure. The error field contains a machine-readable code, and message contains a human-readable description.

{
  "error": "CASH_LIMIT_EXCEEDED",
  "message": "Cash transactions cannot exceed ETB 30,000",
  "details": [
    {
      "field": "payment_method",
      "issue": "CASH payment of ETB 45,000 exceeds limit"
    }
  ],
  "request_id": "req_abc123def456"
}

Always include the request_id when contacting support.

HTTP Status Codes

StatusMeaningWhat to Do
400

Bad Request

The request body is malformed or missing required fields.

Check the request payload against the API docs. Ensure all required fields are present and correctly typed.
401

Unauthorized

Missing or invalid API key.

Verify your API key is correct and has not expired. Check the Authorization header format: `Bearer sk_live_...`
403

Forbidden

Your API key does not have the required scope for this action.

Check the scopes assigned to your API key in the dashboard. See the Authentication docs for required scopes per endpoint.
404

Not Found

The requested resource does not exist.

Verify the resource ID. Check for typos in the URL path. Ensure you are using the correct API version (`/v1/`).
409

Conflict

The request conflicts with the current state of the resource.

Common with duplicate receipt submissions. Use idempotency keys to prevent duplicates.
429

Too Many Requests

Rate limit exceeded (API-SEC-3).

Read the `Retry-After` header and wait before retrying. Consider implementing exponential backoff.
500

Internal Server Error

An unexpected error occurred on the server.

Retry with exponential backoff. If persistent, contact support with the `X-Request-Id` header value.

Business Error Codes

These codes appear in the error field of the response body. They indicate domain-specific issues.

CASH_LIMIT_EXCEEDED

Cash payment exceeds the ETB 30,000 per-transaction limit (CASH-1).

Recovery: Split into multiple transactions or use an electronic payment method (ETHQR, bank transfer).

DEVICE_NOT_ACTIVE

The device is not in `active` status. It may be `pending_activation`, `suspended`, or `revoked`.

Recovery: Activate the device via `POST /v1/devices/{id}/activate` before issuing receipts.

DEVICE_QUOTA_EXCEEDED

Your plan does not allow more devices.

Recovery: Upgrade your plan or deactivate unused devices.

ZREPORT_ALREADY_GENERATED

A Z-Report has already been generated for this device today.

Recovery: Z-Reports are once-per-day per device. Use `GET /v1/devices/{id}/reports/x` for real-time summaries.

NO_TRANSACTIONS

Cannot generate a Z-Report with zero transactions for the period.

Recovery: Issue at least one receipt before generating the Z-Report.

INVALID_ALGORITHM

The signing algorithm is not supported. Only ECDSA-P256 is accepted (SIGN-2).

Recovery: Set `signing_algorithm` to `"ECDSA-P256"` in your device registration request.

INVALID_TIN

The provided TIN is not registered with the Ministry of Revenue.

Recovery: Verify the TIN is exactly 10 digits and matches MOR records.

RECEIPT_CHAIN_BROKEN

The receipt chain integrity check failed (CHAIN-1).

Recovery: Ensure `previous_receipt_hash` matches the hash of the last receipt issued by this device. Do not skip or reorder receipts.

DUPLICATE_RECEIPT

A receipt with this idempotency key already exists.

Recovery: This is expected behavior for retry safety. The original receipt is returned.

VALIDATION_ERROR

One or more request fields failed validation.

Recovery: Check the `details` array in the error response for specific field errors.

Rate Limiting

All endpoints enforce rate limits per API key. When exceeded, you receive a 429 response with a Retry-After header indicating seconds to wait.

PlanRate LimitBurst
Free / Sandbox60 req/min10 req/sec
Starter120 req/min20 req/sec
Business600 req/min50 req/sec
EnterpriseCustomCustom