Skip to content
ERRNAInsight Center

ERRNA expert insight

Order Entry Timeouts on a Crypto Exchange: An Operator's Design for Idempotent Orders and Safe Reconciliation

By Akeel Q.November 4, 202625 min readBlockchain

A client sends a buy order. The connection stalls. No acknowledgment arrives. What should the platform do next?

For a read request, the answer is simple: retry. For an order, retrying can double a customer's market exposure. Not retrying can leave an order resting on the book that the customer believes does not exist. Either mistake creates a financial, support, and audit problem at the same time.

This article is written for product heads and exchange operators who own order-entry behavior, API contracts, and the roadmap decisions behind them. It explains why order-entry timeouts are an ambiguity problem rather than a retry problem, and it proposes a design for handling them: a durable, tenant-scoped intent record bound to an approved payload hash, claimed atomically, dispatched through a recoverable outbox, and reconciled against authoritative venue state before any resend. We call this proposed design the Order Intent Ledger. It is a design pattern for you to evaluate, not a claim about any specific product or an established proprietary method.

The article also ends with an all-required go/no-go control set. It deliberately avoids a summed score, because a platform that passes nine controls and fails the tenth is still not safe for programmatic order entry.

Related reading on this site covers adjacent boundaries: idempotent withdrawals and webhooks and unknown withdrawal outcomes. This piece addresses a different system boundary: the order gateway and matching path, where the dominant risk is unintended market exposure rather than stuck funds.

Key Takeaways (BLUF)

  • A timeout is not a failure. It means completion could not be confirmed. Treat it as an unknown state, never as success and never as a verified rejection.
  • Never blindly resend an order after a timeout. Query authoritative order state by your durable identifier first, then decide.
  • Bind identity to content. A tenant-scoped intent ID plus an immutable hash of the approved payload lets you replay safely and reject a reused ID carrying different content.
  • Claim work atomically. Record the intent, the dispatch work, and the outbox entry in one transaction, and let exactly one worker own dispatch.
  • The venue must enforce too. Read-compare-then-write in the gateway is not compare-and-swap. The matching side needs conditional, target-side checks.
  • Identifiers are data. Client order IDs can leak account, strategy, or user information, so treat them as sensitive.
  • Use go/no-go controls. Every control must pass before you enable programmatic order entry for a tenant or market.

Why Order-Entry Timeouts Are an Ambiguity Problem, Not a Retry Problem

Key Takeaways: An order request crosses several boundaries, and a timeout can occur at any of them. Only one boundary, the engine's own persisted record, is authoritative about whether the order exists.

Most engineers first meet retries in stateless services, where repeating a call is harmless. An order is a consequential mutation. It creates a liability on the book, may trade immediately, and moves balances. The same HTTP or socket timeout means very different things depending on where the request stopped.

Consider the path of a single order: client, edge or API gateway, order service, risk and balance check, matching engine, execution report back to the client. A client that sees no response cannot tell which of these stages completed. The gap between "the request left my process" and "the engine accepted it" is exactly where operators lose money and trust.

Where the request stoppedWhat the client seesWhat may actually be true
Before the gatewayTimeoutNothing exists. A resend is safe.
Gateway received, order service not reachedTimeoutNothing exists, or the work is queued and will run later.
Risk check passed, engine call in flightTimeoutOrder may be accepted, rejected, or lost.
Engine accepted and may have filledTimeoutLive order or fills exist. A resend doubles exposure.
Engine responded, response lostTimeoutAuthoritative result exists but the client never saw it.

The client's timeout is identical in all five rows. That is the core of the problem: the observable signal does not discriminate between states that require opposite actions.

Two further facts make this harder on crypto venues. Markets run continuously, so there is no overnight window to reconcile quietly. And many crypto venues serve programmatic and market-maker traffic, where a single automated client can issue many orders per second, so one ambiguous pattern repeats at scale. Execution quality is also at stake, which is covered separately in our piece on the exchange operator's execution quality mandate.

Session-layer recovery is not business-outcome recovery

Trading protocols such as FIX have session-level mechanisms for sequence numbers and message resend. Those address whether messages were delivered between two session endpoints. They do not, by themselves, tell your product team whether a business instruction was accepted, nor do they prevent your own application from submitting a second logical order. Application-level identity and state are still your responsibility.

