Provider’s Endpoints | Developers

Provider's Endpoints

Estimated reading time: More than 10 minutes

In order to communicate with Ledger’s back-end, you have to give us the mapping of the endpoints we need.
As you can see on the diagram What do we need?, there are 5 main endpoints needed for the swap:

  • To get the list of available currencies: /currencies.
  • To get the list of tradable pairs: /pairs.
  • To query a rate: /quote.
  • To create a signed swap binary payload /swap
  • To query a swap status: /status.

You will find the details about each needed endpoint below.

GET /currencies

  • Function: Returns a list of supported currencies.
  • Input: –
  • Output: Array of supported currencies, with information required to uniquely identify coins/tokens.
  • Payload:
    [
    {
      "id": "BTC",
      "type": "coin",
      "blockchain": "bitcoin",
      "chainId": 1
    },
    {
      "id": "USDC",
      "type": "token",
      "blockchain": "ethereum",
      "chainId": 1,
      "contract": "0xa0b86991c6218b36c1d19d4a2e9eb0ce3606eb48"
    }
    ]
    

GET /pairs

  • Function: Returns a list of supported pairs. This endpoint is not required if all permutations returned by /currencies are supported.
  • Input: –
  • Output: Array of supported swap pairs, with supported quote type (fixed / float).
  • Payload:
    [
     {
        "from": "btc",
        "to": "bat",
        "tradeMethod":[
           "fixed",
           "float"
        ]
     },
     {
        "from": "bat",
        "to": "btc",
        "tradeMethod":[
           "fixed",
           "float"
        ]
     }
    ]
    

Fixed quote: The quote price is guaranteed until execution (or until end of quote validity period).
Float quote: The quote price is indicative only, real price is computed at execution time

POST /quote

  • Function: Returns a quote for a pair and amount.
  • Input:
    • from: currency id in your system.
    • to: currency id in your system.
    • amount: amount requested by the user, without the gas fee.
  • Output:
    • quoteId: quote unique identifier (optional, only required for fixed quotes)
    • amount: should be same as the input one (optional, only required for consistency check) (as an input coin floating amount)
    • amountTo: estimated output amount that will be sent to user (as an output coin floating amount)
    • providerFees: amount, expressed in currencyTo, that is paid to the provider.
    • referralFees: amount, expressed in currencyTo, that is paid to Ledger (as a referral fee).
    • payoutNetworkFees: estimated gas fees that will be used for the payout transaction (as an output coin floating amount)
    • tradeMethod: fixed or float (optional, only required for consistency check)
    • expiry: quote expiration timestamp (optional, only required for fixed quotes)
    • minAmountFrom: minimum valid amount for this pair (optional, only required if amount is too low)
    • maxAmountFrom: maximum valid amount for this pair (optional, only required if amount is too large)
  • Payload:
    • Success
      {
       "quoteId": "CC14E626-CF1B-4EDA-AF5E-766FFD5A3457",
       "amount": "1",
       "amountTo": "270.864632",
       "providerFees": "0.0001",
       "referralFees": "0.0001",
       "payoutNetworkFees": "0.0002",
       "tradeMethod": "float",
       "expiry": "2022-04-04T09:10:51+0000" // ISO-8601 date format
      }
      

All fees are expressed in output currency. For example, during a ETH to USDT on ethereum swap, the fees are expressed in USDT on ethereum.

Some requirements about the /quote endpoint:

  • The quote must work without user auth. It can require a Ledger auth.
  • The quote must be valid long enough (at least a few minutes).

