Submit a new order
Submits a custodial order: Kairos signs and routes it to the venue on the caller’s behalf (custodial signing). This is the standard order-entry path used by both the web app and API-key consumers who have not been allow-listed onto the self-custody “external-signing” lane (POST /v2/orders/intent + POST /v2/orders/submit).
Ownership. The order is always created for the authenticated caller; any user_id in the body is accepted for backwards compatibility but is ignored — the JWT/API-key identity wins.
Ack semantics (async). A 200 response means the order was validated, persisted, and enqueued — it does NOT mean the order is live on the venue yet. The response status is "queued" (or, on an idempotent replay, the current status of the previously-created order). Track the order via GET /orders/{order_id}, GET /orders polling, or (lowest latency) the /ws socket, which pushes order_update / fill events as the worker submits to the venue and fills arrive.
Idempotency. Pass client_order_id to make retries safe: a second submit with the same (user, exchange_id, market_id, client_order_id) tuple returns the existing order instead of creating a duplicate, and does not consume a rate-limit slot. If omitted, the server generates a random one (i.e. retries without a client-supplied id are NOT deduped).
Provider routing. exchange_id selects the venue-specific executor (polymarket, kalshi, predictfun, opinion, hyperliquid, …; kalshi_offchain is a deprecated alias of kalshi). Each venue advertises its own capabilities (supported time_in_force values, max price, order types) — a request that is well-formed in general but unsupported by the specific venue is rejected with 400 EXCHANGE_UNSUPPORTED / 400 VALIDATION_INVALID_ORDER.
Hyperliquid HIP-4. Use the numeric outcome id as market_id, the selected display label as outcome, and the side coin from the market-data OrderbookSnapshot.token_ids as token_id (for example #1010 or #1011). Quantities are whole shares. Hyperliquid maps GTC/GTD to venue GTC and IOC/FAK/FOK to venue IOC. Single-order and selected-order batch cancellation are supported; cancel-all and fee quotes are unavailable.
Order types. kind="market" is a marketable taker order — pair it with time_in_force FOK (fill-or-kill) or FAK/IOC (fill-and-kill / immediate-or-cancel, partials allowed, remainder cancelled). kind="limit" is a resting quote — pair it with GTC (good-til-cancelled) or GTD (good-til-date, requires expiration_minutes). price is REQUIRED for every order, including market orders — for a marketable order it is the limit you are willing to cross to, not a market-price sentinel.
Circuit breakers & gating. Before persisting, the order passes through, in order: the per-user order rate limit, size/price bounds, the venue time-in-force capability gate, a global + per-exchange execution kill-switch, the custodial trading-enabled check, the post-only capability gate, side/kind/TIF-specific breakers, and the API-key minimum-notional rule. Kill-switch and restriction rejections are 503 with error_details.code = MARKET_PAUSED; a disabled or identity-less account is 403 with AUTH_CREDENTIALS_INVALID. Designated canary users bypass both breaker checks.
Rate limiting. A Redis sliding-window limiter caps order submissions per authenticated user (default 5 orders per second, ORDER_RATE_LIMIT_PER_SEC). API keys with an orders override are checked against BOTH their own per-credential window and the aggregate per-user window (either denying is a 429); idempotent replays are resolved before the limiter and never consume a slot. The limiter fails closed — an unreachable Redis denies with 429. The 429 body carries error_details.code = VALIDATION_INVALID_ORDER with the message Order rate limit exceeded (there is no dedicated rate-limit code on this path), and no Retry-After header.
Auth & scope. Requires trade:execute. This mutation endpoint is additionally gated by a service-token/CSRF/API-key check (RequireServiceToken), which any request bearing X-Client-Id / X-Api-Key / X-Api-Secret satisfies automatically — no extra header is needed for API-key consumers.
curl --request POST \
--url https://execution.kairos.trade/orders \
--header 'Content-Type: application/json' \
--header 'X-Api-Key: <api-key>' \
--header 'X-Api-Secret: <api-key>' \
--header 'X-Client-Id: <api-key>' \
--data '
{
"exchange_id": "hyperliquid",
"market_id": "101",
"token_id": "#1011",
"outcome": "No",
"side": "buy",
"kind": "limit",
"quantity": 25,
"price": 0.42,
"time_in_force": "GTC"
}
'import requests
url = "https://execution.kairos.trade/orders"
payload = {
"exchange_id": "hyperliquid",
"market_id": "101",
"token_id": "#1011",
"outcome": "No",
"side": "buy",
"kind": "limit",
"quantity": 25,
"price": 0.42,
"time_in_force": "GTC"
}
headers = {
"X-Client-Id": "<api-key>",
"X-Api-Key": "<api-key>",
"X-Api-Secret": "<api-key>",
"Content-Type": "application/json"
}
response = requests.post(url, json=payload, headers=headers)
print(response.text)const options = {
method: 'POST',
headers: {
'X-Client-Id': '<api-key>',
'X-Api-Key': '<api-key>',
'X-Api-Secret': '<api-key>',
'Content-Type': 'application/json'
},
body: JSON.stringify({
exchange_id: 'hyperliquid',
market_id: '101',
token_id: '#1011',
outcome: 'No',
side: 'buy',
kind: 'limit',
quantity: 25,
price: 0.42,
time_in_force: 'GTC'
})
};
fetch('https://execution.kairos.trade/orders', 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://execution.kairos.trade/orders",
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([
'exchange_id' => 'hyperliquid',
'market_id' => '101',
'token_id' => '#1011',
'outcome' => 'No',
'side' => 'buy',
'kind' => 'limit',
'quantity' => 25,
'price' => 0.42,
'time_in_force' => 'GTC'
]),
CURLOPT_HTTPHEADER => [
"Content-Type: application/json",
"X-Api-Key: <api-key>",
"X-Api-Secret: <api-key>",
"X-Client-Id: <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://execution.kairos.trade/orders"
payload := strings.NewReader("{\n \"exchange_id\": \"hyperliquid\",\n \"market_id\": \"101\",\n \"token_id\": \"#1011\",\n \"outcome\": \"No\",\n \"side\": \"buy\",\n \"kind\": \"limit\",\n \"quantity\": 25,\n \"price\": 0.42,\n \"time_in_force\": \"GTC\"\n}")
req, _ := http.NewRequest("POST", url, payload)
req.Header.Add("X-Client-Id", "<api-key>")
req.Header.Add("X-Api-Key", "<api-key>")
req.Header.Add("X-Api-Secret", "<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://execution.kairos.trade/orders")
.header("X-Client-Id", "<api-key>")
.header("X-Api-Key", "<api-key>")
.header("X-Api-Secret", "<api-key>")
.header("Content-Type", "application/json")
.body("{\n \"exchange_id\": \"hyperliquid\",\n \"market_id\": \"101\",\n \"token_id\": \"#1011\",\n \"outcome\": \"No\",\n \"side\": \"buy\",\n \"kind\": \"limit\",\n \"quantity\": 25,\n \"price\": 0.42,\n \"time_in_force\": \"GTC\"\n}")
.asString();require 'uri'
require 'net/http'
url = URI("https://execution.kairos.trade/orders")
http = Net::HTTP.new(url.host, url.port)
http.use_ssl = true
request = Net::HTTP::Post.new(url)
request["X-Client-Id"] = '<api-key>'
request["X-Api-Key"] = '<api-key>'
request["X-Api-Secret"] = '<api-key>'
request["Content-Type"] = 'application/json'
request.body = "{\n \"exchange_id\": \"hyperliquid\",\n \"market_id\": \"101\",\n \"token_id\": \"#1011\",\n \"outcome\": \"No\",\n \"side\": \"buy\",\n \"kind\": \"limit\",\n \"quantity\": 25,\n \"price\": 0.42,\n \"time_in_force\": \"GTC\"\n}"
response = http.request(request)
puts response.read_body{
"order_id": "3c90c3cc-0d44-4b50-8888-8dd25736052a",
"status": "queued",
"funding": {
"mode": "skip",
"hold_id": "3c90c3cc-0d44-4b50-8888-8dd25736052a",
"intent_ref": "<string>",
"refused_reason": "<string>"
}
}{
"error": "<string>",
"error_details": {
"code": "FUNDS_INSUFFICIENT_USDC",
"message": "<string>",
"actions": [
{
"action": "enable_trading",
"label": "Add Funds",
"primary": true,
"url": "<string>"
}
],
"details": "<string>",
"metadata": {}
},
"code": "<string>"
}{
"error": "Unauthorized"
}{
"error": "<string>",
"error_details": {
"code": "FUNDS_INSUFFICIENT_USDC",
"message": "<string>",
"actions": [
{
"action": "enable_trading",
"label": "Add Funds",
"primary": true,
"url": "<string>"
}
],
"details": "<string>",
"metadata": {}
},
"code": "<string>"
}{
"error": "<string>",
"error_details": {
"code": "FUNDS_INSUFFICIENT_USDC",
"message": "<string>",
"actions": [
{
"action": "enable_trading",
"label": "Add Funds",
"primary": true,
"url": "<string>"
}
],
"details": "<string>",
"metadata": {}
},
"code": "<string>"
}{
"error": "<string>",
"error_details": {
"code": "FUNDS_INSUFFICIENT_USDC",
"message": "<string>",
"actions": [
{
"action": "enable_trading",
"label": "Add Funds",
"primary": true,
"url": "<string>"
}
],
"details": "<string>",
"metadata": {}
},
"code": "<string>"
}{
"error": "<string>",
"error_details": {
"code": "FUNDS_INSUFFICIENT_USDC",
"message": "<string>",
"actions": [
{
"action": "enable_trading",
"label": "Add Funds",
"primary": true,
"url": "<string>"
}
],
"details": "<string>",
"metadata": {}
},
"code": "<string>"
}{
"error": "<string>",
"error_details": {
"code": "FUNDS_INSUFFICIENT_USDC",
"message": "<string>",
"actions": [
{
"action": "enable_trading",
"label": "Add Funds",
"primary": true,
"url": "<string>"
}
],
"details": "<string>",
"metadata": {}
},
"code": "<string>"
}{
"error": "<string>",
"error_details": {
"code": "FUNDS_INSUFFICIENT_USDC",
"message": "<string>",
"actions": [
{
"action": "enable_trading",
"label": "Add Funds",
"primary": true,
"url": "<string>"
}
],
"details": "<string>",
"metadata": {}
},
"code": "<string>"
}{
"error": "<string>",
"error_details": {
"code": "FUNDS_INSUFFICIENT_USDC",
"message": "<string>",
"actions": [
{
"action": "enable_trading",
"label": "Add Funds",
"primary": true,
"url": "<string>"
}
],
"details": "<string>",
"metadata": {}
},
"code": "<string>"
}{
"error": "<string>",
"error_details": {
"code": "FUNDS_INSUFFICIENT_USDC",
"message": "<string>",
"actions": [
{
"action": "enable_trading",
"label": "Add Funds",
"primary": true,
"url": "<string>"
}
],
"details": "<string>",
"metadata": {}
},
"code": "<string>"
}priceis required on every order, including market orders — it is the limit you are willing to cross, not a sentinel.quantitymust be positive. API-key BUYs also have a minimum notional.- Prefer the WebSocket order execution guide: one persistent connection, one round trip, and pushed fills instead of polling.
Authorizations
Credential client id (kairos_ck_...). Must be sent together with X-Api-Key and X-Api-Secret.
64-char hex API key.
64-char hex API secret.
Body
Body for POST /orders (custodial order submission).
Venue identifier, must be a registered exchange (e.g. polymarket, kalshi, predictfun, hyperliquid).
"polymarket"
Market/contract identifier on the venue. Hyperliquid expects the numeric HIP-4 outcome id.
buy or sell, case-insensitive on input.
buy, sell, BUY, SELL, Buy, Sell "buy"
market or limit, lower-case exactly.
market, limit "limit"
Decimal string, shares/contracts. Must be > 0 and <= 1,000,000. A minimum order size (default 1.0, MIN_ORDER_QUANTITY) applies to BUY orders only — SELL/close orders are allowed at any size so a position can be fully closed after partial fills. API-key-authenticated BUYs additionally require quantity × price >= $5 notional; session-JWT callers and all SELLs are exempt.
"100"
Ignored. The authenticated caller's id is always used.
Outcome-token id. For Hyperliquid, pass the selected side coin #<10 * market_id + side_index>; it is required to select side 1.
Human-readable outcome label for display/attribution (e.g. "Yes", "No", a team name).
"Yes"
Decimal string, REQUIRED for every order (including market orders, where it is the limit you're willing to cross to). Must be > 0 and <= the venue's max price (typically 1.0 for prediction markets).
"0.52"
GTC, GTD, FOK, FAK, or IOC (case-insensitive on input, normalized to upper-case). Defaults to GTC if omitted; an unrecognized non-empty value is rejected rather than silently downgraded to GTC. Must be a TIF the target venue's capabilities advertise.
"GTC"
Maker-only. When true the venue must REJECT the order rather than let any part of it cross the spread and take liquidity — it is a guarantee, never a hint, so an order that cannot honour it is rejected instead of being downgraded to a taker. Requires kind=limit and time_in_force of GTC or GTD, on a venue whose capabilities advertise post-only support (currently Polymarket, Kalshi, Predict.fun and Hyperliquid — the last expresses maker-only as its Alo time-in-force rather than a flag, but the request field is the same). Any other combination is a 400. Defaults to false.
false
Minutes from now until expiry. Only meaningful (and validated) when time_in_force=GTD: must be in [1, 43200] (30 days).
60
Decimal string. Trigger price for stop-loss/take-profit style orders. Must be > 0 and, like price, <= the venue's max price.
How much of the collateral router runs for this order. skip (the server default) is today's path: no affordability check, no hold, no router call, zero added latency. check places an affordability check and a hold and refuses a known shortfall, but never moves money. fund is check plus cross-ledger funding inside the two caps below, and REQUIRES both of them. An unrecognised value is rejected 400 naming the three valid values; it is never downgraded to skip.
skip, check, fund "skip"
Kalshi only. Move collateral between the account's own Kalshi shards before submit. Defaults to true — same venue, zero fee, one REST call, and already every account's behaviour — so an existing caller is unaffected. Send false to skip it.
true
Decimal string. The most bridge fee this order consents to pay, in USDC. Required when collateral=fund and rejected 400 otherwise; 0 is a valid cap meaning "fund only if it is free".
"1.50"
The longest this order consents to wait for funding, in milliseconds. Required when collateral=fund and rejected 400 otherwise.
30000
Requests gas sponsorship. Currently not implemented server-side.
Caller-supplied idempotency key. A retry with the same (user, exchange_id, market_id, client_order_id) returns the existing order instead of creating a duplicate, and does not consume a rate-limit slot. If omitted, a random id is generated server-side (so un-keyed retries are NOT deduped).
Ignored. The executor always fetches fresh orderbook data itself. Kept only for backwards-compatible request bodies.
Deprecated — use max_slippage_cents. Decimal in [0, 0.5] (e.g. 0.10 = 10%).
Maximum acceptable slippage in cents. Must be in [1, 99] if provided.
5
Maximum retry attempts for transient failures. Defaults to 0.
Trading-bot id this order is attributed to.
Order-source attribution override. Pass copytrade explicitly when relevant; otherwise the server derives it from the auth method (API-key auth → api, bot_id present → bot, else → manual).
"api"
Response
Order accepted, persisted, and enqueued for execution. Does not imply the order is live on the venue yet — poll or subscribe to /ws for the terminal state.
Response for POST /orders.
Internal Kairos order id. Use with GET /orders/{order_id} and the cancel endpoints.
queued for a newly-created order; on an idempotent replay (matching client_order_id), the pre-existing order's current status (pending, live, partial, filled, cancelled, expired, or failed).
"queued"
What the collateral router did for this order. null whenever no funding work ran — every skip order, and every order while funding orchestration is still being built.
Show child attributes
Show child attributes
Was this page helpful?
curl --request POST \
--url https://execution.kairos.trade/orders \
--header 'Content-Type: application/json' \
--header 'X-Api-Key: <api-key>' \
--header 'X-Api-Secret: <api-key>' \
--header 'X-Client-Id: <api-key>' \
--data '
{
"exchange_id": "hyperliquid",
"market_id": "101",
"token_id": "#1011",
"outcome": "No",
"side": "buy",
"kind": "limit",
"quantity": 25,
"price": 0.42,
"time_in_force": "GTC"
}
'import requests
url = "https://execution.kairos.trade/orders"
payload = {
"exchange_id": "hyperliquid",
"market_id": "101",
"token_id": "#1011",
"outcome": "No",
"side": "buy",
"kind": "limit",
"quantity": 25,
"price": 0.42,
"time_in_force": "GTC"
}
headers = {
"X-Client-Id": "<api-key>",
"X-Api-Key": "<api-key>",
"X-Api-Secret": "<api-key>",
"Content-Type": "application/json"
}
response = requests.post(url, json=payload, headers=headers)
print(response.text)const options = {
method: 'POST',
headers: {
'X-Client-Id': '<api-key>',
'X-Api-Key': '<api-key>',
'X-Api-Secret': '<api-key>',
'Content-Type': 'application/json'
},
body: JSON.stringify({
exchange_id: 'hyperliquid',
market_id: '101',
token_id: '#1011',
outcome: 'No',
side: 'buy',
kind: 'limit',
quantity: 25,
price: 0.42,
time_in_force: 'GTC'
})
};
fetch('https://execution.kairos.trade/orders', 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://execution.kairos.trade/orders",
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([
'exchange_id' => 'hyperliquid',
'market_id' => '101',
'token_id' => '#1011',
'outcome' => 'No',
'side' => 'buy',
'kind' => 'limit',
'quantity' => 25,
'price' => 0.42,
'time_in_force' => 'GTC'
]),
CURLOPT_HTTPHEADER => [
"Content-Type: application/json",
"X-Api-Key: <api-key>",
"X-Api-Secret: <api-key>",
"X-Client-Id: <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://execution.kairos.trade/orders"
payload := strings.NewReader("{\n \"exchange_id\": \"hyperliquid\",\n \"market_id\": \"101\",\n \"token_id\": \"#1011\",\n \"outcome\": \"No\",\n \"side\": \"buy\",\n \"kind\": \"limit\",\n \"quantity\": 25,\n \"price\": 0.42,\n \"time_in_force\": \"GTC\"\n}")
req, _ := http.NewRequest("POST", url, payload)
req.Header.Add("X-Client-Id", "<api-key>")
req.Header.Add("X-Api-Key", "<api-key>")
req.Header.Add("X-Api-Secret", "<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://execution.kairos.trade/orders")
.header("X-Client-Id", "<api-key>")
.header("X-Api-Key", "<api-key>")
.header("X-Api-Secret", "<api-key>")
.header("Content-Type", "application/json")
.body("{\n \"exchange_id\": \"hyperliquid\",\n \"market_id\": \"101\",\n \"token_id\": \"#1011\",\n \"outcome\": \"No\",\n \"side\": \"buy\",\n \"kind\": \"limit\",\n \"quantity\": 25,\n \"price\": 0.42,\n \"time_in_force\": \"GTC\"\n}")
.asString();require 'uri'
require 'net/http'
url = URI("https://execution.kairos.trade/orders")
http = Net::HTTP.new(url.host, url.port)
http.use_ssl = true
request = Net::HTTP::Post.new(url)
request["X-Client-Id"] = '<api-key>'
request["X-Api-Key"] = '<api-key>'
request["X-Api-Secret"] = '<api-key>'
request["Content-Type"] = 'application/json'
request.body = "{\n \"exchange_id\": \"hyperliquid\",\n \"market_id\": \"101\",\n \"token_id\": \"#1011\",\n \"outcome\": \"No\",\n \"side\": \"buy\",\n \"kind\": \"limit\",\n \"quantity\": 25,\n \"price\": 0.42,\n \"time_in_force\": \"GTC\"\n}"
response = http.request(request)
puts response.read_body{
"order_id": "3c90c3cc-0d44-4b50-8888-8dd25736052a",
"status": "queued",
"funding": {
"mode": "skip",
"hold_id": "3c90c3cc-0d44-4b50-8888-8dd25736052a",
"intent_ref": "<string>",
"refused_reason": "<string>"
}
}{
"error": "<string>",
"error_details": {
"code": "FUNDS_INSUFFICIENT_USDC",
"message": "<string>",
"actions": [
{
"action": "enable_trading",
"label": "Add Funds",
"primary": true,
"url": "<string>"
}
],
"details": "<string>",
"metadata": {}
},
"code": "<string>"
}{
"error": "Unauthorized"
}{
"error": "<string>",
"error_details": {
"code": "FUNDS_INSUFFICIENT_USDC",
"message": "<string>",
"actions": [
{
"action": "enable_trading",
"label": "Add Funds",
"primary": true,
"url": "<string>"
}
],
"details": "<string>",
"metadata": {}
},
"code": "<string>"
}{
"error": "<string>",
"error_details": {
"code": "FUNDS_INSUFFICIENT_USDC",
"message": "<string>",
"actions": [
{
"action": "enable_trading",
"label": "Add Funds",
"primary": true,
"url": "<string>"
}
],
"details": "<string>",
"metadata": {}
},
"code": "<string>"
}{
"error": "<string>",
"error_details": {
"code": "FUNDS_INSUFFICIENT_USDC",
"message": "<string>",
"actions": [
{
"action": "enable_trading",
"label": "Add Funds",
"primary": true,
"url": "<string>"
}
],
"details": "<string>",
"metadata": {}
},
"code": "<string>"
}{
"error": "<string>",
"error_details": {
"code": "FUNDS_INSUFFICIENT_USDC",
"message": "<string>",
"actions": [
{
"action": "enable_trading",
"label": "Add Funds",
"primary": true,
"url": "<string>"
}
],
"details": "<string>",
"metadata": {}
},
"code": "<string>"
}{
"error": "<string>",
"error_details": {
"code": "FUNDS_INSUFFICIENT_USDC",
"message": "<string>",
"actions": [
{
"action": "enable_trading",
"label": "Add Funds",
"primary": true,
"url": "<string>"
}
],
"details": "<string>",
"metadata": {}
},
"code": "<string>"
}{
"error": "<string>",
"error_details": {
"code": "FUNDS_INSUFFICIENT_USDC",
"message": "<string>",
"actions": [
{
"action": "enable_trading",
"label": "Add Funds",
"primary": true,
"url": "<string>"
}
],
"details": "<string>",
"metadata": {}
},
"code": "<string>"
}{
"error": "<string>",
"error_details": {
"code": "FUNDS_INSUFFICIENT_USDC",
"message": "<string>",
"actions": [
{
"action": "enable_trading",
"label": "Add Funds",
"primary": true,
"url": "<string>"
}
],
"details": "<string>",
"metadata": {}
},
"code": "<string>"
}{
"error": "<string>",
"error_details": {
"code": "FUNDS_INSUFFICIENT_USDC",
"message": "<string>",
"actions": [
{
"action": "enable_trading",
"label": "Add Funds",
"primary": true,
"url": "<string>"
}
],
"details": "<string>",
"metadata": {}
},
"code": "<string>"
}
