Skip to content
Permalink
master
Go to file
### What
Remove use of the terms whitelist and blacklist, replacing them with other descriptions of what functionality is intended or with other terms allowlist and denylist.

### Why
The terms whitelist and blacklist make many people feel unwelcome and can trigger racial stereotyping. A similar change was made on the Go repository which prompted me to check if we used these terms in our documentation or code. golang/go@608cdca

The terms whitelist and blacklist are not better at communicating intent than simply describing the behavior we're looking for or than using another term. This seems like an easy change to make with no cost that improves the general language of our documentation. An example of how this generally improves the documentation is this sentence where we state:

>...test them with your wallet to be sure they work before allowing them to be used with your wallet.

Which is much clearer and easier to read than the original:

>...test them with your wallet to be sure they work before whitelisting them.

This changes previously accepted documents. I don't think that is particularly an issue given than the meaning of the documents remains the same.
18 contributors

Users who have contributed to this file

@tomquisel @msfeldstein @istrau2 @accordeiro @vcarl @s-a-y @marcinx @christian-rogobete @vitchor @tomerweller @leighmcculloch @jimdanz
844 lines (639 sloc) 50.3 KB

Preamble

SEP: 0006
Title: Anchor/Client interoperability
Author: SDF
Status: Active (Interactive components are deprecated in favor of SEP-24)
Created: 2017-10-30
Updated: 2020-04-01
Version 3.1.1

Simple Summary

This SEP defines the standard way for anchors and wallets to interact 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.

Please note that the interactive components of the SEP are deprecated in favor of SEP-24. For non-interactive integrations, this SEP provides a normalized interface specification that allow wallets and other services to interact with anchors programmatically.

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, including transmitting KYC information about the user to the anchor via SEP-12
  • 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.

Prerequisites

  • An anchor must define the location of their TRANSFER_SERVER in their stellar.toml. This is how a wallet knows where to find the anchor's server.
  • Anchors and clients may support SEP-10 web authentication to enable authenticated deposits, withdrawals, or transaction history lookups

API Endpoints

Authentication

Anchors may support SEP-10 web authentication to enable authenticated deposits, withdrawals, or transaction history lookups. In cases where authentication is required:

  1. anchors must set the authentication_required field in their info endpoint
  2. clients must submit the JWT previously obtained from the anchor via the SEP-10 authentication flow to all API endpoints.

The JWT should be included in all requests as request header:

Authorization: Bearer <JWT>

In the case of the interactive webapp, since the client cannot add the authorization header, The JWT should be passed as a jwt query parameter:

?jwt=<token>

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-6 lays out many options for how deposit and withdrawal can work. 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.toml file and its /info endpoint to display useful information to the user about the asset they've picked.
  • Provide an interface that allows users to pick an asset, anchor, and amount to use for deposit or withdraw. The interface 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.toml file.
  • Use the /info endpoint
    • Determine which anchor endpoints will require authentication
    • Fetch the asset's deposit & withdawal fee structure: if fee_fixed and fee_percent are provided, show this to the user early in the process so they're fully informed.
    • If the /fee endpoint is enabled, use it for computing fees when you need to show them to the user.
    • While /info allows an anchor to communicate non-standard fields that are needed for /deposit or /withdraw, it's easier for a basic wallet implementation to hard-code extra fields that are needed on a per-anchor basis, and ensure those fields are passed in properly.
  • Authentication
    • If needed, perform authentication via SEP-10 before hitting those endpoints
  • Make a request to /deposit or /withdraw.
    • As a conservative measure, pass in any optional fields (including amount) that the wallet has on-hand, such as email_address and account.
    • In the /withdraw request, don't bother providing dest or dest_extra if the anchor uses an interactive flow. Otherwise have the user enter the crypto account or bank account where they'd like their withdrawal to end up, and provide that to the anchor via dest and dest_extra.
  • For /deposit
    • If the issuer's /deposit endpoint 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.
    • If the issuer responds with an interactive flow, handle it as described in detail. We expect this is the most common flow, and it should work smoothly.
    • For now, do not handle the non-interactive or status responses to the /deposit request.
    • Handle the special cases, they're relatively common.
  • For /withdraw
    • If the issuer's /withdraw endpoint 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.
    • If the anchor responds with an interactive flow, handle it as described in detail.
    • For now, do not handle the non-interactive or status responses to the /withdraw request.
    • 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 informed amount and the actual value sent to the anchor's Stellar account. The withdrawn amount will be adjusted accordingly.
  • Transaction history
    • It provides a better experience for users to show deposits or withdrawals they've completed in the past via the /transactions endpoint, but it's not strictly necessary.

