BitelioBitelio

Error Codes

Every error code the Bitelio API can return, what it means, and how to fix it

Overview

Bitelio API errors follow one consistent shape, designed so you can pinpoint the problem fast. Each error carries:

  • A machine-readable error code your code can branch on
  • A human-readable message describing the failure
  • A suggestion pointing at the likely fix
  • A request ID for debugging and support conversations
  • Field-level validation details where they apply

HTTP Status Codes

200 OK

The request went through.

201 Created

The resource was created.

400 Bad Request

Something is wrong with the request format or its parameters — the error details say what.

401 Unauthorized

Authentication is missing or didn't succeed. Double-check your API key.

402 Payment Required

A billing cap was hit, or the operation needs a higher plan. Accompanies BILLING_LIMIT_EXCEEDED and UPGRADE_REQUIRED.

403 Forbidden

You're not allowed to touch this resource — review permissions and project status. Also used when the account's email still needs verifying (EMAIL_VERIFICATION_REQUIRED) or the project was disabled (PROJECT_DISABLED).

404 Not Found

There's no resource with that ID. Confirm the ID is right.

409 Conflict

The request clashes with existing state — e.g. creating a contact whose email is already registered, or renaming to an email that's taken. Accompanies CONFLICT.

422 Unprocessable Entity

Validation rejected the request. The errors array lists the offending fields.

429 Too Many Requests

You've gone over a rate limit. Back off before retrying, or move to a higher plan.

500 Internal Server Error

Something broke on our end. Reach out to support with the request ID.

Error Response Format

Every error uses this one structure:

{
  "success": false,
  "error": {
    "code": "VALIDATION_ERROR",
    "message": "Request validation failed",
    "statusCode": 422,
    "requestId": "f47ac10b-58cc-4372-a567-0e02b2c3d479",
    "errors": [
      {
        "field": "email",
        "message": "Invalid email",
        "code": "invalid_string"
      }
    ],
    "suggestion": "One or more fields have incorrect types. Check that strings are quoted, numbers are unquoted, and booleans are true/false."
  },
  "timestamp": "2025-11-30T10:30:00.000Z"
}

Response Fields

FieldTypeDescription
successbooleanOn errors this is always false
error.codestringMachine-readable identifier (catalogued below)
error.messagestringPlain-language account of what failed
error.statusCodenumberThe HTTP status
error.requestIdstringPer-request identifier for debugging
error.errorsarrayPer-field breakdown (validation failures only)
error.detailsobjectExtra context, when available (optional)
error.suggestionstringA pointer toward the fix (optional)
timestampstringWhen the error happened, as ISO 8601

Error Codes Reference

The code field is present on every error so you can handle them programmatically. The complete set:

Authentication & Authorization

CodeStatusDescription
UNAUTHORIZED401Authentication failed for an unspecified reason
INVALID_CREDENTIALS401The login details don't match
MISSING_AUTH401No usable Authorization header on the request
INVALID_API_KEY401That API key doesn't exist or isn't valid
REVOKED_API_KEY401That key was valid and has been revoked — issue a new one
EXPIRED_API_KEY401That key passed its expiry date — issue a new one
FORBIDDEN403This action isn't permitted
PROJECT_ACCESS_DENIED403You don't have access to this project
PROJECT_DISABLED403The project is currently disabled
EMAIL_VERIFICATION_REQUIRED403Verify the account's email address before doing this

Validation & Input Errors

CodeStatusDescription
BAD_REQUEST400Generic problem with the request
VALIDATION_ERROR422Validation rejected the request (field errors attached)
INVALID_EMAIL422The email address isn't well-formed
INVALID_REQUEST_BODY400The body couldn't be parsed
MISSING_REQUIRED_FIELD422A required field wasn't supplied

Resource Errors

CodeStatusDescription
RESOURCE_NOT_FOUND404No resource matches (generic)
CONTACT_NOT_FOUND404No such contact
TEMPLATE_NOT_FOUND404No such template
CAMPAIGN_NOT_FOUND404No such campaign
WORKFLOW_NOT_FOUND404No such workflow
CONFLICT409Clashes with existing state (e.g. a duplicate)

Rate Limiting & Billing

