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-Afterand 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
- Debugging - tools for investigating issues
- FAQ
- Error Codes