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
- List articles to find the one to edit
- Get article details to read current content
- Draft updated content - body must be valid HTML (
<h2>,<p>,<ul><li>,<strong>,<a href>) - Update as draft first (
"state": "draft") - Confirm with user before publishing
- 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 |