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)

Index: API pipelines — index

Goal: hear people in Telegram groups asking for what your project offers, collect their messages as matches, tune the radar, and make first contact: a draft you approve, or automatic outreach by your oracle.

Lifecycle shared by all kinds: API pipeline: Create, configure, start, stop, measure and delete a Telegram campaign of any kind. Groups: API pipeline: Submit your Telegram groups, find groups by keyword, place or rubric, vet them and attach them to a campaign. A free 7-day radar for a new project: API pipeline: Receive a free 7-day starter radar for your project and watch its matches

How it works

Words → meaning → contact.

Steps

1. Create (Paused).

POST /v0/my/campaigns
Idempotency-Key: radar-nails-la-1
{"title": "Nail masters LA", "project_nonce": "<Pro project>",
 "keyword_groups": [["manicure", "pedicure", "nails"], ["looking for", "need", "recommend"]],
 "not_groups": [["vacancy", "hiring"]],
 "tg_groups": ["<preset nonce>"]}
→ {"nonce": "470370000000000001", "card_type": "campaign", "kind": "mtproto_radar",
   "status": "Paused", "is_outreach_enabled": false, "is_auto_enabled": false,
   "keyword_groups": […], "not_groups": […], "telegram_groups_list": ["<preset nonce>"], …}

kind defaults to mtproto_radar. The response also carries fields of other kinds (speed, reactions, batch_*); ignore them.

2. Start.

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

The first start creates the radar's workspaces and shares them with you: Matches (read), Canonical (read + write); GET /v0/my/campaigns/{nonce} then shows matches_workspace and canonical_matches_workspace (and evicted_matches_workspace after the first evict). Typical 400s: project needs an active Pro membership to run campaigns, outreach requires oracles assigned, outreach requires an agenda assigned.

3. Read matches, newest first.

GET /v0/my/workspaces/<matches_workspace>?contained_limit=200&contained_offset=0
→ {"contained": [{"card_type": "post", "nonce": "470370000000000101", "snippet": "…",
                  "source_url": "https://t.me/example_group/17552", "created_at": "…", …}],
   "contained_next_offset": 200, …}

One match in full (author, group): GET /v0/graph/posts/{nonce} → author_username, source_group, source_group_username, expires_at. Search inside matches: POST /v0/search/graph/keyword {"query": "gel", "card_type": "post", "workspace": "<matches_workspace>"}.

4. Tune.

5. First contact (optional). Turn outreach on: PATCH {"oracles": ["<oracle or team workspace>"], "agenda": "<swappable agenda>", "is_outreach_enabled": true}.

One match at a time (owner only):

POST /v0/my/campaigns/{nonce}/matches/{post}/draft
{"instructions": "mention the free first consultation"}
→ {"text": "…", "target_username": "…", "oracle_nonce": "…", "model": "…"}

POST /v0/my/campaigns/{nonce}/matches/{post}/outreach
{"text": "<the text you approved>"}
→ {"ok": true}

Each can take up to a couple of minutes; if one fails, try again. Typical 400s: outreach is not enabled on this radar, no oracle available: …, all candidates already outreached for this project, no human outreach candidate in post.

Automatic: mark 5+ canonical, then PATCH {"is_auto_enabled": true}.

6. Follow results. Conversations are rooms in your inbox: API pipeline: Supervise conversations your oracles hold: turn the listener off/on, clear a handoff, set a room's agenda, ask the oracle to continue. performance and sends count group posts, so they stay at zero for a radar.

7. Stop, delete, share. POST …/stop pauses (config and matches kept); stop before DELETE. Share it by a link (index, «Sharing by links»): r lets the claimer read config and status; w also edit keywords and start / stop. Matches, Canonical and Evicted are workspaces Cabi.Chat shares with you: your link does not reach them.

8. Where your matches come from. The groups your radar hears matches in, ranked: most matches first, then most distinct authors.

GET /v0/my/campaigns/{nonce}/source_groups?days=14&limit=50
→ {"campaign": "470370000000000001", "days": 14,
   "groups": [{"nonce": "…", "handle": "tgg.example_group", "title": "…", "members": 13934,
               "matches": 41, "authors": 29, "last_seen": "…"}, …]}

Rules

API surface

Endpoint Purpose FE AI / oracle
POST /v0/my/campaigns Create the radar yes yes
GET /v0/my/campaigns, GET /v0/my/campaigns/{nonce} List; config, status, workspaces yes yes
PATCH /v0/my/campaigns/{nonce} Keywords, excludes, groups, oracles, agenda, outreach, auto yes yes
POST /v0/my/campaigns/{nonce}/start, /stop Run / pause yes yes
GET /v0/my/workspaces/{matches_workspace} Read matches yes yes
GET /v0/graph/posts/{nonce} Match details: author, group yes yes
POST /v0/search/graph/keyword with workspace Search inside matches yes yes
POST / DELETE /v0/my/workspaces/{canonical}/{post} Mark / unmark canonical yes yes
POST /v0/my/campaigns/{nonce}/matches/evict Evict matches (negatives) yes yes
POST /v0/my/campaigns/{nonce}/matches/sweep Evict what the excludes now drop yes yes
POST /v0/my/campaigns/{nonce}/matches/{post}/draft Oracle drafts a first message yes user's own AI
POST /v0/my/campaigns/{nonce}/matches/{post}/outreach Send the approved text yes user's own AI
DELETE /v0/my/campaigns/{nonce} Delete (stop first) yes rarely
POST /v0/my/links, GET /v0/my/links/{link}/grants Share the radar; who holds it yes yes
GET /v0/my/campaigns/{nonce}/source_groups Groups the matches come from, ranked no yes
POST /v0/my/campaigns/{nonce}/source_groups/workspace Keep that ranking as a workspace no your token

Mentioned