GramClaw API
v1Drive your Telegram outreach from scripts, AI agents, or the Telegram MCP server: search messages, manage the CRM pipeline, set custom columns, and send messages, broadcasts, and campaigns. Create a key in Settings → API Keys.
Authentication
Every request needs a workspace API key as a Bearer token. Create one in Settings → API Keys — the full key ( gc_live_…) is shown once.
https://gramclaw.comAuthorization: Bearer gc_live_xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxBASE="https://gramclaw.com"
KEY="gc_live_…"
curl -s "$BASE/api/v1/me" -H "Authorization: Bearer $KEY"Heads up: API calls execute directly — there is no confirmation step (unlike the in-app AI). The key is the authorization; guard it like a password. Rate limit: 120 requests / minute per key, with X-RateLimit-* headers on every response. Errors return { "error": "…" } with a 4xx/5xx status.
Scopes: keys carry read (chats, messages, search, analytics), write (pipeline, columns, webhooks), and/or send (messages, broadcasts, campaigns) — choose them when creating the key. Send-type POSTs accept an Idempotency-Key header so retries never double-send.
Endpoints
/api/v1/me— Verify key & list accountsscope: readConfirms a key works and returns the workspace plus the connected accounts it can act on (with account ids for broadcasting).
{
"workspace_id": "cbf805da-…",
"key": { "name": "Claude MCP", "prefix": "gc_live_ab12cd34", "scopes": ["read","send"] },
"accounts": [
{ "id": "acc_…", "provider": "Telegram", "type": "MESSAGING", "name": "…" }
]
}/api/v1/chats— List conversationsscope: readThe workspace's conversations newest-first, served from GramClaw's own store (fast — no provider calls). Cursor-paginated; filter by account, pipeline stage, or column value.
| Field | Type | Notes |
|---|---|---|
| cursor | string | from previous next_cursor |
| limit | number | default 50, max 100 |
| account_id | string | |
| stage_key | string | only chats in this stage |
| column_id | string | with column_value: only matching chats |
| column_value | string |
curl -s "$BASE/api/v1/chats?stage_key=qualified&limit=20" \
-H "Authorization: Bearer $KEY"{
"chats": [{ "id": "…", "name": "Sarah K", "provider": "TELEGRAM",
"last_message_text": "…", "last_message_at": "…", "unread_count": 2 }],
"next_cursor": "bzoyMA", "has_more": true
}/api/v1/chats/{id}— Get one chatscope: readOne chat enriched with its pipeline stage and custom-column values.
{
"chat": { "id": "…", "name": "Sarah K", "stage_key": "qualified",
"columns": [{ "column_id": "…", "value": ["High"] }] }
}/api/v1/chats/{id}/messages— Read message historyscope: readA chat's messages, oldest-first within the page. Pass `before` (ISO timestamp) to page older messages; the response's next_before feeds the next call.
| Field | Type | Notes |
|---|---|---|
| limit | number | default 30, max 100 |
| before | string | ISO timestamp — messages older than this |
curl -s "$BASE/api/v1/chats/CHAT_ID/messages?limit=50" \
-H "Authorization: Bearer $KEY"{
"messages": [{ "id": "…", "text": "Hey!", "is_sender": false,
"timestamp": "2026-07-06T10:00:00Z", "attachments": [] }],
"source": "db", "next_before": "2026-07-01T08:00:00Z"
}/api/v1/chats/start— Start a new conversationscope: sendStart (or find) a DM with someone by phone, @username, or provider id — including people never messaged before. Optionally sends a first message. Supports Idempotency-Key.
| Field | Type | Notes |
|---|---|---|
| account_id* | string | account to send from (see /me) |
| identifier* | string | phone, @username, or provider id |
| provider | string | hint: TELEGRAM, WHATSAPP, … |
| text | string | optional first message |
curl -s "$BASE/api/v1/chats/start" \
-H "Authorization: Bearer $KEY" \
-H "Content-Type: application/json" \
-d '{"account_id":"acc_…","identifier":"@newlead","text":"Hi!"}'{ "chat": { "id": "…" } }/api/v1/contacts— List contactsscope: readThe workspace's contact cache (name + provider id per account). Cursor-paginated, searchable by name.
| Field | Type | Notes |
|---|---|---|
| cursor | string | |
| limit | number | default 100, max 200 |
| account_id | string | |
| q | string | name search |
{
"contacts": [{ "account_id": "…", "provider_id": "…", "name": "Sarah K" }],
"next_cursor": null, "has_more": false
}/api/v1/search— Search messages & emailSearch connected platforms by people, keywords, and date range. Returns matching excerpts plus the chats they came from — use a returned chat_id with the move / message endpoints.
| Field | Type | Notes |
|---|---|---|
| people | string[] | Person names |
| keywords | string[] | Topic keywords (not names) |
| time_after | string | ISO date lower bound |
| time_before | string | ISO date upper bound |
| account_types | "messaging" | "email" | "all" | Default all |
curl -s "$BASE/api/v1/search" \
-H "Authorization: Bearer $KEY" \
-H "Content-Type: application/json" \
-d '{"people":["Sarah"],"keywords":["invoice"]}'{
"match_count": 3,
"platforms_searched": ["Telegram", "Gmail"],
"chats": [{ "chat_id": "…", "chat_name": "Sarah", "provider": "Telegram" }],
"context": "### Sarah (Telegram) …"
}/api/v1/pipeline— Get pipelineThe workspace's pipeline stages and which chats sit in each stage. Chats not in placements are in the default 'new' stage.
{
"stages": [{ "key": "new", "label": "New", "terminal": false }, …],
"placements": [{ "chat_id": "…", "stage_key": "qualified" }]
}/api/v1/pipeline/move— Move a chat to a stageMove a chat into a pipeline stage.
| Field | Type | Notes |
|---|---|---|
| chat_id* | string | |
| stage_key* | string | from GET /api/v1/pipeline |
curl -s "$BASE/api/v1/pipeline/move" \
-H "Authorization: Bearer $KEY" \
-H "Content-Type: application/json" \
-d '{"chat_id":"…","stage_key":"qualified"}'{ "ok": true, "message": "Moved to **Qualified**." }/api/v1/columns— List custom columnsThe workspace's custom columns (tags) with ids, types, and allowed option values.
{
"columns": [
{ "id": "…", "name": "Priority", "type": "select",
"options": [{ "value": "High", "color": "#f87171" }] }
]
}/api/v1/columns/set— Set a column valueSet (or clear) a custom-column value on a chat. An empty value array clears it.
| Field | Type | Notes |
|---|---|---|
| column_id* | string | from GET /api/v1/columns |
| chat_id* | string | |
| value* | string[] | empty clears |
curl -s "$BASE/api/v1/columns/set" \
-H "Authorization: Bearer $KEY" \
-H "Content-Type: application/json" \
-d '{"column_id":"…","chat_id":"…","value":["High"]}'{ "ok": true, "message": "Set **Priority** = High." }/api/v1/messages— Send a messageSend a single message to an existing chat.
| Field | Type | Notes |
|---|---|---|
| chat_id* | string | |
| text* | string |
curl -s "$BASE/api/v1/messages" \
-H "Authorization: Bearer $KEY" \
-H "Content-Type: application/json" \
-d '{"chat_id":"…","text":"Hi there!"}'{ "ok": true, "message": "Message sent." }/api/v1/broadcast— Broadcast to an audienceSend one message to everyone in a pipeline stage or with a custom-column value. Supports {{name}} personalization. Capped at 30 recipients per call.
| Field | Type | Notes |
|---|---|---|
| account_id* | string | account to send from (see /me) |
| audience_type* | "stage" | "column" | |
| audience_ref* | string | stage_key, or column_id for column |
| column_value | string | required for column audiences |
| message_text* | string | may include {{name}} |
curl -s "$BASE/api/v1/broadcast" \
-H "Authorization: Bearer $KEY" \
-H "Content-Type: application/json" \
-d '{"account_id":"acc_…","audience_type":"stage",
"audience_ref":"qualified","message_text":"Hi {{name}}!"}'{ "ok": true, "message": "Broadcast sent to **12** recipients.",
"recipients": 12, "audience_total": 12, "capped": false }/api/v1/campaigns— Create a campaign (large sends)scope: sendThe API path for sends larger than broadcast's 30-recipient cap (max 5,000 contacts). GramClaw's background worker delivers every message — initial + optional follow-up steps — respecting per-account daily quotas. Supports Idempotency-Key. Also: GET /api/v1/campaigns lists campaigns; GET /api/v1/campaigns/{id} returns status + per-contact detail.
| Field | Type | Notes |
|---|---|---|
| name | string | |
| account_id | string | or account_pool: string[] to rotate accounts |
| message_text* | string | may include {{name}} |
| contacts* | array | [{ name?, identifier, chat_id? }] |
| steps | array | follow-ups: [{ branch, wait_hours, variants[] }] |
| daily_quota_per_account | number | default 30 |
curl -s "$BASE/api/v1/campaigns" \
-H "Authorization: Bearer $KEY" \
-H "Content-Type: application/json" \
-H "Idempotency-Key: launch-jul-06" \
-d '{"account_id":"acc_…","message_text":"Hi {{name}}!",
"contacts":[{"name":"Sarah","identifier":"@sarahk"}]}'{ "campaign": { "id": "…", "status": "queued" }, "queued": true }/api/v1/analytics— Campaign analyticsscope: readWorkspace campaign totals (sent, failed, replies, reply rate) plus the 50 most recent campaigns.
{
"totals": { "campaigns": 12, "sent": 452, "replies": 87, "reply_rate": 0.1925 },
"campaigns": [ … ]
}/api/v1/webhooks— Register a webhookscope: writeGet pushed events instead of polling: message.received, message.edited, message.deleted, pipeline.moved, campaign.replied. Deliveries are signed (X-GramClaw-Signature: sha256=HMAC_SHA256(secret, body)); the secret is returned once at creation. GET lists endpoints; PATCH /api/v1/webhooks/{id} updates url/events/active; DELETE removes. Max 10 per workspace; 20 consecutive failures auto-disable an endpoint.
| Field | Type | Notes |
|---|---|---|
| url* | string | your HTTPS endpoint |
| events | string[] | omit or ["*"] for all events |
curl -s "$BASE/api/v1/webhooks" \
-H "Authorization: Bearer $KEY" \
-H "Content-Type: application/json" \
-d '{"url":"https://example.com/hooks/gramclaw",
"events":["message.received","pipeline.moved"]}'{ "webhook": { "id": "…", "events": ["message.received","pipeline.moved"] },
"secret": "whsec_… ← shown once, signs every delivery" }Connect from Claude / Cursor (Telegram MCP)
Easiest — remote connector (a URL). In your MCP client, add a custom connector and paste your personal URL. Create a key in Settings → API Keys to get the full URL with your key. See the Telegram MCP overview for the tool list.
https://gramclaw.com/api/mcp?key=gc_live_…Alternative — local server (Cursor, or Claude Desktop config file):
{
"mcpServers": {
"gramclaw": {
"command": "npx",
"args": ["-y", "gramclaw-mcp"],
"env": {
"GRAMCLAW_API_KEY": "gc_live_…",
"GRAMCLAW_BASE_URL": "https://gramclaw.com"
}
}
}
}