Skip to main content

Documentation Index

Fetch the complete documentation index at: https://docs.gateway.connexease.com/llms.txt

Use this file to discover all available pages before exploring further.

Every error response from the Connexease Gateway follows the same JSON structure with a machine-readable code field. This lets you handle specific failure cases programmatically — pausing campaigns on BILL_001, retrying after the right delay on RATE_001, or skipping invalid recipients on GW_001. This page lists all error codes grouped by category, with example payloads and recommended actions for each.

Response Structure

All error responses use the same JSON format:
{
  "isSuccess": false,
  "errors": {
    "code": "AUTH_001",
    "group": "UNAUTHORIZED",
    "description": "API Key not found, invalid, or expired.",
    "params": {}
  }
}
isSuccess
boolean
Always false for errors.
errors.code
string
Unique error identifier. Use this for programmatic error handling.
errors.group
string
Error category (e.g. UNAUTHORIZED, PAYMENT_REQUIRED).
errors.description
string
Human-readable explanation of the error.
errors.params
object
Optional additional context. Present only on some errors (e.g. RATE_001).

HTTP Status Codes

CodeMeaning
400Malformed or incomplete request
401Authentication failure
402Insufficient account balance
403Permission denied
429Rate limit exceeded
500Server-side error
502Upstream Meta API failure

Authentication Errors (AUTH_*)

HTTP: 401 Unauthorized
{
  "isSuccess": false,
  "errors": {
    "code": "AUTH_001",
    "group": "UNAUTHORIZED",
    "description": "API Key not found, invalid, or expired."
  }
}
When: The token was not found in Redis cache or the Core Service. The key may be invalid, revoked, or expired.Resolution: Verify the key is active in Dashboard → API Keys. Create a new key if needed.
HTTP: 401 Unauthorized
{
  "isSuccess": false,
  "errors": {
    "code": "AUTH_002",
    "group": "UNAUTHORIZED",
    "description": "Missing Authorization header."
  }
}
When: The Authorization header is absent entirely.Resolution: Add Authorization: Bearer YOUR_API_KEY to every request.
HTTP: 401 Unauthorized
{
  "isSuccess": false,
  "errors": {
    "code": "AUTH_003",
    "group": "UNAUTHORIZED",
    "description": "Invalid token format. It must be 'Bearer <token>'."
  }
}
When: The header is present but the Bearer prefix (with a space) is missing. E.g. sending Authorization: YOUR_API_KEY instead of Authorization: Bearer YOUR_API_KEY.Resolution: Ensure the header is exactly in Bearer YOUR_API_KEY format.
HTTP: 500 Internal Server Error
{
  "isSuccess": false,
  "errors": {
    "code": "AUTH_004",
    "group": "INTERNAL_ERROR",
    "description": "An error occurred in the authentication service."
  }
}
When: Both Redis and the Core Service are unreachable.Resolution: Retry after a few seconds. If the error persists, contact support.
HTTP: 500 Internal Server Error
{
  "isSuccess": false,
  "errors": {
    "code": "AUTH_005",
    "group": "INTERNAL_ERROR",
    "description": "Authentication data is corrupted."
  }
}
When: The token was found but cannot be parsed (data integrity issue).Resolution: Contact support.

Webhook Errors (WH_*)

HTTP: 403 Forbidden
{
  "isSuccess": false,
  "errors": {
    "code": "WH_001",
    "group": "FORBIDDEN",
    "description": "Invalid verification token."
  }
}
When: The hub.verify_token value doesn’t match during the Meta webhook verification handshake.Resolution: Ensure the WEBHOOK_VERIFY_TOKEN config value matches exactly what you entered in Meta Business Manager.
HTTP: 401 Unauthorized
{
  "isSuccess": false,
  "errors": {
    "code": "WH_002",
    "group": "UNAUTHORIZED",
    "description": "Missing signature header."
  }
}
When: A POST /v1/wa/webhook request is missing the X-Hub-Signature-256 header.Resolution: This error only occurs on requests from Meta. Do not call this endpoint from your own code.
HTTP: 403 Forbidden
{
  "isSuccess": false,
  "errors": {
    "code": "WH_003",
    "group": "FORBIDDEN",
    "description": "Invalid signature."
  }
}
When: The signature header is present but the computed HMAC-SHA256 doesn’t match.Resolution: Verify that META_APP_SECRET in your config exactly matches the App Secret in Meta Business Manager → App Settings.

Rate Limit Error (RATE_001)

HTTP: 429 Too Many Requests
{
  "isSuccess": false,
  "errors": {
    "code": "RATE_001",
    "group": "TOO_MANY_REQUESTS",
    "description": "Rate limit exceeded. Please try again later.",
    "params": {
      "limit_type": "sec",
      "retry_after": "1s"
    }
  }
}
params Fields:
FieldValuesDescription
limit_type"sec", "min"Which window was exceeded
retry_after"1s", "60s"How long to wait before retrying
Resolution: Wait for the retry_after duration and retry, or use a queue system for high-volume operations.Error handling example:
async function sendWithRetry(payload, maxRetries = 3) {
  for (let attempt = 1; attempt <= maxRetries; attempt++) {
    const res = await fetch('https://api.gateway.connexease.com/v1/wa/message', {
      method: 'POST',
      headers: { 'Authorization': `Bearer ${API_KEY}`, 'Content-Type': 'application/json' },
      body: JSON.stringify(payload),
    });

    if (res.status !== 429) return res;

    const data = await res.json();
    const waitMs = parseInt(data.errors.params.retry_after) * 1000 * attempt;
    await new Promise(r => setTimeout(r, waitMs));
  }
  throw new Error('Max retries exceeded');
}

