Error Handling
Checkout and order endpoints signal business failures inside the response body, not through HTTP status codes.
Error envelope
Branch on error_code, not HTTP status
Business failures return HTTP 200 with a non-zero error_code — a numeric code serialized as a JSON string ("0" is success). HTTP 4xx/5xx appears only for malformed requests or infrastructure problems.
Error response
{
"error_code": "801",
"errors": [
"an order with this order_reference_id already exists"
],
"message": "Order already exists",
"data": null
}Two endpoints use different envelopes: Check Eligibility returns HTTP 400 with { is_error: true, message } for business failures, and Get Customer Invoices signals failures with success: false and a message, with no numeric code. Each endpoint page documents its own envelope.
Error code reference
| Code | Name | Description | Resolution |
|---|---|---|---|
400 | INVALID_PARAMS | A required field is missing or a value failed validation (e.g. totals don't reconcile, invalid phone format, unknown field value). | Check errors[] for the failing field. Ensure order.total_amount equals the sum of items[].total_amount plus shipping_amount minus discount_amount. |
500 | INTERNAL_ERROR | An unexpected failure occurred on FINA's side. | Retry with backoff; contact FINA support if it persists. |
801 | ORDER_ALREADY_EXISTS | An order with the same order_reference_id already exists. order_reference_id is the idempotency anchor. | Use a fresh order_reference_id for new orders; reuse the existing order for retries. |
802 | SELLER_NOT_VALID | The merchant resolved from the bearer token is not recognised for this operation. | Verify the bearer token belongs to the correct merchant account. |
803 | SELLER_INACTIVE | The merchant account exists but is not active. | Contact the FINA team to activate the merchant account. |
804 | ANOTHER_CHECKOUT_IN_PROGRESS | A concurrent checkout for the same buyer is already in flight. | Wait for the in-flight checkout to finish, then retry. |
805 | CUSTOMER_NOT_ONBOARDED | The buyer has not completed FINA onboarding. | Run Check Eligibility and take the buyer through the signup_url onboarding flow. |
806 | CUSTOMER_CREDIT_LIMIT_EXCEEDED | The buyer's available credit does not cover this order. | Offer a plan with a down payment, reduce the order amount, or hide FINA for this purchase. |
808 | INVALID_ORDER | No order was found for the given order_id / order_number. | Use the order_id returned by Initiate Checkout. |
809 | OTP_VERIFICATION_FAILED | The OTP is wrong or has expired. Buyers get 3 verification attempts. | Ask the buyer to re-enter the code, or call Resend OTP and retry Authorise Checkout. |
810 | ANOTHER_ACTION_IN_PROGRESS | A concurrent action on the same order is already in flight. | Wait for the in-flight action to finish, then retry. |
811 | INVALID_ORDER_STATE | The order is not in a state that allows this operation (e.g. authorising an expired order, confirming delivery on an unauthorised order). | Check the order lifecycle; only perform operations valid for the order's current status. |
812 | NOTIFICATION_FAILED | The OTP SMS could not be sent to the buyer. | Retry Resend OTP; verify the buyer's phone number. |
813 | INVALID_FILE | The invoice file could not be downloaded or is not a valid PDF. | Ensure invoice_url is publicly reachable and points to a valid PDF. |
876 | MISSING_PLAN_SELECTION | No repayment plan could be resolved for the order. | Pass a repayment_config_id returned by Repayment Plan Options. |
877 | INVALID_PLAN_SELECTION | The repayment_config_id is invalid, or commission_config.tenure_in_days / merchant_share do not match the selected plan. | Send a repayment_config_id from Repayment Plan Options and keep commission_config consistent with that plan. |
878 | PLAN_NOT_CONFIGURED | No repayment plan is configured for the requested tenure_in_days / channel. | Only offer plans returned by Repayment Plan Options; contact FINA to configure more. |
881 | BG_DOC_EXPIRED | The buyer's credit agreement document has expired. | Send the buyer through onboarding again via Check Eligibility's signup_url. |