# The BoltClaw API

What the API is, where it lives, and a worked example that creates a page and answers a message.

- **Base URL** - `https://api.boltclaw.ai/v1`
- **Operations** - 215
- **Version** - 1.22.0

## The reference

215 operations, each generated from [the specification](https://boltclaw.ai/openapi.yaml).
Nothing on these pages is written twice.

- [Meta](https://boltclaw.ai/docs/api/meta) (2 operations) - Your key and its workspace.
- [API keys](https://boltclaw.ai/docs/api/api-keys) (5 operations) - The workspace's API keys, and what each may do.
- [Pages](https://boltclaw.ai/docs/api/pages) (6 operations) - Link-in-bio pages, served at boltclaw.ai/{slug}.
- [Links](https://boltclaw.ai/docs/api/links) (4 operations) - The links on a page, in display order.
- [Conversations](https://boltclaw.ai/docs/api/conversations) (6 operations) - Threads people start from a page, and the messages in them.
- [Webhooks](https://boltclaw.ai/docs/api/webhooks) (10 operations) - The endpoints registered to receive events. Read only here.
- [Social accounts](https://boltclaw.ai/docs/api/social-accounts) (1 operation) - Connected network accounts. Connecting one happens in the dashboard.
- [Posts](https://boltclaw.ai/docs/api/posts) (6 operations) - Posts to one or more connected accounts, now, scheduled, or as drafts.
- [Media](https://boltclaw.ai/docs/api/media) (2 operations) - Images and videos for posts, uploaded in two steps.
- [Inbox](https://boltclaw.ai/docs/api/inbox) (5 operations) - Comments, mentions and direct messages from every connected account.
- [Automations](https://boltclaw.ai/docs/api/automations) (4 operations) - Comment-to-DM rules that reply to people and capture leads.
- [Leads](https://boltclaw.ai/docs/api/leads) (2 operations) - Contact details people chose to give.
- [Usage](https://boltclaw.ai/docs/api/usage) (1 operation) - The organisation's plan, allowances and platform charges.
- [Referrals](https://boltclaw.ai/docs/api/referrals) (151 operations) - Referral programs, partners, conversions, commissions and payouts.
- [Agents](https://boltclaw.ai/docs/api/agents) (8 operations) - Device sign-in, approvals, and a key acting on itself.
- [Logs](https://boltclaw.ai/docs/api/logs) (2 operations) - What assistants did here, and what everybody did here.

Manage your pages and read the messages they receive, schedule social posts,
work your social inbox, run comment-to-DM automations and run your
[referral programs](https://boltclaw.ai/docs/api/referrals) — from your own systems, or from an AI
assistant through the [MCP server](https://boltclaw.ai/docs/mcp).

The API is a plain JSON REST API over HTTPS. Every request needs an API key.
Everything you can do in the dashboard, you can do here.

- **Base URL** — `https://api.boltclaw.ai/v1`. `https://boltclaw.ai/api/v1` is a
  supported alias that reaches the same gateway, so an integration written
  against it keeps working; use `api.boltclaw.ai` for anything new.
- **Content type** — `application/json` for requests and responses
- **Versioning** — the version is in the path. `/v1` will not change shape
  underneath you; a breaking change ships as `/v2`.

## A worked example

Six requests, in order: check the key, create a page, add a link, publish it,
read it back, and read its statistics. **Every one of them is executed against
a real API by our own test run** before this page ships, which is why each says
the status it answers rather than hoping.

**1. Check the key works** — answers `200`

The cheapest authenticated call there is. It needs no scope, so any working key may make it, and it answers with the scopes the key carries.

```bash
curl https://api.boltclaw.ai/v1/ping \
  -H "Authorization: Bearer bc_live_EXAMPLExxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx"
```

```js
const res = await fetch("https://api.boltclaw.ai/v1/ping", {
  headers: {
    Authorization: `Bearer ${process.env.BOLTCLAW_KEY}`,
  },
});

// 200
const data = await res.json();
```

**2. Create the page** — answers `201`

`published` defaults to `false`, so a page created through the API is never live until you say so. Only `slug` is required.

```bash
curl -X POST https://api.boltclaw.ai/v1/pages \
  -H "Authorization: Bearer bc_live_EXAMPLExxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx" \
  -H "Content-Type: application/json" \
  -d '{
  "slug": "acme",
  "title": "Acme Supply Co.",
  "bio": "Everything for the discerning coyote.",
  "theme": {
    "accent": "#5B8DEF"
  },
  "socials": [
    {
      "platform": "instagram",
      "url": "https://example.com/social"
    }
  ],
  "contact_enabled": true
}'
```

```js
const res = await fetch("https://api.boltclaw.ai/v1/pages", {
  method: "POST",
  headers: {
    Authorization: `Bearer ${process.env.BOLTCLAW_KEY}`,
    "Content-Type": "application/json",
  },
  body: JSON.stringify({
    "slug": "acme",
    "title": "Acme Supply Co.",
    "bio": "Everything for the discerning coyote.",
    "theme": {
      "accent": "#5B8DEF"
    },
    "socials": [
      {
        "platform": "instagram",
        "url": "https://example.com/social"
      }
    ],
    "contact_enabled": true
  }),
});

// 201
const data = await res.json();
```

**3. Add a link** — answers `201`

`position` is the display order and does not have to be unique. Leave it out and the link goes on the end.

```bash
curl -X POST https://api.boltclaw.ai/v1/pages/acme/links \
  -H "Authorization: Bearer bc_live_EXAMPLExxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx" \
  -H "Content-Type: application/json" \
  -d '{
  "label": "Our catalogue",
  "url": "https://example.com/catalogue",
  "icon": "book"
}'
```

```js
const res = await fetch("https://api.boltclaw.ai/v1/pages/acme/links", {
  method: "POST",
  headers: {
    Authorization: `Bearer ${process.env.BOLTCLAW_KEY}`,
    "Content-Type": "application/json",
  },
  body: JSON.stringify({
    "label": "Our catalogue",
    "url": "https://example.com/catalogue",
    "icon": "book"
  }),
});

// 201
const data = await res.json();
```

**4. Publish it** — answers `200`

A `PATCH` is partial: send only what you are changing. This is also the call that answers `402` when an account is at its page allowance.

```bash
curl -X PATCH https://api.boltclaw.ai/v1/pages/acme \
  -H "Authorization: Bearer bc_live_EXAMPLExxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx" \
  -H "Content-Type: application/json" \
  -d '{
  "published": true
}'
```

```js
const res = await fetch("https://api.boltclaw.ai/v1/pages/acme", {
  method: "PATCH",
  headers: {
    Authorization: `Bearer ${process.env.BOLTCLAW_KEY}`,
    "Content-Type": "application/json",
  },
  body: JSON.stringify({
    "published": true
  }),
});

// 200
const data = await res.json();
```

**5. Read it back** — answers `200`

A page that is not yours answers `404`, never `403`. The two are the same answer on purpose.

```bash
curl https://api.boltclaw.ai/v1/pages/acme \
  -H "Authorization: Bearer bc_live_EXAMPLExxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx"
```

```js
const res = await fetch("https://api.boltclaw.ai/v1/pages/acme", {
  headers: {
    Authorization: `Bearer ${process.env.BOLTCLAW_KEY}`,
  },
});

// 200
const data = await res.json();
```

**6. How did it do?** — answers `200`

Views and clicks from our own database. No visitor identifier of any kind is recorded, so there is none to return.

```bash
curl "https://api.boltclaw.ai/v1/pages/acme/stats?from=2026-03-01&to=2026-04-01" \
  -H "Authorization: Bearer bc_live_EXAMPLExxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx"
```

```js
const res = await fetch("https://api.boltclaw.ai/v1/pages/acme/stats?from=2026-03-01&to=2026-04-01", {
  headers: {
    Authorization: `Bearer ${process.env.BOLTCLAW_KEY}`,
  },
});

// 200
const data = await res.json();
```

## What is not in a response

Deliberately, and permanently:

- **No account identifier.** No user id, owner id, or account id appears in any
  response, success or error. Two pages on the same account share no field that
  says so.
- **No identifier that is the same across two pages.** This is the stronger
  form of the rule above, and the one the code actually enforces. The only
  per-person value in this API is `participant.id`, which is minted per page:
  the same human on two of your pages is two unrelated ids, and on another
  creator's page a third. Nothing you store from this API can be joined against
  anything another customer stores from it.
- **No email address in a conversation, on either side.** Yours never
  appears, and neither does the other person's: a thread carries no `email`
  field and a message carries no sender. Replying through this API reaches them
  inside Bolt Claw without either of you learning the other's address — which
  is the reason conversations live here rather than in two mailboxes. **Leads
  are the one exception, and a deliberate one:** a lead *is* an address or a
  number somebody chose to give your automation, it is behind its own scope
  (`leads:read`), and it never appears in a webhook.
- **No network id for another person.** The inbox shows who wrote to you by
  their public handle and name, never by the network's internal id for them.
- **No visitor identifiers.** We do not record IP addresses, user agents,
  cookies or fingerprints against a page view, so there is nothing of that kind
  to return.
- **No partner account, and no customer.** A referral partner is their
  membership id and display name in one program — the same person in two of
  your programs shares no field that says so — and their email only if they
  chose to share it with that program. A conversion carries your own customer
  id and never the customer's email, which is not stored at all.

Pages are not listed publicly, not in a sitemap, and not indexable, and there
is no endpoint here or anywhere else that enumerates them. If you need a list
of your pages, `GET /v1/pages` with your key is it.

<!-- https://boltclaw.ai/docs/api as markdown. Generated from openapi.yaml; API version 1.22.0. -->
<!-- Every /docs page answers as markdown: add .md to its path, or send Accept: text/markdown. -->
