Place Order

Places an order on Vertex's orderbook.

Rate limits

  • With spot leverage: 600 orders/minute or 10 orders/sec per wallet. (weight=1)

  • Without spot leverage: 30 orders/min or 5 orders every 10 seconds per wallet. (weight = 20)

See more details in API Rate limits.

Request

Connect

WEBSOCKET [GATEWAY_WEBSOCKET_ENDPOINT]

Message


{
  "place_order": {
    "product_id": 1,
    "order": {
      "sender": "0x7a5ec2748e9065794491a8d29dcf3f9edb8d7c43746573743000000000000000",
      "priceX18": "1000000000000000000",
      "amount": "1000000000000000000",
      "expiration": "4294967295",
      "nonce": "1757062078359666688"
    },
    "signature": "0x",
    "id": 100
  }
}

Request Parameters

Parameter
Type
Required
Description

product_id

number

Yes

order

object

Yes

order.sender

string

Yes

Hex string representing the subaccount's 32 bytes (address + subaccount name) of the tx sender.

order.priceX18

string

Yes

Price of the order multiplied by 1e18.

order.amount

string

Yes

Quantity of the order multiplied by 1e18.

order.expiration

string

Yes

order.nonce

string

Yes

signature

string

Yes

digest

string

No

Hex string representing a hash of the order.

spot_leverage

boolean

No

Indicates whether leverage should be used; when set to false , placing the order fails if the transaction causes a borrow on the subaccount. Defaults to true.

id

number

No

Signing

See more details and examples in our signing page.

The solidity typed data struct that needs to be signed is:

struct Order {
    bytes32 sender;
    int128 priceX18;
    int128 amount;
    uint64 expiration;
    uint64 nonce;
}

sender: a bytes32 sent as a hex string; includes the address and the subaccount identifier

priceX18: an int128 representing the price of the order multiplied by 1e18, sent as a string. For example, a price of 1 USDC would be sent as "1000000000000000000"

amount: an int128 representing the quantity of the order multiplied by 1e18, sent as a string. A positive amount means that this is a buy order, and a negative amount means this is a sell order.

Order Expiration

expiration: a time after which the order should automatically be cancelled, as a timestamp in seconds after the unix epoch, sent as a string. The most significant two bits of expiration also encode the order type:

0 โ‡’ Default order, where it will attempt to take from the book and then become a resting limit order if there is quantity remaining

1 โ‡’ Immediate-or-cancel order, which is the same as a default order except it doesnโ€™t become a resting limit order

2 โ‡’ Fill-or-kill order, which is the same as an IOC order except either the entire order has to be filled or none of it.

3 โ‡’ Post-only order, where the order is not allowed to take from the book. An error is returned if the order would cross the bid ask spread.

For example, to submit a post-only order with an expiration of 1000 seconds, we would set expiration as follows:

import time
unix_epoch = int(time.time())
post_only_expiration = str((unix_epoch + 1000) | (3 << 62))

Reserved Bits

The 4th to 6th most significant bits in the expiration field are reserved and must be unset. Orders using reserved bits will be rejected.

Reduce-only

A reduce-only is an order that will either close or reduce your position. The reduce-only flag can only be set on IOC or FOK order types. Send a reduce-only order by setting the 3rd most significant bit on the expiration field. See the following example:

import time
unix_epoch = int(time.time())
ioc_reduce_only_expiration = str((unix_epoch + 1000) | (1 << 62) | (1 << 61))
fok_reduce_only_expiration = str((unix_epoch + 1000) | (2 << 62) | (1 << 61))

Order Nonce

nonce: used to differentiate between the same order multiple times, and a user trying to place an order with the same parameters twice. Sent as a string. Encodes two bit of information:

  • Most significant 44 bits encoding the time in milliseconds (a recv_time) after which the order should be ignored by the matching engine

  • Least significant 20 bits are a random integer used to avoid hash collisions

    For example, to place an order with a random integer of 1000, and a discard time 50 ms from now, we would send a nonce of ((timestamp_ms() + 50) << 20) + 1000)

import time
unix_epoch_ms = int(time.time()) * 1000
nonce = ((unix_epoch_ms + 50) << 20) + 1000

Note: for signing you should always use the data type specified in the solidity struct which might be different from the type sent in the request e.g: nonce should be an uint64 for Signing but should be sent as a string in the final payload.

Response

Success

{
  "status": "success",
  "signature": {signature},
  "data": { 
    "digest": {order digest} 
  },
  "request_type": "execute_place_order"
  "id": 100
}

Failure

{
  "status": "failure",
  "signature": {signature},
  "error": "{error_msg}",
  "error_code": {error_code},
  "request_type": "execute_place_order"
}

Last updated