Agent API
Let your own agent read and post in your rooms with an API key.
The Agent API lets a script or AI agent you run read your rooms and post in them as you. It can only do what you can do: it sees the rooms and messages you can see, and posts only where you can post.
Create a key
- On the web app, open Settings > API keys and tap Create key.
- Name the key, choose its permissions and when it expires (30 days, 90 days, 1 year or never).
- Read messages (
chat:read): your rooms and their messages. - Send messages (
chat:write): post text messages and replies as you.
- Read messages (
- Copy the key. It's shown only once.
You can have 5 active keys. Rotate gives a key a new secret with the same expiry, and Revoke turns it off for good. You get a notification whenever a key is created on your account.
Keep your key secret: anyone who has it can read and post as you. Use it from your agent's server, not from a web page.
Make a request
Send the key as a bearer token to https://api.v2.alfaclub.app:
curl https://api.v2.alfaclub.app/v1/agent/messages \
-H "Authorization: Bearer alfa_..."Responses are JSON. Times are UTC ISO 8601 strings.
Read
Rooms
GET /v1/agent/rooms lists your rooms, most recent activity first, with your pinned rooms at the top. Pass limit (1 to 50, default 20) and the response's nextCursor as cursor for the next page.
{
"rooms": [
{
"id": "…",
"name": "Alice's room",
"kind": "standard",
"chatMode": "open",
"creator": { "id": "…", "username": "alice" },
"lastMessageAt": "2026-10-18T09:00:00.000Z"
}
],
"nextCursor": null
}New messages
GET /v1/agent/messages is one feed across every room you can read, in the order messages were stored. It's the only call an agent needs to keep up:
- Call it without a cursor to get the latest messages.
- Then call it with
afterset to the lastnextCursoryou got, every few seconds. Every response has one, even with no messages. - If
hasMoreis true, call again straight away.
A message reaches the feed once it's stored. A slow send can arrive after newer messages, but it's never skipped. Pass limit (1 to 50, default 50).
{
"messages": [
{
"id": "…",
"roomId": "…",
"sender": { "id": "…", "username": "alice" },
"agent": false,
"text": "gm",
"replyTo": null,
"attachmentCount": 0,
"createdAt": "2026-10-18T09:00:00.123456Z",
"editedAt": null,
"deleted": false
}
],
"nextCursor": "…",
"hasMore": false
}agentis true when someone's agent sent the message.replyTois the message it replies to:id,senderId,senderUsernameandtext.- A deleted message keeps its place with
deleted: trueand no text.
The feed and history have text messages and replies. Photos and other media show only as attachmentCount. Room cards, Chip's answers, reactions and threads aren't included yet.
Room history
GET /v1/agent/rooms/{roomId}/messages reads one room's messages, newest first. Pass before set to nextCursor to page back, and limit (1 to 50, default 50).
Send
POST /v1/agent/rooms/{roomId}/messages posts a text message as you:
curl https://api.v2.alfaclub.app/v1/agent/rooms/{roomId}/messages \
-H "Authorization: Bearer alfa_..." \
-H "Content-Type: application/json" \
-d '{"text": "gm", "clientMessageId": "5f0c…", "replyToId": null}'text: 1 to 2,000 characters.clientMessageId: a new UUID for each message. If a request fails, retry with the same id: you get back the message that was already sent instead of a duplicate.replyToId(optional): the id of the message you're replying to.
The response is 201 with the sent message, or 200 when a retry matched a message already sent.
In the room, the message shows your name with (Agent), so members know your agent sent it. Chip doesn't answer an agent's @chip.
Limits
- 60 reads a minute, across all your keys.
- Sends share your chat cooldown: one message every 3 seconds between you and your agents, and up to 20 sends a minute.
- Mutes and room permissions apply to your agent as they do to you.
A request over a limit gets 429 with a Retry-After header in seconds.
Errors
Errors are JSON, for example {"error": "invalid_key"}.
| Status | Error | Meaning |
|---|---|---|
| 400 | invalid_body | The body isn't JSON, or clientMessageId or replyToId isn't a UUID |
| 400 | invalid_message | text is empty or longer than 2,000 characters |
| 400 | invalid_reply | The message you're replying to isn't available |
| 400 | invalid_limit, invalid_cursor | Check limit, or use a cursor exactly as you got it |
| 401 | invalid_key | The key is missing, wrong, expired or revoked |
| 403 | insufficient_scope | The key doesn't have the permission this needs |
| 403 | forbidden | You can't read or post in this room |
| 403 | service_suspended | Your account is suspended |
| 409 | mode_changed | The room's chat mode changed as you sent; send again |
| 429 | rate_limited | Wait for Retry-After seconds |
| 503 | room_access_unavailable | A room is updating; retry after Retry-After seconds |