Agents API reference
Updated
6 operations of the Fax for Agents API, from the OpenAPI document version 1.20.0, snapshot of 2026-11-13. The base URL is https://api.faxforagents.com/v1. This is one group of the full reference.
- Setting enabled to false on an agent revokes every key of that agent.
- An agent key is never issued approval:decide, key:admin, policy:admin or agent:admin.
- The purpose of an agent is shown to people and is never evaluated by the server.
Operations
GET /v1/agentsList agent identitiesPOST /v1/agentsRegister an agent identityGET /v1/agents/{agent_id}Read an agent with its keys and budgetsPATCH /v1/agents/{agent_id}Change an agent; disabling revokes its keysGET /v1/agents/{agent_id}/activityThe agent's audit trailPOST /v1/agents/{agent_id}/keysMint a key for the agent (bounded scopes, secret shown once)
What is an agent identity in the API?
An agent identity is a named principal inside your organization. It has a name, a purpose written for people, a contact address, a list of policies and a status. A fax sent with one of its keys is recorded against the agent. The audit trail then says which agent acted, not only which organization.
Registering an agent does not let it send anything. POST /v1/agents writes the identity and answers with its id. The agent can call the API only after a key is minted for it. The read of one agent returns the identity with its keys and its budgets in one answer, so a dashboard needs one call per agent.
How does an agent get its key?
POST /v1/agents/{agent_id}/keys mints a key that belongs to the agent. The body can name a label, an environment, a number of days until it expires and a list of scopes. Leave the scopes out and the key is given the default agent set. The answer carries the secret once. Later reads show the prefix, the scopes and the dates, never the secret.
The scopes are bounded. The schema of the request says an agent key is never issued approval:decide, key:admin, policy:admin or agent:admin. A request that asks for one of them is refused. That boundary is why an agent can ask a person to approve a send and cannot approve its own request. The agents guide lists the full default set and the scopes that are never issued.
What happens when an agent is disabled?
PATCH /v1/agents/{agent_id} changes the name, the purpose, the contact address and the policy list. It also takes enabled. Sending false disables the agent and revokes each of its keys in the same call, so none of its keys outlives the identity.
Disabling is the fast way to stop one agent without touching the others. Keys of other agents and keys of the organization keep working.
Where do I see what an agent did?
GET /v1/agents/{agent_id}/activity returns the audit rows of one agent, a page at a time. It takes cursor and limit, and each page carries next_cursor while more rows remain. The rows hold metadata about each action. They never hold the content of a document.
Which scopes do these calls need?
Reading the list, one agent or its activity needs agent:read. Registering an agent, changing it and minting a key for it need agent:admin. Each operation below states its own scope on its credential line, read from the OpenAPI document.
Agent keys cannot run the admin calls of this group. A person does that from a signed-in session, or a key of the organization that holds agent:admin does it from a script. The list call returns every agent of the organization in the environment of the credential.
How do agents relate to policies and budgets?
An agent names its policies in policy_ids. A delegated policy says where the agent may send and how much, and the server evaluates it on each send. A budget is a spending cap. The read of an agent returns its budgets. The cap itself is created in the billing group with the agent's id.
The three together bound one agent. Its scopes say which calls it may make. The policy says which sends are allowed without a person. The budget says how much it may spend.
Each operation in detail
GET /v1/agents
List agent identities
Credential: an API key or a signed-in session. Scope: agent:read.
Responses
| Status | Meaning |
|---|---|
200 | Successful Response |
401 | No credential, or one that was not accepted: invalid_token for an API key, unauthenticated where a signed-in session is needed. error.details.reason says why a key was refused. |
403 | The credential is valid and is not allowed to do this. scope_missing puts the scope in error.details.scope. Other codes are agent_forbidden and approval_required. A session can also meet csrf_invalid and reauth_required. |
429 | rate_limited. Retry-After and the RateLimit-* headers say when to try again. |
Response fields
| Field | Type | Required | Description |
|---|---|---|---|
items | array of object Agent | yes |
Example
curl https://api.faxforagents.com/v1/agents \
-H "Authorization: Bearer ffa_test_..."
POST /v1/agents
Register an agent identity
Credential: an API key or a signed-in session. Scope: agent:admin.
Parameters
| Name | In | Type | Required | Notes |
|---|---|---|---|---|
Idempotency-Key | header | string | no | Replay the first successful response for the same request within 24 hours. Reusing the idempotency header with a different request returns 409 idempotency_key_conflict. Responses include Idempotent-Replayed: true on replay. |
Request body application/json, required
| Field | Type | Required | Description |
|---|---|---|---|
contact_email | string or null | no | Where decided approvals are mailed. |
name | string | yes | |
policy_ids | array of string | no | |
purpose | string or null | no | Shown to humans, never evaluated. |
Responses
| Status | Meaning |
|---|---|
201 | Successful Response |
401 | No credential, or one that was not accepted: invalid_token for an API key, unauthenticated where a signed-in session is needed. error.details.reason says why a key was refused. |
403 | The credential is valid and is not allowed to do this. scope_missing puts the scope in error.details.scope. Other codes are agent_forbidden and approval_required. A session can also meet csrf_invalid and reauth_required. |
404 | not_found: no such resource for this credential. A resource of another organization answers the same. |
409 | The resource is in a state that refuses the call, or the Idempotency-Key was used with a different request (idempotency_key_conflict). error.code names the state. |
422 | A field failed validation: invalid_request, with one entry per field in error.details, or a code that names the rule. |
429 | rate_limited. Retry-After and the RateLimit-* headers say when to try again. |
Response fields
| Field | Type | Required | Description |
|---|---|---|---|
budget_id | string or null | yes | |
budgets | array of object | yes | |
contact_email | string or null | yes | |
created_at | string | yes | |
created_by | string | yes | |
disabled_at | string or null | yes | |
enabled | boolean | yes | |
id | string | yes | |
keys | array of object ApiKey | yes | |
name | string | yes | |
policy_ids | array of string | yes | |
project_id | string or null | yes | |
purpose | string or null | yes | |
status | string | yes | |
updated_at | string | yes |
Example
curl https://api.faxforagents.com/v1/agents \
-X POST \
-H "Authorization: Bearer ffa_test_..." \
-H "Content-Type: application/json" \
-d '{"name":"example"}'
GET /v1/agents/{agent_id}
Read an agent with its keys and budgets
Credential: an API key or a signed-in session. Scope: agent:read.
Parameters
| Name | In | Type | Required | Notes |
|---|---|---|---|---|
agent_id | path | string | yes |
Responses
| Status | Meaning |
|---|---|
200 | Successful Response |
401 | No credential, or one that was not accepted: invalid_token for an API key, unauthenticated where a signed-in session is needed. error.details.reason says why a key was refused. |
403 | The credential is valid and is not allowed to do this. scope_missing puts the scope in error.details.scope. Other codes are agent_forbidden and approval_required. A session can also meet csrf_invalid and reauth_required. |
404 | not_found: no such resource for this credential. A resource of another organization answers the same. |
422 | A field failed validation: invalid_request, with one entry per field in error.details, or a code that names the rule. |
429 | rate_limited. Retry-After and the RateLimit-* headers say when to try again. |
Response fields
| Field | Type | Required | Description |
|---|---|---|---|
budget_id | string or null | yes | |
budgets | array of object | yes | |
contact_email | string or null | yes | |
created_at | string | yes | |
created_by | string | yes | |
disabled_at | string or null | yes | |
enabled | boolean | yes | |
id | string | yes | |
keys | array of object ApiKey | yes | |
name | string | yes | |
policy_ids | array of string | yes | |
project_id | string or null | yes | |
purpose | string or null | yes | |
status | string | yes | |
updated_at | string | yes |
Example
curl https://api.faxforagents.com/v1/agents/AGENT_ID \
-H "Authorization: Bearer ffa_test_..."
PATCH /v1/agents/{agent_id}
Change an agent; disabling revokes its keys
Credential: an API key or a signed-in session. Scope: agent:admin.
Parameters
| Name | In | Type | Required | Notes |
|---|---|---|---|---|
agent_id | path | string | yes | |
Idempotency-Key | header | string | no | Replay the first successful response for the same request within 24 hours. Reusing the idempotency header with a different request returns 409 idempotency_key_conflict. Responses include Idempotent-Replayed: true on replay. |
Request body application/json, required
| Field | Type | Required | Description |
|---|---|---|---|
contact_email | string or null | no | |
enabled | boolean or null | no | false revokes every key of the agent. |
name | string or null | no | |
policy_ids | array of string or null | no | |
purpose | string or null | no |
Responses
| Status | Meaning |
|---|---|
200 | Successful Response |
401 | No credential, or one that was not accepted: invalid_token for an API key, unauthenticated where a signed-in session is needed. error.details.reason says why a key was refused. |
403 | The credential is valid and is not allowed to do this. scope_missing puts the scope in error.details.scope. Other codes are agent_forbidden and approval_required. A session can also meet csrf_invalid and reauth_required. |
404 | not_found: no such resource for this credential. A resource of another organization answers the same. |
409 | The resource is in a state that refuses the call, or the Idempotency-Key was used with a different request (idempotency_key_conflict). error.code names the state. |
422 | A field failed validation: invalid_request, with one entry per field in error.details, or a code that names the rule. |
429 | rate_limited. Retry-After and the RateLimit-* headers say when to try again. |
Response fields
| Field | Type | Required | Description |
|---|---|---|---|
budget_id | string or null | yes | |
budgets | array of object | yes | |
contact_email | string or null | yes | |
created_at | string | yes | |
created_by | string | yes | |
disabled_at | string or null | yes | |
enabled | boolean | yes | |
id | string | yes | |
keys | array of object ApiKey | yes | |
name | string | yes | |
policy_ids | array of string | yes | |
project_id | string or null | yes | |
purpose | string or null | yes | |
status | string | yes | |
updated_at | string | yes |
Example
curl https://api.faxforagents.com/v1/agents/AGENT_ID \
-X PATCH \
-H "Authorization: Bearer ffa_test_..." \
-H "Content-Type: application/json" \
-d '{}'
GET /v1/agents/{agent_id}/activity
The agent's audit trail
Credential: an API key or a signed-in session. Scope: agent:read.
Parameters
| Name | In | Type | Required | Notes |
|---|---|---|---|---|
agent_id | path | string | yes | |
cursor | query | string or null | no | |
limit | query | integer | no | Default 50. |
Responses
| Status | Meaning |
|---|---|
200 | Successful Response |
401 | No credential, or one that was not accepted: invalid_token for an API key, unauthenticated where a signed-in session is needed. error.details.reason says why a key was refused. |
403 | The credential is valid and is not allowed to do this. scope_missing puts the scope in error.details.scope. Other codes are agent_forbidden and approval_required. A session can also meet csrf_invalid and reauth_required. |
404 | not_found: no such resource for this credential. A resource of another organization answers the same. |
422 | A field failed validation: invalid_request, with one entry per field in error.details, or a code that names the rule. |
429 | rate_limited. Retry-After and the RateLimit-* headers say when to try again. |
Response fields
| Field | Type | Required | Description |
|---|---|---|---|
items | array of object AgentActivity | yes | |
next_cursor | string or null | no |
Example
curl https://api.faxforagents.com/v1/agents/AGENT_ID/activity \
-H "Authorization: Bearer ffa_test_..."
POST /v1/agents/{agent_id}/keys
Mint a key for the agent (bounded scopes, secret shown once)
Credential: an API key or a signed-in session. Scope: agent:admin.
Parameters
| Name | In | Type | Required | Notes |
|---|---|---|---|---|
agent_id | path | string | yes | |
Idempotency-Key | header | string | no | Replay the first successful response for the same request within 24 hours. Reusing the idempotency header with a different request returns 409 idempotency_key_conflict. Responses include Idempotent-Replayed: true on replay. |
Request body application/json, required
| Field | Type | Required | Description |
|---|---|---|---|
environment | string (live, test) | no | |
expires_in_days | integer or null | no | |
label | string | no | |
scopes | array of string or null | no | Omit for the default agent set. Never approval:decide, key:admin, policy:admin, agent:admin. |
Responses
| Status | Meaning |
|---|---|
201 | Successful Response |
401 | No credential, or one that was not accepted: invalid_token for an API key, unauthenticated where a signed-in session is needed. error.details.reason says why a key was refused. |
403 | The credential is valid and is not allowed to do this. scope_missing puts the scope in error.details.scope. Other codes are agent_forbidden and approval_required. A session can also meet csrf_invalid and reauth_required. |
404 | not_found: no such resource for this credential. A resource of another organization answers the same. |
409 | The resource is in a state that refuses the call, or the Idempotency-Key was used with a different request (idempotency_key_conflict). error.code names the state. |
422 | A field failed validation: invalid_request, with one entry per field in error.details, or a code that names the rule. |
429 | rate_limited. Retry-After and the RateLimit-* headers say when to try again. |
Response fields
| Field | Type | Required | Description |
|---|---|---|---|
agent_id | string or null | yes | |
connected_app | boolean | no | The key belongs to a connected app used over stdio, such as the Gemini CLI extension. The organization's auto-send setting (Settings, Connected apps) binds it like an OAuth connection. |
created_at | string | yes | |
environment | string (live, test) | yes | |
expires_at | string or null | yes | |
id | string | yes | |
label | string | yes | |
last_used_at | string or null | yes | |
prefix | string | yes | |
project_id | string or null | yes | |
revoked_at | string or null | yes | |
rotated_from_id | string or null | yes | |
scopes | array of string | yes | |
secret | string | yes | Shown once. Store it now; it cannot be read back. |
Example
curl https://api.faxforagents.com/v1/agents/AGENT_ID/keys \
-X POST \
-H "Authorization: Bearer ffa_test_..." \
-H "Content-Type: application/json" \
-d '{}'