# 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)

```bash
curl -s "https://api.closefinch.com/v1/media" \
  -H "Authorization: Bearer $RA_API_KEY"
```

```js
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)

```bash
curl -s -X DELETE "https://api.closefinch.com/v1/media/$ID" \
  -H "Authorization: Bearer $RA_API_KEY"
```

```js
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

```bash
curl -s -X POST "https://api.closefinch.com/v1/media/captures" \
  -H "Authorization: Bearer $RA_API_KEY" \
  -H "content-type: application/json" \
  -d '{}'
```

```js
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

```bash
curl -s "https://api.closefinch.com/v1/media/likeness" \
  -H "Authorization: Bearer $RA_API_KEY"
```

```js
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

```bash
curl -s -X DELETE "https://api.closefinch.com/v1/media/likeness/$ID" \
  -H "Authorization: Bearer $RA_API_KEY"
```

```js
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

```bash
curl -s -X POST "https://api.closefinch.com/v1/media/screenshots" \
  -H "Authorization: Bearer $RA_API_KEY" \
  -H "content-type: application/json" \
  -d '{}'
```

```js
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

```bash
curl -s "https://api.closefinch.com/v1/media/videos" \
  -H "Authorization: Bearer $RA_API_KEY"
```

```js
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

```bash
curl -s "https://api.closefinch.com/v1/messaging/connections" \
  -H "Authorization: Bearer $RA_API_KEY"
```

```js
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

```bash
curl -s "https://api.closefinch.com/v1/messaging/templates" \
  -H "Authorization: Bearer $RA_API_KEY"
```

```js
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

```bash
curl -s -X POST "https://api.closefinch.com/v1/messaging/templates/sync" \
  -H "Authorization: Bearer $RA_API_KEY" \
  -H "content-type: application/json" \
  -d '{}'
```

```js
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)

```bash
curl -s "https://api.closefinch.com/v1/messaging/threads" \
  -H "Authorization: Bearer $RA_API_KEY"
```

```js
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)

```bash
curl -s "https://api.closefinch.com/v1/messaging/threads/$ID" \
  -H "Authorization: Bearer $RA_API_KEY"
```

```js
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)

```bash
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 '{}'
```

```js
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

```bash
curl -s "https://api.closefinch.com/v1/messaging/threads/$ID/media/$ASSET" \
  -H "Authorization: Bearer $RA_API_KEY"
```

```js
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](https://www.closefinch.com/openapi.json). All resources: [API reference](https://www.closefinch.com/docs/api).
