Skip to main content
Every POST /exchange request includes a nonce — an integer that the server uses to prevent replay attacks. Because the nonce is embedded in the signed message, an attacker who intercepts a valid signed request cannot resubmit it: the chain records the nonces each signing address has used and rejects a repeat. That same property is what makes re-sending an identical signed request after a timeout safe — see Timeouts and retries.

What Is the Nonce?

The nonce is an int64 (64-bit signed integer) included at the top level of every POST /exchange envelope alongside action and signature. It is part of the signed message, so any tampering with the nonce value will invalidate the signature.
Use the current Unix timestamp in milliseconds. This is a natural choice because it is:
  • Monotonically increasing — subsequent requests naturally have higher nonces.
  • Unique — millisecond resolution makes accidental collisions unlikely in normal usage.
  • Self-documenting — you can decode the approximate time of any request from its nonce.
Millisecond timestamps are sufficient for most use cases. If you need to fire more than one request per millisecond, increment the nonce by 1 for each additional request within the same millisecond.

Code Examples

Rules

A Unix millisecond timestamp satisfies all of these by construction, which is why it is the recommended source.

Rejections

Check your units before you suspect your clock. These messages describe a time problem, but the usual cause is a value in the wrong unit — and the message points the other way, which sends people hunting for latency or clock skew that is not there.A seconds-precision timestamp is roughly a thousand times too small, which reads to the server as a moment in 1970. The window is two days back and one day forward — generous enough that a correctly-scaled nonce never falls outside it, so an out-of-window error is almost always a unit error.
Sign requests from one address in sequence, not in parallel. Because each nonce must exceed the last one accepted, two requests signed concurrently can arrive out of order and the lower one is rejected. Assign nonces from a single serialised point per signing address. To parallelise, give each worker its own agent wallet — separate addresses have separate nonce sequences.
Keep the number of unconfirmed in-flight requests per signing address small. The server retains only a recent set of used nonces per signing address for duplicate detection. If too many requests are outstanding, a retried request that arrives late with an older nonce can be rejected as nonce too old, even when that nonce is only seconds old.

Rapid Succession Requests

If you need to submit multiple requests faster than one per millisecond, read the current timestamp once and increment:

Timeouts and retries

This is where a client is most likely to execute an action twice. A timeout or a lost response tells you nothing about whether the request was applied.
Never re-sign a timed-out request with a fresh nonce before reconciling. A new nonce makes it a new, valid request — if the original did land, you have now executed it twice. This is the single most common way an automated client double-trades.
The safe procedure:
1

Re-send the identical signed payload

Byte for byte — the same action, the same nonce, the same signature. If the original was applied, this one is rejected as nonce already used and nothing happens twice. Retrying the same bytes is always safe; it is the only retry that is.
2

Treat the rejection as inconclusive

nonce already used means “this nonce was consumed”, not “your order rested”. DUPLICATE_NONCE means the original is still in flight. Neither tells you the outcome of the original request.
3

Reconcile by querying

Establish what actually happened from the read side, never by inference.
4

Only then decide

Issue a new signed request with a fresh nonce only once the query shows the original did not take effect.
Always set the client order ID c on orders you may need to reconcile. Without it, matching a submitted order to what you find in userOrders after a lost response is guesswork.
The invitation code is single-use and consumed during registration. If a registerAccount response is lost, check accountByAddress before requesting another code — the original may have succeeded and spent the code.