Skip to content
ABUNA
DocsErrors

Getting started

Errors

Status codes, error codes, and field errors, and how to handle each.

A failed request returns a 4xx or 5xx status and a JSON body. The body has a code that stays the same and an error sentence for developers. Branch on the status and the code. Don't parse error, since its wording can change.

Error body
{
  "code": "forbidden",
  "error": "not authorized for this app"
}

Field errors

When a request fails because of its input, the body also has an errors array, with one item per field. A failed validation returns 422 with code invalid and lists every field that failed.

Field errors (422)
{
  "code": "invalid",
  "error": "email is required; phone_number is required",
  "errors": [
    { "field": "email", "code": "invalid", "error": "email is required" },
    { "field": "phone_number", "code": "required", "error": "phone_number is required" }
  ]
}

Each item's code is one of these:

  • required: the field is missing or blank.
  • invalid: the value isn't allowed, such as an amount of 0 or an unknown status.
  • currency_unsupported: the currency isn't XAF or XOF.
  • phone_invalid: the phone number has no country code, or the wrong number of digits for its country.
  • unchanged: the value is the one already set, such as a new price amount equal to the current one.
  • too_soon: the date is too close, such as a price change less than 14 days ahead.
  • unknown_field: an update sent a field the endpoint doesn't take.
  • not_found: the ID in the field doesn't exist in the app, such as a price_id or an invoice_id when you create a session.
  • url_invalid: the URL isn't an absolute URL with a host, or uses http where only https is allowed.

A product's slug must be unique in its app. The slug comes from the name unless you send one. A clash returns 409 with code name_taken, and its errors item names the name field.

Error codes

These are the codes a request with a secret key can get. Each code shows the HTTP status it comes with.

Error codes

  • invalid_json400

    The body isn't valid JSON, has a value of the wrong type, or has a field the endpoint doesn't take.
  • invalid422

    One or more fields failed validation. See errors for each field. An Idempotency-Key header longer than 255 characters gets this code with 400.
  • payment_declined402

    The payment failed. The provider can also give a more specific reason, listed below.
  • insufficient_funds402

    The customer's balance is too low.
  • payment_not_approved402

    The customer declined the prompt on their phone or let it time out.
  • wallet_not_found402

    The number has no wallet on the network charged, or isn't a valid number.
  • wallet_limit_reached402

    The customer's wallet reached a transaction or balance limit.
  • wallet_busy402

    Another payment is already waiting for the customer's approval.
  • network_unavailable402

    The network can't take this payment now, or can't take it at all on your provider account.
  • forbidden403

    The key is missing, revoked, or for another app. A secret key also gets this on endpoints that need a dashboard sign-in, and a dashboard sign-in gets it on endpoints that need a secret key, like sessions.
  • email_unverified403

    The app is in Live mode and the team owner hasn't verified their email.
  • plan_limit403

    The request would pass a limit on your plan, such as its number of Live subscribers.
  • plan_read_only403

    Your plan has made this Live app read-only. Reads still work, and so does charging an entry.
  • not_found404

    The app, or the object named in the path or body, doesn't exist.
  • plan_offer_not_found404

    The plan change link is wrong. Send the customer a new one with Change plan.
  • name_taken409

    Another product in the app already has this slug.
  • already_paid409

    The entry is already paid, or you asked to pay an invoice that is already paid.
  • invoice_not_open409

    The invoice is void, for example because the subscription was canceled. You can't create a session to pay it.
  • subscription_canceled409

    The subscription has ended, so a scheduled cancel can't be undone and you can't request a cancel. Create a new subscription instead.
  • subscription_not_active409

    Only an active subscription can be canceled. You can't request a cancel for one that isn't, for example one whose first period was never paid.
  • cancel_already_scheduled409

    The subscription is already scheduled to cancel, so you can't request a cancel.
  • payment_in_progress409

    A payment for this entry is already waiting for approval. A plan change or cancel that would void an unpaid period, or replace an upgrade waiting for payment, also gets this while that payment is in flight.
  • plan_change_unavailable409

    The subscription isn't active, so its plan can't change. A subscription whose first period was never paid can't change plan.
  • plan_offer_inactive409

    The plan change offer was already accepted, canceled, or replaced by a newer one.
  • session_not_open409

    The session is already completed or expired, so it can't be expired.
  • idempotency_in_progress409

    A request with the same Idempotency-Key is still running. Retry after a moment.
  • no_pending_change409

    The price has no scheduled change to cancel.
  • change_in_effect409

    The price's pending change has reached its day, so it can't be replaced or canceled.
  • conflict409

    The request conflicts with the current state of the object.
  • price_archived410

    The price is archived, so no new subscription can use it.
  • plan_offer_expired410

    The plan change offer ran out. It lasts 7 days, or until the current period ends if that comes first.
  • session_expired410

    The session expired before the customer submitted their details. The hosted checkout page gets this, not your server. Create a new session.
  • price_not_eligible422

    The subscription can't move to this price: it is the current price, archived, for another product, in another currency, or not in the app.
  • not_accepting_payments422

    The Live app can't take payments yet: the team owner hasn't verified their email, or no payment provider is connected. An upgrade with something to pay gets this too.
  • payment_unavailable422

    The payment method isn't offered, or doesn't take payments in the invoice's currency.
  • idempotency_key_reused422

    The Idempotency-Key was already used with a different request in the last 24 hours. Use a new key for a new request.
  • webhook_url_missing422

    You asked to send or resend a webhook, but the app has no webhook URL.
  • rate_limited429

    Too many test webhooks. Each app can send 10 a minute.
  • internal500

    Something went wrong on Abuna's side. Retry later.

Rate limits

Each IP address can make 600 requests a minute. Past that, the API returns 429 with a plain-text body, not JSON. Wait for the number of seconds in the Retry-After header, then try again.

Next steps