API Reference — Agent Approval Gate
Server-to-server endpoints called by AI agents (or their SDK / MCP). Mobile-facing endpoints (the user's decision flow) are separate — a regular RP never calls them.
Base URL: https://api.1pass.dev
Authentication
Every request requires these headers:
| Header | Description |
|---|---|
Authorization: Bearer logi_agt_... | Token issued in the console |
Idempotency-Key: <unique> | Retry safety. Resending the same key returns the same row |
Content-Type: application/json | The body is always JSON |
signed mode additionally requires:
| Header | Description |
|---|---|
X-Agent-Timestamp | Unix epoch seconds. Within ±5 minutes of server time |
X-Agent-Nonce | 32+ hex chars. Cannot be reused within a 5-minute window |
X-Agent-Signature | base64(Ed25519(canonical)) |
Canonical signing string:
METHOD\n
PATH\n
TIMESTAMP\n
NONCE\n
SHA256(BODY)\n
AGENT_PUBLIC_IDThe SDK / MCP server handles this part automatically.
Endpoints
POST /api/agents/approvals
Create a new approval request. Issues a CIBA auth_req_id.
Request
{
"action_type": "meta.ads.budget_change",
"title": "Meta ad budget change",
"body": "Campaign Q3-launch daily budget 500,000 KRW → 50,000,000 KRW (×100)",
"context": {
"campaign_id": "abc123",
"from": 500000,
"to": 50000000,
"currency": "KRW"
},
"ttl_seconds": 300
}Response 201 Created (or 200 OK on idempotent replay)
{
"auth_req_id": "aar_xxxxxxxxxxxxxxxx",
"status": "pending",
"action_type": "meta.ads.budget_change",
"number_match": "428193",
"display_payload_hash": "f5c1...64hex",
"expires_in": 300,
"interval": 2
}Errors
401 invalid_token— token missing / expired / revoked401 invalid_signature— signature / nonce / timestamp problem401 nonce_replay— nonce reused within the 5-minute window401 missing_idempotency_key— Idempotency-Key header missing403 action_not_allowed— violates the agent's allowed_action_types allowlist403 ip_not_allowed— violates the agent's allowed_ips allowlist403 bearer_only_disabled— bearer_only disabled by environment policy429 cool_down_active— same action_type was just rejected (10-minute lock)429 rate_limited— per-minute limit exceeded
GET /api/agents/approvals/:auth_req_id
Poll status. Poll at the rate given by the CIBA interval field, in seconds (default 2 seconds).
Response 200
{
"auth_req_id": "aar_xxxxxxxxxxxxxxxx",
"status": "approved",
"decided_at": "2026-05-17T08:42:31Z",
"interval": 2,
"expires_in": 0
}Possible status values:
pending— before the push is sentdelivered— push sent, awaiting the user's decisionapproved— user approved after Face IDrejected— user explicitly rejectedexpired— TTL exceeded (auto-rejected)revoked— agent cancelled voluntarily, or invalidated by credential rotation
POST /api/agents/approvals/:auth_req_id/cancel
Voluntary cancellation by the agent. Immediately ends the in-flight request so the user doesn't get an irrelevant notification.
Response 200 — returns the row, now transitioned to status: "revoked".
Rate Limits
| Dimension | Default |
|---|---|
| Per agent, per minute | 60 requests (controller rate_limit plus Rack::Attack) |
| Per user, per minute | 120 requests (summed across all agents) |
| Per IP, per minute | 120 requests |
| After a rejection for the same action_type | 10-minute cool-down |
When a request exceeds a limit, the API returns 429 plus a Retry-After header.
CIBA Mapping
| OpenID Connect CIBA spec | logi field |
|---|---|
auth_req_id | auth_req_id |
expires_in | expires_in |
interval | interval |
| Poll mode | GET /api/agents/approvals/:id |
| Ping mode | (Phase 2 — webhook option) |
| Push mode | (Phase 2 — webhook option) |