Use the REST API
Every command is one POST with a JSON body. The examples use a local instance on port 8080 and an agent token in $AGENT_TOKEN.
The shape of every call
POST /api/{model}/{command}
Authorization: Bearer <token>
Content-Type: application/json
{ ...input... }model and command are the two halves of the command id: lead.search is POST /api/lead/search. The response is JSON:
{"denied": [], "value": ...}value is the result and denied lists field names withheld from this caller. Other endpoints: GET /api/commands (what this token may call), GET /api/meta (models, fields and actions this token may see), POST /api/approve/{plan_id} (a person approves a plan) and the two /api/auth/ endpoints from Create an agent token. The full list is in the REST reference.
See what the token may do
curl -s http://127.0.0.1:8080/api/commands -H "Authorization: Bearer $AGENT_TOKEN"{
"commands": [
{ "id": "lead.create", "description": "Create a record", "needs_approval": false },
{
"id": "lead.delete",
"description": "Delete a record that no other record refers to",
"needs_approval": true
},
{
"id": "lead.qualify",
"description": "Move a new lead to the qualified stage",
"needs_approval": false
}
]
}needs_approval tells the agent in advance which commands it can only propose.
Read, with masking
curl -s -X POST http://127.0.0.1:8080/api/party/list \
-H "Authorization: Bearer $AGENT_TOKEN" -H 'content-type: application/json' -d '{}'{
"denied": ["party.tax_id"],
"value": [
{
"email": "EMAIL_1",
"id": "01a1464f-b0c8-700e-9f39-0cbf8e848c0b",
"name": "NAME_2",
"notes": "NOTES_3"
}
]
}The tax identifier is withheld and named in denied. Name, email and notes are personal data and come back as tokens.
Search and filter
search takes the same input as list and also returns the total before paging. Filters and sorting only work on fields the agent can read in clear.
curl -s -X POST http://127.0.0.1:8080/api/lead/search \
-H "Authorization: Bearer $AGENT_TOKEN" -H 'content-type: application/json' \
-d '{"filter":[{"field":"stage","op":"eq","value":"new"}],
"order":[{"field":"expected_revenue_minor","dir":"desc"}],
"limit":10}'{
"denied": [],
"value": {
"rows": [
{
"id": "...",
"stage": "new",
"title": "Fleet telematics",
"expected_revenue_minor": 3125000,
"contact_email": "CONTACT_EMAIL_7",
"contact_name": "CONTACT_NAME_8"
}
],
"total": 1
}
}Operators: eq, ne, contains, in, gt, gte, lt, lte, is_null. At most 50 conditions, 5 order keys and 5000 rows per call.
Create and update
curl -s -X POST http://127.0.0.1:8080/api/lead/create \
-H "Authorization: Bearer $AGENT_TOKEN" -H 'content-type: application/json' \
-d '{"title":"Support renewal","contact_name":"NAME_2","contact_email":"EMAIL_1"}'Money is an integer in minor units (3125000 is 31,250.00). Dates are YYYY-MM-DD. The tokens NAME_2 and EMAIL_1 were read earlier; the server swaps them for the real values on write and the agent never sees them. See Masking tokens.
update takes the record id and the fields to change:
curl -s -X POST http://127.0.0.1:8080/api/lead/update \
-H "Authorization: Bearer $AGENT_TOKEN" -H 'content-type: application/json' \
-d '{"id":"01a14650-41ae-7455-9566-1ec1a313bdf3","expected_revenue_minor":3500000}'Run a workflow action
curl -s -X POST http://127.0.0.1:8080/api/lead/qualify \
-H "Authorization: Bearer $AGENT_TOKEN" -H 'content-type: application/json' \
-d '{"id":"01a14650-41ae-7455-9566-1ec1a313bdf3"}'An action that needs approval answers 202 instead; see the next section.
Propose something that needs approval
curl -si -X POST http://127.0.0.1:8080/api/lead/delete \
-H "Authorization: Bearer $AGENT_TOKEN" -H 'content-type: application/json' \
-d '{"id":"01a14650-41ae-7455-9566-1ec1a313bdf3"}'HTTP/1.1 202 Accepted
{"approval_required":true,"plan_id":"01a14650-41d3-7205-b97a-20fa74bb3420"}Nothing has changed. Give the plan id to a person; see The approval loop.
Status codes
| Code | Meaning |
|---|---|
| 200 | Done. Read value and denied. |
| 202 | Approval required. plan_id is in the body. Nothing changed. |
| 400 | The input was refused. error says why, for example lead.title is required or invalid token. |
| 401 | No bearer token, or an unknown, expired or revoked one. |
| 404 | The command does not exist, is not visible to this token, or the plan is unknown. All three look the same on purpose. |
| 415 | The body was not sent as application/json. |
| 429 | Too many failed sign-ins (five in a minute lock a username for a minute). |
Tips for agents
- Start with
GET /api/commandsandGET /api/metaso the agent learns the model instead of guessing. - Send small, specific calls. A
searchwith afilterand alimitbeats listing everything. - Treat
deniedas information: that field exists but is not for this agent.