Skip to main content
Conduit.im

Error Handling

The Conduit API uses consistent error responses with machine-readable error codes to help you handle failures gracefully.

Error Response Format

All API errors return a JSON object with the following structure:

{
  "error": {
    "message": "Invalid API key",
    "code": "API_KEY_INVALID",
    "details": {},
    "timestamp": "2026-03-09T12:00:00.000Z",
    "requestId": "req_abc123"
  }
}
FieldTypeDescription
messagestringA human-readable description of the error
codestringA machine-readable error code (e.g., API_KEY_INVALID)
detailsobject?Optional additional context (e.g., field-level validation errors)
timestampstringISO 8601 timestamp of when the error occurred
requestIdstringUnique request identifier for support and debugging

The requestId is also returned in the X-Request-Id response header. Include it when contacting support.

HTTP Status Codes

The API uses standard HTTP status codes to indicate the outcome of a request.

StatusMeaningRetryable
400Bad Request — Invalid parameters or malformed request bodyNo
401Unauthorized — Missing or invalid API keyNo
402Payment Required — Insufficient account balanceNo
403Forbidden — Valid key but insufficient permissionsNo
404Not Found — Resource or endpoint does not existNo
409Conflict — Resource already exists or state conflictNo
422Unprocessable Entity — Request understood but cannot be processedNo
429Too Many Requests — Rate limit or spending limit exceeded Yes
500Internal Server Error — Unexpected server-side failure Yes
503Service Unavailable — Upstream service temporarily down Yes
504Gateway Timeout — Request to upstream service timed out Yes

Error Codes

The code field provides a specific, machine-readable identifier you can use to programmatically handle errors.

Authentication & Authorization

CodeHTTPDescription
API_KEY_INVALID401The API key provided is not valid
API_KEY_EXPIRED401The API key has expired — generate a new one from your dashboard
AUTH_UNAUTHORIZED401Authentication is required but no valid credentials were provided
AUTH_FORBIDDEN403You do not have permission to perform this action

Validation

CodeHTTPDescription
VALIDATION_ERROR400Request body failed validation — check the details.fields object for specifics
BAD_REQUEST400The request is malformed or contains invalid parameters

Validation errors include a details.fields object mapping field names to error messages:

{
  "error": {
    "message": "Validation failed",
    "code": "VALIDATION_ERROR",
    "details": {
      "fields": {
        "model": "Required",
        "messages": "Expected array, received string"
      }
    },
    "timestamp": "2026-03-09T12:00:00.000Z",
    "requestId": "req_abc123"
  }
}

Billing

CodeHTTPDescription
BILLING_INSUFFICIENT_FUNDS402Your account balance is too low — add credits from your dashboard to continue

Rate Limiting

CodeHTTPDescription
RATE_LIMIT_EXCEEDED429Too many requests — wait and retry with exponential backoff
API_KEY_LIMIT_EXCEEDED429This API key's spending limit has been reached — increase it in your dashboard

Resource

CodeHTTPDescription
NOT_FOUND404The requested resource does not exist
CHAT_MODEL_NOT_FOUND404The specified model does not exist or is not available

Server

CodeHTTPDescription
INTERNAL_SERVER_ERROR500An unexpected error occurred on the server
SERVICE_UNAVAILABLE503An upstream service is temporarily unavailable
SERVICE_TIMEOUT504The request timed out — safe to retry

Handling Errors

We recommend implementing retry logic with exponential backoff for retryable errors (429, 500, 503, 504).

JavaScript / TypeScript

async function callConduit(messages, retries = 3) {
  for (let attempt = 0; attempt < retries; attempt++) {
    const res = await fetch("https://api.conduit.im/v1/chat/completions", {
      method: "POST",
      headers: {
        "Authorization": `Bearer ${API_KEY}`,
        "Content-Type": "application/json",
      },
      body: JSON.stringify({ model: "gpt-4", messages }),
    });

    if (res.ok) return await res.json();

    const { error } = await res.json();
    console.error(`[${error.code}] ${error.message} (request: ${error.requestId})`);

    // Don't retry client errors (except rate limits)
    if (res.status < 500 && res.status !== 429) {
      throw new Error(error.message);
    }

    // Exponential backoff: 1s, 2s, 4s
    await new Promise((r) => setTimeout(r, 1000 * 2 ** attempt));
  }
  throw new Error("Max retries exceeded");
}

Python

import time, requests

def call_conduit(messages, retries=3):
    for attempt in range(retries):
        res = requests.post(
            "https://api.conduit.im/v1/chat/completions",
            headers={
                "Authorization": f"Bearer {API_KEY}",
                "Content-Type": "application/json",
            },
            json={"model": "gpt-4", "messages": messages},
        )

        if res.ok:
            return res.json()

        error = res.json()["error"]
        print(f"[{error['code']}] {error['message']} (request: {error['requestId']})")

        # Don't retry client errors (except rate limits)
        if res.status_code < 500 and res.status_code != 429:
            raise Exception(error["message"])

        # Exponential backoff: 1s, 2s, 4s
        time.sleep(2 ** attempt)

    raise Exception("Max retries exceeded")
Important: Never retry 401 or 402 errors automatically. These require user action — check your API key or add funds to your account.

Next Steps