Operating Model:
Operating Model:

Placing an order

This guide walks you through all aspects of placing an order with the Upvest Investment API, including the related cash balance and position updates.

Prerequisites

You can always place an order with our Investment API regardless of whether:

  • The user checks are passed (know-your-customer, proof-of-residence, instrument fit).
  • The account is currently locked for any reason (e.g., compliance reasons).
  • The user has sufficient funds in their account.
  • The exchange is open.
  • The ISIN is open for trading that day.

However, the order will only be executed when all the previous requisites are met.

INFO

Conducting an instrument fit check means that to offer investment products to your users, you are required to assess their investment experience and knowledge for different instruments.

Examples of how to place an order

Below are two examples of how the Investment API works and what you can expect when placing an order:

  1. Placing a nominal buy order (EUR 1,000).
  2. Placing a unit sell order (10 shares).
INFO

Orders can be created as nominal orders, i.e. buying/selling a security for a specified amount (e.g. EUR 1,000), or as unit orders, i.e. buying/selling a security by specifying the quantity of securities (e.g. 10 shares).

Additional cash / security buffers

For nominal sell and unit buy orders, there is an additional +10% buffer:

  • For nominal sell orders: To account for possible price fluctuations, Upvest adds a 10% buffer, i.e. the order is processed if it is estimated to be no more than 90% of the user's current position.
  • For unit buy orders: Similar to above, Upvest adds a 10% buffer to ensure sufficient cash balance to purchase securities, i.e. the order will be processed if it is estimated to be no more than 90% of the user’s cash balance.
INFO

Orders may be cancelled by Upvest in the event of insufficient cash balance or insufficient securities. However, it is important to note that if an order is cancelled by Upvest, the order can never be executed or placed again, so you can safely place the order again.

Example 1: How to place a nominal buy order

To place a nominal buy order, send POST /orders.

For the nominal buy order call, you need to specify the cash amount whilst you can omit the share quantity (vice versa for a unit order), “BUY” as order side, the instrument_id_type (either UUID or ISIN), and then the specific UUID or ISIN you want to trade in instrument_id. Any other required order data is populated by Upvest.

Optionally, you can also provide your own generated order ID via the client_reference field. This, for example, allows you to map orders back to your end-users in an easy manner.

INFO

It does not have to be your order ID, it can be anything that you deem relevant.

Since each account group will have the cash balance for a specific currency, the currency for the order should be supported by that account group.

Additionally, the user_instrument_fit_acknowledgement should be true if the user has proven to you a non-instrument fit, but has accepted the related risks of which you have informed them. In all other cases it should be false.

INFO

The user instrument fit acknowledgement is an optional field and the absence of it will be equal to false. Consequently, Upvest is only interested in the outcome and needs to be able to prove whether an instrument fit check has been performed or not.

The following flow diagram illustrates the nominal buy order flow with two equal order executions (execution price of EUR 85.22), including all related state changes, cash balance and positions updates, as well as buy order report webhooks.

Nominal buy order flowchart

INFO

For nominal sell and unit buy orders, there will be one additional webhook:

  • Nominal sell: Positions update webhook to unlock the 10% buffer
  • Unit buy: Cash balance update webhook to unlock the 10% buffer

Example request for a nominal buy order

{
  "user_id": "2dedfeb0-58cd-44f2-ae08-0e41fe0413d9",
  "account_id": "debf2026-f2da-4ff0-bb84-92e45babb1e3",
  "cash_amount": "1000",
  "currency": "EUR",
  "side": "BUY",
  "instrument_id": "US0378331005",
  "instrument_id_type": "ISIN",
  "order_type": "MARKET",
  "user_instrument_fit_acknowledgement": true,
  "price": ""
}
INFO

The instrument id type gives you the freedom to interact with our API using UUIDs or ISINs depending on your needs and whatever is easiest for you.

COMING SOON

The price field only has to be specified for LIMIT and STOP orders, which the Investment API will also support in the future. Currently, only orders for order type MARKET are possible.

After a successful order request, the sample response for the above will look as follows:

Example response

{
  "id": "eb5ba93f-5dfe-4bf1-8571-4da0caacc80c",
  "created_at": "2021-07-21T14:10:00.00Z",
  "updated_at": "2021-07-21T14:10:00.00Z",
  "user_id": "2dedfeb0-58cd-44f2-ae08-0e41fe0413d9",
  "account_id": "debf2026-f2da-4ff0-bb84-92e45babb1e3",
  "cash_amount": "1000",
  "currency": "EUR",
  "side": "BUY",
  "instrument_id": "US0378331005",
  "instrument_id_type": "ISIN",
  "order_type": "MARKET",
  "quantity": "0",
  "user_instrument_fit_acknowledgement": true,
  "price": "",
  "status": "NEW",
  "fee": "0.0",
  "executions": [],
  "client_reference": ""
}

Once all relevant order checks have been passed, the order transitions into PROCESSING state, you will receive an orders event webhook. At this point, the order cannot be cancelled via the Investment API any longer.

You can always retrieve an individual order by sending GET /orders/{order_id}.

After that, the order gets executed at our trading partner and you will receive an order execution FILLED webhook for each execution, followed by an order FILLED webhook once the order is completely filled, including the amount of fees charged (if applicable). This means that executions will contain all order executions associated with this order (and taxes incurred for sell orders - see example 2).

Further, you can also retrieve individual order executions via GET /orders/{order_id}/executions/{execution_id}. Hence, the executions array for the above order looks as follows:

Example response

{
  "id": "eb5ba93f-5dfe-4bf1-8571-4da0caacc80c",
  "created_at": "2021-07-21T14:10:00.00Z",
  "updated_at": "2021-07-21T14:10:00.00Z",
  "user_id": "2dedfeb0-58cd-44f2-ae08-0e41fe0413d9",
  "account_id": "debf2026-f2da-4ff0-bb84-92e45babb1e3",
  "cash_amount": "1000",
  "currency": "EUR",
  "side": "BUY",
  "instrument_id": "US0378331005",
  "instrument_id_type": "ISIN",
  "order_type": "MARKET",
  "quantity": "0",
  "user_instrument_fit_acknowledgement": true,
  "price": "",
  "status": "FILLED",
  "fee": "0.0",
  "executions": [
    {
      "id": "b9dc0676-8a7d-412d-802a-3b325eefd15e",
      "side": "BUY",
      "currency": "EUR",
      "status": "FILLED",
      "order_id":  "eb5ba93f-5dfe-4bf1-8571-4da0caacc80c",
      "cash_amount": "1000",
      "share_quantity": "11.734334663",
      "price": "85.22",
      "transaction_time": "2021-07-21T14:10:00.020Z",
      "taxes": [
        {
          "type": "TOTAL",
          "amount": "0"
        }
      ]
    }
  ],
  "client_reference": ""
}
COMING SOON

Once the order executions are settled (typically on T+2) you will also receive an order execution SETTLED webhook. For sell orders, this means that the cash can now be withdrawn (see example 2).

To see what the respective webhooks for cash balance and positions updates look like, please go to the API References for cash balance events and positions events.

Example 2: How to place a unit sell order

To place a unit sell order - selling a security by specifying the quantity of securities to be sold, e.g. 10 shares - you send POST /orders. Different from the nominal buy order explained above, you now need to specify the share quantity (and omitting the cash amount) as well as the SELL side.

The following flow diagram illustrates the unit sell order flow with two equal order executions (at an execution price of EUR 85.22), including all related state changes, cash balance and positions updates, as well as sell order report webhooks.

Unit sell

Example request for a unit sell order

{
  "user_id": "2dedfeb0-58cd-44f2-ae08-0e41fe0413d9",
  "account_id": "debf2026-f2da-4ff0-bb84-92e45babb1e3",
  "currency": "EUR",
  "side": "SELL",
  "instrument_id": "US0378331005",
  "instrument_id_type": "ISIN",
  "order_type": "MARKET",
  "quantity": "10",
  "user_instrument_fit_acknowledgement": true,
  "price": ""
} 

After a successful order request, the sample response for the above will look as follows:

Example response

{
  "id": "eb5ba93f-5dfe-4bf1-8571-4da0caacc80c",
  "created_at": "2021-07-21T14:10:00.00Z",
  "updated_at": "2021-07-21T14:10:00.00Z",
  "user_id": "2dedfeb0-58cd-44f2-ae08-0e41fe0413d9",
  "account_id": "debf2026-f2da-4ff0-bb84-92e45babb1e3",
  "cash_amount": "0",
  "currency": "EUR",
  "side": "SELL",
  "instrument_id": "US0378331005",
  "instrument_id_type": "ISIN",
  "order_type": "MARKET",
  "quantity": "10",
  "user_instrument_fit_acknowledgement": true,
  "price": "",
  "status": "NEW",
  "fee": "0.0",
  "executions": [],
  "client_reference": ""
}

Analogous to the nominal buy order, you will receive an order PROCESSING webhook, followed by an order execution FILLED webhook for each execution, and an order FILLED webhook once the order is completely filled, including the amount of fees charged (if applicable), and the taxes incurred:

{
  "id": "eb5ba93f-5dfe-4bf1-8571-4da0caacc80c",
  "created_at": "2021-07-21T14:10:00.00Z",
  "updated_at": "2021-07-21T14:10:00.00Z",
  "user_id": "2dedfeb0-58cd-44f2-ae08-0e41fe0413d9",
  "account_id": "debf2026-f2da-4ff0-bb84-92e45babb1e3",
  "cash_amount": "0",
  "currency": "EUR",
  "side": "SELL",
  "instrument_id": "US0378331005",
  "instrument_id_type": "ISIN",
  "order_type": "MARKET",
  "quantity": "10",
  "user_instrument_fit_acknowledgement": true,
  "price": "",
  "status": "FILLED",
  "fee": "0.0",
  "executions": [
    {
      "id": "b9dc0676-8a7d-412d-802a-3b325eefd15e",
      "side": "SELL",
      "currency": "EUR",
      "status": "FILLED",
      "order_id":  "eb5ba93f-5dfe-4bf1-8571-4da0caacc80c",
      "cash_amount":"852.20",
      "share_quantity":"10",
      "price":"85.22",
      "transaction_time":"2021-07-21T14:10:00.020Z",
      "taxes": [
        {
          "type": "TOTAL", 
          "amount": "23.45"
        }
      ]
    }
  ],
  "client_reference": ""
}
INFO

The cash amount is the total amount the user realised from the sell order, including all taxes incurred.

Similar to the nominal buy order, you will also receive a positions and cash balance updates respectively, which you can also find in the API References for cash balance events and positions events.

Next steps

In order to provide your users with all relevant reports that will be generated when successfully placing an order, you can now move on to implement user reporting.

Was this page helpful?