The connector reference.
Everything a platform needs to become a lane on Fanogram: authenticate, declare what you can honour, stream what happened, and execute the actions we hand back. Chat, CRM, co-pilot, autopilot and payments are inherited. You do not implement them.
This reference documents the connector standard: the Connect engine’s
ExternalPlatformProvider contract, published via @fanogram/connect-contracts.
It is the API for connecting a platform as a lane on Fanogram: your creators’ identity and
auth, thread and message webhooks, media, the shared fan record, attribution, and the payments
hand-off. Running the engines inside your own product is a separate, coming-soon offering and
carries no endpoint documentation on this page: see
Engines overview.
Getting started
Three things happen before your first event lands: you log in to the partner dashboard and generate a sandbox key, you register your platform with the capabilities you can honour, and you point a webhook at your side. Nothing in the sandbox touches real money or a real fan.
Keys are issued per partner, inside the dashboard, after you log in. There is no public key endpoint, and no page (this one included) ever displays a real key.
Log in to generate your sandbox keys →fg_live_…………………………………… (shown once at creation)
The value above shows the key format and nothing more: this is a concept page and it has no secret to show. A real key is displayed exactly once, at the moment you create it in the dashboard, and is stored only as a hash on our side. If you lose it, you rotate it. We cannot recover it, and no support route can.
Limits are per key and scale with your connector’s stage: sandbox, pilot and production keys each carry a different ceiling. The exact numbers, along with every commercial term, live in docs/PRICING-CANONICAL.md; this page never quotes them, so it can never drift from them.
Auth
Every request carries a bearer key. Every request that acts on a creator also carries the creator
scope you were granted. A key alone can read your connector, never a creator’s fans. Access decisions
fail closed: an unresolvable scope is a 403, never a silent empty list.
curl https://api.fanogram.co/v1/connectors/self \ -H "Authorization: Bearer fg_live_…" \ -H "Fg-Creator-Scope: crt_9f2a41" \ -H "Fg-Api-Version: 2026-08-01"
const fg = new Fanogram({ key: process.env.FG_API_KEY, // never inline a key apiVersion: '2026-08-01' }); const me = await fg.connectors.self({ creatorScope: 'crt_9f2a41' });
A creator grants your connector a scope; you cannot mint one. Revocation is immediate and
one-sided: the creator revokes, your next call is a 403, and no cached grant survives it.
Connector standard
Registration is where you declare what your platform can actually do. Capabilities you do not declare are never offered to your creators, and never appear in their UI. A lane cannot over-promise by accident; that is the whole point of declaring rather than discovering.
Register a platform, or update its declared capabilities. Re-posting with the same
slug updates in place.
| Parameter | Type | Description | |
|---|---|---|---|
| slug | string | Required | Stable lowercase identifier for your platform. Immutable once live. |
| display_name | string | Required | Shown to creators in the connect flow and on their lane chips. |
| capabilities[] | string[] | Required | What you can honour: chat.send, chat.media,
payments.unlock, crm.read. Anything omitted is never offered. |
| webhook_url | string | Required | HTTPS endpoint that receives signed actions. Must respond 2xx within 5s. |
| regions[] | string[] | Optional | ISO country codes you can serve. Omit for no restriction. |
| contact_email | string | Optional | Where delivery failures and deprecation notices are sent. |
{
"slug": "yourplatform",
"display_name": "Your Platform",
"capabilities": [
"chat.send",
"chat.media",
"payments.unlock",
"crm.read"
],
"webhook_url": "https://api.yourplatform.com/fg/actions",
"regions": ["GB", "US", "DE"]
}
{
"id": "con_4b81de",
"slug": "yourplatform",
"status": "sandbox",
"capabilities": [
"chat.send",
"chat.media",
"payments.unlock",
"crm.read"
],
"webhook_secret_hint": "whsec_…4f7c", // full value shown once
"created_at": "2026-08-12T09:14:02Z"
}
Map one of your user ids onto the shared fan or creator record. After linking, a fan who exists in two lanes is one fan, with one lifetime value.
| Parameter | Type | Description | |
|---|---|---|---|
| external_id | string | Required | The id in your system. Never re-used for a different person. |
| role | enum | Required | fan or creator. |
| creator_scope | string | Required | Which creator’s world this identity belongs to. |
| handle | string | Optional | Display handle. Improves matching against an existing record. |
Per-platform enablement
Implementing the standard once grants access to the standardised capabilities. Which of them are enabled for a given lane is a per-platform decision, ruled on the Connect engine’s side: a ruling, not a default. Registration declares what your platform can honour; the engine’s enablement rules decide what your lane actually offers. A capability that is declared but not enabled for your lane is never offered to your creators, and calling it is refused: like every access decision on this page, enablement fails closed.
Who connects
- Platforms with the audience: inherit chat, CRM, autopilot and payments, stay the brand your users see, and ship a lane instead of a payments company.
- Tools with the workflow: read the fan record you never had, attribute your workflow to real revenue, and embed chat where the work already happens.
- Agencies with the operators: one integration per agency, scoped access by creator, lane and hours, with attribution and splits already computed.
Trust and compliance
- Consent: voice, likeness and chat training are opt-in per feature, per creator, and revocable. A partner cannot enable them on a creator’s behalf.
- Data: every token is scoped to declared capabilities. Access decisions fail closed, and every read of a fan record is attributable to a key.
- Content: paid media is invisibly watermarked to the buying fan on every send, including sends your product initiates.
- Money: Fanogram is merchant of record. Refunds, chargebacks and payouts resolve against a single book; there is no partner-side reconciliation.
Chat API
The differentiator, in endpoint form: a connected platform is not handed a read-only feed and asked to rebuild a chat client. Your lane gets the thread itself (send, media, drafts, unsend, reactions and read state), with correctness owned on our side. This is part of the connector standard, for platforms connected as lanes; it is not the standalone engine offering. See the partner overview for why that matters.
co-pilot / autopilot mode names, however, are
fixed vocabulary and will not change: approve-each and autonomous, never a third mode.
Send into a thread from your surface. The message lands in the same thread the creator sees in Fanogram, attributed to whoever your key says sent it.
| Parameter | Type | Description | |
|---|---|---|---|
| body | string | Required | Message text. Max 4000 characters after normalisation. |
| media_ids[] | string[] | Optional | Vault media to attach. Paid attachments are watermarked to the buying fan automatically. |
| price | integer | Optional | Fan-facing unlock price in minor units. Omit for a free send. |
| mode | enum | Optional | direct · co-pilot (creates a draft awaiting approval) ·
autopilot (sends autonomously, subject to guardrails). |
| idempotency_key | string | Optional | Retry safely. A repeat within 24h returns the original message, not a duplicate. |
curl -X POST https://api.fanogram.co/v1/threads/thr_71c/messages \ -H "Authorization: Bearer fg_live_…" \ -H "Fg-Creator-Scope: crt_9f2a41" \ -H "Content-Type: application/json" \ -d '{ "body": "It’s live. It unlocks right here in the chat.", "media_ids": ["med_28ba9f"], "price": 2400, "mode": "co-pilot", "idempotency_key": "snd_2026-08-12_01" }'
{
"id": "msg_c02e19",
"thread_id": "thr_71c",
"state": "awaiting_approval", // co-pilot: creator approves
"mode": "co-pilot",
"price": 2400,
"currency": "USD",
"attribution": {
"connector": "con_4b81de",
"surface": "partner"
},
"created_at": "2026-08-12T09:31:44Z"
}
co-pilot drafts and waits for the creator. autopilot sends on its own.
There is no third mode anywhere in the product, and the same two words are used for chat,
auto-post and scripts.
The CRM record behind the thread: lifetime value, tags, lanes and last activity. Read-only from a partner key; writes go through the event stream.
{
"id": "fan_a81f30",
"handle": "alex",
"lifetime_value": 92700, // minor units, fan-facing
"currency": "USD",
"lanes": ["telegram", "yourplatform"],
"tags": ["vip", "renewed"],
"last_active_at": "2026-08-12T08:52:10Z"
}
Payments
You render the money; you never hold it. Fanogram is merchant of record, mints the transaction, and settles out through the Spire rail. Your side asks for an unlock and reads the resulting ledger line; there is no partner-side book to reconcile.
The Spire settlement rail is coming soon on both Fanogram and Folo. The existing processors (CCBill, Centrobill, Paybl) are live behind the same interface. Treat the settlement fields below as design, not as a shipped behaviour.
Charge a fan for a paid message or vault item and record the resulting ledger line. Splits are resolved server-side from the creator’s configuration. A partner never computes a share.
| Parameter | Type | Description | |
|---|---|---|---|
| fan_id | string | Required | Who is paying. Must be linked via /v1/identities/link. |
| message_id | string | Required | The paid message being unlocked. |
| amount | integer | Required | Fan-facing price in minor units. Must match the message’s declared price. |
| idempotency_key | string | Required | Required here, not optional: a double-charge is not a recoverable error. |
{
"id": "unl_5d7a02",
"state": "captured",
"amount": 2400,
"currency": "USD",
"merchant_of_record": "fanogram",
"processor": "ccbill",
"ledger_entry": "led_9ce441",
"splits": "resolved_server_side", // terms: PRICING-CANONICAL.md
"settlement": {
"rail": "spire",
"status": "pending_launch" // concept, not live
}
}
Webhooks
Step 4 of the connector standard: we hand you signed actions to perform. Your side stays a thin,
verifiable executor. Verify the signature, do the thing, return 2xx.
- Signed with
Fg-Signature: a timestamp and an HMAC over the raw body. Verify before parsing. - Retried with exponential backoff for 24 hours on any non-
2xxor timeout over 5 seconds. - At-least-once delivery. Deduplicate on
event.id: a repeat is expected, not a bug. - Order is not guaranteed across threads. Within a thread,
sequenceis monotonic.
{
"id": "evt_0f3b7c",
"type": "action.dispatch",
"sequence": 418,
"created_at": "2026-08-12T09:33:01Z",
"data": {
"action": "send_message",
"thread_id": "thr_71c",
"external_fan_id": "u_88213",
"body": "It’s live. It unlocks right here in the chat.",
"media": [{ "url": "https://cdn.fanogram.co/…", "expires_in": 600 }]
}
}
// Fg-Signature: t=1786000381,v1=9f2c… const [t, v1] = parseSig(req.headers['fg-signature']); const expected = hmacSha256( process.env.FG_WEBHOOK_SECRET, `${t}.${rawBody}` // RAW body, before JSON.parse ); if (!timingSafeEqual(v1, expected)) return res.status(400).end(); if (Date.now()/1000 - t > 300) return res.status(400).end(); // replay window
Engines overview
Everything in this section describes standalone engine use: the engines running inside a partner’s own product. That is a separate offering from the connector standard documented above, and the two are never mixed: no endpoint on this page belongs to it, and none is documented here yet. The engines only run Fanogram itself today. Register interest with the team and watch the docs changelog for the launch.
Four surfaces arrive wired to one fan record. A conversation that starts in your app, a sale that closes in ours and a payout that settles next week are the same object with three views, not three integrations you reconcile by hand:
- Chat: threads, media, unsend, reactions, scheduled sends and read state, rendered in your product and backed by the shared engine. One thread per fan, whichever lane the message arrived on.
- CRM: lifetime value, spend history, tags, smart lists and the whole relationship, computed once and readable from your side.
- Co-pilot and autopilot: two modes, and only two. Co-pilot drafts and waits for approval; autopilot runs autonomously. Both write in the creator’s trained tone and are switchable per chat.
- Payments: tips, subscriptions and in-chat unlocks, plus the ledger underneath them: splits, refunds, chargebacks and payouts. Your product shows the money; it never has to hold it.
Chat: the surface, not a feed
Most partner APIs in this category hand you events and wish you luck. You rebuild threading, media and the AI layer yourself, and it drifts from the source of truth on the first release. Ours will expose the chat surface itself: your creators answer inside your app, and the thread, fan record and attribution are the same objects we run. The Chat API above is a different thing: it documents the connected-platform lane under the connector standard. The standalone reference lands here when this offering opens.
Payments: without becoming the bank
Being the merchant of record in this category is the expensive part: high-risk processing, chargeback exposure, KYC and payout compliance in every country. Fanogram mints the transaction instead. One ledger records the split, refund, chargeback and payout, and Spire settles it out. The Payments section above covers the connector standard’s hand-off for connected lanes; no standalone payments reference exists yet.
Errors
Errors are machine-readable first. Every response carries a stable code, a human
message that is safe to log, and a request_id to quote. Access failures fail
closed: you get a refusal, never a quietly empty result.
| Code | Status | Meaning | What to do |
|---|---|---|---|
| invalid_key | 401 | Key missing, malformed or rotated. | Re-read from your secret store; do not retry. |
| scope_revoked | 403 | The creator revoked your grant. | Stop calling for that creator and drop cached state. |
| capability_not_declared | 403 | You called something you did not register in step 1. | Re-register with the capability, or stop offering it in your UI. |
| identity_unlinked | 404 | The external id has no shared record. | Call /v1/identities/link first. |
| price_mismatch | 409 | Unlock amount does not match the message price. | Re-read the message; never reconcile by adjusting the amount. |
| rate_limited | 429 | Ceiling for this key reached. | Back off using Retry-After. Limits scale with connector stage. |
| guardrail_blocked | 422 | An autopilot send hit a hard safety limit. | Surface the refusal to the creator. Guardrails are not settings and cannot be disabled. |
Changelog
Breaking changes ship behind a dated Fg-Api-Version. A version is supported for twelve
months after its successor lands, and deprecations are announced here before they are enforced.
This reference now documents the connector standard (the Connect engine’s
ExternalPlatformProvider contract, via @fanogram/connect-contracts)
exclusively. Standalone engine use is a separate coming-soon offering with no endpoints here.
Keys are issued in the partner dashboard, after login.
This reference published as a design shell. Endpoints illustrative pending the engineering contract.
mode vocabulary fixedChat send modes are co-pilot and autopilot only. Any third mode name
in earlier drafts is retired.
capabilities[] on registrationConnectors now declare what they can honour. Undeclared capabilities are never offered to creators.
Fg-Signature verification becomes mandatory in the next dated version.