> ## Documentation Index
> Fetch the complete documentation index at: https://docs.sumvin.com/llms.txt
> Use this file to discover all available pages before exploring further.

# Nonce Management

> How server-side nonces prevent replay attacks on Stamped Mandates

Every <Tooltip headline="Stamped Mandate" tip="A signed authorisation a user grants for specific scoped actions — delivered on the wire as a PINT." cta="Glossary →" href="/glossary">Stamped Mandate</Tooltip> carries a `nonce` field that prevents replay attacks. The <Tooltip headline="SIS" tip="Sumvin Identity Service — the B2B API that exchanges signed Stamped Mandates for JWTs." cta="Glossary →" href="/glossary">SIS</Tooltip> maintains a server-side nonce registry per wallet, ensuring each Stamped Mandate can only be processed once.

<Snippet file="product-term-disambiguation.mdx" />

A Stamped Mandate is delivered over the API as a `PINT` (header `x-sumvin-pint-token`); the `nonce` lives in the PINT's EIP-712 payload, so the rules below read the same whether you call it a Stamped Mandate or a PINT.

## How Nonces Work

Each wallet address has a monotonically increasing nonce counter maintained by the SIS. When a PINT is submitted for [token exchange](/identity/token-exchange), the nonce in the PINT must be **strictly greater** than the wallet's last-used nonce.

```
Wallet: 0xE23c...
Last nonce: 41

PINT with nonce 42  →  ✅ Accepted (42 > 41). Last nonce updated to 42.
PINT with nonce 42  →  ❌ Rejected (42 = 42). Error: PINT-409-001
PINT with nonce 40  →  ❌ Rejected (40 < 42). Error: PINT-409-001
PINT with nonce 50  →  ✅ Accepted (50 > 42). Last nonce updated to 50.
```

## Rules

**Nonces must increase.** Each PINT's nonce must be strictly greater than the wallet's current `last_nonce`. Equal or lower values are rejected with `409 Conflict` and error code `PINT-409-001`.

**Gaps are allowed.** You don't need to use sequential nonces. Jumping from nonce 5 to nonce 8 is valid. This supports concurrent signing workflows where multiple PINTs may be prepared in parallel but submitted in unpredictable order.

**Atomic validation.** The nonce check and update happen atomically — there's no window for race conditions when multiple PINT exchanges are submitted simultaneously for the same wallet.

**Per-wallet scope.** Nonce counters are scoped to individual wallet addresses. Different wallets have independent nonce sequences.

## Client Implementation

When constructing a PINT, your client should:

1. Track the last-used nonce locally (or retrieve the current nonce from the PINT list endpoint)
2. Set the PINT's nonce to a value greater than the last-used nonce
3. If the exchange returns `PINT-409-001`, increment the nonce and retry

A simple approach is to use Unix millisecond timestamps as nonces — they're naturally monotonically increasing and allow concurrent operations without coordination:

```typescript theme={null}
const pint = {
  wallet: "0xE23c9A70BC749EBddd8c78a864fd911D04E9e992",
  nonce: Date.now(), // Millisecond timestamp as nonce
  // ...
};
```

<Warning>
  The nonce is a `uint256` in the EIP-712 schema. Make sure your implementation handles large integers correctly — JavaScript's `Number` type will lose precision above `2^53`. Use `BigInt` in JavaScript/TypeScript.
</Warning>
