Polymr
For IT · 6 min

Idempotency keys 101 for ERP writes

Why the natural unit of the destination system matters more than your sequence ID, what a retry storm looks like in practice, and the three keys to pick for SAP MM, NetSuite, and a custom Oracle MDM.

Idempotency is the property that a repeated operation has the same effect as a single operation. Writes to an ERP have to be idempotent because retries are inevitable. The choice of idempotency key is the load-bearing detail and the one most often gotten wrong.

Why idempotency matters more than people think

The naive failure mode: the operations layer issues a PO write to the ERP. The write succeeds at the ERP. The response back to the layer times out. The layer retries. The ERP creates a second PO. The vendor receives two POs for the same requirement. Inventory is over-committed. The buyer is fielding a phone call within the hour.

The right shape is that the second write is a no-op because the ERP recognises the operation as a duplicate. The recognition requires an idempotency key that the ERP will check against its history of recent operations. Choose the key wrong and the ERP either rejects valid retries or accepts duplicates.

What an idempotency key is and is not

An idempotency key is a unique string the client generates and sends with the write. The server records the key against the operation. If the same key arrives again, the server returns the original result without re-executing the operation. The key has to be stable across retries (so the second attempt looks the same as the first) and unique across operations (so two different operations do not collide).

The key is not a sequence number from your system. Sequence numbers are stable per write but they assume that retries come from a single client. If two retry paths converge (the operations layer retries and a downstream service also retries), they generate different sequence numbers for what is the same operation. The ERP sees two operations and accepts both.

How to pick a key

The principle is to use the natural unit of the destination system. The natural unit is the field combination that the destination treats as identifying a single operation.

SAP MM

For PO creation in SAP MM, the natural unit is typically the combination of (plant, vendor, document_type, source_reference). The source_reference is a free-text field SAP accepts on PO creation that downstream consumers ignore. Stuffing a stable hash of the source artifact into the source reference and using the combined key as the idempotency identifier gives you a stable, ERP-checkable, naturally-unique key.

Why not just the source artifact hash on its own? Because two different POs can reference the same source artifact legitimately (a long-running quote that produces multiple POs across plants). Combining with plant and vendor disambiguates.

NetSuite

NetSuite supports an external ID field on most record types. The external ID is a free-form string that NetSuite guarantees unique per record. Stuff your stable idempotency key into the external ID at create time. Subsequent attempts with the same external ID return the existing record. This is the cleanest pattern of the three because NetSuite explicitly designed for it.

The external ID has a length limit (100 characters at the time of writing) and a uniqueness check. Use a hash-of-the-canonical-operation-payload as the external ID. The hash is deterministic and short enough.

Custom Oracle MDM

Custom Oracle environments rarely have a clean idempotency-key pattern built in. The honest answer for custom Oracle is to add one. The right shape is a dedicated external_idempotency_key column on the target table, indexed and unique. Writes from the operations layer set the column. The layer's write path checks for the key's existence before issuing the insert. If the key exists, the write becomes a select that returns the existing row.

The column addition is a schema change. The work to add it is a one-time cost that pays back forever. Skipping it and trying to derive an idempotency key from existing fields invariably produces edge cases where two legitimate operations collide or one legitimate retry is treated as a duplicate.

What a retry storm looks like

A retry storm without idempotency keys is a specific failure shape that operations teams recognise once and remember forever. The operations layer is writing to the ERP at a steady rate of a few hundred POs per day. A network blip causes the layer to lose connectivity to the ERP for 90 seconds. The layer queues the writes. When connectivity restores, the layer retries the queued writes. The ERP accepts all of them, including the ones that actually succeeded before the blip.

The result: the ERP now has duplicate POs for everything that was in flight during the blip. The buyer's queue is twice as long the next morning. Vendors start emailing about duplicate orders. Procurement cancels half of them manually. The cleanup takes two days. The audit log shows the layer behaved correctly (retried after a failure) and the ERP behaved correctly (accepted the writes). Nobody violated their contract. The contract was missing.

With idempotency keys, the same scenario produces no duplicates. The retry attempts arrive at the ERP, the ERP checks the keys, finds them already processed, returns the original responses. The layer's queue drains cleanly and the buyer's morning is unchanged.

The three rules for the operations-layer side

  1. Generate the key before the first attempt and persist it. The key has to survive crashes of the operations layer. Generate it at the point the operation is intended, write it to the layer's own state, and use that key on every attempt including retries after a process restart.
  2. Use a deterministic key derivation, not a random UUID. If the operation is computed twice from the same inputs (a duplicate intent), the key should match so the ERP treats it as the same operation. A random UUID does not have this property and can mask duplicate intents as separate operations.
  3. Log every retry with the key it used. The audit log should show how many retries an operation took. Operations that needed three or more retries are often early-warning signals of an integration that is flaking or being rate-limited.

What good looks like, in one sentence

Good looks like: every write to the ERP carries a deterministic idempotency key tied to the natural unit of the destination, every retry uses the same key, and the audit log shows the key and the retry count for every operation. With those properties, a retry storm is a non-event. Without them, a retry storm is a two-day cleanup the buyer remembers for the rest of their tenure.