Basic Anchor Implementation

  • Provide a full-featured implementation of /info. Leave the fields object in the withdraw object empty if you accept all your necessary fields in your interactive flow.
  • Decide which endpoints, if any, need to be authenticated, and declare that properly in the /info endpoint.
  • Pick your approach to fees. We recommend using /info to express fees as it provides a better user experience (the user can see the fee structure in the wallet early in the process).
  • For both deposit and withdrawal:
    • We recommend you use the interactive flow. It's flexible and simple to integrate.
    • To start an interactive flow, provide the Customer info needed response.
    • Include the id field in your response so the wallet can check up on the status of the transaction if it wants.
    • Also include the id field in the popup URL you provide to the wallet. This allows you to keep track of the transaction when the user visits the URL.
    • Make sure to pass along the amount to the popup URL, especially on the /withdraw flow.
    • We recommend you use SEP-10 authentication in the interactive flow and do not separately prompt for password to achieve a good user experience (although asking for MFA when confirming a transaction or requiring email confirmation is reasonable). Be sure to accept the jwt parameter so the user does not have to re-login. Support the callback parameter as well.
    • Test your interactive flows on mobile. They should be easy to use on all devices: make them responsive, handle auto-fill well, and do smart keyboard management on mobile devices.
  • Interactive deposit
    • Your interactive deposit popup will do everything needed to initiate the deposit without the user needing to interact with the wallet further. It should either directly initiate the deposit, or handle displaying information (such as reference number or bank account number) that the user will need to complete their deposit.
  • Interactive withdrawal
    • Your withdrawal flow will have to pass control back to the user's wallet, so it can initiate the withdrawal with a Stellar payment to your withdrawal address. You'll need to communicate the withdrawal address, amount and status to the wallet using the callback parameter, and also by making it available on your /transaction endpoint. See details.
    • If an amount parameter is provided to the interactive URL, make sure to use that value to pre-populate the amount on the interactive form, since this greatly improves the user experience.
    • In order to fulfill a withdrawal, a wallet must make a payment to the Stellar address that the anchor provides. It is the anchor's job to watch for Stellar payments to the given address and make the external transaction as soon as they're detected. It is recommended for anchors to listen to at least payment and path_payment operations, although supporting the remaining ones is important for covering all use cases. Most Stellar SDKs already support listening to all payment forms via streaming.
    • Some wallets might exchange currencies only once they're ready to send the withdrawal payment, so there might be slight fluctuations of value between the informed withdrawal amount and the actual transferred amount. It is recommended for anchors to accept an amount fluctuation of up to ±10%, and adjust the amount to be transferred (and fees) to reflect the actual value received.
  • Providing transaction status
    • Provide the /transaction endpoint. The wallet may rely on it to complete interactive withdrawals.
    • Provide the /transactions endpoint. Users like to see transaction histories.

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 via a popup browser window or via SEP-12 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

GET TRANSFER_SERVER/deposit

Request Parameters:

Name Type Description
asset_code string The code of the asset the user wants to deposit with the anchor. Ex BTC, ETH, USD, INR, etc. This may be different from the asset code that the anchor issues. Ex if a user deposits BTC and receives MyBTC tokens, asset_code must be BTC.
account G... string The stellar account ID of the user that wants to deposit. This is where the asset token will be sent.
memo_type string (optional) Type of memo that 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 (optional) Type of deposit. If the anchor supports multiple deposit methods (e.g. SEPA or SWIFT), the wallet should specify type.
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:

GET https://api.example.com/deposit?asset_code=ETH&account=GACW7NONV43MZIFHCOKCQJAKSJSISSICFVUJ2C6EZIW5773OU3HD64VI

