Guides
Sending messages
Send your SuperCool agent a message with POST /v1/messages. Attach files, follow up on work in progress, answer the agent's questions and route webhooks.
Everything starts with POST /v1/messages. You talk to the agent the way you would in the SuperCool app: say what you want, attach what it needs, and follow up.
#Send a message
curl https://api.supercool.com/v1/messages \
-H "Authorization: Bearer $SUPERCOOL_API_KEY" \
-H "Content-Type: application/json" \
-H "Idempotency-Key: launch-video-2026-09-30" \
-d '{"message": "Research my top 5 competitors (candle shops in Austin) and make a one-page PDF summary"}'| Field | Type | Description |
|---|---|---|
message |
string | What you want, in plain language. Up to 20,000 characters. For longer text, attach it as a file. |
files |
array | Small files inline: up to 5, each a public url or base64 bytes. See Attach files. |
upload_ids |
array | Large files you uploaded first: up to 10. See Files & uploads. |
webhook_endpoint_id |
string | Send this message's webhook events to one registered endpoint. See Webhooks. |
You need a message, files or upload_ids. An empty request gets 400 empty_message.
Always send an Idempotency-Key: one fresh value per logical request, reused on retries. See Idempotency & retries.
#What comes back
The call returns within about 30 seconds with the message object and HTTP 201:
- A quick answer comes back finished:
"status": "completed","final": true, the answer inreply, and any files the agent handed over infiles. - Longer work comes back as
"status": "processing": the agent replied ("On it…") and started one or more jobs. Each job is one piece of work running in a chat (work_id), with its ownstatusand alinkto that chat in the app.
{
"id": "msg_3f9a1c2e7b8d4e5f6a7b8c9d",
"object": "message",
"status": "processing",
"reason": null,
"question": null,
"final": false,
"reply": "I'll research the five closest competitors and put it in a one-page PDF.",
"jobs": [
{
"job_id": "exe_9b2c4d6e8f0a1b3c5d7e9f1a2b4c6d8e",
"kind": "execution",
"role": "execution",
"work_id": "5d0c3e2a-8f1b-4c6d-9e7f-1a2b3c4d5e6f",
"title": "Austin candle shop competitors",
"status": "running",
"final": false,
"link": "https://supercool.com/chat/5d0c3e2a-8f1b-4c6d-9e7f-1a2b3c4d5e6f",
"files": []
}
],
"files": [],
"notes": [],
"credits_used": 0,
"created_at": "2026-09-30T14:02:03.118000Z",
"updated_at": "2026-09-30T14:02:12.950000Z"
}Keep the message id (msg_…). You use it to get the result. Message ids are always generated by SuperCool.
Messages belong to the API key that sent them: another key gets 404 not_found for them. The work itself (the chats) belongs to your account and is visible to every key through /v1/work.
#Attach files
For small files, put them in files. Each entry has either a url (a public https link SuperCool downloads) or base64 (the bytes), plus an optional name and content_type:
{
"message": "Turn these product photos into a 3-slide carousel for Instagram",
"files": [
{ "url": "https://example.com/photos/candle-1.jpg" },
{ "name": "candle-2.png", "content_type": "image/png", "base64": "iVBORw0KGgoAAAANSUhEUgAA..." }
]
}- Up to 5 files, each up to 10 MB, 25 MB in total. Only the first 5 are taken.
- Executables are refused.
- A file that can't be fetched doesn't fail the message. The agent gets the rest, and the problem is listed in the message's
notes(for example"candle-1.jpg: couldn't be fetched (timeout)").
For anything bigger (footage, long PDFs, audio), use an upload: up to 500 MB per file and 10 files per message.
#Follow-ups
Send another message and the agent continues the conversation, with the same memory it has in the app. Refer to earlier work naturally:
{ "message": "Love it. Make a 9:16 version with captions, and a 1:1 cut for the feed" }If the work is still running, a follow-up can join it instead of starting something new. The follow-up's message then lists that job with "role": "follow_up", and its status follows the running work. If the agent starts new work, you get new jobs.
Every message is its own object with its own id and status. To track the combined result, follow the latest message, or read the chat with GET /v1/work/{work_id}.
#When the agent asks a question
Sometimes the agent needs a decision before it can go on ("vertical or square?"). The message then ends as "status": "needs_input" with the question in question:
{
"id": "msg_3f9a1c2e7b8d4e5f6a7b8c9d",
"status": "needs_input",
"question": "Should the ad be vertical (9:16) for Reels, or square (1:1) for the feed?",
"final": true
}Answer by sending a new message. The agent picks up where it left off:
{ "message": "Vertical, for Reels" }#Out of credits, busy, and other outcomes
Talking to the agent is free. Work uses credits. With no credits, the message is still accepted (HTTP 201) and comes back "status": "blocked", "reason": "out_of_credits". That's a normal outcome, not an error. See Credits & pricing.
Up to 5 jobs can run at once per account. Messages always get through, but new work may not start: see At capacity.
Every status and reason is explained in Getting results.
#At capacity
Up to 5 jobs can run at once on your account. A message is never refused for this: stopping work ("stop the ad") or following up on running work always gets through. But if the agent tries to start new work while 5 jobs are already running, that start is refused:
- The message comes back normally (
201) with a job ofkind: "refusal"(job_idlikeref_…),status: "blocked",reason: "too_many_running"andfinal: true. - The message's
statusfollows the usual rules:blockedif that was its only job,partialif another of its jobs completed. - The message has a
runningarray listing the work that's running now:
{
"id": "msg_7a1d0c9e8b2f4a6c5d3e1f0b",
"status": "blocked",
"reason": "too_many_running",
"final": true,
"jobs": [{ "job_id": "ref_3c9e1a7b5d2f", "kind": "refusal", "status": "blocked", "reason": "too_many_running", "final": true }],
"running": [
{ "job_id": "exe_9b2c4d6e8f0a1b3c5d7e9f1a2b4c6d8e", "message_id": "msg_3f9a1c2e7b8d4e5f6a7b8c9d", "work_id": "5d0c3e2a-8f1b-4c6d-9e7f-1a2b3c4d5e6f" }
]
}Wait for one of the running jobs to finish (follow its message, or a webhook), then send the request again. Queued work that is waiting for credits also doesn't resume while 5 jobs are running. It stays queued and resumes once there's room, as long as that's within its 24-hour window.
#Route this message's webhooks
By default a message's webhook events go to every endpoint on your account that wants them. To send one message's events to a single endpoint instead (say, one per customer or environment), pass its id:
{ "message": "...", "webhook_endpoint_id": "whe_4c1d2e3f4a5b6c7d8e9f" }It must be an endpoint registered on your account (POST /v1/webhooks). Unknown ids get 404 not_found.
#Limits
| Limit | Value |
|---|---|
| Message text | 20,000 characters |
| Inline files | 5 per message, 10 MB each, 25 MB total |
| Uploads | 10 per message, 500 MB each, 1 GB total |
| Messages | 120 per hour and 1,000 per day, per account |
| Running jobs | 5 per account (new work waits; see At capacity) |
See Rate limits & errors for everything else.