API reference
API: Messaging
| Method | Path | What it does | Scope |
|---|---|---|---|
| GET | /v1/media | Your files (owners: everyone's) | messages:read |
| POST | /v1/media | Upload a file to send (up to 15 MB): a voice note in your own voice (confirm it with own_voice: true), an image, a video or a PDF (web app only) | messages:write |
| DELETE | /v1/media/:id | Archive a file (it isn't sent again) | messages:write |
| GET | /v1/media/:id/:exp/:sig | A file by its signed, expiring link (what the channels fetch) (no sign-in) | — |
| POST | /v1/media/captures | The browser extension's screenshot of your own tab, as an image for a message | messages:write |
| GET | /v1/media/likeness | Your likeness consents for AI video (owners: everyone's) and the statement you'd type | messages:read |
| POST | /v1/media/likeness | Consent to AI video of yourself: your own photo (HeyGen) or your own Tavus replica, with the dated statement typed exactly (web app only) | messages:write |
| DELETE | /v1/media/likeness/:id | Withdraw a likeness consent (you, or an owner): its videos stop being sendable | messages:write |
| POST | /v1/media/screenshots | A screenshot of a public web page (ScreenshotOne, your organization's key) as an image for a message | messages:write |
| GET | /v1/media/videos | Your AI videos (owners: everyone's): rendering, ready (a draft), approved | messages:read |
| POST | /v1/media/videos | Make an AI video of yourself from a script ({first_name} and {company} filled from a contact); it's a draft until you approve it (web app only) | messages:write |
| POST | /v1/media/videos/:id/decision | Approve or reject your AI video (only the person in it); nothing is sent (web app only) | messages:write |
| POST | /v1/media/voice-notes | Make an AI voice note in your own cloned voice (your consent must cover voice messages; at most a minute); it's sent only by you, always with a line saying it was made with AI (web app only) | messages:write |
| GET | /v1/messaging/connections | Your organization's messaging channels (WhatsApp, Telegram, Instagram, iMessage) and their webhook URLs | connections:read |
| POST | /v1/messaging/connections | Connect a channel account with your own credentials (checked with the provider first). The response shows, once, what to paste into Meta's dashboard or Sendblue. iMessage needs acknowledge_platform_risk: true (web app only) | integrations:write |
| DELETE | /v1/messaging/connections/:id | Disconnect a channel: nothing more is sent or captured (web app only) | integrations:write |
| PATCH | /v1/messaging/connections/:id | Change a channel's settings: the AI agent on or off, the WABA id, Instagram's Human Agent permission (web app only) | integrations:write |
| POST | /v1/messaging/telegram/link | A Telegram deep link: for a contact (their chat with the bot is tied to them), or for yourself (capture your own Telegram Business chats, private to you) (web app only) | connections:write |
| GET | /v1/messaging/templates | WhatsApp templates and their Meta review status | messages:read |
| POST | /v1/messaging/templates | Submit a WhatsApp template to Meta for review (owners) (web app only) | settings:write |
| POST | /v1/messaging/templates/sync | Refresh template statuses from Meta | settings:write |
| GET | /v1/messaging/threads | Conversations you may see, newest first (optionally one contact's) | messages:read |
| GET | /v1/messaging/threads/:id | One conversation: its messages and what may be sent now (the channel's window) | messages:read |
| POST | /v1/messaging/threads/:id/contact | Tie the conversation to a contact (its messages join their timeline) | messages:write |
| GET | /v1/messaging/threads/:id/media/:asset | A file someone sent in the conversation | messages:read |
| POST | /v1/messaging/threads/:id/messages | Send as yourself: text, your files, or (WhatsApp, outside the window) an approved template. The channel's rules, opt-outs, consent and the organization's policy apply; anything they refuse is refused before it's sent (web app only) | messages:send |
| GET | /v1/messaging/webhooks/:token | Meta's webhook subscription handshake (hub.challenge, checked against your verify token) (no sign-in) | — |
| POST | /v1/messaging/webhooks/:token | Channel webhooks (public): Meta's X-Hub-Signature-256 over the raw body, Telegram's secret token header, or Sendblue's header secret; each message applied once (no sign-in) | — |
Examples
GET /v1/media
Your files (owners: everyone's)
curl -s "https://api.closefinch.com/v1/media" \
-H "Authorization: Bearer $RA_API_KEY"const res = await fetch(`https://api.closefinch.com/v1/media`, {
method: "GET",
headers: { authorization: `Bearer ${process.env.RA_API_KEY}` },
});
const data = await res.json();DELETE /v1/media/$ID
Archive a file (it isn't sent again)
curl -s -X DELETE "https://api.closefinch.com/v1/media/$ID" \
-H "Authorization: Bearer $RA_API_KEY"const res = await fetch(`https://api.closefinch.com/v1/media/${id}`, {
method: "DELETE",
headers: { authorization: `Bearer ${process.env.RA_API_KEY}` },
});
const data = await res.json();POST /v1/media/captures
The browser extension's screenshot of your own tab, as an image for a message
curl -s -X POST "https://api.closefinch.com/v1/media/captures" \
-H "Authorization: Bearer $RA_API_KEY" \
-H "content-type: application/json" \
-d '{}'const res = await fetch(`https://api.closefinch.com/v1/media/captures`, {
method: "POST",
headers: { authorization: `Bearer ${process.env.RA_API_KEY}`, "content-type": "application/json" },
body: JSON.stringify({}), // fields: see the OpenAPI schema
});
const data = await res.json();GET /v1/media/likeness
Your likeness consents for AI video (owners: everyone's) and the statement you'd type
curl -s "https://api.closefinch.com/v1/media/likeness" \
-H "Authorization: Bearer $RA_API_KEY"const res = await fetch(`https://api.closefinch.com/v1/media/likeness`, {
method: "GET",
headers: { authorization: `Bearer ${process.env.RA_API_KEY}` },
});
const data = await res.json();DELETE /v1/media/likeness/$ID
Withdraw a likeness consent (you, or an owner): its videos stop being sendable
curl -s -X DELETE "https://api.closefinch.com/v1/media/likeness/$ID" \
-H "Authorization: Bearer $RA_API_KEY"const res = await fetch(`https://api.closefinch.com/v1/media/likeness/${id}`, {
method: "DELETE",
headers: { authorization: `Bearer ${process.env.RA_API_KEY}` },
});
const data = await res.json();POST /v1/media/screenshots
A screenshot of a public web page (ScreenshotOne, your organization's key) as an image for a message
curl -s -X POST "https://api.closefinch.com/v1/media/screenshots" \
-H "Authorization: Bearer $RA_API_KEY" \
-H "content-type: application/json" \
-d '{}'const res = await fetch(`https://api.closefinch.com/v1/media/screenshots`, {
method: "POST",
headers: { authorization: `Bearer ${process.env.RA_API_KEY}`, "content-type": "application/json" },
body: JSON.stringify({}), // fields: see the OpenAPI schema
});
const data = await res.json();GET /v1/media/videos
Your AI videos (owners: everyone's): rendering, ready (a draft), approved
curl -s "https://api.closefinch.com/v1/media/videos" \
-H "Authorization: Bearer $RA_API_KEY"const res = await fetch(`https://api.closefinch.com/v1/media/videos`, {
method: "GET",
headers: { authorization: `Bearer ${process.env.RA_API_KEY}` },
});
const data = await res.json();GET /v1/messaging/connections
Your organization's messaging channels (WhatsApp, Telegram, Instagram, iMessage) and their webhook URLs
curl -s "https://api.closefinch.com/v1/messaging/connections" \
-H "Authorization: Bearer $RA_API_KEY"const res = await fetch(`https://api.closefinch.com/v1/messaging/connections`, {
method: "GET",
headers: { authorization: `Bearer ${process.env.RA_API_KEY}` },
});
const data = await res.json();GET /v1/messaging/templates
WhatsApp templates and their Meta review status
curl -s "https://api.closefinch.com/v1/messaging/templates" \
-H "Authorization: Bearer $RA_API_KEY"const res = await fetch(`https://api.closefinch.com/v1/messaging/templates`, {
method: "GET",
headers: { authorization: `Bearer ${process.env.RA_API_KEY}` },
});
const data = await res.json();POST /v1/messaging/templates/sync
Refresh template statuses from Meta
curl -s -X POST "https://api.closefinch.com/v1/messaging/templates/sync" \
-H "Authorization: Bearer $RA_API_KEY" \
-H "content-type: application/json" \
-d '{}'const res = await fetch(`https://api.closefinch.com/v1/messaging/templates/sync`, {
method: "POST",
headers: { authorization: `Bearer ${process.env.RA_API_KEY}`, "content-type": "application/json" },
body: JSON.stringify({}), // fields: see the OpenAPI schema
});
const data = await res.json();GET /v1/messaging/threads
Conversations you may see, newest first (optionally one contact's)
curl -s "https://api.closefinch.com/v1/messaging/threads" \
-H "Authorization: Bearer $RA_API_KEY"const res = await fetch(`https://api.closefinch.com/v1/messaging/threads`, {
method: "GET",
headers: { authorization: `Bearer ${process.env.RA_API_KEY}` },
});
const data = await res.json();GET /v1/messaging/threads/$ID
One conversation: its messages and what may be sent now (the channel's window)
curl -s "https://api.closefinch.com/v1/messaging/threads/$ID" \
-H "Authorization: Bearer $RA_API_KEY"const res = await fetch(`https://api.closefinch.com/v1/messaging/threads/${id}`, {
method: "GET",
headers: { authorization: `Bearer ${process.env.RA_API_KEY}` },
});
const data = await res.json();POST /v1/messaging/threads/$ID/contact
Tie the conversation to a contact (its messages join their timeline)
curl -s -X POST "https://api.closefinch.com/v1/messaging/threads/$ID/contact" \
-H "Authorization: Bearer $RA_API_KEY" \
-H "content-type: application/json" \
-d '{}'const res = await fetch(`https://api.closefinch.com/v1/messaging/threads/${id}/contact`, {
method: "POST",
headers: { authorization: `Bearer ${process.env.RA_API_KEY}`, "content-type": "application/json" },
body: JSON.stringify({}), // fields: see the OpenAPI schema
});
const data = await res.json();GET /v1/messaging/threads/$ID/media/$ASSET
A file someone sent in the conversation
curl -s "https://api.closefinch.com/v1/messaging/threads/$ID/media/$ASSET" \
-H "Authorization: Bearer $RA_API_KEY"const res = await fetch(`https://api.closefinch.com/v1/messaging/threads/${id}/media/${asset}`, {
method: "GET",
headers: { authorization: `Bearer ${process.env.RA_API_KEY}` },
});
const data = await res.json();Request and response schemas: https://www.closefinch.com/openapi.json. All resources: API reference.