Payments - Collections
If you havenβt already, Sign Up for Sandbox Access to get your client ID and secret to work through this Build Guide!
Use the Rail Payments API to receive payment collections from external counterparties. Receive payments from customers, collect subscriptions from investors, build a payment gateway or a checkout. All of these use cases and more are possible using the below guide.
Prerequisities
-
Customer onboarded
- The corporation or individual wishing to receive the payment has been fully onboarded and is in an
ACTIVE
status. See Applications. -
Account open
- The onboarded customer has an account in the asset type they wish the payment to settle in. The account is in an
OPEN
status.
Steps
1. Authenticating Your Request
Every request you make to a Rail API endpoint requires an AUTH_TOKEN
. We secure our endpoints using standards based OAuth2 Client Credentials Grant and scopes. This makes authenticating secure and easy.
To obtain the AUTH_TOKEN
, you will need to authorize your account using your BASE_64_ENCODED_CLIENTID_AND_SECRET
with the scopes you require:
π€ Request:
curl --location --request POST 'https://auth.layer2financial.com/oauth2/ausbdqlx69rH6OjWd696/v1/token?grant_type=client_credentials&scope=customers:read+customers:write+accounts:read+accounts:write+exchanges:read+exchanges:write' \
--header 'Accept: application/json' \
--header 'Content-Type: application/x-www-form-urlencoded' \
--header 'Cache-Control: no-cache' \
--header 'Authorization: Basic {BASE_64_ENCODED_CLIENTID_AND_SECRET}' \
π₯ Response:
This gives you a response object containing your {AUTH_TOKEN}:
{
"token_type":"Bearer",
"expires_in":43200,
"access_token": {AUTH_TOKEN},
"scope":"customers:read customers:write accounts:write accounts:read exchanges:read exchanges:write"
}
The scopes weβll need for this tutorial are:
-
customers:read
andcustomers:write
so we can create our customer and get information about them. -
accounts:read
andaccounts:write
so we can create our counterparties and get information about them. -
payments:read
andpayments:write
so we can create our payments and get information about them.
The full list of scopes are available here.
2. Create Counterparty
First, Create a Counterparty to represent the external corporation or individual who the customer wishes to collect payments from. The relevant counterparty type here is counterparty_type = BASIC
.
π Note: Other counterparty types can be used here, however
BASIC
requires the least information.
π€ Request:
curl --location POST 'https://alpha.layer2financial.dev/api/v1/counterparties' \
--header 'Content-Type: application/json' \
--header 'Authorization: Bearer {AUTH_TOKEN}' \
--data '{
"customer_id": "XYZ_012",
"counterparty_type": "BASIC",
"profile": {
"profile_type": "INDIVIDUAL",
"name": "Joe Bloggs",
"address": {
"state": "MA",
"country_code": "US"
},
"relationship_to_customer": "CUSTOMER"
}
}'
π₯ Response:
The response object will contain a unique id
for the newly created counterparty. This id will be used as the destinationcounterpartyid in the Create Payment step.
{
"data": {
"id": "9843d07c-1e52-463e-a7d1-f35f40971025"
}
}
3. Create Payment
Once your counterparty is created and is in an ACTIVE status, use Create Payment. Set the source_counterparty_id
to be the counterparty id retrieved in step 2. Set the account_id
to be the account the customer would like funds to settle into.
π€ Request:
curl --location POST 'https://sandbox.layer2financial.dev/api/v1/payments' \
--header 'Content-Type: application/json' \
--header 'Authorization: Bearer {AUTH_TOKEN}' \
--data '{
"payment_source": {
"source_counterparty_id": "9843d07c-1e52-463e-a7d1-f35f40971025",
"asset_type": ["FIAT_TESTNET_USD"]
},
"payment_destination": {
"account_id": "Automation-Account-4724"
},
"payment_info": {
"description": "Invoice 123"
}
}'
π₯ Response:
The response object will contain a unique id
for the newly created payment.
{
"data": {
"payment_id": "2ce4d1ca-6835-4a06-90b8-22043f4b888f",
"status": "REQUESTED"
}
}
3. Review Payment
Before accepting a payment you should Retreive Payment Status. The response will inform you if there are any pending RFIs requiring attention before the payment can be accepted.
π€ Request:
curl --location GET 'https://sandbox.layer2financial.dev/api/v1/payments/{payment_id}/status' \
--header 'Content-Type: application/json' \
--header 'Authorization: Bearer {AUTH_TOKEN}' \
--data '{
"payment_source": {
"source_counterparty_id": "9843d07c-1e52-463e-a7d1-f35f40971025",
"asset_type": ["FIAT_TESTNET_USD"]
},
"payment_destination": {
"account_id": "Automation-Account-4724"
},
"payment_info": {
"description": "Invoice 123"
}
}'
π₯ Response:
The response object will return the current status of the payment. Payments with a status of CHANGES_REQUESTED
require action to be taken before the payment can be accepted.
{
"data": {
"payment_id": "2ce4d1ca-6835-4a06-90b8-22043f4b888f",
"status": "REQUESTED",
...
}
}
4. Accept Payment
β Best Practice - Upload Documents Before Accepting: Before accepting a payment, upload proof of payments, transaction source of funds and additional context as it will reduce likelihood of RFIs and speed up payment processing.
β Best Practice - Ensure Memos are Used: Ensuring the counterparty (payor) provides the unique memo when submitting their payment ensures smooth payment reconciliation thus reducing settlement times.
To initiate retrive payment instructions, use Accept Payment using the payment id. The response will return the unique payment instructions to be provided to the counterparty. Each payment instruction is unique ensuring easy reconciliation when the payor sends funds.
π€ Request:
curl --location POST 'https://sandbox.layer2financial.dev/api/v1/payments/{payment_id}/accept' \
--header 'Content-Type: application/json' \
--header 'Authorization: Bearer {AUTH_TOKEN}' \
--data '{
"payment_source": {
"source_counterparty_id": "9843d07c-1e52-463e-a7d1-f35f40971025",
"asset_type": ["FIAT_TESTNET_USD"]
},
"payment_destination": {
"account_id": "Automation-Account-4724"
},
"payment_info": {
"description": "Invoice 123"
}
}'
π₯ Response: The response will return provide deposit instructions that are unique to the payment. These instructions are what the counterparty must send the funds to.
{
"data": {
"payment_id": "2ce4d1ca-6835-4a06-90b8-22043f4b888f",
"status": "ACCEPTED"
}
}
5. Receive Payment Transactions
When funds arrive at specified payment instructions, a payment transaction will appear on the relevant account in PENDING
status. A TRANSACTION_PENDING
webhook is emitted to notify you of this event. Before the funds are made available the transaction must pass the transaction monitoring process.
When the transaction is approved, the transaction status is updated to POSTED
, a TRANSACTION_POSTED
webhook is sent and the funds are made available to the customer.
Below is what the payment transactions looks like on the account.
π Note -
transaction_type
=PAYMENT_IN
,category_type
=PAYMENT
,category_id
={payment_id}
.
{
"id": "string",
"value": 0,
"transaction_date": "2019-08-24T14:15:22Z",
"transaction_posted_date": "2019-08-24T14:15:22Z",
"transaction_status": "AUTHORIZED",
"transaction_type": "PAYMENT_IN",
"category_type": "PAYMENT",
"category_id": "string",
"description": "string",
"originator": {
"originator_type": "FIAT_US",
"profile": {
"name": "string"
}
},
"rail_information": {
"rail": "string",
"reference": "string",
"memo": "string"
}
}
Useful Information
API Specifications:
- API Spec - Create Counterparty - link.
- API Spec - Create Payment - link.
- API Spec - Retrieve Payment Status - link.
- API Spec - Accept Payment - link.
- API Spec - Create Subscription - link.
Webhooks:
Validation: