For AI agents: a documentation index is available at the root level at /llms.txt and /llms-full.txt. Append /llms.txt to any URL for a page-level index, or .md for the markdown version of any page.
Contact UsDashboard
DocumentationAPI ReferenceChangelog
DocumentationAPI ReferenceChangelog
  • Get Started
    • Welcome
    • What is Ottimate?
    • Integration Journey
    • Sandbox Environment
    • Authentication
    • API Limits
    • Idempotency
    • Release Plan
  • Account Set Up
    • Onboarding an Ottimate account
    • Accounting Integration
  • Invoice Capture
    • Overview
  • Accounts payable
    • Overview
    • Purchase Orders
    • Purchase Receipts
    • Invoices
  • Catalog
    • Overview
    • Catalog-Entries
LogoLogo
Contact UsDashboard
On this page
  • When to Use
  • How It Works
  • Example
  • Key Format
  • Scope and Lifetime
  • Response Codes
  • Applicability
Get Started

Idempotency

Safely retry write requests without creating duplicates
Was this page helpful?
Previous

Release Plan

Keep track of changes and upgrades to the Ottimate API.
Next
Built with

Network failures, timeouts, and worker restarts make retries unavoidable. The Idempotency-Key header lets you retry a write request without risking duplicate side effects: the first successful response is cached for 24 hours, and any subsequent request with the same key is replayed verbatim from cache.

When to Use

Send Idempotency-Key on every state-changing request where a duplicate would be problematic — creating invoices, posting payments, bulk imports, etc.

The header is optional. If omitted, the request is processed normally without idempotency protection.

How It Works

  1. The client generates a unique key (UUID/ULID recommended) and sends it in the Idempotency-Key header.
  2. On the first request with that key, the server processes normally and caches the 2xx response.
  3. On a retry with the same key:
    • Content-Type: application/json (JSON tier) — body is compared using a SHA-256 hash:
      • Same body → cached response returned with X-Idempotent-Replayed: true.
      • Different body → 422 Unprocessable Entity (catches accidental key reuse with mutated payload).
    • All other content types (e.g. multipart file uploads) — key-only match: a retry with the same key returns 422 Unprocessable Entity, since the binary body cannot be hashed to confirm it matches the original. Use a new key for a new request.
  4. If a retry arrives while the first request is still being processed → 409 Conflict. Retry after the original completes.

Example

$curl -X POST https://api.ottimate.com/v1/invoices \
> -H "X-API-Key: YOUR_API_KEY" \
> -H "Authorization: Bearer YOUR_ACCESS_TOKEN" \
> -H "Idempotency-Key: 550e8400-e29b-41d4-a716-446655440000" \
> -H "Content-Type: application/json" \
> -d '{ "vendor_id": "...", "amount": 1234.56 }'

If the same request is retried with the same Idempotency-Key and body, the response is identical, no new invoice is created, and the response includes:

X-Idempotent-Replayed: true

Key Format

ConstraintValue
Length1–128 characters
Allowed charactersA–Z, a–z, 0–9, ., _, -, +, =, /
RecommendedUUIDv4 or ULID

Invalid keys are rejected with 400 Bad Request.

Scope and Lifetime

AttributeBehavior
Cache lifetime24 hours from the first response
ScopePer API key + HTTP method + path + idempotency key
Cached responsesOnly 2xx responses are cached. 4xx/5xx responses are not — retries are processed fresh.
API key rotationRotating your API key invalidates all cached entries scoped to the old key.
Because scope includes the path and method, the same Idempotency-Key value can be safely reused across different endpoints — they will not collide.

Response Codes

StatusMeaning
2xx + X-Idempotent-Replayed: trueReplay of a cached response. Side effects already happened on the original request.
208 Already ReportedThe original response was too large to cache (>64 KB) or was streamed. The original operation did succeed — fetch the current state via the corresponding GET endpoint.
400 Bad RequestMalformed Idempotency-Key header (length / charset).
409 ConflictA concurrent request with the same key is still being processed. Wait and retry.
422 Unprocessable EntitySame key was previously used with a different request body (JSON requests only).

Applicability

Idempotency-Key takes effect on all POST requests under /v1/*. Each endpoint that supports it lists Idempotency-Key in its parameter table — refer to the per-endpoint API reference.

The header is ignored (no caching) for:

  • Non-POST methods (GET, PATCH, PUT, DELETE — currently)
  • Requests without an API key

For multipart file uploads and other non-JSON content types, the server cannot verify the request body without loading the full upload into memory. A retry with the same key always returns 422 — use a new key for each new upload.