How to choose the right idempotency key for an event: Keep the same idempotency key for retries of one action; use a new key for a new action.; Write: one [effect] for each [identity], e.g. one standard invoice per approved order.; Check stability, uniqueness, scope and lifetime; include tenant ID for tenant-scoped IDs.
Image: Workflow Automation Guide

Error Handling

Part of Idempotency and duplicate prevention

Choosing an idempotency key for an event

Choose a stable idempotency key that recognises retries without blocking a legitimate new event or action.

Choose an idempotency key that stays the same for retries of one action and changes for a genuinely new action. The key states identity; it is not a convenient hash of whatever fields are available. Define the business action, then choose the field or combination that represents it.

How to choose and validate an idempotency key

  1. Define the business actionState what the action is before choosing a key; the key should represent that action, not a hash of convenient fields.
  2. Write the one-effect sentenceUse “There should be one [effect] for each [identity]” to derive the key, such as one standard invoice for each approved order.
  3. Check the four questionsTest stability, uniqueness, scope and lifetime, including tenant or organisation boundaries.
  4. Match the downstream contractKeep the same key for retries of the same intended API call; generate a new key only for a new action.
  5. Test the casesTest a repeated event, a second event for the same business action, and a genuinely new action with similar content.

Separate delivery identity from business identity

A producer's event ID can identify a redelivered event. It does not always identify a duplicated business request. Two distinct events might both ask a workflow to create the same invoice.

Conversely, two orders from the same customer may have identical amounts and still deserve separate invoices. An email address, timestamp rounded to a minute or entire payload hash can collapse legitimate actions or fail to recognise retries after harmless data changes.

For each protected effect, write a sentence: “There should be one [effect] for each [identity].” For example, “one standard invoice for each approved order” suggests an order ID plus invoice type.

“One welcome email for each account activation” suggests account ID plus activation event, provided the product's definition of activation is clear. These are design examples, not claims about a particular platform.

Delivery identity vs business identity

  • Delivery identityA producer's event ID can identify a redelivered event. It may not identify a duplicated business request.
  • Business identityThe field or combination that represents the business action, such as order ID plus invoice type or account ID plus activation event.

Check the key against four questions

  1. Stability:Will a timeout and retry reuse exactly the same key?
  2. Uniqueness:Can two legitimate actions accidentally share it?
  3. Scope:Is the key unique within the right tenant, account or workflow, rather than only within one queue?
  4. Lifetime:How long can a duplicate arrive, and how long will the system remember the key?

Include a tenant or organisation identifier when IDs are only unique inside that boundary. Avoid personal information in a key if an opaque stable identifier will do. Store enough of the original request to reject a key reused for a different action. The outcome for a duplicate should be deliberate: return the earlier result, report “already processed”, or expose a conflict that needs investigation.

Four questions to test an idempotency key

  • StabilityWill a timeout and retry reuse exactly the same key?
  • UniquenessCan two legitimate actions accidentally share it?
  • ScopeIs the key unique within the right tenant, account or workflow, rather than only within one queue?
  • LifetimeHow long can a duplicate arrive, and how long will the system remember the key?

Match the downstream contract

Some external APIs offer their own idempotency mechanism. Stripe's API documentation says a client supplies a key for retryable create or update requests; it compares later request parameters with the original and may remove keys after at least 24 hours. Those details are specific to Stripe.

If your retry window is longer, or your workflow also writes to another system, its key alone may not cover every duplicate path.

Keep the same key through every retry of the same intended API call. Generate a new key only when the user or business process initiates a new action. Log the key with the workflow run and resulting object ID so an operator can explain why a later event was accepted or skipped.

Test a repeated event, a second event for the same business action and a genuinely new action with similar content. A key is well chosen only if it separates those cases in the way the business expects.

More from Error Handling