SEP: 0031
Title: Cross-Border Payments API
Author: SDF
Status: Active
Created: 2020-04-07
Updated: 2022-05-13
Version 1.6.0
This SEP defines a protocol for enabling payments between two financial accounts that exist outside the Stellar network.
The entities involved in a transaction are:
- A Sending Client: The owner of the origin financial account.
- A Sending Anchor: The business receiving funds from the Sending Client and delivering them to the Receiving Anchor for the Receiving Client. Must have a business relationship with the Receiving Anchor.
- A Receiving Anchor: The business receiving funds from the Sending Anchor and delivering them to the Receiving Client.
- A Receiving Client: The owner of the destination financial account.
At a high level, the following steps are performed to complete a transaction:
- The Sending Client sends funds from their financial account to the Sending Anchor's financial account (off/on-Stellar)
- The Sending Anchor sends the funds to the Receiving Anchor's Stellar account (on-Stellar)
- The Receiving Anchor sends funds to the Receiving Client's financial account (off/on-Stellar)
Typically, the Sending and Receiving Clients reside in different regulatory jurisdictions and therefore a payment between their financial accounts must be facilitated by two business entities, the Sending and Receiving Anchors, who have the necessary licenses in their respective jurisdictions.
Alice in Nigeria wants to send money to Bob in Europe. Alice signs up with NigeriaPay to make this payment to send money directly into Bob’s bank account. Bob doesn’t need to do anything, or know anything about this payment, besides letting Alice know what his bank account information is. Alice only needs to deal with her anchor (NigeriaPay). Alice passes this information and her money to NigeriaPay, and NigeriaPay sends those funds to the EuroPay Anchor service, and Europay deposits those funds into Bob’s bank account.
The diagrams provided offer a detailed view of various flows that are possible using this protocol. Note that these diagrams are opinionated. Variations of the these flows may also be sufficient.
This diagram demonstrates the interactions between the entities involved in a successful transaction. Specifically it uses the Receiving Anchor Asset Conversion strategy defined described later in the document.
sequenceDiagram
participant Sending Client
participant Sending Anchor
participant Stellar
participant Receiving Anchor
participant Receiving Client
Sending Client->>Sending Anchor: initiates send to <br> Receiving Client's country
Sending Anchor-->>Sending Anchor: maps country to Receiving Anchor
Sending Anchor->>+Receiving Anchor: GET /.well-known/stellar.toml
Receiving Anchor-->>-Sending Anchor: SEP-10, 12, 31, & 38 URLs
Sending Anchor->>+Receiving Anchor: GET [SEP-31]/info
Receiving Anchor-->>-Sending Anchor: Stellar assets, customer types, fees
Sending Anchor->>+Receiving Anchor: GET [SEP-38]/prices
Receiving Anchor-->>-Sending Anchor: pairs and est. rates for Stellar asset
Sending Anchor-->>Sending Anchor: calculates fiat-to-fiat est. rates
Sending Anchor->>+Sending Client: provides pair <br> est. rates & fees
Sending Client-->>-Sending Anchor: selects asset pair
Sending Anchor->>+Receiving Anchor: GET [SEP-10]
Receiving Anchor-->>-Sending Anchor: challenge transaction
Sending Anchor-->>Sending Anchor: signs challenge
Sending Anchor->>+Receiving Anchor: POST [SEP-10]
Receiving Anchor-->>Receiving Anchor: verifies challenge
Receiving Anchor-->>-Sending Anchor: authentication token
loop once for Sending Client, once of Receiving Client
note right of Sending Anchor: If Sending Client or Receiving Client <br >has already been <br> accepted, this section <br> is unnecessary.
Sending Anchor->>+Receiving Anchor: GET [SEP-12]/customer?type=
Receiving Anchor-->>-Sending Anchor: fields required
Sending Anchor->>+Sending Client: requests fields
Sending Client-->>-Sending Anchor: provides field values
Sending Anchor->>+Receiving Anchor: PUT [SEP-12]/customer?type=
Receiving Anchor-->>Receiving Anchor: validates KYC values
Receiving Anchor-->>-Sending Anchor: id, ACCEPTED
end
Sending Anchor->>+Receiving Anchor: GET [SEP-38]/price
Receiving Anchor-->>-Sending Anchor: exchange rate
Sending Anchor->>+Sending Client: provides estimated rate
Sending Client-->>-Sending Anchor: continues
Sending Anchor->>+Receiving Anchor: POST [SEP-38]/quote
Receiving Anchor-->>Sending Anchor: quote id, rate, expiration
Sending Anchor->>+Receiving Anchor: POST [SEP-31]/transactions
Receiving Anchor-->>Receiving Anchor: checks customer statuses, <br> links quote, <br> creates transaction record
Receiving Anchor-->>-Sending Anchor: transaction id, receiving account & memo
Sending Anchor->>+Receiving Anchor: GET [SEP-31]/transactions/:id
Receiving Anchor-->>-Sending Anchor: transaction object containing amount_in, amount_in_asset, stellar_account_id, etc.
note right of Sending Anchor: Use the info returned from <br>GET [SEP-31]/transactions/:id to <br>make the stellar payment.
Sending Anchor->>+Stellar: submit Stellar payment
Stellar->>+Receiving Anchor: receives payment, matches w/ transaction
Receiving Anchor-->>Receiving Anchor: updates transaction status
Stellar-->>-Sending Anchor: success response
Receiving Anchor->>Receiving Client: Sends off-chain payment to recipient
Receiving Anchor-->>Receiving Anchor: updates transaction to complete
Sending Anchor->>+Receiving Anchor: GET /transactions?id=
Receiving Anchor-->>-Sending Anchor: transaction complete
Sending Anchor->>Sending Client: notifies sender
- The Receiving Anchor must define
DIRECT_PAYMENT_SERVER
in theirstellar.toml
. - The Sending and Receiving Anchors must create bi-lateral agreements to interoperate with each other.
- If the Receiving Anchor requires KYC information for the Sending or Receiving Clients, the Receiving Anchor must implement SEP-12 and define a
KYC_SERVER
in their stellar.toml. - If the Receiving Anchor supports the Receiving Anchor Asset Conversion flow using SEP-38,
ANCHOR_QUOTE_SERVER
must be defined in theirstellar.toml
.
Sending Anchors must authenticate with Receiving Anchors via SEP-10 Web Authentication. Sending Anchors must provide the Stellar account they will authenticate with to their Receiving Anchors, and Receiving Anchors must ensure that the authenticated Stellar account belongs to a Sending Anchor for which a bi-lateral agreement has been made.
The SEP-10 JWT be included as a header in requests to all endpoints:
Authorization: Bearer <JWT>
Any API request that fails to meet proper authentication should return a 403 Forbidden response.
Note that the source account of payments made by Sending Anchors can differ from the account used to authenticate with Receiving Anchors. Only the payment transaction's memo should be used to match incoming payments with the transaction record in the Receiving Anchor's database.
This protocol involves the transfer of value, and so HTTPS is required for all endpoints for security. Anchors should refuse to interact with any insecure HTTP endpoints.
All endpoints accept in requests the following Content-Type
s:
application/json
All endpoints respond with content type:
application/json
This protocol is designed for the common case where the Sending Client provides the Sending Anchor with a particular asset (the source asset) and the Receiving Client receives a different asset (the destination asset). It is possible to use this protocol when the Sending and Receiving clients wish to send and receive the same asset, but that is not the common use case it has been designed.
When the source asset and destination assets are different, the source asset must be converted into the receiving asset at some point prior to delivering funds to the Receiving Client. This conversion must be done by either the Sending Anchor, the Stellar Network, or the Receiving Anchor. The subsections below outline the strategies used for each method.
The Sending Anchor can collect the source asset from the Sending Client and send the destination asset to the Receiving Anchor.
This approach requires the Sending Anchor to provide an exchange rate, or quote, to the Sending Client. It also requires the Sending Anchor to hold a balance of the destination asset on Stellar. The Sending Anchor would use Payment operations to send the quoted amount of the destination asset to the Receiving Anchor.
Instead of holding a balance of the destination asset on Stellar, the Sending Anchor can use Path Payments to convert the source asset to the destination asset on the Stellar Network.
This approach requires a sufficiently liquid market to exist between the source and destination assets on the Stellar Decentralized Exchange (SDEX).
Finally, the Receiving Anchor can receive payments of the source asset on Stellar and deliver payments of the destination asset to the Receiving Client.
This requires the Receiving Anchor to implement the SEP-38 Anchor RFQ API, which enables the Receiving Anchor to provide quotes to the Sending Anchor. These quotes can be indicative or firm. If a firm quote is used, the Stellar transaction must be submitted to the Stellar network prior to the quote's expiration. More specifically, the created_at
timestamp returned in the Horizon GET /transactions/:id request must be earlier than the quote's expiration.
- The Sending Client initiates a payment to the Receiving Client.
- The Sending Anchor identifies the Receiving Anchor it will use for the payment based on the receipient's location.
- The Sending Anchor makes a request to the Receiving Anchor's
GET /info
endpoint to collect asset information and thetransaction.fields
describing the transaction-related information required by the Receiving Anchor. - The Sending Anchor fetches the relevant KYC
type
values from thesep12
object for the Sending and Receiving Client. If notype
values are defined for either client, KYC information is not required for that client. - The Sending Anchor makes SEP-12 GET /customer?type= requests for the Sending and Receiving Clients. The response includes the SEP-9 KYC attributes required for registering a client of the associated
type
. - The Sending Anchor collects all required information from the Sending Client. This includes the custom fields listed in the Receiving Anchor's
GET /info
response as well as the KYC fields described in theGET /customer
responses for both the Sending and Recieving Clients. How the Sending Anchor collects this information from the Sending Client is out of the scope of this document, but the Receving Client should not be required to take any action in order for the Sending Client to make the payment to the Receiving Anchor. - The Sending Anchor makes SEP-12 PUT /customer requests containing the collected information for each client.
- If the Receiving Anchor supports the SEP-38 Anchor RFQ API, the Sending Anchor can request a quote from the Receiving Anchor. See the Receiving Anchor Asset Conversion section for more information.
- The Sending Anchor makes a
POST /transactions
request to create a transaction record with the Receiving Anchor. This request contains theid
s returned by thePUT /customer
requests, thetransaction.fields
values collected from the Sending Client, as well as the transaction information. The response will include aid
that will be used to check the transaction data and status. - The Sending Anchor makes
GET /transactions/:id
requests until the transaction'sstatus
ispending_sender
. - The Sending Anchor submits the payment transaction to Stellar using the information provided in the
GET /transactions/:id
response. - The Sending Anchor makes
GET /transactions/:id
requests until the transaction'sstatus
iscompleted
,error
,pending_customer_info_update
, orpending_transaction_info_update
. - If
completed
, the Sending Anchor should notify the Sending Client that funds have been delivered to the Receiving Client. - If
error
, the Receiving Anchor should be contacted to resolve the situation. - If
pending_transaction_info_update
, thetransaction.fields
values collected from the Sending Client were invalid and must be corrected by the Sending Client. See the Pending Transaction Info Update section for more information. - If
pending_customer_info_update
, the SEP-9 KYC values collected were invalid and must be corrected by the Sending Client. See the Pending Customer Info Update section for more information. - After providing the Receiving Anchor with updated values, the status should ultimately change to
completed
.
- The Sending Anchor makes a request to the Receiving Anchor's
GET /info
endpoint. - The Sending Anchor makes a
SEP-12 GET /customer
request for the Sending and Receiving Clients if required. - The Sending Anchor makes a
SEP-12 PUT /customer
request for the Sending and Receiving Clients if required. - The Receiving Anchor must validate the KYC data provided and reject the request with useful error messages if invalid.
- The Sending Anchor may request a quote using the
SEP-38 GET /price
orSEP-38 POST /quote
endpoints. - The Sending Anchor makes a
POST /transactions
request. - The Receiving Anchor must ensure the
asset_code
,amount
, transactionfields
, and customers IDs are valid. The Sending Anchor may provide adestination_asset
attribute if the Receiving Anchor supports the exchange ofasset_code
anddestination_asset
via SEP-38, and if a firm quote was provided previously the Sending Anchor may provide thequote_id
as well. - The Recieving Anchor must create a transaction record in their database and expose it via
GET /transactions/:id
. - Transactions should initially be
pending_sender
. If any preprocessing is required before receiving a payment, mark the transaction aspending_receiver
until ready to receive funds. - The Receiving Anchor then waits to receive the payment identified by the
stellar_memo
included in thePOST /transactions
response. - Once the Stellar payment has been received and matched with the internal transaction record, the Receiving Anchor must attempt to transfer an equivalent amount of the asset (minus fees) off-chain to the Receiving Client using the KYC and rails data collected by the Sending Anchor.
- If the off-chain payment succeeds, the transaction's status should be updated to
completed
. - If the off-chain payment cannot be received by the Recieving Client almost immediately, the transaction's status should be updated to
pending_external
until received. - If the off-chain payment fails, the Recieving Anchor must determine why, which is outside the scope of this document. Once determined, the Receiving Anchor must either correct it themselves (internal error) or receive updated values from the Sending Anchor for the fields that were discovered to be invalid.
- If the invalid values were described in
GET /info
'stransaction.fields
object, the transaction's status should be updated topending_transaction_info_update
andrequired_info_updates
should contain an object describing the errors. - If the invalid values were described in
SEP-12 GET /customer
responses, the transaction's status should be updated topending_customer_info_update
and the invalid field names should be returned in the nextGET /customer?id=
request for each Client. - The Sending Anchor will detect the transaction's status and invalid fields, collect the info from the Sending Client, and make requests to the Receiving Anchor containing the updated information.
- Once the provided information is validated, the Receiving Anchor should update the transaction's status to
pending_receiver
and retry the off-chain transfer. This loop of attempting the transfer and waiting for updated information should continue until the transfer is successful.
GET DIRECT_PAYMENT_SERVER/info
Allows an anchor to communicate basic info about what currencies their DIRECT_PAYMENT_SERVER
supports receiving from partner anchors.
Request parameters:
Name | Type | Description |
---|---|---|
lang |
string | (optional) Defaults to en . Language code specified using ISO 639-1. description fields in the response should be in this language. |
The response should be a JSON object like:
{
"receive": {
"USDC": {
"quotes_supported": true,
"quotes_required": false,
"fee_fixed": 5,
"fee_percent": 1,
"min_amount": 0.1,
"max_amount": 1000,
"sep12": {
"sender": {
"types": {
"sep31-sender": {
"description": "U.S. citizens limited to sending payments of less than $10,000 in value"
},
"sep31-large-sender": {
"description": "U.S. citizens that do not have sending limits"
},
"sep31-foreign-sender": {
"description": "non-U.S. citizens sending payments of less than $10,000 in value"
}
}
},
"receiver": {
"types": {
"sep31-receiver": {
"description": "U.S. citizens receiving USD"
},
"sep31-foreign-receiver": {
"description": "non-U.S. citizens receiving USD"
}
}
}
},
"fields":{
"transaction":{
"receiver_routing_number":{
"description": "routing number of the destination bank account"
},
"receiver_account_number":{
"description": "bank account number of the destination"
},
"type":{
"description": "type of deposit to make",
"choices": [
"SEPA",
"SWIFT"
]
}
}
}
}
}
}
The JSON object contains an entry for each Stellar asset that the Receiving Anchor supports receiving from the Sending Anchor.
If the Receiving Anchor supports SEP-38, the Sending Client can check the SEP-38 GET /prices
endpoint to determine which off-chain assets the Receiving Anchor can deliver to recipients in exchange for an asset listed in the SEP-31 GET /info
response. If the Receiving Anchor does not provide exchange rates for an asset, it is assumed that the Stellar asset can be exchanged 1-for-1 with the corresponding off-chain asset.
Name | Type | Description |
---|---|---|
sep12 |
object | An object containing sender and receiver keys. |
min_amount |
number | (optional) Minimum amount. No limit if not specified. |
max_amount |
number | (optional) Maximum amount. No limit if not specified. |
fee_fixed |
number | (optional) A fixed fee in units of the Stellar asset. Leave blank if there is no fee or fee calculation cannot be modeled using a fixed and percentage fee. |
fee_percent |
number | (optional) A percentage fee in percentage points. Leave blank if there is no fee or fee calculation cannot be modeled using a fixed and percentage fee. |
sender_sep12_type |
string | (deprecated, optional) The value of the type parameter the Sending Anchor should use for a SEP-12 GET /customer request. This field can be omitted if no KYC is necessary. Use a value from sep12.sender.types instead if any are present. |
receiver_sep12_type |
string | (deprecated, optional) The value of the type parameter the Sending Anchor should use for a SEP-12 GET /customer request. This field can be omitted if no KYC is necessary. Use a values from sep12.receiver.types instead if any are present. |
fields |
object | An object containing the per-transaction parameters required in POST /transactions requests. |
quotes_supported |
boolean | (optional) If true, the Receiving Anchor can deliver the off-chain assets listed in the SEP-38 GET /prices response in exchange for receiving the Stellar asset. |
quotes_required |
boolean | (optional) If true, the Receiving Anchor can only deliver an off-chain asset listed in the SEP-38 GET /prices response in exchange for receiving the Stellar asset. |
Name | Type | Description |
---|---|---|
sender |
object | An object containing a types key if KYC information is required for the Sending Client, empty otherwise. |
receiver |
object | An object containing a types key if KYC information is required for the Receiving Client, empty otherwise. |
Name | Type | Description |
---|---|---|
types |
object | (optional) An object containing the accepted values for the type parameter in SEP-12 requests. Each key should map to an object with a human-readable description . |
If KYC is required for a Sending or Receiving client in some cases but not others, it is recommended to provide values in the respective types
object for all cases and return an empty fields
object from SEP-12 GET /customer for the cases where no KYC is necessary.
Name | Type | Description |
---|---|---|
fields |
object | An object containing single transaction key. |
Name | Type | Description |
---|---|---|
description |
string | A description of field to show to user. |
choices |
array | (optional) A list of possible values for the field. |
optional |
boolean | (optional) false if not specified. |
This request initiates a payment. The Sending and Receiving Client must be registered via SEP-12 if required by the Receiving Anchor.
The following is an example request body if Sending Anchor Asset Conversions or Stellar Network Asset Conversions are used.
POST DIRECT_PAYMENT_SERVER/transactions
Content-Type: application/json
{
"amount": 100,
"asset_code": "USD",
"asset_issuer": "GDRHDSTZ4PK6VI3WL224XBJFEB6CUXQESTQPXYIB3KGITRLL7XVE4NWV",
"sender_id": "d2bd1412-e2f6-4047-ad70-a1a2f133b25c",
"receiver_id": "137938d4-43a7-4252-a452-842adcee474c",
"fields": {
"transaction": {
"receiver_routing_number": "442928834",
"receiver_account_number": "0029483242",
"type": "SEPA"
}
}
}
The following is an example request body if the Sending Anchor requested an indicative quote from SEP-38 GET /price
and found the estimated rate acceptable.
Note that the amount delivered to the Receiving Client in this scenario varies depending on the exchange rate used by the Receiving Anchor, which may differ from the rate provided in the GET /price
response.
POST DIRECT_PAYMENT_SERVER/transactions
Content-Type: application/json
{
"amount": 100,
"asset_code": "USD",
"asset_issuer": "GDRHDSTZ4PK6VI3WL224XBJFEB6CUXQESTQPXYIB3KGITRLL7XVE4NWV",
"destination_asset": "iso4217:BRL",
"sender_id": "d2bd1412-e2f6-4047-ad70-a1a2f133b25c",
"receiver_id": "137938d4-43a7-4252-a452-842adcee474c",
"fields": {
"transaction": {
"receiver_routing_number": "442928834",
"receiver_account_number": "0029483242",
"type": "SEPA"
}
}
}
The following is an example request body if the Sending Anchor requested a firm quote from SEP-38 POST /quote
and found the rate acceptable. In this case, the Receiving Anchor must ensure that the information passed in the POST /transactions
request matches the assets and amounts defined in the POST /quote
request and response.
POST DIRECT_PAYMENT_SERVER/transactions
Content-Type: application/json
{
"amount": 100,
"asset_code": "USD",
"asset_issuer": "GDRHDSTZ4PK6VI3WL224XBJFEB6CUXQESTQPXYIB3KGITRLL7XVE4NWV",
"destination_asset": "iso4217:BRL",
"quote_id": "2bc5b322-5117-413f-869f-e7ca494cb1a4",
"sender_id": "d2bd1412-e2f6-4047-ad70-a1a2f133b25c",
"receiver_id": "137938d4-43a7-4252-a452-842adcee474c",
"fields": {
"transaction": {
"receiver_routing_number": "442928834",
"receiver_account_number": "0029483242",
"type": "SEPA"
}
}
}
Name | Type | Description |
---|---|---|
amount |
number | Amount of the Stellar asset sent to the Receiving Anchor. |
asset_code |
string | Code of the asset the Sending Anchor intends to send. This must match one of the entries listed in the receiving anchor's GET /info endpoint. |
asset_issuer |
string | (optional) The issuer of the Stellar asset the Sending Anchor intends to send. If not specified, the asset sent must be issued by the Receiving Anchor. |
destination_asset |
string | (optional) The off-chain asset the Receiving Anchor will deliver to the Receiving Client. The value must match one of the asset values included in a SEP-38 GET /prices?sell_asset=stellar:<asset_code>:<asset_issuer> response using SEP-38 Asset Identification Format. If neither this field nor quote_id are set, it's assumed that Sending Anchor Asset Conversions was used. |
quote_id |
string | (optional) The id returned from a SEP-38 POST /quote response. If this attribute is specified, the values for the fields defined above must match the values associated with the quote. |
sender_id |
string |
(optional) The ID included in the SEP-12 PUT /customer response for the Sending Client. Required if the Receiving Anchor requires SEP-12 KYC on the Sending Client. |
receiver_id |
string |
(optional) The ID included in the SEP-12 PUT /customer response for the Receiving Client. Required if the Receiving Anchor requires SEP-12 KYC on the Receiving Client. |
fields |
object | An object containing the values requested by the Receiving Anchor in the GET /info endpoint. |
lang |
string | (optional) Defaults to en . Language code specified using ISO 639-1. Any human-readable error codes or field descriptions will be returned in this language. |
This is the successful case where a Receiving Anchor confirms that they can fulfill this payment as described. The response body should be a JSON object with the following values
Name | Type | Description |
---|---|---|
id |
string | The persistent identifier to check the status of this payment transaction. |
stellar_account_id |
string | The Stellar account to send payment to. |
stellar_memo_type |
string | The type of memo to attach to the Stellar payment (text , hash , or id ). |
stellar_memo |
string | The memo to attach to the Stellar payment. |
In the case where the Sending Anchor didn't provide all the KYC information requested in SEP-12 GET /customer
, or where the Receiving Anchor requires additional KYC information after amount
, the response should include a 400 status code and the following body. The sender should then retry both the SEP-12 GET /customer
request to collect the additional fields and the SEP-12 PUT /customer
request including all fields described in the GET /customer
response.
Name | Type | Description |
---|---|---|
error |
string | customer_info_needed |
type |
string | (optional) A string for the type URL argument the Sending Anchor should use when making the SEP-12 GET /customer request. The value should be included in the sender.types or receiver.types object from GET /info . |
In the case where the Sending Anchor didn't provide all the information requested in GET /info
, the response should include a 400 status code the following body. The Sending Anchor should then retry the entire request including all the previously sent fields plus the fields described in the response.
Name | Type | Description |
---|---|---|
error |
string | transaction_info_needed |
fields |
object | A key-value pair of missing fields in the same format as fields described in GET /info . |
In the case where the transaction cannot be completed, return an error response body containing an error
key describing the error in human-readable format in the language indicated in the request.
{
'error': "The amount was above the maximum limit"
}
{
'error': "That bank account is restricted via AML laws"
}
The transaction endpoint enables Sending Clients to fetch information on a specific transaction with the Receiving Anchor.
GET DIRECT_PAYMENT_SERVER/transactions/:id
Request parameters:
Name | Type | Description |
---|---|---|
id |
string | The id of the transaction. |
On success the response should include a 200 OK
HTTP status code and the following body:
Name | Type | Description |
---|---|---|
transaction |
object | The transaction that was requested by the client. |
transaction
Object Schema
Name | Type | Description |
---|---|---|
id |
string | The ID returned from the POST /transactions request that created this transaction record. |
status |
string | The status of the transaction. Values are outlined below. |
status_eta |
number | (optional) The estimated number of seconds until a status change is expected. |
amount_in |
string | (optional) The amount of the Stellar asset received or to be received by the Receiving Anchor. Excludes any fees charged after Receiving Anchor receives the funds. |
amount_in_asset |
string | (optional) The asset received or to be received by the Receiving Anchor. Must be present if quote_id or destination_asset was included in the POST /transactions request. The value must be in SEP-38 Asset Identification Format. |
amount_out |
string | (optional) The amount sent by the Receiving Anchor to Receiving Client. |
amount_out_asset |
string | (optional) The asset delivered to the Receiving Client. Must be present if quote_id or destination_asset was included in the POST /transactions request. The value must be in SEP-38 Asset Identification Format. |
amount_fee |
string | (optional) The amount of fee charged by the Receiving Anchor. |
amount_fee_asset |
string | (optional) The asset in which fees are calculated in. Must be present if quote_id or destination_asset was included in the POST /transactions request. The value must be in SEP-38 Asset Identification Format. |
stellar_account_id |
string | The Receiving Anchor's Stellar account that the Sending Anchor will be making the payment to. |
stellar_memo_type |
string | The type of memo to attach to the Stellar payment: text , hash , or id . |
stellar_memo |
string | The memo to attach to the Stellar payment. |
started_at |
UTC ISO 8601 string | (optional) Start date and time of transaction. |
completed_at |
UTC ISO 8601 string | (optional) Completion date and time of transaction. |
stellar_transaction_id |
string | (optional) The transaction_id on Stellar network of the transfer that initiated the payment. |
external_transaction_id |
string | (optional) The ID of transaction on external network that completes the payment into the receivers account. |
refunded |
boolean | (deprecated, optional) This field is deprecated in favor of the refunds object. True if the transaction was refunded in full. False if the transaction was partially refunded or not refunded. For more details about any refunds, see the refunds object. |
refunds |
object | (optional) An object describing any on-chain refund associated with this transaction. The schema for this object is defined in the Refunds Object Schema section below. |
required_info_message |
string | (optional) A human-readable message indicating any errors that require updated information from the sender. |
required_info_updates |
object | (optional) A set of fields that require update values from the Sending Anchor, in the same format as described in GET /info. This field is only relevant when status is pending_transaction_info_update . |
status
should be one of:
pending_sender
-- awaiting payment to be sent by Sending Anchor.pending_stellar
-- transaction has been submitted to Stellar network, but is not yet confirmed.pending_customer_info_update
-- certain pieces of information need to be updated by the Sending Anchor. See the Pending Customer Info Update section for more information.pending_transaction_info_update
-- certain pieces of information need to be updated by the Sending Anchor. See the Pending Transaction Info Update section for more information.pending_receiver
-- payment is being processed by the Receiving Anchor.pending_external
-- payment has been submitted to external network, but is not yet confirmed.completed
-- funds have been delivered to the Receiving Client.error
-- catch-all for any error not enumerated above.
Name | Type | Description |
---|---|---|
amount_refunded |
string | The total amount refunded to the Sending Anchor, in units of amount_in_asset . If a full refund was issued, this amount should match amount_in . |
amount_fee |
string | The total amount charged in fees for processing all refund payments, in units of amount_in_asset . The sum of all fee values in the payments object list should equal this value. |
payments |
array | A list of objects containing information on the individual payments made back to the Sending Anchor as refunds. The schema for these objects is defined in the section below. |
Name | Type | Description |
---|---|---|
id |
string | The Stellar transaction hash of the transaction that included the refund payment. This id is not guaranteed to be unique. |
amount |
string | The amount sent back to the Sending Anchor for the payment identified by id , in units of amount_in_asset . |
fee |
string | The amount charged as a fee for processing the refund, in units of amount_in_asset . |
The following should hold true for all transaction records, assuming amount_in_asset
and amount_out_asset
are the same. If they are different, the following should still hold true after converting all amounts to units of one of the assets.
amount_out = amount_in - amount_fee - refunds.amount_refunded - refunds.amount_fee
refunds.amount_refunded = sum(refunds.payments[].amount)
refunds.amount_fee = sum(refunds.payments[].fee)
Example response:
{
"transaction": {
"id": "82fhs729f63dh0v4",
"status": "pending_external",
"status_eta": 3600,
"stellar_transaction_id": "b9d0b2292c4e09e8eb22d036171491e87b8d2086bf8b265874c8d182cb9c9020",
"external_transaction_id": "ABCDEFG1234567890",
"stellar_account_id": "GBRPYHIL2CI3FNQ4BXLFMNDLFJUNPU2HY3ZMFSHONUCEOASW7QC7OX2H",
"stellar_memo": "123456789",
"stellar_memo_type": "id",
"amount_in": "18.34",
"amount_out": "18.24",
"amount_fee": "0.1",
"started_at": "2017-03-20T17:05:32Z"
}
}
{
"transaction": {
"id": "82fhs729f63dh0v4",
"status": "pending_transaction_info_update",
"status_eta": 3600,
"stellar_transaction_id": "b9d0b2292c4e09e8eb22d036171491e87b8d2086bf8b265874c8d182cb9c9020",
"external_transaction_id": "ABCDEFG1234567890",
"amount_in": "18.34",
"amount_out": "18.24",
"amount_fee": "0.1",
"stellar_account_id": "GBRPYHIL2CI3FNQ4BXLFMNDLFJUNPU2HY3ZMFSHONUCEOASW7QC7OX2H",
"stellar_memo": "123456789",
"stellar_memo_type": "id",
"started_at": "2017-03-20T17:05:32Z",
"required_info_message": "The bank reported an incorrect account number for the receiver, please ensure the account matches legal documents",
"required_info_updates": {
"transaction": {
"receiver_account_number": {
"description": "The receiver's bank account number"
}
}
}
}
}
{
"transaction": {
"id": "82fhs729f63dh0v4",
"status": "completed",
"amount_in": "110",
"amount_out": "90",
"amount_fee": "5",
"started_at": "2017-03-20T17:05:32Z",
"stellar_transaction_id": "b9d0b2292c4e09e8eb22d036171491e87b8d2086bf8b265874c8d182cb9c9020",
"stellar_account_id": "GBRPYHIL2CI3FNQ4BXLFMNDLFJUNPU2HY3ZMFSHONUCEOASW7QC7OX2H",
"stellar_memo": "123456789",
"stellar_memo_type": "id",
"refunds": {
"amount_refunded": "10",
"amount_fee": "5",
"payments": [
{
"id": "54321ab047a193c6fda1c47f5962cbcca8708d79b87089ababd57532c21c5402",
"amount": "10",
"fee": "5"
}
]
}
}
}
If the transaction cannot be found, the endpoint should return a 404 NOT FOUND
result.
In certain cases the Receiving Anchor might need to request updated information from the Sending Anchor. For example, if the bank tells the Receiving Anchor that the provided Receiving Client's name is incorrect or missing a middle initial. Since this information was sent via SEP-12, the transaction should go into the pending_customer_info_update
state until the Sending Anchor makes another SEP-12 PUT /customer
request to update. The Sending Anchor can check which fields need to be updated by making a SEP-12 GET /customer
request including the id
or account
& memo
parameters. The Receiving Anchor should respond with a NEEDS_INFO
status and last_name
included in the fields described.
Another possibility is that the per-transaction information provided in the POST /transactions
fields
object was later discovered to be invalid. In this case, the transaction should go into the pending_transaction_info_update
state until the Sending Anchor makes a request to the endpoint outlined below.
This endpoint should only be used when the Receiving Anchor needs more info via the pending_transaction_info_update
status from the Sending Anchor. The required_info_updates
transaction field should contain the fields required for the update. If the Sending Anchor tries to update at a time when no info is requested, the Receiving Anchor should fail with an error response.
PATCH DIRECT_PAYMENT_SERVER/transactions/:id
Request parameters:
Name | Type | Description |
---|---|---|
id |
string | The id of the transaction. |
fields |
object | A key-pair object containing the values requested to be updated by the receiving anchor in the same format as fields in the POST /transactions request. |
PATCH DIRECT_PAYMENT_SERVER/transactions/82fhs729f63dh0v4
{
"fields": {
"transaction": {
"receiver_bank_account": "12345678901234",
"receiver_routing_number": "021000021"
}
}
}
If the information was successfully updated and all fields required for the transaction are patched, respond with a 200 status code, and return a response body matching GET /transactions/:id
. The transaction should return to pending_receiver
, though it is possible that the information could still need to be updated again.
If the transaction specified by "id"
does not exist, return a 404 response.
If the information was malformed, or if the sender tried to update data that isn't updatable, return a 400 with an object containing an error message.
{
"error": "Supplied fields do not allow updates, please only try to updates the fields requested"
}
v1.6.0
: Updated the "Sending Anchor Flow" so the Sending Anchor needs to reach theGET /transactions/:id
endpoint to get the payment information before sending the payment to the Receiving Anchor. (#????)v1.5.5
: Updated the description ofPATCH /transactions
. (#1166)v1.5.4
: Add the state diagram of a SEP-31 transaction. (#1164)v1.5.3
: Clarify whensender_id
andreceiver_id
attributes are required forPOST /transactions
requests. (#1158)v1.5.2
: Add a use case when the receiving client may receive on-stellar asset. (#1149)v1.5.1
: Add a sequence diagram for successful transactions using firm quotes. (#1145)v1.5.0
: Deprecate refunded boolean. Add refund object to transaction records. (#1128)