Summary
API v2 is a stream-centred redesign. Three primary verbs frame the surface:- Create streams -
POST /api/v2/streams(one-shot: handles + segments + schedule + delivery) - Update streams -
PATCH /api/v2/streams/{id}(any setting, including full-replace pairs and inline segment creation) - Extract leads -
GET /api/v2/streams/{id}/leads(per-stream) orGET /api/v2/leads(cross-stream polling)
Vocabulary
- Stream - a campaign. Owns N
(tracked_account, segment)pairs and shared config (schedule, enrich, delivery, csv-email). The primary resource. - Segment - a reusable filter set (lead description + applied labels + gender + follower-count tiers). Code-side identifier is still
segments. - Lead - a discovered profile that survived bot-filtering and (optionally) matched one or more segments. Renamed from “people of interest”.
- Lookup - a one-shot enrichment or NL-to-segment operation for the Chrome extension. Distinct surface at
/api/v2/lookups/*.
Endpoint mapping
Identity
Streams (new primary resource)
Leads
Account management
Tracked accounts no longer have a public “add” verb - adding happens via stream creation. Management verbs survive:Segments
Editing a segment’s filters in place is intentionally NOT exposed (footgun risk for external integrators - mutating a segment affects classification across every stream that references it). Workflow: create a new segment viaPOST, then PATCH the affected streams to swap.
Sync settings
Lookups (Chrome extension surface)
Utility (unchanged path, sometimes shape)
Conceptual changes
Stream is a campaign
The keystone of the v2 redesign. Onestream row owns N (tracked_account, segment) pairs and a shared config (schedule, enrich, delivery, csv-email). A segment can appear in multiple streams. A stream can contain multiple segments AND/OR multiple accounts in any combination.
One-shot stream creation
POST /api/v2/streams accepts handles (resolves via ScrapeBadger -> kaitoeasyapi, upserts tracked accounts, increments Stripe quantity) AND inline segment objects (creates new segments rows) in one call. Existing accounts/segments can be referenced by ID instead.
Full-replace pair updates
PATCH /api/v2/streams/{id} accepts a pairs array as full-replace semantics: server diffs against existing pairs, adds new (upserting accounts + creating inline segments), removes ones not in the new array.
Lead lifecycle
Leads carry a server-derivedexported_at field. ?lifecycle=new filters for IS NULL (default). ?lifecycle=exported filters for IS NOT NULL. Exporting is done via POST /api/v2/leads/{id}/export.
matchConfidence enum
'full' / 'maybe' -> 'high' / 'medium' (column rewrite in migration 0113). Reflected in /api/v2/leads, /api/v2/streams/{id}/leads, webhook filter config.
Per-account billing visibility
GET /api/v2/me exposes per-account daily-sync slots + monthly re-test budgets, plus credit balance + low-balance flag, plus a totals rollup (“how much headroom do I have anywhere right now”). No standalone /api/v2/budget - it’s folded into /me.
Tracked accounts are second-class in the API
Adding accounts happens via stream creation. Removing pairs leaves orphan accounts (tracked but referenced by no active stream); orphans stay tracked + billed until explicitly slept viaPOST /api/v2/accounts/{id}/sleep. Account-level operations (sleep / wake / change-tier) survive as /api/v2/accounts/{id}/<verb>.
Webhook filter
Filter config supports{streamId?, accountId?, sourceType?, feedbackStatus?, matchConfidence?}. segmentId is removed. Existing subscriptions stored with segmentId filter silently match nothing post-deploy (the filter was a TODO that never actually applied anyway). Re-subscribe with streamId if you want filtering.
Paywall error codes
Every server gate that surfaces a paywall returns{ error: '<code>', message: '<copy>' } with HTTP 403 (or 400 / 429 where appropriate). Branch on the code, not the message text.
Auth (unchanged)
API key auth viaAuthorization: Bearer <ctgo_…> header. Existing PATs continue working post-deploy.
In-app UI calls (cookie session) work transparently on the hybrid-auth routes (/api/v2/streams*, /api/v2/leads*, /api/v2/segments, /api/v2/accounts/{id}/*, /api/v2/me, /api/v2/runs).