CodeStatusDescription
RATE_LIMIT_EXCEEDED429Request rate is too high
BILLING_LIMIT_EXCEEDED402A billing cap was reached
UPGRADE_REQUIRED402The feature needs a higher plan

Server Errors

CodeStatusDescription
INTERNAL_SERVER_ERROR500Unexpected failure on our side
DATABASE_ERROR500A database operation didn't complete
EXTERNAL_SERVICE_ERROR500A downstream service was unreachable

Common Error Examples

Authentication Errors

Invalid API Key

{
  "success": false,
  "error": {
    "code": "INVALID_API_KEY",
    "message": "Invalid secret API key. This endpoint requires a secret key (sk_*), not a public key.",
    "statusCode": 401,
    "requestId": "abc-123",
    "suggestion": "Verify your API key is correct and starts with \"sk_\" for secret keys or \"pk_\" for public keys."
  },
  "timestamp": "2025-11-30T10:30:00.000Z"
}

Solution: Confirm the key itself and its type — endpoints that need a secret key expect a sk_ prefix, while event tracking uses pk_ keys.

Missing Authorization Header

{
  "success": false,
  "error": {
    "code": "MISSING_AUTH",
    "message": "Authorization header is required",
    "statusCode": 401,
    "requestId": "abc-123",
    "suggestion": "Include an Authorization header with format: \"Authorization: Bearer YOUR_API_KEY\""
  },
  "timestamp": "2025-11-30T10:30:00.000Z"
}

Solution: Send your key as a Bearer token in the Authorization header.

Validation Errors

Invalid Email Format

{
  "success": false,
  "error": {
    "code": "VALIDATION_ERROR",
    "message": "Request validation failed",
    "statusCode": 422,
    "requestId": "abc-123",
    "errors": [
      {
        "field": "email",
        "message": "Invalid email",
        "code": "invalid_string"
      }
    ],
    "suggestion": "One or more fields have incorrect types. Check that strings are quoted, numbers are unquoted, and booleans are true/false."
  },
  "timestamp": "2025-11-30T10:30:00.000Z"
}

Solution: Send a well-formed email address. Look at the errors array to see exactly which fields were rejected.

Missing Required Fields

{
  "success": false,
  "error": {
    "code": "VALIDATION_ERROR",
    "message": "Request validation failed",
    "statusCode": 422,
    "requestId": "abc-123",
    "errors": [
      {
        "field": "event",
        "message": "Required",
        "code": "invalid_type"
      },
      {
        "field": "email",
        "message": "Required",
        "code": "invalid_type"
      }
    ],
    "suggestion": "Required fields are missing. Ensure all required fields are included in your request."
  },
  "timestamp": "2025-11-30T10:30:00.000Z"
}

Solution: Add every required field to the request body.

Resource Errors

Template Not Found

{
  "success": false,
  "error": {
    "code": "TEMPLATE_NOT_FOUND",
    "message": "Template with ID \"tpl_abc123\" was not found",
    "statusCode": 404,
    "requestId": "abc-123",
    "details": {
      "resource": "Template",
      "id": "tpl_abc123"
    },
    "suggestion": "Ensure the template ID is correct and belongs to your project. You can list available templates via the API."
  },
  "timestamp": "2025-11-30T10:30:00.000Z"
}

Solution: Make sure the template ID exists and lives in your project.

Rate Limiting

Rate Limit Exceeded

{
  "success": false,
  "error": {
    "code": "RATE_LIMIT_EXCEEDED",
    "message": "Rate limit exceeded. Please try again later.",
    "statusCode": 429,
    "requestId": "abc-123",
    "suggestion": "You have exceeded the rate limit. Wait a moment before retrying, or upgrade your plan."
  },
  "timestamp": "2025-11-30T10:30:00.000Z"
}

Solution: Add retry logic with exponential backoff. If you routinely hit the ceiling, a plan upgrade raises it.

Success Response Format

When a request succeeds, the response comes back as success: true with a data object:

{
  "success": true,
  "data": {
    "contact": "cnt_abc123",
    "event": "evt_xyz789",
    "timestamp": "2025-11-30T10:30:00.000Z"
  }
}

Response Fields

FieldTypeDescription
successbooleanOn success this is always true
dataobjectEndpoint-specific payload

Handling Errors in Your Code

