---
title: "Idempotent requests"
description: "Safely retry failed requests without duplicating orders, payments, or notifications."
canonical: "https://studio.inttegro.com/api/idempotency"
format: inttegro-machine-docs/v1
language: "TypeScript"
sdk_version: "v12.0.0"
reader_profile: optional
reader_manifest: "https://studio.inttegro.com/machine/typescript/readers/index.json"
reader_identification: "Optional: declare your client only if known and your current-session capabilities; use reader_manifest for supplemental recommendations."
preamble_estimated_tokens: 581
model_token_report: "https://studio.inttegro.com/machine/token-report.json"
preamble_questions: 5
preamble_source: "machine-only-decisions"
recommended_mcp_tools: ["create_order"]
estimated_tokens: 3589
token_estimate_method: "utf8_bytes_divided_by_4"
---

## Machine preamble

**Summary:** Safely retry failed requests without duplicating orders, payments, or notifications. This TypeScript representation uses the selected SDK's native names wherever Studio has a verified mapping.

### Five questions

#### Q1. Is Idempotent requests the right source for this task?

Use this reference for safely retry failed requests without duplicating orders, payments, or notifications. For the complete outcome or lifecycle, start with [Send customer notification](https://studio.inttegro.com/machine/typescript/guides/send-customer-notification.md); return here for exact operations and fields.

#### Q2. What does “Derive one stable key before the first attempt and reuse it unchanged” require?

**Derive one stable key before the first attempt and reuse it unchanged.** A
newly generated key represents a new action and cannot protect against an
earlier success whose response was lost.

#### Q3. What does “Reuse requires the same operation and payload” require?

**Reuse requires the same operation and payload.** Replaying a successful
request with the same key and payload within 24 hours returns its original
response. Changing the payload produces an idempotency conflict instead of a
second execution.

#### Q4. What does “A failed validation or authentication attempt is not cached as a success” require?

**A failed validation or authentication attempt is not cached as a success.**
Correct the underlying problem, then repeat the same logical request with its
existing key. For a transient failure, back off as directed by
[Errors](https://studio.inttegro.com/machine/typescript/api/errors.md).

#### Q5. What does “Verify endpoint support” require?

**Verify endpoint support.** Idempotency is operation-specific. Do not infer
replay protection merely because an operation mutates state; confirm it in
that endpoint's API reference.

### Recommended MCP assistance

Use these through an authenticated Inttegro MCP connection. This document remains the contract source.

- [`create_order`](https://studio.inttegro.com/machine/typescript/inttegro-mcp/tools.md#create_order) — action; exact user confirmation required. Creates an order for an existing customer from catalog product and price IDs. This tool never executes payment; finalize defaults to false.

## Document content

# Idempotent requests

Network failures, timeouts, and server errors happen in production. Idempotency keys let you retry failed requests safely without creating duplicate orders, charging customers twice, uploading duplicate files, or sending multiple notifications for the same event. This guide explains how Inttegro APIs handle idempotency and how to implement retry logic that protects your customers and your business.

## Preserve one logical action across retries

The four decision rules are in the machine preamble above.

## How it works

For an operation that supports idempotency, Inttegro assigns an idempotency key to each request. If you don't send one, Inttegro generates a key for that individual request. To make a later retry find the original result, send your own stable key in the `Idempotency-Key` header. Order creation also accepts the same value as `request_meta.idempotency_key`; if you send both locations, they must match. A successful request replayed with the same key and payload within 24 hours returns the original response without re-executing the operation.

Failed requests are not cached—if a request fails with validation errors, authentication issues, or server errors, you can immediately retry with the same idempotency key after addressing the underlying problem. This eliminates the burden of generating new keys for legitimate retries while still protecting against duplicate successful operations.

Idempotency is enabled operation by operation, not automatically for every mutation. Check the endpoint reference before relying on replay protection. For orders, create, pay, confirm payment, request confirmation, update, finalize, send invoice, and send receipt support idempotent retries. Read-only order lookup and pagination do not.

The idempotency guarantee applies per Inttegro account—two accounts can use the same idempotency key without conflict. Client-provided keys are case-sensitive and must be between 1 and 255 characters. Inttegro recommends constructing keys from stable business identifiers like `order_${orderNumber}` or `payment_${cartId}_${timestamp}` rather than generating a fresh random value for each attempt—this makes debugging easier and ensures retries genuinely duplicate the original intent.

**Important**: Idempotency protects against duplicate execution of the same operation. If you reuse the same key with a different operation payload, Inttegro returns `idempotency_key_conflict` before executing the new operation. Fields inside `request_meta` are request controls and are excluded from that operation comparison.

## When to use idempotency keys

Supply stable idempotency keys for any operation where duplicates would cause problems:

**Critical operations (always supply a stable key)**

- **Creating orders** - Prevents charging customers twice for the same purchase
- **Executing payments** - Ensures payment attempts aren't duplicated during retries
- **Scheduling payouts** - Avoids sending funds multiple times to the same destination
- **Sending notifications** - Prevents customers from receiving duplicate order confirmations or payment receipts

**When network failures occur**

- Socket timeouts before receiving a response
- Connection drops mid-request
- HTTP 5xx server errors (500, 502, 503, 504)
- HTTP 429 rate limit errors (safe to retry with backoff)

## How to use idempotency keys

Use the `Idempotency-Key` request header on any operation whose reference marks idempotency as supported. Order creation also accepts `request_meta.idempotency_key`. The key is a string between 1 and 255 characters that identifies one logical operation. If you send it in both locations, the values must match.

**Using idempotency keys — POST /orders/create**

```typescript
import * as Inttegro from '@inttegro/inttegro-sdk'

const inttegro = new Inttegro.InttegroClient({
  apiKey: process.env.INTTEGRO_API_KEY!,
})
const result = await inttegro.orders.create({
  requestMeta: {
    idempotencyKey: "order_checkout_abc123_1737371200",
  },
  customerData: {
    name: "Akua Mensah",
    emailAddress: "akua@example.com",
    phoneNumber: "+233544998605",
  },
  finalize: true,
  lineItems: [
    {
      type: Inttegro.LineItemTypes.Product,
      product: {
        name: "Monthly subscription",
        price: {
          currency: "ghs",
          value: 5000,
        },
        quantity: 1,
        type: Inttegro.ProductTypes.Service,
      },
    },
  ],
})
```

The pattern here is to construct idempotency keys from stable business identifiers rather than generating a new random value for each attempt. The `checkout_id` identifies the specific operation (which cart or session), while the `timestamp` ensures uniqueness if the same cart is checked out multiple times. If a request times out, retry with the exact same key to retrieve the original response. If you omit the key, Inttegro still processes the request with an auto-generated UUIDv7 key, but your next retry will not know that generated key.

## Constructing effective keys

Good client-provided idempotency keys are predictable, debuggable, and tied to business events. They should contain enough context to understand what operation they represent when reading logs or investigating issues.

**Recommended patterns:**

- `order_${cart_id}_${timestamp}` - Order creation from shopping cart
- `payment_${order_id}_attempt` - Payment execution for an order
- `payout_${batch_id}_${currency}` - Scheduled payout for a batch
- `notify_${resource_type}_${resource_id}_${event}` - Event-driven notifications
- `refund_${payment_id}_${amount}` - Partial or full refund operations

**Key characteristics:**

- **Stable identifiers** - Use business IDs (order numbers, cart IDs) for retryable operations
- **Event context** - Include what happened (`confirmed`, `failed`, `shipped`)
- **Resource type** - Prefix with resource name (`order_`, `payment_`, `payout_`)
- **Timestamp when needed** - Add Unix timestamp for operations that can repeat legitimately
- **Length constraint** - Keep under 255 characters (Inttegro enforces 1-255 character range)

**Avoid these patterns:**

- ❌ `random_uuid()` per attempt - Each retry uses a different key, so it cannot replay the original response
- ❌ `request_${counter}` - Counter state is hard to maintain across retries
- ❌ `${timestamp}_only` - Doesn't identify what operation is being attempted
- ❌ `order` - Not unique, will incorrectly return cached response

## Retry behavior and timing

When you retry a successful request with an idempotency key, Inttegro returns the original response without executing the operation again. The replay uses the original HTTP status, original response body, and replay-safe response headers. Failed requests are not cached, so you can retry immediately with the same key after fixing validation errors, authentication issues, or waiting out transient server problems.

**What gets cached:**

- **Successful responses only** - 2xx status codes with full response body are stored for 24 hours
- **Failed requests are not cached** - 4xx and 5xx errors can be retried immediately with the same key
- **In-progress requests are protected** - if the first request is still executing, a retry with the same key returns `idempotency_key_in_progress`
- **Payload conflicts are rejected** - same key plus different operation payload returns `idempotency_key_conflict`

**In-progress retries:**

Inttegro reserves an idempotency key before executing a mutation, then stores the successful response after the mutation completes. If a retry arrives while the first request is still running, Inttegro returns `409 Conflict` with `idempotency_key_in_progress`. Do not change the key for that retry. Keep retrying the same request with exponential backoff so the retry can replay the original response once it completes.

In rare cases, a worker can stop after reserving the key but before storing the successful response or releasing the reservation. Inttegro treats that reserved key as in progress to avoid duplicate side effects. If `idempotency_key_in_progress` continues for several minutes on the same key, contact support with the endpoint, approximate request time, and key value.

If idempotency storage is temporarily unavailable, Inttegro returns `503 Service Unavailable` with `idempotency_storage_unavailable`. Retry the same request with the same key later; do not switch to a new key for the retry.

**Cache duration:**

Inttegro stores successful responses for **24 hours** from the original request. After 24 hours, the same idempotency key can be reused for a genuinely new operation. This 24-hour window is sufficient for most use cases while allowing keys to naturally expire for legitimate new operations.

**Retry strategy:**

Implement exponential backoff when retrying failed requests—don't hammer the API with rapid retries. Start with a 1-second delay and double it after each failure:

1. First retry: wait 1 second
2. Second retry: wait 2 seconds
3. Third retry: wait 4 seconds
4. Fourth retry: wait 8 seconds
5. Fifth retry: wait 16 seconds
6. Give up or alert support after 5 attempts

This approach gives transient issues time to resolve while avoiding API rate limits. For HTTP 429 rate limit errors, respect the `Retry-After` header instead of using exponential backoff.

## Idempotency key requirements

Inttegro generates a UUIDv7 key when you don't provide one. If you do provide an idempotency key, Inttegro validates it before processing the request to ensure it meets system constraints:

**Length constraints:**

- **Minimum**: 1 character
- **Maximum**: 255 characters
- Keys outside this range return a `400 Bad Request` error

**Format requirements:**

- **Case-sensitive** - `Order_123` and `order_123` are different keys
- **No special encoding** - Use plain ASCII or UTF-8, no URL encoding required
- **No whitespace inside the key** - Leading and trailing spaces are trimmed, then whitespace or control characters are rejected

**Uniqueness scope:**

- **Per Inttegro account** - Different accounts can use the same key without conflict
- **Per endpoint** - Same key can be used for different operations (order vs. payment)
- **Time-bound** - Keys expire after 24 hours and can be reused

If you provide an invalid idempotency key (too long or improper format), Inttegro returns an error before attempting to process the request—no operation is executed, and you can immediately retry with a corrected key. If you omit the key, Inttegro generates a valid UUIDv7 key automatically.

## Related resources

- **[Accept a payment](https://studio.inttegro.com/machine/typescript/guides/accept-a-payment.md)** - Complete payment flow with idempotency
- **[Send customer notification](https://studio.inttegro.com/machine/typescript/guides/send-customer-notification.md)** - Notification delivery with duplicate protection
- **[Errors](https://studio.inttegro.com/machine/typescript/api/errors.md)** - Understanding error responses and retry strategies
- **[Authentication](https://studio.inttegro.com/machine/typescript/api/authentication.md)** - Securing API requests with bearer tokens
