# Send a payment This page is for developers of new applications that send RippleNet payments. It is recommended that new integrations use the *orchestration* API operations that make it easy to initiate and fulfill a payment, and to obtain notifications about payment status. The goals of this topic are: * Describe the high-level payment flow for senders. * Provide a tutorial to send one test payment. * Outline the options for getting notifications about payments. ## Overview Note Before you read this tutorial, make sure you're familiar with the concepts presented in the [Payment flow](/products/payments-odl/introduction/concepts/payment-flow) article. ### Payment flow for senders — automatic quote acceptance The following describes the flow of tasks a sender must complete to successfully send a payment: 1. **Get access token** — All RippleNet API operations (except the Authentication operation itself) must include a valid access token in the `Authorization` header of each request. This is described in [Authentication](/products/payments-odl/api-docs/ripplenet/best-practices/authentication). 2. **Create payment** — A single call to the [*Create orchestration payment*](/products/payments-odl/api-docs/ripplenet/reference/openapi/orchestration-payments/createorchestrationpayment) operation lets you specify all the fields needed to initiate and fulfill a new payment, including quote retrieval and approval, and payment instructions, including the identifying information of the originator and beneficiary of the payment. 3. **Check payment status** — You can check the status of your payment, by *polling*, or using use a *webhook*. These are described below. 4. **Additional actions (if required)** — In case of an exception in payment processing, your client application can indicate the next course of action using the [*Post action to orchestration payment*](/products/payments-odl/api-docs/ripplenet/reference/openapi/orchestration-payments/sendorchestrationpaymentaction) API operation. ### Payment flow for senders — manual quote acceptance Ordinarily, *Create orchestration payment* takes care of the steps of fetching and approving a quote for you. All you need to do as the **sender** is execute the *Create orchestration payment* operation, and this sets the status of the new payment to `ACCEPTED`, ready for your **receiver** counterparty to lock the payment, which initiates the settlement process automatically. However, if you prefer, you can choose to control the process of fetching and approving the quote. The process is exactly the same as described above, except instead of calling *Create orchestration payment*, you first call *Create quote collection* to fetch the quote, and then the *Accept orchestration payment* operation. The rest of the payment flow is the same. 1. **Get Access Token** — All RippleNet API operations (except the Authentication operation itself) must include a valid access token in the `Authorization` header of each request. This is described in [Authentication](/products/payments-odl/api-docs/ripplenet/best-practices/authentication). 2. **Fetch quote** — The **sender** supplies payment parameters with a [*Create quote collection*](/products/payments-odl/api-docs/ripplenet/reference/openapi/quotes/createquotecollection) request for all available quotes from RippleNet. Typically you will chose the first of these. 3. **Accept payment** — A call to [*Accept orchestration payment*](/products/payments-odl/api-docs/ripplenet/reference/openapi/orchestration-payments/acceptorchestrationpayment) lets you specify all the fields needed to first accept the quote, and then initiate and fulfill a new payment, including the identifying information of the originator and beneficiary of the payment. 4. **Check payment status** — You can check the status of your payment, using either *webhooks* (recommended) or *polling*. These are described below. 5. **Additional actions (if required)** — In case of an exception in payment processing, your client application can indicate the next course of action via the [*Post action to orchestration payment*](/products/payments-odl/api-docs/ripplenet/reference/openapi/orchestration-payments/sendorchestrationpaymentaction) API operation. ### The orchestration API operations To complete a payment, both **senders** and **receivers** require a very small set of API operations that use *orchestration* to simplify the workflow. These orchestration operations not only simplify the process of completing a payment, but they also support *webhooks* for delivering notifications about payment states. Note about '_orchestration_' and '_templates_' The term *orchestration* refers to a pre-defined sequence of actions that occur during a payment flow. The payment flow is governed by an *orchestration template* (sometimes referred to as a *workflow template*) that defines the action that the RippleNet service takes automatically at each stage of the payment process. Orchestration templates are pre-defined by Ripple, and different payment flows are represented by different templates. There are three categories of orchestration operations: * [Orchestration payments](/products/payments-odl/api-docs/ripplenet/reference/openapi/orchestration-payments) — These operations are primarily of use by **senders** for initiating and and working with payments. * [Orchestration notifications](/products/payments-odl/api-docs/ripplenet/reference/openapi/orchestration-payments/getorchestrationpaymentnotifications) — These operations are used both by **senders** and **receivers** to get notifications about payments and payment states. * [Orchestration actions](/products/payments-odl/api-docs/ripplenet/reference/openapi/orchestration-payments/sendorchestrationpaymentaction) — This category consists of a single API operation, [*Post action to orchestration payment*](/products/payments-odl/api-docs/ripplenet/reference/openapi/orchestration-payments/sendorchestrationpaymentaction), that lets you perform various webhook-enabled actions on payments. For example, **receivers** use this API operation both to lock and to complete a payment. ### Check payment status To check the status of your payment, you first need to receive notification of a status change. The recommended way to do this is set up *webhooks* notifications, to have RippleNet post to a previously registered callback URL. The body of the post contains a message ID (`uuid`) that you can use with a call to [*Get orchestration notification*](/products/payments-odl/api-docs/ripplenet/reference/openapi/orchestration-payments/getorchestrationpaymentnotificationbyuuid) to retrieve the full notification details about the status of your payment. For more information, see [Webhooks](/products/payments-odl/api-docs/ripplenet/best-practices/webhooks) under Best Practices. Alternatively, if webhook notifications are not an option for you, you can use *polling* — repeatedly calling a *Get orchestration notifications* operation, until your payment appears in the response. For more information, see [Polling](/products/payments-odl/api-docs/ripplenet/best-practices/polling-basic). ## Send a payment — instructions ### Prerequisites Before you begin, you must have the following: * If you plan to use webhook notifications, your callback URL needs to be registered with RippleNet. Contact your CPE for details. * Access to your RippleNet test instance. * Access to RippleNet Home. * Access to a [counterparty](/products/payments-odl/glossary#counterparty) instance; either through an *ODL Test Mode* environment that Ripple provides, or a counterparty's UAT instance. * Credentials to authenticate API authorization to your RippleNet test instance. * A way to make API requests and view the responses. For example, you can use a REST client like Postman, or **cURL** from the command line. ### Get access token To access all RippleNet API operations (except the Authentication operation itself), you need a valid access token. See [Authentication](/products/payments-odl/api-docs/ripplenet/best-practices/authentication). ### Create the payment To create a payment using orchestration, you have two options: * You can create the payment using automatic quote acceptance; or * You can get a quote collection and examine the quote before accepting it manually. These two options are described next. #### Create the payment using automatic quote acceptance If you want to auto-accept the quote, just call the [*Create orchestration payment*](/products/payments-odl/api-docs/ripplenet/reference/openapi/orchestration-payments/createorchestrationpayment) API operation as follows: ``` POST /v4/orchestration/payment HTTP/1.1 Host: aclient.i.ripple.com Content-Type: application/json Authorization: Bearer ``` In the body of the POST call, you specify all the parameters needed to fetch and accept the quote, and to settle the payment when the **receiver** locks the payment. details summary Click to view the i Create orchestration payment body ... ```json { "sender_end_to_end_id": "19999999999-012", "sending_address": "dev.bfox01.sgd", "receiving_address": "dev.bfox02.sgd", "currency": "SGD", "amount": "10", "paymentMethod": "CASH", "quote_type": "SENDER_AMOUNT", "user_info" : { "ChrgBr" : "SHAR", "Cdtr" : { "Id" : "8675309", "Nm" : "John3" }, "Dbtr" : { "Id" : "8675309", "Nm" : "Jenny" } } } ``` Each of these required parameters is described below. If RippleNet successfully receives your *Create orchestration payment* request, its response will simply confirm the unique `sender_end_to_end_id` that you provided in the API call. ``` { "sender_end_to_end_id": "19999999999-012" } ``` #### Create the payment and manually accept the quote If you prefer to fetch and accept the quote manually, first call the [*Create orchestration payment*](/products/payments-odl/api-docs/ripplenet/reference/openapi/orchestration-payments/createorchestrationpayment) operation, followed by the [*Accept orchestration payment*](/products/payments-odl/api-docs/ripplenet/reference/openapi/orchestration-payments/acceptorchestrationpayment) operation, as follows: ``` POST /v4/quote_collections HTTP/1.1 Host: aclient.i.ripple.com Content-Type: application/json Authorization: Bearer ``` In the body of the POST call, you specify all the parameters need to fetch the quote: details summary Click to view the i Create quote collection body ... ```json { "sending_address": "dev.bfox01.sgd", "receiving_address": "dev.bfox02.sgd", "currency": "SGD", "amount": "10", "paymentMethod": "CASH", "quote_type": "SENDER_AMOUNT", } ``` The response from the *Create quote collection* operation contains all the information about the quote, including the `quote_id` you need to accept the quote. details summary Click to view the response from i Create quote collection call ... ```json { "quote_collection_id": "23bfaac6-1dc6-4f41-8d8a-58859301bebf", "quotes": [ { "quote_id": "02d6cfe6-6ba8-4d9e-a52b-452d934af952", "created_at": "2022-09-13T00:12:58.178Z", "expires_at": "2022-09-13T01:12:58.178Z", "type": "SENDER_AMOUNT", "price_guarantee": "FIRM", "sender_address": "trans_usd_alpha@rn.dev.apac.alpha", "receiver_address": "trans_usd_beta@rn.dev.apac.beta", "amount": "25", "currency_code": "USD", "currency_code_filter": null, "service_type": null, "quote_elements": [ { "quote_element_id": "0787550e-b547-4d58-ab48-19e426398fc7", "quote_element_type": "TRANSFER", "quote_element_order": "1", "sender_address": "trans_usd_alpha@rn.dev.apac.alpha", "receiver_address": "alias_usd_alpha@rn.dev.apac.alpha", "sending_amount": "25.00", "receiving_amount": "25.00", "sending_fee": "0.00", "receiving_fee": "0.00", "sending_currency_code": null, "receiving_currency_code": null, "fx_rate": null, "transfer_currency_code": "USD" }, { "quote_element_id": "4eb4a084-0f64-48e8-8b1e-3a7d2c73d18b", "quote_element_type": "TRANSFER", "quote_element_order": "2", "sender_address": "alias_usd_beta@rn.dev.apac.beta", "receiver_address": "trans_usd_beta@rn.dev.apac.beta", "sending_amount": "25.00", "receiving_amount": "25.00", "sending_fee": "0.00", "receiving_fee": "0.00", "sending_currency_code": null, "receiving_currency_code": null, "fx_rate": null, "transfer_currency_code": "USD" } ], "liquidity_warning": null, "payment_method": null } ], "quote_errors": [] } ``` Once you have the `quote_id` for the quote, call [*Accept orchestration payment*](/products/payments-odl/api-docs/ripplenet/reference/openapi/orchestration-payments/acceptorchestrationpayment) to finish creating the payment: ``` POST /v4/orchestration/payment/accept HTTP/1.1 Host: aclient.i.ripple.com Content-Type: application/json Authorization: Bearer ``` And in the body of the POST call, you specify the `quote_id` needed to accept the quote, and the remaining parameters needed to settle the payment when the **receiver** locks the quote: details summary Click to view i Accept orchestration payment body ... ```json { "sender_end_to_end_id": "19999999999-012", "quote_id": "02d6cfe6-6ba8-4d9e-a52b-452d934af952", "user_info" : { "ChrgBr" : "SHAR", "Cdtr" : { "Id" : "8675309", "Nm" : "John3" }, "Dbtr" : { "Id" : "8675309", "Nm" : "Jenny" } } } ``` These required parameters are described below: If RippleNet successfully receives your *Accept orchestration payment* request, its response will simply confirm the unique `sender_end_to_end_id` that you provided in the API call. ```json { "sender_end_to_end_id": "19999999999-012" } ``` #### Required information As the *Create orchestration payment* operation is essentially a combination of the *Create quote collection* and *Accept orchestration payment* operations, the three operations share a number of parameters that must be supplied in the body of the POST request. This table summarizes which parameters are required by each operation. | **Parameter** | Required by*Create orchestration payment* | Required by*Create quote collection* | Required by*Accept orchestration payment* | | --- | --- | --- | --- | | `sender_end_to_end_id` | ✅ | | ✅ | | `sending_address` | ✅ | ✅ | | | `receiving_address` | ✅ | ✅ | | | `amount` | ✅ | ✅ | | | `currency` | ✅ | ✅ | | | `quote type` | ✅ | ✅ | | | `payment method` | ✅ | ✅ | | | `user_info` | ✅ | | ✅ | | `quote_id` | | | ✅ | Here is a description of each of these parameters: * `sender_end_to_end_id` — Any [randomly generated UUID](https://www.uuidgenerator.net/guid). This is to allow your client application to distinguish this payment from any others that it has created. * `sending_address` — RippleNet account name and address of the **sender**, in the format `{ACCOUNT_NAME}@{RIPPLENET_ADDRESS}`. For example, `new_york@rn.usa.north_bank.new_york`. For more information, see [RippleNet Addressing Scheme](/products/payments-odl/api-docs/ripplenet/resources/ripplenet-addressing-scheme). * `receiving_address` — RippleNet address of the destination partner. This is not the **beneficiary**'s account. It is the address of the last RippleNet member institution that processes the final leg of the payment. For example, the institution that provides the payment delivery over local rails. The field should use the following format: `{ACCOUNT_NAME}@{RIPPLENET_ADDRESS}`. For more information, see [RippleNet Addressing Scheme](/products/payments-odl/api-docs/ripplenet/resources/ripplenet-addressing-scheme). * `amount` — The amount of the payment. If you specify `SENDER_AMOUNT` for `quote_type`, this amount is debited from your account. If you specify `RECEIVER_AMOUNT` for `quote_type`, this amount is delivered to the **beneficiary**. * `currency` — Currency code of the amount to be sent or received, depending on the `quote_type` value. If `quote_type` is set to `SENDER_AMOUNT` or `SENDER_INSTITUTION_AMOUNT`, this is the currency of the amount to be sent. If `quote_type` is set to `RECEIVER_AMOUNT` or `RECEIVER_INSTITUTION_AMOUNT`, this is the currency of the amount to be received. Use a valid [ISO 2117](https://en.wikipedia.org/wiki/ISO_4217#Active_codes) currency code. * `quote_type` — Specifies how RippleNet calculates the quote. Valid values are `SENDER_AMOUNT`, `RECEIVER_AMOUNT`, `SENDER_INSTITUTION_AMOUNT`, or `RECEIVER_INSTITUTION_AMOUNT`. + To create a quote based on the amount the **sender** (on behalf of the **originator**) wants to send, set to `SENDER_AMOUNT`. + To create a quote based on the amount the **sender** institution will send, set to `SENDER_INSTITUTION_AMOUNT`. + To create a quote based on the amount the **receiver** institution will receive, set to `RECEIVER_INSTITUTION_AMOUNT`. + To create a quote based on the amount the **receiver** (on behalf of the **beneficiary**) will receive, set to `RECEIVER_AMOUNT`. * `payment_method` — When making a payment through an exchange on local rails, you must provide the `payment_method` in the *Create orchestration payment* or *Create quote collection* request. When you accept a quote, the payout `outlet_id` you specify in the `outbound_instructions` for payment on local rails must match the `payment_method` value in the quote. Examples: If you want to send a payment in MXN through `spei`, add `"payment_method": "spei"` to your quote request. If you want to send a payment in PHP through the InstaPay payment outlet `chinabankx`, add `"payment_method": "chinabankx"` to your quote request. If you do not provide a `payment_method` value in your quote request, RippleNet interprets the `payment_method` value as follows: + For payment in PHP on [Coins.ph](https://coins.ph/), the value defaults to `bdo`. + For payment in MXN on Bitso, the value defaults to `spei`. + For all other exchanges, the value defaults to `"none"`. When the value is `"none"`, The quote response does not include a fee quote for payment on local rails, and your payment terminates in the destination exchange.For a list of `payment_method` values supported by exchanges for payment over local rails, see [Outbound Instructions](/products/payments-odl/api-docs/ripplenet/resources/outbound-instructions). #### Required user info Payment **senders** typically provide required compliance information about the **originator** and **beneficiary** in this step. You can add this supporting information in the `user_info` field of JSON request body for the *Create orchestration payment* or *Accept orchestration payment* operation. For more information about the format of supporting information, see the [Standard RippleNet Payment Object](/products/payments-odl/api-docs/ripplenet/resources/standard-ripplenet-payment-object), or consult with Ripple's Solution Architects. #### Optional information — ODL If you are using *On-Demand Liquidity* (*ODL*), you can also supply the following optional fields when making a [*Create quote collection*](/products/payments-odl/api-docs/ripplenet/reference/openapi/quotes/createquotecollection) request: * `digital_asset_origination` - This is a boolean flag that tells RippleNet to use On-Demand-Liquidity (ODL) to originate your payment in XRP from the source digital asset exchange/wallet. Example: `"digital_asset_origination": true` Add this flag to request a RippleNet quote for a payment using the currency code provided, with the intention to originate in XRP at the source exchange/wallet using ODL. Any quote you receive contains 0 as a value for FX trading fees for the source exchange trade. When you settle the payment, On-Demand Liquidity skips the FX trade in the source exchange, and executes the payment using XRP from your ODL wallet/exchange account. You must be running on RippleNet 4.6.0 or higher to use this feature. * `enable_quote_per_payout_method` - A boolean flag that tells RippleNet to return a quote collection that includes fees for every supported `payment_method` for your payment. Example: `"enable_quote_per_payout_method": true` RippleNet ignores this flag if you supply a `payment_method` with a value in your request body. Using this flag with On-Demand Liquidity for payout through an exchange may result in a long response time and a large JSON response body, as some exchanges have many `payment_method` options available. For a list of `payment_method` values supported by exchanges for payment over local rails, see [Outbound Instructions](/products/payments-odl/api-docs/ripplenet/resources/outbound-instructions). This call is especially useful on the *ODL Test Mode* environment for discovering supported payment methods when building out your business integration logic. Note Quotes for payments using *On-Demand Liquidity* (*ODL*) expire after 60 minutes (3600 seconds), which is the default expiry time. Allow enough time for payment settlement when accepting a quote. #### Other optional information For other optional information that you can provide in the JSON body when creating payment, see the respective reference documentation for the [*Create orchestration payment*](/products/payments-odl/api-docs/ripplenet/reference/openapi/orchestration-payments/createorchestrationpayment) and [*Create quote collection*](/products/payments-odl/api-docs/ripplenet/reference/openapi/quotes/createquotecollection) operations. ## Check payment status To check on the status of your payment request, you first have to check that there is a status notification waiting, and then get the full notification details, as well as further details on the payment itself. The two ways to check that there is a status notification waiting, are using *webhooks* (recommended), and using *polling*. ### Checking status using polling To poll the RippleNet service to check for new notifications, call the *Get orchestration notifications by status* operation, setting the `status` parameter to `NEW` to get a list of any new notifications. ``` GET /v4/orchestration/payment/notification?status=NEW&size=10 HTTP/1.1 Host: aclient.i.ripple.com Content-Type: application/json Authorization: Bearer ``` The response to the call to *Get orchestration notifications by status* contains a paginated array of notifications matching the `status` you specified — all `NEW` notifications. ```json [ { "uuid": "720a2aab-88ab-4830-befd-dd10218fcadd", "notification_type": "PAYMENT_SUCCESS", "notification_version": "1.0", "notification_status": "NEW", "notification_payload": { "sender_end_to_end_id": "19999999999-012", "payment_id": "ab2d66c9-e67a-4020-b0c9-c249912a07a0", "payment_status": "COMPLETED", "previous_payment_status": "PREPARED", "connector_role": "SENDING", "payment_type": "REGULAR", "payout_method": null, "original_sender_end_to_end_id": null, "output": null }, "created_at": "2021-09-03T12:30:22.081Z", "modified_at": "2021-09-03T12:30:22.081Z" } ] ``` If your payment — as identified by the `sender_end_to_end_id` you specified when you created the payment — is not in the array of results, your application will need to keep calling *Get orchestration notifications by status* until it appears. ### Get payment details Once you have received notification that the payment fulfillment is complete, you can retrieve the full details of the payment. ``` GET /v4/orchestration/payment/19999999999-012 HTTP/1.1 Host: aclient.i.ripple.com Content-Type: application/json Authorization: Bearer ``` The response will contain the full payment details. details summary Click to view the full payment details ... ```json { "uuid": "d148d9b2-2d18-414a-a289-8e7abab23f7f", "sender_end_to_end_id": "19999999999-012", "payment_type": "REGULAR", "connector_role": "SENDING", "payment_id": "ab2d66c9-e67a-4020-b0c9-c249912a07a0", "payment_status": "ACCEPTED", "previous_payment_status": "PENDING", "orchestration_template": "defaultSendPaymentTemplateV2", "orchestration_status": "PAUSED", "current_activity": "waitForRNToLockV1", "current_activity_status": "PAUSED", "initial_context": { "sender_end_to_end_id": "19999999999-012", "internal_id": null, "payment_type": "REGULAR", "connector_role": "SENDING", "payment_id": null, "payment_status": null, "orchestration_template": "defaultSendPaymentTemplateV2", "sending_address": "dev.bfox01.sgd", "receiving_address": "dev.bfox02.sgd", "amount": "10.0", "currency": "SGD", "quote_type": "SENDER_AMOUNT", "sender_or_receiver_currency": null, "custom_fee": null, "custom_rate": null, "quote_route": null, "payment_method": null, "enable_quote_per_payout_method": null, "digital_asset_origination": null, "user_info": { "ChrgBr": "SHAR", "Cdtr": { "Id": "8675309", "Nm": "John3" }, "Dbtr": { "Id": "8675309", "Nm": "Jenny" } }, "original_sender_end_to_end_id": null, "original_payment_id": null, "return_amount_type": null, "return_reasons": null, "receiver_currency": null, "quote_id": null, "quote_expiry": null, "receiving_amount": null, "quote_elements": null, "reversal_reason": null, "force_path_finding_and_liquidity_path_finding": false, "payout_method_category": null }, "current_context": { "GET_QUOTE": { "quote_collection_id": "08b5179e-e643-4a5c-8c5d-de996a99e4e2", "quotes": [ { "quote_id": "f2aff21d-66a2-4131-a980-4d5509d31dbc", "created_at": "2021-09-03T12:10:03.483Z", "expires_at": "2021-09-03T13:10:03.483Z", "type": "SENDER_AMOUNT", "price_guarantee": "FIRM", "sender_address": "trans_sgd_bfox01@dev.bfox01.sgd", "receiver_address": "trans_sgd_bfox02@dev.bfox02.sgd", "amount": "10.0", "currency_code": "SGD", "currency_code_filter": null, "service_type": null, "quote_elements": [ { "quote_element_id": "935e9459-30c4-44a4-b71e-45b10147658f", "quote_element_type": "TRANSFER", "quote_element_order": "1", "sender_address": "trans_sgd_bfox01@dev.bfox01.sgd", "receiver_address": "conct_sgd_bfox01@dev.bfox01.sgd", "sending_amount": "10.0", "receiving_amount": "10.0", "sending_fee": "0", "receiving_fee": "0", "sending_currency_code": null, "receiving_currency_code": null, "fx_rate": null, "transfer_currency_code": "SGD" }, { "quote_element_id": "877a068e-330b-417c-be35-0c36f3adae70", "quote_element_type": "TRANSFER", "quote_element_order": "2", "sender_address": "conct_sgd_bfox02@dev.bfox02.sgd", "receiver_address": "trans_sgd_bfox02@dev.bfox02.sgd", "sending_amount": "10.0", "receiving_amount": "10.0", "sending_fee": "0", "receiving_fee": "0", "sending_currency_code": null, "receiving_currency_code": null, "fx_rate": null, "transfer_currency_code": "SGD" } ], "liquidity_warning": null, "payment_method": null, "payment_method_fields": null, "payout_method_info": null } ], "quote_errors": [] }, "SELECT_QUOTE": { "quote_id": "f2aff21d-66a2-4131-a980-4d5509d31dbc", "expires_at": "2021-09-03T13:10:03.483Z" }, "ACCEPT_QUOTE": { "payment_id": "ab2d66c9-e67a-4020-b0c9-c249912a07a0" } }, "error_message": null, "activity_list": [ { "name": "getQuoteV1", "status": "SUCCESS", "startTime": "2021-09-03T12:10:02.466Z", "endTime": "2021-09-03T12:10:03.546Z", "message": null }, { "name": "selectQuoteV1", "status": "SUCCESS", "startTime": "2021-09-03T12:10:03.557Z", "endTime": "2021-09-03T12:10:03.557Z", "message": null }, { "name": "validateSchemaV1", "status": "SUCCESS", "startTime": "2021-09-03T12:10:03.567Z", "endTime": "2021-09-03T12:10:03.573Z", "message": null }, { "name": "acceptQuoteV1", "status": "SUCCESS", "startTime": "2021-09-03T12:10:03.582Z", "endTime": "2021-09-03T12:10:04.164Z", "message": null }, { "name": "waitForRNToLockV1", "status": "PAUSED", "startTime": "2021-09-03T12:10:04.175Z", "endTime": "2021-09-03T12:10:04.175Z", "message": null } ], "created_at": "2021-09-03T12:10:01.992Z" } ``` ## Error handling Your integration logic should handle the following potential errors. Unsuccessful responses (responses returned with an HTTP status code other than `201`) could indicate any of the following issues. (Note: this list is not exhaustive): * The request may have timed out. * The request may have been malformed. * The requesting client does not have the correct OAuth token. * The requesting client does not provide an Authorization header or does not have the correct credentials. If using ODL, some other issues may be involved: * If using ODL, one of the digital asset exchanges in the request may not have received the request. * If using ODL, you may receive a `liquidity_warning` in your quote response. If you do receive a warning, it means that one or more accounts on the digital asset exchanges doesn't have enough liquidity to fulfill part of the payment's execution. * For a list of ODL errors you may receive during execution of API calls, see [On-Demand Liquidity error codes](/products/payments-odl/api-docs/ripplenet/resources/error-codes/on-demand-liquidity-error-codes). At the point you accept a quote — either automatically, or as a separate step — no funds have been transferred or put on hold. Accepting a quote only confirms the originating institution's intent to transfer funds. If network failures or other issues prevent you from accepting a quote before the quote expires, you can restart the process by requesting a new quote. RippleNet generates the `payment_id` after it receives the request to accept the quote. This means that you cannot check the status of the payment without a response from RippleNet. If you can't determine the status of the payment, the best workaround is typically to retry the request. If the quote was already accepted, On-Demand Liquidity responds with this error message: ```json { "error_type": "resubmitted_request", "message": "Payment with ID [{YOUR_PAYMENT_ID}] has already been accepted" } ```