Place a limit order
Builds an unsigned tx that places a resting order on the owner’s limit-order maker book (auto-funds collateral). The order exists only once the owner signs and that tx lands on-chain.
The write is an UpdateBookLimit: every level change is guarded by the resting size the backend read, so if a fill lands between the build and the send the tx fails (LevelSizeMismatch) instead of overwriting the fill — refetch and retry. Preflight simulation catches this before the tx is returned whenever possible.
Spread guard (post-only): unless crossSpread is true, a buy priced at/above the best registered ask (or a sell at/below the best registered bid, across the market’s registered maker books excluding the owner’s own) is rejected with CROSSES_SPREAD; the program enforces the same rule on-chain (PostOnlyWouldCross). If swapIfReject is also set, a market order for the same base size is built instead (a SwapFromArcherAccount when archerAccount is given) and the response has orderKind='market'.
curl --request POST \
--url https://api.archer.exchange/v1/order/limit \
--header 'Content-Type: application/json' \
--header 'X-API-Key: <api-key>' \
--data '
{
"market": "u8tnfCb1JSSghuNFquQ2beStYgAN1kmd1f1Lhxbaec4",
"price": "150.00",
"side": "buy",
"signer": "u8tnfCb1JSSghuNFquQ2beStYgAN1kmd1f1Lhxbaec4",
"size": "1.5",
"accountOwner": "<string>",
"crossSpread": false,
"maxSlippageBps": 50,
"platform": "self",
"swapIfReject": false,
"withInstructions": false
}
'import requests
url = "https://api.archer.exchange/v1/order/limit"
payload = {
"market": "u8tnfCb1JSSghuNFquQ2beStYgAN1kmd1f1Lhxbaec4",
"price": "150.00",
"side": "buy",
"signer": "u8tnfCb1JSSghuNFquQ2beStYgAN1kmd1f1Lhxbaec4",
"size": "1.5",
"accountOwner": "<string>",
"crossSpread": False,
"maxSlippageBps": 50,
"platform": "self",
"swapIfReject": False,
"withInstructions": False
}
headers = {
"X-API-Key": "<api-key>",
"Content-Type": "application/json"
}
response = requests.post(url, json=payload, headers=headers)
print(response.text)const options = {
method: 'POST',
headers: {'X-API-Key': '<api-key>', 'Content-Type': 'application/json'},
body: JSON.stringify({
market: 'u8tnfCb1JSSghuNFquQ2beStYgAN1kmd1f1Lhxbaec4',
price: '150.00',
side: 'buy',
signer: 'u8tnfCb1JSSghuNFquQ2beStYgAN1kmd1f1Lhxbaec4',
size: '1.5',
accountOwner: '<string>',
crossSpread: false,
maxSlippageBps: 50,
platform: 'self',
swapIfReject: false,
withInstructions: false
})
};
fetch('https://api.archer.exchange/v1/order/limit', options)
.then(res => res.json())
.then(res => console.log(res))
.catch(err => console.error(err));<?php
$curl = curl_init();
curl_setopt_array($curl, [
CURLOPT_URL => "https://api.archer.exchange/v1/order/limit",
CURLOPT_RETURNTRANSFER => true,
CURLOPT_ENCODING => "",
CURLOPT_MAXREDIRS => 10,
CURLOPT_TIMEOUT => 30,
CURLOPT_HTTP_VERSION => CURL_HTTP_VERSION_1_1,
CURLOPT_CUSTOMREQUEST => "POST",
CURLOPT_POSTFIELDS => json_encode([
'market' => 'u8tnfCb1JSSghuNFquQ2beStYgAN1kmd1f1Lhxbaec4',
'price' => '150.00',
'side' => 'buy',
'signer' => 'u8tnfCb1JSSghuNFquQ2beStYgAN1kmd1f1Lhxbaec4',
'size' => '1.5',
'accountOwner' => '<string>',
'crossSpread' => false,
'maxSlippageBps' => 50,
'platform' => 'self',
'swapIfReject' => false,
'withInstructions' => false
]),
CURLOPT_HTTPHEADER => [
"Content-Type: application/json",
"X-API-Key: <api-key>"
],
]);
$response = curl_exec($curl);
$err = curl_error($curl);
curl_close($curl);
if ($err) {
echo "cURL Error #:" . $err;
} else {
echo $response;
}package main
import (
"fmt"
"strings"
"net/http"
"io"
)
func main() {
url := "https://api.archer.exchange/v1/order/limit"
payload := strings.NewReader("{\n \"market\": \"u8tnfCb1JSSghuNFquQ2beStYgAN1kmd1f1Lhxbaec4\",\n \"price\": \"150.00\",\n \"side\": \"buy\",\n \"signer\": \"u8tnfCb1JSSghuNFquQ2beStYgAN1kmd1f1Lhxbaec4\",\n \"size\": \"1.5\",\n \"accountOwner\": \"<string>\",\n \"crossSpread\": false,\n \"maxSlippageBps\": 50,\n \"platform\": \"self\",\n \"swapIfReject\": false,\n \"withInstructions\": false\n}")
req, _ := http.NewRequest("POST", url, payload)
req.Header.Add("X-API-Key", "<api-key>")
req.Header.Add("Content-Type", "application/json")
res, _ := http.DefaultClient.Do(req)
defer res.Body.Close()
body, _ := io.ReadAll(res.Body)
fmt.Println(string(body))
}HttpResponse<String> response = Unirest.post("https://api.archer.exchange/v1/order/limit")
.header("X-API-Key", "<api-key>")
.header("Content-Type", "application/json")
.body("{\n \"market\": \"u8tnfCb1JSSghuNFquQ2beStYgAN1kmd1f1Lhxbaec4\",\n \"price\": \"150.00\",\n \"side\": \"buy\",\n \"signer\": \"u8tnfCb1JSSghuNFquQ2beStYgAN1kmd1f1Lhxbaec4\",\n \"size\": \"1.5\",\n \"accountOwner\": \"<string>\",\n \"crossSpread\": false,\n \"maxSlippageBps\": 50,\n \"platform\": \"self\",\n \"swapIfReject\": false,\n \"withInstructions\": false\n}")
.asString();require 'uri'
require 'net/http'
url = URI("https://api.archer.exchange/v1/order/limit")
http = Net::HTTP.new(url.host, url.port)
http.use_ssl = true
request = Net::HTTP::Post.new(url)
request["X-API-Key"] = '<api-key>'
request["Content-Type"] = 'application/json'
request.body = "{\n \"market\": \"u8tnfCb1JSSghuNFquQ2beStYgAN1kmd1f1Lhxbaec4\",\n \"price\": \"150.00\",\n \"side\": \"buy\",\n \"signer\": \"u8tnfCb1JSSghuNFquQ2beStYgAN1kmd1f1Lhxbaec4\",\n \"size\": \"1.5\",\n \"accountOwner\": \"<string>\",\n \"crossSpread\": false,\n \"maxSlippageBps\": 50,\n \"platform\": \"self\",\n \"swapIfReject\": false,\n \"withInstructions\": false\n}"
response = http.request(request)
puts response.read_body{
"addressLookupTables": [
"<string>"
],
"anchorMidTicks": 123,
"depositBaseLots": 123,
"depositQuoteLots": 123,
"expiresAt": 123,
"includesDeposit": true,
"nextSequenceNumber": 123,
"orderIds": [
"<string>"
],
"requiredBaseLots": 123,
"requiredQuoteLots": 123,
"transaction": "<string>",
"orderKind": "limit",
"instructions": {
"addressLookupTables": [
"<string>"
],
"computeBudgetInstructions": [
{
"accounts": [
{
"isSigner": true,
"isWritable": true,
"pubkey": "<string>"
}
],
"data": "<string>",
"programId": "<string>"
}
],
"instructions": [
{
"accounts": [
{
"isSigner": true,
"isWritable": true,
"pubkey": "<string>"
}
],
"data": "<string>",
"programId": "<string>"
}
],
"signer": "<string>"
},
"price": "<string>",
"side": "buy",
"size": "<string>"
}{
"error": "INVALID_PARAMS",
"message": "<string>"
}{
"error": "INVALID_PARAMS",
"message": "<string>"
}{
"error": "INVALID_PARAMS",
"message": "<string>"
}Authorizations
Body
Market address (PDA). Get one from GET /v1/markets.
"u8tnfCb1JSSghuNFquQ2beStYgAN1kmd1f1Lhxbaec4"
Limit price, quote per base (human units).
"150.00"
buy, sell "buy"
The wallet that signs: the book's maker, or with accountOwner the account's owner or delegate. Existing clients may keep sending it as owner; send one name only.
"u8tnfCb1JSSghuNFquQ2beStYgAN1kmd1f1Lhxbaec4"
Order size in base tokens (human units).
"1.5"
The wallet that owns the ArcherAccount this request acts through. With platform it derives the account PDA server-side — you never handle a PDA. Omit for a plain wallet-owned book. Replaces the earlier archerAccount field, which is no longer read.
When false (default), a price that crosses the spread — a buy at/above the best registered ask, or a sell at/below the best registered bid — is rejected (or auto-swapped, see swapIfReject), and the tx is sent post-only so the program rejects it too if the books move before it lands. Set true to explicitly rest a spread-crossing limit order (the program's post-only check is skipped).
Slippage tolerance (bps) for the swapIfReject market fallback. Ignored unless a swap fires. Defaults to 50 bps (0.5%).
Platform namespace for accountOwner. Ignored unless accountOwner is set.
self, treadfi When true and the order would be rejected for crossing the spread (crossSpread false), build a market order for the same base size instead of erroring (from the ArcherAccount when archerAccount is given). The response then has orderKind='market'.
Also return the unsigned instructions under instructions, for composing your own transaction instead of signing ours. Omitted or false leaves the response exactly as it was.
Response
Unsigned transaction built (limit order, or a market order when swapIfReject fired).
- Option 1
- Option 2
Result of placing a limit order. When orderKind='limit', all LimitOrderActionResponse fields are present at the top level. When the price crossed the spread and swapIfReject was set, orderKind='market' and all BuildOrderResponse fields are present at the top level instead.
The book's mid anchor in ticks. Always 0 for limit-order books: a level's offset is its absolute price tick.
The maker-book sequence number this tx writes.
Total base lots the resulting book state requires as collateral (the program's update_book solvency check).
Total quote lots required, including the positive-maker-fee buffer.
Base64 unsigned VersionedTransaction in its wire encoding: a v0 message when the write fits 1232 bytes, otherwise a v1 (SIMD-0385) message, which a full maker registry needs. A v1 transaction must be sent base64-encoded and signed by a wallet that supports version 1.
Which kind of order was built. 'market' only when a spread-crossing price triggered the swapIfReject fallback.
limit, market Unsigned instructions, present only when the request set withInstructions.
Show child attributes
Show child attributes
Human price (quote per base) the order rests/rested at. Absent for cancel-all.
Side this action targets. Absent for cancel-all.
buy, sell Human base-token size the action targets — placed size (place), new size (modify), or canceled size (cancel-one). Absent for cancel-all.
curl --request POST \
--url https://api.archer.exchange/v1/order/limit \
--header 'Content-Type: application/json' \
--header 'X-API-Key: <api-key>' \
--data '
{
"market": "u8tnfCb1JSSghuNFquQ2beStYgAN1kmd1f1Lhxbaec4",
"price": "150.00",
"side": "buy",
"signer": "u8tnfCb1JSSghuNFquQ2beStYgAN1kmd1f1Lhxbaec4",
"size": "1.5",
"accountOwner": "<string>",
"crossSpread": false,
"maxSlippageBps": 50,
"platform": "self",
"swapIfReject": false,
"withInstructions": false
}
'import requests
url = "https://api.archer.exchange/v1/order/limit"
payload = {
"market": "u8tnfCb1JSSghuNFquQ2beStYgAN1kmd1f1Lhxbaec4",
"price": "150.00",
"side": "buy",
"signer": "u8tnfCb1JSSghuNFquQ2beStYgAN1kmd1f1Lhxbaec4",
"size": "1.5",
"accountOwner": "<string>",
"crossSpread": False,
"maxSlippageBps": 50,
"platform": "self",
"swapIfReject": False,
"withInstructions": False
}
headers = {
"X-API-Key": "<api-key>",
"Content-Type": "application/json"
}
response = requests.post(url, json=payload, headers=headers)
print(response.text)const options = {
method: 'POST',
headers: {'X-API-Key': '<api-key>', 'Content-Type': 'application/json'},
body: JSON.stringify({
market: 'u8tnfCb1JSSghuNFquQ2beStYgAN1kmd1f1Lhxbaec4',
price: '150.00',
side: 'buy',
signer: 'u8tnfCb1JSSghuNFquQ2beStYgAN1kmd1f1Lhxbaec4',
size: '1.5',
accountOwner: '<string>',
crossSpread: false,
maxSlippageBps: 50,
platform: 'self',
swapIfReject: false,
withInstructions: false
})
};
fetch('https://api.archer.exchange/v1/order/limit', options)
.then(res => res.json())
.then(res => console.log(res))
.catch(err => console.error(err));<?php
$curl = curl_init();
curl_setopt_array($curl, [
CURLOPT_URL => "https://api.archer.exchange/v1/order/limit",
CURLOPT_RETURNTRANSFER => true,
CURLOPT_ENCODING => "",
CURLOPT_MAXREDIRS => 10,
CURLOPT_TIMEOUT => 30,
CURLOPT_HTTP_VERSION => CURL_HTTP_VERSION_1_1,
CURLOPT_CUSTOMREQUEST => "POST",
CURLOPT_POSTFIELDS => json_encode([
'market' => 'u8tnfCb1JSSghuNFquQ2beStYgAN1kmd1f1Lhxbaec4',
'price' => '150.00',
'side' => 'buy',
'signer' => 'u8tnfCb1JSSghuNFquQ2beStYgAN1kmd1f1Lhxbaec4',
'size' => '1.5',
'accountOwner' => '<string>',
'crossSpread' => false,
'maxSlippageBps' => 50,
'platform' => 'self',
'swapIfReject' => false,
'withInstructions' => false
]),
CURLOPT_HTTPHEADER => [
"Content-Type: application/json",
"X-API-Key: <api-key>"
],
]);
$response = curl_exec($curl);
$err = curl_error($curl);
curl_close($curl);
if ($err) {
echo "cURL Error #:" . $err;
} else {
echo $response;
}package main
import (
"fmt"
"strings"
"net/http"
"io"
)
func main() {
url := "https://api.archer.exchange/v1/order/limit"
payload := strings.NewReader("{\n \"market\": \"u8tnfCb1JSSghuNFquQ2beStYgAN1kmd1f1Lhxbaec4\",\n \"price\": \"150.00\",\n \"side\": \"buy\",\n \"signer\": \"u8tnfCb1JSSghuNFquQ2beStYgAN1kmd1f1Lhxbaec4\",\n \"size\": \"1.5\",\n \"accountOwner\": \"<string>\",\n \"crossSpread\": false,\n \"maxSlippageBps\": 50,\n \"platform\": \"self\",\n \"swapIfReject\": false,\n \"withInstructions\": false\n}")
req, _ := http.NewRequest("POST", url, payload)
req.Header.Add("X-API-Key", "<api-key>")
req.Header.Add("Content-Type", "application/json")
res, _ := http.DefaultClient.Do(req)
defer res.Body.Close()
body, _ := io.ReadAll(res.Body)
fmt.Println(string(body))
}HttpResponse<String> response = Unirest.post("https://api.archer.exchange/v1/order/limit")
.header("X-API-Key", "<api-key>")
.header("Content-Type", "application/json")
.body("{\n \"market\": \"u8tnfCb1JSSghuNFquQ2beStYgAN1kmd1f1Lhxbaec4\",\n \"price\": \"150.00\",\n \"side\": \"buy\",\n \"signer\": \"u8tnfCb1JSSghuNFquQ2beStYgAN1kmd1f1Lhxbaec4\",\n \"size\": \"1.5\",\n \"accountOwner\": \"<string>\",\n \"crossSpread\": false,\n \"maxSlippageBps\": 50,\n \"platform\": \"self\",\n \"swapIfReject\": false,\n \"withInstructions\": false\n}")
.asString();require 'uri'
require 'net/http'
url = URI("https://api.archer.exchange/v1/order/limit")
http = Net::HTTP.new(url.host, url.port)
http.use_ssl = true
request = Net::HTTP::Post.new(url)
request["X-API-Key"] = '<api-key>'
request["Content-Type"] = 'application/json'
request.body = "{\n \"market\": \"u8tnfCb1JSSghuNFquQ2beStYgAN1kmd1f1Lhxbaec4\",\n \"price\": \"150.00\",\n \"side\": \"buy\",\n \"signer\": \"u8tnfCb1JSSghuNFquQ2beStYgAN1kmd1f1Lhxbaec4\",\n \"size\": \"1.5\",\n \"accountOwner\": \"<string>\",\n \"crossSpread\": false,\n \"maxSlippageBps\": 50,\n \"platform\": \"self\",\n \"swapIfReject\": false,\n \"withInstructions\": false\n}"
response = http.request(request)
puts response.read_body{
"addressLookupTables": [
"<string>"
],
"anchorMidTicks": 123,
"depositBaseLots": 123,
"depositQuoteLots": 123,
"expiresAt": 123,
"includesDeposit": true,
"nextSequenceNumber": 123,
"orderIds": [
"<string>"
],
"requiredBaseLots": 123,
"requiredQuoteLots": 123,
"transaction": "<string>",
"orderKind": "limit",
"instructions": {
"addressLookupTables": [
"<string>"
],
"computeBudgetInstructions": [
{
"accounts": [
{
"isSigner": true,
"isWritable": true,
"pubkey": "<string>"
}
],
"data": "<string>",
"programId": "<string>"
}
],
"instructions": [
{
"accounts": [
{
"isSigner": true,
"isWritable": true,
"pubkey": "<string>"
}
],
"data": "<string>",
"programId": "<string>"
}
],
"signer": "<string>"
},
"price": "<string>",
"side": "buy",
"size": "<string>"
}{
"error": "INVALID_PARAMS",
"message": "<string>"
}{
"error": "INVALID_PARAMS",
"message": "<string>"
}{
"error": "INVALID_PARAMS",
"message": "<string>"
}