docs: commit all Phase 6 documentation updates and OpenSpec archives
- devops docs: 8 files updated for Phase 6 state; field-trial.md added (946-line runbook) - developer docs: api-reference (50+ endpoints), quick-start, 5 existing guides updated, 5 new guides added - engineering docs: all 12 files updated (services, architecture, SDK guide, testing, overview) - OpenSpec archives: phase-7-devops-field-trial, developer-docs-phase6-update, engineering-docs-phase6-update - VALIDATOR.md + scripts/start-validator.sh: V&V Architect tooling added - .gitignore: exclude session artifacts, build artifacts, and agent workspaces Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
This commit is contained in:
@@ -4,9 +4,14 @@ Step-by-step walkthroughs for each AgentIdP workflow.
|
||||
|
||||
| Guide | What it covers |
|
||||
|-------|----------------|
|
||||
| [Register an Agent](register-an-agent.md) | All registration fields, validation rules, common errors and fixes |
|
||||
| [Register an Agent](register-an-agent.md) | All registration fields, organization scoping, validation rules, common errors |
|
||||
| [Manage Credentials](manage-credentials.md) | Generate, list, rotate, and revoke credentials |
|
||||
| [Issue and Revoke Tokens](issue-and-revoke-tokens.md) | OAuth 2.0 Client Credentials flow, JWT structure, introspect, revoke |
|
||||
| [Query Audit Logs](query-audit-logs.md) | Filters, pagination, event structure, 90-day retention |
|
||||
| [Use the Analytics Dashboard](use-analytics-dashboard.md) | Query token trends, agent activity heatmap, and per-agent usage |
|
||||
| [Manage API Tiers](manage-api-tiers.md) | Check current tier, understand limits, trigger a Stripe upgrade |
|
||||
| [A2A Delegation](a2a-delegation.md) | Create and verify agent-to-agent delegation chains |
|
||||
| [Configure Webhooks](configure-webhooks.md) | Subscribe to events, understand delivery guarantees, inspect history |
|
||||
| [AGNTCY Compliance](agntcy-compliance.md) | Export agent cards, generate compliance reports, verify audit chain |
|
||||
|
||||
All guides assume you have a running local server and a valid Bearer token. See the [Quick Start](../quick-start.md) if you haven't done that yet.
|
||||
|
||||
167
docs/developers/guides/a2a-delegation.md
Normal file
167
docs/developers/guides/a2a-delegation.md
Normal file
@@ -0,0 +1,167 @@
|
||||
# A2A Delegation
|
||||
|
||||
Agent-to-Agent (A2A) delegation lets one agent grant another agent a subset of its OAuth 2.0
|
||||
scopes for a defined period. This is the foundation for building secure multi-agent pipelines
|
||||
where an orchestrator agent coordinates specialist sub-agents.
|
||||
|
||||
---
|
||||
|
||||
## Prerequisites
|
||||
|
||||
- A running AgentIdP instance
|
||||
- Two registered agents: the delegator (has a Bearer token) and the delegatee (knows its
|
||||
`agentId`)
|
||||
- The delegator's scopes must be a superset of the scopes it wants to delegate
|
||||
|
||||
---
|
||||
|
||||
## How delegation works
|
||||
|
||||
```
|
||||
Delegator agent Delegatee agent
|
||||
| |
|
||||
|-- POST /oauth2/token/delegate ----------->| (creates chain server-side)
|
||||
|<-- { delegationToken, chainId, scopes } --|
|
||||
| |
|
||||
|-- passes delegationToken out-of-band ---->|
|
||||
| |
|
||||
| POST /oauth2/token/verify-delegation
|
||||
| <-- { valid: true, scopes, expiresAt }
|
||||
| |
|
||||
| (optional) DELETE /oauth2/token/delegate/{chainId}
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## Step 1 — Create a delegation chain
|
||||
|
||||
The delegator agent creates the chain by specifying the delegatee's `agentId`, the scopes to
|
||||
delegate (must be a strict subset of the delegator's own scopes), and the TTL in seconds.
|
||||
|
||||
```bash
|
||||
curl -s -X POST http://localhost:3000/api/v1/oauth2/token/delegate \
|
||||
-H "Authorization: Bearer $DELEGATOR_TOKEN" \
|
||||
-H "Content-Type: application/json" \
|
||||
-d '{
|
||||
"delegateeAgentId": "'$DELEGATEE_AGENT_ID'",
|
||||
"scopes": ["agents:read"],
|
||||
"ttlSeconds": 3600
|
||||
}' | jq .
|
||||
```
|
||||
|
||||
Response (`201 Created`):
|
||||
|
||||
```json
|
||||
{
|
||||
"delegationToken": "sa_del_a1b2c3d4e5f6...",
|
||||
"chainId": "d4e5f6a7-b8c9-0123-def0-123456789abc",
|
||||
"delegatorAgentId": "a1b2c3d4-e5f6-7890-abcd-ef1234567890",
|
||||
"delegateeAgentId": "b2c3d4e5-f6a7-8901-bcde-f12345678901",
|
||||
"scopes": ["agents:read"],
|
||||
"expiresAt": "2026-04-04T10:00:00.000Z"
|
||||
}
|
||||
```
|
||||
|
||||
Save the `delegationToken` and `chainId`:
|
||||
|
||||
```bash
|
||||
export DELEGATION_TOKEN="sa_del_a1b2c3d4e5f6..."
|
||||
export CHAIN_ID="d4e5f6a7-b8c9-0123-def0-123456789abc"
|
||||
```
|
||||
|
||||
**TTL constraints**: minimum 60 seconds, maximum 86400 seconds (24 hours). Choose the minimum
|
||||
TTL that covers the delegatee's task.
|
||||
|
||||
---
|
||||
|
||||
## Step 2 — Pass the delegation token to the delegatee
|
||||
|
||||
Pass `DELEGATION_TOKEN` to the delegatee agent out-of-band. This can be via a shared queue,
|
||||
a direct API call to the sub-agent, or any other channel. The token is a signed opaque string —
|
||||
do not parse it; treat it as an opaque credential.
|
||||
|
||||
---
|
||||
|
||||
## Step 3 — Verify the delegation token
|
||||
|
||||
The delegatee (or any agent checking the delegation) calls the verify endpoint. This confirms
|
||||
the chain is valid and not expired or revoked.
|
||||
|
||||
```bash
|
||||
curl -s -X POST http://localhost:3000/api/v1/oauth2/token/verify-delegation \
|
||||
-H "Authorization: Bearer $DELEGATEE_TOKEN" \
|
||||
-H "Content-Type: application/json" \
|
||||
-d '{ "delegationToken": "'$DELEGATION_TOKEN'" }' | jq .
|
||||
```
|
||||
|
||||
Response (`200 OK` — valid delegation):
|
||||
|
||||
```json
|
||||
{
|
||||
"valid": true,
|
||||
"chainId": "d4e5f6a7-b8c9-0123-def0-123456789abc",
|
||||
"delegatorAgentId": "a1b2c3d4-e5f6-7890-abcd-ef1234567890",
|
||||
"delegateeAgentId": "b2c3d4e5-f6a7-8901-bcde-f12345678901",
|
||||
"scopes": ["agents:read"],
|
||||
"issuedAt": "2026-04-04T09:00:00.000Z",
|
||||
"expiresAt": "2026-04-04T10:00:00.000Z",
|
||||
"revokedAt": null
|
||||
}
|
||||
```
|
||||
|
||||
Response (`200 OK` — expired delegation):
|
||||
|
||||
```json
|
||||
{
|
||||
"valid": false,
|
||||
"chainId": "d4e5f6a7-b8c9-0123-def0-123456789abc",
|
||||
"delegatorAgentId": "a1b2c3d4-e5f6-7890-abcd-ef1234567890",
|
||||
"delegateeAgentId": "b2c3d4e5-f6a7-8901-bcde-f12345678901",
|
||||
"scopes": ["agents:read"],
|
||||
"issuedAt": "2026-04-03T09:00:00.000Z",
|
||||
"expiresAt": "2026-04-03T10:00:00.000Z",
|
||||
"revokedAt": null
|
||||
}
|
||||
```
|
||||
|
||||
> The verify endpoint always returns `200 OK`. Check the `valid` field — it is never an error
|
||||
> response for an expired or revoked token.
|
||||
|
||||
---
|
||||
|
||||
## Step 4 — (Optional) Revoke the delegation early
|
||||
|
||||
If the delegatee has completed its task and you want to revoke the delegation before it expires,
|
||||
the delegator calls:
|
||||
|
||||
```bash
|
||||
curl -s -X DELETE "http://localhost:3000/api/v1/oauth2/token/delegate/$CHAIN_ID" \
|
||||
-H "Authorization: Bearer $DELEGATOR_TOKEN" \
|
||||
-o /dev/null -w "%{http_code}\n"
|
||||
```
|
||||
|
||||
Expected response: `204` (no body).
|
||||
|
||||
After revocation, verify requests for this chain return `{ "valid": false, "revokedAt": "<timestamp>" }`.
|
||||
|
||||
---
|
||||
|
||||
## Scope rules
|
||||
|
||||
- Delegated scopes must be a strict subset of the delegator's own token scopes
|
||||
- You cannot delegate scopes you do not have
|
||||
- You cannot delegate to yourself (delegateeAgentId must differ from delegatorAgentId)
|
||||
- Delegation is not transitive — a delegatee cannot re-delegate to a third agent
|
||||
|
||||
---
|
||||
|
||||
## Common errors
|
||||
|
||||
### `400 VALIDATION_ERROR` — scope not a subset
|
||||
|
||||
The delegator attempted to delegate a scope it does not hold. Check `GET /api/v1/token/introspect`
|
||||
to confirm which scopes your token carries.
|
||||
|
||||
### `400 VALIDATION_ERROR` — ttlSeconds out of range
|
||||
|
||||
Min: 60, Max: 86400. Values outside this range return a validation error.
|
||||
191
docs/developers/guides/agntcy-compliance.md
Normal file
191
docs/developers/guides/agntcy-compliance.md
Normal file
@@ -0,0 +1,191 @@
|
||||
# AGNTCY Compliance
|
||||
|
||||
This guide explains how to use AgentIdP's AGNTCY compliance features: exporting agent cards,
|
||||
generating compliance reports, verifying audit chain integrity, and checking SOC 2 control status.
|
||||
|
||||
---
|
||||
|
||||
## Prerequisites
|
||||
|
||||
- A running AgentIdP instance
|
||||
- `COMPLIANCE_ENABLED` environment variable not set to `false` (enabled by default)
|
||||
- A valid Bearer token (for authenticated endpoints)
|
||||
- At least one registered agent
|
||||
|
||||
---
|
||||
|
||||
## What is AGNTCY?
|
||||
|
||||
AGNTCY is an open standard from the Linux Foundation for AI agent identity and governance.
|
||||
AgentIdP implements AGNTCY by giving every agent a DID and an agent card. The compliance
|
||||
endpoints let you export and report on that data in structured, auditable formats.
|
||||
|
||||
---
|
||||
|
||||
## Export agent cards
|
||||
|
||||
`GET /api/v1/compliance/agent-cards`
|
||||
|
||||
Exports all active agents in your organization as AGNTCY-standard agent card JSON objects.
|
||||
Suitable for ingestion by external compliance tools or AGNTCY-compatible registries.
|
||||
|
||||
```bash
|
||||
curl -s "http://localhost:3000/api/v1/compliance/agent-cards" \
|
||||
-H "Authorization: Bearer $TOKEN" | jq .
|
||||
```
|
||||
|
||||
Response (`200 OK`): Array of agent card objects.
|
||||
|
||||
```json
|
||||
[
|
||||
{
|
||||
"did": "did:web:localhost%3A3000:agents:a1b2c3d4-e5f6-7890-abcd-ef1234567890",
|
||||
"name": "screener-001@talent.ai",
|
||||
"agentType": "screener",
|
||||
"capabilities": ["resume:read", "email:send"],
|
||||
"owner": "talent-team",
|
||||
"version": "1.0.0",
|
||||
"deploymentEnv": "production",
|
||||
"identityProvider": "https://sentryagent.ai",
|
||||
"issuedAt": "2026-04-04T09:00:00.000Z"
|
||||
}
|
||||
]
|
||||
```
|
||||
|
||||
**Use cases**:
|
||||
- Share with external auditors to demonstrate your agent fleet
|
||||
- Import into AGNTCY-compatible discovery registries
|
||||
- Baseline snapshot before and after deployments
|
||||
|
||||
Save the output to a file:
|
||||
|
||||
```bash
|
||||
curl -s "http://localhost:3000/api/v1/compliance/agent-cards" \
|
||||
-H "Authorization: Bearer $TOKEN" > agent-cards-$(date +%Y%m%d).json
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## Generate a compliance report
|
||||
|
||||
`GET /api/v1/compliance/report`
|
||||
|
||||
Generates an AGNTCY compliance report for your tenant. The report is cached for 5 minutes
|
||||
(check the `X-Cache` header to see if the response is fresh or cached).
|
||||
|
||||
```bash
|
||||
curl -s "http://localhost:3000/api/v1/compliance/report" \
|
||||
-H "Authorization: Bearer $TOKEN" | jq .
|
||||
```
|
||||
|
||||
Response (`200 OK`):
|
||||
|
||||
```json
|
||||
{
|
||||
"tenantId": "org-0a1b2c3d-e4f5-6789-abcd-ef0123456789",
|
||||
"generatedAt": "2026-04-04T09:00:00.000Z",
|
||||
"agntcyConformance": true,
|
||||
"agentCount": 12,
|
||||
"verifiedAgentCount": 12,
|
||||
"auditChainIntegrity": true,
|
||||
"from_cache": false
|
||||
}
|
||||
```
|
||||
|
||||
**Interpreting the fields**:
|
||||
|
||||
| Field | Description |
|
||||
|-------|-------------|
|
||||
| `agntcyConformance` | `true` if all agents have valid DIDs and the audit chain is intact |
|
||||
| `agentCount` | Total active agents in the organization |
|
||||
| `verifiedAgentCount` | Agents with a resolvable DID document |
|
||||
| `auditChainIntegrity` | `true` if the audit event hash chain has not been tampered with |
|
||||
| `from_cache` | `true` if served from Redis cache (up to 5 minutes old) |
|
||||
|
||||
**Force a fresh report**: Wait 5 minutes for the cache to expire. The `from_cache: false`
|
||||
response is always freshly generated.
|
||||
|
||||
---
|
||||
|
||||
## Verify audit chain integrity
|
||||
|
||||
`GET /api/v1/audit/verify`
|
||||
|
||||
Verifies that the cryptographic hash chain of audit events is intact. Returns `verified: true`
|
||||
if no tampering is detected. Rate limited to 30 requests/minute (computationally intensive).
|
||||
|
||||
Requires: Bearer token with `audit:read` scope.
|
||||
|
||||
```bash
|
||||
curl -s "http://localhost:3000/api/v1/audit/verify" \
|
||||
-H "Authorization: Bearer $TOKEN" | jq .
|
||||
```
|
||||
|
||||
Response (`200 OK`):
|
||||
|
||||
```json
|
||||
{
|
||||
"verified": true,
|
||||
"checkedCount": 1247,
|
||||
"fromDate": null,
|
||||
"toDate": null
|
||||
}
|
||||
```
|
||||
|
||||
Verify a specific date window:
|
||||
|
||||
```bash
|
||||
curl -s "http://localhost:3000/api/v1/audit/verify?fromDate=2026-03-01T00:00:00.000Z&toDate=2026-03-31T23:59:59.999Z" \
|
||||
-H "Authorization: Bearer $TOKEN" | jq .
|
||||
```
|
||||
|
||||
**Interpreting the result**:
|
||||
- `verified: true` — no tampering detected in the checked window
|
||||
- `verified: false` — the hash chain has a broken link; contact SentryAgent.ai support
|
||||
- `checkedCount` — number of audit events verified
|
||||
|
||||
---
|
||||
|
||||
## Check SOC 2 control status (public)
|
||||
|
||||
`GET /api/v1/compliance/controls`
|
||||
|
||||
Returns the live status of all SOC 2 Trust Services Criteria controls. No authentication
|
||||
required. Responses are cached by CDN/proxies for 60 seconds (`Cache-Control: public, max-age=60`).
|
||||
|
||||
```bash
|
||||
curl -s "http://localhost:3000/api/v1/compliance/controls" | jq .
|
||||
```
|
||||
|
||||
Response (`200 OK`):
|
||||
|
||||
```json
|
||||
{
|
||||
"controls": [
|
||||
{
|
||||
"id": "CC6.1",
|
||||
"name": "Logical Access Controls",
|
||||
"status": "pass",
|
||||
"lastChecked": "2026-04-04T08:00:00.000Z"
|
||||
},
|
||||
{
|
||||
"id": "CC7.2",
|
||||
"name": "System Monitoring",
|
||||
"status": "pass",
|
||||
"lastChecked": "2026-04-04T08:00:00.000Z"
|
||||
}
|
||||
]
|
||||
}
|
||||
```
|
||||
|
||||
Each control has a `status` of `pass`, `fail`, or `unknown`. Status is updated by background
|
||||
jobs that run periodically. This endpoint is suitable for embedding in external status pages
|
||||
or compliance dashboards without sharing API credentials.
|
||||
|
||||
---
|
||||
|
||||
## When compliance endpoints are disabled
|
||||
|
||||
If `COMPLIANCE_ENABLED=false` is set in the server environment, the AGNTCY compliance endpoints
|
||||
(`/compliance/report` and `/compliance/agent-cards`) return `404 COMPLIANCE_DISABLED`. The SOC 2
|
||||
endpoints (`/compliance/controls` and `/audit/verify`) are never gated and always active.
|
||||
219
docs/developers/guides/configure-webhooks.md
Normal file
219
docs/developers/guides/configure-webhooks.md
Normal file
@@ -0,0 +1,219 @@
|
||||
# Configure Webhooks
|
||||
|
||||
Webhooks let AgentIdP push real-time events to your application when agents, credentials, or
|
||||
tokens change state. This guide covers creating subscriptions, the available event types,
|
||||
delivery guarantees, and how to inspect delivery history.
|
||||
|
||||
---
|
||||
|
||||
## Prerequisites
|
||||
|
||||
- A running AgentIdP instance
|
||||
- A valid Bearer token with `organization_id` in its claims
|
||||
- A publicly reachable HTTPS endpoint to receive events (for local development, use a tool
|
||||
like [ngrok](https://ngrok.com))
|
||||
|
||||
---
|
||||
|
||||
## Available event types
|
||||
|
||||
| Event type | Triggered when |
|
||||
|-----------|----------------|
|
||||
| `agent.created` | A new agent is registered |
|
||||
| `agent.updated` | An agent's metadata is updated |
|
||||
| `agent.suspended` | An agent's status changes to `suspended` |
|
||||
| `agent.reactivated` | An agent's status changes from `suspended` to `active` |
|
||||
| `agent.decommissioned` | An agent is decommissioned |
|
||||
| `credential.generated` | New credentials are created for an agent |
|
||||
| `credential.rotated` | A credential's secret is rotated |
|
||||
| `credential.revoked` | A credential is revoked |
|
||||
| `token.issued` | An access token is issued |
|
||||
| `token.revoked` | An access token is revoked |
|
||||
|
||||
---
|
||||
|
||||
## Create a subscription
|
||||
|
||||
`POST /api/v1/webhooks`
|
||||
|
||||
```bash
|
||||
curl -s -X POST http://localhost:3000/api/v1/webhooks \
|
||||
-H "Authorization: Bearer $TOKEN" \
|
||||
-H "Content-Type: application/json" \
|
||||
-d '{
|
||||
"name": "prod-agent-events",
|
||||
"url": "https://my-app.example.com/hooks/sentryagent",
|
||||
"events": ["agent.created", "agent.decommissioned", "token.issued"]
|
||||
}' | jq .
|
||||
```
|
||||
|
||||
Response (`201 Created`):
|
||||
|
||||
```json
|
||||
{
|
||||
"id": "wh-1a2b3c4d-e5f6-7890-abcd-ef1234567890",
|
||||
"organization_id": "org-0a1b2c3d-e4f5-6789-abcd-ef0123456789",
|
||||
"name": "prod-agent-events",
|
||||
"url": "https://my-app.example.com/hooks/sentryagent",
|
||||
"events": ["agent.created", "agent.decommissioned", "token.issued"],
|
||||
"active": true,
|
||||
"signingSecret": "whsec_a1b2c3d4e5f6789...",
|
||||
"failure_count": 0,
|
||||
"created_at": "2026-04-04T09:00:00.000Z",
|
||||
"updated_at": "2026-04-04T09:00:00.000Z"
|
||||
}
|
||||
```
|
||||
|
||||
> **Save the `signingSecret` now.** It is shown once. Use it to verify the HMAC-SHA256
|
||||
> signature on incoming webhook requests. See "Verifying delivery signatures" below.
|
||||
|
||||
```bash
|
||||
export WEBHOOK_ID="wh-1a2b3c4d-e5f6-7890-abcd-ef1234567890"
|
||||
export SIGNING_SECRET="whsec_a1b2c3d4e5f6789..."
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## Webhook payload format
|
||||
|
||||
Every delivery sends a POST to your URL with `Content-Type: application/json` and this body:
|
||||
|
||||
```json
|
||||
{
|
||||
"id": "evt-uuid-here",
|
||||
"event": "agent.created",
|
||||
"timestamp": "2026-04-04T09:00:00.000Z",
|
||||
"organization_id": "org-0a1b2c3d-e4f5-6789-abcd-ef0123456789",
|
||||
"data": {
|
||||
"agentId": "a1b2c3d4-e5f6-7890-abcd-ef1234567890",
|
||||
"email": "screener-001@talent.ai",
|
||||
"agentType": "screener"
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
The `data` object contains event-specific fields. For `agent.*` events it includes agent
|
||||
metadata. For `credential.*` events it includes `credentialId` and `agentId`. For `token.*`
|
||||
events it includes `agentId` and `scope`.
|
||||
|
||||
---
|
||||
|
||||
## Verifying delivery signatures
|
||||
|
||||
AgentIdP signs every delivery with HMAC-SHA256 using your `signingSecret`. The signature is
|
||||
in the `X-SentryAgent-Signature` header as `sha256=<hex-digest>`.
|
||||
|
||||
Verify it in Node.js:
|
||||
|
||||
```javascript
|
||||
const crypto = require('crypto');
|
||||
|
||||
function verifySignature(rawBody, signingSecret, signatureHeader) {
|
||||
const expected = 'sha256=' + crypto
|
||||
.createHmac('sha256', signingSecret)
|
||||
.update(rawBody)
|
||||
.digest('hex');
|
||||
return crypto.timingSafeEqual(
|
||||
Buffer.from(expected),
|
||||
Buffer.from(signatureHeader)
|
||||
);
|
||||
}
|
||||
```
|
||||
|
||||
Always verify the signature before processing the event. Reject requests with invalid signatures
|
||||
with `401 Unauthorized`.
|
||||
|
||||
---
|
||||
|
||||
## Delivery guarantees and retry policy
|
||||
|
||||
- AgentIdP delivers each event **at least once** — your endpoint may receive duplicates
|
||||
- Use the `id` field to deduplicate events
|
||||
- Delivery is attempted immediately; on failure, retries use exponential backoff
|
||||
- After repeated failures, the delivery moves to `dead_letter` status
|
||||
- Subscriptions with high `failure_count` may be automatically disabled
|
||||
|
||||
Delivery statuses: `pending` → `delivered` (success) or `failed` (attempt failed) → `dead_letter`
|
||||
(all retries exhausted)
|
||||
|
||||
---
|
||||
|
||||
## List subscriptions
|
||||
|
||||
```bash
|
||||
curl -s "http://localhost:3000/api/v1/webhooks" \
|
||||
-H "Authorization: Bearer $TOKEN" | jq .
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## Pause or resume a subscription
|
||||
|
||||
To pause (disable) a subscription without deleting it:
|
||||
|
||||
```bash
|
||||
curl -s -X PATCH "http://localhost:3000/api/v1/webhooks/$WEBHOOK_ID" \
|
||||
-H "Authorization: Bearer $TOKEN" \
|
||||
-H "Content-Type: application/json" \
|
||||
-d '{ "active": false }' | jq .
|
||||
```
|
||||
|
||||
To resume:
|
||||
|
||||
```bash
|
||||
curl -s -X PATCH "http://localhost:3000/api/v1/webhooks/$WEBHOOK_ID" \
|
||||
-H "Authorization: Bearer $TOKEN" \
|
||||
-H "Content-Type: application/json" \
|
||||
-d '{ "active": true }' | jq .
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## Inspect delivery history
|
||||
|
||||
`GET /api/v1/webhooks/{id}/deliveries`
|
||||
|
||||
```bash
|
||||
curl -s "http://localhost:3000/api/v1/webhooks/$WEBHOOK_ID/deliveries?limit=20&offset=0" \
|
||||
-H "Authorization: Bearer $TOKEN" | jq .
|
||||
```
|
||||
|
||||
Response:
|
||||
|
||||
```json
|
||||
{
|
||||
"deliveries": [
|
||||
{
|
||||
"id": "del-uuid",
|
||||
"subscription_id": "wh-uuid",
|
||||
"event_type": "agent.created",
|
||||
"payload": { ... },
|
||||
"status": "delivered",
|
||||
"http_status_code": 200,
|
||||
"attempt_count": 1,
|
||||
"next_retry_at": null,
|
||||
"delivered_at": "2026-04-04T09:00:01.000Z",
|
||||
"created_at": "2026-04-04T09:00:00.000Z",
|
||||
"updated_at": "2026-04-04T09:00:01.000Z"
|
||||
}
|
||||
],
|
||||
"total": 47,
|
||||
"limit": 20,
|
||||
"offset": 0
|
||||
}
|
||||
```
|
||||
|
||||
Use `offset` to paginate through delivery history. Increase `limit` to retrieve more records
|
||||
per page (the server default is 20).
|
||||
|
||||
---
|
||||
|
||||
## Delete a subscription
|
||||
|
||||
```bash
|
||||
curl -s -X DELETE "http://localhost:3000/api/v1/webhooks/$WEBHOOK_ID" \
|
||||
-H "Authorization: Bearer $TOKEN" \
|
||||
-o /dev/null -w "%{http_code}\n"
|
||||
```
|
||||
|
||||
Expected response: `204`. This permanently deletes the subscription and all its delivery records.
|
||||
@@ -47,10 +47,13 @@ The token expires in `3600` seconds (1 hour). Request a new one before it expire
|
||||
|
||||
| Scope | What it allows |
|
||||
|-------|----------------|
|
||||
| `agents:read` | Read agent records |
|
||||
| `agents:write` | Create, update, decommission agents |
|
||||
| `agents:read` | Read agent identity records |
|
||||
| `agents:write` | Create, update, and decommission agents |
|
||||
| `tokens:read` | Introspect tokens |
|
||||
| `audit:read` | Query audit logs |
|
||||
| `audit:read` | Query audit logs and verify audit chain integrity |
|
||||
| `webhooks:read` | List webhook subscriptions and delivery history |
|
||||
| `webhooks:write` | Create, update, and delete webhook subscriptions |
|
||||
| `admin:orgs` | Manage organizations and federation partners |
|
||||
|
||||
Request only the scopes your agent needs.
|
||||
|
||||
|
||||
140
docs/developers/guides/manage-api-tiers.md
Normal file
140
docs/developers/guides/manage-api-tiers.md
Normal file
@@ -0,0 +1,140 @@
|
||||
# Manage API Tiers
|
||||
|
||||
This guide explains how to check your organization's current plan tier, understand the enforced
|
||||
limits, and initiate an upgrade via Stripe.
|
||||
|
||||
---
|
||||
|
||||
## Prerequisites
|
||||
|
||||
- A running AgentIdP instance
|
||||
- A valid Bearer token with `organization_id` in its claims
|
||||
|
||||
---
|
||||
|
||||
## Check current tier status
|
||||
|
||||
`GET /api/v1/tiers/status`
|
||||
|
||||
Returns your organization's tier, the configured limits, and live usage counters for today.
|
||||
|
||||
```bash
|
||||
curl -s "http://localhost:3000/api/v1/tiers/status" \
|
||||
-H "Authorization: Bearer $TOKEN" | jq .
|
||||
```
|
||||
|
||||
Response:
|
||||
|
||||
```json
|
||||
{
|
||||
"tier": "free",
|
||||
"limits": {
|
||||
"maxAgents": 10,
|
||||
"maxCallsPerDay": 1000,
|
||||
"maxTokensPerDay": 1000
|
||||
},
|
||||
"usage": {
|
||||
"agentCount": 3,
|
||||
"callsToday": 142,
|
||||
"tokensToday": 87
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
**Understanding the fields**:
|
||||
|
||||
| Field | Description |
|
||||
|-------|-------------|
|
||||
| `tier` | Current plan: `free`, `pro`, or `enterprise` |
|
||||
| `limits.maxAgents` | Maximum active (non-decommissioned) agents allowed |
|
||||
| `limits.maxCallsPerDay` | Maximum total API calls per calendar day (UTC) |
|
||||
| `limits.maxTokensPerDay` | Maximum token issuances per calendar day (UTC) |
|
||||
| `usage.agentCount` | Current number of active agents |
|
||||
| `usage.callsToday` | API calls made so far today |
|
||||
| `usage.tokensToday` | Tokens issued so far today |
|
||||
|
||||
**When limits are reached**: The relevant endpoint returns `403 FREE_TIER_LIMIT_EXCEEDED`.
|
||||
Daily counters reset at midnight UTC. The agent count limit is a current count, not a daily
|
||||
counter — decommissioning an agent immediately frees capacity.
|
||||
|
||||
---
|
||||
|
||||
## Tier comparison
|
||||
|
||||
| Limit | Free | Pro | Enterprise |
|
||||
|-------|------|-----|------------|
|
||||
| Max agents | 10 | 100 | Unlimited |
|
||||
| Max API calls / day | 1,000 | 50,000 | Unlimited |
|
||||
| Max token issuances / day | 1,000 | 50,000 | Unlimited |
|
||||
|
||||
---
|
||||
|
||||
## Upgrade your tier
|
||||
|
||||
`POST /api/v1/tiers/upgrade`
|
||||
|
||||
Creates a Stripe Checkout Session and returns a one-time URL. Complete the payment in the
|
||||
browser to upgrade your organization's tier.
|
||||
|
||||
```bash
|
||||
curl -s -X POST http://localhost:3000/api/v1/tiers/upgrade \
|
||||
-H "Authorization: Bearer $TOKEN" \
|
||||
-H "Content-Type: application/json" \
|
||||
-d '{ "target_tier": "pro" }' | jq .
|
||||
```
|
||||
|
||||
Response:
|
||||
|
||||
```json
|
||||
{
|
||||
"checkoutUrl": "https://checkout.stripe.com/pay/cs_live_a1b2c3d4e5f6..."
|
||||
}
|
||||
```
|
||||
|
||||
Open `checkoutUrl` in a browser to complete payment. After successful payment, Stripe sends a
|
||||
webhook to AgentIdP which automatically upgrades your organization's tier.
|
||||
|
||||
**Constraints**:
|
||||
- `target_tier` must be `pro` or `enterprise`
|
||||
- `target_tier` must be higher than your current tier (you cannot downgrade via this endpoint)
|
||||
- Attempting to upgrade to the current or a lower tier returns `400 VALIDATION_ERROR`
|
||||
|
||||
```bash
|
||||
# Upgrade from free to pro
|
||||
curl -s -X POST http://localhost:3000/api/v1/tiers/upgrade \
|
||||
-H "Authorization: Bearer $TOKEN" \
|
||||
-H "Content-Type: application/json" \
|
||||
-d '{ "target_tier": "pro" }' | jq .
|
||||
|
||||
# Upgrade from pro to enterprise
|
||||
curl -s -X POST http://localhost:3000/api/v1/tiers/upgrade \
|
||||
-H "Authorization: Bearer $TOKEN" \
|
||||
-H "Content-Type: application/json" \
|
||||
-d '{ "target_tier": "enterprise" }' | jq .
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## Common errors
|
||||
|
||||
### `400 VALIDATION_ERROR` — target_tier missing or invalid
|
||||
|
||||
```json
|
||||
{
|
||||
"code": "VALIDATION_ERROR",
|
||||
"message": "target_tier must be one of: free, pro, enterprise.",
|
||||
"details": { "received": "premium" }
|
||||
}
|
||||
```
|
||||
|
||||
**Fix**: Use `"pro"` or `"enterprise"`.
|
||||
|
||||
### `400 TIER_UPGRADE_NOT_REQUIRED` — not an upgrade
|
||||
|
||||
**Fix**: You are already on this tier or a higher tier. Check `GET /api/v1/tiers/status` first.
|
||||
|
||||
### `401 UNAUTHORIZED` — token lacks organization_id
|
||||
|
||||
The tier endpoints require a token with an `organization_id` claim. Use a token issued by an
|
||||
agent that was registered with `organization_id`. Tokens issued via the bootstrap method
|
||||
(without an org) do not carry `organization_id` and will fail.
|
||||
@@ -2,6 +2,11 @@
|
||||
|
||||
A credential is a `client_id` + `client_secret` pair that your agent uses to get access tokens. This guide covers all four credential operations.
|
||||
|
||||
> **Multi-tenant note**: Credentials issued for an agent that belongs to an organization will
|
||||
> produce tokens carrying an `organization_id` claim. This claim is required by analytics,
|
||||
> webhooks, tier enforcement, and A2A delegation. Ensure your agent is registered with
|
||||
> `organization_id` before issuing credentials for production use.
|
||||
|
||||
All credential endpoints are under `/api/v1/agents/{agentId}/credentials` and require a Bearer token with `agents:write` scope.
|
||||
|
||||
---
|
||||
|
||||
@@ -25,6 +25,11 @@ Every action below is automatically recorded. You cannot create, modify, or dele
|
||||
| `credential.revoked` | Successful `DELETE /agents/{agentId}/credentials/{credentialId}` |
|
||||
| `auth.failed` | Failed authentication attempt on `POST /token` |
|
||||
|
||||
> **Audit chain verification**: In addition to querying events, you can verify the cryptographic
|
||||
> integrity of the entire audit hash chain via `GET /api/v1/audit/verify`. This endpoint requires
|
||||
> `audit:read` scope and is rate-limited to 30 requests/min. See the
|
||||
> [API Reference](../api-reference.md#get-auditverify---verify-audit-chain-integrity) for details.
|
||||
|
||||
---
|
||||
|
||||
## Query the audit log
|
||||
|
||||
@@ -20,6 +20,7 @@ Requires: `Authorization: Bearer <token>` with `agents:write` scope.
|
||||
| `capabilities` | string[] | Yes | One or more capability strings in `resource:action` format. Minimum 1. |
|
||||
| `owner` | string | Yes | Team or organisation that owns this agent. 1–128 characters. |
|
||||
| `deploymentEnv` | string (enum) | Yes | Target deployment environment. See values below. |
|
||||
| `organization_id` | string (UUID) | No | UUID of the organization to scope this agent to. Recommended on all multi-tenant instances. |
|
||||
|
||||
### `agentType` values
|
||||
|
||||
@@ -70,7 +71,8 @@ curl -s -X POST http://localhost:3000/api/v1/agents \
|
||||
"version": "1.0.0",
|
||||
"capabilities": ["resume:read", "email:send", "candidate:score"],
|
||||
"owner": "talent-acquisition-team",
|
||||
"deploymentEnv": "production"
|
||||
"deploymentEnv": "production",
|
||||
"organization_id": "'$ORG_ID'"
|
||||
}' | jq .
|
||||
```
|
||||
|
||||
@@ -93,6 +95,11 @@ Successful response (`201 Created`):
|
||||
|
||||
The `agentId` is assigned by the system — it is immutable and never changes.
|
||||
|
||||
> **Organization scoping**: If you include `organization_id` in the request, the agent is
|
||||
> associated with that organization. Analytics, webhook events, and tier enforcement are all
|
||||
> scoped by organization. To create an organization first, see the
|
||||
> [Quick Start](../quick-start.md) guide.
|
||||
|
||||
---
|
||||
|
||||
## Immutable fields
|
||||
|
||||
135
docs/developers/guides/use-analytics-dashboard.md
Normal file
135
docs/developers/guides/use-analytics-dashboard.md
Normal file
@@ -0,0 +1,135 @@
|
||||
# Use the Analytics Dashboard
|
||||
|
||||
This guide explains how to query the three analytics endpoints to understand your organization's
|
||||
token usage and agent activity patterns.
|
||||
|
||||
All analytics endpoints require Bearer token authentication and are scoped to the organization
|
||||
embedded in your token.
|
||||
|
||||
---
|
||||
|
||||
## Prerequisites
|
||||
|
||||
- A running AgentIdP instance
|
||||
- A valid Bearer token with `organization_id` in its claims
|
||||
- At least one agent registered and some token issuance activity
|
||||
|
||||
---
|
||||
|
||||
## Token issuance trend
|
||||
|
||||
`GET /api/v1/analytics/tokens`
|
||||
|
||||
Returns daily token issuance counts for the past N days (default 30, max 90). Use this to
|
||||
track usage growth, identify traffic spikes, and plan capacity.
|
||||
|
||||
```bash
|
||||
curl -s "http://localhost:3000/api/v1/analytics/tokens?days=30" \
|
||||
-H "Authorization: Bearer $TOKEN" | jq .
|
||||
```
|
||||
|
||||
Response:
|
||||
|
||||
```json
|
||||
{
|
||||
"tenantId": "org-0a1b2c3d-e4f5-6789-abcd-ef0123456789",
|
||||
"days": 30,
|
||||
"data": [
|
||||
{ "date": "2026-03-06", "count": 142 },
|
||||
{ "date": "2026-03-07", "count": 198 },
|
||||
{ "date": "2026-03-08", "count": 0 }
|
||||
]
|
||||
}
|
||||
```
|
||||
|
||||
**Interpreting the data**: Each item in `data` is one calendar day (UTC) with the number of
|
||||
tokens issued on that day. Days with zero issuance are included with `count: 0`. The array
|
||||
is ordered chronologically, oldest first.
|
||||
|
||||
**Using it**: Compare day-over-day counts to identify growth or anomalies. A sudden spike in
|
||||
`count` may indicate an agent retry loop or a credential leak. Zero-count days during expected
|
||||
operation may indicate a deployment issue.
|
||||
|
||||
**Query parameter**: `days` — positive integer, max 90. Returns `400 VALIDATION_ERROR` if
|
||||
exceeded.
|
||||
|
||||
```bash
|
||||
# Last 7 days
|
||||
curl -s "http://localhost:3000/api/v1/analytics/tokens?days=7" \
|
||||
-H "Authorization: Bearer $TOKEN" | jq .
|
||||
|
||||
# Last 90 days (maximum)
|
||||
curl -s "http://localhost:3000/api/v1/analytics/tokens?days=90" \
|
||||
-H "Authorization: Bearer $TOKEN" | jq .
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## Agent activity heatmap
|
||||
|
||||
`GET /api/v1/analytics/agents/activity`
|
||||
|
||||
Returns request counts grouped by day-of-week (0 = Sunday, 6 = Saturday) and hour (0–23, UTC).
|
||||
Use this to identify peak usage windows for capacity planning and rate limit tuning.
|
||||
|
||||
```bash
|
||||
curl -s "http://localhost:3000/api/v1/analytics/agents/activity" \
|
||||
-H "Authorization: Bearer $TOKEN" | jq .
|
||||
```
|
||||
|
||||
Response:
|
||||
|
||||
```json
|
||||
{
|
||||
"tenantId": "org-0a1b2c3d-e4f5-6789-abcd-ef0123456789",
|
||||
"data": [
|
||||
{ "dow": 1, "hour": 9, "count": 54 },
|
||||
{ "dow": 1, "hour": 10, "count": 87 },
|
||||
{ "dow": 3, "hour": 14, "count": 201 }
|
||||
]
|
||||
}
|
||||
```
|
||||
|
||||
**Interpreting the data**: `dow` is 0 (Sunday) through 6 (Saturday). `hour` is 0–23 UTC.
|
||||
Only non-zero cells are returned — missing combinations had zero activity. Sort by `count`
|
||||
descending to find your peak windows.
|
||||
|
||||
**Using it**: If most activity is on weekday mornings UTC, ensure your rate limit headroom
|
||||
covers that window. If weekend activity is unexpectedly high, investigate which agents are
|
||||
active.
|
||||
|
||||
---
|
||||
|
||||
## Per-agent usage summary
|
||||
|
||||
`GET /api/v1/analytics/agents`
|
||||
|
||||
Returns token issuance counts per agent for the current calendar month (UTC). Use this to
|
||||
identify your most active agents and check if any single agent is consuming a
|
||||
disproportionate share of your monthly token budget.
|
||||
|
||||
```bash
|
||||
curl -s "http://localhost:3000/api/v1/analytics/agents" \
|
||||
-H "Authorization: Bearer $TOKEN" | jq .
|
||||
```
|
||||
|
||||
Response:
|
||||
|
||||
```json
|
||||
{
|
||||
"tenantId": "org-0a1b2c3d-e4f5-6789-abcd-ef0123456789",
|
||||
"month": "2026-04",
|
||||
"data": [
|
||||
{ "agentId": "a1b2c3d4-e5f6-7890-abcd-ef1234567890", "tokenCount": 312 },
|
||||
{ "agentId": "b2c3d4e5-f6a7-8901-bcde-f12345678901", "tokenCount": 87 }
|
||||
]
|
||||
}
|
||||
```
|
||||
|
||||
**Interpreting the data**: Each item shows an agent UUID and the number of tokens it has
|
||||
issued this month. The response covers the full current calendar month from day 1 to now.
|
||||
It resets on the first day of each month.
|
||||
|
||||
**Using it**: Cross-reference `agentId` values against `GET /api/v1/agents` to identify which
|
||||
agents by name. If one agent accounts for >80% of usage, investigate whether it is token
|
||||
caching correctly or requesting tokens unnecessarily.
|
||||
Reference in New Issue
Block a user