Idempotency
Senticore exposes two separate mechanisms. They are not interchangeable:
| Mechanism | Axis | Use |
|---|---|---|
Idempotency-Key header | Response dedup | Safe HTTP retry for signed action submit, delegated batch submit, and replace/cancel flows. |
clientOrderId (cloid) | Order identity | Strategy-level order label carried in the signed payload and echoed back on BSL full results, execution streams, and drop-copy where provisioned. |
clientOrderId is not a dedup key. It does not collapse duplicate
submissions, and the server keeps no (account, clientOrderId) lookup that
returns a prior order. Use Idempotency-Key for retry safety; use
clientOrderId to correlate your own order id with engine results.
Idempotency-Key (retry safety)
For signed actions and delegated batches, send an Idempotency-Key header when
a network retry may happen. Reuse the same key only for the same intended
payload. Re-submitting the same key returns the original response instead of
re-applying the action.
clientOrderId (order identity)
clientOrderId is part of the signed ActionPayload. When present it is
folded into both the signing hash and the derived OrderId, so two payloads
that differ only by clientOrderId sign to different hashes and resolve to
different order ids. When absent it is omitted from the canonical bytes (it is
not signed as null), which is why existing golden vectors and clients that
never set it are unaffected. See
Local Action Signing.
On the direct-HTTP/BSL signed-action path and the FIX path,
clientOrderId (FIX ClOrdID tag 11) is threaded into the signed payload,
echoed in full response-mode actionResults
(HotpathOrderResult.clientOrderId), and carried into the private execution
stream or drop-copy stream where provisioned.
const order = await client.placeOrder({
market: 'BTC-USDC',
side: 'buy',
price: '60000',
quantity: '0.01',
clientOrderId: 'my-strategy-12345',
});
On the agent (delegated) path the signed engine ActionPayload is built with
client_order_id = None, so the cloid is not in the signed bytes, the
derived OrderId, the engine state, or the state_root. Drop-copy records for
agent orders therefore report clientOrderId = null. A clientOrderId you
pass on a delegated place-order survives only as off-engine sidecar metadata for
a single place-order (not for agent batches); do not rely on it round-tripping
through engine results on this path.
Retention
Idempotency-Key dedup state is retained for the reconciliation window below;
after it lapses a client may reuse the same key. clientOrderId is not retained
as a dedup record - it lives only inside the signed payload and the results that
echo it.
| State | Retention |
|---|---|
| Active order | Until terminal state |
| Terminal order | 7 days for reconciliation |
| Historical fill | Standard account history retention |
Best practices
- Generate
Idempotency-Keyper submitted payload and persist it until a terminal response is known. - Never reuse a key for a different intended action or order.
- Treat an idempotency conflict as "already responded, fetch state".
- Generate
clientOrderIddeterministically from your internal order id; use UUID v4 if no deterministic source exists. - To correlate engine results back to your order, read
clientOrderIdfrom BSLfullresponse-modeactionResultsand from the private execution stream or drop-copy (direct-HTTP/BSL and FIX paths only). - To cancel or replace, target the engine
order_id(the derivedOrderId), not theclientOrderId- cloid is a label, not a server-side handle.
Protocol equivalents
clientOrderId is the same signed-payload field across surfaces:
| Surface | Field |
|---|---|
| HTTP (signed action) | clientOrderId in the action payload |
| FIX | ClOrdID tag 11 |
| BSL compact order entry | client_order_id field in the signed action payload |