Description

Trade is one of the crucial operations of the Send Platform. Trades allow the users to move their funds from one currency to another.

Trades are a conversion between 2 different currencies within the same Trading Account. At the time of creating a Trade, funds must be instructed to be transferred to a Wallet within the same Trading Account or paid to a Recipient and their Payment Address.

Before booking a Trade the user can request a Ratesheet. Requesting the Ratesheet will lock in a rate for the client for a short period of time. That will guarantee that the Trade will be performed with exactly that locked rate*. If Ratesheet is not included in Trade request, then Send will apply the best market rate available at the time of booking.

*Rates may vary due to the commercial agreement you have with Send. Rates quoted by the Ratesheet will include any relevant markup for the deal except for the cases where there are specific discounts given for trades over time OR you have previously agreed with Send that the margin will not be included.

The following example contains a Payment Object which will be handled after the Trade is complete.

How to request a Ratesheet

To fetch a Ratesheet you need to send a POST /rate-sheets request including the accessToken you’ve received
during the Authentication process in the headers.

Within the request you can optionally specify the tradingAccountId to apply the rates to a particular Trading Account. If not supplied the Ratesheet and its Rate will be applied for the whole Enterprise Parent Account.

Ratesheets expire in a standard 2.5 minutes (160 seconds) time period.

📘

Variable Ratesheet Expiry Windows

If you have a requirement for a different ratesheet expiry window please let us know. We're looking to extend this functionality in the future.

Besides this the request must include at least one Currency Pair. A Currency Pair consists of buyCurrency and sellCurrency. The request can include unlimited number of valid Currency Pairs.

Request example for POST /rate-sheets
{
  "tradingAccountId": "a1b2c3d4-e5f6-7g8h-9i0j-k1l2m3n4o5p6",
  "currencyPairs": [
    {
      "buyCurrency": "NZD",
      "sellCurrency": "AUD"
    }
  ]
}

In response to your request you will receive either a SUCCESS 201 response or one of the error responses (400, 401, 500). See Status Codes & Error Messages.

In case of successful response you will receive back all the information you’ve sent with a rate specified for each Currency Pair and expiresAt (Ratesheet expiry) date and time.

Ratesheet expiration time is explicit. If the user tries to book a Trade referring to the expired Ratesheet the Trade will be rejected.

📘

Rates are always represented as sellCurrencybuyCurrency.

For example, for a AUD → USD trade a 0.7 rate will indicate that for every 1 AUD you will get 0.7 USD.

Response example for POST /rate-sheets
{
  "item": {
    "rateSheetId": "string",
    "tradingAccountId": "string",
    "currencyPairs": [
      {
        "buyCurrency": "AUD",
        "sellCurrency": "AUD",
        "rate": 0
      }
    ],
    "expiresAt": "2024-08-12T05:53:05.709Z"
  }
}

Each Ratesheet can be used across multiple Trades.

The quoted rate for a currency will be updated based on its liquidity in Send network. The rate of the higher liquid currencies will update every few minutes whilst lower liquid currencies will only update once in 1-2 hours.

Ratesheets can be fetched 24/7 but that rates fetched outside of market hours will have an additional spread
applied to cover market movement during the market close window.

How to book a Trade

To book and further perform a Trade you need to send a POST /trades request including the accessToken you’ve received during the Authentication process in the headers.

