FTX OTC Portal API

FTX OTC ftxotcportal
Help

Apiary Powered Documentation

Sign in with Apiary account.

FTX OTC Portal API

Introduction

Requests should be sent to https://otc.ftx.com/api/ for FTX or https://otc.ftx.us/api for FTXUS. Requests and responses use JSON.

See our sample client code here: https://github.com/ftexchange/ftx/blob/master/rest/otc_client.py

Authentication

Requests should be sent with the following headers:

  • FTX-APIKEY: Your API key

  • FTX-TIMESTAMP: Number of milliseconds since Unix epoch

  • FTX-SIGNATURE: SHA256 HMAC of the following four strings, using your API secret:

    • Request timestamp (e.g. 1528394229375)
    • HTTP method in uppercase (e.g. GET or POST)
    • Request path, including any URL parameters but not including the hostname (e.g. /otc/quotes?limit=10)
    • (POST only) Request body (JSON-encoded)

Signature Verification

We sign every API response using ECDSA signatures. In each payload, you will see fields called "signature" and "canonical". The signature is an ECDSA signature of the value in "canonical", which the same as the API response but with keys sorted

Our public key is:

-----BEGIN PUBLIC KEY-----
MFYwEAYHKoZIzj0CAQYFK4EEAAoDQgAEZGMMvr3y0ZaDiuhJgVlYMsu4TGjXcpow
dHuHktZsgU5oNiFTeIYxGPzFFaDqimkzg1b1SZS5zE/iKv7wFZNPGg==
-----END PUBLIC KEY-----

Rate limits

Please do not send more than 10 requests per second. Sending requests more frequently will result in HTTP 429 errors.

We also limit the number of quote requests. Contact us please if you need higher limits.

Error codes

  • 3 (401): Unauthenticated

  • 4 (400): MissingParameter

  • 5 (400): InvalidParameter

  • 6 (404): UnknownMarket

  • 7 (404): OrderNotFound

  • 8 (400): NotEnoughBalances

  • 9 (400): OrderTooSmall

  • 10 (400): OrderAlreadyClosed

  • 11 (404): UnknownCoin

  • 12 (400): InvalidAddress

  • 13 (400): WithdrawalsNotSupported

  • 14 (404): WithdrawalNotFound

  • 15 (400): WithdrawalAlreadySent

  • 16 (400): MarketDisabled

  • 17 (403): NotAllowed

  • 18 (429): RateLimitExceeded

  • 19 (400): CoinLimitExceeded

  • 20 (400): OrderTooLarge

  • 21 (400): CannotWithdraw

Reference

Public Endpoints


List All Currencies

List All Currencies

Get the list of currency symbols and their corresponding metadata

Response
object
  • success
    boolean
    true
  • result
    object

Trading Pairs

Trading Pairs

Get metadata about all trading pairs.

Response
object
  • success
    boolean
    true
  • result
    array

Account


Get User Info

Get User Info

Response
object
  • success
    string
    true
  • result
    object

Get Balances

Get Balances

URI Parameters
hideZerocan set this to anything to drop 0 balances from response
Response
object
  • success
    boolean
    true
  • result
    object

Get Deposits

Get Deposits

Includes USD deposits

URI Parameters
limit

default 100, max 200

start_time

unix timestamp in seconds. Only fetch deposits on or after this time. Must include end_time.

end_time

unix timestamp in seconds. Only fetch deposits on or before this time. Must include start_time.

Response
object
  • success
    boolean
    true
  • result
    deposit
    object

Get Deposit Address

Get Deposit Address

URI Parameters
ticker
Response
object
  • success
    boolean
    true
  • result
    deposit address
    object

Get Withdrawals

Get Withdrawals

Includes USD withdrawals

URI Parameters
limit

default 100, max 200

start_time

unix timestamp in seconds. Only fetch deposits on or after this time. Must include end_time.

end_time

unix timestamp in seconds. Only fetch deposits on or before this time. Must include start_time.

Response
object
  • success
    boolean
    true
  • result
    array

Request Withdrawal

Request Withdrawal

  • Body
    • coin (string) - coin
    • address (string) - address
    • tag (string, optional) - tag, if applicable
    • size (number) - amount
    • fastWithdrawal (boolean, optional) - whether you would like this withdrawal to be processed quickly, for a small fee
    • password (string, optional) - withdrawal password, if set
    • code (string, optional) - two-factor code if you require two-factor authentication for withdrawals