Billing Errors (BILL_*)

HTTP: 402 Payment Required
{
  "isSuccess": false,
  "errors": {
    "code": "BILL_001",
    "group": "PAYMENT_REQUIRED",
    "description": "Insufficient balance. Please top up your account to continue sending messages."
  }
}
When: Account balance is ≤ 0 at the time of the request, before forwarding to Meta.Resolution:
  1. Immediately pause any active campaigns.
  2. Go to Dashboard → Billing → Add Balance.
  3. Resume the campaign.
HTTP: 400 Bad Request
{
  "isSuccess": false,
  "errors": {
    "code": "BILL_002",
    "group": "BAD_REQUEST",
    "description": "API Key does not have an associated billing account. Please contact support."
  }
}
When: No billing account is associated with this API key.Resolution: Contact the Connexease support team.

WhatsApp Credentials Error (WABA_001)

HTTP: 401 Unauthorized
{
  "isSuccess": false,
  "errors": {
    "code": "WABA_001",
    "group": "UNAUTHORIZED",
    "description": "WABA credentials are missing or invalid. Please check your configuration."
  }
}
When: No WhatsApp Business API credentials (phone number ID + access token) were found for the app associated with your API key.Resolution: Verify in Dashboard → App Settings that your WhatsApp Business account is properly connected.

Security Error (SEC_001)

HTTP: 500 Internal Server Error
{
  "isSuccess": false,
  "errors": {
    "code": "SEC_001",
    "group": "INTERNAL_ERROR",
    "description": "Access token decryption failed. Please contact support."
  }
}
When: The WhatsApp access token could not be decrypted (encryption key mismatch).Resolution: Contact support.

Gateway / Upstream Error (GW_001)

HTTP: 502 Bad Gateway
{
  "isSuccess": false,
  "errors": {
    "code": "GW_001",
    "group": "UPSTREAM_ERROR",
    "description": "The phone number you are trying to reach is not registered on WhatsApp."
  }
}
When: All auth and billing checks passed, but the Meta API returned an error. The description field contains Meta’s original error message.Common Meta errors surfaced via GW_001:
SituationMeta Error MessageResolution
Unregistered recipient”not registered on WhatsApp”Verify the number is a WhatsApp user
24-hour window expired”outside the 24-hour window”Use a template message
Wrong template name/language”template with the name does not exist”Check template name and language code
Inaccessible media URL”media URL is not accessible”Verify the URL is publicly accessible
Resolution: Log the description field and skip the failing recipient.

Centralized Error Handling Pattern

async function sendMessage(payload) {
  const res = await fetch('https://api.gateway.connexease.com/v1/wa/message', {
    method: 'POST',
    headers: {
      'Authorization': `Bearer ${process.env.API_KEY}`,
      'Content-Type': 'application/json',
    },
    body: JSON.stringify(payload),
  });

  const data = await res.json();

  if (!data.isSuccess) {
    const { code, description, params } = data.errors;

    switch (code) {
      case 'BILL_001':
        await notifyTeam('Balance depleted — campaign paused');
        throw new Error('INSUFFICIENT_BALANCE');

      case 'RATE_001':
        const waitMs = parseInt(params.retry_after) * 1000;
        await sleep(waitMs);
        return sendMessage(payload); // retry

      case 'AUTH_001':
      case 'AUTH_002':
      case 'AUTH_003':
        throw new Error(`Auth error: ${description}`);

      case 'GW_001':
        // Meta error — log and skip this recipient
        logger.warn({ code, description, to: payload.to }, 'Meta API error');
        return null;

      default:
        logger.error({ code, description }, 'Unexpected error');
        throw new Error(`${code}: ${description}`);
    }
  }

  return data;
}
import requests, time, logging

def send_message(payload, api_key):
    res = requests.post(
        "https://api.gateway.connexease.com/v1/wa/message",
        headers={"Authorization": f"Bearer {api_key}", "Content-Type": "application/json"},
        json=payload,
    )
    data = res.json()

    if not data.get("isSuccess"):
        err = data["errors"]
        code = err["code"]

        if code == "BILL_001":
            raise Exception("INSUFFICIENT_BALANCE")
        elif code == "RATE_001":
            wait = int(err["params"]["retry_after"].replace("s", ""))
            time.sleep(wait)
            return send_message(payload, api_key)  # retry
        elif code == "GW_001":
            logging.warning(f"Meta error for {payload.get('to')}: {err['description']}")
            return None
        else:
            raise Exception(f"{code}: {err['description']}")

    return data