JavaScript/TypeScript Example

try {
  const response = await fetch('https://api.bitelio.com/v1/track', {
    method: 'POST',
    headers: {
      'Authorization': `Bearer ${publicKey}`,
      'Content-Type': 'application/json'
    },
    body: JSON.stringify({
      event: 'purchase',
      email: 'user@example.com'
    })
  });

  const data = await response.json();

  if (!data.success) {
    // Something went wrong
    console.error(`Error [${data.error.code}]:`, data.error.message);

    // Surface the API's suggested fix
    if (data.error.suggestion) {
      console.log('Suggestion:', data.error.suggestion);
    }

    // Keep the request ID around for support
    console.log('Request ID:', data.error.requestId);

    // Branch on the specific code
    switch (data.error.code) {
      case 'VALIDATION_ERROR':
        // Print each field that failed
        data.error.errors?.forEach(err => {
          console.log(`${err.field}: ${err.message}`);
        });
        break;
      case 'INVALID_API_KEY':
        // Ask the user to re-check their key
        break;
      case 'REVOKED_API_KEY':
      case 'EXPIRED_API_KEY':
        // The key WAS valid: rotate it rather than asking anyone to re-check a typo
        break;
      case 'RATE_LIMIT_EXCEEDED':
        // Retry later with backoff
        break;
    }

    return;
  }

  // Success path
  console.log('Event tracked:', data.data);
} catch (error) {
  console.error('Network error:', error);
}

Python Example

import requests

response = requests.post(
    'https://api.bitelio.com/v1/track',
    headers={
        'Authorization': f'Bearer {public_key}',
        'Content-Type': 'application/json'
    },
    json={
        'event': 'purchase',
        'email': 'user@example.com'
    }
)

data = response.json()

if not data.get('success'):
    error = data['error']
    print(f"Error [{error['code']}]: {error['message']}")

    # Surface the suggested fix
    if 'suggestion' in error:
        print(f"Suggestion: {error['suggestion']}")

    # Keep the request ID around
    print(f"Request ID: {error['requestId']}")

    # Print field-level failures
    if error['code'] == 'VALIDATION_ERROR':
        for err in error.get('errors', []):
            print(f"{err['field']}: {err['message']}")
else:
    print(f"Event tracked: {data['data']}")

Troubleshooting Guide

Using Request IDs

Each error ships with a requestId that follows the request across our whole stack. That makes it valuable in two directions:

For Developers:

  • The ID is stamped on every log line for that request
  • Grep your logs by ID and every related entry surfaces at once
  • Follow one request across API → Database → Queue → Worker

For Support:

  1. Paste the request ID into your message
  2. Explain what you were attempting
  3. Attach the complete error response when you can

Example: Given the request ID f47ac10b-58cc-4372-a567-0e02b2c3d479, a log search on our side reveals:

  • The request body exactly as it arrived
  • The database queries that ran
  • Any background jobs it spawned
  • The full stack trace, if one exists

That means we can usually diagnose the problem straight away, without a back-and-forth asking you for more detail.

How to Find Request IDs

The request ID shows up in three places:

  • Error responses: the error.requestId field
  • Response headers: the X-Request-ID header (present on successes too)
  • Your application logs: write the header into your own logs so you can correlate
// Capture the request ID in your own logging
const response = await fetch('https://api.bitelio.com/v1/send', {
  // ... your request
});

const requestId = response.headers.get('X-Request-ID');
console.log('Request ID:', requestId);  // Store it for correlation

const data = await response.json();
if (!data.success) {
  console.error('Error:', data.error.message);
  console.error('Request ID:', data.error.requestId);  // Matches the header
}

Common Issues and Solutions

Best Practices

  1. Inspect success first, before touching the rest of the response
  2. Record request IDs so debugging and support requests go faster
  3. Fail gracefully, translating errors into messages your users understand
  4. Retry transient failures using exponential backoff
  5. Watch your error rates so problems surface early
  6. Branch on error codes, not just HTTP statuses, in your handling logic

Getting Help

Still stuck? Work through this list:

  1. Start with the suggestion field in the error itself
  2. Compare your request against the API Reference
  3. Look up your exact error code in these docs
  4. Write to support and include your request ID
  5. Ask the community — other developers have often hit the same thing