How Most Platforms Handle It, and Why That Fails

Key Takeaways: The common patterns each solve one failure and create another. The usual gap is that identity is not bound to content, scope is not bound to a tenant, and "no response" is quietly treated as a verdict.

Most order gateways evolve organically. A retry is added after a support ticket. A duplicate check is added after a double fill. Each patch is rational on its own. Together they rarely form a coherent contract.

Common practiceWhy it seems reasonableHow it failsRequired correction
Client auto-retries on timeout with a freshly generated order IDKeeps the client simplePlatform cannot tell the retry from a new order. Both can execute.Reuse one stable intent ID per logical order and reconcile before resending.
Dedupe on key onlyEasy to implementA reused key with different quantity or price returns the old result, so the client believes the new content was accepted.Store a payload hash and reject changed-payload reuse.
Dedupe in a time window cacheBounded memoryA late retry after expiry executes as a new order.Durable records with a published retention policy.
Global key namespaceSimple schemaIn multi-tenant or white-label setups, two tenants can collide or one can probe another's identifiers.Scope uniqueness by tenant, and authenticate before lookup.
"No response in N seconds means rejected"Gives the user a quick answerOrder may still be live. The UI shows "failed" for a resting order.Introduce an explicit unknown state.
Read existing record, compare, then writeFeels like deduplicationTwo concurrent requests can both read "absent" and both write.Unique constraint or conditional write enforced by the store.
Acknowledge the client after enqueueing, separately from persistingLow latencyA crash between the two loses the order or duplicates it on recovery.Persist intent and outbox entry atomically before acknowledging intake.

A recurring root cause is organizational rather than technical. The API team owns the client contract, the matching team owns engine behavior, and operations owns reconciliation. Nobody owns the end-to-end question: for a given order intent, what is the single authoritative state, and who is allowed to change it?

Platforms deploying a packaged exchange stack face a version of this too. If you are evaluating a white-label crypto exchange, ask early how order-entry identity, duplicate handling, and reconciliation behave across tenants, because those behaviors are hard to retrofit once API clients depend on them.

The Proposed Design: An Order Intent Ledger

Key Takeaways: The Order Intent Ledger is a proposed design, not a standard. It binds a tenant-scoped intent ID to an immutable approved payload hash, claims dispatch atomically, and defines terminal, unknown, and acknowledged states precisely.

The ledger rests on five rules.

  1. Durable, tenant-scoped identity. The uniqueness key is the pair (tenant, intent ID). The same ID under a different tenant is a different intent.
  2. Immutable approved payload. After validation, the gateway computes a hash over a canonical form of the approved fields (side, instrument, quantity, price, order type, time-in-force, and any account reference). The record stores that hash and never overwrites it.
  3. Atomic acceptance. The intent row and the outbox entry that schedules dispatch are written in one transaction. Only after commit does the gateway tell the client the intent was accepted for processing. That message is not a venue acknowledgment.
  4. Atomic claim. Exactly one worker moves an intent from received to dispatching, using a conditional update that checks the current state and increments a claim epoch.
  5. Venue-side enforcement. The matching or order-management layer also enforces uniqueness of (tenant, intent ID) with the same hash. A gateway check alone cannot protect against a second gateway instance or a recovered worker.

States and what each one permits

StateMeaningResend allowed?Customer-visible wording
RECEIVEDIntent persisted, not yet dispatchedDispatch only via the claimed workerAccepted for processing
DISPATCHINGA worker holds the claimNo, unless the claim lapses and is re-fencedProcessing
VENUE_CONFIRMED_LIVE / PARTIAL / FILLED / CANCELEDEngine-authored execution report persistedNeverVenue status
VENUE_REJECTEDEngine-authored reject persisted, with reasonOnly as a new intent with a new ID after the client decidesRejected, with reason
REJECTED_PRE_DISPATCHFailed validation before anything was sentNew intent onlyRejected, not sent
NOT_ACCEPTED_FENCEDVenue confirmed it will refuse any late arrival of this intentNew intent onlyNot accepted
UNKNOWNDispatched, completion could not be confirmedNo. Reconcile first.Status being confirmed

