Common Issues#

Solutions to frequently encountered problems, organised by area. Each entry shows the symptom (including the actual error message where the API returns one), the likely cause, and the fix.

Authentication#

401: Authorization header missing or invalid#

Symptom:

{"error": "Authorization header missing or invalid. Include 'Authorization: Bearer YOUR_TOKEN' header."}

Cause: The request has no Authorization header, or it isn’t in Bearer format.

Fix: Send your API key as a bearer token:

curl https://api.outeract.com/ \
  -H "Authorization: Bearer YOUR_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{"query": "{ events(limit: 1) { id } }"}'

401: Invalid API key#

Symptom: {"error": "Invalid API key"}

Cause: The key doesn’t exist. It was mistyped, truncated, deleted, or rotated.

Fix: Copy the key again from the console (Settings → API Keys). Keys are shown once at creation; if you’ve lost the value, create a new key. If you recently rotated the key, make sure every deployment picked up the new value.

401: API key is disabled / API key has expired#

Symptom: {"error": "API key is disabled"} or {"error": "API key has expired"}

Cause: The key was toggled off in the console, or its expiresAt date has passed.

Fix: Re-enable the key or create a replacement. Check the key’s status in the console under Settings → API Keys.

API key validation is cached briefly on the server, so a just-revoked key may keep working for a short time, and a just-created key is picked up immediately.

Resource belongs to a different application#

Symptom: Queries return empty results, or Platform connection not found for current organisation style errors, even though the resource exists.

Cause: Each API key is scoped to exactly one application. Querying with a key from a different application won’t find the resource.

Fix: Use a key belonging to the application that owns the resource. The console shows which application each key belongs to under Settings → API Keys.

Sending Messages#

Recipient user not found or not in current application#

Symptom: sendMessage fails with Recipient user not found or not in current application.

Cause: The userId you passed belongs to a different application, or doesn’t exist.

Fix: Users are per-application. Query users in the same application (same API key) to confirm the ID.

Recipient user does not have a platform account#

Symptom: Recipient user does not have a whatsapp account (or another platform name).

Cause: You asked Outeract to send on a platform where the recipient has no identity. A user only gains a platform identity when they message you on that platform or when you create the identity explicitly.

Fix: Check the user’s identities:

query {
  user(id: "USER_ID") {
    id
    identities { id identityType externalId }
  }
}

Either send on a platform the user actually has, or omit the platform and let Outeract infer it from the recipient’s identities on enabled connections.

Platform connection is disabled#

Symptom: Platform connection <name> is disabled and cannot send messages

Cause: The connection’s enabled toggle is off. Disabled connections are also skipped during platform inference, which can surface as “no account” errors instead.

Fix: Re-enable the connection in the console (Integrations) or via updatePlatformConnection.

No connection found for this application#

Symptom: No whatsapp connection found for this application or No platform connections found for this application

Cause: The application has no connection for the requested platform (or none at all).

Fix: Create the platform connection first; see the platform guides. If you passed an explicit platformConnectionId, verify it with Platform connection not found or not in current application in mind: connections are per-application too.

Validation errors#

Symptom: Errors like Invalid user_id: <value>. Must be a valid UUID. or Identity <id> does not exist.

Cause: A malformed or stale ID in the mutation arguments.

Fix: All entity IDs are UUIDs. Re-query the entity to get the current ID rather than caching IDs across environments.

Message accepted but never delivered#

Symptom: sendMessage succeeds but the recipient never receives anything; the message event shows delivery_status.failed_at set.

Cause: Platform-side rejection, most commonly the 24-hour messaging window on WhatsApp/Instagram/Facebook (error_type: messaging_window_closed).

Fix: See OUTSIDE_MESSAGING_WINDOW and use a pre-approved template. Subscribe to system.message_delivery_failed webhooks to be notified of asynchronous failures.

Webhooks Not Arriving#

Event pattern doesn’t match#

Symptom: Deliveries never appear for certain event types, while others arrive fine.

Cause: Webhook subscriptions match eventTypes patterns against the event’s type using shell-style wildcards (fnmatch). message.* matches message.inbound and message.outbound; a bare message matches nothing. Events without an event type never match any pattern.

Fix: Open the subscription in the console (Settings → Webhooks) and check its patterns: widen them (message.*, or * for everything) or add the missing exact type. Also confirm the subscription is enabled; disabled subscriptions receive nothing.

Endpoint returns 4xx/5xx#

Symptom: Deliveries show failed status with your endpoint’s status code.

Cause: Your endpoint rejected the request. Outeract retries failed deliveries up to the subscription’s max attempts (default 5) on an exponential schedule (5 s, 5 m, 30 m, 2 h, 5 h after each failed attempt), then marks the delivery failed permanently.

Fix: Inspect the delivery records on the subscription’s detail page in the console. They include the response code, error message and attempt count for every attempt.

Return a 2xx quickly (do heavy processing asynchronously), and make sure the URL is publicly reachable over HTTPS with a valid certificate.

Subscription was automatically disabled#

Symptom: Deliveries stop entirely; the subscription shows as disabled in the console with a reason given, and its health status reads disabled.

Cause: Outeract auto-disables a subscription after 20 consecutive delivery failures with no successful delivery in the last 24 hours, typically an endpoint that has been down or rejecting requests for a sustained period. A system.webhook_endpoint_disabled event is emitted when this happens (subscribe to system.* on another endpoint to be notified).

Fix: Repair the endpoint, then re-enable the subscription in the console; the webhook detail page shows a re-enable banner. Re-enabling resets the failure counters.

Signature verification fails#

Symptom: Your endpoint rejects every delivery as having a bad signature.

Cause: Common verification bugs: signing the parsed/re-serialised JSON instead of the raw request body, dropping the sha256= prefix, or comparing against a base64 digest.

Fix: Outeract sends an HMAC-SHA256 of the raw request body, keyed with the subscription’s secret, in the X-Outeract-Signature header formatted as sha256=<hex digest>:

import hmac, hashlib

def verify(secret: str, raw_body: bytes, header: str) -> bool:
    expected = "sha256=" + hmac.new(
        secret.encode(), raw_body, hashlib.sha256
    ).hexdigest()
    return hmac.compare_digest(expected, header)

Use the subscription’s test action in the console to send a signed test delivery on demand; see Debugging.

Platform Connections#

OAuth token expired or revoked#

Symptom: Sends fail with platform errors like INVALID_TOKEN; the connection health check reports authentication failures.

Cause: The platform-side access token expired, or the user revoked access / changed their password on the platform.

Fix: Open the connection in the console and run a health check to confirm, then reconnect via OAuth from the same page.

Health check failures#

Symptom: A health check reports the connection as invalid, with one or more failing tests.

Cause: Each test pinpoints a different problem: credential validation, webhook registration, API quota. A failing webhook test usually means the platform-side webhook subscription was removed or points at a stale URL.

Fix: Fix the failing test’s area. For webhook registration issues, the connection’s Reconnect Webhook action in the console re-registers the webhook with the platform (for platforms that support auto-setup).

Invalid configuration on create/update#

Symptom: Invalid configuration: <field errors> when creating or updating a connection.

Cause: The connection’s config is validated against the platform’s config form schema: missing required fields (tokens, phone number IDs, etc.) or wrong types.

Fix: Query availablePlatforms to see each platform’s required config fields, or use the console’s connection form, which renders the same schema.

Rate Limiting#

429: Rate limit exceeded#

Symptom:

{"error": "Rate limit exceeded", "limit": 100, "window": "1 minute"}

with headers X-RateLimit-Limit, X-RateLimit-Remaining: 0, X-RateLimit-Reset, and Retry-After: 60.

Cause: The API key exceeded its per-minute request budget. Each key has its own rateLimitPerMinute (default 100, capped at 1000).

Fix:

  • Honour Retry-After and back off exponentially.
  • Batch reads: GraphQL lets you fetch related data in one request instead of N.
  • Raise the key’s rate limit in the console (Settings → API Keys) if your workload genuinely needs it.

Every successful response also carries the X-RateLimit-* headers, so you can throttle proactively before hitting 429s.

See Also#