intercom-api

Installation
SKILL.md

Intercom API (Write Operations)

Perform write operations on Intercom conversations and Help Center via REST API using curl.

Authentication

Store your Intercom Personal Access Token as an environment variable. The Intercom-Version: 2.11 header is required on all requests.

# Set your token (add to ~/.zshenv, ~/.bashrc, or ~/.zshrc)
export INTERCOM_ACCESS_TOKEN="your-token-here"

# Test authentication
curl -s https://api.intercom.io/me \
  -H "Authorization: Bearer $INTERCOM_ACCESS_TOKEN" \
  -H "Accept: application/json" \
  -H "Intercom-Version: 2.11" \
  | python3 -c "import sys,json; d=json.load(sys.stdin); print(d['name'], d['email'])"

Conversation Write Operations

All conversation actions use $CONVERSATION_ID. Find this from the Intercom URL or search API.

Reply to Conversation (Customer-Visible)

Sends a reply that the customer can see.

CONVERSATION_ID="12345678"
ADMIN_ID="YOUR_ADMIN_ID"

curl -s -X POST "https://api.intercom.io/conversations/$CONVERSATION_ID/reply" \
  -H "Authorization: Bearer $INTERCOM_ACCESS_TOKEN" \
  -H "Content-Type: application/json" \
  -H "Accept: application/json" \
  -H "Intercom-Version: 2.11" \
  -d "{
    \"message_type\": \"comment\",
    \"type\": \"admin\",
    \"admin_id\": \"$ADMIN_ID\",
    \"body\": \"Your reply text here.\"
  }" | python3 -c "import sys,json; d=json.load(sys.stdin); print('Reply sent:', d.get('id', d))"

Add Internal Note

Adds a note visible only to admins (not the customer). Notes support HTML.

CONVERSATION_ID="12345678"
ADMIN_ID="YOUR_ADMIN_ID"

curl -s -X POST "https://api.intercom.io/conversations/$CONVERSATION_ID/reply" \
  -H "Authorization: Bearer $INTERCOM_ACCESS_TOKEN" \
  -H "Content-Type: application/json" \
  -H "Accept: application/json" \
  -H "Intercom-Version: 2.11" \
  -d "{
    \"message_type\": \"note\",
    \"type\": \"admin\",
    \"admin_id\": \"$ADMIN_ID\",
    \"body\": \"<p>Investigation notes here.</p><p>Root cause: ...</p>\"
  }" | python3 -c "import sys,json; d=json.load(sys.stdin); print('Note added:', d.get('id', d))"

Assign Conversation

CONVERSATION_ID="12345678"
ADMIN_ID="YOUR_ADMIN_ID"        # Admin performing the assignment
ASSIGNEE_ID="TARGET_ADMIN_ID"   # Who to assign to

curl -s -X POST "https://api.intercom.io/conversations/$CONVERSATION_ID/parts" \
  -H "Authorization: Bearer $INTERCOM_ACCESS_TOKEN" \
  -H "Content-Type: application/json" \
  -H "Accept: application/json" \
  -H "Intercom-Version: 2.11" \
  -d "{
    \"message_type\": \"assignment\",
    \"type\": \"admin\",
    \"admin_id\": \"$ADMIN_ID\",
    \"assignee_id\": \"$ASSIGNEE_ID\",
    \"body\": \"Assigning to support team for follow-up.\"
  }" | python3 -c "import sys,json; d=json.load(sys.stdin); print('Assigned:', d.get('conversation_parts', {}).get('conversation_parts', [{}])[0].get('id', d))"

Close Conversation

CONVERSATION_ID="12345678"
ADMIN_ID="YOUR_ADMIN_ID"