Response
object
  • success
    boolean
    true
  • result
    withdrawal
    object

Cancel Requested Withdrawal

Cancel Requested Withdrawal

Withdrawal must have status requested

  • Body
    • id (string) - withdrawal id
Response
object
  • success
    boolean
    true
  • result
    null
    string, nullable

Transfer from FTX to OTC

Transfer from FTX to OTC

Can only be done for coins with property canTransferFromFtx. Query the /currencies endpoint for this information

  • Body
    • coin: SOL (string) - coin
    • size: 1 (number) - amount
Response
object
  • success
    boolean
    true
  • result
    string
    OK

Transfer from OTC to FTX

Transfer from OTC to FTX

Can only be done for coins with property canTransferToFtx. Query the /currencies endpoint for this information

  • Body
    • coin: SOL (string)
    • size: 1 (number)
Response
object
  • success
    boolean
    true
  • result
    string
    OK

RFQ Trading


Request Quote

Request Quote

Request a quote. Quotes are generated asynchronously, so the response object will not contain a price. Instead, a request needs to be made to /otc/quotes/{quote_id} with the quote ID to retrieve the price

Note that the counterparty is always FTX.

Request
object
  • baseCurrency
    base currency
    string
    BTC
  • quoteCurrency
    quote currency
    string
    USDT
  • side

    buy, sell, or twoWay

    string
    buy
  • baseCurrencySize

    either this or quoteCurrencySize needs to be specified

    number
    1.23
  • quoteCurrencySize

    either this or baseCurrencySize needs to be specified

    number
    4908.8
  • apiOnly

    if true, do not show the quote on the website. If accepted, expire other live quotes with matching apiOnly

    boolean
    false
  • secondsUntilSettlement
    number of seconds until the user must settle the quote cost before they being making defer cost payments
    number
  • counterpartyAutoSettles
    if the counterparty must auto settle proceeds after the user settles costs
    boolean
  • waitForPrice

    if true, wait for the price to be generated before returning a response. Defaults to false.

    boolean
Response
object
  • success
    boolean
    true
  • result
    quote
    object

List Recent Quotes

List Recent Quotes

List recent quotes

Response
object
  • success
    boolean
    true
  • result
    array

Get Requested Quote

Get Requested Quote

Retrieve a quote by ID.

URI Parameters
quote_id
Response
object
  • success
    boolean
    true
  • result
    quote
    object

Accept Quote

Accept Quote

The URL parameter quote_id is an integer or string, e.g. 12345. You can optionally prefix it with "rfq:", e.g. "rfq:12345"

  • Body
    • customSize: 0.1 (number, optional) - partial size (must be less than quote size)
Response
object
  • success
    boolean
    true
  • result
    quote
    object

List Recent Accepted Quotes

List Recent Accepted Quotes

URI Parameters
settledImmediatelywhether or not the quote was fully settled immediately by both parties
fullySettledwhether or not the quote has been fully settled by both parties
before

max id to fetch (by default, we will fetch the most recent accepted quotes)

limit
Response
object
  • success
    boolean
    true
  • result
    sorted in descending order of id
    array

List Defer Cost Payments

List Defer Cost Payments

URI Parameters
quoteIdid of the quote to restrict returned defer costs payments to
before

max id to fetch (by default, we will fetch the most recent defer cost payments)

limit
Response
object
  • success
    boolean
    true
  • result
    sorted in descending order of id
    array

List Defer Proceeds Payments

List Defer Proceeds Payments

URI Parameters
quoteIdid of the quote to restrict returned defer costs payments to
before

max id to fetch (by default, we will fetch the most recent defer proceeds payments)

limit
Response
object
  • success
    boolean
    true
  • result
    sorted in descending order of id
    array

List Settlements

List Settlements

URI Parameters
quoteIdid of the quote to restrict returned defer costs payments to
before

max id to fetch (by default, we will fetch the most recent settlements)

limit
Response
object
  • success
    boolean
    true
  • result
    sorted in descending order of id
    array

List Counterparty Settlements

List Counterparty Settlements

URI Parameters
quoteIdid of the quote to restrict returned defer costs payments to
before

max id to fetch (by default, we will fetch the most recent counterparty settlements)

limit
Response
object
  • success
    boolean
    true
  • result
    sorted in descending order of id
    array