Within the request you need to specify the following:

  • buyCurrency and sellCurrency;

    • The list of available currencies to use will be defined as part of your enterprise agreement.
  • Either buyAmount OR sellAmount.

    • Send will automatically use rates to calculate the amount that was not provided. When booking a Trade the amount should be in the lowest denominator of the currency.
      F.e. for AUD $1.00 would be 100 and in JPY ¥100 = 100.
    • The maximum amount that can be booked for a Trade without first prefunding the Wallet with the required cash will be negotiated as part of your contract with Send.
  • FromWalletId

    • The balance of the fromWallet will be reduced to cover the sellAmount. The fromWallet currency must match the sellCurrency.
  • Either toWalletId OR Payment Object

    • The ability to include Payment Object in Trade can help in cases where the user needs to make a Trade into a currency not supported by Wallets. It is also possible to include Payment Object in Trade even if currencies are supported by the Wallets.
    • If a Payment Object is provided with the Trade then a Payment Transaction will be automatically created. After the settlement of the Trade the funds will be sent to the Recipient. For detailed description of the Payments see Payments Endpoint.
    • If a toWalletId is supplied instead, then this Wallet should be created, active and must be within the same Trading Account as the fromWalletId. (If you would like to trade into a currency to be given to another tradingAccountId then you will need to create a Trade and then a Transfer separately.
    • The same applies to Payment Object - both recipientId and paymentAddressId should be created and Active before booking a Trade.
    • toWallet/paymentAddress currency must match the buyCurrency.
  • RatesheetId (optionally)

    • The Ratesheet can only be included if it is not expired yet. If no ratesheetId provided then real time rates will be applied for the Trade.
Request Example for POST /trades without the Payment Object
{
  "buyCurrency": "NZD",
  "sellCurrency": "AUD",
  "buyAmount": 20000,
  "ratesheetId": "1a2b3c4d-5e6f-7g8h-9i0j-1k2l3m4n5o6",
  "fromWalletId": "a1b2c3d4-e5f6-7g8h-9i0j-k1l2m3n4o5p6",
  "toWalletId": "a1b2c3d4-5e6f-7g8h-9i0j-klmnop123456",
  "externalReference": "string"
}
Request Example for POST /trades with the Payment Object
{
  "buyCurrency": "NZD",
  "sellCurrency": "AUD",
  "sellAmount": 19000,
  "ratesheetId": "1a2b3c4d-5e6f-7g8h-9i0j-1k2l3m4n5o6",
  "fromWalletId": "a1b2c3d4-e5f6-7g8h-9i0j-k1l2m3n4o5p6",
  "externalReference": "string",
  "payment": {
    "paymentReason": "buying_a_vehicle",
    "reference": "string",
    "recipientId": "a1b2c3d4-5e6f-7g8h-9i0j-klmnop123456",
    "paymentAddressId": "a1b2c3d4-e5f6-7g8h-9i0j-k1l2m3n4o5p6"
  }
}

In response to your request you will receive either a SUCCESS 201 response or one or the error responses (400, 401, 500). See Status Codes & Error Messages.

Within the successful response you will receive all the data you’ve provided with the following data included:

  • tradeTransactionId which can be used to refer to the trade transaction
  • both buyAmount and sellAmount as either one of them was provided in the request and the other will be calculated based on the Rate
  • ratesheetId will only be returned if it was provided in the request.
  • Factual rate will be provided even if there was no Ratesheet provided in the request
  • status How do Trade Transactions work
  • createdAt, updatedAt dates and time.
  • Payment object details
    Details include paymentTransactionId which can be used to subsequently fetch details about
    (or listen to Webhooks about) the Payment. Detailed description of the Payments Endpoint can be found here.

To receive updates on the Trade Transaction and Payment Transaction status changes please refer to Webhooks.

Response example for POST /trades without the Payment Object
{
  "item": {
    "tradeTransactionId": "string",
    "buyCurrency": "NZD",
    "sellCurrency": "AUD",
    "buyAmount": 20000,
    "sellAmount": 19000,
    "rateSheetId": "string",
    "rate": 0,
    "status": "submitted",
    "fromWalletId": "string",
    "toWalletId": "string",
    "tenor": "T0",
    "settlementDate": "2024-08-12T05:53:05.709Z",
    "createdAt": "2024-08-12T05:53:05.709Z",
    "updatedAt": "2024-08-12T05:53:05.709Z",
    "externalReference": "string"
  }
}
Response example for POST /trades with the Payment Object can be found below
{
  "item": {
    "tradeTransactionId": "string",
    "buyCurrency": "NZD",
    "sellCurrency": "AUD",
    "buyAmount": 20000,
    "sellAmount": 19000,
    "rateSheetId": "string",
    "rate": 0,
    "status": "submitted",
    "fromWalletId": "string",
    "toWalletId": "string",
    "tenor": "T0",
    "settlementDate": "2024-08-12T05:53:05.709Z",
    "createdAt": "2024-08-12T05:53:05.709Z",
    "updatedAt": "2024-08-12T05:53:05.709Z",
    "externalReference": "string",
    "payment": {
      "paymentTransactionId": "string",
      "paymentReason": "string",
      "reference": "string",
      "paymentType": "payout",
      "payoutType": "swift",
      "currency": "AUD",
      "amount": 0,
      "fromWalletId": "string",
      "recipientId": "string",
      "paymentAddressId": "string",
      "rejectReason": "string",
      "status": "submitted",
      "createdAt": "2024-08-12T05:53:05.709Z",
      "updatedAt": "2024-08-12T05:53:05.709Z",
      "paymentDate": "2024-08-12",
      "externalReference": "string"
    }
  }
}

How do Trade Transactions work

Firstly before creating a Trade Transaction a Trade undergoes a round of checks to make sure everything is set correctly and no data is missing. These checks include:

  • needed data is provided;
  • currencies match the Wallets;
  • currencies are available for trading;
  • trade is within the parameters set for your commercial agreement with Send*;
  • the balance is sufficient** to make a Trade;
  • ratesheet is not expired and ratesheetId is correct (if provided)

Provided all checks pass, the status of the Transaction will be set to Submitted and the Wallet’s balances will be updated (you will see the fromWallet has the trade value added to it's committed balance).

If there is a Payment object within the Trade request any necessary payments will also be initiated here and the paymentTransactionId passed back in the API for future reference.

After that, the Trade will then be internally confirmed with Send and the status of the Transaction will be changed to Processing. In most cases that should happen immediately.

The next step for the Transaction is to undergo the transaction monitoring (if any action is required, Send will reach out via established channels to rectify any issues/gather necessary documentation).

At this point, if compliance fails the Trade it will go into a Rejected status and Wallet debt will be erased along with the Payment if one was initiated by the Trade. Otherwise, once the trades settlement date has arrived, the Trade will go into the Awaiting Funds status. Note: This is true for the reverse as well, if a payment linked to a trade fails compliance checks, the trade will also be marked as Rejected.

Once enough funds are in the fromWallet (which may already have enough) the Trade will go into the Settled
status and either the toWallet will have its balance updated with the buyCurrency or the linked Payment will be released to the Recipient via the established payment rails.

Regarding the time frames please note the following:

  • In the response Send will provide settlement date and time which will indicate when the Trade will settle (this is when enough funds are available on the wallet to close the trade position and the agreed settlement date is reached).
    • If the fromWallet does not have sufficient funds by the settlement date, Send will reach out to determine the reason for this, and may choose to cancel the trade if the trade remains unfunded.
  • T0 Trades booked on weekends, or after market hours will fully settle at 9:30AM AEST on the next business day. Full details can be found at Trade Settlement and Cutoff Times.

* When you sign your contract with Send to use our services we will work with you to define a set of acceptable parameters for your activity. This will include things like Min/Max trade limits, enabled currencies, funding flows etc.

**You can have an agreement with Send for a post-funding model where trades can be booked before funds being on a wallet. In that case the Transaction will stay in “Awaiting Funds” status after the Compliance Check until the Wallet has enough funds for the Trade.

Trade Status Flow

Fetching Trade Information

Fetching the previously created Ratesheet

To request the information about the previously created Ratesheet you can send a signed GET /rate-sheets/{rateSheetId} request.

In response to your request you will receive either a SUCCESS 200 response or one or the error responses (400, 401, 500) See Status Codes & Error Messages.

Given a valid ratesheetId in the URL, a SUCCESS response will return the previously created Ratesheet.

Even if the Ratesheet has expired by the moment of GET request it will be still returned in the response.
Only Trade POST requests will fail if they include an expired Ratesheet.

Fetching the previously created Trade Transaction

To request the information about the previously created Trade Transaction you can send a signed GET /trades/{tradeTransactionId} request.

In response to your request you will receive either a SUCCESS 200 response or one or the error responses (400, 401, 500) See Status Codes & Error Messages.

Given a valid tradeTransactionId in the URL, a SUCCESS response will return the previously created Trade Transaction.

Fetching all the trades for the a given Trading Account

To request the information about all the Trades made for the Trading Account you can send a signed GET /accounts/{tradingaccountId}/trades request.

In response to your request you will receive either a SUCCESS 200 response or one or the error responses (400, 401, 500) See Status Codes & Error Messages.

Given a valid tradingAccountId in the URL, a SUCCESS response will return all the Trades made for the Trading Account.

Note that standard pagination rules are applied for the response.

📘

Not Seeing What You're Looking For?

We are always looking to improve our API documentation to ensure Sends systems are easy to understand and quick to build against. If you're struggling to find the answer to a question we either haven't made it easy enough to find the relevant docs or we haven't had a chance to write something up for it yet.

Either way we want to hear from you!

Head over to our Discussion Board and leave us a note. We keep a close eye on this and want to ensure we make these docs as useful as they can be so will jump on any posts quickly.