Notice what is absent: there is no state called "timeout failed." An unknown result means completion could not be confirmed, not success and not verified failure. Only engine-authored records, or a verified fence, move an intent out of unknown.

Verified acknowledgment versus intake receipt

Two different messages are routinely conflated. The intake receipt says your platform durably recorded the intent. The venue acknowledgment says the engine accepted or rejected it. Only the second changes market exposure. Surface both, name them differently, and never let an intake receipt render as "order placed."

Illustrative sketch

The following is an illustrative, PostgreSQL-style sketch of the intake and claim steps. It is not an official API contract for any venue or product, and the names are placeholders.

-- Illustrative sketch only. Not an official API contract. CREATE TABLE order_intent (   tenant_id     text   NOT NULL,   intent_id     text   NOT NULL,   payload_hash  bytea  NOT NULL,   -- hash of canonical approved payload, never updated   state         text   NOT NULL,   -- RECEIVED, DISPATCHING, UNKNOWN, ...   claim_epoch   bigint NOT NULL DEFAULT 0,   claim_owner   text,   venue_ref     text,              -- engine-assigned reference, once confirmed   PRIMARY KEY (tenant_id, intent_id) );  -- Intake: one transaction covers intent record AND outbox entry. BEGIN; INSERT INTO order_intent (tenant_id, intent_id, payload_hash, state) VALUES (:tenant, :intent, :hash, 'RECEIVED') ON CONFLICT (tenant_id, intent_id) DO NOTHING; -- If zero rows inserted: read the stored row. --   stored hash differs  -> reject as changed-payload reuse (conflict) --   stored hash matches  -> return recorded state; do NOT enqueue again INSERT INTO outbox (tenant_id, intent_id, payload_hash) SELECT :tenant, :intent, :hash WHERE EXISTS (SELECT 1 FROM order_intent               WHERE tenant_id = :tenant AND intent_id = :intent                 AND state = 'RECEIVED' AND payload_hash = :hash) ON CONFLICT DO NOTHING; COMMIT;  -- Claim: the conditional update is the compare-and-swap. UPDATE order_intent    SET state = 'DISPATCHING', claim_owner = :worker, claim_epoch = claim_epoch + 1  WHERE tenant_id = :tenant AND intent_id = :intent AND state = 'RECEIVED' RETURNING claim_epoch; -- Zero rows returned: another worker owns it or it already advanced. -- Send the claim_epoch to the venue so stale workers can be fenced out.

Two details matter here. First, the stored hash is compared in the same transaction path as the insert, so the decision does not rely on a separate read-then-write window. Second, the claim is a conditional update that the database enforces, which is the difference between real compare-and-swap and a check that two workers can pass simultaneously. If your store cannot offer an equivalent conditional write, disclose the limitation and serialize those operations explicitly.

Distinguishing legitimate later operations

Idempotency must not block legitimate behavior. A customer who deliberately places the same order again ten minutes later is a new intent and needs a new ID. A cancel or an amendment is its own operation with its own identity, and it should reference the order it targets. In FIX, for instance, a cancel/replace request carries its own ClOrdID and references the prior one; the venue-level pattern is the same: new operation, new identity, explicit target.

Amendments deserve extra care because they depend on the order's current state. Require an expected order version or equivalent precondition, and have the engine reject the amendment if the live order has moved on. Otherwise a stale amendment can overwrite a newer one.

Reconciling an Unknown Order Before Any Resend

Key Takeaways: Query authoritative state by your durable identifier. If the answer is "not found," that is only a proof if the venue can fence late arrivals. Otherwise the state stays unknown.

When an intent sits in dispatching with no engine response, a reconciler takes over. The sequence below is the one we propose operators encode as a runbook and as code.

  1. Freeze resends. Block any further dispatch of that intent ID. Do not let a client library or a worker retry on its own.
  2. Query by durable identifier. Ask the order-management or engine layer for the status of (tenant, intent ID). In FIX terms this resembles an order status request keyed by ClOrdID, which prompts an execution report with an order-status exec type.
  3. Classify the answer. Found and live, partially filled, filled, canceled, or rejected: persist the engine-authored record and move to the matching state.
  4. Handle "not found" with care. A missing record can mean the order never arrived or that it is still in flight. Ask the venue to fence the identifier so any later arrival is refused. If the fence is confirmed, record NOT_ACCEPTED_FENCED. If the venue cannot fence, the state remains UNKNOWN.
  5. Escalate what remains unknown. Route it to a human queue with the intent, hash, timestamps, claim epoch, and last observed signals. Keep the customer-facing status honest.
  6. Only then permit a new intent. If the customer still wants the trade, they submit a new intent with a new ID. The platform never silently converts one into the other.
