error_code the Bachs API returns. When an error has a code, its doc_url links to that code’s entry here, or to the guide that explains it. For the error object shape and how to handle errors, see Errors.
Sections marked Limited Access cover features that are not enabled by default. Contact hello@bachs.io to request access.
General
Errors that can occur on any endpoint.| Code | Status | Cause and resolution |
|---|---|---|
BAD_REQUEST | 400 | The request is malformed or has invalid parameters. Check it against the endpoint reference. |
UNAUTHORIZED | 401 | No Authorization header, or the key is invalid or revoked. Send a valid key. |
FORBIDDEN | 403 | The key is valid but lacks permission. Check your key’s permissions. |
NOT_FOUND | 404 | The resource does not exist in your scope. Verify the ID and environment. |
INSUFFICIENT_BALANCE | 400 | The available_balance will not cover the debit. detail states the shortfall, what was required, and what was available. Fund the balance, or wait for a pending charge to settle. |
IDEMPOTENCY_IN_PROGRESS | 409 | A request with the same Idempotency-Key is still in flight. Retry after a short delay; the winner’s response is replayed once it lands. |
CONFLICT | 409 | The request conflicts with current state, such as a duplicate. Reconcile and retry. |
VALIDATION_ERROR | 422 | One or more fields failed validation. Inspect the errors array and correct the input. |
VALIDATION_FAILED | 422 | A business rule rejected a well-formed request. Read detail for the rule. |
INVALID_REQUIREMENT_FIELD | 400 | A field submitted on POST /v1/accounts/{account_id} was rejected. Inspect errors[] (field, message, code); no field from that submission was saved, though anything else in the same call (contact details, capability requests, profile changes) was applied before the fields were validated. See payout_destination for its rejection codes. |
TOO_MANY_REQUESTS | 429 | Rate limit exceeded. Check Retry-After or X-RateLimit-Reset before retrying. |
PRECONDITION_REQUIRED | 428 | A required precondition is missing. Read detail for what to supply. |
TOTP_STEP_UP_REQUIRED | 428 | This action needs two-factor verification. Complete step-up and retry. |
IMMUTABLE_FIELD | 400 | A field that cannot change after creation was included in an update. Remove it. |
INTERNAL_SERVER_ERROR | 500 | Unexpected server-side failure. The request was not processed. Retry shortly. |
NOT_IMPLEMENTED | 501 | The operation is not yet supported. |
BAD_GATEWAY | 502 | An upstream dependency is temporarily unavailable. Retry shortly. |
SERVICE_UNAVAILABLE | 503 | The service is temporarily overloaded or in maintenance. Retry shortly. |
Payments
Encountered when initiating or processing payments.| Code | Status | Cause and resolution |
|---|---|---|
PAYMENT_ERROR | 400 | A general payment processing error. Read detail for the cause. |
PAYMENTS_NOT_ENABLED | 400 | Payments are not enabled for your organization. Complete onboarding or contact support. |
PAYMENT_METHOD_NOT_ENABLED | 400 | The selected method is not enabled. Use an enabled method or contact support. |
CARD_TOKEN_INVALID | 400 | The card token is invalid or expired. Collect the card again for a fresh token. |
CARD_VAULT_UNAVAILABLE | 500 | The card service could not be reached. Retry shortly. |
PAYMENT_METHOD_SETUP_FAILED | 500 | Payment method setup could not start. Retry shortly. |
OFF_SESSION_CHARGE_FAILED | 500 | The off-session charge could not be created. Retry, or fall back to an on-session payment. |
OFF_SESSION_NOT_SUPPORTED | 400 | This payment method cannot be charged off-session. Use an on-session flow. |
NO_SAVED_PAYMENT_METHOD | 400 | The customer has no saved card to charge. Save one on a checkout first. See Charge a saved card. |
SAVED_PAYMENT_METHOD_NOT_FOUND | 404 | No saved card with that pm_ id belongs to this customer. Cards are scoped to one customer. |
PAYMENT_METHOD_UNUSABLE | 400 | The saved card has expired or been removed. Ask the customer to save a new one. |
CHECKOUT_CANNOT_SAVE_PAYMENT_METHOD | 400 | Saving a card needs a card on the checkout. This one offers no card method, so nothing could be saved. See Why a checkout cannot save a card. |
GATEWAY_UNAVAILABLE | 500 | Our payment processing infrastructure is temporarily unreachable. Rare. Retry shortly, contact support if it persists. |
PROVIDER_ERROR | 500 | Our payment processing infrastructure returned an unexpected error. Retry shortly. |
Products & Prices
Encountered when creating or updating products and prices.| Code | Status | Cause and resolution |
|---|---|---|
PRODUCT_NOT_FOUND | 400 | A referenced product does not exist or is archived. Verify the product ID. |
PRODUCT_NO_PRICE | 400 | The product has no price in the requested currency. Add a price in that currency. |
PRODUCT_ARCHIVED | 400 | The product is archived and cannot be used for new checkouts. Unarchive or use another. |
PRICE_REQUIRED | 400 | At least one price is required. Include a price on the product. |
MINIMUM_PRICE_REQUIRED | 400 | A product must keep at least one price. You cannot remove the last one. |
DUPLICATE_CURRENCY | 400 | A price for this currency already exists. Update the existing price instead. |
UNSUPPORTED_CURRENCY | 400 | The currency is not in the active supported set. Use a supported currency. |
INTERVAL_REQUIRED | 400 | interval_count requires a positive integer when interval is set. Supply both. |
INTERVAL_NOT_ALLOWED | 400 | interval_count was provided without an interval. Add an interval or remove the count. |
INVALID_INTERVAL | 400 | interval must be one of day, week, month, or year. |
RECURRING_INTERVAL_IMMUTABLE | 400 | recurring_interval cannot change once set. Create a new product instead. |
TRIAL_REQUIRES_RECURRING | 400 | A trial is only valid on a recurring product. Remove the trial or make it recurring. |
MEDIA_LIMIT_EXCEEDED | 400 | A product supports at most 5 media items. Remove some before adding more. |
METADATA_LIMIT_EXCEEDED | 400 | metadata allows at most 20 keys, each key and value at most 500 characters. Trim it. |
ENVIRONMENT_MISMATCH | 400 | All products in a group must be in the same environment. Use one environment. |
INVALID_PRODUCT_REFERENCE | 400 | A product ID is invalid or belongs to another merchant. Verify the IDs. |
INVALID_UPLOAD_REFERENCE | 400 | An upload ID is invalid or belongs to another merchant. Verify the IDs. |
Checkout Sessions
Encountered when creating or processing checkout sessions.| Code | Status | Cause and resolution |
|---|---|---|
CHECKOUT_ERROR | 400 | A general checkout configuration or processing error. Read detail for the cause. |
CHECKOUT_PRICE_CHANGED | 409 | The price changed after the quote was issued. Fetch a fresh quote and retry. |
CUSTOM_AMOUNT_REQUIRED | 400 | A CUSTOM-priced product needs an amount in the line item. Provide one. |
FIXED_AMOUNT_OVERRIDE_NOT_ALLOWED | 400 | An amount was set for a FIXED-priced product. Remove amount from the line item. |
HETEROGENEOUS_PRICE_TYPES | 422 | All prices for a product must share one type (FIXED, CUSTOM, or FREE). |
PAYMENT_METHOD_NOT_ALLOWED | 400 | The checkout was restricted to other payment methods or currencies. Choose one the checkout offers. |
CHECKOUT_HAS_NO_PAYMENT_METHOD | 400 | Nothing can be offered on this checkout, so it was refused instead of created unpayable. Work through Why a checkout has no payment method. |
CHECKOUT_RESTRICTION_LEAVES_NO_PAYMENT_METHOD | 400 | Your payment_method_types narrowed the checkout to nothing that is available. Widen it, or see Why a checkout has no payment method. |
ACCOUNT_NOT_ACTIVATED | 400 | The account has payment methods configured but is not yet approved to accept live payments. Finish going live, or keep building against a sandbox key. |
ACCOUNT_PAYMENT_METHODS_RESTRICTED | 400 | Every payment method on the account is restricted, so no checkout can offer one. You cannot lift this from your own settings. Contact hello@bachs.io. |
CART_CURRENCY_MISMATCH | 400 | All products in a multi-item checkout must share the same base currency. |
BASE_CURRENCY_NOT_HELD_BY_ORG | 422 | A recurring checkout was priced in a currency you do not hold. One-time checkouts convert and settle in any supported currency; recurring will too once renewals settle to USD, but for now price the plan in a held currency. See Charge in any currency. |
BASE_CURRENCY_NOT_COLLECTIBLE | 422 | No payment method can collect the base_currency. Crypto asset codes are refused here: an asset code names a rail, not a price. |
BASE_CURRENCY_NOT_ENABLED | 422 | The base_currency is collectible, but not enabled for your organization. Enable it in your checkout settings first. |
BASE_CURRENCY_NOT_CONVERTIBLE | 422 | We can collect the base_currency but have no rate to settle it into your settlement currency, so the checkout is refused rather than created with money that could not be paid out. |
BILLING_CURRENCY_NOT_AVAILABLE | 400 | Nothing in the checkout is priced in the requested billing_currency. Add a price in that currency, or request one of the currencies named in detail. |
BILLING_CURRENCY_HAS_NO_PAYMENT_METHOD | 400 | The checkout is priced in the requested billing_currency, but no payment method it offers can charge it. Request one of the currencies named in detail. See Pin the currency. |
Subscriptions Limited Access
Encountered when creating or managing subscriptions.| Code | Status | Cause and resolution |
|---|---|---|
SUBSCRIPTIONS_NOT_ENABLED | 403 | Subscriptions are not enabled for this account. Contact support to request access. |
NGN_SUBSCRIPTIONS_NOT_ENABLED | 403 | NGN subscriptions are not enabled. Contact support to request access. |
TRIALS_NOT_ENABLED | 403 | Trials are not enabled for this account. Contact support to request access. |
SUBSCRIPTION_NOT_FOUND | 404 | No subscription exists for this ID in your scope. Verify the ID. |
SUBSCRIPTION_ALREADY_CANCELED | 400 | The subscription is already canceled and cannot be canceled again. |
SUBSCRIPTION_NOT_MODIFIABLE | 400 | The subscription cannot be modified in its current status. Check its status first. |
SUBSCRIPTION_NOT_TRIALING | 400 | The action requires a trialing subscription, but this one is not in a trial. |
INVALID_SUBSCRIPTION_PRICE | 400 | The price is not valid for a subscription. It must be recurring with a positive amount. |
SUBSCRIPTION_PRICE_NOT_RECURRING | 400 | A subscription needs a recurring price. Use a product with one. |
SUBSCRIPTION_REQUIRES_CATALOG_PRODUCT | 400 | A subscription checkout needs exactly one recurring catalog product. Raw amounts and inline products are not supported. |
SUBSCRIPTION_METHOD_NOT_SUPPORTED | 400 | Subscription checkouts can only be paid with a card. Use a card. |
PLAN_NOT_PRICED_IN_CURRENCY | 400 | The target product has no price in the subscription’s currency. Add one or choose another plan. |
SUBSCRIPTION_PLAN_INTERVAL_MISMATCH | 400 | The target product’s interval must match the subscription’s. Choose a matching plan. |
PRORATION_BEHAVIOR_NOT_SUPPORTED | 400 | The requested proration behavior is not supported yet. Use a supported value. |
Payouts Limited Access
Encountered when sending payouts or managing payout destinations.| Code | Status | Cause and resolution |
|---|---|---|
PAYOUTS_NOT_ENABLED | 400 | Payouts are not enabled for this organization. Contact support to request access. |
DESTINATION_NOT_FOUND | 404 | No destination with that id belongs to this account. Check the id. |
DESTINATION_PENDING_REVIEW | 400 | The destination has not cleared review, so it cannot receive money yet. Wait for is_usable to be true. |
DESTINATION_REJECTED | 400 | The destination was rejected in review and never becomes usable. Register a new one. |
DESTINATION_TYPE_REQUIRED | 400 | The currency is served by more than one payout rail, so the type cannot be inferred. Send type explicitly. |
CURRENCY_NOT_SUPPORTED | 400 | No payout rail serves this currency. See Supported currencies. |
AMOUNT_REQUIRED | 400 | A same-currency payout needs an amount. |
AMOUNT_NOT_ALLOWED_WITH_QUOTE | 400 | A quoted payout carries no amount, because the quote already fixes both sides. Send one or the other. |
QUOTE_REQUIRED | 400 | The destination’s currency differs from the balance being debited. Create a quote and pass quote_id. |
QUOTE_NOT_APPLICABLE | 400 | A quote was passed to a same-currency payout, which converts nothing. Drop quote_id. |
QUOTE_NOT_FOUND | 400 | The quote does not exist, or belongs to another organization. Create a new one. |
QUOTE_EXPIRED | 400 | The quote has lapsed. Quotes are short-lived; create one immediately before the payout. |
QUOTE_DESTINATION_MISMATCH | 400 | The quote was created for a different currency pair than this destination’s. Quote the pair you are paying. |
PAYOUT_DESTINATION_NOT_FOUND | 404 | No destination with that id belongs to this account. Returned when choosing the destination a payout schedule uses. |
PAYOUT_DESTINATION_NOT_APPROVED | 400 | Only an approved destination can be a payout schedule’s default. Wait for review to clear. |
PAYOUT_DESTINATION_INACTIVE | 400 | A deleted destination cannot be a payout schedule’s default. Register the account again and promote the new one. |
WITHDRAWAL_LIMIT_EXCEEDED | 400 | The amount exceeds your single-withdrawal limit. details has requested_amount_usd and max_allowed_usd. Lower the amount. |
DAILY_WITHDRAWAL_LIMIT_EXCEEDED | 400 | The amount would exceed your daily cap. details has requested_amount_usd, max_allowed_usd, and total_today_usd. Retry within the cap. |
INSUFFICIENT_BALANCE | 400 | available_balance will not cover the payout. Compare it against total_debited (what the destination receives plus the fee), not against amount. See General for the shortfall the response states. |
Limit errors include a
details object alongside error_code and detail. Parse it to show remaining allowance and cap amounts directly to your users.Deposits
Encountered when collecting payments from customers.| Code | Status | Cause and resolution |
|---|---|---|
DEPOSIT_LIMIT_EXCEEDED | 400 | The payment exceeds your deposit limit for this currency. details has requested_amount, max_allowed_amount, and currency. Lower the amount or contact support. |
UNSUPPORTED_DEPOSIT_CURRENCY | 400 | The currency is not a supported deposit currency. Use a supported currency. |
Virtual accounts
Encountered when creating or reading an account’s fixed account number. See Virtual accounts.| Code | Status | Cause and resolution |
|---|---|---|
VIRTUAL_ACCOUNT_CURRENCY_NOT_SUPPORTED | 400 | We do not issue virtual accounts in that currency. Request NGN, the only supported currency today. |
FORBIDDEN | 403 | Your key lacks the required virtual_accounts:read or virtual_accounts:write permission, or the account’s virtual_accounts capability is not active. Check the key’s permissions, then contact support if the permission is present. |
VALIDATION_FAILED | 422 | The account representative has no BVN on file. The response includes missing_fields: ["bvn"]. Submit the representative’s BVN through the account’s requirements, then retry. |
NOT_FOUND | 404 | On GET, the account has no virtual account in that currency, so create one with POST /v1/virtual-accounts. On POST, virtual accounts are not available for this account; contact support to request access. |
Quotes Limited Access
Encountered when requesting conversion quotes.| Code | Status | Cause and resolution |
|---|---|---|
QUOTE_ERROR | 400 | The conversion quote could not be generated. Check the currency pair and amount are valid. |

