A client order ID is an identifier that your application assigns when it places an order. Polyester
binds the value to the first retained create attempt for that account. Reusing the value is rejected
as CONFLICT_DUPLICATE_CLIENT_ORDER_ID; Polyester does not replay the earlier create result. After
creation, some order APIs also accept it as a client-defined reference to locate the target order.
It is not a general idempotency key for cancels or modifications.
The field is named clientOrderId in REST, ConnectRPC ProtoJSON, and Polyester SDKs. The protobuf
source field is client_order_id; generated language-specific names vary.
Client order ID versus order ID
| Identifier | Assigned by | Purpose |
|---|---|---|
clientOrderId | Your client | Duplicate guard, client-side correlation, and locating the order later |
orderId | Polyester | Canonical order identity returned after the order is accepted |
Store both values after a successful response. Use orderId as the canonical identity in your
application, while retaining clientOrderId for reconciliation and retry handling.
Format
A client order ID:
- is optional when placing an order
- must contain no more than 36 characters
- may contain ASCII letters, numbers,
.,_,:,/, and- - is case-sensitive
- is scoped to the account or subaccount that places the order
A UUID is a suitable default because its standard string representation is exactly 36 characters:
0190f3f4-7c2a-7d86-9e2b-7af0f8f8f102Do not put secrets or sensitive user information in client order IDs. They may appear in responses, logs, order history, and support workflows.
Retry behavior
When Polyester receives an order with a client order ID it has retained for the same account, it
rejects the request with CONFLICT_DUPLICATE_CLIENT_ORDER_ID. This applies when the payload is
identical or different, while the original order is open or terminal, and when the retained first
attempt was rejected. CreateOrder does not return the previously recorded outcome.
A duplicate conflict proves only that the account-scoped ID is retained. It does not prove that the payload matched, that the earlier attempt was accepted, or what state an accepted order is in. Use the order read APIs to reconcile the original attempt.
Reconcile an uncertain create
Generate and persist the client order ID before sending the request:
const clientOrderId = crypto.randomUUID();
const order = {
symbol: "BTC-USDC",
side: "buy" as const,
orderType: "limit" as const,
timeInForce: "gtc" as const,
price: "64250.5",
qty: "0.25",
clientOrderId,
};
await client.orders.create(order);If the response is lost because of a timeout or network failure:
- Keep the original
clientOrderIdand payload. - Look up the order by
clientOrderId. Retry the read after backoff if the accepted order has not reached the read projection yet. - If a repeated create is still necessary, send the same ID and unchanged payload. It can create
the order only when the ID was not retained. If it returns
CONFLICT_DUPLICATE_CLIENT_ORDER_ID, continue reconciliation because the conflict does not replay the original outcome. - Use a new client order ID only for a deliberate new order after resolving the earlier intent.
This pattern is unsafe:
await retry(() =>
client.orders.create({
...order,
clientOrderId: crypto.randomUUID(),
})
);Generating a new ID for each attempt makes every attempt a new logical order and can place a second order when the first response was merely lost.
When to retry
Retry only when the failure may be temporary, such as:
- a connection failure
- a request timeout
- rate limiting
- temporary service unavailability
Use bounded exponential backoff with jitter. Keep the client order ID and all order parameters unchanged while resolving the original intent. A repeated single-order create is not a replay: it may succeed if the earlier attempt was never retained, or return a duplicate conflict if it was.
Do not retry validation, authorization, insufficient-funds, or conflicting-client-ID errors as if they were temporary. Reconcile a duplicate conflict. A corrected order is a new logical order and needs a new client order ID.
Retention and reuse
Polyester retains client order IDs according to the order lifecycle:
| Order state | Client order ID behavior |
|---|---|
| Pending or open | Retained without a TTL while the order remains active |
| Terminal | Retained through the configured terminal window after the order is filled, canceled, rejected, or expired |
| After the retention window | Eligible for background cleanup; the ID may remain reserved until cleanup completes |
The current default terminal retention window is 24 hours. Deployments can configure this window, and background cleanup runs asynchronously, so 24 hours is not an exact release time. Polyester does not provide an API that reports when a particular ID has been released.
Uniqueness is enforced within the selected account. The same value can be reused across different subaccounts without conflict, but globally unique values simplify reconciliation and incident investigation.
Using the ID after creation
Order APIs can use a client order ID to locate an existing order. Depending on the endpoint, you can
use either the Polyester-assigned orderId or your clientOrderId to:
- cancel an order
- identify the target of a modification
- retrieve order details
In these operations, clientOrderId identifies the target order. It is not necessarily the
idempotency key for the operation itself. For example, order modification uses a separate requestId so a retry of the same modification can be deduplicated.
GetOrder briefly waits server-side when an accepted order has not reached the selected API
region's read projection yet. If that bounded grace window expires before projection freshness can
be confirmed, the API returns a temporary unavailable error instead of NOT_FOUND. Retry the same
ordinary lookup with the same orderId or clientOrderId; no consistency token or sticky session
is required.SDK behavior
The Polyester TypeScript SDK does not generate a client order ID for order creation. If you omit clientOrderId, the create request has no client-order-ID duplicate guard or reconciliation key.
Generate and persist your own client order ID before the first attempt whenever your application may retry, resume after a restart, or reconcile an uncertain outcome.