Reconciliation resultAuthoritative?Action
Engine reports live, partial, or filledYesPersist, notify, never resend
Engine reports rejected with reasonYesPersist reason, allow a new intent
Engine reports not found, fence confirmedYesRecord fenced, allow a new intent
Engine reports not found, no fence possibleNoRemain UNKNOWN, escalate
Status query itself times outNoRemain UNKNOWN, retry the query (not the order)
Venue disagrees with your ledgerVenue record wins for exposureOpen an incident, reconcile balances and positions

Retry the query, not the order

Status queries are safe to repeat. Orders are not. Keep these two retry policies separate in code, in dashboards, and in on-call runbooks.

Cancels have the same ambiguity

A cancel that times out is also unknown. The order might be canceled, filled before the cancel arrived, or still live. Apply the same treatment: durable intent for the cancel, query the order's authoritative state, and report "cancel being confirmed" rather than "cancel failed."

Exposure while unknown

For market orders and aggressive limit orders, time matters. Decide in advance what your risk layer does while an intent is unknown: reserve the balance, hold the margin, and apply per-tenant limits on the number of simultaneously unknown intents. These are product decisions, and they belong on your roadmap rather than in an incident review. For the withdrawal-side equivalent, see our reconciliation playbook for stuck crypto transactions.

Identifiers Are Data: Privacy, Ownership, and Standards Scope

Key Takeaways: Client order IDs and idempotency keys can themselves be sensitive. Assign data ownership explicitly, and use each standard only within the transport and use case it was written for.

It is tempting to treat an order identifier as a harmless token. In practice, API clients often build IDs from meaningful parts: an account number, a strategy name, a timestamp, a sequence counter. Those strings then flow into logs, support tickets, analytics, error messages, and vendor tools. An identifier that encodes a user or a trading strategy is personal or commercially sensitive data, and you are now storing and propagating it.

Privacy and ownership checklist for identifiers

  • Do not require meaningful IDs. Recommend opaque random values, and document that clients should not embed account, personal, or strategy data.
  • Define the data owner. In a multi-tenant or white-label arrangement, state who is the controller or owner of order metadata, and who may read the ledger.
  • Minimize stored content. The ledger needs the payload hash and the fields required for reconciliation and audit. Do not copy full request bodies into every log line.
  • Separate retention clocks. Idempotency records, audit records, and personal data may each have different retention needs. Decide and document each. Which duties apply to you depends on your jurisdiction and licensing, so take advice from qualified counsel.
  • Authenticate before lookup. A duplicate response should never reveal the existence or content of another tenant's intent.
  • Redact in observability. Mask or hash identifiers in logs shared with vendors and support tooling.

Scoping the standards you cite

ReferenceWhat it coversWhat it does not cover
FIX ClOrdID (tag 11)Buy-side order identifier in FIX. Uniqueness is defined per sender and within a trading day. Firms trading globally or across days should embed a date or equivalent to keep identifiers unique across days.REST or WebSocket API behavior, tenant isolation in your platform, payload-hash enforcement, or your internal ledger.
FIX OrderStatusRequest and ExecutionReportA message to ask the order recipient for status, and the report that returns it.Whether a venue can fence a missing order. That is venue-specific.
IETF Idempotency-Key header draftA work-in-progress Internet-Draft describing an HTTP request header for fault-tolerant POST or PATCH. It states that a key must not be reused with a different payload and that the resource should publish its idempotency policy and expiry.FIX sessions, WebSocket order entry, or any guarantee that a given venue honors it. An Internet-Draft is not a standard.

Whatever header or field you adopt, publish your own contract: key scope, key format, expiry, changed-payload behavior, concurrent-request behavior, and which responses are replayed.

