#Simple Summary
This SEP defines the standard way for wallets to interact with anchors on behalf of users. This improves user experience by allowing wallets and other clients to interact with anchors directly without the user needing to leave the wallet to go to the anchor's site.
It is based on, but backwards incompatible with SEP-0006.
There are cases where the anchor service might wish that all interactions with users happen on a different app or web service hosted by the anchor itself. For such cases, please refer to the interactive workflow found in SEP-0024.
#Abstract
This proposal defines a standard protocol enabling the following features directly within a wallet or other Stellar client:
- Deposit external assets with an anchor
- Withdraw assets from an anchor
- Communicate deposit & withdrawal fee structure for an anchor to the user
- Handle anchor KYC needs
- Check the status of ongoing deposits or withdrawals involving the user
- View history of deposits and withdrawals involving the user
To support this protocol, an anchor acts as a server and implements the specified REST API endpoints, while a wallet implements a client that consumes the API. The goal is interoperability, so a wallet implements a single client according to the protocol, and will be able to interact with any compliant anchor. Similarly, an anchor that implements the API endpoints according to the protocol will work with any compliant wallet.
#SEP-0027 Asset Information Response
SEP-27 specifies an endpoint that provides extra information
about an asset. We define our SEP-26 transfer protocols parameters inside the
transfer_protocols field as specified in SEP-0027.
{
"transfer_protocols": {
"sep26": {
"transfer_server": "https://api.examplebtcanchor.com",
"fund_wallet": {
"enabled": true,
"amount_native": 5,
"fee": "2 * XLM/BTC market price",
"funding_protocols": ["sep25"]
},
"deposits": {
"enabled": true,
"authentication_protocols": []
},
"withdrawals": {
"enabled": true,
"authentication_protocols": ["sep10"],
"fields": [
{
"id": "priority",
"name": "Priority",
"type": "choice",
"choices": [
{
"value": "low",
"title": "Low"
},
{
"value": "med",
"title": "Medium"
},
{
"value": "high",
"title": "High"
}
]
}
]
},
"transaction_history": {
"enabled": true,
"authentication_protocols": ["sep10"]
},
"authentication_protocols": {
"sep10": {
"authentication_server": "sep10.auth.server.com",
"authentication_signing_key": "GCKLZLMYTLRBKM6BDZJYAKHDBSNCGBSN7EDF32FMIAYFAITLCB45ZJW4"
}
}
}
}
}
{
"transfer_protocols": {
"sep26": {
"transfer_server": "https://acme.inc/api26/usd",
"deposits": {
"enabled": true,
"authentication_protocols": ["sep10"],
"options": [
{
"id": "cashapp",
"name": "Cash App",
"fee": "1 USD",
"logo": "https://squa.re/cashapp.png",
"fields": [
{
"id": "email",
"optional": true,
"title": "Your Email",
"description": "Your email will enable us to automatically notify you about the status of your withdrawal."
}
]
},
{
"id": "wire",
"name": "Wire Transfer",
"fee": "0.1% + 1 USD",
"logo": "https://acme.inc/bank_wire_logo.png",
"fields": [
{
"id": "email",
"optional": true,
"title": "Your Email",
"description": "Your email will enable us to automatically notify you about the status of your withdrawal."
}
]
}
]
},
"withdrawals": {
"enabled": true,
"authentication_protocols": ["sep10"],
"options": [
{
"id": "facebook_pay",
"name": "Facebook Pay",
"fee": "0.1% + 1 USD",
"logo": "https://fb.com/pay.png",
"fields": [
{
"id": "dest",
"title": "Your Facebook Pay ID"
}
]
},
{
"id": "google_cache",
"name": "Google Cache",
"fee": "0.1% + 1 USD",
"logo": "https://goog.com/cache.png",
"fields": [
{
"id": "dest",
"title": "Your Google Cache ID"
}
]
},
{
"id": "cashapp",
"name": "Cash App",
"fee": "0.2% + 1 USD",
"logo": "https://squa.re/cashapp.png",
"fields": [
{
"id": "dest",
"title": "Your Google Cache ID"
},
{
"id": "email",
"optional": true,
"title": "Your Email",
"description": "Your email will enable us to automatically notify you about the status of your withdrawal."
}
]
},
{
"id": "wire",
"name": "Wire Transfer",
"fee": "0.1% + 1 USD",
"logo": "https://acme.inc/bank_wire_logo.png",
"fields": [
{
"id": "swift_code",
"title": "Swift Code"
},
{
"id": "routing_number",
"title": "Routing Number"
},
{
"id": "dest",
"title": "Account Number"
},
{
"id": "receiver_name",
"title": "Full names of your recepient"
},
{
"id": "reason",
"title": "Reason for the transfer"
},
{
"id": "email",
"optional": true,
"title": "Your Email",
"description": "Your email will enable us to automatically notify you about the status of your withdrawal."
}
]
}
]
},
"transaction_history": {
"enabled": true,
"authentication_protocols": ["sep10"]
},
"authentication_protocols": {
"sep10": {
"authentication_server": "sep10.auth.server.com",
"authentication_signing_key": "GCKLZLMYTLRBKM6BDZJYAKHDBSNCGBSN7EDF32FMIAYFAITLCB45ZJW4"
}
}
}
}
}
{
"transfer_protocols": {
"sep26": {
"transfer_server": "https://acme.inc/api26/cny",
"deposits": {
"enabled": true,
"authentication_protocols": ["sep10"],
"options": [
{
"id": "wechat",
"name": "WeChat",
"fee": "0 CNY",
"logo": "https://wech.at/wechat.png"
},
{
"id": "alipay",
"name": "AliPay",
"fee": "0 CNY",
"logo": "https://alip.ay/alipay.png"
}
]
},
"withdrawals": {
"enabled": true,
"authentication_protocols": ["sep10"],
"options": [
{
"id": "wechat",
"name": "WeChat",
"fee": "0.1% + 1 CNY",
"logo": "https://wech.at/wechat.png",
"fields": [
{
"id": "dest",
"title": "Your WeChat ID"
}
]
},
{
"id": "alipay",
"name": "AliPay",
"fee": "0.1% + 1 CNY. Max 10 CNY.",
"logo": "https://alip.ay/alipay.png",
"fields": [
{
"id": "dest",
"title": "Your AliPay ID"
}
]
}
]
},
"transaction_history": {
"enabled": true,
"authentication_protocols": ["sep10"]
},
"authentication_protocols": {
"sep10": {
"authentication_server": "sep10.auth.server.com",
"authentication_signing_key": "GCKLZLMYTLRBKM6BDZJYAKHDBSNCGBSN7EDF32FMIAYFAITLCB45ZJW4"
}
}
}
}
}
#Transfer Protocol sep26
The concept of "transfer protocols" was introduced in SEP-27. By
convention, the transfer protocol described in this document will be called
sep26. Other transfer protocols include sep24.
The following fields are allowed under the sep26 object.
| Field | Type | Description |
|---|---|---|
transfer_server | url | The asset's transfer server for handling deposits, withdrawals and transaction history. |
Certain anchored assets may support the ability to fund unfunded accounts. In
that case, the anchor should define the fund_wallet field under the sep26
field.
The following fields are allowed under fund_wallet:
| Field | Type | Description |
|---|---|---|
enabled | boolean | Set to true for assets that support funding of unfunded wallet accounts. Default is false if not set. |
amount_native | number | The number of lumens the anchored asset will use to fund the wallet |
fees | string | human readable fee structure for funding accounts. e.g. "2 * XLM/BTC market price". |
funding_protocols | array | An array of funding protocols the anchored asset supports. e.g. "sep25". For custom funding protocols that only work on specific wallets, simply use the name of your supported wallets e.g. ["sep25", "walleta", "walletb"] |
Deposit metadata for each anchored asset is specified inside the deposits
field
The following fields are allowed:
| Field | Type | Description |
|---|---|---|
enabled | boolean | Determines if deposits are supported or not. Wallets should consider deposits disabled if this field is not specified. |
authentication_protocols | array | An array of all authentication methods supported by the anchored asset when performing deposits. An anchored asset that doesn't need any authentication protocol for deposits doesn't need to specify this field. You could for example set the value for authentication_protocols to ["sep10"], if an anchored asset supports SEP-10 authentication for deposits. |
An array of objects containing all supported deposit options for the asset.
The following fields are allowed under each deposit option.
| Field | Type | Description |
|---|---|---|
id | string (required) | e.g. crypto, mobilemoney, wire |
name | string | Short name for the deposit option. |
min_amount | number | Minimum deposit amount supported by this deposit option. |
max_amount | number | Maximum deposit amount supported by this deposit option. |
fee | string/url | Human readable fee structure supported by this deposit option. e.g. "1 USD", "0.1%", "0.1% plus 0.001 BTC", "0.1%, Max: 100 USD", "https://acme.inc/ourfees" |
An array of form fields supported for each deposit option.
The following fields are allowed.
| Field | Type | Description |
|---|---|---|
id | string (required) | Id of the form field. e.g. dest, email, routing_number. |
title | string | Title of the form field e.g. "Your Email", "Routing Number". |
description | string | Description of the form field. |
optional | boolean | Marks the form field as optional or not. |
type | string | One of 'text', 'number', 'email', or 'choice'. The default form field type is text. See below on how to specify choices for the 'choice' type. |
An array of choices for deposit form fields that have type set to choice.
| Field | Type | Description |
|---|---|---|
value | string (required) | e.g. This is the value that will be sent back to the deposit api endpoint. e.g. "bank001". |
title | string | Human readable title for the choice. E.g. Bank of America. |
See the [BTC SEP-0027 example response](#btc-example) above of an asset that uses the choice type on a withdrawal field.
See "sep26.deposits"
Transaction history metadata for each anchored asset is specified inside the
transaction_history field.
The following fields are allowed:
| Field | Type | Description |
|---|---|---|
enabled | boolean | Determines if transaction history is enabled or not. Wallets should consider transaction history disabled if this field is not specified. |
authentication_protocols | array | An array of all authentication methods supported by the anchored asset when querying transaction history. An anchored asset that doesn't need any authentication protocol for transaction history doesn't need to specify this field. You could for example set the value for authentication_protocols to ["sep10"], if an anchored asset supports SEP-10 authentication for transaction history. |
Authentication configuration parameters for each supported authentication
protocol is defined under the authentication_protocols field.
The fields allowed depend on each authentication protocol.
For SEP-0010, you need to specify two fields:
| Field | Type | Description |
|---|---|---|
authentication_server | url | Server to use for SEP-10 authentication. |
authentication_signing_key | G... | Public key used for signing SEP-0010 transactions. |
#API Endpoints
POST /deposit: requiredPOST /withdraw: requiredGET /transactions: optional, but recommendedGET /transaction: optional
#Authentication
Asset anchors that need authentication should do the relevant changes to their SEP-0027 response JSON as stipulated above.
Wallets, clients and anchors should follow the authentication protocol specifications of each supported authentication protocol. For example SEP-10 web authentication to enable authenticated deposits, withdrawals, or transaction history lookups.
#Cross-Origin Headers
Valid CORS headers are necessary to allow web clients from other sites to use the endpoints. The following HTTP header must be set for all transfer server responses, including error responses.
Access-Control-Allow-Origin: *
#HTTPS Only
This protocol involves the transfer of value, and so HTTPS is required for all endpoints for security. Wallets and anchors should refuse to interact with any insecure HTTP endpoints.
#Recommendations
SEP-26 lays out many options for how deposit and withdrawal can work non-interactively. These are recommendations for getting a wallet or anchor implementation working with minimal effort while providing a great user experience.
Note: Both wallets and anchors should implement a sandbox mode for testing that uses the Stellar testnet.
#Basic Wallet Implementation
- Identify anchors you want to support manually, and test them with your wallet to be sure they work before allowing them to be used with your wallet. We encourage you to support as many anchors as possible.
- For each anchor, use information from its
stellar.tomlfile and SEP-27 response to display useful information to the user about the asset they've picked. Asset information obtained via SEP-0027 takes precendence over the same information found in stellar.toml. This is especially true for fields that need localization. - Provide a UI that allows users to pick an asset, anchor, and amount to use
for deposit or withdraw. The UI should display the asset's fee structure (if
possible) as well as information such as the address of the anchor and
description of the asset from the
stellar.tomlfile and SEP-0027 response. - Use the
SEP-27response to:- Determine which anchor endpoints will require authentication
- Fetch the asset's deposit & withdawal fee structure: show this to the user early in the process so they're fully informed.
- Authentication
- If needed, perform authentication via SEP-0010 or any other supported authentication mechanism before hitting those endpoints
- Make a request to
/depositor/withdraw. - For
/deposit- If the issuer's
/depositendpoint immediately returns success:- display the deposit info that came back from the endpoint to the user, including fee. You're done! The user will execute the deposit exernally using the instructions if they want to.
- Handle the special cases, they're relatively common.
- If the issuer's
- For
/withdraw- If the issuer's
/withdrawendpoint immediately returns success:- Provide an interface to the user that allows them to view the withdrawal details including the computed fee. The user can confirm and then the wallet will initiate the withdrawal by sending the Stellar payment to the address provided by the issuer.
- Some wallets might exchange currencies only once they're ready to send the
withdrawal payment, so exchange rate fluctuations might require withdrawal
values to slightly vary from the originally provided
amount. Anchors are instructed to accept a variation of ±10% between the informedamountand the actual value sent to the anchor's Stellar account. The withdrawn amount will be adjusted accordingly.
- If the issuer's
- Transaction history
- It provides a better experience for users to show deposits or withdrawals
they've completed in the past via the
/transactionsendpoint, but it's not strictly necessary.
- It provides a better experience for users to show deposits or withdrawals
they've completed in the past via the
#Basic Anchor Implementation
- Decide which endpoints, if any, need to be authenticated.
- Pick your approach to [fees].
- Providing transaction status
- Provide the
/transactionendpoint. The wallet may rely on it to complete non-interactive withdrawals. - Provide the
/transactionsendpoint. Users like to see transaction histories.
- Provide the
#Deposit
A deposit is when a user sends an external token (BTC via Bitcoin, USD via bank transfer, etc...) to an address held by an anchor. In turn, the anchor sends an equal amount of tokens on the Stellar network (minus fees) to the user's Stellar account.
The deposit endpoint allows a wallet to get deposit information from an anchor, so a user has all the information needed to initiate a deposit. It also lets the anchor specify additional information (if desired) that the user must submit interactively to be able to deposit.
If the given account does not exist, or if the account doesn't have a trust line for that specific asset, see the Special Cases section below.
#Request
POST TRANSFER_SERVER/deposit
Content-Type: multipart/form-data
Request Parameters:
| Name | Type | Description |
|---|---|---|
asset_code | string | The code of the asset the user wants to deposit with the anchor. E.g. BTC, ETH, USD, INR, etc. This should be the same asset code specified in the stellar.toml file. |
asset_issuer | string | The issuer of the asset the user wants to deposit with the anchor. |
account | G... string | The stellar account ID of the user that wants to deposit. This is where the asset token will be sent to. |
memo_type | string | (optional) Type of memo that the anchor should attach to the Stellar payment transaction, one of text, id or hash. |
memo | string | (optional) Value of memo to attach to transaction, for hash this should be base64-encoded. |
email_address | string | (optional) Email address of depositor. If desired, an anchor can use this to send email updates to the user about the deposit. |
type | string | (required) Deposit option. If the anchor supports one or multiple deposit methods (e.g. SEPA or SWIFT), the wallet should specify type. The type should be set to one of the deposit options defined above in the SEP-0027 json response. |
wallet_name | string | (optional) In communications / pages about the deposit, anchor should display the wallet name to the user to explain where funds are going. |
wallet_url | string | (optional) Anchor should link to this when notifying the user that the transaction has completed. |
lang | string | (optional) Defaults to en. Language code specified using ISO 639-1. error fields in the response should be in this language. |
Example:
POST https://api.example.com/deposit
Content-Type: multipart/form-data
asset_code=ETH&account=GACW7NONV43MZIFHCOKCQJAKSJSISSICFVUJ2C6EZIW5773OU3HD64VI
#Response
There are several types of responses, depending on whether the anchor needs more information about the user, how it should be sent to the anchor, and if there are any errors.
The first response, the success response, is explained below. The other possible responses are shared with the withdrawal endpoint, and are explained in the Deposit and Withdraw shared responses section below.
#1. Success: no additional information needed
Response code: 200 OK
This is the correct response if the anchor is able to accept the deposit and needs no additional information about the user. It should also be used if the anchor requires information about the user, but the information has previously been submitted and accepted.
The response body should be a JSON object with the following fields:
| Name | Type | Description |
|---|---|---|
how | string | Markdown formatted instructions on how to deposit the asset. In the case of most cryptocurrencies it is just an address to which the deposit should be sent to. Important: Wallets should make sure markdown inputs are sanitized for security purposes. |
eta | int | (optional) Estimate of how long the deposit will take to credit in seconds. |
min_amount | float | (optional) Minimum amount of an asset that a user can deposit. |
max_amount | float | (optional) Maximum amount of asset that a user can deposit. |
fee | float | (optional) Calculated fee (if any). In units of the deposited asset. |
extra_info | array | (optional) JSON array with additional information about the deposit process. Each element in the array is formatted as follows {key: KEY, value: VALUE}. Wallets are encouraged to present extra_info in a tabular manner and enable easy copy to clipboard for each line value. |
{
"how": "1Nh7uHdvY6fNwtQtM1G5EZAFPLC33B59rB",
"fee": 0.0002
}
{
"how": "**Ripple address**: rNXEkKCxvfLcM1h4HJkaj2FtmYuAWrHGbf\n\n**tag:** 88",
"eta": 60,
"fee": 0.1,
"extra_info": [
{
"key": "Important",
"value": "Do not forget the tag"
},
{
"key": "Ripple Address",
"value": "rNXEkKCxvfLcM1h4HJkaj2FtmYuAWrHGbf"
},
{
"key": "Tag",
"value": "88"
}
]
}
{
"how": "\n\nMake a payment to Bank: STP\n\nAccount: 646180111803859359",
"eta": 1800,
"fee": 100,
"extra_info": [
{
"key": "Bank",
"value": "STP"
},
{
"key": "Swift Code",
"value": "XYZ"
},
{
"key": "Account",
"value": "646180111803859359"
}
]
}
Special Cases
Stellar account does not exist
If the given Stellar account does not exist, on receipt of the deposit, the
anchor should use create_account to create the account with at least enough
XLM for the minimum reserve and a trust line (2.01 XLM is recommended). The
anchor should take some of the asset that is sent in to pay for the XLM. The
anchor should not list this minimal funding as a fee because the user still
receives the value of the XLM in their account. The anchor should detect if the
account has been created before returning deposit information, and adjust the
min_amount in the response to be at least the amount needed to create the
account.
Since the anchor doesn't have the user account's secret key, the user must create a trust line to the anchor's asset before the anchor can send the remaining asset tokens to the user's account. The anchor should listen for the user to establish this trust line. Once the trust line is there, the anchor should send the remaining asset tokens to the account in Stellar to complete the deposit.
If the anchor does not support creating new accounts for users and account
doesn't exist yet, the anchor should return a 400 Bad Request error. The
response body should be a JSON object containing an error field that explains
why the request failed.
Stellar account doesn't trust asset
The deposit flow can only be fulfilled if the Stellar Account has established
a trust line for the given asset. To ensure this is accomplished, when
initiating the deposit flow, Wallet should check if the Account has a trust
line for the given asset. If it doesn't:
Walletchecks ifAccounthas enough XLM to create a trust line. If it does, skip to step4.- If
Accountdoesn't have enough XLM,Walletstarts listening for transactions to the givenAccount, waiting for it to have enough XLM for a trust line. - When asked for a deposit,
Anchordetects ifAccounthas enough XLM to create a trust line. If it doesn't,Anchorsends the needed amount of XLM to theAccountfor creating a trust line.Anchorthen starts listening for trust line creations for thatAccount. Walletdetects the arrival of XLM in theAccount, and establishes a trust line.Anchordetects the trust line creation in theAccount. If the asset isAUTH_REQUIRED,Anchorapproves the new trust line.Anchorproceeds with the deposit flow.
#Withdraw
This operation allows a user to redeem an asset currently on the Stellar network for the real asset (BTC, USD, stock, etc...) via the anchor of the Stellar asset.
The withdraw endpoint allows a wallet to get withdrawal information from an anchor, so a user has all the information needed to initiate a withdrawal. It also lets the anchor specify additional information (if desired) that the user must submit interactively via a popup browser window to be able to withdraw.
#Request
POST TRANSFER_SERVER/withdraw
Content-Type: multipart/form-data
Request parameters:
| Name | Type | Description |
|---|---|---|
asset_code | string | Code of the asset the user wants to withdraw. This must match the asset code issued by the anchor. For example, if a user withdraws MyBTC tokens and receives BTC, the asset_code must be MyBTC. |
asset_issuer | string | The issuer of the asset the user wants to deposit with the anchor. |
amount | number | The amount the user wishes to withdraw. Some anchors may use the amount to withdraw to determine fees. |
type | string | Type of withdrawal. Can be: crypto, bank_account, cash, mobile, bill_payment or other custom values. |
dest | string | The account that the user wants to withdraw their funds to. This can be a crypto account, a bank account number, IBAN, mobile number, or email address. |
account | G... string | The stellar account ID of the user that wants to do the withdrawal. This can be used by the anchor to calculate fees based on the account. It might also be needed if the anchor requires KYC information for withdrawal. The anchor can use account to look up the user's KYC information. |
memo | string | (optional) A wallet will send this to uniquely identify a user if the wallet has multiple users sharing one Stellar account. The anchor can use this along with account to look up the user's KYC info. |
memo_type | string | (optional) Type of memo. One of text, id or hash. |
wallet_name | string | (optional) In communications / pages about the withdrawal, anchor should display the wallet name to the user to explain where funds are coming from. |
wallet_url | string | (optional) Anchor can show this to the user when referencing the wallet involved in the withdrawal (ex. in the anchor's transaction history). |
lang | string | (optional) Defaults to en. Language code specified using ISO 639-1. error fields in the response should be in this language. |
Example:
POST https://api.example.com/withdraw
Content-Type: multipart/form-data
asset_code=ETH&dest=0xde0B295669a9FD93d5F28D9Ec85E40f4cb697BAe
#Response
There are several possible kinds of responses, depending on whether the anchor needs more information about the user, how it should be sent to the anchor, and if there are any errors.
The first response, the success response, is explained below. The other possible responses are shared with the deposit endpoint, and are explained in the Deposit and Withdraw shared responses section directly below.
#1. Success: no additional information needed
Response code: 200 OK
This is the correct response if the anchor is able to execute the withdrawal and needs no additional information about the user. It should also be used if the anchor requires information about the user, but the information has previously been submitted and accepted.
The response body should be a JSON object with the following fields:
| Name | Type | Description |
|---|---|---|
account_id | G... string | The account the user should send its token back to. |
memo_type | string | (optional) Type of memo to attach to transaction, one of text, id or hash. |
memo | string | (optional) Value of memo to attach to transaction, for hash this should be base64-encoded. |
eta | int | (optional) Estimate of how long the withdrawal will take to credit in seconds. |
min_amount | float | (optional) Minimum amount of an asset that a user can withdraw. |
max_amount | float | (optional) Maximum amount of asset that a user can withdraw. |
fee | float | (optional) If there is a fee for withdraw. Already calculated. In units of the withdrawn asset. |
extra_info | array | (optional) JSON array with additional information about the withdrawal process. Each element in the array is formatted as follows {key: KEY, value: VALUE}. Wallets are encouraged to present extra_info in a tabular manner and enable easy copy to clipboard for each line value. |
{
"account_id": "GCIBUCGPOHWMMMFPFTDWBSVHQRT4DIBJ7AD6BZJYDITBK2LCVBYW7HUQ",
"memo_type": "id",
"memo": "123",
"fee": "2.5",
"extra_info": [
{
"key": "Receiver Name",
"value": "Luke Skywalker"
},
{
"key": "Loyalty Program",
"value": "You have 4 more withdrawals left to do to benefit from our discount rates"
}
]
}
#Deposit and Withdraw shared responses
#1. Interactive customer information needed
Response code: 403 Forbidden
An anchor that requires the user to fill out one time information on a
webpage hosted by the anchor should use this response. This can happen in
situations where the anchor needs KYC information about a user, or needs a user
to agree to Terms of Service. A wallet that receives this response should open
a popup browser window or embedded webview to the specified URL. The anchor
must take care that the popup page displays well on a mobile device, as many
wallets are phone apps.
Note that this is for one time information only. Please use SEP-24 instead if you need other custom steps interactive to be performed for every deposit and withdrawal. e.g. SMS confirmation before withdrawing.
The response body must be a JSON object with the following fields:
| Name | Type | Description |
|---|---|---|
type | string | Always set to interactive_customer_info_needed. |
url | string | URL hosted by the anchor. The wallet should show this URL to the user either as a popup or an iframe. We encourage anchors to make this url unique for each wallet, and to include a required random short-lived session id for privacy and security reasons. |
{
"type": "interactive_customer_info_needed",
"url": "https://api.example.com/kycflow?account=GACW7NONV43MZIFHCOKCQJAKSJSISSICFVUJ2C6EZIW5773OU3HD64VI&session_id=short_lived_random_uuid"
}
jwt details
Even when the user has authenticated with SEP-0010, the wallet should NEVER pass the jwt into the interactive URL.
#2. Customer Information Needed
Response code: 403 Forbidden
An anchor should use this response if customer information was submitted for
the account, but the information is either still being processed or was not
accepted.
| Name | Type | Description |
|---|---|---|
type | string | Always set to customer_info_status. |
status | string | Status of customer information processing. One of: pending, denied. |
more_info_url | string | (optional) A URL the user can visit if they want more information about their account / status. We encourage anchors to make this url unique for each wallet, and to include a required random short-lived session id for privacy and security reasons. |
eta | int | (optional) Estimated number of seconds until the customer information status will update. |
If the anchor decides that more customer information is needed after receiving
some information and processing it, it can respond again with a response of
type interactive_customer_info_needed. In the case of a denied request, an
anchor can use the more_info_url to explain to the user the issue with their
request and give them a way to rectify it manually. A wallet should show the
more_info_url to the user when explaining that the request was denied.
Note: this status response should never be used in the case that the user's KYC request succeeds. In that case, the anchor should respond with a deposit / withdrawal address as described by those endpoints.
{
"type": "customer_info_status",
"status": "denied",
"more_info_url": "https://api.example.com/kycstatus?account=GACW7NONV43MZIFHCOKCQJAKSJSISSICFVUJ2C6EZIW5773OU3HD64VI&session_id=random_short_lived_uuid"
}
#3. Authentication required
Response code: 401 Authorization
This endpoint requires authentication.
{
"type": "authentication_required"
}
#4. Error
Every other HTTP status code will be considered an error. The body should contain a string indicating the error details. This error is in a human readable format in the language indicated in the request and is intended to be displayed by the wallet. For example:
{
"error": "This anchor doesn't support the given currency code: ETH"
}
#Transaction History
The transaction history endpoint helps anchors enable a better experience for users using an external wallet. With it, wallets can display the status of deposits and withdrawals while they process and a history of past transactions with the anchor. It's only for transactions that are deposits to or withdrawals from the anchor.
GET TRANSFER_SERVER/transactions
Request parameters:
| Name | Type | Description |
|---|---|---|
asset_code | string | The code of the asset of interest. E.g. BTC, ETH, USD, INR, etc. |
asset_issuer | string | The issuer of the asset the user wants to deposit with the anchor. |
account | string | The stellar account ID involved in the transactions. |
no_older_than | UTC ISO 8601 string | (optional) The response should contain transactions starting on or after this date & time. |
limit | int | (optional) The response should contain at most limit transactions. |
kind | string | (optional) The kind of transaction that is desired. Should be either deposit or withdrawal. |
paging_id | string | (optional) The response should contain transactions starting prior to this ID (exclusive). |
On success the endpoint should return 200 OK HTTP status code and a JSON
object with the following fields:
| Name | Type | Description |
|---|---|---|
transactions | array | List of transactions as requested by the client, sorted in time-descending order. |
Each object in the transactions array should have the following fields:
| Name | Type | Description |
|---|---|---|
id | string | Unique, anchor-generated id for the deposit/withdrawal. |
kind | string | deposit or withdrawal. |
status | string | Processing status of deposit/withdrawal. |
status_eta | number | (optional) Estimated number of seconds until a status change is expected. |
more_info_url | string | (optional) A URL the user can visit if they want more information about their account / status. |
amount_in | string | (optional) Amount received by anchor at start of transaction as a string with up to 7 decimals. Excludes any fees charged before the anchor received the funds. |
amount_out | string | (optional) Amount sent by anchor to user at end of transaction as a string with up to 7 decimals. Excludes amount converted to XLM to fund account and any external fees. |
amount_fee | string | (optional) Amount of fee charged by anchor. |
from | string | (optional) Sent from address (perhaps BTC, IBAN, or bank account in the case of a deposit, Stellar address in the case of a withdrawal). |
to | string | (optional) Sent to address (perhaps BTC, IBAN, or bank account in the case of a withdrawal, Stellar address in the case of a deposit). |
external_extra | string | (optional) Extra information for the external account involved. It could be a bank routing number, BIC, or store number for example. |
external_extra_text | string | (optional) Text version of external_extra. This is the name of the bank or store. |
deposit_memo | string | (optional) If this is a deposit, this is the memo (if any) used to transfer the asset to the to Stellar address |
deposit_memo_type | string | (optional) Type for the deposit_memo. |
withdraw_anchor_account | string | (optional) If this is a withdrawal, this is the anchor's Stellar account that the user transferred (or will transfer) their issued asset to. |
withdraw_memo | string | (optional) Memo used when the user transferred to withdraw_anchor_account. |
withdraw_memo_type | string | (optional) Memo type for withdraw_memo. |
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) transaction_id on Stellar network of the transfer that either completed the deposit or started the withdrawal. |
external_transaction_id | string | (optional) ID of transaction on external network that either started the deposit or completed the withdrawal. |
message | string | (optional) Human readable explanation of transaction status, if needed. |
refunded | boolean | (optional) Should be true if the transaction was refunded. Not including this field means the transaction was not refunded. |
status should be one of:
completed-- deposit/withdrawal fully completed.pending_external-- deposit/withdrawal has been submitted to external network, but is not yet confirmed. This is the status when waiting on Bitcoin or other external crypto network to complete a transaction, or when waiting on a bank transfer.pending_anchor-- deposit/withdrawal is being processed internally by anchor.pending_stellar-- deposit/withdrawal operation has been submitted to Stellar network, but is not yet confirmed.pending_trust-- the user must add a trust-line for the asset for the deposit to complete.pending_user-- the user must take additional action before the deposit / withdrawal can complete.pending_user_transfer_start-- the user has not yet initiated their transfer to the anchor. This is the necessary first step in any deposit or withdrawal flow.incomplete-- there is not yet enough information for this transaction to be initiated. Perhaps the user has not yet entered necessary info in an interactive flow.no_market-- could not complete deposit because no satisfactory asset/XLM market was available to create the account.too_small-- deposit/withdrawal size less thanmin_amount.too_large-- deposit/withdrawal size exceededmax_amount.error-- catch-all for any error not enumerated above.
{
"transactions": [
{
"id": "82fhs729f63dh0v4",
"kind": "deposit",
"status": "pending_external",
"status_eta": 3600,
"external_transaction_id": "2dd16cb409513026fbe7defc0c6f826c2d2c65c3da993f747d09bf7dafd31093",
"amount_in": "18.34",
"amount_out": "18.24",
"amount_fee": "0.1",
"started_at": "2017-03-20T17:05:32Z"
},
{
"id": "82fhs729f63dh0v4",
"kind": "withdrawal",
"status": "completed",
"amount_in": "500",
"amount_out": "495",
"amount_fee": "3",
"started_at": "2017-03-20T17:00:02Z",
"completed_at": "2017-03-20T17:09:58Z",
"stellar_transaction_id": "17a670bc424ff5ce3b386dbfaae9990b66a2a37b4fbe51547e8794962a3f9e6a",
"external_transaction_id": "2dd16cb409513026fbe7defc0c6f826c2d2c65c3da993f747d09bf7dafd31093"
}
]
}
Every HTTP status code other than 200 OK will be considered an error. An
empty transaction list is not an error. The body should contain error
details. For example:
{
"error": "This anchor doesn't support the given currency code: ETH"
}
#Single Historical Transaction
The transaction endpoint enables clients to query/validate a specific transaction at an anchor.
GET TRANSFER_SERVER/transaction
Request parameters:
| Name | Type | Description |
|---|---|---|
id | string | (optional) The id of the transaction. |
stellar_transaction_id | (optional) string | The stellar transaction id of the transaction. |
external_transaction_id | (optional) string | The external transaction id of the transaction. |
One of id, stellar_transaction_id or external_transaction_id is required.
On success the endpoint should return 200 OK HTTP status code and a JSON
object with the following fields:
| Name | Type | Description |
|---|---|---|
transaction | object | The transaction that was requested by the client. |
The transaction object should be of the same form as the objects returned by
the TRANSFER_SERVER/transactions endpoint.
{
"transaction": {
"id": "82fhs729f63dh0v4",
"kind": "deposit",
"status": "pending_external",
"status_eta": 3600,
"external_transaction_id": "2dd16cb409513026fbe7defc0c6f826c2d2c65c3da993f747d09bf7dafd31093",
"amount_in": "18.34",
"amount_out": "18.24",
"amount_fee": "0.1",
"started_at": "2017-03-20T17:05:32Z"
}
}
If the transaction cannot be found, the endpoint should return a
404 NOT FOUND result.
Every HTTP status code other than 200 OK will be considered an error. An
empty transaction list is not an error. The body should contain error
details. For example:
{
"error": "This anchor doesn't support the given currency code: ETH"
}