Set Settlement Priority

Set Settlement Priority

  • Body
    • settlementPriority: (number, optional) - priority of settlement for the quote with id quote_id. If not provided, will set the priority of the quote to the max of all user-unsettled quotes
Response
object
  • success
    boolean
    true
  • result
    quote
    object

List Fills

List Fills

List your most recent trades, even those from quotes that are unsettled

URI Parameters
limitnumber of fills to retrieve
start_time

unix timestamp in seconds, only show fills after this

end_time

unix timestamp in seconds, only show fills before this

Response
object
  • success
    boolean
    true
  • result
    array

List RFQ Fills

List RFQ Fills

List your most recent RFQ trades

URI Parameters
limit

number of fills to retrieve. max 100, default 100

startMs

unix timestamp in milliseconds, only show fills created after this

endMs

unix timestamp in milliseconds, only show fills created before this

Response
object
  • success
    boolean
    true
  • result
    array

List RFS Orders

List RFS Orders

List your most recent RFS orders, even those that were not filled

URI Parameters
limit

number of fills to retrieve. max 100, default 100

startMs

unix timestamp in seconds, only show fills created after this

endMs

unix timestamp in seconds, only show fills created before this

clientStreamIdscomma delimited client stream IDs
clientOrderIdscomma delimited client order IDs
filledOnlyset this field to anything to make the response only include filled orders
Response
object
  • success
    boolean
    true
  • result
    array

TWAP


List Twaps

List Twaps

Response
object
  • success
    boolean
    true
  • result
    array

Create Twap

Create Twap

  • Notes:

    • Must provide exactly one of either baseCurrencySize or quoteCurrencySize
    • If limitPrice is set, you will receive a partial fill if quote price is worse than this
  • Body

    • baseCurrency: BTC (string)
    • quoteCurrency: USD (string)
    • side: sell (string)
    • intervalSeconds: 3600 (number) - minimum number of seconds between twap fills. Must be 60 (1 minute) or greater
    • baseCurrencySize 1.0 (number, nullable)
    • quoteCurrencySize 100.0 (number, nullable) - must provide exactly one of base/quote currency size
    • limitPrice: 40000.0 (number, nullable)
    • durationSeconds: 3600 (number) - how long the TWAP should last, in seconds
    • minStartTimeMilliseconds: 1656014151 (number, optional) - do not start the TWAP before this time
Response
object
  • success
    boolean
    true
  • result
    object

Accept Twap

Accept Twap

  • Body
    • twapId: 1 (number)
Response
object
  • success
    boolean
    true
  • result
    info representing the TWAP
    object

Reject Twap

Reject Twap

  • Body
    • twapId: 1 (number)
Response
object
  • success
    boolean
    true
  • result
    info representing the TWAP
    object

RFS Trading


The FTX and FTXUS OTC portal now supports the ability to create a websocket connection and stream quotes for a (market, max size) pairs

  • For FTX OTC, connect to wss://otc.ftx.com/ws

  • For FTXUS OTC, connect to wss://otc.ftx.us/ws

See our sample client code here: https://github.com/ftexchange/ftx/blob/master/websocket/otc_client.py

Login

Send a message with the following payload:

{
    "op": "login",
    "args": {
        "api_key": "your-api-key",
        "sign": "signature-using-api-secret",
        "timestamp": 1647980276000
    }
}

Upon successfully logging in you will receive the following message:

{
    "type": "login",
    "message": "logged in"
}

Signature

Our signature format for RFS is the SHA256 HMAC of the request timestamp (in milliseconds) signed with your api secret. You may use the same signing function as for RFQ authentication, with method, path and request data as empty strings

Subscribe to a quote stream

Send a message with the following payload:

{
    "op": "subscribe",
    "channel": "quotes",
    "baseCurrency": "ETH",
    "quoteCurrency": "USD",
    "baseCurrencySize": 100.0
}

Optionally you can include a clientId argument that will be passed back on each payload in the stream. This must be unique

Upon successfully subscribing, you will receive a message to confirm this:

{
    "type": "subscribed",
    "channel": "quotes",
    "userId": 1,
    "baseCurrency": "ETH",
    "quoteCurrency": "USD",
    "baseCurrencySize": 100.0,
    "clientId": "uvm123"
}

You can unsubscribe to a stream by passing in the same payload you would use to subscribe, except with "op": "unsubscribe":

