Skip to main content

Errors

Last updated: 2026-09-26

Merchant API application errors use a google.rpc.Status-compatible JSON body:

{
"code": 3,
"message": "currencyCode is required",
"details": []
}

The JSON code is an API error code, not the HTTP status or a payment's failureReasonCode. Use paymentOrder.status to determine a payment outcome. If a non-success response is empty or cannot be read as JSON, do not infer a payment result from it; follow the transport-error reconciliation guidance below.

Common code values:

codeMeaning
3INVALID_ARGUMENT (validation)
5NOT_FOUND
7PERMISSION_DENIED
9FAILED_PRECONDITION (the request requires a condition to be resolved first)
13INTERNAL
14UNAVAILABLE (retryable only when the response provides retry guidance)
16UNAUTHENTICATED

Choose the next action​

  • For a field validation error, correct the named field before retrying. A pay-in reference conflict needs reconciliation of the existing payment instead of a new reference.
  • For the account-level payout refusal, contact support. Repeating the same request or changing methods does not resolve the condition.
  • For the documented retryable payout preparation response, honor the delay and retry the same request/reference a limited number of times.
  • For a timeout, connection loss, or an error without a confirmed outcome, look up the existing payment before creating another attempt. HTTP status alone does not establish the financial outcome.

Validation error example (field violations)​

{
"code": 3,
"message": "invalid argument",
"details": [
{
"@type": "type.googleapis.com/google.rpc.BadRequest",
"fieldViolations": [
{
"field": "currency_code|payin.currency.required",
"description": "currencyCode is required"
},
{
"field": "amount|payin.amount.required",
"description": "amount must be greater than 0"
}
]
}
]
}

Use fieldViolations to map API validation errors to specific form fields on your side (for example highlight currencyCode input when currency_code|payin.currency.required is returned).

Nested field violations can use snake_case paths. Localized merchant validations may append a |<messageId> suffix, while other validation errors may use just the field path. For example, a missing payout operator can be reported as mobile_money_details.operator, which maps to the JSON field mobileMoneyDetails.operator.

Pay-in reference conflict​

When a pay-in reference is already reserved and the request cannot be repeated, the response is HTTP 400 / INVALID_ARGUMENT. For example:

{
"code": 3,
"message": "validation error",
"details": [
{
"@type": "type.googleapis.com/google.rpc.BadRequest",
"fieldViolations": [
{ "field": "PayIn/#merchant_reference", "description": "Taken" }
]
}
]
}

Read the payment by merchantReference and continue reconciling that attempt. Do not change the reference to work around this response. The pay-in retry rules distinguish an equivalent repeat, a conflicting request and permitted reuse after cancellation or expiry. If a repeat returns the same error, including HTTP 500, stop the automatic retry loop and check the payment before contacting support.

Method temporarily unavailable​

When a configured payment method or submethod rejects a request before processing, the API can return HTTP 400 / INVALID_ARGUMENT with the public reason method_unavailable and this message:

Payment method is temporarily unavailable. Please contact support.

The reason can appear in google.rpc.ErrorInfo.reason and as the suffix of a field violation. The complete field value includes the operation prefix, for example PayOut/#payment_method|method_unavailable. The prefix depends on the operation; identify the condition from ErrorInfo.reason or the |method_unavailable suffix, rather than comparing the entire field string. A payment accepted far enough to produce a payment order can instead expose method_unavailable in paymentOrder.failureReason. Handle this reason separately from malformed input, offer another discovered method when appropriate, and do not retry in a tight loop.

Payout unavailable for the account​

Payout creation can return HTTP 400 / FAILED_PRECONDITION (code: 9) with the message below. Identify this condition by the exact public google.rpc.PreconditionFailure violation type and subject:

{
"code": 9,
"message": "Payouts are currently unavailable. Please contact support.",
"details": [
{
"@type": "type.googleapis.com/google.rpc.PreconditionFailure",
"violations": [
{
"type": "merchant_payout_accounting_not_ready",
"subject": "merchant_payout",
"description": "Payouts are currently unavailable. Please contact support."
}
]
}
]
}

Contact support before retrying. Changing the payment method does not resolve this account-level condition. It describes the current request and does not establish the outcome of an earlier attempt; continue reconciling earlier payouts by their payment ID or reference.

Payout preparation temporarily unavailable​

Payout creation can return HTTP 503 / UNAVAILABLE (code: 14) with retry details when the service cannot prepare the requested payout. For the operation_busy response described here, the rejected preparation has not created a new payout, reserved funds, or submitted a payout for processing.

Read google.rpc.RetryInfo.retryDelay in details. The accompanying google.rpc.ErrorInfo has reason operation_busy and string-valued retry metadata. The relevant response fields are shown below; additional metadata can be present:

{
"code": 14,
"message": "payment operation is temporarily busy",
"details": [
{
"@type": "type.googleapis.com/google.rpc.RetryInfo",
"retryDelay": "1s"
},
{
"@type": "type.googleapis.com/google.rpc.ErrorInfo",
"reason": "operation_busy",
"metadata": { "retryable": "true", "retryAfterSeconds": "1" }
}
]
}

Wait at least the returned delay, then retry an equivalent request with the same merchantReference. Use increasing delays and a bounded retry policy; if the response persists, stop automatic retries and contact support. An HTTP Retry-After header is not required for this response; use the JSON details. A missing or unsupported operator follows its validation guidance instead.

Do not apply this no-new-payout guarantee to a generic HTTP 503, connection failure, or timeout. If the outcome is unknown, reconcile the existing attempt before attempting another payout.

Payment failure reasons​

When a payment reaches a negative state, paymentOrder.failureReason and the string-encoded paymentOrder.failureReasonCode can contain these current values:

failureReasonfailureReasonCodeMeaning
internal_error1Processing error
unknown2Unknown reason
declined3Declined by the customer or payment partner
cancelled_by_user4Customer cancelled the payment
invalid_request5Invalid or unsupported payment request
insufficient_funds6Insufficient customer or merchant funds, depending on the flow
expired_payment7Payment session expired
expired_payment_form8Hosted payment form expired
suspected_fraud9Payment was rejected as suspected fraud
provider_unavailable10Temporary processing unavailability after the payment was created
amount_out_of_range11Amount is outside the supported range
method_unavailable12Selected method or submethod is temporarily unavailable

This is not an exhaustive list. Treat unrecognized reason strings or codes as unknown reasons, and use the payment status to determine the result. If an update follows an earlier completion, reconcile it with that same payment; see Later amount corrections.

Outcome vs transport status​

  • Validation/auth/system issues return non-2xx with rpc.Status.
  • Payment outcome is carried by paymentOrder.status (often in HTTP 200 responses).
  • For mobile-money pay-ins, missing mobileMoneyDetails or mobileMoneyDetails.mobileNumber is a validation error and returns non-2xx.
  • For operator-aware mobile-money pay-ins and payouts, a missing required mobileMoneyDetails.operator is a validation error and returns non-2xx.
  • For mobile money transfer, missing mobileMoneyTransferDetails, .operator, or .mobileNumber is a validation error and returns non-2xx.
  • For voucher-based mobile-money pay-ins, send mobileMoneyDetails.voucherPin when the selected route requires voucher collection.