POST /swap

  • Function: Generates a secure binary payload for the nano in order to authorize the transaction. The provider should validate consistency between quoteId and other inputs (addresses, amounts and currencies).
  • Input:
    • quoteId: previously generated quote id
    • refundAddress: user’s refund address. This address is generaly the fromAddress.
    • refundAddressExtraId: tag or memo (optional).
    • payoutAddress: user’s payout transaction address.
    • payoutAddressExtraId: tag or memo (optional).
    • currencyFrom: from currency id, using your identifiers (for checking purpose on your side only) (optional).
    • currencyTo: to currency id, using you identifiers (for checking purpose on your side only) (optional).
    • payloadCurrencyFrom: from currency id, using ledger’s referencial. This value has to be used for currency_from field in the protobuf payload.
    • payloadCurrencyTo: to currency id, using ledger’s referencial. This value has to used for currency_to field in the protobuf payload.
    • amountToProvider: amount of currencyFrom that the provider expects to receive from client.
    • amountToWallet: amount of currencyTo that the provider agrees to send to the client in exchange from (optional for a float trade).
    • nonce: value to use for device_transaction_id field in the protobuf payload.
  • Output:
    • swapId: provider’s id of the ongoing swap transaction. This will be used by Ledger’s backend to retrieve the status of user swap transaction.
    • payinAddress: provider’s address.
    • createdAt: date of creation of the swap payload in ISO-8601 format.
    • providerFees: amount, expressed in currencyTo, that is paid to the provider.
    • referralFees: amount, expressed in currencyTo, that is paid to Ledger (as a referral fee).
    • payoutNetworkFees: estimated gas fees that will be used for the payout transaction (as an output coin floating amount).
    • providerSig:
      • payload: protobuf payload (in a binary format)
      • signature: payload signed in a JWS format
  • Payload:
    • Success
      Refer to payload in the JWS signature section below.
      {
       "swapId":"SWAP-ID-165940",
       "payinAddress":"0xa0b86991c627e936c1d19d4a2e90a2ce3606eb48",
       "createAt": "2030-05-26T14:13:39",
       "providerFees": "0.0001",
       "referralFees": "0.0001",
       "payoutNetworkFees": "0.0002",
       "providerSig":
       {
      "payload":"CgUweGZmZhoFMHhmZmYqBTB4ZmZmOgNCVENCA0JBVEoIMTIwMDAwMDBSCDExNTAwMDAwWhF2ZXJ5IGxvbmd1ZSBub25jZQ==",
      "signature": "MEUCIBRm4PrdgRw0aBwRepuOGGRmR/YPcCoyKNJ7UDjFO030AiEA/VT0anolum0a3X/9lGPeovZHqzeDG9brcUB4zhYmwbs="
       }
      }
      
    • Error
      {
      code: "KYC_PENDING",
      error: "Your KYC is under validation" ,
      description: "Your KYC is under validation by an operator"
      }
      

Here is a little diagram to explain how the payload and the signature are generated: Payload and Payload Signature generation diagram

  • payload: the trade parameters are assembled in a protobuf message. Then using the protobuf tools we do a binary encoding of the protobuf (Byte Array). Finally, with base64 encoding we get the payload field.
  • signature: From the binary encoding of the previous protobuf (Byte Array), we sign it with ES256 and the provider’s private key to get a Signature Byte Array. Finally, with base64 encoding we get the signature.

Input field: nonce

A nonce field will be passed as a parameter of the /swap endpoint.
It is a 32 bytes nonce which is generated by the hardware wallet to avoid replay attacks.
It will be base 64 URL encoded before being sent to the /swap endpoint.

Protobuf message (payload)

Your Protobuf message should have the following structure:

syntax = "proto3";
package ledger_swap;

message NewTransactionResponse {
    string    payin_address = 1;
    string    payin_extra_id = 2;
    string    refund_address = 3;
    string    refund_extra_id = 4;
    string    payout_address = 5;
    string    payout_extra_id = 6;
    string    currency_from = 7;
    string    currency_to = 8;
    bytes     amount_to_provider = 9;
    bytes     amount_to_wallet = 10;
    string    device_transaction_id = 11; // nonce
}

Explanation of each fields:

  • payin_address: provider address to receive payment
  • payin_extra_id: eventual memo for the payment (stellar payment, for instance)
  • refund_address: client address to receive back the payment funds in case the provider is not able to execute the swap for some unpredictable reasons
  • refund_extra_id: eventual memo for the payment (stellar payment, for instance)
  • payout_address: client address to receive the money resulting from a successful swap
  • payout_extra_id: eventual memo for the payment (stellar payment, for instance)
  • currency_from: must be set to value of payloadCurrencyFrom from the /swap API request
  • currency_to: must be set to value of payloadCurrencyTo from the /swap API request
  • amount_to_provider: amount of currency_from that the provider expects to receive from client
  • amount_to_wallet: amount of currency_to that the provider agrees to send to the client in exchange from amount_to_provider. This amount must also include the network fees that the provider will pay to send the crypto to the user.
  • device_transaction_id: swap transaction nonce provided by client at initialization (must be set to value of nonce from the API request)

