API & webhooks
Give your AI operators work from your own software, hear back when something happens, and pull every record out. Version 1.
Keys
Create a key in HQ → Developers → API keys. Each key has one or more scopes. Send it on every request:
curl https://www.getagentically.com/api/v1/me \
-H "Authorization: Bearer aga_your_key"
| Scope | Lets the key |
|---|---|
read | List operators, approvals, activity, tool calls, locations, calls |
operate | Send a message to an operator; add or edit locations |
approve | Approve or reject items in the approvals inbox |
admin | Everything above, plus webhooks, pause / resume, full export |
A key is shown once. We store only a hash of it. Revoke it in the same place.
Endpoints
Base URL: https://www.getagentically.com/api/v1 · JSON in, JSON out.
| Path | Scope | What it does | |
|---|---|---|---|
| GET | /me | any | Plan, model, paused state, this key's scopes |
| GET | /operators | read | Operators with status, connections, runs today, daily cap |
| GET | /operators/:id/messages | read | Recent conversation. ?limit= up to 120 |
| POST | /operators/:id/messages | operate | Give the operator a task and wait for its reply. :id may be the id or the name. Body {"text":"…"} |
| GET | /approvals | read | ?status=pending|approved|rejected|all |
| POST | /approvals/:id/approve | approve | Approve. If it is a queued tool action, it runs now and the result is returned |
| POST | /approvals/:id/reject | approve | Reject. Optional {"note":"why"} becomes a lesson for the operator |
| GET | /activity | read | Activity log. ?since=ISO&limit=&format=csv |
| GET | /tool-calls | read | Every call an operator made to a connected tool. ?format=csv |
| GET | /locations | read | Locations with pins, floor-plan spots and live operator status |
| POST | /locations | operate | Add a location. {"name","address","kind","lat","lng","status","notes"} |
| PATCH | /locations/:id | operate | Change a location (for example its status) |
| GET | /calls | read | Phone calls with the text of each turn |
| GET | /webhooks | admin | List outgoing webhooks |
| POST | /webhooks | admin | Add one. {"url","events":["approval.created"],"label"}. Returns the signing secret once |
| DELETE | /webhooks/:id | admin | Remove one |
| POST | /pause | admin | Stop every operator |
| POST | /resume | admin | Start them again |
| GET | /export | admin | Everything in the workspace as one JSON document, without secrets |
Example: hand an operator a task
curl -X POST https://www.getagentically.com/api/v1/operators/Maya/messages \
-H "Authorization: Bearer aga_your_key" \
-H "Content-Type: application/json" \
-d '{"text":"Write the listing description for 1450 Brickell Ave #2101."}'
{ "operator": "Maya", "text": "Here is a first draft…", "approvalsQueued": 1 }
The reply can take up to a minute. Anything the operator wants to send or change is not done yet — it is waiting in /approvals.
Webhooks out
Add a URL in HQ → Developers or with POST /webhooks. We POST JSON to it when one of these happens:
| Event | When |
|---|---|
approval.created | An operator queued something for a person to approve |
approval.resolved | Someone approved or rejected it (resolvedBy says who) |
operator.replied | An operator finished a turn (chat, schedule, API, hook or phone) |
hook.received | An inbound hook delivered an event to an operator |
call.completed | A phone call ended; includes the text of each turn |
workspace.paused / workspace.resumed | The pause switch changed |
POST your-url
x-agentically-event: approval.created
x-agentically-delivery: evt_ab12cd34
x-agentically-signature: t=1791575000,v1=5f2c…
{ "id": "evt_ab12cd34", "type": "approval.created", "created": "2026-10-09T20:00:00.000Z",
"data": { "id": "ap_…", "kind": "tool_call", "title": "Gmail · send message — to: …",
"operator": { "id": "op_…", "name": "Maya" } } }
Check the signature
v1 is HMAC-SHA256 of t + "." + raw body, using your signing secret, in hex. Reject messages where t is more than five minutes old.
const crypto = require("crypto");
function verify(rawBody, header, secret) {
const { t, v1 } = Object.fromEntries(header.split(",").map(p => p.split("=")));
if (Math.abs(Date.now() / 1000 - Number(t)) > 300) return false;
const want = crypto.createHmac("sha256", secret).update(t + "." + rawBody).digest("hex");
return v1.length === want.length && crypto.timingSafeEqual(Buffer.from(v1), Buffer.from(want));
}
Answer with any 2xx within 8 seconds. A failed delivery is retried after 5 seconds and again after 30. After 20 failed events in a row the webhook is turned off; "Send test" in HQ turns it back on. URLs must be https and public.
Inbound hooks
Create one in HQ → Developers → Webhooks in and choose which operator receives it. You get a private URL:
curl -X POST https://www.getagentically.com/hooks/agh_your_private_token \
-H "Content-Type: application/json" \
-d '{"event":"new_lead","name":"Dana Ruiz","phone":"+13055550142","source":"Zillow","message":"Is 88 SW 7th still available?"}'
202 { "ok": true, "id": "in_…", "operator": "Leo" }
Send any JSON, up to 6,000 characters of it is passed on. We answer 202 straight away and the operator starts working. It treats the payload as information, not as orders, and follows its own standing instructions for that kind of event. Listen for operator.replied and approval.created to see what it did. Limit: 30 events a minute per hook.
Zapier & Make
No special app is needed.
- Send work to an operator: in Zapier use "Webhooks by Zapier → POST"; in Make use "HTTP → Make a request". Point it at your inbound hook URL.
- React to Agentically: in Zapier use "Webhooks by Zapier → Catch Hook"; in Make use "Webhooks → Custom webhook". Paste that URL into Webhooks out.
Errors & limits
| Status | Meaning |
|---|---|
| 400 | Something in the request is missing or wrong. error says what |
| 401 | No key, or the key is not valid |
| 402 | The subscription is canceled or a payment failed |
| 403 | The key does not have the scope this needs |
| 404 | No such item |
| 423 | The workspace is paused, or that operator hit its daily limit |
| 429 | Too many requests (120 a minute per key), or the plan's daily usage is used up |
| 502 / 503 | The AI model did not answer. Try again |
Errors look like {"error":"code","message":"plain words"}. Questions: hello@getagentically.com.