# Payment states Every payment in Ripple Payments Direct 2.0 moves through a defined set of **states** from the moment a quote is accepted to final settlement. Understanding these states is fundamental to building a reliable integration. They determine when funds move, when an error has occurred, and what action (if any) your system should take next. ## What you'll learn - What each payment state means and when it occurs. - How to follow the normal payment lifecycle from quote to completion. - The key differences between `FAILED`, `DECLINED`, and `RETURNED`. - How funds in your account are affected at each state. - How to track state changes using the API and webhooks. ## Payment states reference The `paymentState` field appears on every payment object and state transition record. The following states are currently defined: | State | Description | Terminal? | | --- | --- | --- | | `INITIATED` | The payment has been submitted and is awaiting validation by Ripple. | No | | `VALIDATING` | Ripple is validating the payment details and reserving funds from the originator's available balance. | No | | `TRANSFERRING` | The payment is being processed and funds are moving through the network toward the beneficiary. The source amount has been debited from the originator's account. | No | | `COMPLETED` | The payment has completed and the beneficiary has received the funds. | **Yes** | | `FAILED` | The payment could not be completed. Any funds previously reserved to complete the payment are released back to the available balance. | **Yes** | | `RETURNED` | The payment was returned by a downstream institution after initially completing. Funds that were previously reserved and debited are returned and added back to the available balance. | **Yes** | | `DECLINED` | The payment was declined due to user input errors or business rule violations. Any funds previously reserved to complete the payment are released back to the available balance. | **Yes** | Future states Additional states may be introduced in the future. Design your integration to handle unknown payment states gracefully. Do not fail hard on unexpected `paymentState` values. ## The payment lifecycle The typical, successful lifecycle of a payment follows this progression: ![Payment lifecycle](/assets/payment-states-rpd2-happy-path.c0fb43a0a62e223b1e76571839c9ec581c9d8c21ac59ed41b1aaa61bd19d64d1.a69a9225.png) A payment enters `INITIATED` as soon as it is submitted by accepting a valid quote. It then moves through `VALIDATING` while Ripple checks payment details and reserves funds. When validation succeeds, the payment enters `TRANSFERRING` as funds move to the beneficiary, and finally reaches `COMPLETED` when settlement is confirmed. ### Terminal states A terminal state means the payment lifecycle has ended and no further transitions will occur. There are four terminal states: - **`COMPLETED` -** the successful outcome. - **`FAILED` -** a processing or system error prevented completion. - **`DECLINED` -** a validation or business rule error prevented completion. - **`RETURNED` -** the payment completed but was subsequently reversed by a downstream institution. Once a payment reaches a terminal state, the `paymentId` can no longer be used to initiate further activity. If you need to retry, you must create a new quote and payment. ## How funds are affected at each state The state of a payment determines what has happened to the originator's funds: | State | Fund status | | --- | --- | | `INITIATED` | No funds reserved yet. The payment has been submitted but not yet validated. | | `VALIDATING` | Funds are **reserved** from the available balance. The originator cannot use reserved funds for other payments. | | `TRANSFERRING` | Funds are **debited**. The payment is in flight; the source amount has left the originator's account. | | `COMPLETED` | Funds remain debited. Settlement is confirmed. | | `FAILED` | Reserved funds are **released** back to the available balance. No debit occurred. | | `DECLINED` | Reserved funds are **released** back to the available balance. No debit occurred. | | `RETURNED` | Debited funds are **credited back** to the available balance. Ripple handles the return automatically. | ## Understanding FAILED, DECLINED, and RETURNED These three terminal states all indicate that a payment did not reach the beneficiary, but they have distinct causes and implications: ### FAILED `FAILED` indicates that Ripple Payments could not complete the payment due to a processing or system error, for example, a network failure, a timeout with a downstream rail, or an internal service error. The failure is not caused by an error in the payment data you provided. - **Funds**: Reserved funds are released. No debit occurred. - **What to do**: Check the `errors[]` field on the payment object for a reason code, then consider retrying the payment with a new quote after a delay. ### DECLINED `DECLINED` indicates that the payment was rejected due to user input errors or a business rule violation, for example, invalid beneficiary account details, a compliance rule block, or a field that fails downstream validation. - **Funds**: Reserved funds are released. No debit occurred. - **What to do**: Review the `errors[]` field for a specific error code and description. Correct the underlying issue (for example, update the beneficiary's financial instrument) before retrying. ### RETURNED `RETURNED` indicates that the payment initially reached `COMPLETED` (funds were debited and settlement was confirmed) but was subsequently returned by a downstream institution or payout partner. For example, the destination bank may have rejected the transfer after it was processed, or a compliance review may have triggered a return. - **Funds**: Debited funds are credited back to your available balance automatically by Ripple. - **What to do**: Check the `errors[]` field on the payment object for the return reason code. In many cases, you will need to correct the beneficiary's details before retrying. No manual fund recovery action is needed. Note Webhook notifications for `PAYMENT_STATE_TRANSITION` events do not include error details such as reason codes. To retrieve error details for `FAILED`, `DECLINED`, or `RETURNED` payments, call `GET /v3/payments/{paymentId}` and inspect the `errors[]` array. ## Tracking state changes ### Using the state transitions endpoint To retrieve the full history of state changes for a payment, use: ``` GET /v3/payments/{paymentId}/state-transitions ``` Each record in the response includes: - `updatedFrom` - the state before the transition - `updatedTo` - the state after the transition - `updatedAt` - the timestamp of the transition **Example response (excerpt)** ```json [ { "updatedFrom": "INITIATED", "updatedTo": "VALIDATING", "updatedAt": "2026-03-01T14:22:10.123Z" }, { "updatedFrom": "VALIDATING", "updatedTo": "TRANSFERRING", "updatedAt": "2026-03-01T14:22:18.456Z" }, { "updatedFrom": "TRANSFERRING", "updatedTo": "COMPLETED", "updatedAt": "2026-03-01T14:22:45.789Z" } ] ``` ### Using webhooks Ripple Payments Direct 2.0 sends a `PAYMENT_STATE_TRANSITION` webhook notification each time a payment changes state. This is the recommended approach for monitoring payment progress in production integrations, as it eliminates the need to poll. The webhook payload uses a "thin-plus" design: it includes the `paymentId` and the new `paymentState`, along with additional context fields such as `sourceCurrency`, `sourceAmount`, `destinationCurrency`, `payoutAmount`, and `beneficiaryToken`. **Example webhook payload** ```json { "id": "4d3f90cf-b70f-5ff1-827a-f8aa9cf84ab9", "eventType": "PAYMENT_STATE_TRANSITION", "eventVersion": 1, "eventData": { "paymentId": "5ce2c433-a96d-48d0-8857-02637a60abf4", "paymentState": "COMPLETED", "sourceCurrency": "USD", "sourceAmount": 100.00, "destinationCurrency": "BRL", "payoutAmount": 518.50, "beneficiaryToken": "cb207125-73a7-4a94-8502-a7780f1cae78", "createdAt": "2026-03-01T14:20:00.000Z", "expiresAt": "2026-04-30T14:20:00.000Z" }, "createDate": "2026-03-01T14:22:46.000Z" } ``` Out-of-order delivery Webhook delivery order is not guaranteed. Notifications may arrive out of sequence if retries occur. Always use `updatedAt` timestamps from the state transitions endpoint (not webhook arrival order) to determine the authoritative state sequence. ## Designing a robust state handler When building integration logic that reacts to payment states, follow these guidelines: - **Treat all terminal states explicitly.** Handle `COMPLETED`, `FAILED`, `DECLINED`, and `RETURNED` as distinct outcomes with different downstream behavior. - **Do not assume state order from webhooks.** Use `GET /v3/payments/{paymentId}/state-transitions` to confirm the authoritative sequence if delivery order matters. - **For `FAILED` and `DECLINED`, fetch the full payment object** to retrieve error details before deciding to retry. - **Implement idempotency on state handlers.** Webhooks may be delivered more than once. Your handler should be safe to call repeatedly for the same `paymentId` and `paymentState`. - **Handle unknown states gracefully.** Log and alert on unexpected state values, but do not discard the event. ## Relevant API operations | Operation | Method | Path | | --- | --- | --- | | Create a payment | POST | `/v3/payments` | | Get a payment by ID | GET | `/v3/payments/{paymentId}` | | Get state transitions by payment ID | GET | `/v3/payments/{paymentId}/state-transitions` | | Search payments | POST | `/v3/payments/filter` | ## Next steps - To learn how to create a payment and handle its lifecycle end-to-end, see [Create a payment](/products/payments-direct-2/api-docs/tutorials/create-a-payment). - To understand what happens when a payment is returned and how funds are recovered, see [Payment returns](/products/payments-direct-2/api-docs/concepts/payment-returns). - To set up webhooks for real-time state transition notifications, see [Notification webhooks](/products/payments-direct-2/api-docs/best-practices/notification-webhooks).