From intercom-pack
Diagnoses and fixes Intercom API errors by HTTP status code and type, with error shapes, causes, curl verification, and TypeScript handling examples. Use for failed requests or integrations.
npx claudepluginhub jeremylongshore/claude-code-plugins-plus-skills --plugin intercom-packThis skill is limited to using the following tools:
Quick reference for Intercom API errors by HTTP status code, with real error response shapes and proven solutions.
Executes Intercom incident runbook with bash triage scripts for API status, rate limits, status page checks, error decision tree, and mitigation for outages.
Diagnose and fix HubSpot API errors like 401, 403, 409 with real JSON responses, causes, and solutions including curl token checks and scope regeneration.
Diagnoses and fixes SalesLoft REST API v2 errors: 401 (tokens), 403 (scopes), 422 (validation), 429 (rate limits), 5xx. Includes OAuth troubleshooting, retry code, and curl examples.
Share bugs, ideas, or general feedback.
Quick reference for Intercom API errors by HTTP status code, with real error response shapes and proven solutions.
All Intercom errors return this structure:
{
"type": "error.list",
"request_id": "req_abc123",
"errors": [
{
"code": "unauthorized",
"message": "Access Token Invalid"
}
]
}
{
"type": "error.list",
"errors": [{ "code": "unauthorized", "message": "Access Token Invalid" }]
}
Causes:
Fix:
# Verify token works
curl -s https://api.intercom.io/me \
-H "Authorization: Bearer $INTERCOM_ACCESS_TOKEN" \
-H "Accept: application/json" | jq '.type'
# Should return "admin"
# If invalid, regenerate at:
# app.intercom.com > Settings > Developer Hub > Your App > Authentication
{
"type": "error.list",
"errors": [{ "code": "forbidden", "message": "You do not have permission to access this resource" }]
}
Causes:
Fix: Add the required OAuth scope in Developer Hub > OAuth Scopes.
{
"type": "error.list",
"errors": [{ "code": "not_found", "message": "User Not Found" }]
}
Causes:
user_id where contact_id is expected (or vice versa)Fix:
// Always check existence before operating
try {
const contact = await client.contacts.find({ contactId: id });
} catch (err) {
if (err instanceof IntercomError && err.statusCode === 404) {
console.log(`Contact ${id} not found, skipping`);
}
}
{
"type": "error.list",
"errors": [{ "code": "conflict", "message": "A contact matching those details already exists with id=abc123" }]
}
Causes:
external_id or emailFix:
// Search first, create if not found
async function findOrCreateContact(email: string, externalId: string) {
const existing = await client.contacts.search({
query: { field: "email", operator: "=", value: email },
});
if (existing.data.length > 0) {
return existing.data[0];
}
return client.contacts.create({
role: "user",
email,
externalId,
});
}
{
"type": "error.list",
"errors": [{ "code": "parameter_invalid", "message": "email is not a valid email address" }]
}
Causes:
Fix: Validate inputs before sending. Check the errors array for specifics.
{
"type": "error.list",
"errors": [{ "code": "rate_limit_exceeded", "message": "Rate limit exceeded" }]
}
Response headers:
X-RateLimit-Limit: 10000
X-RateLimit-Remaining: 0
X-RateLimit-Reset: 1711100060
Limits: 10,000 req/min per app, 25,000 req/min per workspace.
Fix:
import { IntercomError } from "intercom-client";
async function withBackoff<T>(fn: () => Promise<T>, maxRetries = 3): Promise<T> {
for (let attempt = 0; attempt <= maxRetries; attempt++) {
try {
return await fn();
} catch (err) {
if (err instanceof IntercomError && err.statusCode === 429) {
if (attempt === maxRetries) throw err;
const resetAt = err.headers?.["x-ratelimit-reset"];
const waitMs = resetAt
? (parseInt(resetAt) * 1000) - Date.now() + 1000
: 1000 * Math.pow(2, attempt);
console.log(`Rate limited, waiting ${waitMs}ms`);
await new Promise(r => setTimeout(r, Math.max(waitMs, 1000)));
} else {
throw err;
}
}
}
throw new Error("Unreachable");
}
Causes: Intercom-side issue, not your fault.
Fix:
# 1. Check Intercom status
curl -s https://status.intercom.com/api/v2/summary.json | jq '.status'
# 2. Retry with backoff (same pattern as 429)
# 3. If persistent, contact Intercom support with request_id
#!/bin/bash
TOKEN="${INTERCOM_ACCESS_TOKEN}"
echo "=== Intercom API Diagnostics ==="
# Test auth
echo -n "Auth: "
STATUS=$(curl -s -o /dev/null -w "%{http_code}" \
-H "Authorization: Bearer $TOKEN" \
https://api.intercom.io/me)
echo "$STATUS $([ "$STATUS" = "200" ] && echo "OK" || echo "FAIL")"
# Check rate limits
echo -n "Rate limit remaining: "
curl -s -D - -o /dev/null \
-H "Authorization: Bearer $TOKEN" \
https://api.intercom.io/me 2>/dev/null | grep -i x-ratelimit-remaining
# Intercom status
echo -n "Intercom status: "
curl -s https://status.intercom.com/api/v2/status.json | jq -r '.status.description'
| Error Code | HTTP | Retryable | Action |
|---|---|---|---|
unauthorized | 401 | No | Regenerate token |
forbidden | 403 | No | Add OAuth scope |
not_found | 404 | No | Verify resource ID |
conflict | 409 | No | Search before create |
parameter_invalid | 422 | No | Fix input data |
rate_limit_exceeded | 429 | Yes | Backoff and retry |
server_error | 500+ | Yes | Retry, check status page |
For comprehensive debugging, see intercom-debug-bundle.