Navigation

Idempotency

Use idempotency keys to safely retry POST requests without creating duplicate resources. This is critical for reliable integrations.

How It Works

Include an Idempotency-Key header with a unique value (UUID v4 recommended) on POST requests. If the same key is sent again within 24 hours, the API returns the original response instead of processing the request a second time.

This means you can safely retry failed requests due to network timeouts or connection errors without worrying about duplicate side effects.

POST /link/token/create
Content-Type: application/json
X-Client-ID: your_client_id
X-Client-Secret: bb_test_xxxxxxxx
Idempotency-Key: 550e8400-e29b-41d4-a716-446655440000

Generating Idempotency Keys

Use a UUID v4 for each unique operation. Do not reuse keys across different operations — each distinct action should have its own key.

Generate a UUID v4
import { randomUUID } from 'crypto';

const idempotencyKey = randomUUID();
// e.g., '550e8400-e29b-41d4-a716-446655440000'

Supported Endpoints

The following POST endpoints support idempotency keys:

EndpointDescription
POST /link/token/createCreate a new link token for the Connect flow.
POST /bills/sync/triggerTrigger a bill sync for a connected account.
POST /request-to-link/createCreate a biller-initiated link request.

Full Example

Here is a complete example showing how to use an idempotency key with retry logic:

Idempotent request with retry
import { randomUUID } from 'crypto';

async function createLinkToken(userId, billerId) {
  // Generate key once — reuse on retries for the SAME operation
  const idempotencyKey = randomUUID();

  for (let attempt = 0; attempt < 3; attempt++) {
    try {
      const response = await fetch(
        'https://sandbox.api.billerapi.com/link/token/create',
        {
          method: 'POST',
          headers: {
            'Content-Type': 'application/json',
            'X-Client-ID': process.env.BILLERAPI_CLIENT_ID,
            'X-Client-Secret': process.env.BILLERAPI_CLIENT_SECRET,
            'Idempotency-Key': idempotencyKey,
          },
          body: JSON.stringify({
            client_id: process.env.BILLERAPI_CLIENT_ID,
            client_user_id: userId,
            biller_id: billerId,
            consents: ['bills'],
          }),
        }
      );

      if (response.ok) {
        return await response.json();
      }

      // Don't retry client errors (except 429)
      if (response.status < 500 && response.status !== 429) {
        throw new Error(`Client error: ${response.status}`);
      }
    } catch (err) {
      if (attempt === 2) throw err;
    }

    // Exponential backoff before retry
    await new Promise(r => setTimeout(r, 1000 * Math.pow(2, attempt)));
  }
}

Important Notes

  • Idempotency keys expire after 24 hours. After that, the same key will be treated as a new request.
  • Use the same key for retries of the same operation. Generate a new key for each distinct operation.
  • If you send the same key with a different request body, the API returns a 409 Conflict error.
  • GET, PUT, and DELETE requests are naturally idempotent and do not require the header.

Related