Content · Web Development · PHP

Handling Idempotency Keys in APIs

Record an idempotency key and request fingerprint to replay an earlier operation result.

1 views Published Oct 17, 2026 Updated Oct 17, 2026 admin

Record an idempotency key and request fingerprint to replay an earlier operation result safely. The examples separate the essential operation from the conditions a production implementation must enforce.

What It Does


Record an idempotency key and request fingerprint to replay an earlier operation result safely.

Prerequisites


Use a dedicated development environment with test accounts and records. Separate authorization, validation and error handling from response formatting; never copy demonstration-only secrets into production.

Example 1: Core Behavior


The first example isolates the core operation so its result is easy to understand.

<?php
$key='req_'.bin2hex(random_bytes(8));
$fingerprint=hash('sha256',json_encode(['item'=>3,'quantity'=>2],JSON_THROW_ON_ERROR));
echo json_encode(compact('key','fingerprint'));

Example 2: Alternative or Failure Case


The second example demonstrates an alternative outcome, rule or failure condition.

<?php
$existing=['hash'=>'abc','response'=>['id'=>9]]; $incoming='wrong';
if (!hash_equals($existing['hash'],$incoming)) {http_response_code(409);echo 'Key reused with different payload';}

Practical Example: Applying the Rule


This practical workflow performs the relevant operation, with strict error checks. Configure the required transport or database driver before running it.

<?php
$pdo = new PDO('sqlite::memory:', null, null, [PDO::ATTR_ERRMODE => PDO::ERRMODE_EXCEPTION]);
$pdo->exec('CREATE TABLE idempotency (user_id INTEGER, request_key TEXT, payload_hash TEXT, response TEXT, PRIMARY KEY(user_id,request_key))');
$userId = 9; $key = 'req_123'; $payload = ['item' => 4];
$fingerprint = hash('sha256', json_encode($payload, JSON_THROW_ON_ERROR));
$pdo->beginTransaction();
try {
    $insert = $pdo->prepare('INSERT OR IGNORE INTO idempotency VALUES (?, ?, ?, ?)');
    $response = json_encode(['orderId' => 11], JSON_THROW_ON_ERROR);
    $insert->execute([$userId, $key, $fingerprint, $response]);
    $row = $pdo->prepare('SELECT payload_hash, response FROM idempotency WHERE user_id = ? AND request_key = ?');
    $row->execute([$userId, $key]); $existing = $row->fetch(PDO::FETCH_ASSOC);
    if (!hash_equals($existing['payload_hash'], $fingerprint)) throw new LogicException('Key reused with different payload');
    // Put the business write into this transaction before returning the response.
    $pdo->commit(); echo $existing['response'];
} catch (Throwable $e) { if ($pdo->inTransaction()) $pdo->rollBack(); throw $e; }

Important Behavior and Edge Cases


Key claims and business writes must be atomic to prevent concurrent duplicate charges or orders.

Comparison with Related Functions or Patterns


ApproachWhen it differs
Handling Idempotency Keys in APIsRecord an idempotency key and request fingerprint to replay an earlier operation result safely.
Related API or patternSafe HTTP methods and idempotency keys solve different retry problems.

Common Beginner Mistakes


MistakeCorrect approach
Checking a replay key outside the transaction that changes business stateKey claims and business writes must be atomic to prevent concurrent duplicate charges or orders.
Substituting a related API without checking its semanticsSafe HTTP methods and idempotency keys solve different retry problems.

Key Takeaways


  • Record an idempotency key and request fingerprint to replay an earlier operation result safely.
  • Key claims and business writes must be atomic to prevent concurrent duplicate charges or orders.
  • Safe HTTP methods and idempotency keys solve different retry problems.

Select this API or pattern based on its documented behavior and the trust boundaries in your own application, and test all external integrations against their actual deployments.

Share this resourceSend this page to someone who may find it useful.