Response

There are several possible kinds of response, 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 Terse but complete instructions for how to deposit the asset. In the case of most cryptocurrencies it is just an address to which the deposit should be sent.
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_fixed float (optional) Fixed fee (if any). In units of the deposited asset.
fee_percent float (optional) Percentage fee (if any). In units of percentage points.
extra_info object (optional) JSON object with additional information about the deposit process.

extra_info fields:

Name Type Description
message string (optional) Additional details about the deposit process.

Bitcoin response example:

{
  "how" : "1Nh7uHdvY6fNwtQtM1G5EZAFPLC33B59rB",
  "fee_fixed" : 0.0002
}

Ripple response example:

{
  "how" : "Ripple address: rNXEkKCxvfLcM1h4HJkaj2FtmYuAWrHGbf tag: 88",
  "eta": 60,
  "fee_percent" : 0.1,
  "extra_info": {
    "message": "You must include the tag. If the amount is more than 1000 XRP, deposit will take 24h to complete."
  }
}

Mexican peso (MXN) response example:

{
  "how" : "Make a payment to Bank: STP Account: 646180111803859359",
  "eta": 1800
}
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:

  1. Wallet checks if Account has enough XLM to create a trust line. If it does, skip to step 4.
  2. If Account doesn't have enough XLM, Wallet starts listening for transactions to the given Account, waiting for it to have enough XLM for a trust line.
  3. When asked for a deposit, Anchor detects if Account has enough XLM to create a trust line. If it doesn't, Anchor sends the needed amount of XLM to the Account for creating a trust line. Anchor then starts listening for trust line creations for that Account.
  4. Wallet detects the arrival of XLM in the Account, and establishes a trust line.
  5. Anchor detects the trust line creation in the Account. If the asset is AUTH_REQUIRED, Anchor approves the new trust line.
  6. Anchor proceeds 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 or via SEP-12 to be able to withdraw.

Request

GET TRANSFER_SERVER/withdraw

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. Ex if a user withdraws MyBTC tokens and receives BTC, the asset_code must be MyBTC.
type string (optional if interactive) Type of withdrawal. Can be: crypto, bank_account, cash, mobile, bill_payment or other custom values. Optional if the anchor will respond that interactive customer information is needed.
dest string (optional if interactive) 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. Optional if the anchor will respond that interactive customer information is needed.
dest_extra string (optional) Extra information to specify withdrawal location. For crypto it may be a memo in addition to the dest address. It can also be a routing number for a bank, a BIC, or the name of a partner handling the withdrawal.
account G... string (optional) The stellar account ID of the user that wants to do the withdrawal. This is only 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:

GET https://api.example.com/withdraw?asset_code=ETH&dest=0xde0B295669a9FD93d5F28D9Ec85E40f4cb697BAe

Response

There are several possible kinds of response, 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_fixed float (optional) If there is a fee for withdraw. In units of the withdrawn asset.
fee_percent float (optional) If there is a percent fee for withdraw.
extra_info object (optional) Any additional data needed as an input for this withdraw, example: Bank Name.

Example:

{
  "account_id": "GCIBUCGPOHWMMMFPFTDWBSVHQRT4DIBJ7AD6BZJYDITBK2LCVBYW7HUQ",
  "memo_type": "id",
  "memo": "123"
}

Deposit and Withdraw shared responses

2. Customer information needed (non-interactive)

Response code: 403 Forbidden

If the anchor needs more information about the customer and all the information can be received non-interactively via SEP-12, this is the correct response. Once the user / wallet transmits information via SEP-12, they can retry the deposit or withdraw endpoint to see if the anchor is ready to execute the deposit or withdrawal.

The response body should be a JSON object with the following fields:

Name Type Description
type string Always set to non_interactive_customer_info_needed.
fields list of strings A list of field names that need to be transmitted via SEP-12 for the deposit to proceed.

The field names specified in fields must be drawn from the list defined in SEP-9.

Example:

{
  "type": "non_interactive_customer_info_needed",
  "fields" : ["family_name", "given_name", "address", "tax_id"]
}

