API pipeline: Create, configure, start, stop, measure and delete a Telegram campaign of any kind

Index: API pipelines — index

Goal: create, configure, start, stop, measure and delete a Telegram campaign of any kind. A campaign is a card (card_type: "campaign") that does one job for a project in Telegram, on your oracles and in groups. All kinds share one card, one set of routes and one lifecycle; kind is chosen at create and cannot change.

Kinds

kind What it does Needs to start Ends Pipeline
mtproto_radar (default) Listens to groups for messages matching your keywords; matches can go to an oracle for a first message Pro project; outreach on: oracles + agenda; auto: outreach + 5 canonical matches When stopped API pipeline: Listen to Telegram groups for people who need you: create and tune a radar, work its matches and make first contact (draft, send, auto outreach)
mtproto_ai_scout AI reads groups in batches, posts an overview to a channel, can hand picks to a radar Pro project, agenda, oracles, groups When stopped API pipeline: Have AI read groups in batches, post an overview to your channel and hand picks to a radar
mtproto_announcements Posts your posts into groups at a pace set by their traffic Pro project, groups, oracles, posts, agenda When stopped API pipeline: Post your posts into groups at a pace set by their traffic and follow what was sent and deleted
mtproto_join_chats / mtproto_leave_chats Your oracles join or leave a list of groups within Telegram limits Pro project, groups, oracles Completed when every oracle walked the list API pipeline: Have your oracles join or leave a list of Telegram groups within Telegram limits
mtproto_reactions Your oracles react to fresh messages Pro project, oracles, at least 1 reaction; groups optional When stopped API pipeline: Have your oracles react to fresh messages in groups at a chosen pace

Groups for any kind: API pipeline: Submit your Telegram groups, find groups by keyword, place or rubric, vet them and attach them to a campaign

Steps

1. Create (always Paused).

POST /v0/my/campaigns
Idempotency-Key: camp-join-phuket-1
{"title": "Join Phuket chats", "kind": "mtproto_join_chats",
 "project_nonce": "<Pro project>", "tg_groups": ["<preset nonce>"], "oracles": ["<oracle nonce>"]}
→ {"nonce": "470360000000000001", "card_type": "campaign", "kind": "mtproto_join_chats",
   "status": "Paused", "is_active": false,
   "telegram_groups_list": ["<preset nonce>"], "oracles_list": ["<oracle nonce>"],
   "lists": {"telegram_groups": [{…tile…}], "oracles": [{…}], "posts": []}, …}

2. Configure. PATCH /v0/my/campaigns/{nonce} with any create field; a slot in the body replaces the whole list. An Active radar or AI scout picks up keyword, exclude, group, project, auto and batch changes while it runs.

3. Start.

POST /v0/my/campaigns/470360000000000001/start
→ {"success": true, "status": "Active", "is_active": true}

Each failed check is 400 with the reason: assign this campaign to a project before activating, assigned project not found, project needs an active Pro membership to run campaigns, assign telegram groups before activating, assign oracles before activating, assign posts before activating, announcements require an agenda assigned: …, assign at least one reaction before activating, ai scout requires an agenda assigned.

4. Stop. POST …/stop → Paused (a radar keeps its config and matches). A 400 means the stop did not go through: call stop again.

5. Measure.

GET /v0/my/campaigns/{nonce}/performance
→ {"totals": {"sent": 40, "deleted": 3, "replied": 5, "reacted": 0, "groups": 25, "oracles": 1,
              "joined": 0, "join_pending": 0, "already_member": 0, …, "first_at": "…", "last_at": "…"},
   "timeline": [{"day": "2026-10-08", "sent": 0, "joined": 31, "reacted": 40, …}],
   "groups": [{"username": "example_group", "sent": 3, "deleted": 2, "replied": 0, "join_status": "already_member", …}],
   "join": {"member": 30, "pending": 4, "skipped": 2, "remaining": 0, "oracles": [{…, "flooded_until": null}]}}

GET /v0/my/campaigns/{nonce}/sends?page=1&limit=50
→ {"rows": [{"username": "example_group", "message_id": 17552, "oracle": "…", "post": "…",
             "sent_at": "…", "deleted_at": null, "replied_at": "…", "replies": 2}], "total": 40, "has_more": true, …}

Radar results are matches and inbox rooms, not sends. Landing visits by campaign: GET /v0/my/console/traffic/campaign?campaign=. Cabi.Chat Inbox — Leads

6. Delete. Stop it first, then DELETE /v0/my/campaigns/{nonce}.

Statuses: Active, Paused, Completed, Cancelled, Failed. When the project loses Pro, its active campaigns are paused.

One oracle's activity

What one oracle did across all campaigns (owner only, 404 otherwise):

Membership states in these reports: joined, join_pending (join request waits for the admins), join_banned, join_dead (group gone), join_skipped, join_flood (Telegram asked to wait), join_limit (the account hit a Telegram join limit), already_member, left, leave_failed, not_member.

Behind

Rules (who may do what)

Action Needs
GET /{nonce} read
PATCH, matches/evict, matches/sweep, start, stop write
Anchoring to a project (project_nonce) the campaign owner owns the project or holds x on it
DELETE, performance, sends, matches/{post}/draft, matches/{post}/outreach owner only

GET /v0/my/campaigns lists only campaigns you own. Share one by a link (rights, grant_ttl, who may claim): index, «Sharing by links»; when a w grant ends, the campaign is paused unless another live w grant holds it. Cabi.Chat Graph — Card Policies

API surface

Endpoint Purpose FE AI / oracle
GET /v0/my/campaigns Own campaigns as tiles + total (limit, offset, archived) yes yes
POST /v0/my/campaigns Create any kind, Paused yes yes
GET /v0/my/campaigns/{nonce} Full card: kind, status, slots, its workspaces yes yes
PATCH /v0/my/campaigns/{nonce} Edit config and slots yes yes
DELETE /v0/my/campaigns/{nonce} Delete (owner) yes rarely
POST /v0/my/campaigns/{nonce}/start, /stop Validate and start; pause yes yes
GET /v0/my/campaigns/{nonce}/performance Totals, timeline, per group, join plan yes yes, reporting
GET /v0/my/campaigns/{nonce}/sends Each sent message and its fate (page, limit) yes yes
POST /v0/my/campaigns/{nonce}/matches/… Radar: evict, sweep, draft, outreach yes see the radar pipeline
GET /v0/my/oracles/{nonce}/performance, /campaigns One oracle's activity yes yes, reporting
GET /v0/my/console/traffic/campaign?campaign= Landing visits by campaign yes optional

Mentioned