{"templateId":"markdown","versions":[{"version":"v2026.03","label":"v2026.03","link":"/products/payments-direct-2/api-docs/best-practices/error-handling","default":true,"active":true,"folderId":"eb16255d"},{"version":"v2025.11","label":"v2025.11","link":"/products/payments-direct-2/v2025.11/api-docs/best-practices/error-handling","default":false,"active":false,"folderId":"eb16255d"}],"sharedDataIds":{"sidebar":"sidebar-products/payments-direct-2/@v2025.11/sidebars.yaml"},"props":{"metadata":{"markdoc":{"tagList":["admonition"]},"type":"markdown"},"seo":{"title":"Error handling and retry strategy","description":"User guides, API reference, and support resources.","siteUrl":"https://docs.ripple.com/products/custody","lang":"en-US","llmstxt":{"hide":false,"sections":[{"title":"Table of contents","includeFiles":["**/*"],"excludeFiles":[]}],"excludeFiles":[]}},"dynamicMarkdocComponents":[],"compilationErrors":[],"ast":{"$$mdtype":"Tag","name":"article","attributes":{},"children":[{"$$mdtype":"Tag","name":"Heading","attributes":{"level":1,"id":"error-handling-and-retry-strategy","__idx":0},"children":["Error handling and retry strategy"]},{"$$mdtype":"Tag","name":"p","attributes":{},"children":["Payments Direct 2.0 returns a ",{"$$mdtype":"Tag","name":"a","attributes":{"href":"/products/payments-direct-2/api-docs/error-codes/payments-direct-api-errors"},"children":["standardized error response"]}," for every failed API request. Building a reliable integration means classifying errors correctly, retrying safely, and escalating promptly when retrying won't help."]},{"$$mdtype":"Tag","name":"p","attributes":{},"children":["This topic covers:"]},{"$$mdtype":"Tag","name":"ul","attributes":{},"children":[{"$$mdtype":"Tag","name":"li","attributes":{},"children":["How to classify errors using the ",{"$$mdtype":"Tag","name":"code","attributes":{},"children":["code"]}," and ",{"$$mdtype":"Tag","name":"code","attributes":{},"children":["type"]}," fields"]},{"$$mdtype":"Tag","name":"li","attributes":{},"children":["Which errors are safe to retry, and how to retry them"]},{"$$mdtype":"Tag","name":"li","attributes":{},"children":["Recommended exponential backoff parameters"]},{"$$mdtype":"Tag","name":"li","attributes":{},"children":["Handling authentication errors"]},{"$$mdtype":"Tag","name":"li","attributes":{},"children":["Handling payment failures (FAILED, DECLINED, RETURNED states)"]},{"$$mdtype":"Tag","name":"li","attributes":{},"children":["What to log and monitor"]}]},{"$$mdtype":"Tag","name":"hr","attributes":{},"children":[]},{"$$mdtype":"Tag","name":"Heading","attributes":{"level":2,"id":"classify-before-you-act","__idx":1},"children":["Classify before you act"]},{"$$mdtype":"Tag","name":"p","attributes":{},"children":["Every error response includes a ",{"$$mdtype":"Tag","name":"code","attributes":{},"children":["code"]}," field (for example, ",{"$$mdtype":"Tag","name":"code","attributes":{},"children":["USR_067"]},") and a ",{"$$mdtype":"Tag","name":"code","attributes":{},"children":["type"]}," field (for example, ",{"$$mdtype":"Tag","name":"code","attributes":{},"children":["USER_ERROR"]},"). Always use the ",{"$$mdtype":"Tag","name":"code","attributes":{},"children":["code"]}," field as your primary signal, not the HTTP status code alone. Two errors can share an HTTP status but require completely different handling."]},{"$$mdtype":"Tag","name":"Heading","attributes":{"level":3,"id":"error-type-reference","__idx":2},"children":["Error type reference"]},{"$$mdtype":"Tag","name":"div","attributes":{"className":"md-table-wrapper"},"children":[{"$$mdtype":"Tag","name":"table","attributes":{"className":"md"},"children":[{"$$mdtype":"Tag","name":"thead","attributes":{},"children":[{"$$mdtype":"Tag","name":"tr","attributes":{},"children":[{"$$mdtype":"Tag","name":"th","attributes":{"data-label":"Type"},"children":["Type"]},{"$$mdtype":"Tag","name":"th","attributes":{"data-label":"Prefix"},"children":["Prefix"]},{"$$mdtype":"Tag","name":"th","attributes":{"data-label":"What it means"},"children":["What it means"]},{"$$mdtype":"Tag","name":"th","attributes":{"data-label":"General action"},"children":["General action"]}]}]},{"$$mdtype":"Tag","name":"tbody","attributes":{},"children":[{"$$mdtype":"Tag","name":"tr","attributes":{},"children":[{"$$mdtype":"Tag","name":"td","attributes":{},"children":[{"$$mdtype":"Tag","name":"code","attributes":{},"children":["USER_ERROR"]}," or ",{"$$mdtype":"Tag","name":"code","attributes":{},"children":["NOT_FOUND"]}]},{"$$mdtype":"Tag","name":"td","attributes":{},"children":[{"$$mdtype":"Tag","name":"code","attributes":{},"children":["USR_"]}]},{"$$mdtype":"Tag","name":"td","attributes":{},"children":["The request itself is the problem: missing fields, invalid values, or a resource that doesn't exist."]},{"$$mdtype":"Tag","name":"td","attributes":{},"children":["Fix the request and resubmit. Do not retry the same request."]}]},{"$$mdtype":"Tag","name":"tr","attributes":{},"children":[{"$$mdtype":"Tag","name":"td","attributes":{},"children":[{"$$mdtype":"Tag","name":"code","attributes":{},"children":["AUTH_ERROR"]}]},{"$$mdtype":"Tag","name":"td","attributes":{},"children":[{"$$mdtype":"Tag","name":"code","attributes":{},"children":["AUTH_"]}]},{"$$mdtype":"Tag","name":"td","attributes":{},"children":["The request was rejected due to an authentication or authorization problem."]},{"$$mdtype":"Tag","name":"td","attributes":{},"children":["See ",{"$$mdtype":"Tag","name":"a","attributes":{"href":"#handling-authentication-errors"},"children":["Handling authentication errors"]}," below."]}]},{"$$mdtype":"Tag","name":"tr","attributes":{},"children":[{"$$mdtype":"Tag","name":"td","attributes":{},"children":[{"$$mdtype":"Tag","name":"code","attributes":{},"children":["SYSTEM_ERROR"]}]},{"$$mdtype":"Tag","name":"td","attributes":{},"children":[{"$$mdtype":"Tag","name":"code","attributes":{},"children":["SYS_"]}]},{"$$mdtype":"Tag","name":"td","attributes":{},"children":["An internal error occurred in Ripple's infrastructure."]},{"$$mdtype":"Tag","name":"td","attributes":{},"children":["Retry with exponential backoff. Escalate to Ripple technical support if the condition persists."]}]},{"$$mdtype":"Tag","name":"tr","attributes":{},"children":[{"$$mdtype":"Tag","name":"td","attributes":{},"children":[{"$$mdtype":"Tag","name":"code","attributes":{},"children":["CONFIGURATION_ERROR"]}]},{"$$mdtype":"Tag","name":"td","attributes":{},"children":[{"$$mdtype":"Tag","name":"code","attributes":{},"children":["CFG_"]}]},{"$$mdtype":"Tag","name":"td","attributes":{},"children":["An account or service configuration issue prevents the request from completing."]},{"$$mdtype":"Tag","name":"td","attributes":{},"children":["Do not retry. Contact Ripple technical support."]}]}]}]}]},{"$$mdtype":"Tag","name":"hr","attributes":{},"children":[]},{"$$mdtype":"Tag","name":"Heading","attributes":{"level":2,"id":"transient-vs-permanent-errors","__idx":3},"children":["Transient vs. permanent errors"]},{"$$mdtype":"Tag","name":"p","attributes":{},"children":["Before retrying, confirm that the error is transient (a condition that may resolve itself) rather than permanent."]},{"$$mdtype":"Tag","name":"div","attributes":{"className":"md-table-wrapper"},"children":[{"$$mdtype":"Tag","name":"table","attributes":{"className":"md"},"children":[{"$$mdtype":"Tag","name":"thead","attributes":{},"children":[{"$$mdtype":"Tag","name":"tr","attributes":{},"children":[{"$$mdtype":"Tag","name":"th","attributes":{"data-label":"Error type"},"children":["Error type"]},{"$$mdtype":"Tag","name":"th","attributes":{"data-label":"HTTP status"},"children":["HTTP status"]},{"$$mdtype":"Tag","name":"th","attributes":{"data-label":"Retryable?"},"children":["Retryable?"]},{"$$mdtype":"Tag","name":"th","attributes":{"data-label":"Recommended action"},"children":["Recommended action"]}]}]},{"$$mdtype":"Tag","name":"tbody","attributes":{},"children":[{"$$mdtype":"Tag","name":"tr","attributes":{},"children":[{"$$mdtype":"Tag","name":"td","attributes":{},"children":[{"$$mdtype":"Tag","name":"code","attributes":{},"children":["USER_ERROR"]}]},{"$$mdtype":"Tag","name":"td","attributes":{},"children":["400, 404, 415"]},{"$$mdtype":"Tag","name":"td","attributes":{},"children":["No"]},{"$$mdtype":"Tag","name":"td","attributes":{},"children":["Fix the request and resubmit."]}]},{"$$mdtype":"Tag","name":"tr","attributes":{},"children":[{"$$mdtype":"Tag","name":"td","attributes":{},"children":[{"$$mdtype":"Tag","name":"code","attributes":{},"children":["USER_ERROR"]}]},{"$$mdtype":"Tag","name":"td","attributes":{},"children":["402"]},{"$$mdtype":"Tag","name":"td","attributes":{},"children":["Not until resolved"]},{"$$mdtype":"Tag","name":"td","attributes":{},"children":["Resolve the underlying condition (insufficient balance, credit limit, or past-due invoice) before retrying."]}]},{"$$mdtype":"Tag","name":"tr","attributes":{},"children":[{"$$mdtype":"Tag","name":"td","attributes":{},"children":[{"$$mdtype":"Tag","name":"code","attributes":{},"children":["NOT_FOUND"]}]},{"$$mdtype":"Tag","name":"td","attributes":{},"children":["404"]},{"$$mdtype":"Tag","name":"td","attributes":{},"children":["No"]},{"$$mdtype":"Tag","name":"td","attributes":{},"children":["Verify the resource ID and resubmit."]}]},{"$$mdtype":"Tag","name":"tr","attributes":{},"children":[{"$$mdtype":"Tag","name":"td","attributes":{},"children":[{"$$mdtype":"Tag","name":"code","attributes":{},"children":["AUTH_ERROR"]}]},{"$$mdtype":"Tag","name":"td","attributes":{},"children":["401"]},{"$$mdtype":"Tag","name":"td","attributes":{},"children":["Yes (after token refresh)"]},{"$$mdtype":"Tag","name":"td","attributes":{},"children":["Regenerate your access token and retry."]}]},{"$$mdtype":"Tag","name":"tr","attributes":{},"children":[{"$$mdtype":"Tag","name":"td","attributes":{},"children":[{"$$mdtype":"Tag","name":"code","attributes":{},"children":["AUTH_ERROR"]}]},{"$$mdtype":"Tag","name":"td","attributes":{},"children":["403"]},{"$$mdtype":"Tag","name":"td","attributes":{},"children":["No"]},{"$$mdtype":"Tag","name":"td","attributes":{},"children":["Verify your token has the required scopes. Contact Ripple technical support if the issue persists."]}]},{"$$mdtype":"Tag","name":"tr","attributes":{},"children":[{"$$mdtype":"Tag","name":"td","attributes":{},"children":[{"$$mdtype":"Tag","name":"code","attributes":{},"children":["SYSTEM_ERROR"]}]},{"$$mdtype":"Tag","name":"td","attributes":{},"children":["500"]},{"$$mdtype":"Tag","name":"td","attributes":{},"children":["Yes (with backoff)"]},{"$$mdtype":"Tag","name":"td","attributes":{},"children":["Retry with exponential backoff. Contact Ripple technical support if the issue persists."]}]},{"$$mdtype":"Tag","name":"tr","attributes":{},"children":[{"$$mdtype":"Tag","name":"td","attributes":{},"children":[{"$$mdtype":"Tag","name":"code","attributes":{},"children":["CONFIGURATION_ERROR"]}]},{"$$mdtype":"Tag","name":"td","attributes":{},"children":["500"]},{"$$mdtype":"Tag","name":"td","attributes":{},"children":["No"]},{"$$mdtype":"Tag","name":"td","attributes":{},"children":["Contact Ripple technical support."]}]}]}]}]},{"$$mdtype":"Tag","name":"hr","attributes":{},"children":[]},{"$$mdtype":"Tag","name":"Heading","attributes":{"level":2,"id":"retry-strategy","__idx":4},"children":["Retry strategy"]},{"$$mdtype":"Tag","name":"Heading","attributes":{"level":3,"id":"exponential-backoff-with-jitter","__idx":5},"children":["Exponential backoff with jitter"]},{"$$mdtype":"Tag","name":"p","attributes":{},"children":["When a request fails with a retryable error (",{"$$mdtype":"Tag","name":"code","attributes":{},"children":["SYSTEM_ERROR"]}," / 500, or ",{"$$mdtype":"Tag","name":"code","attributes":{},"children":["AUTH_ERROR"]}," / 401 after a token refresh), use exponential backoff with jitter rather than retrying immediately or at a fixed interval. Immediate or synchronized retries amplify load on an already stressed system and can trigger rate limiting."]},{"$$mdtype":"Tag","name":"p","attributes":{},"children":["Recommended approach:"]},{"$$mdtype":"Tag","name":"ol","attributes":{},"children":[{"$$mdtype":"Tag","name":"li","attributes":{},"children":["On the first failure, wait a short base interval."]},{"$$mdtype":"Tag","name":"li","attributes":{},"children":["On each subsequent failure, double the wait time."]},{"$$mdtype":"Tag","name":"li","attributes":{},"children":["Add random jitter (±10–20% of the interval) to desynchronize retries across clients."]},{"$$mdtype":"Tag","name":"li","attributes":{},"children":["Cap the maximum wait at a reasonable ceiling."]},{"$$mdtype":"Tag","name":"li","attributes":{},"children":["After a configurable number of attempts, stop retrying and alert your on-call team."]}]},{"$$mdtype":"Tag","name":"p","attributes":{},"children":[{"$$mdtype":"Tag","name":"strong","attributes":{},"children":["Example backoff schedule:"]}]},{"$$mdtype":"Tag","name":"div","attributes":{"className":"md-table-wrapper"},"children":[{"$$mdtype":"Tag","name":"table","attributes":{"className":"md"},"children":[{"$$mdtype":"Tag","name":"thead","attributes":{},"children":[{"$$mdtype":"Tag","name":"tr","attributes":{},"children":[{"$$mdtype":"Tag","name":"th","attributes":{"data-label":"Retry attempt"},"children":["Retry attempt"]},{"$$mdtype":"Tag","name":"th","attributes":{"data-label":"Base wait"},"children":["Base wait"]},{"$$mdtype":"Tag","name":"th","attributes":{"data-label":"With jitter (±20%)"},"children":["With jitter (±20%)"]}]}]},{"$$mdtype":"Tag","name":"tbody","attributes":{},"children":[{"$$mdtype":"Tag","name":"tr","attributes":{},"children":[{"$$mdtype":"Tag","name":"td","attributes":{},"children":["1"]},{"$$mdtype":"Tag","name":"td","attributes":{},"children":["2s"]},{"$$mdtype":"Tag","name":"td","attributes":{},"children":["1.6s – 2.4s"]}]},{"$$mdtype":"Tag","name":"tr","attributes":{},"children":[{"$$mdtype":"Tag","name":"td","attributes":{},"children":["2"]},{"$$mdtype":"Tag","name":"td","attributes":{},"children":["4s"]},{"$$mdtype":"Tag","name":"td","attributes":{},"children":["3.2s – 4.8s"]}]},{"$$mdtype":"Tag","name":"tr","attributes":{},"children":[{"$$mdtype":"Tag","name":"td","attributes":{},"children":["3"]},{"$$mdtype":"Tag","name":"td","attributes":{},"children":["8s"]},{"$$mdtype":"Tag","name":"td","attributes":{},"children":["6.4s – 9.6s"]}]},{"$$mdtype":"Tag","name":"tr","attributes":{},"children":[{"$$mdtype":"Tag","name":"td","attributes":{},"children":["4"]},{"$$mdtype":"Tag","name":"td","attributes":{},"children":["16s"]},{"$$mdtype":"Tag","name":"td","attributes":{},"children":["12.8s – 19.2s"]}]},{"$$mdtype":"Tag","name":"tr","attributes":{},"children":[{"$$mdtype":"Tag","name":"td","attributes":{},"children":["5"]},{"$$mdtype":"Tag","name":"td","attributes":{},"children":["32s"]},{"$$mdtype":"Tag","name":"td","attributes":{},"children":["25.6s – 38.4s"]}]},{"$$mdtype":"Tag","name":"tr","attributes":{},"children":[{"$$mdtype":"Tag","name":"td","attributes":{},"children":["6+"]},{"$$mdtype":"Tag","name":"td","attributes":{},"children":["60s (cap)"]},{"$$mdtype":"Tag","name":"td","attributes":{},"children":["48s – 72s"]}]}]}]}]},{"$$mdtype":"Tag","name":"Heading","attributes":{"level":3,"id":"use-a-maximum-retry-count","__idx":6},"children":["Use a maximum retry count"]},{"$$mdtype":"Tag","name":"p","attributes":{},"children":["Set a hard limit on the number of retries (for example, 5 attempts). After that limit is reached without a successful response, stop retrying, record the failure, and alert your team. Continuing to retry indefinitely can mask a persistent issue and delay investigation."]},{"$$mdtype":"Tag","name":"hr","attributes":{},"children":[]},{"$$mdtype":"Tag","name":"Heading","attributes":{"level":2,"id":"idempotency-and-safe-retries","__idx":7},"children":["Idempotency and safe retries"]},{"$$mdtype":"Tag","name":"p","attributes":{},"children":["Before retrying a mutating request (such as creating a payment), check whether the original request may have been received and processed by Ripple despite returning an error. A network timeout, for example, does not mean the payment was not created."]},{"$$mdtype":"Tag","name":"p","attributes":{},"children":[{"$$mdtype":"Tag","name":"strong","attributes":{},"children":["Best practice:"]}," Use a client-assigned ",{"$$mdtype":"Tag","name":"code","attributes":{},"children":["internalId"]}," or idempotency mechanism when creating payments. If you retry a payment creation request, include the same ",{"$$mdtype":"Tag","name":"code","attributes":{},"children":["internalId"]}," as the original request. Ripple will return the existing payment if it was already created, preventing duplicate payments."]},{"$$mdtype":"Tag","name":"Admonition","attributes":{"type":"warning","name":"Do not blindly retry payment creation"},"children":[{"$$mdtype":"Tag","name":"p","attributes":{},"children":["If you receive a timeout or connection error on a create payment request, do not immediately retry without first checking whether the payment was created. Use ",{"$$mdtype":"Tag","name":"code","attributes":{},"children":["GET /v3/payments"]}," with your ",{"$$mdtype":"Tag","name":"code","attributes":{},"children":["internalId"]}," to check before submitting again."]}]},{"$$mdtype":"Tag","name":"hr","attributes":{},"children":[]},{"$$mdtype":"Tag","name":"Heading","attributes":{"level":2,"id":"handling-authentication-errors","__idx":8},"children":["Handling authentication errors"]},{"$$mdtype":"Tag","name":"Heading","attributes":{"level":3,"id":"401-unauthorized-auth_001-auth_003","__idx":9},"children":["401 Unauthorized (AUTH_001, AUTH_003)"]},{"$$mdtype":"Tag","name":"p","attributes":{},"children":["A 401 error typically means your access token is expired or invalid. Access tokens have a 1-hour TTL."]},{"$$mdtype":"Tag","name":"p","attributes":{},"children":[{"$$mdtype":"Tag","name":"strong","attributes":{},"children":["Recommended handling:"]}]},{"$$mdtype":"Tag","name":"ol","attributes":{},"children":[{"$$mdtype":"Tag","name":"li","attributes":{},"children":["Generate a new access token using your ",{"$$mdtype":"Tag","name":"code","attributes":{},"children":["client_id"]}," and ",{"$$mdtype":"Tag","name":"code","attributes":{},"children":["client_secret"]},"."]},{"$$mdtype":"Tag","name":"li","attributes":{},"children":["Retry the original request with the new token."]},{"$$mdtype":"Tag","name":"li","attributes":{},"children":["Do not cache tokens beyond their ",{"$$mdtype":"Tag","name":"code","attributes":{},"children":["expires_in"]}," value."]}]},{"$$mdtype":"Tag","name":"p","attributes":{},"children":["For guidance on token generation and caching, see ",{"$$mdtype":"Tag","name":"a","attributes":{"href":"/products/payments-direct-2/api-docs/best-practices/authentication"},"children":["Authentication"]},"."]},{"$$mdtype":"Tag","name":"Heading","attributes":{"level":3,"id":"403-forbidden-auth_002","__idx":10},"children":["403 Forbidden (AUTH_002)"]},{"$$mdtype":"Tag","name":"p","attributes":{},"children":["A 403 error means your token is valid but lacks the required scopes for the requested operation."]},{"$$mdtype":"Tag","name":"p","attributes":{},"children":[{"$$mdtype":"Tag","name":"strong","attributes":{},"children":["Recommended handling:"]}]},{"$$mdtype":"Tag","name":"ul","attributes":{},"children":[{"$$mdtype":"Tag","name":"li","attributes":{},"children":["Do not retry with the same token. A new token with the same credentials will have the same scopes."]},{"$$mdtype":"Tag","name":"li","attributes":{},"children":["Review the required scopes for the operation in the API reference."]},{"$$mdtype":"Tag","name":"li","attributes":{},"children":["Contact Ripple technical support if you believe your credentials should have the required permissions."]}]},{"$$mdtype":"Tag","name":"Heading","attributes":{"level":3,"id":"403-unauthorized-auth_051","__idx":11},"children":["403 Unauthorized (AUTH_051)"]},{"$$mdtype":"Tag","name":"p","attributes":{},"children":["AUTH_051 occurs when a request references a payment created by a different organization. This is a permanent error. Do not retry."]},{"$$mdtype":"Tag","name":"hr","attributes":{},"children":[]},{"$$mdtype":"Tag","name":"Heading","attributes":{"level":2,"id":"handling-payment-failures","__idx":12},"children":["Handling payment failures"]},{"$$mdtype":"Tag","name":"p","attributes":{},"children":["Payment failures are distinct from API errors. A payment failure occurs after a payment is created successfully (HTTP 201) but later transitions to a terminal state of ",{"$$mdtype":"Tag","name":"code","attributes":{},"children":["FAILED"]},", ",{"$$mdtype":"Tag","name":"code","attributes":{},"children":["DECLINED"]},", or ",{"$$mdtype":"Tag","name":"code","attributes":{},"children":["RETURNED"]},". These are not errors in the API response. They are ",{"$$mdtype":"Tag","name":"code","attributes":{},"children":["paymentState"]}," values you observe when polling or receiving webhooks."]},{"$$mdtype":"Tag","name":"Admonition","attributes":{"type":"info","name":"How to detect a payment failure"},"children":[{"$$mdtype":"Tag","name":"p","attributes":{},"children":["Payment failure details, including the error code and reason, are available on the payment object at ",{"$$mdtype":"Tag","name":"code","attributes":{},"children":["GET /v3/payments/{paymentId}"]}," after the payment reaches a terminal state. Webhook payloads include the new ",{"$$mdtype":"Tag","name":"code","attributes":{},"children":["paymentState"]}," but not the error code. Always fetch the full payment record to get failure details."]}]},{"$$mdtype":"Tag","name":"Heading","attributes":{"level":3,"id":"terminal-states","__idx":13},"children":["Terminal states"]},{"$$mdtype":"Tag","name":"div","attributes":{"className":"md-table-wrapper"},"children":[{"$$mdtype":"Tag","name":"table","attributes":{"className":"md"},"children":[{"$$mdtype":"Tag","name":"thead","attributes":{},"children":[{"$$mdtype":"Tag","name":"tr","attributes":{},"children":[{"$$mdtype":"Tag","name":"th","attributes":{"data-label":"State"},"children":["State"]},{"$$mdtype":"Tag","name":"th","attributes":{"data-label":"Retryable?"},"children":["Retryable?"]},{"$$mdtype":"Tag","name":"th","attributes":{"data-label":"Action"},"children":["Action"]}]}]},{"$$mdtype":"Tag","name":"tbody","attributes":{},"children":[{"$$mdtype":"Tag","name":"tr","attributes":{},"children":[{"$$mdtype":"Tag","name":"td","attributes":{},"children":[{"$$mdtype":"Tag","name":"code","attributes":{},"children":["FAILED"]}]},{"$$mdtype":"Tag","name":"td","attributes":{},"children":["Possibly"]},{"$$mdtype":"Tag","name":"td","attributes":{},"children":["Fetch the payment record to get the error code. Check the ",{"$$mdtype":"Tag","name":"a","attributes":{"href":"/products/payments-direct-2/api-docs/error-codes/api-payment-failures"},"children":["API payment failures reference"]}," and ",{"$$mdtype":"Tag","name":"a","attributes":{"href":"/products/payments-direct-2/api-docs/error-codes/api-errors"},"children":["API error codes reference"]}," for the specific code. Some ",{"$$mdtype":"Tag","name":"code","attributes":{},"children":["FAILED"]}," states are caused by transient issues and can be retried with a new payment; others indicate a permanent condition."]}]},{"$$mdtype":"Tag","name":"tr","attributes":{},"children":[{"$$mdtype":"Tag","name":"td","attributes":{},"children":[{"$$mdtype":"Tag","name":"code","attributes":{},"children":["DECLINED"]}]},{"$$mdtype":"Tag","name":"td","attributes":{},"children":["Not until resolved"]},{"$$mdtype":"Tag","name":"td","attributes":{},"children":["Fetch the payment record to get the error code. ",{"$$mdtype":"Tag","name":"code","attributes":{},"children":["DECLINED"]}," usually indicates a business rule violation or account condition (insufficient balance, credit limit, etc.) that must be resolved before resubmitting."]}]},{"$$mdtype":"Tag","name":"tr","attributes":{},"children":[{"$$mdtype":"Tag","name":"td","attributes":{},"children":[{"$$mdtype":"Tag","name":"code","attributes":{},"children":["RETURNED"]}]},{"$$mdtype":"Tag","name":"td","attributes":{},"children":["Consult Ripple"]},{"$$mdtype":"Tag","name":"td","attributes":{},"children":["The payment was returned by a downstream institution after completing. This is not a retry scenario. Contact Ripple technical support to investigate the return reason."]}]}]}]}]},{"$$mdtype":"Tag","name":"p","attributes":{},"children":["For a full list of payment failure codes and their descriptions, see ",{"$$mdtype":"Tag","name":"a","attributes":{"href":"/products/payments-direct-2/api-docs/error-codes/api-payment-failures"},"children":["API payment failures"]},"."]},{"$$mdtype":"Tag","name":"p","attributes":{},"children":["For background on payment states and the payment lifecycle, see ",{"$$mdtype":"Tag","name":"a","attributes":{"href":"/products/payments-direct-2/api-docs/concepts/payment-states"},"children":["Payment states"]},"."]},{"$$mdtype":"Tag","name":"hr","attributes":{},"children":[]},{"$$mdtype":"Tag","name":"Heading","attributes":{"level":2,"id":"what-to-log-and-monitor","__idx":14},"children":["What to log and monitor"]},{"$$mdtype":"Tag","name":"p","attributes":{},"children":["Log the following fields from every error response:"]},{"$$mdtype":"Tag","name":"ul","attributes":{},"children":[{"$$mdtype":"Tag","name":"li","attributes":{},"children":[{"$$mdtype":"Tag","name":"code","attributes":{},"children":["code"]}," — the specific error code; use this for alerting rules and dashboards"]},{"$$mdtype":"Tag","name":"li","attributes":{},"children":[{"$$mdtype":"Tag","name":"code","attributes":{},"children":["type"]}," — the error category; use this to route to the correct handler"]},{"$$mdtype":"Tag","name":"li","attributes":{},"children":[{"$$mdtype":"Tag","name":"code","attributes":{},"children":["status"]}," — the HTTP status code"]},{"$$mdtype":"Tag","name":"li","attributes":{},"children":[{"$$mdtype":"Tag","name":"code","attributes":{},"children":["timestamp"]}," — the time the error occurred in the upstream system"]},{"$$mdtype":"Tag","name":"li","attributes":{},"children":["The API endpoint and HTTP method that returned the error"]},{"$$mdtype":"Tag","name":"li","attributes":{},"children":["Your request ID or correlation ID (if your integration generates one)"]}]},{"$$mdtype":"Tag","name":"Heading","attributes":{"level":3,"id":"alerting-recommendations","__idx":15},"children":["Alerting recommendations"]},{"$$mdtype":"Tag","name":"div","attributes":{"className":"md-table-wrapper"},"children":[{"$$mdtype":"Tag","name":"table","attributes":{"className":"md"},"children":[{"$$mdtype":"Tag","name":"thead","attributes":{},"children":[{"$$mdtype":"Tag","name":"tr","attributes":{},"children":[{"$$mdtype":"Tag","name":"th","attributes":{"data-label":"Condition"},"children":["Condition"]},{"$$mdtype":"Tag","name":"th","attributes":{"data-label":"Alert priority"},"children":["Alert priority"]}]}]},{"$$mdtype":"Tag","name":"tbody","attributes":{},"children":[{"$$mdtype":"Tag","name":"tr","attributes":{},"children":[{"$$mdtype":"Tag","name":"td","attributes":{},"children":["Any ",{"$$mdtype":"Tag","name":"code","attributes":{},"children":["CONFIGURATION_ERROR"]}," (",{"$$mdtype":"Tag","name":"code","attributes":{},"children":["CFG_"]},")"]},{"$$mdtype":"Tag","name":"td","attributes":{},"children":["High — these require Ripple involvement and will not self-resolve"]}]},{"$$mdtype":"Tag","name":"tr","attributes":{},"children":[{"$$mdtype":"Tag","name":"td","attributes":{},"children":["Repeated ",{"$$mdtype":"Tag","name":"code","attributes":{},"children":["SYSTEM_ERROR"]}," (",{"$$mdtype":"Tag","name":"code","attributes":{},"children":["SYS_"]},") from the same endpoint"]},{"$$mdtype":"Tag","name":"td","attributes":{},"children":["Medium — investigate after retry budget is exhausted"]}]},{"$$mdtype":"Tag","name":"tr","attributes":{},"children":[{"$$mdtype":"Tag","name":"td","attributes":{},"children":[{"$$mdtype":"Tag","name":"code","attributes":{},"children":["AUTH_ERROR"]}," 403 (",{"$$mdtype":"Tag","name":"code","attributes":{},"children":["AUTH_002"]},", ",{"$$mdtype":"Tag","name":"code","attributes":{},"children":["AUTH_051"]},")"]},{"$$mdtype":"Tag","name":"td","attributes":{},"children":["Medium — may indicate a configuration change or credential scope issue"]}]},{"$$mdtype":"Tag","name":"tr","attributes":{},"children":[{"$$mdtype":"Tag","name":"td","attributes":{},"children":["Sustained ",{"$$mdtype":"Tag","name":"code","attributes":{},"children":["USER_ERROR"]}," 402 (",{"$$mdtype":"Tag","name":"code","attributes":{},"children":["USR_062"]},"–",{"$$mdtype":"Tag","name":"code","attributes":{},"children":["USR_067"]},")"]},{"$$mdtype":"Tag","name":"td","attributes":{},"children":["Medium — indicates an account condition (balance, limits, invoice) requiring attention"]}]}]}]}]},{"$$mdtype":"Tag","name":"hr","attributes":{},"children":[]},{"$$mdtype":"Tag","name":"Heading","attributes":{"level":2,"id":"next-steps","__idx":16},"children":["Next steps"]},{"$$mdtype":"Tag","name":"ul","attributes":{},"children":[{"$$mdtype":"Tag","name":"li","attributes":{},"children":["For the complete list of error codes, descriptions, and HTTP statuses, see ",{"$$mdtype":"Tag","name":"a","attributes":{"href":"/products/payments-direct-2/api-docs/error-codes/api-errors"},"children":["API error codes"]},"."]},{"$$mdtype":"Tag","name":"li","attributes":{},"children":["For payment-specific failure codes, see ",{"$$mdtype":"Tag","name":"a","attributes":{"href":"/products/payments-direct-2/api-docs/error-codes/api-payment-failures"},"children":["API payment failures"]},"."]},{"$$mdtype":"Tag","name":"li","attributes":{},"children":["For guidance on tracking payment state changes without polling, see ",{"$$mdtype":"Tag","name":"a","attributes":{"href":"/products/payments-direct-2/api-docs/best-practices/notification-webhooks"},"children":["Notification webhooks"]},"."]},{"$$mdtype":"Tag","name":"li","attributes":{},"children":["To poll for payment updates instead of using webhooks, see ",{"$$mdtype":"Tag","name":"a","attributes":{"href":"/products/payments-direct-2/api-docs/best-practices/polling"},"children":["Polling"]},"."]},{"$$mdtype":"Tag","name":"li","attributes":{},"children":["For access token generation and caching details, see ",{"$$mdtype":"Tag","name":"a","attributes":{"href":"/products/payments-direct-2/api-docs/best-practices/authentication"},"children":["Authentication"]},"."]},{"$$mdtype":"Tag","name":"li","attributes":{},"children":["For payment state definitions and lifecycle details, see ",{"$$mdtype":"Tag","name":"a","attributes":{"href":"/products/payments-direct-2/api-docs/concepts/payment-states"},"children":["Payment states"]},"."]}]}]},"headings":[{"value":"Error handling and retry strategy","id":"error-handling-and-retry-strategy","depth":1},{"value":"Classify before you act","id":"classify-before-you-act","depth":2},{"value":"Error type reference","id":"error-type-reference","depth":3},{"value":"Transient vs. permanent errors","id":"transient-vs-permanent-errors","depth":2},{"value":"Retry strategy","id":"retry-strategy","depth":2},{"value":"Exponential backoff with jitter","id":"exponential-backoff-with-jitter","depth":3},{"value":"Use a maximum retry count","id":"use-a-maximum-retry-count","depth":3},{"value":"Idempotency and safe retries","id":"idempotency-and-safe-retries","depth":2},{"value":"Handling authentication errors","id":"handling-authentication-errors","depth":2},{"value":"401 Unauthorized (AUTH_001, AUTH_003)","id":"401-unauthorized-auth_001-auth_003","depth":3},{"value":"403 Forbidden (AUTH_002)","id":"403-forbidden-auth_002","depth":3},{"value":"403 Unauthorized (AUTH_051)","id":"403-unauthorized-auth_051","depth":3},{"value":"Handling payment failures","id":"handling-payment-failures","depth":2},{"value":"Terminal states","id":"terminal-states","depth":3},{"value":"What to log and monitor","id":"what-to-log-and-monitor","depth":2},{"value":"Alerting recommendations","id":"alerting-recommendations","depth":3},{"value":"Next steps","id":"next-steps","depth":2}],"frontmatter":{"seo":{"title":"Error handling and retry strategy"}},"lastModified":"2026-03-31T03:43:45.000Z","pagePropGetterError":{"message":"","name":""}},"slug":"/products/payments-direct-2/api-docs/best-practices/error-handling","userData":{"isAuthenticated":false,"teams":["anonymous"]},"isPublic":true}