2027 Update: standards status, then the durable rule

As of late 2026, the Idempotency-Key header specification remained an active Internet-Draft under the IETF HTTP API working group, and drafts can change or lapse. Check the current datatracker status before citing it as anything more than work in progress. The durable rule outlasts any single draft: whatever the wire format, bind a durable, tenant-scoped identity to an immutable payload hash, and publish how your platform behaves on replay, conflict, and expiry.

Why This Fails in the Real World: Common Failure Patterns

Key Takeaways: These scenarios are illustrative composites for teaching purposes, not customer results. Capable teams still fail because ownership is split, tests miss concurrency, and a quiet "no response" gets treated as a verdict.

The following illustrative scenarios show how intelligent teams end up with duplicate or phantom orders. None describe a specific company. They describe system, process, and governance gaps.

Pattern 1: The failover that created a second order

Illustrative scenario. A client submits a buy for 10 units. The primary gateway instance stalls mid-request. The client library, configured to retry with an automatically generated ID, resends to a second instance. The first instance recovers and forwards its original request. Both reach the engine under different IDs. The client now holds 20 units of exposure that it never intended.

Why capable teams miss it: Each component behaved correctly in isolation. The client retried as documented. The gateway forwarded what it had accepted. The engine accepted two distinct orders. The missing element was a stable intent identity that survives retries and an engine that refuses a second arrival.

Pattern 2: The reused key with different content

Illustrative scenario. An integration bug in a customer's order manager reuses a request key after the order parameters were edited. The platform's duplicate check keys only on the identifier, so it returns the original acknowledgment. The customer's system now believes the edited price is live. The book shows the old price.

Why capable teams miss it: Deduplication tests used identical payloads. Nobody tested the case where the payload changed. The fix is a payload hash and an explicit conflict response.

Pattern 3: The reconciler that declared a verdict

Illustrative scenario. A nightly job marks any intent with no engine record after ten minutes as failed and releases the customer's reserved balance. In one case, the dispatch message was sitting in a delayed queue. It executes after the release. The platform now has an executed order against balances it no longer holds.

Why capable teams miss it: "Not found" was equated with "did not happen." Without a fence on late arrival, that is an assumption, not a proof.

Pattern 4: The white-label namespace collision

Illustrative scenario. Two tenants on a shared platform both use sequential integers as order IDs. The uniqueness constraint is global, so one tenant's valid order is rejected as a duplicate. Worse, a duplicate response leaks a status for an order the caller does not own.

Why capable teams miss it: The schema was designed for a single operator and later reused for multiple tenants. Tenant scope was never part of the key. If you are assessing a packaged stack, our go-live controls for tenant safety and fund movement cover related checks.

The common thread

In every pattern, the engineers were competent and the individual components worked. The failure lived in the seams: no single owner for end-to-end order state, no concurrency testing of the dedupe path, no explicit unknown state, and no tenant scope in the identity model. Fix the seams, not the people.

Practical Implications for Product Heads and Exchange Operators

Key Takeaways: Treat order-entry identity and reconciliation as product features with owners, service levels, and roadmap entries. Choose a delivery option by asking which one gives you verifiable control over these seams.

As a product head, you probably will not write the ledger. You will decide what it must do, what the API promises, and how support explains the unknown state to a customer. The following decisions belong on your roadmap.

  • API contract. Document key scope, format, expiry, conflict behavior, and the exact meaning of each response. Include a statement of what a timeout means.
  • Customer messaging. Define wording for accepted, confirmed, rejected, and "being confirmed." Make the unknown state visible rather than hiding it.
  • Risk policy during unknown. Define balance reservation, per-tenant caps on concurrent unknown intents, and escalation timers.
  • Operational ownership. Name one owner for end-to-end order state. Give that owner the authority to change gateway, engine, and reconciler behavior.
  • Observability. Track counts of unknown intents, their age, fenced versus unresolved outcomes, changed-payload conflicts, and venue-versus-ledger disagreements. Alert on age, not just counts. See also our note on architecting for uptime and low latency.

Comparing delivery options on this one capability