3. Customer information needed (interactive)

Response code: 403 Forbidden

An anchor that requires the user to fill out 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 when the anchor needs the user to perform a custom step for each transaction like entering an SMS code to confirm a withdrawal or selecting a bank account. A wallet that receives this response should open a popup browser window 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.

As the user is interacting with the anchor popup, they will make progress on their deposit or withdrawal and cause updates to the transaction status. The wallet must either listen for a callback or poll the /transaction endpoint for updates about the transaction from the anchor. This allows the wallet to show the user status information and confirm if the deposit attempt initiated successfully or failed. For withdrawals, the wallet must get information on where to send the withdrawal payment to the anchor.

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.
id string (optional) The anchor's internal ID for this deposit / withdrawal request. Can be passed to the /transaction endpoint to check status of the request.

Example response:

{
  "type": "interactive_customer_info_needed",
  "url" : "https://api.example.com/kycflow?account=GACW7NONV43MZIFHCOKCQJAKSJSISSICFVUJ2C6EZIW5773OU3HD64VI",
  "id": "82fhs729f63dh0v4"
}

Adding parameters to the URL

Before the wallet sends the user to the url field received from the anchor, it may add query parameters to the URL.

The possible parameters are summarized in the table below.

Name Type Description
callback string (optional) A URL that the anchor should POST a JSON message to when the user successfully completes the interactive flow. Can also be set to postMessage.
jwt string (optional) JWT previously obtained from the anchor via the SEP-10 authentication flow.

callback details

If the wallet wants to be notified that the user has completed the anchor's interactive flow (either success or failure), it can add this parameter to the URL. If the user abandons the process, the anchor does not need to report anything to the wallet. If the callback value is a URL, the anchor must POST to it with a JSON message as the body. If callback=postMessage is passed, the anchor must post a JSON message to window.opener via the Javascript Window.postMessage method. If window.opener is undefined, the message must be posted to window.parent instead.

In either case, the JSON message should be identical to the response format for the /transaction endpoint.

// Example postMessage callback at the end of an interactive withdraw, indicating that the anchor is waiting for the wallet to send a payment in the amount of 80 of the asset in question. 
const target = window.opener || window.parent;
target.postMessage({
 transaction: {
   id: "anchors_identifier_for_this_transaction",
   status: "pending_user_transfer_start",
   withdraw_anchor_account: "ANCHORS_STELLAR_ACCOUNT_ID",
   withdraw_memo: "MEMO_ANCHOR_EXPECTS_TO_SEE",
   withdraw_memo_type: "text|hash|id",
   amount_in: "80"
   // ... Any other values from the /transaction endpoint may be passed as well
 }
}, "*");

As an alternative to using the callback parameter, the wallet can poll the transaction endpoint /transaction with the request id to check the status of the request.

jwt details

If the anchor's deposit or withdrawal endpoints require SEP-10 authentication, the wallet should include this extra parameter. It allows the anchor to continue the interactive flow without requiring the user to authenticate again. When the user visits the anchor's interactive flow URL and provides a jwt, the anchor must verify the JWT.

  • If the JWT is valid: The anchor must honor the user's authenticated session. The anchor should respond with a 302 redirect response that sets a cookie authenticating the user and redirects the user to a different URL that does not contain the jwt parameter. This is to avoid the JWT appearing in the user's browser history. After the redirect, the authenticated interactive flow must continue as usual.
  • If the JWT is missing or invalid: The anchor may display a login or signup form allowing the user to authenticate manually. On success, the anchor may allow the deposit / withdrawal to proceed normally.

Guidance for wallets: completing an interactive withdrawal

In the case of an interactive withdrawal, the user will interact with the anchor via the popup. They enter information needed to complete the withdrawal like destination bank account or KYC details. Once the anchor has enough information to know how to complete the withdrawal, the wallet detects this and allows the user to complete the withdrawal inside the wallet's app. It has to work this way because the wallet must transfer the correct amount of the withdrawal asset to the anchor's Stellar account before the anchor can complete its end of the withdrawal.

