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

# Idempotency

> Use idempotency keys so duplicate requests do not create duplicate work.

<Tip>
  **Live.** This area is documented as current, user-reliable behavior.
</Tip>

## Goal

Make job starts safe for retries, webhooks, signups, and payments.

## Prerequisites

* A stable identifier for the logical work, such as a user ID, order ID, payment ID, or webhook event ID

## Workflow

<Steps>
  <Step>
    Choose a key that represents the logical work.
  </Step>

  <Step>
    Pass that key when starting or enqueueing the job.
  </Step>

  <Step>
    Reuse the same key when the same request is retried.
  </Step>

  <Step>
    Treat a key with a different payload as an error to fix, not a new job.
  </Step>
</Steps>

## The problem

APIs retry. Browsers double-submit. Payment providers resend webhooks. Workers restart after partial progress.

Without idempotency, those duplicates can send two emails, charge twice, provision twice, or process the same webhook more than once.

## The solution

An idempotency key tells StackShift that repeated starts represent the same logical job.

<CodeGroup>
  ```ts Send verification email once theme={null}
  await stackshift.queue('emails').enqueue(
    'sendVerificationEmail',
    { userId: '123' },
    { idempotencyKey: `verify:123` }
  )
  ```

  ```go Go theme={null}
  _, err := client.Queue("emails").Enqueue(ctx,
    "sendVerificationEmail",
    map[string]any{"userId": "123"},
    &stackshift.EnqueueOptions{
      IdempotencyKey: "verify:123",
    },
  )
  ```
</CodeGroup>

## Behavior

* Same key and same payload: StackShift reuses the existing run.
* Same key and different payload: StackShift returns an error because the caller is trying to reuse a key for different work.
* Retries are safe because the same logical operation maps to the same run.
* Webhooks are safe because repeated delivery can reuse the provider event ID as the key.

## Real use cases

* Payments: use the payment intent, transaction, or provider event ID.
* Webhooks: use the webhook event ID.
* User signup: use the user ID or email-verification token ID.

## Expected result

<Check>
  Duplicate requests reuse the same run instead of doing the same side effect twice.
</Check>

## Related guides

<CardGroup cols={2}>
  <Card title="Event Waiting + Correlation" href="/durable-jobs/event-waiting-and-correlation">
    Pause a workflow until the right external event arrives, then resume the correct run.
  </Card>

  <Card title="Retries & Failure Handling" href="/durable-jobs/retries-and-failure-handling">
    Durable Jobs retries transient failures, preserves completed steps, and gives failed work a clear recovery path.
  </Card>
</CardGroup>