curl -s -X POST "https://api.intercom.io/conversations/$CONVERSATION_ID/parts" \
  -H "Authorization: Bearer $INTERCOM_ACCESS_TOKEN" \
  -H "Content-Type: application/json" \
  -H "Accept: application/json" \
  -H "Intercom-Version: 2.11" \
  -d "{
    \"message_type\": \"close\",
    \"type\": \"admin\",
    \"admin_id\": \"$ADMIN_ID\"
  }" | python3 -c "import sys,json; d=json.load(sys.stdin); print('Closed. State:', d.get('state', d))"

Snooze Conversation

Snooze until a Unix timestamp.

CONVERSATION_ID="12345678"
ADMIN_ID="YOUR_ADMIN_ID"
# macOS: $(date -v+1d +%s)   Linux: $(date -d '+1 day' +%s)
SNOOZE_UNTIL=$(date -v+1d +%s)

curl -s -X POST "https://api.intercom.io/conversations/$CONVERSATION_ID/parts" \
  -H "Authorization: Bearer $INTERCOM_ACCESS_TOKEN" \
  -H "Content-Type: application/json" \
  -H "Accept: application/json" \
  -H "Intercom-Version: 2.11" \
  -d "{
    \"message_type\": \"snoozed\",
    \"type\": \"admin\",
    \"admin_id\": \"$ADMIN_ID\",
    \"snoozed_until\": $SNOOZE_UNTIL
  }" | python3 -c "import sys,json; d=json.load(sys.stdin); print('Snoozed until:', d.get('snoozed_until', d))"

Open (Reopen) Conversation

CONVERSATION_ID="12345678"
ADMIN_ID="YOUR_ADMIN_ID"

curl -s -X POST "https://api.intercom.io/conversations/$CONVERSATION_ID/parts" \
  -H "Authorization: Bearer $INTERCOM_ACCESS_TOKEN" \
  -H "Content-Type: application/json" \
  -H "Accept: application/json" \
  -H "Intercom-Version: 2.11" \
  -d "{
    \"message_type\": \"open\",
    \"type\": \"admin\",
    \"admin_id\": \"$ADMIN_ID\"
  }" | python3 -c "import sys,json; d=json.load(sys.stdin); print('Opened. State:', d.get('state', d))"

Tracker Tickets

Create tracker tickets to group related customer issues.

python3 - <<'PYEOF'
import subprocess, json, os

token = os.environ["INTERCOM_ACCESS_TOKEN"]

payload = json.dumps({
    "ticket_type_id": "YOUR_TICKET_TYPE_ID",
    "ticket_attributes": {
        "_default_title_": "Short bug title",
        "_default_description_": "Description of the issue and any linked references"
    },
    "contacts": []
})

result = subprocess.run([
    "curl", "-s", "-X", "POST", "https://api.intercom.io/tickets",
    "-H", f"Authorization: Bearer {token}",
    "-H", "Content-Type: application/json",
    "-H", "Accept: application/json",
    "-H", "Intercom-Version: 2.11",
    "-d", payload
], capture_output=True, text=True)

d = json.loads(result.stdout)
print("Ticket ID:", d.get("ticket_id"))
print("Internal ID:", d.get("id"))
PYEOF

Use python3 heredoc pattern (not inline curl) to avoid shell escaping issues with apostrophes in the description.

Note: Linking tracker tickets to conversations is UI-only. The REST API linking endpoints silently fail. Use the Intercom UI to link tickets to conversations.

Help Center Management

List All Articles

curl -s "https://api.intercom.io/articles" \
  -H "Authorization: Bearer $INTERCOM_ACCESS_TOKEN" \
  -H "Accept: application/json" \
  -H "Intercom-Version: 2.11" \
  | python3 -c "