To detect that the user has completed their interaction with the anchor, the wallet needs to either poll the /transaction endpoint with the id provided in the interactive_customer_info_needed response from the anchor until the necessary information is available, or register a callback with the anchor as described above.

In the polling case, if the anchor responds with HTTP status 404 or with a JSON status field set to incomplete, it means the user is either still going through the interactive flow with the anchor, or has abandoned the transaction part way through. The wallet should simply keep polling or waiting in this case. The wallet should provide the user with an x or other way to abort the transaction and return to their wallet. When the user aborts on the wallet side, the wallet must close the popup containing the anchor's flow as well.

When a successful response comes back (either from polling or via callback), the response will contain the transaction fields described in the /transactions endpoint.

The wallet must use the response fields in the following way to complete the withdrawal:

  • status: pending_user_transfer_start means the user has given all necessary info to the anchor, and the ball is back in the wallet's court.
  • withdraw_anchor_account: send the withdrawal payment to this Stellar account.
  • withdraw_memo: (if specified) use this memo in the payment transaction to the anchor.
  • withdraw_memo_type: use this as the memo type.
  • amount_in: the amount expected in the Stellar payment.

The next step is for the wallet to display a confirmation screen summarizing the withdrawal to the user, and then send a Stellar payment to withdraw_anchor_account. The wallet should show the following info to the user:

  • to: show the user what external account they will be withdrawing to.
  • external_extra_text: show the bank name or store name that the user will be withdrawing their funds to.
  • more_info_url: tell the user they can visit this URL for more info about their transaction as it processes.

The anchor may chose to replace most of the digits in the to account number with *s to keep it confidential.

Guidance for wallets: completing an interactive deposit

When a user initiates a deposit, the wallet must kick off a background process to handle the case where the account has no trustline.

After that, the wallet displays the anchor's interactive URL in a popup, and everything else the user needs to do to complete that deposit either happens in the popup, or externally (for example by initiating a SEPA transfer). The wallet must track the status of the deposit in the same fashion as described in the withdrawal guidance section, and may show that information to the user.

If the wallet displays information to the user, it can display any of the fields that may be useful to the user, such as more_info_url, status, and amount_in.

4. Customer Information Status

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.
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 or non_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.

Example:

{
  "type": "customer_info_status",
  "status": "denied",
  "more_info_url": "https://api.example.com/kycstatus?account=GACW7NONV43MZIFHCOKCQJAKSJSISSICFVUJ2C6EZIW5773OU3HD64VI"
}

5. Authentication required

Response code: 403 Forbidden

This endpoint requires authentication.

{
  "type": "authentication_required"
}

6. 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"
}

Info

Allows an anchor to communicate basic info about what their TRANSFER_SERVER supports to wallets and clients.

Request

GET TRANSFER_SERVER/info

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.

Response

The response should be a JSON object like:

{
  "deposit": {
    "USD": {
      "enabled": true,
      "authentication_required": true,
      "fee_fixed": 5,
      "fee_percent": 1,
      "min_amount": 0.1,
      "max_amount": 1000,
      "fields": {
        "email_address" : {
          "description": "your email address for transaction status updates",
          "optional": true
        },
        "amount" : {
          "description": "amount in USD that you plan to deposit"
        },
        "type" : {
          "description": "type of deposit to make",
          "choices": ["SEPA", "SWIFT", "cash"]
        }
      }
    },
    "ETH": {
      "enabled": true,
      "authentication_required": false,
      "fee_fixed": 0.002,
      "fee_percent": 0
    }
  },
  "withdraw": {
    "USD": {
      "enabled": true,
      "authentication_required": true,
      "fee_fixed": 5,
      "fee_percent": 0,
      "min_amount": 0.1,
      "max_amount": 1000,
      "types": {
        "bank_account": {
          "fields": {
              "dest": {"description": "your bank account number" },
              "dest_extra": { "description": "your routing number" },
              "bank_branch": { "description": "address of your bank branch" },
              "phone_number": { "description": "your phone number in case there's an issue" }
          }
        },
        "cash": {
          "fields": {
            "dest": { 
              "description": "your email address. Your cashout PIN will be sent here. If not provided, your account's default email will be used",
              "optional": true
            }
          }
        }
      }
    },
    "ETH": {
      "enabled": false
    }
  },
  "fee": {
    "enabled": false
  },
  "transactions": {
    "enabled": true, 
    "authentication_required": true
  },
  "transaction": {
    "enabled": false,
    "authentication_required": true
  }
}