DimensionCustom buildWhite-label or self-hosted packageManaged SaaS exchange
Control over order identity and engine fencingHighest, if you build itDepends on the source access and the extension points the vendor providesDepends on the vendor's published contract
Effort to implement the ledger and reconcilerHigh, owned by youMedium, if hooks exist. Otherwise a wrapper layer.Low on your side, but verify rather than assume
Evidence you can inspectEverything, including testsSource or test evidence, as contractedDocumentation, test environment, and contractual statements
Main hidden riskUnderestimated concurrency and recovery testingShared assumptions across tenantsOpaque behavior in unknown-outcome cases

No delivery option removes the need to verify. Whichever you choose, ask the vendor or your own team to demonstrate the behaviors in the go/no-go list below in a test environment. Vendor statements are claims until you have seen the behavior. If you are early in the decision, our overview of crypto exchange development describes the engagement options available.

Go/No-Go Controls Before You Enable Programmatic Order Entry

Key Takeaways: Every control below is required. One failed control means no-go for that tenant or market, regardless of how many others pass. This list supports your own review, and it does not certify production readiness or regulatory compliance.

We deliberately do not offer a points total. A weighted score invites trading a missing control for a surplus elsewhere, and a missing atomic claim cannot be offset by excellent dashboards. Treat the table as a gate. Each row asks for evidence you can observe in a test environment.

#Control (all required)Evidence to requestGo / No-Go
1Order identity is durable and scoped by tenantSchema or contract showing a (tenant, ID) uniqueness enforced by the storeMust be Go
2Intent is bound to an immutable hash of the approved payloadTest: replay the same ID with a changed quantity returns a conflict, not the old resultMust be Go
3Intent record, outbox entry, and dispatch scheduling commit atomically, or recovery is explicit and testedCrash test between steps. No lost and no duplicated orders on restart.Must be Go
4One worker claims dispatch through a conditional update with a claim epochConcurrency test with multiple workers and forced duplicate deliveryMust be Go
5Venue or engine enforces uniqueness independently of the gatewayTest sending the same intent through two gateway instances. Only one order exists.Must be Go
6Acknowledgment is engine-authored and persisted, distinct from intake receiptAPI responses and UI states showing both messages with different namesMust be Go
7Terminal failures are defined: venue-rejected, pre-dispatch rejected, and fencedState machine documentation and tests for each pathMust be Go
8Unknown is a first-class state, with no auto-resend and a reconciler that queries before actingFault-injection test that drops engine responses. Orders stay unknown and are queried.Must be Go
9"Not found" becomes a negative only through a confirmed fenceTest with a delayed message arriving after a not-found resultMust be Go
10Cancel and amend operations carry their own identity and a state preconditionTest with a stale amend against a changed orderMust be Go
11Later legitimate orders are not blocked by earlier onesTest that a new ID with identical parameters creates a new orderMust be Go
12Identifier privacy and ownership are documented, and logs are redactedData map, retention statement, log samplesMust be Go
13Unknown-intent age and venue-ledger disagreements are monitored with an on-call ownerAlert definitions and a named ownerMust be Go

If a control cannot pass

If the venue cannot fence missing orders (control 9), the answer is not to pretend. Keep affected intents UNKNOWN, cap concurrent unknowns per tenant, and escalate to a human. If the store cannot enforce a conditional write (control 4), serialize those operations and disclose the throughput limit. Either way, document the limitation and its residual risk so the business accepts it knowingly.

Recommendation by role

  • Product head or exchange operator (primary reader): Own the contract and the unknown-state wording. Require the evidence column before enabling any tenant.
  • Engineering lead: Own the ledger, claim logic, and fault-injection tests.
  • Risk and compliance: Review retention, identifier privacy, and escalation records. Regulatory applicability depends on your licensing and jurisdiction, so seek qualified legal advice.

Do your order-entry timeouts end in a verdict or in evidence?

If a stalled order can be resent, marked failed, or double-booked, you have a gap worth closing before volume finds it.

Ask Errna's blockchain and exchange engineers to review your order-entry contract against these go/no-go controls.

Request a Review

Conclusion: Five Actions to Take This Quarter