import sys, json
d = json.load(sys.stdin)
for a in d.get('data', []):
    print(f\"{a['id']:10} {a.get('state',''):10} {a.get('title','')[:60]}\")
print(f'\nTotal: {len(d.get(\"data\", []))}')
"

Get Article Details

ARTICLE_ID="12345"

curl -s "https://api.intercom.io/articles/$ARTICLE_ID" \
  -H "Authorization: Bearer $INTERCOM_ACCESS_TOKEN" \
  -H "Accept: application/json" \
  -H "Intercom-Version: 2.11" \
  | python3 -c "
import sys, json
d = json.load(sys.stdin)
print('Title:', d.get('title'))
print('State:', d.get('state'))
print('URL:', d.get('url'))
print()
print('Body (truncated):')
print(d.get('body', '')[:500])
"

Create Article

AUTHOR_ID="YOUR_ADMIN_ID"
PARENT_ID="YOUR_COLLECTION_ID"

curl -s -X POST "https://api.intercom.io/articles" \
  -H "Authorization: Bearer $INTERCOM_ACCESS_TOKEN" \
  -H "Content-Type: application/json" \
  -H "Accept: application/json" \
  -H "Intercom-Version: 2.11" \
  -d "{
    \"title\": \"Article Title\",
    \"description\": \"Short description shown in search results\",
    \"body\": \"<h2>Overview</h2><p>Content here...</p>\",
    \"author_id\": $AUTHOR_ID,
    \"state\": \"draft\",
    \"parent_id\": $PARENT_ID,
    \"parent_type\": \"collection\"
  }" | python3 -c "import sys,json; d=json.load(sys.stdin); print('Created:', d.get('id'), d.get('title'), d.get('url'))"

States: "draft" (default) or "published". Parent types: "collection" or "section".

Update Article

ARTICLE_ID="12345"

curl -s -X PUT "https://api.intercom.io/articles/$ARTICLE_ID" \
  -H "Authorization: Bearer $INTERCOM_ACCESS_TOKEN" \
  -H "Content-Type: application/json" \
  -H "Accept: application/json" \
  -H "Intercom-Version: 2.11" \
  -d "{
    \"title\": \"Updated Title\",
    \"body\": \"<h2>Overview</h2><p>Updated content...</p>\",
    \"state\": \"published\"
  }" | python3 -c "import sys,json; d=json.load(sys.stdin); print('Updated:', d.get('id'), d.get('title'), d.get('state'))"

List Collections

curl -s "https://api.intercom.io/help_center/collections" \
  -H "Authorization: Bearer $INTERCOM_ACCESS_TOKEN" \
  -H "Accept: application/json" \
  -H "Intercom-Version: 2.11" \
  | python3 -c "
import sys, json
d = json.load(sys.stdin)
for c in d.get('data', []):
    print(f\"{c['id']:10} {c.get('name','')}\")
"

Help Center Editing Workflow

  1. List articles to find the one to edit
  2. Get article details to read current content
  3. Draft updated content - body must be valid HTML (<h2>, <p>, <ul><li>, <strong>, <a href>)
  4. Update as draft first ("state": "draft")
  5. Confirm with user before publishing
  6. Publish by updating "state": "published"

Error Handling

Status Meaning Fix
401 Invalid token Check INTERCOM_ACCESS_TOKEN is set and valid
403 Insufficient permissions Token needs write scopes
404 Resource not found Verify the ID
422 Invalid request body Check required fields and types
429 Rate limited Wait and retry; Intercom limit is 1000/min

Quick Reference

Operation Endpoint Method Key Field
Reply (visible) /conversations/{id}/reply POST message_type: "comment"
Internal note /conversations/{id}/reply POST message_type: "note"
Assign /conversations/{id}/parts POST message_type: "assignment"
Close /conversations/{id}/parts POST message_type: "close"
Snooze /conversations/{id}/parts POST message_type: "snoozed"
Open/reopen /conversations/{id}/parts POST message_type: "open"
List articles /articles GET
Get article /articles/{id} GET
Create article /articles POST state: "draft"/"published"
Update article /articles/{id} PUT
List collections /help_center/collections GET
Weekly Installs
1
GitHub Stars
26
First Seen
Apr 4, 2026