The JSON object contains an entry for each asset that the anchor supports for SEP6 deposit and/or withdrawal.

For each deposit asset, response contains:

  • enabled: true if SEP-6 deposit for this asset is supported
  • authentication_required: Optional. true if client must be authenticated before accessing the deposit endpoint for this asset. false if not specified.
  • min_amount: Optional minimum amount. No limit if not specified.
  • max_amount: Optional maximum amount. No limit if not specified.
  • fee_fixed: Optional fixed (flat) fee for deposit. In units of the deposited asset. Leave blank if there is no fee or the fee schedule is complex.
  • fee_percent: Optional percentage fee for deposit. In percentage points. Leave blank if there is no fee or the fee schedule is complex.
  • fields object as explained below.

For each withdrawal asset, response contains:

  • enabled: true if SEP-6 withdrawal for this asset is supported
  • authentication_required: Optional. true if client must be authenticated before accessing the deposit endpoint for this asset. false if not specified.
  • min_amount: Optional minimum amount. No limit if not specified.
  • max_amount: Optional maximum amount. No limit if not specified.
  • fee_fixed: Optional fixed (flat) fee for withdraw. In units of the deposited asset. Leave blank if there is no fee or the fee schedule is complex.
  • fee_percent: Optional percentage fee for withdraw. In percentage points. Leave blank if there is no fee or the fee schedule is complex.
  • a types field with each type of withdrawal supported for that asset as a key. Each type can specify a fields object as below explaining what fields are needed and what they do.

The fields object allows an anchor to describe fields that are passed into /deposit and /withdraw. It can explain standard fields like dest and dest_extra for withdrawal, and it can also specify extra fields that should be passed into /deposit or /withdraw such as an email address or bank name. If a field is part of the KYC/AML flow handled by SEP-12 or the field is handled by your interactive deposit/withdrawal flow, there's no need to list it in /info. Only fields that are passed to /deposit or /withdraw need appear here.

The fields object contains a key for each field name and an object with the following fields as the value:

  • description: description of field to show to user.
  • optional: if field is optional. Defaults to false.
  • choices: list of possible values for the field.

The wallet should display a form to the user to fill out any fields with unknown values as part of the deposit/withdrawal flow. Each field should be a text input, unless choices is specified, in which case a dropdown should be used.

An anchor should also indicate in the /info response if they support the fee, transactions and transaction endpoints, by providing the following fields for each:

  • enabled: true if the endpoint is available.
  • authentication_required: true if client must be authenticated before accessing the endpoint.

Fee

The fee endpoint allows an anchor to report the fee that would be charged for a given deposit or withdraw operation. This is important to allow an anchor to accurately report fees to a user even when the fee schedule is complex. If a fee can be fully expressed with the fee_fixed and fee_percent fields in the /info response, then an anchor should not implement this endpoint.

GET TRANSFER_SERVER/fee

Request parameters:

Name Type Description
operation string Kind of operation (deposit or withdraw).
type string (optional) Type of deposit or withdrawal (SEPA, bank_account, cash, etc...).
asset_code string Asset code.
amount float Amount of the asset that will be deposited/withdrawn.

Example request:

GET https://api.example.com/fee?operation=withdraw&asset_code=ETH&amount=0.5

On success the endpoint should return 200 OK HTTP status code and a JSON object with the following fields:

Name Type Description
fee float The total fee (in units of the asset involved) that would be charged to deposit/withdraw the specified amount of asset_code.

Example response:

{
  "fee": 0.013
}

Every HTTP status code other than 200 OK will be considered an error. The body should contain error details. 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.
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 than min_amount.
  • too_large -- deposit/withdrawal size exceeded max_amount.
  • error -- catch-all for any error not enumerated above.

Example response:

{
  "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.

Example response:

{
  "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"
}

Implementations

You can’t perform that action at this time.