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

# Idempotency

> Prevent duplicate operations with idempotency keys

## What is Idempotency?

Idempotency ensures that making the same API request multiple times produces the same result as making it once. This is critical for:

* **Network failures**: Retry safely without creating duplicates
* **Timeouts**: Resubmit requests that timed out
* **Distributed systems**: Handle concurrent requests

## How It Works

Include an `idempotencyKey` in your POST requests:

```json theme={null}
{
  "idempotencyKey": "order-12345-abc",
  ...
}
```

If you send the same key within 24 hours:

1. The system recognizes the duplicate
2. Returns the **original response** without re-executing
3. No duplicate resources are created

## Implementation

### Generate Unique Keys

Use a consistent strategy for generating keys:

```javascript theme={null}
// Option 1: Use your order ID
const idempotencyKey = `order-${orderId}`;

// Option 2: UUID
const idempotencyKey = crypto.randomUUID();

// Option 3: Composite key
const idempotencyKey = `${customerId}-${orderId}-${timestamp}`;
```

### Example: Safe Order Creation

```javascript theme={null}
async function createOrder(order) {
  // Key based on your order ID ensures idempotency
  const idempotencyKey = `create-order-${order.id}`;
  
  try {
    const response = await fetch('https://api.crbtrack.com/api/v1/orders/create', {
      method: 'POST',
      headers: {
        'X-API-Key': process.env.API_KEY,
        'Content-Type': 'application/json'
      },
      body: JSON.stringify({
        idempotencyKey,
        ...orderData
      })
    });
    
    const data = await response.json();
    return data;
    
  } catch (error) {
    // Safe to retry - same idempotencyKey won't create duplicate
    if (shouldRetry(error)) {
      return createOrder(order);  // Same key = same result
    }
    throw error;
  }
}
```

## Idempotency Rules

<AccordionGroup>
  <Accordion title="Key Requirements">
    * **Length**: 8-64 characters
    * **Characters**: Alphanumeric, hyphens, underscores
    * **Uniqueness**: Must be unique per operation type
    * **Expiry**: Keys expire after 24 hours
  </Accordion>

  <Accordion title="Scope">
    * Keys are scoped to your API key (not global)
    * Same key can be used for different endpoints
    * Example: `order-123` for `/orders/create` is different from `order-123` for `/orders/void`
  </Accordion>

  <Accordion title="Response Behavior">
    * **First request**: Operation executes, response cached
    * **Duplicate request**: Cached response returned (HTTP 200)
    * **Different payload, same key**: Error returned (409 Conflict)
  </Accordion>
</AccordionGroup>

## Endpoints Supporting Idempotency

| Endpoint                           | idempotencyKey |
| ---------------------------------- | -------------- |
| `POST /api/v1/orders/create`       | Required       |
| `POST /api/v1/manifests/submit`    | Optional       |
| `POST /api/v1/orders/void`         | Required       |
| `POST /api/v1/labels/{id}/reprint` | Required       |

## Common Patterns

### Pattern 1: Order ID as Key

Best for e-commerce integrations:

```javascript theme={null}
const idempotencyKey = `order-${order.id}`;
```

✅ Simple and predictable\
✅ Natural deduplication if order already processed\
✅ Easy to debug

### Pattern 2: Request Hash

Best for operations without natural IDs:

```javascript theme={null}
const idempotencyKey = crypto
  .createHash('sha256')
  .update(JSON.stringify(requestBody))
  .digest('hex')
  .substring(0, 32);
```

✅ Automatically detects identical requests\
⚠️ Different results for slightly different payloads

### Pattern 3: Timestamp + ID

Best for retry-heavy workflows:

```javascript theme={null}
const idempotencyKey = `${customerId}-${action}-${Date.now()}`;
```

⚠️ Generates new key on each attempt\
⚠️ Doesn't prevent accidental duplicates

## Handling Conflicts

If you send a different payload with the same key:

```json theme={null}
{
  "success": false,
  "error": {
    "code": "IDEMPOTENCY_CONFLICT",
    "message": "Request payload differs from original request with this idempotencyKey"
  }
}
```

**Resolution**: Generate a new unique key for the modified request.

## Best Practices

<CardGroup cols={2}>
  <Card title="Do" icon="check">
    * Use predictable keys (order IDs)
    * Store keys with requests for debugging
    * Retry with same key on failures
  </Card>

  <Card title="Don't" icon="xmark">
    * Generate random keys per retry
    * Reuse keys for different operations
    * Rely on idempotency for business logic
  </Card>
</CardGroup>