A timeout is a question, not an answer. These steps turn the question into a controlled process.

  1. Write down what a timeout means. Add an explicit unknown state to your order lifecycle, your API documentation, and your customer messaging. Remove any code path that treats silence as success or as failure.
  2. Bind identity to content. Make the uniqueness key (tenant, intent ID), store an immutable hash of the approved payload, and return a conflict when an ID is reused with different content.
  3. Make acceptance and claiming atomic. Commit the intent and its outbox entry together, claim dispatch with a conditional update, and confirm the venue enforces uniqueness itself.
  4. Rehearse the ugly cases. Run fault-injection tests for dropped responses, duplicate delivery, delayed messages after a "not found," and stale amendments. Keep the evidence.
  5. Assign owners and review identifiers. Name one owner for end-to-end order state, and review what your order identifiers reveal, who can read them, and how long you keep them.

About the author team

Errna is a blockchain, cryptocurrency, and digital-asset technology company, established in 2003, that builds exchange software, custom blockchain systems, and smart contracts for business clients. Its company pages list accreditations such as ISO 27001 and CMMI; as with any vendor, confirm the scope and currency of any certificate during due diligence, since a certification covers a defined scope and is not blanket compliance for any client system. The Order Intent Ledger described here is a proposed design offered for your evaluation. It is not a statement about any specific deployed product.

Reviewed by Errna Expert Team.

Frequently Asked Questions

Is it safe to retry an order after a timeout?

Not blindly. A timeout means completion could not be confirmed. The order may be live, filled, rejected, or never received. Reconcile first by querying the authoritative order state using your durable identifier. Retry the status query as often as needed, but resend the order only after you have an engine-authored result or a confirmed fence on late arrival.

What is the difference between an idempotency key and a client order ID?

They serve related but different purposes. A client order ID identifies the order inside the trading system and appears on execution reports. An idempotency key identifies a request so a repeat can be recognized, typically at the HTTP layer. Many platforms use one value for both, which is fine if the scope, expiry, and changed-payload rules are documented. Whatever you choose, scope it by tenant and bind it to a payload hash.

Does using FIX solve duplicate-order risk?

  • FIX defines ClOrdID as a unique identifier assigned by the order sender, with uniqueness guaranteed within a trading day. Firms trading across days should embed a date or equivalent.
  • FIX sessions have message resend and sequence mechanisms at the session layer.
  • Neither replaces your platform's tenant-scoped ledger, payload-hash comparison, or venue-side uniqueness enforcement.

FIX gives you useful building blocks, such as order status requests, but the design obligations remain with you.

Is the Idempotency-Key HTTP header an official standard?

At the time of writing it was an IETF Internet-Draft in the HTTP API working group, which is work in progress rather than a published standard. Its scope is HTTP requests, so it does not govern FIX or WebSocket order entry. Check the current datatracker status before relying on it, and publish your own idempotency policy in any case.

How long should an operator keep order-intent records?

It depends on your audit, dispute, and legal requirements, which vary by jurisdiction and license. Two points are stable: the retention policy for replay protection should be published to API clients, and a replay after expiry must not silently create a duplicate order. Many operators keep long-lived audit records separately from short-lived replay keys. Consult qualified counsel for your obligations.

How should a white-label exchange isolate tenants on order identifiers?

  • Make tenant part of the uniqueness key, not just a column.
  • Authenticate and authorize before any duplicate lookup.
  • Never return another tenant's status or existence in a conflict response.
  • Redact identifiers in shared logs and support tooling.

Then verify the behavior with a cross-tenant test in a test environment.

What if the venue cannot query orders by client order ID?

Then your ability to resolve unknown intents is limited, and you should say so. Keep affected intents in the unknown state, cap how many a tenant can hold at once, reserve exposure conservatively, and escalate to a human. Consider whether that venue is appropriate for programmatic order entry at all until it can provide an authoritative status lookup.

Should cancel requests also be idempotent?

Yes. A cancel that times out is also ambiguous: the order might be canceled, filled before the cancel arrived, or still live. Give each cancel its own durable identity, reference the target order, query authoritative state before any resend, and show "cancel being confirmed" instead of "cancel failed."

Ready to find out what your platform does when an order goes quiet?

Duplicate fills and phantom orders rarely announce themselves in testing. They appear under load, at failover, and at the worst hour.

Talk with Errna's exchange and blockchain team about order-entry design, reconciliation, and white-label exchange options.

Contact Us