Managing Escrow
Hold any payment method in escrow for later release.
An escrow is an arrangement to hold funds in a transaction between two or more parties. Escrows help settle an exchange between a buyer and seller based upon the agreed requirements. When a buyer makes a high value purchase and the funds are held in escrow, the funds are held for one or multiple sellers and can be released in the following ways:
Full or partial release on demand.
Release automatically after a specific number of days.
Partial releases can be released by amount or percentage and proportional or non-proportional.
Escrow is a feature of Rapyd Collect that works with your website back end, and holds funds using a Rapyd Wallet. When the purchase is made, your website back end asks Rapyd to process the payment and then holds the funds in the wallet. The funds are then released to the seller of the item according to your predetermined agreement with the seller or on demand request. When the money is released, Rapyd notifies you via webhook that the transfer was completed successfully.
A customer purchases an item for 250 USD (U.S. Dollars) from a seller on your marketplace. You hold the funds in escrow that the customer paid. You release a partial amount of funds automatically after 5 days, and release the rest of the funds to the seller on demand based on your business policies.
PCI Certification
Only clients with PCI-DSS certification can handle personal identifying information for cards. This method is available to merchants who have signed a special agreement with Rapyd.
Step 1: Processing Escrow Payment
Finding the specific payment methods you'll accept and the corresponding required fields that customers fill out is described under How it Works.
A customer on your marketplace purchases a product from a seller.
The website back end asks Rapyd to process the transaction and hold the funds in escrow for five days.
Rapyd processes the payments and holds the funds in escrow.
Step 2: Releasing Escrow Funds
The website back end asks Rapyd to release part of the funds for the seller.
Rapyd automatically releases part of the funds for the seller, and continues to hold the remaining funds in escrow.
Rapyd manually releases the remaining escrow funds to the seller based on the delivery of the high value item.
The finite state diagram below summarizes the statuses for escrow payments.
Description of Statuses
Status | Description |
---|---|
pending | The payment and escrow were created, but the payment is not completed and the funds are not in escrow. |
on_hold | The payment is completed and the funds are in escrow. |
released | All or part of the funds have been released to the wallets. |
canceled | The escrow is canceled. |
Prerequisites
To run the examples of this use case, you must create the following IDs in your own sandbox:
ewallet_ - Run Create Wallet for the Rapyd Wallet of the seller of the phone. Use the 'id' you get in the response. For more information, see Creating a Rapyd Wallet. Repeat for the wallet of the seller of the speaker.
On your payment page, you let the customer select a payment method. First, you need to decide which payment methods you'll accept. In this example, you'll check for payment methods using USD (U.S. Dollars) in the United States.
For that, you'll use List Payment Methods by Country with the following parameters.
Description of Query Parameters
Query Parameter | Description |
---|---|
country | Enter US as the country code for the United States. |
currency | Enter USD as the currency code for U.S. Dollars. |
List Payment Methods by Country Request
You ask for the list of all available US payment methods in USD.
Request
// Request URL: GET https://sandboxapi.rapyd.net/v1/payment_methods/country?country=US¤cy=USD // Message body absent
.NET Core
using System; namespace RapydApiRequestSample { class Program { static void Main(string[] args) { try { string country = "US"; string currency = "USD"; string result = RapydApiRequestSample.Utilities.MakeRequest("GET", $"/v1/payment_methods/country?country={country}¤cy={currency}"); Console.WriteLine(result); } catch (Exception e) { Console.WriteLine("Error completing request: " + e.Message); } } } }
JavaScript
const makeRequest = require('<path-to-your-utility-file>/utilities').makeRequest; async function main() { try { const result = await makeRequest('GET', '/v1/payment_methods/country?country=US¤cy=USD'); console.log(result); } catch (error) { console.error('Error completing request', error); } }
PHP
<?php $path = $_SERVER['DOCUMENT_ROOT']; $path .= "/<path-to-your-utility-file>/utilities.php"; include($path); try { $object = make_request('get', '/v1/payment_methods/country?country=US¤cy=USD'); var_dump($object); } catch (Exception $e) { echo "Error: $e"; } ?>
Python
from pprint import pprint from utilities import make_request results = make_request(method='get', path=f'/v1/payment_methods/country?country=US¤cy=USD') pprint(results)
List Payment Methods by Country Response
Let's take a look at the response.
Response
{ "status": { "error_code": "", "status": "SUCCESS", "message": "", "response_code": "", "operation_id": "2ef3f76f-6a57-4d1f-bf60-162313d304bc" }, "data": [ { "type": "us_debit_visa_card", "name": "Visa", "category": "card", "image": "https://iconslib.rapyd.net/checkout/us_visa_card.png", "country": "US", "payment_flow_type": "card", "currencies": [ "USD" ], "status": 1, "is_cancelable": false, "payment_options": [], "is_expirable": false, "is_online": false, "minimum_expiration_seconds": null, "maximum_expiration_seconds": null } ] }
The data
section of this response shows that us_debit_visa_card is an acceptable payment method.
Note: A real response usually lists many payment methods.
You need to find which fields the customer must fill in for the payment method.
For that, you'll use Get Payment Method Required Fields with the following parameter:
Description of Path Parameters
Path Parameter | Description |
---|---|
type | Enter us_debit_visa_card as the payment method type. |
Get Payment Method Required Fields Request
You ask for the set of required fields for a us_debit_visa_card payment.
Request
/ Request URL: GET https://sandboxapi.rapyd.net/v1/payment_methods/us_debit_visa_card/required_fields // Message body absent
.NET Core
using System; namespace RapydApiRequestSample { class Program { static void Main(string[] args) { try { string type = "us_visa_card"; string result = RapydApiRequestSample.Utilities.MakeRequest("GET", $"/v1/payment_methods/{type}/required_fields"); Console.WriteLine(result); } catch (Exception e) { Console.WriteLine("Error completing request: " + e.Message); } } } }
JavaScript
const makeRequest = require('<path-to-your-utility-file>/utilities').makeRequest; async function main() { try { const result = await makeRequest('GET', '/v1/payment_methods/us_visa_card/required_fields'); console.log(result); } catch (error) { console.error('Error completing request', error); } }
PHP
<?php $path = $_SERVER['DOCUMENT_ROOT']; $path .= "/<path-to-your-utility-file>/utilities.php"; include($path); try { $object = make_request('get', '/v1/payment_methods/us_visa_card/required_fields'); var_dump($object); } catch (Exception $e) { echo "Error: $e"; } ?>
Python
from pprint import pprint from utilities import make_request payment_method = 'us_visa_card' results = make_request(method='get', path=f'/v1/payment_methods/{payment_method}/required_fields') pprint(results)
Get Payment Method Required Fields Response
Let's take a look at the response.
Response
{ "status": { "error_code": "", "status": "SUCCESS", "message": "", "response_code": "", "operation_id": "0cd7be44-fd91-4b27-941f-158f5e47fb7c" }, "data": { "type": "us_debit_visa_card", "fields": [ { "name": "number", "type": "string", "regex": "", "is_required": true, "instructions": "card number" }, { "name": "expiration_month", "type": "string", "regex": "", "is_required": true, "instructions": "expiration month as string, 01-12" }, { "name": "expiration_year", "type": "string", "regex": "", "is_required": true, "instructions": "expiration year in to digits as string, 18-99" }, { "name": "cvv", "type": "string", "regex": "", "is_required": true, "instructions": "card cvv" }, { "name": "name", "type": "string", "regex": "", "is_required": false, "instructions": "card holder name" }, { "name": "address", "type": "Address", "regex": "", "is_required": false, "instructions": "card billing address. see Address object for more details" } ], "payment_method_options": [ { "name": "3d_required", "type": "string", "regex": "", "description": "", "is_required": false, "is_updatable": false } ], "payment_options": [], "minimum_expiration_seconds": null, "maximum_expiration_seconds": null } }
The data
section of this response shows that five fields are required for a us_debit_visa_card payment. These fields are number
, expiration_month
, expiration_year
, cvv
, and name
.
John Doe makes the following purchases on your marketplace website:
A speaker from one seller for 50.00 USD (U.S. Dollars).
A phone from another seller for 200.00 USD (U.S. Dollars).
You ask Rapyd to process the payment and include an escrow to hold the funds for five days.
For that, you'll use Create Payment with the following parameters:
Description of Body Parameters
Body Parameter | Description |
---|---|
amount | Enter 250 as the total amount of the payment. |
currency | Enter USD as the code for U.S. Dollars. |
payment_method | Enter a 'payment_method' object that has the following fields:
|
ewallets | Enter an 'ewallets' array that has two objects with the following fields: First object:
Second object:
|
escrow | Enter true to enable the escrow. |
escrow_release_days | Enter 5 as the number of days before the escrow funds are automatically released. |
Create Payment Request
You ask Rapyd to process the payment and escrow payment.
Request
// Request URL: POST https://sandboxapi.rapyd.net/v1/payments // Message body: { "amount": 250, "currency": "USD", "requested_currency": "USD", "payment_method": { "type": "us_debit_visa_card", "fields": { "number": "4111111111111111", "expiration_month": "10", "expiration_year": "20", "cvv": "123", "name": "Test User" } }, "ewallets": [ { "ewallet": "ewallet_090e1ef18c3aa754fd43cce9ee454858", "amount": 50 }, { "ewallet": "ewallet_11078019438f943986c1fcfbaba05e13", "amount": 200 } ], "escrow": true, "escrow_release_days": "5" }
Python
from pprint import pprint from utilities import make_request payment_body = { "amount": 250, "currency": "USD", "requested_currency": "USD", "payment_method": { "type": "us_visa_card", "fields": { "number": "4111111111111111", "expiration_month": "10", "expiration_year": "20", "cvv": "123", "name": "John Doe" } }, "ewallets": [ { "ewallet": "ewallet_090e1ef18c3aa754fd43cce9ee454858", "amount": 50 }, { "ewallet": "ewallet_11078019438f943986c1fcfbaba05e13", "amount": 200 } ], "escrow": True, "escrow_release_days": "5" } create_payment_response = make_request(method='post', path='/v1/payments', body=payment_body) pprint(create_payment_response)
Create Payment Response
Let's take a look at the response.
Response
{ "status": { "error_code": "", "status": "SUCCESS", "message": "", "response_code": "", "operation_id": "2eb07c96-f541-43fa-bd33-3599c7ebb033" }, "data": { "id": "payment_3b01b41950ec59d92c532974edc8f7dd", "amount": 250, "original_amount": 250, "is_partial": false, "currency_code": "USD", "country_code": "US", "status": "CLO", "description": "", "merchant_reference_id": "", "customer_token": "cus_30896ef7ee24397f340cc64a1f474697", "payment_method": "card_cf53c0452fb183a09d1fff2f16577b74", // ... "created_at": 1580986835, // ... "paid": true, "paid_at": 1580986836, // ... "ewallets": [ { "ewallet_id": "ewallet_090e1ef18c3aa754fd43cce9ee454858", "amount": 200, "percent": 0, "released_amount": 0, "refunded_amount": 0 }, { "ewallet_id": "ewallet_11078019438f943986c1fcfbaba05e13", "amount": 50, "percent": 80, "released_amount": 0, "refunded_amount": 0 } ], "payment_method_options": {}, "payment_method_type": "us_debit_visa_card", "payment_method_type_category": "card", // ... "escrow": { "id": "escrow_150c88345d2bca0a8be05e54a952cc80", "payment": "payment_3b01b41950ec59d92c532974edc8f7dd", "amount_on_hold": 250, "total_amount_released": 0, "status": "on_hold", "escrow_release_days": 5, "created_at": 1580986835, "updated_at": 1580986835, "last_payment_completion": 1580986836 }, "group_payment": "" } }
The data
section of this response shows that:
The
amount
is 250.The
currency
is USD.The
ewallets
object indicates:An amount of 50 is held in escrow for
ewallet_id
ewallet_090e1ef18c3aa754fd43cce9ee454858 .An amount of 200 is held in escrow for
ewallet_id
ewallet_11078019438f943986c1fcfbaba05e13 .
The
escrow
object indicates:Its
id
is escrow_150c88345d2bca0a8be05e54a952cc80 .The payment ID is
payment_3b01b41950ec59d92c532974edc8f7dd
.The
amount_on_hold
is 250.The
status
is on_hold.The
escrow_release_days
is 5.
When you ask Rapyd to release the funds to the speaker seller, you will use the speaker seller's ewallet_id
, the escrow
object's id
and the payment
ID .
You decide to immediately release the funds of 50 USD (U.S. Dollars) to the seller of the speaker.
For that, you'll use Release Funds from Escrow with the following parameters:
Description of Path Parameters
Path Parameter | Description |
---|---|
payment | Enter the payment ID 'id' that you received when you created the payment in your sandbox. For purposes of this use case lesson, we are using payment_3b01b41950ec59d92c532974edc8f7dd, which is the payment ID we created in our sandbox. |
escrow | Enter the escrow ID 'id' that you received when you created the payment in your sandbox. For purposes of this use case lesson, we are using escrow_150c88345d2bca0a8be05e54a952cc80, which is the escrow ID we created in our sandbox. |
Description of Body Parameters
Body Parameter | Description |
---|---|
ewallets | Enter an 'ewallets' array with one object that has the following fields:
|
Release Funds from Escrow Request
You ask Rapyd to release the funds to a seller.
Request
// Request URL: POST https://sandboxapi.rapyd.net/v1/payments/payment_3b01b41950ec59d92c532974edc8f7dd/escrows/escrow_150c88345d2bca0a8be05e54a952cc80/escrow_releases // Message body: { "ewallets": [ { "ewallet": "ewallet_090e1ef18c3aa754fd43cce9ee454858", "amount": 50 } ] }
.NET Core
using System; using System.Text.Json; namespace RapydApiRequestSample { class Program { static void Main(string[] args) { try { string payment = "payment_3b01b41950ec59d92c532974edc8f7dd"; string escrow = "escrow_150c88345d2bca0a8be05e54a952cc80"; var requestObj = new { ewallets = new Object[] { new { ewallet = "ewallet_090e1ef18c3aa754fd43cce9ee454858", amount = 50 }, } }; string request = JsonSerializer.Serialize(requestObj); string result = RapydApiRequestSample.Utilities.MakeRequest("POST", $"/v1/payments/{payment}/escrows/{escrow}/escrow_releases", request); Console.WriteLine(result); } catch (Exception e) { Console.WriteLine("Error completing request: " + e.Message); } } } }
PHP
<?php $path = $_SERVER['DOCUMENT_ROOT']; $path .= "/<path-to-your-utility-file>/utilities.php"; include($path); $body = [ array( "ewallet" => "ewallet_090e1ef18c3aa754fd43cce9ee454858", "amount" => 50 ) ]; try { $object = make_request('post', '/v1/payments/payment_3b01b41950ec59d92c532974edc8f7dd/escrows/escrow_150c88345d2bca0a8be05e54a952cc80/escrow_releases', $body); var_dump($object); } catch (Exception $e) { echo "Error: $e"; } ?>
Python
from pprint import pprint from utilities import make_request release_funds_body = { "ewallets": [ { "ewallet": "ewallet_090e1ef18c3aa754fd43cce9ee454858", "amount": 50 } ] } release_funds_response = make_request(method='post', path='/v1/payments/payment_3b01b41950ec59d92c532974edc8f7dd/escrows/escrow_150c88345d2bca0a8be05e54a952cc80/escrow_releases', body=release_funds_body) pprint(release_funds_response)
Release Funds from Escrow Response
Let's take a look at the response.
Response
{ "status": { "error_code": "", "status": "SUCCESS", "message": "", "response_code": "", "operation_id": "8338da6d-997c-41fb-97ef-def18c133224" }, "data": { "id": "escrow_150c88345d2bca0a8be05e54a952cc80", "payment": "payment_3b01b41950ec59d92c532974edc8f7dd", "amount_on_hold": 250, "total_amount_released": 50, "status": "released", "escrow_release_days": 5, "escrow_releases": { "data": [ { "id": "er_ac023aae3b13b0e74ad64c876b1034dd", "amount": 50, "trigger": "event", "proportional_release": false, "ewallets": [ { "ewallet": "ewallet_090e1ef18c3aa754fd43cce9ee454858", "amount": 250 } ], "created_at": 1580987535 } ], "has_more": false, "total_count": 1, "url": "/v1/payments/payment_3b01b41950ec59d92c532974edc8f7dd/escrows/escrow_150c88345d2bca0a8be05e54a952cc80/escrow_releases" }, "created_at": 1580986835, "updated_at": 1580987535, "last_payment_completion": 1580986836 } }
The data
section of this response shows that:
The
amount_on_hold
is 250.The
escrow_releases
object indicates:An amount of 50 USD was released to
ewallet_id
ewallet_090e1ef18c3aa754fd43cce9ee454858
The
escrow_release_days
is 5.
After five days, 50 USD is automatically released to ewallet_11078019438f943986c1fcfbaba05e13. For a list of all releases of funds from this escrow, run List Escrow Releases.