Skip to main content
The Bota API supports idempotency for safely retrying requests without performing the same operation twice. This is critical for operations that create resources or trigger processing jobs.

How It Works

Include an Idempotency-Key header with a unique value for each distinct operation:
curl -X POST https://api.bota.dev/v1/recordings \
  -H "Authorization: Bearer sk_live_..." \
  -H "Idempotency-Key: rec_create_user123_1704067200" \
  -H "Content-Type: application/json" \
  -d '{
    "end_user_id": "eu_abc123",
    "device_id": "dev_xyz789"
  }'
If you send the same request with the same idempotency key:
  • First request — Creates the resource and returns the response
  • Subsequent requests — Returns the cached response from the first request

Idempotency Key Requirements

RequirementDetails
FormatString, 1-255 characters
CharactersAlphanumeric, hyphens, underscores
UniquenessMust be unique per operation per project
TTLKeys are stored for 24 hours
# Pattern: {operation}_{entity}_{unique_id}_{timestamp}

rec_create_user123_1704067200
txn_start_rec456_1704067200
upload_complete_up789_1704067200
Using the same idempotency key for different request bodies will return an error. The key is tied to both the endpoint and the original request payload.

Supported Endpoints

Idempotency keys are supported on all POST endpoints that create resources or trigger jobs:
EndpointUse Case
POST /end-usersCreating end users
POST /devicesRegistering devices
POST /devices/:id/bindBinding devices to users
POST /recordingsCreating recordings
POST /uploads/:id/completeCompleting uploads
POST /transcriptionsStarting transcription jobs
POST /summariesStarting summarization jobs
POST /webhooksCreating webhook endpoints

Response Behavior

Successful Replay

When replaying a previously successful request:
{
  "id": "rec_abc123",
  "status": "created",
  "created_at": "2025-01-15T10:00:00Z"
}
The response includes the original resource, and no duplicate is created.

Error Replay

If the original request failed with a client error (4xx), the error is returned on replay. Server errors (5xx) are not cached — you can safely retry with the same key.

Key Conflict

If you reuse a key with a different request body:
{
  "error": {
    "code": "idempotency_key_conflict",
    "message": "Idempotency key was used with different request parameters",
    "param": "Idempotency-Key"
  }
}

Implementation Example

const crypto = require('crypto');

async function createRecordingIdempotent(endUserId, deviceId) {
  // Generate a unique key for this operation
  const idempotencyKey = `rec_create_${endUserId}_${Date.now()}`;

  const response = await fetch('https://api.bota.dev/v1/recordings', {
    method: 'POST',
    headers: {
      'Authorization': `Bearer ${process.env.BOTA_API_KEY}`,
      'Content-Type': 'application/json',
      'Idempotency-Key': idempotencyKey,
    },
    body: JSON.stringify({
      end_user_id: endUserId,
      device_id: deviceId,
    }),
  });

  return response.json();
}

// Safe to retry on network errors
async function createRecordingWithRetry(endUserId, deviceId, maxRetries = 3) {
  const idempotencyKey = `rec_create_${endUserId}_${Date.now()}`;

  for (let attempt = 1; attempt <= maxRetries; attempt++) {
    try {
      const response = await fetch('https://api.bota.dev/v1/recordings', {
        method: 'POST',
        headers: {
          'Authorization': `Bearer ${process.env.BOTA_API_KEY}`,
          'Content-Type': 'application/json',
          'Idempotency-Key': idempotencyKey,
        },
        body: JSON.stringify({
          end_user_id: endUserId,
          device_id: deviceId,
        }),
      });

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

      // Don't retry client errors
      if (response.status < 500) {
        throw new Error(`Client error: ${response.status}`);
      }
    } catch (error) {
      if (attempt === maxRetries) throw error;
      await new Promise(r => setTimeout(r, 1000 * attempt));
    }
  }
}

Best Practices

Always generate idempotency keys on the client before making the request. This ensures the same key is used across retries.
Include relevant identifiers in the key (user ID, timestamp) to make debugging easier and prevent accidental collisions.
Each distinct operation should have its own idempotency key. Reusing keys across different operations will cause conflicts.
For payment-like operations (e.g., triggering transcription jobs), store the idempotency key in your database so you can retry with the exact same key if needed.