Let your assistant build the campaign
Point ChatGPT or Claude at your Promo-Chats account. Hand it the track, the artwork and what you want said, and it puts the whole promo together — release details, audio, cover, message, audience. You stay the one who decides it goes out.
What an assistant can and cannot do
A key carries scopes, and a scope it does not have is a door that is not there. Reading your campaigns, creating one, and uploading assets are separate permissions. Sending is its own scope, off unless you turn it on — and even with it, the send call is refused unless it carries an explicit confirmation, so an assistant cannot decide on its own that today is the day your promo goes out.
Anything queued through the API obeys the same limits as the app: the daily cap, the warm-up pace, the one-reminder-a-week rule, and the guard that pauses a campaign by itself if addresses start bouncing. There is no faster path in here. It is the same engine.
1. Create a key
In the app, Setup → API. Pick what the key may do and copy it — it is shown once and stored only as a hash, so nobody, including us, can read it back.
From an empty account to a promo
Everything below can be done by an assistant with the right scopes, in this order. The two things it cannot do are marked, and they are the two you would want to keep anyway.
GET /api/v1/setup → what is still missing. Read this first.
PATCH /api/v1/settings → sender name, reply address, sending hours, invoice details
POST /api/v1/lists → create a list
POST /api/v1/contacts → add the recipients onto it
POST /api/v1/campaigns → create the campaign
POST /api/v1/campaigns/{id}/assets → audio, artwork, press note
── you pay for the campaign, in the app ──
POST /api/v1/campaigns/{id}/send → queue it, with confirm: true
GET /api/v1/campaigns/{id}/stats → what came backTwo things are not an assistant's to do: entering card details, and signing in to your Instagram or WhatsApp. Not because the API stops short — it builds the Stripe payment link for you and reports exactly which channels are connected — but because a card needs its holder to authenticate, and a social login needs you. Everything up to and after those two steps is in the API.
2a. Connect Claude
Promo-Chats speaks the Model Context Protocol. Add it as a remote MCP server:
{
"mcpServers": {
"promo-chats": {
"type": "http",
"url": "https://promo-chats.com/api/mcp",
"headers": { "Authorization": "Bearer pc_live_YOUR_KEY" }
}
}
}Then just talk: “Set up the promo for the new Occipital track, here is the WAV and the cover, send it to the techno list.” It will create the campaign, attach the files and stop to ask you before anything leaves.
2b. Connect ChatGPT
Create a GPT, add an Action, and import the schema from promo-chats.com/api/v1/openapi.json. For authentication choose API Key, type Bearer, and paste your key.
3. Or use it directly
curl https://promo-chats.com/api/v1/me \
-H "Authorization: Bearer pc_live_YOUR_KEY"
curl -X POST https://promo-chats.com/api/v1/campaigns \
-H "Authorization: Bearer pc_live_YOUR_KEY" \
-H "Content-Type: application/json" \
-H "Idempotency-Key: occipital-summer-01" \
-d '{
"artist": "Occipital",
"track": "Bright Fold",
"title": "Occipital — Bright Fold (SuperMarket)",
"message": "First class techno for your next set.",
"channels": "email",
"listIds": [3]
}'The endpoints
/api/v1/meWho the key acts for, and today’s sending room/api/v1/setupWhat is still missing before a send/api/v1/settingsThe account settings/api/v1/settingsSender identity, sending hours, invoice details/api/v1/listsContact lists and who is reachable/api/v1/contactsThe address book, a page at a time/api/v1/contactsAdd recipients, onto a list if you want/api/v1/listsCreate a list/api/v1/campaignsYour campaigns/api/v1/campaignsCreate one/api/v1/campaigns/{'{id}'}One campaign and its audience/api/v1/campaigns/{'{id}'}Edit it/api/v1/campaigns/{'{id}'}/assetsAudio, artwork, press note/api/v1/campaigns/{'{id}'}/sendQueue the send — needs confirm/api/v1/campaigns/{'{id}'}Delete it, audio and all — needs confirm/api/v1/campaigns/{'{id}'}/pauseStop a send, or resume it/api/v1/campaigns/{'{id}'}/checkoutA payment link to hand over/api/v1/campaigns/{'{id}'}/statsOpens, plays, downloads, feedback/api/v1/jobs/{'{id}'}How a queued send is going/api/v1/analyticsThe account as a whole/api/v1/feedbackWhat curators said/api/v1/storageSpace used, and what is safe to delete/api/v1/assetsThe audio and files on your campaigns/api/v1/assetsDelete one and release the space/api/v1/contacts/{'{id}'}One contact and their history/api/v1/contacts/{'{id}'}Edit them/api/v1/contacts/{'{id}'}Delete them/api/v1/lists/{'{id}'}Rename a list/api/v1/lists/{'{id}'}Delete a list, keep the people/api/v1/templatesMessage templates/api/v1/channelsWhat you can send on/api/v1/invoicesInvoices/api/v1/activityRecent activity/api/v1/billing-portalA link to your Stripe billing pageRetries cannot send twice
An assistant that loses the connection will try again. Send an Idempotency-Key header on anything that creates or sends: the second attempt gets the first answer back, marked as a replay, instead of a second campaign in the same inboxes.
When something goes wrong
Every answer has the same shape, and every error says which kind it is and what to do about it.
{
"error": {
"type": "invalid_request",
"code": "confirmation_required",
"message": "This will send real messages to real people…",
"docs": "https://promo-chats.com/developers"
},
"request_id": "req_9f2c…"
}Rate limits come back as 429 with Retry-After, and every response carries X-RateLimit-Remaining. Quote the request_id if you write to us about one.
An unsubscribe is for ever
Adding recipients is the part where an assistant can do real harm, so it is the part with the most checks. Anyone who unsubscribed is refused — including someone whose record was deleted afterwards, because the platform keeps the fact of the unsubscribe once the person is gone. An address that has bounced anywhere on the platform is refused too: every account here sends through the same domain, and a dead mailbox spends everyone’s reputation.
Nothing is refused quietly. Every contact that does not go in comes back with a reason, so an assistant can tell you “480 added, 20 refused because they had unsubscribed” rather than reporting a clean success it did not have.
Your contacts stay yours
The API never hands an assistant a downloadable copy of your address book: contacts come back one page at a time, and a key without the contacts scope does not see them at all. Reading and adding are separate permissions. Files are fetched only from public addresses, never from inside our network. And a key you no longer trust dies the moment you revoke it in Setup.