Agent endpoints
List, create, update and delete AI agents, rotate their API key and webhook secret, and send a test event through the REST API.
Updated
Paths are relative to https://api.fishcamp.space/api/v1 and all need the X-Workspace-Id header and a person:
requests with an API key get 403 forbidden on every agent route, reading included. Everyone in the workspace can list
and read agents; creating, changing and deleting them are admin actions. What agents are and how they work is in
AI agents, and the events they get are in Agent webhooks.
The agent object
{
"id": "e5c4b3a2-1f0e-4d9c-8b7a-6f5e4d3c2b1a",
"name": "Scout",
"role": "Lists what to track after a meeting",
"instructions": "Suggest a task only when someone agrees on an owner and a date.",
"autonomy": "PROPOSE",
"events": ["message.created", "transcript.handoff"],
"channelIds": ["0b6f3c55-2a51-4e0a-a3d6-6a3f1f2e9d10"],
"webhookUrl": "https://scout.example.com/webhook",
"status": "ACTIVE",
"apiKeyPrefix": "cwk_8Hq2kL7x",
"createdAt": "2026-11-05T14:00:00.000Z",
"updatedAt": "2026-11-05T14:00:00.000Z",
"lastDeliveryAt": "2026-11-05T15:26:03.000Z",
"lastDeliveryStatus": 202,
"lastError": null,
"deliveriesOk": 18,
"deliveriesFailed": 0
}| Field | Description |
|---|---|
role | What it does, up to 120 characters. |
instructions | How it should work, up to 4,000 characters. Sent with transcript handoffs. |
autonomy | OBSERVE, PROPOSE, ACT_LOW_RISK or AUTONOMOUS. See autonomy. |
events | The events sent to its webhook. See Events. |
channelIds | The channels it works in. Its key only reaches these. |
webhookUrl | A public https address, or null. |
status | ACTIVE, or PAUSED when it gets no events. |
apiKeyPrefix | The first characters of its active key, or null when the key was revoked. |
lastDeliveryAt, lastDeliveryStatus, lastError | The last delivery, its HTTP status and its error, if any. |
deliveriesOk, deliveriesFailed | How many deliveries worked and failed. |
The API key and the webhook secret themselves are never in this object.
List agents
GET /agents
GET /agents/:agentIdPeople. The workspace's agents, sorted by name, or one agent. For members who aren't admins, webhookUrl is
null, lastError only says Delivery failed, and channelIds lists only the channels they can see.
Create an agent
POST /agentsAdmins.
| Field | Type | Required | Description |
|---|---|---|---|
name | string | Yes | 1 to 40 characters, unique in the workspace. |
role | string | Yes | What it does, 1 to 120 characters. |
instructions | string | No | How it should work, up to 4,000 characters. |
autonomy | string | Yes | OBSERVE, PROPOSE, ACT_LOW_RISK or AUTONOMOUS. |
channelIds | array | No | Up to 100 IDs of channels you can see: public channels, or private channels you're in. Not direct messages. |
webhookUrl | string or null | No | A public https address without a user or password, up to 2,048 characters. |
events | array | No | Any of message.created, audio.started, audio.ended, transcript.routed and transcript.handoff. |
curl -X POST "https://api.fishcamp.space/api/v1/agents" \
-H "Authorization: Bearer YOUR_SESSION_TOKEN" \
-H "X-Workspace-Id: YOUR_WORKSPACE_ID" \
-H "Content-Type: application/json" \
-d '{
"name": "Scout",
"role": "Lists what to track after a meeting",
"autonomy": "PROPOSE",
"channelIds": ["0b6f3c55-2a51-4e0a-a3d6-6a3f1f2e9d10"],
"webhookUrl": "https://scout.example.com/webhook",
"events": ["message.created", "transcript.handoff"]
}'Returns 201 Created with agent (the agent object), apiKey (cwk_…) and, when you gave a webhook URL,
webhookSecret (whsec_…). The key and the secret are in this response only.
| Error | When |
|---|---|
409 conflict | Another agent already has that name. |
422 validation_error | A field is invalid: for example, a webhook URL that isn't public https, a channel from another workspace, or a private channel you're not in. |
Update an agent
PATCH /agents/:agentIdAdmins. Send only the fields you want to change: the same ones as above, plus status (ACTIVE or PAUSED).
Returns the agent.
- A new
autonomyornameapplies to the agent's key at once. "webhookUrl": nullremoves the webhook and its secret.- Adding a webhook URL to an agent that had none creates a secret, but this response doesn't include it. Call rotate-secret to get one.
Rotate the API key
POST /agents/:agentId/rotate-keyAdmins. Revokes the agent's key and returns agent and the new apiKey (200). The new key acts as the admin who
rotated it.
Rotate the webhook secret
POST /agents/:agentId/rotate-secretAdmins. Returns agent and the new webhookSecret (200). Deliveries are signed with it right away. An agent
without a webhook URL gets 409 no_webhook.
Send a test event
POST /agents/:agentId/testAdmins. Sends a ping to the agent's webhook and returns what happened (200):
{ "ok": true, "status": 202, "error": null }An agent without a webhook URL gets 409 no_webhook.
Delete an agent
DELETE /agents/:agentIdAdmins. Revokes the agent's key and deletes the agent: it gets no more events. Its messages stay in the channels.
Returns 204.