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 — from your own systems, or from an AI assistant through the MCP server.
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/v1is a supported alias that reaches the same gateway, so an integration written against it keeps working; useapi.boltclaw.aifor anything new. - Content type —
application/jsonfor requests and responses - Versioning — the version is in the path.
/v1will 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.
curl https://api.boltclaw.ai/v1/ping \
-H "Authorization: Bearer bc_live_EXAMPLExxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx"
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.
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
}'
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.
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"
}'
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.
curl -X PATCH https://api.boltclaw.ai/v1/pages/acme \
-H "Authorization: Bearer bc_live_EXAMPLExxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx" \
-H "Content-Type: application/json" \
-d '{
"published": true
}'
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.
curl https://api.boltclaw.ai/v1/pages/acme \
-H "Authorization: Bearer bc_live_EXAMPLExxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx"
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.
curl "https://api.boltclaw.ai/v1/pages/acme/stats?from=2026-03-01&to=2026-04-01" \
-H "Authorization: Bearer bc_live_EXAMPLExxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx"
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
emailfield 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.