{
    "op": "unsubscribe",
    "channel": "quotes",
    "baseCurrency": "ETH",
    "quoteCurrency": "USD",
    "baseCurrencySize": 100.0
}

The messages in the quote stream will be of the form:

{
    "channel": "quotes",
    "userId": 1,
    "baseCurrency": "ETH",
    "quoteCurrency": "USD",
    "baseCurrencySize": 100.0,
    "type": "update",
    "clientId": "uvm123",
    "data": {
        "id": 3286,
        "askPrice": 2875.91,
        "bidPrice": 2872.9,
        "expiresAt": 1647843528197,
        "quotedAt": 1647843468197,
        "clientId": "uvm123",
        "baseCurrency": "ETH",
        "quoteCurrency": "USD",
        "baseCurrencySize": 100.0,
    }
}

If you disconnect and then resubscribe, and the latest quote you had been sent before you disconnected is still alive, then you will receive that quote upon subscribing except the "type" of this payload will be "latest" rather than "update"

Executing a trade

Send a message with the following payload:

{
    "op": "trade",
    "quoteId": 3286,
    "side": "buy",
    "price": 2875.91,
    "baseCurrencySize": 10.0,
    "clientOrderId": "abc123"
}
  • To sell instead of buy, set side to "sell"

  • The price you submit will be the worst possible price you are willing to receive

    • If FTX/FTXUS can execute at a price better for the client, we will
    • If FTX/FTXUS is not willing to execute at a price better than or equal to this price, you will not receive a fill
  • Sizes:

    • You may also set a "quoteCurrencySize"
    • You must set exactly "baseCurrencySize" or "quoteCurrencySize"; not both
    • You may execute with a size less than or equal to the size of the stream
    • Orders you send are fill-or-kill; if we cannot execute the whole size, you will receive no fill
  • Client IDs are optional; they can be ascii strings up to 32 characters. If you do not pass this in, we will create it for you

Accept RFS Quote using REST

You may also accept an RFS quote using the same API to accept an RFQ quote. To do this you prefix the RFS quote_id with "rfs:", e.g. "rfs:1234". Then fill out the following JSON body. The response will be the same as you would expect when accepting an RFQ quote

  • Body
    • side: buy (string) - either "buy" or "sell", as all RFS quotes are two-sided
    • price: 1000.0 (number, optional) a limit price for the quote
    • baseCurrencySize: 1.0 (number, optional) execute a fraction of the size, expressed in base currency terms
    • quoteCurrencySize: 100.0 (number, optional) execute a fraction of the size, expressed in qupte currency terms
    • clientOrderId: abc123 (string, optional)
Response
object
  • success
    boolean
    true
  • result
    quote
    object

Fills

When a trade is executed, you will immediately receive a fill of the form:

{
    "type": "fill",
    "message": "sold 0.00023428 BTC @ 42,683.16 (received 9.9998107 USD)",
    "data": {
        "order": {
            "id": 1255,
            "streamingQuoteId": 4112,
            "side": "sell",
            "price": 42683.16,
            "state": "filled",
            "clientOrderId": "abc123"
            "placedAt": "2022-03-22T21:23:05.138897"
        },
        "quote": {
            "baseCurrency": "BTC",
            "quoteCurrency": "USD",
            "maxBaseCurrencySize": 10.0,
            "id": 4112,
            "askPrice": 42717.25,
            "bidPrice": 42683.16,
            "expiresAt": 1647984185885,
            "quotedAt": 1647984185004,
            "fillId": 41513991,
            "unsettledCost": 0.0,
            "unsettledProceeds": 0.0,
            "clientId": "xvu123"
        },
        "fill": {
            "id": 41513991,
            "orderId": 291669965,
            "market": "BTC-USD",
            "baseCurrency": "BTC",
            "quoteCurrency": "USD",
            "side": "sell",
            "price": 42683.16,
            "size": 0.00023428,
            "liquidity": "taker",
            "fee": 0.0,
            "feeCurrency": "BTC",
            "time": "2022-03-22T21:23:05.173244+00:00"
        }
    },
    "channel": "fills"
}

Shortly after receiving the fill, you may also receive cancelled (and subsequently updated) quotes for other streams

Cancelled quotes

The payload for a cancelled quote is identical to a quote update, except the "type" is "cancel" and the "expiresAt" timestamp will be in the past