Skip to main content

Secure API and Idempotency Mechanism

Idempotency-Key Header

What is it?

The Idempotency-Key is a unique, cryptographically generated value added to each API request header.
It ensures that retries of the same request are not executed more than once by the server.
This is especially important for operations that create or modify resources (e.g., payments, transactions, device records), where duplicate processing could lead to inconsistent data or unintended side effects.

Why is it used?

  • Prevents duplicates: If a client retries a request due to a timeout or network error, the server can detect the same Idempotency-Key and ignore duplicate executions.
  • Ensures consistency: Clients can safely retry requests without worrying about unintended multiple writes.
  • Improves reliability: Makes APIs more resilient against network instability.

Example Postman Pre-request script for API clients

// Use the body of the request as the payload.
const {Url} = require('postman-collection');
let payloadString = pm.request.body.raw;

if ( ! payloadString ) {
    let url = new Url(pm.environment.get("url") + pm.request.url.getPath());
    payloadString = "/api" + url.getPath();
    console.log( 'Payload: ' + payloadString );
} else {
    console.log( 'Payload: ' + JSON.stringify ( payloadString ) );
}

// Load the CryptoJS library required for the SHA256 hash operation.
eval(pm.globals.get("CryptoJS"));

// Calculate the SHA256 hash of the payload.
const hash = CryptoJS.SHA256(payloadString);

// Obtain the hexadecimal equivalent of the hash value.
const hashHex = hash.toString(CryptoJS.enc.Hex).toUpperCase();
console.log ( 'SHA256 Hash: ' + hashHex );

// Calculate the epoch millisecond of the current time.
const currentTime = new Date().getTime();
const currentTimeString = currentTime.toString();
console.log ( 'Epoch ms: ' + currentTimeString );

// Pad the length of currentTimeString to a multiple of 8.
const paddedCurrentTimeString = currentTimeString.padStart(Math.ceil(currentTimeString.length / 8) * 8, '0');
console.log( 'paddedCurrentTimeString: ' + paddedCurrentTimeString );

// Generate a 3DES encryption key and iv (initialization vector).
const key = CryptoJS.enc.Hex.parse( hashHex ); // Extract the 3DES key here.
const message = CryptoJS.enc.Utf8.parse(paddedCurrentTimeString);

const encrypted = CryptoJS.TripleDES.encrypt( paddedCurrentTimeString, key, {
    mode: CryptoJS.mode.ECB,
    padding: CryptoJS.pad.NoPadding
});

// Convert the result of the encryption to a Hex String.
const hexString = encrypted.ciphertext.toString().toUpperCase();
console.log ( 'Idempotency-Key: ' + hexString );

// Assign the result of the cryptographic operation to the “Idempotency-Key” header of the request.
pm.request.headers.add({ key: 'Idempotency-Key', value: hexString });

How is it calculated in the Pre-request Script?

The provided Postman pre-request script generates the Idempotency-Key as follows:
  1. Payload extraction
    • Uses the raw request body as the payload.
    • If the body is empty, falls back to the request URL path.
  2. SHA256 hashing
    • Computes a SHA256 hash of the payload string.
    • Converts the result into an uppercase hex string.
    • This ensures a deterministic and unique base for the key.
  3. Timestamp inclusion
    • Takes the current epoch time in milliseconds.
    • Pads the string to make its length a multiple of 8.
    • This adds uniqueness per request, even if the payload is identical.
  4. TripleDES encryption
    • Uses the SHA256 hash as the key for 3DES encryption.
    • Encrypts the padded timestamp in ECB mode without padding.
    • Produces an encrypted value as a hex string.
  5. Final header assignment
    • The resulting encrypted hex string becomes the Idempotency-Key.
    • Added to the request headers automatically:
      pm.request.headers.add({ key: 'Idempotency-Key', value: hexString });
      

Example Output (from console logs)

Payload: "{'screenName':'bienport.demo', 'password':'demo', 'rememberMe':true}"
SHA256 Hash: 65179C12FE83D08F....
Epoch ms: 1756141928597
paddedCurrentTimeString: 0001756141928597
Idempotency-Key: 1F11611E2483A1C360CE711B791A0711
POST https://apigw.bienport.com/api/auth/login

Summary

  • Purpose: Guarantees safe retries by preventing duplicate request execution.
  • Mechanism: Combines request payload + timestamp + encryption to create a unique key.
  • Usage: Always included in the request header automatically when running an API client.