Skip to content

Latest commit

 

History

History
1061 lines (833 loc) · 44.3 KB

sep-0026.md

File metadata and controls

1061 lines (833 loc) · 44.3 KB

Preamble

SEP: 0026
Title: Non-interactive Anchor/Wallet Asset Transfer
Authors: SDF, Fritz Ekwoge (@efritze), Ernest Mbenkum (@cameroon)
Status: Rejected (in favor of SEP-6)
Created: 2019-11-16
Updated: 2021-02-23
Version: 0.8.0
Discussion: https://github.com/stellar/stellar-protocol/issues/484

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

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

    }
  }
}
FIATUSD Example
{
  "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"
        }
      }
    }
  }
}
FIATCNY Example
{
  "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.

sep26

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.
sep26.fund_wallet

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"]
sep26.deposits

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.
sep26.deposits.options

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"
sep26.deposits.options.fields

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.
sep26.deposits.options.fields.choices

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-27 example response above of an asset that uses the choice type on a withdrawal field.

sep26.withdrawals

See "sep26.deposits"

sep26.transaction_history

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.
sep26.authentication_protocols.{authenticactionProtocol}

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-10, 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-10 transactions.

API Endpoints

Authentication

Asset anchors that need authentication should do the relevant changes to their SEP-27 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-27 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-27 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-10 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:

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-27 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.
Bitcoin response example
{
  "how" : "1Nh7uHdvY6fNwtQtM1G5EZAFPLC33B59rB",
  "fee" : 0.0002
}
Ripple response example
{
  "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"
    }
  ]
}
Mexican peso (MXN) response example
{
  "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:

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

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