Amounts must be in the lowest unit of the coin, encoded into a 16 bytes array in big endian.
Example:

  • 1 BTC would be 0x5F5E100 (100000000 in hexadecimal). The smallest unit is a satoshi which is 10^-8 BTC.
    So multiply 1 BTC by 10^80x5F5E100.
    And 0x5F5E100 encoded into a 16 bytes array in big endian is [0x00, ... 0x00, 0x05, 0xF5, 0xE1, 0x00].
  • 2 ETH would be 0x1BC16D674EC80000 (or 2000000000000000000). The smallest unit is a wei which is 10^-18 ETH.
    So multiply 2 ETH by 10^180x1BC16D674EC80000.
    And 0x1BC16D674EC80000 encoded into a 16 bytes array in big endian is [0x00, ... 0x00, 0x1B, 0xC1, 0x6D, 0x67, 0x4E, 0xC8, 0x00, 0x00].

Output field: providerSig

The real return value of the /swap endpoint is the providerSig field with the JSON Web Signature (JWS) in compact form within:

  • providerSig.payload - base 64 URL of the binary serialized protobuf message.NewTransactionResponse.
  • providerSig.signature - base 64 URL of the ES256 signature of providerSig.payload. More details in the JWS signature and Protobuf message (payload) sections.

Signature usage

  • Payload and Signature
    From the provider to Ledger Live. The payload is a protobuf message containing the trade data. It is generated by the provider and sent to Ledger Live.
    payload = {
    payin_address,      // address (of provider)
    refund_address,     // address (of customer)
    payout_address,     // address (of customer)
    currency_from,      // currency name (to provider)
    currency_to,
    amount_to_provider, // amount (to provider)
    amount_to_wallet,   // amount (to customer)
    device_transaction_id,
    
    }
    R, S = Sign(payload, priv_key)
    
  • Validate
    Exchange app checks and validates payload (signature and content).
    // Compare nonce in payload
    Verify((R, S), payload, pub_key)
    
  • Display
    Exchange app request approval to user by displaying swap summary on screen.
    Validate?
    Send currency_from amount_to_provider
    Receive currency_to amount_to_wallet
    

JWS-Signature

The output field is providerSig is base on the flattened JWS JSON, without the optional protected and header parameter.

The algorithm supported by Ledger are ES256 with secp256k1 or secp256r1 curve. There is no need to specify them into the header, as we will store your public key with this information in our system.

As specified in the JWA spec, the signature is a concatenation of the (R, S) pair in a 64 octets array, and not the ASN1 format.

GET /status

  • Function: Returns the status of an executed swap transaction.
  • Input: swapId.
  • Output:
    • status:
      • FINISHED: Trade has been completed successfully (user has received payout transaction).
      • EXPIRED: Payin transaction was not received in time, trade is cancelled. User will be refunded if payin transaction is received afterwards.
      • ON_HOLD: Trade has been put on hold (eg: for KYC reasons). User must contact support.
      • PENDING: Trade is in progress (provider is waiting to receive payin transaction, or user is waiting to receive payout transaction)
      • REFUNDED: Trade has been cancelled, refund transaction has been successfully received by user.
      • UNKNOWN: Trade is in unknown state. User must contact support.
    • amount: as soon as this information is known, this should contain the final amount transferred to the user in output currency
    • payinTransactionId: as soon as this information is known, this should contain the payin transaction hash
    • payoutTransactionId: as soon as this information is known, this should contain the payout transaction hash
    • providerFees: fees amount that has been paid to the provider.
    • referralFees: fees amount that has been paid to Ledger (as a referral fee).
    • payoutNetworkFees: gas fees that has been be used for the payout transaction (as an output coin floating amount).
  • Payload:
    • Success
      {
      "status":"FINISHED",
      "amount": 1.337,
      "payinTransactionId": "0xfffffffffffff",
      "payoutTransactionId": "0xfffffffffffff",
      "providerFees": "0.0001",
      "referralFees": "0.0001",
      "payoutNetworkFees": "0.0002"
      }
      

Did you find this page helpful?


How would you improve this page for developers?



What do we need?
Provider's LiveApp
Getting Started
Theme Features
Customization

Swap