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 article.
Payment flow for senders — automatic quote acceptance
The following describes the flow of tasks a sender must complete to successfully send a payment:
-
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 . - Create payment — A single call to the Create orchestration payment 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.
- Check payment status — You can check the status of your payment, by polling , or using use a webhook . These are described below.
- 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 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.
-
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 . - Fetch quote — The sender supplies payment parameters with a Create quote collection request for all available quotes from RippleNet. Typically you will chose the first of these.
- Accept payment — A call to Accept orchestration payment 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.
- Check payment status — You can check the status of your payment, using either webhooks (recommended) or polling . These are described below.
- 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 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 — These operations are primarily of use by senders for initiating and and working with payments.
- Orchestration notifications — These operations are used both by senders and receivers to get notifications about payments and payment states.
- Orchestration actions — This category consists of a single API operation, Post action to orchestration payment , 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 to retrieve the full notification details about the status of your payment. For more information, see 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.
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 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.
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 API operation as follows:
POST /v4/orchestration/payment HTTP/1.1
Host: aclient.i.ripple.com
Content-Type: application/json
Authorization: Bearer <token>
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.
Click to view the Create orchestration payment body ...
{
"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 operation, followed by the Accept orchestration payment operation, as follows:
POST /v4/quote_collections HTTP/1.1
Host: aclient.i.ripple.com
Content-Type: application/json
Authorization: Bearer <token>
In the body of the POST call, you specify all the parameters need to fetch the quote:
Click to view the Create quote collection body ...
{
"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.
Click to view the response from Create quote collection call ...
{
"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 to finish creating the payment:
POST /v4/orchestration/payment/accept HTTP/1.1
Host: aclient.i.ripple.com
Content-Type: application/json
Authorization: Bearer <token>
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:
Click to view Accept orchestration payment body ...
{
"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.
{
"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 . 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 . -
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 . -
amount
— The amount of the payment. If you specifySENDER_AMOUNT
forquote_type
, this amount is debited from your account. If you specifyRECEIVER_AMOUNT
forquote_type
, this amount is delivered to the beneficiary . -
currency
— Currency code of the amount to be sent or received, depending on thequote_type
value. Ifquote_type
is set toSENDER_AMOUNT
orSENDER_INSTITUTION_AMOUNT
, this is the currency of the amount to be sent. Ifquote_type
is set toRECEIVER_AMOUNT
orRECEIVER_INSTITUTION_AMOUNT
, this is the currency of the amount to be received. Use a valid ISO 2117 currency code. -
quote_type
— Specifies how RippleNet calculates the quote. Valid values areSENDER_AMOUNT
,RECEIVER_AMOUNT
,SENDER_INSTITUTION_AMOUNT
, orRECEIVER_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
.
-
To create a quote based on the amount the
sender
(on behalf of the
originator
) wants to send, set to
-
payment_method
— When making a payment through an exchange on local rails, you must provide thepayment_method
in the Create orchestration payment or Create quote collection request. When you accept a quote, the payoutoutlet_id
you specify in theoutbound_instructions
for payment on local rails must match thepayment_method
value in the quote. Examples: If you want to send a payment in MXN throughspei
, add"payment_method": "spei"
to your quote request. If you want to send a payment in PHP through the InstaPay payment outletchinabankx
, add"payment_method": "chinabankx"
to your quote request. If you do not provide apayment_method
value in your quote request, RippleNet interprets thepayment_method
value as follows:-
For payment in PHP on
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 ofpayment_method
values supported by exchanges for payment over local rails, see Outbound Instructions .
-
For payment in PHP on
Coins.ph
, the value defaults to
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, 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 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.
Note
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 supportedpayment_method
for your payment. Example:"enable_quote_per_payout_method": true
RippleNet ignores this flag if you supply apayment_method
with a value in your request body.Tip
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 ofpayment_method
values supported by exchanges for payment over local rails, see 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 and Create quote collection 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 <token>
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.
[
{
"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 <token>
The response will contain the full payment details.
Click to view the full payment details ...
{
"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 .
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:
{
"error_type": "resubmitted_request",
"message": "Payment with ID [{YOUR_PAYMENT_ID}] has already been accepted"
}