← All standards
SEP-0026Source ↗

Non-interactive Anchor/Wallet Asset Transfer

29 min · 6,353 words

#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.

FieldTypeDescription
transfer_serverurlThe 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:

FieldTypeDescription
enabledbooleanSet to true for assets that support funding of unfunded wallet accounts. Default is false if not set.
amount_nativenumberThe number of lumens the anchored asset will use to fund the wallet
feesstringhuman readable fee structure for funding accounts. e.g. "2 * XLM/BTC market price".
funding_protocolsarrayAn 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:

FieldTypeDescription
enabledbooleanDetermines if deposits are supported or not. Wallets should consider deposits disabled if this field is not specified.
authentication_protocolsarrayAn 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.

FieldTypeDescription
idstring (required)e.g. crypto, mobilemoney, wire
namestringShort name for the deposit option.
min_amountnumberMinimum deposit amount supported by this deposit option.
max_amountnumberMaximum deposit amount supported by this deposit option.
feestring/urlHuman 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.

FieldTypeDescription
idstring (required)Id of the form field. e.g. dest, email, routing_number.
titlestringTitle of the form field e.g. "Your Email", "Routing Number".
descriptionstringDescription of the form field.
optionalbooleanMarks the form field as optional or not.
typestringOne 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.

FieldTypeDescription
valuestring (required)e.g. This is the value that will be sent back to the deposit api endpoint. e.g. "bank001".
titlestringHuman 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:

FieldTypeDescription
enabledbooleanDetermines if transaction history is enabled or not. Wallets should consider transaction history disabled if this field is not specified.
authentication_protocolsarrayAn 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:

FieldTypeDescription
authentication_serverurlServer to use for SEP-10 authentication.
authentication_signing_keyG...Public key used for signing SEP-0010 transactions.

#API Endpoints

#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.toml file 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.toml file and SEP-0027 response.
  • Use the SEP-27 response 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 /deposit or /withdraw.
  • 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.
    • 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.
    • 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

  • Decide which endpoints, if any, need to be authenticated.
  • Pick your approach to [fees].
  • Providing transaction status
    • Provide the /transaction endpoint. The wallet may rely on it to complete non-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 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:

NameTypeDescription
asset_codestringThe 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_issuerstringThe issuer of the asset the user wants to deposit with the anchor.
accountG... stringThe stellar account ID of the user that wants to deposit. This is where the asset token will be sent to.
memo_typestring(optional) Type of memo that the anchor should attach to the Stellar payment transaction, one of text, id or hash.
memostring(optional) Value of memo to attach to transaction, for hash this should be base64-encoded.
email_addressstring(optional) Email address of depositor. If desired, an anchor can use this to send email updates to the user about the deposit.
typestring(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_namestring(optional) In communications / pages about the deposit, anchor should display the wallet name to the user to explain where funds are going.
wallet_urlstring(optional) Anchor should link to this when notifying the user that the transaction has completed.
langstring(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:

NameTypeDescription
howstringMarkdown 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.
etaint(optional) Estimate of how long the deposit will take to credit in seconds.
min_amountfloat(optional) Minimum amount of an asset that a user can deposit.
max_amountfloat(optional) Maximum amount of asset that a user can deposit.
feefloat(optional) Calculated fee (if any). In units of the deposited asset.
extra_infoarray(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": "![STP logo](https://stpbank.com/logo.png)\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:

  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 to be able to withdraw.

#Request

POST TRANSFER_SERVER/withdraw
Content-Type: multipart/form-data

Request parameters:

NameTypeDescription
asset_codestringCode 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_issuerstringThe issuer of the asset the user wants to deposit with the anchor.
amountnumberThe amount the user wishes to withdraw. Some anchors may use the amount to withdraw to determine fees.
typestringType of withdrawal. Can be: crypto, bank_account, cash, mobile, bill_payment or other custom values.
deststringThe 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.
accountG... stringThe 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.
memostring(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_typestring(optional) Type of memo. One of text, id or hash.
wallet_namestring(optional) In communications / pages about the withdrawal, anchor should display the wallet name to the user to explain where funds are coming from.
wallet_urlstring(optional) Anchor can show this to the user when referencing the wallet involved in the withdrawal (ex. in the anchor's transaction history).
langstring(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:

NameTypeDescription
account_idG... stringThe account the user should send its token back to.
memo_typestring(optional) Type of memo to attach to transaction, one of text, id or hash.
memostring(optional) Value of memo to attach to transaction, for hash this should be base64-encoded.
etaint(optional) Estimate of how long the withdrawal will take to credit in seconds.
min_amountfloat(optional) Minimum amount of an asset that a user can withdraw.
max_amountfloat(optional) Maximum amount of asset that a user can withdraw.
feefloat(optional) If there is a fee for withdraw. Already calculated. In units of the withdrawn asset.
extra_infoarray(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:

NameTypeDescription
typestringAlways set to interactive_customer_info_needed.
urlstringURL 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.

NameTypeDescription
typestringAlways set to customer_info_status.
statusstringStatus of customer information processing. One of: pending, denied.
more_info_urlstring(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.
etaint(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:

NameTypeDescription
asset_codestringThe code of the asset of interest. E.g. BTC, ETH, USD, INR, etc.
asset_issuerstringThe issuer of the asset the user wants to deposit with the anchor.
accountstringThe stellar account ID involved in the transactions.
no_older_thanUTC ISO 8601 string(optional) The response should contain transactions starting on or after this date & time.
limitint(optional) The response should contain at most limit transactions.
kindstring(optional) The kind of transaction that is desired. Should be either deposit or withdrawal.
paging_idstring(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:

NameTypeDescription
transactionsarrayList of transactions as requested by the client, sorted in time-descending order.

Each object in the transactions array should have the following fields:

NameTypeDescription
idstringUnique, anchor-generated id for the deposit/withdrawal.
kindstringdeposit or withdrawal.
statusstringProcessing status of deposit/withdrawal.
status_etanumber(optional) Estimated number of seconds until a status change is expected.
more_info_urlstring(optional) A URL the user can visit if they want more information about their account / status.
amount_instring(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_outstring(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_feestring(optional) Amount of fee charged by anchor.
fromstring(optional) Sent from address (perhaps BTC, IBAN, or bank account in the case of a deposit, Stellar address in the case of a withdrawal).
tostring(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_extrastring(optional) Extra information for the external account involved. It could be a bank routing number, BIC, or store number for example.
external_extra_textstring(optional) Text version of external_extra. This is the name of the bank or store.
deposit_memostring(optional) If this is a deposit, this is the memo (if any) used to transfer the asset to the to Stellar address
deposit_memo_typestring(optional) Type for the deposit_memo.
withdraw_anchor_accountstring(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_memostring(optional) Memo used when the user transferred to withdraw_anchor_account.
withdraw_memo_typestring(optional) Memo type for withdraw_memo.
started_atUTC ISO 8601 string(optional) Start date and time of transaction.
completed_atUTC ISO 8601 string(optional) Completion date and time of transaction.
stellar_transaction_idstring(optional) transaction_id on Stellar network of the transfer that either completed the deposit or started the withdrawal.
external_transaction_idstring(optional) ID of transaction on external network that either started the deposit or completed the withdrawal.
messagestring(optional) Human readable explanation of transaction status, if needed.
refundedboolean(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.
{
  "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:

NameTypeDescription
idstring(optional) The id of the transaction.
stellar_transaction_id(optional) stringThe stellar transaction id of the transaction.
external_transaction_id(optional) stringThe 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:

NameTypeDescription
transactionobjectThe 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"
}