# AIdenID — Full LLM API Reference > The Clearance Layer for Agentic Access > Complete API reference for LLM consumption — last updated 2026-04-29 AIdenID is the site-owned clearance layer for AI-agent traffic. It answers one question per request: should this agent-attributable traffic be **allowed**, **throttled**, **queued**, **sandboxed**, **denied**, or **price-required**? The hard path verifies HTTP Message Signatures, DPoP proofs, audience-bound session tokens, key epochs, and replay resistance. The soft path labels traffic as `verified_agent`, `signed_agent`, `likely_human`, `suspicious_automation`, or `unknown` without pretending to know human intent. Supporting identity, inbox, webhook, target-registry, and resilience-testing APIs provide issuer context, demo traffic, audit evidence, and controlled testing for the clearance layer. Those surfaces are documented below because they are still public APIs; they are supporting surfaces, not the core buyer story by themselves. AIdenID does not automate third-party account signup or fabricate sessions outside declared authority. Base URL: `https://api.aidenid.com` --- ## Table of Contents 1. Platform Overview 2. Authentication 3. API Reference - Free Tier API (`/v1/free/*`) - Consumer API (`/v1/consumer/*`) - Identities API (`/v1/identities/*`) - Trials API (`/v1/trials/*`) - Webhooks API (`/v1/webhooks/*`) - Auth Flows API (`/v1/reliability/*`) - Domains & Targets API (`/v1/domains/*`, `/v1/targets/*`) - Billing API (`/v1/billing/*`) - Realtime API (`/v1/realtime/*`) - Exports API (`/v1/exports/*`) - Marketplace API (`/v1/marketplace/*`) 4. Identity Lifecycle 5. Trial Lifecycle 6. Webhook Event Types & Payload Formats 7. Error Handling 8. Rate Limits & Quotas 9. Response Headers 10. Pricing 11. MCP Server Integration 12. Links --- ## 1. Platform Overview AIdenID is a clearance platform. It serves one primary buyer and several support audiences through one unified system: **For Site Owners and Security Teams** — Mount AIdenID at the edge or origin, register route policies, classify traffic, enforce six-outcome decisions, stream OCSF-shaped evidence, and revoke sessions or issuers instantly. **For Agent Builders and Swarms** — Use scoped identity visas, delegated subidentities, target registries, DPoP/session binding, and budget envelopes so websites can safely recognize useful automation. **For QA, Demo, and GTM Teams** — Run authorized browser swarms against customer-controlled staging portals and produce dashboard logs, videos, evidence ledgers, and report emails that show the verified/signed/suspicious/unknown decomposition. **For Supporting Human Inbox Users** — Human inbox and magic-link flows remain a supporting surface for consumer identities, demos, and legacy inbox workflows; they are no longer the core clearance-layer pitch. **For Zero-Friction Prototyping** — The free tier remains available for identity/inbox experiments. It is keyed by client IP and provides a single identity with a 24-hour TTL. ### Core Primitives - **Clearance decision** — a per-request outcome: `allow`, `throttle`, `queue`, `sandbox`, `deny`, or `price_required`. - **Actor class** — bounded traffic label: `verified_agent`, `signed_agent`, `likely_human`, `suspicious_automation`, or `unknown`. - **Route policy** — host/path/method/actor-class rules with observe, shadow, and enforce rollout modes. - **Cryptographic proof** — HTTP Message Signature + DPoP + audience-bound session token + issuer key epoch + replay resistance. - **Revocation epoch** — session, grant, issuer, or delegated-chain kill switch that strict routes honor before grant lookup. - **Evidence root** — transparency-log and report artifacts binding decisions, policies, revocations, and demo proof to audit trails. - **Identity visa** — supporting issuer primitive with declared intent, allowed targets, TTL, and lease identifier. - **Delegated subidentity** — supporting swarm primitive for inherited budgets and lineage tracking. - **Budget envelope** — per-tenant and per-swarm quota; every identity or route policy inherits a hard ceiling. ### Core Capabilities - **Six-Outcome Decision Ladder**: Resolve each request to `allow | throttle | queue | sandbox | deny | price_required`. - **Route Clearance Policy**: Configure observe, shadow, and enforce behavior per host, route, method, actor class, quota, and risk tier. - **Cryptographic Hard Path**: Verify request signatures, DPoP, exchanged session tokens, key epochs, and replay windows. - **Confidence-Labeled Soft Path**: Classify unsigned or incomplete traffic without claiming certainty. - **Instant Revocation**: Deny revoked actors before grant lookup on strict routes. - **Transparency-Log Audit**: Commit policy versions, issuer rotations, revocation epochs, decision batches, and evidence roots. - **Edge and Origin Verifiers**: Cloudflare, Fastly, Node, Python, and origin middleware share the same decision model. - **Decision Event Stream**: Server-Sent Events and OCSF-shaped exports for dashboard, SIEM, and evidence packs. - **Authorized Demo Swarms**: Generate verified/signed/suspicious/unknown staging traffic with video, logs, reports, and email-ready proof. - **Signed Webhooks**: HMAC-SHA256 signed payloads with replay support and secret rotation. - **MCP Server**: Model Context Protocol integration with resource-bound token exchange and no token passthrough. - **Supporting Identity Provisioning**: Create disposable email identities on demand when issuer, QA, or demo workflows need inbox evidence. - **Supporting Extraction Pipeline**: Redacted OTP, magic-link, and confirmation extraction for authorized inbox workflows. - **Billing, Quotas, and Trials**: Stripe-powered billing, credit top-ups, tenant quotas, and trial controls. - **Data Exports**: Bulk export events, extractions, and decision evidence in JSONL or CSV. --- ## 2. Authentication AIdenID supports three authentication modes depending on the caller: ### 2.1 API Key Authentication (for AI Agents) All authenticated agent API requests require three headers: ``` Authorization: Bearer X-Org-Id: X-Project-Id: ``` API keys are prefixed with `aid_` and are scoped to a specific organization and project. Generate keys from the dashboard at https://aidenid.com/dashboard/settings. #### API Key Scopes | Scope | Description | |----------------------|--------------------------------------------| | `identities:read` | List and retrieve identities | | `identities:write` | Create, extend, squash, bulk operations | | `webhooks:read` | List webhook endpoints | | `webhooks:write` | Create, update, rotate, replay webhooks | | `reliability:write` | Create auth flow test runs | | `domains:read` | List domains and targets | | `domains:write` | Register, verify, freeze/unfreeze domains | | `billing:read` | View usage, credit balance, transactions | | `billing:write` | Create checkout sessions, top up credits | | `exports:write` | Create event exports | | `admin:read` | Manage marketplace templates | All mutation endpoints require an `Idempotency-Key` header (any unique string, typically a UUID). The server returns `X-Idempotent-Replay: true` when replaying a previously processed request. ### 2.2 Magic-Link Session Authentication (for Consumers) Human consumers authenticate via passwordless magic links: 1. Call `POST /v1/consumer/signup` or `POST /v1/consumer/login` with a personal email 2. Receive a magic-link verification token via email 3. Call `POST /v1/consumer/verify` with the token to obtain a `sessionToken` 4. Use `Authorization: Bearer ` for authenticated consumer endpoints ### 2.3 IP-Keyed Token Authentication (for Free Tier) The free tier requires no signup. On first call to `POST /v1/free/identity`: 1. The server identifies the caller by IP address 2. Returns an `apiToken` (prefixed `free_`) along with the identity 3. Use `?token=` query parameter on subsequent polling and status endpoints The same IP always returns the existing active grant (idempotent behavior). One identity per IP, 24-hour TTL. --- ## 3. API Reference All request and response bodies use JSON (`Content-Type: application/json`). --- ### 3.1 Free Tier API (`/v1/free/*`) No authentication required. IP-keyed, 1 identity per IP, 24-hour TTL, polling-only. --- #### POST /v1/free/identity Create a free ephemeral identity. Returns the existing active grant if one already exists for the caller's IP. **Request Headers:** ``` Content-Type: application/json (optional — body is optional) ``` **Request Body (optional):** ```json { "aliasHint": "my-agent" } ``` | Field | Type | Required | Description | |-------------|--------|----------|--------------------------------------------| | `aliasHint` | string | No | Optional prefix for the email address (max 32 chars) | **Response (201 Created):** ```json { "identityId": "id_abc123", "emailAddress": "agent-8f3c1a2b@free.aidenid.dev", "expiresAt": "2026-04-07T22:00:00Z", "apiToken": "free_aBc123...", "pollUrl": "/v1/free/identity/id_abc123/extraction" } ``` | Field | Type | Description | |----------------|--------|------------------------------------------------| | `identityId` | string | Unique identity identifier | | `emailAddress` | string | Disposable email address to use for signups | | `expiresAt` | string | ISO 8601 UTC expiration timestamp | | `apiToken` | string | Ephemeral token for polling and status queries | | `pollUrl` | string | Relative URL to poll for extraction results | **curl example:** ```bash curl -X POST https://api.aidenid.com/v1/free/identity ``` **Python example:** ```python import requests resp = requests.post("https://api.aidenid.com/v1/free/identity") data = resp.json() email = data["emailAddress"] token = data["apiToken"] identity_id = data["identityId"] print(f"Use this email to sign up: {email}") ``` **TypeScript example:** ```typescript const resp = await fetch("https://api.aidenid.com/v1/free/identity", { method: "POST", }); const data = await resp.json(); console.log(`Use this email: ${data.emailAddress}`); ``` --- #### GET /v1/free/identity/{identity_id}/extraction Poll for OTP extraction result. Returns 202 when pending, 200 when ready. **Path Parameters:** | Parameter | Type | Description | |---------------|--------|---------------------| | `identity_id` | string | The identity ID | **Query Parameters:** | Parameter | Type | Required | Description | |-----------|--------|----------|----------------------| | `token` | string | Yes | Ephemeral API token | **Response (202 Accepted — pending):** ```json { "status": "pending", "retryAfterSeconds": 30, "message": "No extraction yet. Poll again shortly." } ``` **Response (200 OK — ready):** ```json { "status": "ready", "type": "otp", "has_secret": true, "redacted_value": "***", "primaryActionUrl": null, "confidence": 0.98, "receivedAt": "2026-04-06T22:05:00Z" } ``` | Field | Type | Description | |--------------------|--------|-----------------------------------------------| | `status` | string | `"pending"` or `"ready"` | | `has_secret` | bool | Whether a raw secret exists in the secure server-side path | | `redacted_value` | string | Redacted placeholder for display/logging | | `type` | string | `"otp"` or `"link"` | | `primaryActionUrl` | string | Extracted action URL (when type is `"link"`) | | `confidence` | float | Extraction confidence score (0.0 - 1.0) | | `receivedAt` | string | ISO 8601 timestamp of email receipt | **curl example:** ```bash curl "https://api.aidenid.com/v1/free/identity/id_abc123/extraction?token=free_aBc123" ``` **Python example (polling loop):** ```python import time import requests API = "https://api.aidenid.com" identity_id = "id_abc123" token = "free_aBc123" for attempt in range(60): resp = requests.get(f"{API}/v1/free/identity/{identity_id}/extraction", params={"token": token}) if resp.status_code == 200: data = resp.json() if data["status"] == "ready": print(f"Extraction ready: {data['type']} (confidence: {data['confidence']})") break time.sleep(2) ``` --- #### GET /v1/free/identity/{identity_id} Check the status of a free-tier identity. **Query Parameters:** | Parameter | Type | Required | Description | |-----------|--------|----------|----------------------| | `token` | string | Yes | Ephemeral API token | **Response (200 OK):** ```json { "identityId": "id_abc123", "emailAddress": "agent-8f3c1a2b@free.aidenid.dev", "status": "ACTIVE", "expiresAt": "2026-04-07T22:00:00Z", "createdAt": "2026-04-06T22:00:00Z" } ``` **curl example:** ```bash curl "https://api.aidenid.com/v1/free/identity/id_abc123?token=free_aBc123" ``` #### Free Tier Limits - 1 identity per IP address - 24-hour TTL (non-extendable) - 1 OTP delivery - 10 requests per minute - Same IP returns existing active grant (idempotent) - No webhooks, no realtime SSE, no bulk operations --- ### 3.2 Consumer API (`/v1/consumer/*`) For human consumers. Public endpoints require no auth; authenticated endpoints require a magic-link session token. --- #### POST /v1/consumer/signup Create a consumer account with email verification. **Auth:** None (public) **Request Body:** ```json { "email": "user@example.com", "displayName": "Jane Doe" } ``` | Field | Type | Required | Description | |---------------|--------|----------|----------------------------------| | `email` | string | Yes | Personal email address | | `displayName` | string | No | Display name (max 128 chars) | **Response (201 Created):** ```json { "accountId": "acct_x1y2z3", "email": "user@example.com", "status": "pending_verification", "verificationToken": "vt_abc123..." } ``` **curl example:** ```bash curl -X POST https://api.aidenid.com/v1/consumer/signup \ -H "Content-Type: application/json" \ -d '{"email": "user@example.com", "displayName": "Jane Doe"}' ``` **TypeScript example:** ```typescript const resp = await fetch("https://api.aidenid.com/v1/consumer/signup", { method: "POST", headers: { "Content-Type": "application/json" }, body: JSON.stringify({ email: "user@example.com", displayName: "Jane Doe" }), }); const data = await resp.json(); // Check email for magic link, then call /verify ``` --- #### POST /v1/consumer/verify Verify email using a magic-link token. Returns a session token for authenticated endpoints. **Auth:** None (public) **Request Body:** ```json { "token": "vt_abc123..." } ``` **Response (200 OK):** ```json { "accountId": "acct_x1y2z3", "email": "user@example.com", "verified": true, "organizationId": "org_abc123", "projectId": "proj_def456", "sessionToken": "cs_session_token..." } ``` **curl example:** ```bash curl -X POST https://api.aidenid.com/v1/consumer/verify \ -H "Content-Type: application/json" \ -d '{"token": "vt_abc123..."}' ``` --- #### POST /v1/consumer/login Request a magic-link login email. The user receives a link/token via email to authenticate. **Auth:** None (public) **Request Body:** ```json { "email": "user@example.com" } ``` **Response (200 OK):** ```json { "email": "user@example.com", "status": "magic_link_sent", "verificationToken": "vt_def456..." } ``` **curl example:** ```bash curl -X POST https://api.aidenid.com/v1/consumer/login \ -H "Content-Type: application/json" \ -d '{"email": "user@example.com"}' ``` --- #### GET /v1/consumer/identities List temp email identities for the authenticated consumer. **Auth:** Consumer session token (`Authorization: Bearer `) **Response (200 OK):** ```json { "items": [ { "identityId": "id_abc123", "emailAddress": "abc123@inbox.aidenid.com", "status": "ACTIVE", "expiresAt": "2026-04-13T10:00:00Z", "createdAt": "2026-04-06T10:00:00Z" } ] } ``` **curl example:** ```bash curl https://api.aidenid.com/v1/consumer/identities \ -H "Authorization: Bearer cs_session_token..." ``` --- #### POST /v1/consumer/identities Create a new temp email identity for the consumer. Enforces tier limits. **Auth:** Consumer session token **Response (201 Created):** ```json { "identityId": "id_new123", "emailAddress": "new123@inbox.aidenid.com", "status": "ACTIVE", "expiresAt": "2026-04-13T10:00:00Z", "createdAt": "2026-04-06T10:00:00Z" } ``` **curl example:** ```bash curl -X POST https://api.aidenid.com/v1/consumer/identities \ -H "Authorization: Bearer cs_session_token..." ``` --- #### GET /v1/consumer/notifications List recent notifications for the consumer. **Auth:** Consumer session token **Query Parameters:** | Parameter | Type | Default | Description | |-----------|------|---------|-------------------------------| | `limit` | int | 20 | Max results (1-100) | **Response (200 OK):** ```json { "items": [ { "notificationId": "notif_abc", "identityId": "id_abc123", "type": "extraction.completed", "channel": "email", "status": "delivered", "subject": "Your OTP code was extracted", "body": {}, "createdAt": "2026-04-06T10:05:00Z", "readAt": null } ] } ``` **curl example:** ```bash curl "https://api.aidenid.com/v1/consumer/notifications?limit=10" \ -H "Authorization: Bearer cs_session_token..." ``` --- #### POST /v1/consumer/notifications/{notification_id}/read Mark a notification as read. **Auth:** Consumer session token **Response:** 204 No Content **curl example:** ```bash curl -X POST https://api.aidenid.com/v1/consumer/notifications/notif_abc/read \ -H "Authorization: Bearer cs_session_token..." ``` --- ### 3.3 Identities API (`/v1/identities/*`) Core API for identity provisioning and lifecycle management. Requires API key authentication. **Standard Auth Headers (required on all endpoints):** ``` Authorization: Bearer aid_your_api_key X-Org-Id: org_abc123 X-Project-Id: proj_def456 ``` --- #### POST /v1/identities Create a new disposable email identity. **Additional Required Headers:** ``` Idempotency-Key: Content-Type: application/json ``` **Request Body:** ```json { "aliasTemplate": "signup-bot", "ttlHours": 24, "tags": ["onboarding", "test"], "domainPoolId": "dp_abc123", "policy": { "receiveMode": "EDGE_ACCEPT", "allowWebhooks": true, "extractionTypes": ["otp", "link"] } } ``` | Field | Type | Default | Description | |-----------------|----------|------------------|-------------------------------------------------| | `aliasTemplate` | string | null | Optional prefix for the email address | | `ttlHours` | int | 24 | Lifecycle duration in hours (1 - 720) | | `tags` | string[] | [] | Tags for filtering and bulk operations | | `domainPoolId` | string | null | Domain pool to use (uses default pool if null) | | `policy` | object | (see below) | Identity policy configuration | **Policy object defaults:** | Field | Type | Default | Description | |-------------------|----------|--------------------|----------------------------------------| | `receiveMode` | string | `"EDGE_ACCEPT"` | Email receive mode | | `allowWebhooks` | bool | true | Whether to deliver webhook events | | `extractionTypes` | string[] | `["otp", "link"]` | Types of extraction to attempt | **Response (200 OK):** ```json { "id": "ident_a1b2c3d4e5", "emailAddress": "a1b2c3d4e5@inbox.aidenid.com", "status": "PROVISIONED", "expiresAt": "2026-04-07T10:00:00Z", "projectId": "proj_def456", "parentIdentityId": null, "domainPoolId": "dp_abc123", "tags": ["onboarding", "test"], "policy": { "receiveMode": "EDGE_ACCEPT", "allowWebhooks": true, "ttlHours": 24, "extractionTypes": ["otp", "link"] }, "createdAt": "2026-04-06T10:00:00Z", "updatedAt": "2026-04-06T10:00:00Z" } ``` **curl example:** ```bash curl -X POST https://api.aidenid.com/v1/identities \ -H "Authorization: Bearer aid_your_api_key" \ -H "X-Org-Id: org_abc123" \ -H "X-Project-Id: proj_def456" \ -H "Idempotency-Key: $(uuidgen)" \ -H "Content-Type: application/json" \ -d '{ "aliasTemplate": "signup-bot", "ttlHours": 24, "tags": ["onboarding"] }' ``` **Python example:** ```python import requests import uuid API = "https://api.aidenid.com" HEADERS = { "Authorization": "Bearer aid_your_api_key", "X-Org-Id": "org_abc123", "X-Project-Id": "proj_def456", "Content-Type": "application/json", } resp = requests.post( f"{API}/v1/identities", headers={**HEADERS, "Idempotency-Key": str(uuid.uuid4())}, json={"aliasTemplate": "signup-bot", "ttlHours": 24, "tags": ["onboarding"]}, ) identity = resp.json() print(f"Email: {identity['emailAddress']}") print(f"Expires: {identity['expiresAt']}") ``` **TypeScript example:** ```typescript const API = "https://api.aidenid.com"; const headers = { "Authorization": "Bearer aid_your_api_key", "X-Org-Id": "org_abc123", "X-Project-Id": "proj_def456", "Content-Type": "application/json", "Idempotency-Key": crypto.randomUUID(), }; const resp = await fetch(`${API}/v1/identities`, { method: "POST", headers, body: JSON.stringify({ aliasTemplate: "signup-bot", ttlHours: 24, tags: ["onboarding"] }), }); const identity = await resp.json(); console.log(`Email: ${identity.emailAddress}`); ``` --- #### GET /v1/identities List identities for the current project. Supports cursor-based pagination. **Query Parameters:** | Parameter | Type | Default | Description | |-----------|--------|---------|-----------------------------------| | `cursor` | string | null | Pagination cursor from previous response | | `limit` | int | 50 | Max results (1-100) | **Response (200 OK):** ```json { "items": [ { "id": "ident_a1b2c3d4e5", "emailAddress": "a1b2c3d4e5@inbox.aidenid.com", "status": "ACTIVE", "expiresAt": "2026-04-07T10:00:00Z", "projectId": "proj_def456", "parentIdentityId": null, "domainPoolId": "dp_abc123", "tags": ["onboarding"], "policy": { "receiveMode": "EDGE_ACCEPT", "allowWebhooks": true, "ttlHours": 24, "extractionTypes": ["otp", "link"] }, "createdAt": "2026-04-06T10:00:00Z", "updatedAt": "2026-04-06T10:00:00Z" } ], "meta": { "cursor": "eyJ...", "hasMore": false, "total": 1 } } ``` **curl example:** ```bash curl "https://api.aidenid.com/v1/identities?limit=20" \ -H "Authorization: Bearer aid_your_api_key" \ -H "X-Org-Id: org_abc123" \ -H "X-Project-Id: proj_def456" ``` --- #### GET /v1/identities/{identity_id} Retrieve a specific identity by ID. **Response (200 OK):** Same shape as identity object above. **curl example:** ```bash curl https://api.aidenid.com/v1/identities/ident_a1b2c3d4e5 \ -H "Authorization: Bearer aid_your_api_key" \ -H "X-Org-Id: org_abc123" \ -H "X-Project-Id: proj_def456" ``` --- #### POST /v1/identities/{identity_id}/extend Extend an identity's lifecycle by adding hours to its TTL. **Additional Required Headers:** ``` Idempotency-Key: ``` **Request Body:** ```json { "ttlHours": 48 } ``` | Field | Type | Required | Description | |------------|------|----------|------------------------------------| | `ttlHours` | int | Yes | Additional hours to add (1 - 720) | **Response (200 OK):** Updated identity object with new `expiresAt` and `status: "ACTIVE"`. **curl example:** ```bash curl -X POST https://api.aidenid.com/v1/identities/ident_a1b2c3d4e5/extend \ -H "Authorization: Bearer aid_your_api_key" \ -H "X-Org-Id: org_abc123" \ -H "X-Project-Id: proj_def456" \ -H "Idempotency-Key: $(uuidgen)" \ -H "Content-Type: application/json" \ -d '{"ttlHours": 48}' ``` --- #### POST /v1/identities/{identity_id}/squash Revoke an identity immediately. Disables the inbox and halts all extraction. **Additional Required Headers:** ``` Idempotency-Key: ``` **Request Body:** None **Response (200 OK):** Updated identity object with `status: "SQUASHED"`. **curl example:** ```bash curl -X POST https://api.aidenid.com/v1/identities/ident_a1b2c3d4e5/squash \ -H "Authorization: Bearer aid_your_api_key" \ -H "X-Org-Id: org_abc123" \ -H "X-Project-Id: proj_def456" \ -H "Idempotency-Key: $(uuidgen)" ``` **Python example:** ```python resp = requests.post( f"{API}/v1/identities/{identity_id}/squash", headers={**HEADERS, "Idempotency-Key": str(uuid.uuid4())}, ) print(f"Status: {resp.json()['status']}") # "SQUASHED" ``` --- #### GET /v1/identities/{identity_id}/events List inbound events (emails received) for an identity. Supports cursor-based pagination. **Query Parameters:** | Parameter | Type | Default | Description | |-----------|--------|---------|----------------------------| | `cursor` | string | null | Pagination cursor | | `limit` | int | 50 | Max results (1-100) | **Response (200 OK):** ```json { "items": [ { "id": "evt_x1y2z3", "sender": "noreply@example.com", "subject": "Your verification code", "messageId": "", "storageKey": "s3://bucket/key", "receivedAt": "2026-04-06T10:05:00Z" } ], "meta": { "cursor": null, "hasMore": false, "total": 1 } } ``` **curl example:** ```bash curl "https://api.aidenid.com/v1/identities/ident_a1b2c3d4e5/events?limit=10" \ -H "Authorization: Bearer aid_your_api_key" \ -H "X-Org-Id: org_abc123" \ -H "X-Project-Id: proj_def456" ``` --- #### GET /v1/identities/{identity_id}/latest Get the most recent inbound event for an identity, including extraction data if available. **Response (200 OK):** ```json { "eventId": "evt_x1y2z3", "sender": "noreply@example.com", "subject": "Your verification code", "receivedAt": "2026-04-06T10:05:00Z", "extraction": { "eventId": "evt_x1y2z3", "type": "otp", "has_secret": true, "redacted_value": "***", "primaryActionUrl": null, "confidence": 0.99, "parserVersion": "v3.2", "modelName": null, "createdAt": "2026-04-06T10:05:02Z" } } ``` **curl example:** ```bash curl https://api.aidenid.com/v1/identities/ident_a1b2c3d4e5/latest \ -H "Authorization: Bearer aid_your_api_key" \ -H "X-Org-Id: org_abc123" \ -H "X-Project-Id: proj_def456" ``` --- #### GET /v1/identities/{identity_id}/latest-extraction Get the most recent extraction result (OTP code, magic link, etc.) for an identity. **Response (200 OK):** ```json { "eventId": "evt_x1y2z3", "type": "otp", "has_secret": true, "redacted_value": "***", "primaryActionUrl": null, "confidence": 0.99, "parserVersion": "v3.2", "modelName": null, "createdAt": "2026-04-06T10:05:02Z" } ``` | Field | Type | Description | |--------------------|--------|-------------------------------------------------| | `eventId` | string | Source event that produced this extraction | | `type` | string | `"otp"` or `"link"` | | `has_secret` | bool | Whether a raw secret exists in the secure server-side path | | `redacted_value` | string | Redacted placeholder for display/logging | | `primaryActionUrl` | string | Extracted URL (null if type is `"otp"`) | | `confidence` | float | Extraction confidence score (0.0 - 1.0) | | `parserVersion` | string | Version of the extraction parser | | `modelName` | string | ML model used for extraction (null if rules) | **curl example:** ```bash curl https://api.aidenid.com/v1/identities/ident_a1b2c3d4e5/latest-extraction \ -H "Authorization: Bearer aid_your_api_key" \ -H "X-Org-Id: org_abc123" \ -H "X-Project-Id: proj_def456" ``` **Python example (poll for extraction):** ```python import time import requests for attempt in range(30): resp = requests.get( f"{API}/v1/identities/{identity_id}/latest-extraction", headers=HEADERS, ) if resp.status_code == 200: extraction = resp.json() if extraction["type"] == "otp": print(f"Extraction ready: {extraction['type']} (confidence: {extraction['confidence']})") else: print("Action link is available in the secure server-side path") break time.sleep(2) ``` --- #### GET /v1/identities/events/recent List recent inbound events across all identities in the project. Includes extraction data when available. **Query Parameters:** | Parameter | Type | Default | Description | |--------------|--------|---------|--------------------------------------| | `cursor` | string | null | Pagination cursor | | `limit` | int | 20 | Max results (1-100) | | `identityId` | string | null | Filter to a specific identity | **Response (200 OK):** ```json { "items": [ { "id": "evt_x1y2z3", "identityId": "ident_a1b2c3d4e5", "identityEmailAddress": "a1b2c3d4e5@inbox.aidenid.com", "sender": "noreply@example.com", "subject": "Your verification code", "messageId": "", "storageKey": "s3://bucket/key", "receivedAt": "2026-04-06T10:05:00Z", "extraction": { "type": "otp", "has_secret": true, "redacted_value": "***", "primaryActionUrl": null, "confidence": 0.99, "parserVersion": "v3.2", "modelName": null, "createdAt": "2026-04-06T10:05:02Z" } } ], "meta": { "cursor": null, "hasMore": false, "total": 1 } } ``` **curl example:** ```bash curl "https://api.aidenid.com/v1/identities/events/recent?limit=10" \ -H "Authorization: Bearer aid_your_api_key" \ -H "X-Org-Id: org_abc123" \ -H "X-Project-Id: proj_def456" ``` --- #### POST /v1/identities/{identity_id}/children Create a child identity linked to a parent. Useful for multi-step flows (e.g., signup then password reset on the same service). **Additional Required Headers:** ``` Idempotency-Key: ``` **Request Body:** ```json { "aliasTemplate": "recovery-flow", "ttlHours": 24, "tags": ["recovery"], "policy": { "receiveMode": "EDGE_ACCEPT", "allowWebhooks": true, "extractionTypes": ["otp", "link"] }, "eventBudget": 10 } ``` | Field | Type | Default | Description | |----------------|--------|---------|-------------------------------------------------| | `aliasTemplate`| string | null | Optional email prefix | | `ttlHours` | int | 24 | Lifecycle hours (1 - 720) | | `tags` | string[]| [] | Tags for filtering | | `domainPoolId` | string | null | Domain pool to use | | `policy` | object | default | Policy config (same as parent creation) | | `eventBudget` | int | null | Max inbound events before auto-squash (1 - 1M) | **Response (200 OK):** Identity object with `parentIdentityId` set. **curl example:** ```bash curl -X POST https://api.aidenid.com/v1/identities/ident_parent/children \ -H "Authorization: Bearer aid_your_api_key" \ -H "X-Org-Id: org_abc123" \ -H "X-Project-Id: proj_def456" \ -H "Idempotency-Key: $(uuidgen)" \ -H "Content-Type: application/json" \ -d '{"aliasTemplate": "recovery", "ttlHours": 24, "eventBudget": 10}' ``` --- #### POST /v1/identities/{identity_id}/revoke-children Revoke (squash) all child identities of a parent. **Additional Required Headers:** ``` Idempotency-Key: ``` **Response (200 OK):** ```json { "parentIdentityId": "ident_parent", "revokedCount": 3, "revokedIdentityIds": ["ident_child1", "ident_child2", "ident_child3"] } ``` **curl example:** ```bash curl -X POST https://api.aidenid.com/v1/identities/ident_parent/revoke-children \ -H "Authorization: Bearer aid_your_api_key" \ -H "X-Org-Id: org_abc123" \ -H "X-Project-Id: proj_def456" \ -H "Idempotency-Key: $(uuidgen)" ``` --- #### GET /v1/identities/{identity_id}/lineage Get the full lineage tree for an identity — parent and all children/descendants. **Response (200 OK):** ```json { "rootIdentityId": "ident_root", "nodes": [ { "identityId": "ident_root", "parentIdentityId": null, "emailAddress": "root@inbox.aidenid.com", "status": "ACTIVE", "expiresAt": "2026-04-10T10:00:00Z", "depth": 0 }, { "identityId": "ident_child1", "parentIdentityId": "ident_root", "emailAddress": "child1@inbox.aidenid.com", "status": "ACTIVE", "expiresAt": "2026-04-08T10:00:00Z", "depth": 1 } ], "edges": [ { "parentIdentityId": "ident_root", "childIdentityId": "ident_child1" } ] } ``` **curl example:** ```bash curl https://api.aidenid.com/v1/identities/ident_root/lineage \ -H "Authorization: Bearer aid_your_api_key" \ -H "X-Org-Id: org_abc123" \ -H "X-Project-Id: proj_def456" ``` --- #### POST /v1/identities/bulk Create multiple identities in a single request. **Additional Required Headers:** ``` Idempotency-Key: ``` **Request Body:** ```json { "count": 5, "aliasTemplate": "load-test", "ttlHours": 12, "tags": ["load-test", "batch-1"], "domainPoolId": "dp_abc123", "policy": { "receiveMode": "EDGE_ACCEPT", "allowWebhooks": true, "extractionTypes": ["otp"] } } ``` | Field | Type | Required | Description | |-----------------|----------|----------|------------------------------------------| | `count` | int | Yes | Number of identities to create (1-10000) | | `aliasTemplate` | string | No | Email prefix template | | `ttlHours` | int | No | TTL in hours (default: 24) | | `tags` | string[] | No | Tags for all created identities | | `domainPoolId` | string | No | Domain pool to use | | `policy` | object | No | Policy for all created identities | **Response (200 OK):** ```json { "items": [ { "id": "ident_001", "emailAddress": "001@inbox.aidenid.com", "status": "PROVISIONED", "..." : "..." }, { "id": "ident_002", "emailAddress": "002@inbox.aidenid.com", "status": "PROVISIONED", "..." : "..." } ], "count": 5 } ``` **curl example:** ```bash curl -X POST https://api.aidenid.com/v1/identities/bulk \ -H "Authorization: Bearer aid_your_api_key" \ -H "X-Org-Id: org_abc123" \ -H "X-Project-Id: proj_def456" \ -H "Idempotency-Key: $(uuidgen)" \ -H "Content-Type: application/json" \ -d '{"count": 5, "ttlHours": 12, "tags": ["load-test"]}' ``` **Python example:** ```python resp = requests.post( f"{API}/v1/identities/bulk", headers={**HEADERS, "Idempotency-Key": str(uuid.uuid4())}, json={"count": 10, "ttlHours": 24, "tags": ["batch-run"]}, ) bulk = resp.json() for ident in bulk["items"]: print(f" {ident['emailAddress']}") print(f"Created {bulk['count']} identities") ``` --- #### POST /v1/identities/bulk-squash Squash multiple identities at once, filtered by tags. **Additional Required Headers:** ``` Idempotency-Key: ``` **Request Body:** ```json { "tags": ["load-test"], "limit": 100, "onlyActive": true, "confirmAll": false } ``` | Field | Type | Default | Description | |--------------|----------|---------|-----------------------------------------------------| | `tags` | string[] | [] | Filter by tags (empty = all) | | `limit` | int | 1000 | Max identities to squash (1 - 10000) | | `onlyActive` | bool | true | Only squash active identities | | `confirmAll` | bool | false | Confirm squashing even when tags are empty | **Response (200 OK):** ```json { "scope": "project", "requestedLimit": 100, "matchedCount": 5, "squashedCount": 5, "skippedCount": 0, "tags": ["load-test"], "identityIds": ["ident_001", "ident_002", "ident_003", "ident_004", "ident_005"] } ``` **curl example:** ```bash curl -X POST https://api.aidenid.com/v1/identities/bulk-squash \ -H "Authorization: Bearer aid_your_api_key" \ -H "X-Org-Id: org_abc123" \ -H "X-Project-Id: proj_def456" \ -H "Idempotency-Key: $(uuidgen)" \ -H "Content-Type: application/json" \ -d '{"tags": ["load-test"], "limit": 100}' ``` --- ### 3.4 Trials API (`/v1/trials/*`) Start, check, and convert free trials of paid agent plans. 7-day trial, no credit card required. --- #### POST /v1/trials/start Start a free trial. Provisions an organization, project, and API key for the trial period. **Auth:** None (public) **Request Body:** ```json { "planId": "growth", "ownerEmail": "agent-dev@company.com", "orgName": "My AI Startup" } ``` | Field | Type | Required | Description | |--------------|--------|----------|------------------------------------------------| | `planId` | string | Yes | Plan to trial: `"starter"`, `"growth"`, `"pro"` | | `ownerEmail` | string | Yes | Email of the trial owner | | `orgName` | string | No | Optional organization display name (max 128) | **Response (201 Created):** ```json { "trialId": "trial_abc123", "planId": "growth", "planName": "Growth", "status": "ACTIVE", "startedAt": "2026-04-06T10:00:00Z", "expiresAt": "2026-04-13T10:00:00Z", "organizationId": "org_new123", "projectId": "proj_new456", "apiToken": "aid_trial_..." } ``` **curl example:** ```bash curl -X POST https://api.aidenid.com/v1/trials/start \ -H "Content-Type: application/json" \ -d '{ "planId": "growth", "ownerEmail": "agent-dev@company.com", "orgName": "My AI Startup" }' ``` **Python example:** ```python resp = requests.post( "https://api.aidenid.com/v1/trials/start", json={"planId": "growth", "ownerEmail": "dev@company.com"}, ) trial = resp.json() api_key = trial["apiToken"] org_id = trial["organizationId"] project_id = trial["projectId"] print(f"Trial active until {trial['expiresAt']}") print(f"API Key: {api_key}") ``` **TypeScript example:** ```typescript const resp = await fetch("https://api.aidenid.com/v1/trials/start", { method: "POST", headers: { "Content-Type": "application/json" }, body: JSON.stringify({ planId: "growth", ownerEmail: "dev@company.com" }), }); const trial = await resp.json(); console.log(`Trial API key: ${trial.apiToken}`); console.log(`Expires: ${trial.expiresAt}`); ``` --- #### GET /v1/trials/{trial_id} Check the status of a trial including remaining time. **Auth:** None (public, keyed by trial ID) **Response (200 OK):** ```json { "trialId": "trial_abc123", "planId": "growth", "planName": "Growth", "status": "ACTIVE", "startedAt": "2026-04-06T10:00:00Z", "expiresAt": "2026-04-13T10:00:00Z", "convertedAt": null, "convertedPlanId": null, "remainingHours": 168, "organizationId": "org_new123", "projectId": "proj_new456" } ``` | Field | Type | Description | |-------------------|--------|---------------------------------------------------| | `status` | string | `ACTIVE`, `EXPIRED`, `CONVERTED`, or `CANCELED` | | `remainingHours` | int | Hours remaining in the trial | | `convertedAt` | string | Timestamp when trial was converted (null if not) | | `convertedPlanId` | string | Plan ID after conversion (null if not converted) | **curl example:** ```bash curl https://api.aidenid.com/v1/trials/trial_abc123 ``` --- #### POST /v1/trials/{trial_id}/convert Convert a trial to a paid subscription. Optionally specify a different target plan. **Auth:** None (public, keyed by trial ID) **Request Body (optional):** ```json { "targetPlanId": "pro" } ``` | Field | Type | Required | Description | |----------------|--------|----------|---------------------------------------------| | `targetPlanId` | string | No | Plan to convert to (defaults to trial plan) | **Response (200 OK):** ```json { "trialId": "trial_abc123", "convertedPlanId": "pro", "convertedPlanName": "Pro", "status": "CONVERTED", "convertedAt": "2026-04-08T14:00:00Z", "message": "Trial converted to Pro plan. Billing starts now." } ``` **curl example:** ```bash curl -X POST https://api.aidenid.com/v1/trials/trial_abc123/convert \ -H "Content-Type: application/json" \ -d '{"targetPlanId": "pro"}' ``` --- ### 3.5 Webhooks API (`/v1/webhooks/*`) Register webhook endpoints to receive real-time event notifications. All webhook payloads are signed with HMAC-SHA256. Requires API key authentication. --- #### POST /v1/webhooks Register a new webhook endpoint. **Additional Required Headers:** ``` Idempotency-Key: ``` **Request Body:** ```json { "url": "https://your-app.com/webhooks/aidenid" } ``` | Field | Type | Required | Description | |-------|--------|----------|------------------------------------| | `url` | string | Yes | HTTPS URL to receive webhook POSTs | **Response (200 OK):** ```json { "id": "wh_p1q2r3s4", "url": "https://your-app.com/webhooks/aidenid", "status": "active", "signatureVersion": "v1", "createdAt": "2026-04-06T10:00:00Z", "lastRotatedAt": "2026-04-06T10:00:00Z", "secret": "whsec_..." } ``` The `secret` is only returned on creation and rotation. Store it securely. **curl example:** ```bash curl -X POST https://api.aidenid.com/v1/webhooks \ -H "Authorization: Bearer aid_your_api_key" \ -H "X-Org-Id: org_abc123" \ -H "X-Project-Id: proj_def456" \ -H "Idempotency-Key: $(uuidgen)" \ -H "Content-Type: application/json" \ -d '{"url": "https://your-app.com/webhooks/aidenid"}' ``` **Python example:** ```python resp = requests.post( f"{API}/v1/webhooks", headers={**HEADERS, "Idempotency-Key": str(uuid.uuid4())}, json={"url": "https://your-app.com/webhooks/aidenid"}, ) webhook = resp.json() secret = webhook["secret"] # Store this securely print(f"Webhook registered: {webhook['id']}") ``` --- #### GET /v1/webhooks List all registered webhook endpoints for the project. **Query Parameters:** | Parameter | Type | Default | Description | |-----------|------|---------|---------------------| | `limit` | int | 50 | Max results (1-100) | **Response (200 OK):** ```json { "items": [ { "id": "wh_p1q2r3s4", "url": "https://your-app.com/webhooks/aidenid", "status": "active", "signatureVersion": "v1", "createdAt": "2026-04-06T10:00:00Z", "lastRotatedAt": "2026-04-06T10:00:00Z" } ], "meta": { "cursor": null, "hasMore": false, "total": 1 } } ``` **curl example:** ```bash curl https://api.aidenid.com/v1/webhooks \ -H "Authorization: Bearer aid_your_api_key" \ -H "X-Org-Id: org_abc123" \ -H "X-Project-Id: proj_def456" ``` --- #### POST /v1/webhooks/{webhook_id}/rotate-secret Rotate the signing secret for a webhook endpoint. Returns a new secret; the old one is invalidated immediately. **Additional Required Headers:** ``` Idempotency-Key: ``` **Response (200 OK):** ```json { "endpointId": "wh_p1q2r3s4", "secret": "whsec_new_...", "signatureVersion": "v1", "lastRotatedAt": "2026-04-06T14:00:00Z" } ``` **curl example:** ```bash curl -X POST https://api.aidenid.com/v1/webhooks/wh_p1q2r3s4/rotate-secret \ -H "Authorization: Bearer aid_your_api_key" \ -H "X-Org-Id: org_abc123" \ -H "X-Project-Id: proj_def456" \ -H "Idempotency-Key: $(uuidgen)" ``` --- #### POST /v1/webhooks/{webhook_id}/replay Replay a specific event to a webhook endpoint. Useful for debugging or recovering from failures. **Additional Required Headers:** ``` Idempotency-Key: ``` **Request Body:** ```json { "eventId": "evt_x1y2z3" } ``` **Response (200 OK):** ```json { "deliveryId": "dlv_abc123", "status": "delivered", "attemptCount": 1, "lastAttemptAt": "2026-04-06T14:01:00Z", "lastError": null } ``` **curl example:** ```bash curl -X POST https://api.aidenid.com/v1/webhooks/wh_p1q2r3s4/replay \ -H "Authorization: Bearer aid_your_api_key" \ -H "X-Org-Id: org_abc123" \ -H "X-Project-Id: proj_def456" \ -H "Idempotency-Key: $(uuidgen)" \ -H "Content-Type: application/json" \ -d '{"eventId": "evt_x1y2z3"}' ``` --- ### 3.6 Auth Flows / Reliability API (`/v1/reliability/*`) Create and monitor automated auth flow test runs. Test that your password reset and invite flows actually deliver OTPs/links and that AIdenID extracts them correctly. Requires API key authentication. --- #### POST /v1/reliability/password-reset/run Create a password reset flow test run. **Additional Required Headers:** ``` Idempotency-Key: ``` **Request Body:** ```json { "identityId": "ident_a1b2c3d4e5", "expectedSender": "noreply@example.com", "expectedSubjectContains": "password reset", "expectedActionHost": "example.com", "completionCallbackUrl": "https://your-app.com/callbacks/reliability", "metadata": { "environment": "staging", "triggered_by": "ci-pipeline" } } ``` | Field | Type | Required | Description | |----------------------------|--------|----------|----------------------------------------------------| | `identityId` | string | Yes | Identity to use for receiving the reset email | | `expectedSender` | string | No | Expected sender address for assertion | | `expectedSubjectContains` | string | No | Expected substring in subject | | `expectedActionHost` | string | No | Expected host in extracted action URL | | `completionCallbackUrl` | string | No | HTTPS URL to POST results when run completes | | `metadata` | object | No | Arbitrary key-value metadata | **Response (200 OK):** ```json { "id": "run_t1u2v3w4", "projectId": "proj_def456", "identityId": "ident_a1b2c3d4e5", "flowType": "password_reset", "status": "pending", "sourceEventId": null, "extractionId": null, "assertions": { "emailReceived": false, "extractionHasOtpOrLink": false, "completionCallbackCaptured": false }, "callback": { "url": "https://your-app.com/callbacks/reliability", "status": "pending", "httpStatus": null, "error": null, "attemptedAt": null }, "failureReason": null, "metadata": { "environment": "staging", "triggered_by": "ci-pipeline" }, "createdAt": "2026-04-06T10:10:00Z", "updatedAt": "2026-04-06T10:10:00Z", "completedAt": null } ``` **curl example:** ```bash curl -X POST https://api.aidenid.com/v1/reliability/password-reset/run \ -H "Authorization: Bearer aid_your_api_key" \ -H "X-Org-Id: org_abc123" \ -H "X-Project-Id: proj_def456" \ -H "Idempotency-Key: $(uuidgen)" \ -H "Content-Type: application/json" \ -d '{ "identityId": "ident_a1b2c3d4e5", "expectedSender": "noreply@example.com", "expectedSubjectContains": "password reset" }' ``` **Python example:** ```python resp = requests.post( f"{API}/v1/reliability/password-reset/run", headers={**HEADERS, "Idempotency-Key": str(uuid.uuid4())}, json={ "identityId": identity_id, "expectedSender": "noreply@example.com", "completionCallbackUrl": "https://your-app.com/callbacks/reliability", }, ) run = resp.json() run_id = run["id"] print(f"Reliability run started: {run_id}") ``` --- #### POST /v1/reliability/invite/run Create an invite flow test run. Same request/response shape as password-reset but with `flowType: "invite"`. **Additional Required Headers:** ``` Idempotency-Key: ``` **Request Body:** Same as password-reset/run. **curl example:** ```bash curl -X POST https://api.aidenid.com/v1/reliability/invite/run \ -H "Authorization: Bearer aid_your_api_key" \ -H "X-Org-Id: org_abc123" \ -H "X-Project-Id: proj_def456" \ -H "Idempotency-Key: $(uuidgen)" \ -H "Content-Type: application/json" \ -d '{"identityId": "ident_a1b2c3d4e5"}' ``` --- #### GET /v1/reliability/runs/{run_id} Get the status and result of a reliability test run. **Response (200 OK):** Same shape as the run creation response, with `status` updated to `"passed"`, `"failed"`, or `"timeout"`, and assertions populated. **curl example:** ```bash curl https://api.aidenid.com/v1/reliability/runs/run_t1u2v3w4 \ -H "Authorization: Bearer aid_your_api_key" \ -H "X-Org-Id: org_abc123" \ -H "X-Project-Id: proj_def456" ``` --- ### 3.7 Domains & Targets API (`/v1/domains/*`, `/v1/targets/*`) Register custom domains for identity inboxes, verify ownership via DNS, and manage domain lifecycle. Targets represent external services tested via reliability runs. Requires API key authentication. --- #### POST /v1/domains Register a custom domain for identity inboxes. **Additional Required Headers:** ``` Idempotency-Key: ``` **Request Body:** ```json { "domainName": "mail.mycompany.com", "trustClass": "BYOD", "verificationMethod": "DNS_TXT", "challengeValue": null, "proofTtlHours": 24 } ``` | Field | Type | Default | Description | |----------------------|--------|------------|--------------------------------------------| | `domainName` | string | (required) | Domain to register (3-255 chars) | | `trustClass` | string | `"BYOD"` | Trust classification | | `verificationMethod` | string | `"DNS_TXT"`| Verification method | | `challengeValue` | string | null | Optional custom challenge value | | `proofTtlHours` | int | 24 | How long the verification proof is valid | **Response (200 OK):** ```json { "domain": { "id": "dom_abc123", "projectId": "proj_def456", "domainName": "mail.mycompany.com", "verificationStatus": "pending", "trustClass": "BYOD", "freezeStatus": "active", "verificationMethod": "DNS_TXT", "verifiedAt": null, "expiresAt": null, "reviewerOverride": false, "reviewerOverrideReason": null, "domainPoolId": "dp_xyz", "createdAt": "2026-04-06T10:00:00Z", "updatedAt": "2026-04-06T10:00:00Z" }, "proofId": "proof_abc", "challengeValue": "aidenid-verify=abc123def456", "proofStatus": "pending", "proofExpiresAt": "2026-04-07T10:00:00Z" } ``` **curl example:** ```bash curl -X POST https://api.aidenid.com/v1/domains \ -H "Authorization: Bearer aid_your_api_key" \ -H "X-Org-Id: org_abc123" \ -H "X-Project-Id: proj_def456" \ -H "Idempotency-Key: $(uuidgen)" \ -H "Content-Type: application/json" \ -d '{"domainName": "mail.mycompany.com"}' ``` --- #### POST /v1/domains/{domain_id}/verify Trigger domain verification by providing proof of DNS record. **Additional Required Headers:** ``` Idempotency-Key: ``` **Request Body:** ```json { "method": "DNS_TXT", "challengeValue": "aidenid-verify=abc123def456", "proofValue": "abc123def456", "verificationSource": "cloudflare", "reviewerOverride": false, "expiresHours": 24 } ``` **Response (200 OK):** DomainProofResponse with updated `proofStatus` and `verifiedAt`. **curl example:** ```bash curl -X POST https://api.aidenid.com/v1/domains/dom_abc123/verify \ -H "Authorization: Bearer aid_your_api_key" \ -H "X-Org-Id: org_abc123" \ -H "X-Project-Id: proj_def456" \ -H "Idempotency-Key: $(uuidgen)" \ -H "Content-Type: application/json" \ -d '{"method": "DNS_TXT", "challengeValue": "aidenid-verify=abc123"}' ``` --- #### POST /v1/domains/{domain_id}/freeze Freeze a domain (disable all identity provisioning on this domain). Used for abuse response. **Additional Required Headers:** ``` Idempotency-Key: ``` **Request Body:** ```json { "reason": "Abuse detected: high volume spam signups", "poolIsolated": true } ``` | Field | Type | Required | Description | |----------------|--------|----------|----------------------------------------------| | `reason` | string | Yes | Reason for freezing (3-512 chars) | | `poolIsolated` | bool | No | Whether to isolate the domain pool (default: true) | **Response (200 OK):** DomainResponse with `freezeStatus: "frozen"`. **curl example:** ```bash curl -X POST https://api.aidenid.com/v1/domains/dom_abc123/freeze \ -H "Authorization: Bearer aid_your_api_key" \ -H "X-Org-Id: org_abc123" \ -H "X-Project-Id: proj_def456" \ -H "Idempotency-Key: $(uuidgen)" \ -H "Content-Type: application/json" \ -d '{"reason": "Abuse detected"}' ``` --- #### POST /v1/domains/{domain_id}/unfreeze Unfreeze a previously frozen domain. **Additional Required Headers:** ``` Idempotency-Key: ``` **Request Body:** ```json { "reason": "Abuse investigation resolved" } ``` **Response (200 OK):** DomainResponse with `freezeStatus: "active"`. **curl example:** ```bash curl -X POST https://api.aidenid.com/v1/domains/dom_abc123/unfreeze \ -H "Authorization: Bearer aid_your_api_key" \ -H "X-Org-Id: org_abc123" \ -H "X-Project-Id: proj_def456" \ -H "Idempotency-Key: $(uuidgen)" \ -H "Content-Type: application/json" \ -d '{"reason": "Issue resolved"}' ``` --- #### POST /v1/targets Register a reliability-test target (external service to test auth flows against). **Additional Required Headers:** ``` Idempotency-Key: ``` **Request Body:** ```json { "host": "example.com", "domainId": "dom_abc123", "maintenanceWindow": {}, "contact": { "email": "ops@example.com" }, "policy": { "allowedPaths": ["/forgot-password", "/invite"], "allowedMethods": ["POST"], "allowedScenarios": ["password_reset", "invite"], "maxRps": 5, "maxConcurrency": 5, "stopConditions": {} } } ``` **Response (200 OK):** TargetProofResponse with target details and verification proof. **curl example:** ```bash curl -X POST https://api.aidenid.com/v1/targets \ -H "Authorization: Bearer aid_your_api_key" \ -H "X-Org-Id: org_abc123" \ -H "X-Project-Id: proj_def456" \ -H "Idempotency-Key: $(uuidgen)" \ -H "Content-Type: application/json" \ -d '{"host": "example.com"}' ``` --- #### POST /v1/targets/{target_id}/verify Verify ownership of a target. **Additional Required Headers:** ``` Idempotency-Key: ``` **Request Body:** Same shape as domain verify. **curl example:** ```bash curl -X POST https://api.aidenid.com/v1/targets/tgt_abc123/verify \ -H "Authorization: Bearer aid_your_api_key" \ -H "X-Org-Id: org_abc123" \ -H "X-Project-Id: proj_def456" \ -H "Idempotency-Key: $(uuidgen)" \ -H "Content-Type: application/json" \ -d '{"method": "DNS_TXT", "challengeValue": "aidenid-verify=xyz"}' ``` --- #### GET /v1/targets/{target_id} Get target details. **Response (200 OK):** ```json { "id": "tgt_abc123", "projectId": "proj_def456", "domainId": "dom_abc123", "host": "example.com", "verificationStatus": "verified", "status": "active", "freezeStatus": "active", "maintenanceWindow": {}, "contact": { "email": "ops@example.com" }, "verifiedAt": "2026-04-06T11:00:00Z", "createdAt": "2026-04-06T10:00:00Z", "updatedAt": "2026-04-06T11:00:00Z", "policy": { "allowedPaths": ["/forgot-password"], "allowedMethods": ["POST"], "allowedScenarios": ["password_reset"], "maxRps": 5, "maxConcurrency": 5, "stopConditions": {}, "approvedBy": null, "approvedAt": null, "updatedAt": "2026-04-06T10:00:00Z" } } ``` **curl example:** ```bash curl https://api.aidenid.com/v1/targets/tgt_abc123 \ -H "Authorization: Bearer aid_your_api_key" \ -H "X-Org-Id: org_abc123" \ -H "X-Project-Id: proj_def456" ``` --- ### 3.8 Billing API (`/v1/billing/*`) Manage subscriptions, view usage, create Stripe checkout sessions, and manage credit balances. Requires API key authentication. --- #### GET /v1/billing/usage Get billing usage for the current billing period. **Required Permission:** `billing:read` **Query Parameters:** | Parameter | Type | Default | Description | |------------|--------|---------|--------------------------------------| | `asOfDate` | string | today | ISO date (YYYY-MM-DD) for usage snapshot | **Response (200 OK):** ```json { "asOfDate": "2026-04-06", "windowStart": "2026-04-01T00:00:00Z", "windowEnd": "2026-04-30T23:59:59Z", "items": [ { "dimension": "identities.provisioned", "quantity": 42.0, "unit": "count", "sourceCount": 42 }, { "dimension": "events.inbound", "quantity": 1234.0, "unit": "count", "sourceCount": 1234 } ] } ``` **curl example:** ```bash curl "https://api.aidenid.com/v1/billing/usage?asOfDate=2026-04-06" \ -H "Authorization: Bearer aid_your_api_key" \ -H "X-Org-Id: org_abc123" \ -H "X-Project-Id: proj_def456" ``` --- #### POST /v1/billing/checkout Create a Stripe checkout session for a plan subscription. **Required Permission:** `billing:write` **Request Body:** ```json { "planId": "growth", "quantity": 1, "successUrl": "https://your-app.com/billing/success", "cancelUrl": "https://your-app.com/billing/cancel" } ``` | Field | Type | Default | Description | |--------------|--------|------------|------------------------------------| | `planId` | string | `"starter"`| Plan ID to subscribe to | | `quantity` | int | 1 | Quantity (1 - 10,000) | | `successUrl` | string | (required) | URL to redirect on success | | `cancelUrl` | string | (required) | URL to redirect on cancel | **Response (200 OK):** ```json { "provider": "stripe", "mode": "subscription", "checkoutUrl": "https://checkout.stripe.com/c/pay/cs_...", "sessionId": "cs_abc123", "expiresAt": "2026-04-06T11:00:00Z" } ``` **curl example:** ```bash curl -X POST https://api.aidenid.com/v1/billing/checkout \ -H "Authorization: Bearer aid_your_api_key" \ -H "X-Org-Id: org_abc123" \ -H "X-Project-Id: proj_def456" \ -H "Content-Type: application/json" \ -d '{ "planId": "growth", "successUrl": "https://your-app.com/billing/success", "cancelUrl": "https://your-app.com/billing/cancel" }' ``` --- #### POST /v1/billing/credits/topup Create a Stripe checkout session to top up account credits. **Required Permission:** `billing:write` **Request Body:** ```json { "amountCents": 5000, "successUrl": "https://your-app.com/credits/success", "cancelUrl": "https://your-app.com/credits/cancel" } ``` | Field | Type | Required | Description | |---------------|--------|----------|----------------------------------------| | `amountCents` | int | Yes | Amount in cents (min $5.00, max $100k) | | `successUrl` | string | Yes | Redirect URL on success | | `cancelUrl` | string | Yes | Redirect URL on cancel | **Response (200 OK):** ```json { "provider": "stripe", "checkoutUrl": "https://checkout.stripe.com/c/pay/cs_...", "sessionId": "cs_topup_abc", "amountCents": 5000, "expiresAt": "2026-04-06T11:00:00Z" } ``` **curl example:** ```bash curl -X POST https://api.aidenid.com/v1/billing/credits/topup \ -H "Authorization: Bearer aid_your_api_key" \ -H "X-Org-Id: org_abc123" \ -H "X-Project-Id: proj_def456" \ -H "Content-Type: application/json" \ -d '{ "amountCents": 5000, "successUrl": "https://your-app.com/credits/success", "cancelUrl": "https://your-app.com/credits/cancel" }' ``` --- #### GET /v1/billing/credits/balance Get current credit balance. **Required Permission:** `billing:read` **Response (200 OK):** ```json { "balanceCents": 15000, "lifetimeTopupCents": 50000, "lifetimeUsageCents": 35000, "currency": "usd" } ``` **curl example:** ```bash curl https://api.aidenid.com/v1/billing/credits/balance \ -H "Authorization: Bearer aid_your_api_key" \ -H "X-Org-Id: org_abc123" \ -H "X-Project-Id: proj_def456" ``` --- #### GET /v1/billing/credits/transactions List credit transactions with pagination. **Required Permission:** `billing:read` **Query Parameters:** | Parameter | Type | Default | Description | |-----------|------|---------|-----------------------| | `limit` | int | 50 | Max results (1-200) | | `offset` | int | 0 | Pagination offset | **Response (200 OK):** ```json { "items": [ { "id": "txn_abc", "txnType": "topup", "amountCents": 5000, "balanceAfterCents": 15000, "description": "Credit top-up via Stripe", "createdAt": "2026-04-06T10:00:00Z" }, { "id": "txn_def", "txnType": "usage", "amountCents": -250, "balanceAfterCents": 14750, "description": "Identity provisioning (5 identities)", "createdAt": "2026-04-06T10:30:00Z" } ], "total": 2 } ``` **curl example:** ```bash curl "https://api.aidenid.com/v1/billing/credits/transactions?limit=10" \ -H "Authorization: Bearer aid_your_api_key" \ -H "X-Org-Id: org_abc123" \ -H "X-Project-Id: proj_def456" ``` --- #### GET /v1/billing/domains/{domain_id}/pricing Get pricing details for a domain, including marketplace and platform fees. **Required Permission:** `billing:read` **Response (200 OK):** ```json { "domainId": "dom_abc123", "domainName": "mail.mycompany.com", "pricePerIdentityCents": 100, "setupFeeCents": 2500, "monthlyHostingFeeCents": 1000, "marketplaceListed": true, "platformSetupFeeCents": 500, "platformMonthlyHostingCents": 200, "platformRevenueSharePct": 15.0 } ``` **curl example:** ```bash curl https://api.aidenid.com/v1/billing/domains/dom_abc123/pricing \ -H "Authorization: Bearer aid_your_api_key" \ -H "X-Org-Id: org_abc123" \ -H "X-Project-Id: proj_def456" ``` --- #### PUT /v1/billing/domains/{domain_id}/pricing Update pricing for a domain. **Required Permission:** `billing:write` **Request Body:** ```json { "pricePerIdentityCents": 150, "setupFeeCents": 3000, "monthlyHostingFeeCents": 1200, "marketplaceListed": true } ``` **Response (200 OK):** Same as GET pricing response with updated values. **curl example:** ```bash curl -X PUT https://api.aidenid.com/v1/billing/domains/dom_abc123/pricing \ -H "Authorization: Bearer aid_your_api_key" \ -H "X-Org-Id: org_abc123" \ -H "X-Project-Id: proj_def456" \ -H "Content-Type: application/json" \ -d '{"pricePerIdentityCents": 150, "setupFeeCents": 3000, "monthlyHostingFeeCents": 1200, "marketplaceListed": true}' ``` --- #### POST /v1/billing/webhook Stripe webhook endpoint. Receives Stripe events (checkout.session.completed, etc.). Verified by Stripe signature, no AIdenID auth required. **Required Headers:** ``` Stripe-Signature: ``` This is an internal endpoint for Stripe event delivery; you do not call this directly. --- ### 3.9 Realtime API (`/v1/realtime/*`) Server-Sent Events (SSE) stream for real-time delivery of inbound events across all identities in a project. Requires API key authentication. --- #### GET /v1/realtime/events Opens a persistent SSE connection. The server pushes `inbound_event` messages as emails arrive at any identity in the project. **Query Parameters:** | Parameter | Type | Default | Description | |-----------|--------|---------|-------------------------------------------------| | `cursor` | string | null | Base64-encoded cursor for resuming from a position | | `limit` | int | 50 | Max events per poll cycle (1-100) | **SSE Event Format:** ``` id: evt_x1y2z3 event: inbound_event data: {"cursor":"eyJ...","eventId":"evt_x1y2z3","identityId":"ident_a1b2c3d4e5","sender":"noreply@example.com","subject":"Your code","messageId":"","receivedAt":"2026-04-06T10:05:00Z"} ``` **Keep-alive (sent when no events):** ``` : keep-alive ``` **Connection Details:** - Content-Type: `text/event-stream` - Cache-Control: `no-cache` - Connection: `keep-alive` - Max stream duration: 30 minutes (reconnect after) - Use `Last-Event-ID` or `cursor` parameter for reconnection **curl example:** ```bash curl -N "https://api.aidenid.com/v1/realtime/events" \ -H "Authorization: Bearer aid_your_api_key" \ -H "X-Org-Id: org_abc123" \ -H "X-Project-Id: proj_def456" ``` **TypeScript example (EventSource):** ```typescript const url = new URL("https://api.aidenid.com/v1/realtime/events"); // Note: EventSource does not support custom headers. Use a polyfill // like eventsource or event-source-polyfill that supports headers. const es = new EventSource(url.toString()); es.addEventListener("inbound_event", (event) => { const data = JSON.parse(event.data); console.log(`New email at ${data.identityId} from ${data.sender}`); console.log(`Subject: ${data.subject}`); // Store cursor for reconnection lastCursor = data.cursor; }); es.onerror = () => { // Reconnect with cursor console.log("Reconnecting..."); }; ``` **Python example (sseclient):** ```python import json import sseclient import requests url = f"{API}/v1/realtime/events" resp = requests.get(url, headers=HEADERS, stream=True) client = sseclient.SSEClient(resp) for event in client.events(): if event.event == "inbound_event": data = json.loads(event.data) print(f"Event at {data['identityId']}: {data['subject']}") ``` --- ### 3.10 Exports API (`/v1/exports/*`) Bulk export inbound events and extraction data in JSONL or CSV format. Requires API key authentication and `exports:write` permission. --- #### POST /v1/exports/events Create an event export job. Returns a time-limited download URL. **Additional Required Headers:** ``` Idempotency-Key: ``` **Request Body:** ```json { "identityId": "ident_a1b2c3d4e5", "createdAfter": "2026-04-01T00:00:00Z", "createdBefore": "2026-04-06T23:59:59Z", "includeExtraction": true, "format": "jsonl", "limit": 500 } ``` | Field | Type | Default | Description | |---------------------|--------|----------|--------------------------------------------| | `identityId` | string | null | Filter to a specific identity | | `createdAfter` | string | null | ISO 8601 start date filter | | `createdBefore` | string | null | ISO 8601 end date filter | | `includeExtraction` | bool | true | Include extraction data in export | | `format` | string | `"jsonl"`| Export format: `"jsonl"` or `"csv"` | | `limit` | int | 500 | Max records (1 - 5000) | **Response (200 OK):** ```json { "exportId": "exp_abc123", "format": "jsonl", "recordCount": 42, "createdAfter": "2026-04-01T00:00:00Z", "createdBefore": "2026-04-06T23:59:59Z", "expiresAt": "2026-04-06T11:00:00Z", "downloadUrl": "https://api.aidenid.com/v1/exports/exp_abc123/download?token=..." } ``` **curl example:** ```bash curl -X POST https://api.aidenid.com/v1/exports/events \ -H "Authorization: Bearer aid_your_api_key" \ -H "X-Org-Id: org_abc123" \ -H "X-Project-Id: proj_def456" \ -H "Idempotency-Key: $(uuidgen)" \ -H "Content-Type: application/json" \ -d '{ "createdAfter": "2026-04-01T00:00:00Z", "format": "csv", "limit": 1000 }' ``` **Python example:** ```python resp = requests.post( f"{API}/v1/exports/events", headers={**HEADERS, "Idempotency-Key": str(uuid.uuid4())}, json={"format": "csv", "limit": 1000}, ) export = resp.json() download_url = export["downloadUrl"] print(f"Download {export['recordCount']} records: {download_url}") # Download the file download_resp = requests.get(download_url) with open("events.csv", "wb") as f: f.write(download_resp.content) ``` --- #### GET /v1/exports/{export_id}/download Download an export file. Uses a time-limited token for authentication (no API key needed). **Query Parameters:** | Parameter | Type | Required | Description | |-----------|--------|----------|--------------------------------| | `token` | string | Yes | Download token (min 16 chars) | **Response:** Binary file download with these headers: | Header | Description | |---------------------------|-------------------------------------| | `Content-Disposition` | `attachment; filename="export.csv"` | | `Cache-Control` | `private, no-store, max-age=0` | | `X-Export-Record-Count` | Number of records in the export | **curl example:** ```bash curl -o events.csv "https://api.aidenid.com/v1/exports/exp_abc123/download?token=abc123..." ``` --- ### 3.11 Marketplace API (`/v1/marketplace/*`) Browse and provision pre-built agent templates. Public browsing, authenticated template management. --- #### GET /v1/marketplace/agents List all active agent templates available in the marketplace. **Auth:** None (public) **Response (200 OK):** ```json { "items": [ { "id": "tmpl_signup", "slug": "signup-verifier", "name": "Signup Verifier", "description": "Automates email verification during user registration flows", "audience": "developers", "defaultPlan": "starter", "defaultScopes": ["identities:read", "identities:write"], "pricingHint": "From $49/mo" } ], "total": 1 } ``` **curl example:** ```bash curl https://api.aidenid.com/v1/marketplace/agents ``` **Python example:** ```python resp = requests.get(f"{API}/v1/marketplace/agents") agents = resp.json() for agent in agents["items"]: print(f"{agent['name']}: {agent['description']} ({agent['pricingHint']})") ``` --- #### POST /v1/marketplace/provision Provision an agent from a marketplace template. Creates a Stripe checkout session and onboarding flow. **Auth:** None (public) **Request Body:** ```json { "templateSlug": "signup-verifier", "agentName": "My Signup Bot", "ownerEmail": "dev@company.com", "planId": "growth", "successUrl": "https://your-app.com/onboarding/success", "cancelUrl": "https://your-app.com/onboarding/cancel" } ``` | Field | Type | Required | Description | |----------------|--------|----------|-------------------------------------------| | `templateSlug` | string | Yes | Marketplace template slug (1-64 chars) | | `agentName` | string | Yes | Display name for the agent (1-128 chars) | | `ownerEmail` | string | Yes | Owner email (5-255 chars) | | `planId` | string | No | Plan ID (defaults to template default) | | `successUrl` | string | Yes | Redirect URL on checkout success | | `cancelUrl` | string | Yes | Redirect URL on checkout cancel | **Response (200 OK):** ```json { "provider": "stripe", "checkoutUrl": "https://checkout.stripe.com/c/pay/cs_...", "sessionId": "cs_onboard_abc", "onboardingId": "onb_abc123", "templateSlug": "signup-verifier", "planId": "growth", "expiresAt": "2026-04-06T11:00:00Z" } ``` **curl example:** ```bash curl -X POST https://api.aidenid.com/v1/marketplace/provision \ -H "Content-Type: application/json" \ -d '{ "templateSlug": "signup-verifier", "agentName": "My Signup Bot", "ownerEmail": "dev@company.com", "successUrl": "https://your-app.com/success", "cancelUrl": "https://your-app.com/cancel" }' ``` --- #### GET /v1/marketplace/templates/{template_id} Get detailed information about a specific agent template. **Auth:** API key with `admin:read` permission **Response (200 OK):** ```json { "id": "tmpl_signup", "slug": "signup-verifier", "name": "Signup Verifier", "description": "Automates email verification during user registration flows", "audience": "developers", "defaultPlan": "starter", "defaultScopes": ["identities:read", "identities:write"], "isActive": true, "createdAt": "2026-01-15T10:00:00Z" } ``` **curl example:** ```bash curl https://api.aidenid.com/v1/marketplace/templates/tmpl_signup \ -H "Authorization: Bearer aid_your_api_key" \ -H "X-Org-Id: org_abc123" \ -H "X-Project-Id: proj_def456" ``` --- #### POST /v1/marketplace/templates Create a new agent template (admin only). **Auth:** API key with `admin:read` permission **Request Body:** ```json { "slug": "password-reset-bot", "name": "Password Reset Bot", "description": "Automates password reset flow testing and verification", "audience": "security-teams", "defaultPlan": "growth", "defaultScopes": ["identities:read", "identities:write", "reliability:write"], "isActive": true } ``` **Response (201 Created):** AgentTemplateDetailResponse. **curl example:** ```bash curl -X POST https://api.aidenid.com/v1/marketplace/templates \ -H "Authorization: Bearer aid_your_api_key" \ -H "X-Org-Id: org_abc123" \ -H "X-Project-Id: proj_def456" \ -H "Content-Type: application/json" \ -d '{"slug": "password-reset-bot", "name": "Password Reset Bot", "defaultPlan": "growth"}' ``` --- #### PATCH /v1/marketplace/templates/{template_id} Update an existing agent template (admin only). Only provided fields are updated. **Auth:** API key with `admin:read` permission **Request Body (all fields optional):** ```json { "name": "Updated Name", "description": "Updated description", "audience": "all", "defaultPlan": "pro", "defaultScopes": ["identities:read", "identities:write"], "isActive": false } ``` **Response (200 OK):** Updated AgentTemplateDetailResponse. **curl example:** ```bash curl -X PATCH https://api.aidenid.com/v1/marketplace/templates/tmpl_signup \ -H "Authorization: Bearer aid_your_api_key" \ -H "X-Org-Id: org_abc123" \ -H "X-Project-Id: proj_def456" \ -H "Content-Type: application/json" \ -d '{"isActive": false}' ``` --- ## 4. Identity Lifecycle Identities in AIdenID follow a defined state machine: ``` +-------------+ | PROVISIONED | <-- Identity created, inbox active, ready to receive +------+------+ | v +------+------+ | ACTIVE | <-- Identity in use, receiving and processing events +------+------+ | +----+----+ | | v v +---+----+ +--+------+ |EXTENDED| |SQUASHED | <-- Manual revocation, inbox disabled +---+----+ +----------+ | v +---+----+ |EXPIRED | <-- TTL elapsed without extension +--------+ ``` ### State Descriptions | State | Description | |---------------|----------------------------------------------------------------| | `PROVISIONED` | Identity created, inbox active, ready to receive email | | `ACTIVE` | Identity in use, receiving and processing inbound events | | `EXTENDED` | Lifecycle extended beyond original TTL | | `SQUASHED` | Identity revoked manually, inbox deactivated, data retained | | `EXPIRED` | Lifecycle TTL elapsed without extension | ### Lifecycle Policies - **TTL**: Configurable time-to-live (1 to 720 hours, depending on plan) - **Extension**: Active identities can be extended before expiration via `POST /extend` - **Squash**: Immediate revocation via `POST /squash`, disabling inbox and halting extraction - **Child identities**: Subordinate identities linked to a parent for multi-step flows - **Event budget**: Optional cap on inbound events before auto-squash (child identities only) - **Bulk operations**: Create and squash identities in batch --- ## 5. Trial Lifecycle Trials follow this state machine: ``` +--------+ | ACTIVE | <-- 7-day trial started, API key issued +---+----+ | +---+---+---+---+ | | | v v v EXPIRED CONVERTED CANCELED ``` | State | Description | |-------------|----------------------------------------------------| | `ACTIVE` | Trial is running, all plan features available | | `EXPIRED` | 7-day period elapsed without conversion | | `CONVERTED` | Trial converted to paid subscription | | `CANCELED` | Trial canceled by the owner | - Trials are 7 days, no credit card required - One trial per owner email per plan - `GET /v1/trials/{trial_id}` returns `remainingHours` - Convert at any time via `POST /v1/trials/{trial_id}/convert` - On expiration, API key is deactivated and identities are squashed --- ## 6. Webhook Event Types & Payload Formats ### Delivery Headers All webhook deliveries include: | Header | Description | |----------------|-----------------------------------------------------| | `X-Signature` | HMAC-SHA256 signature of `{timestamp}.{payload}` | | `X-Timestamp` | Unix timestamp of the delivery | | `Content-Type` | `application/json` | ### Verifying Signatures ``` signed_payload = "{X-Timestamp}.{raw_json_body}" expected = HMAC-SHA256(webhook_secret, signed_payload) Compare X-Signature header with expected (use constant-time comparison) ``` **TypeScript verification example:** ```typescript import { createHmac, timingSafeEqual } from "crypto"; function verifyWebhookSignature( payload: string, signature: string, timestamp: string, secret: string ): boolean { const signedPayload = `${timestamp}.${payload}`; const expected = createHmac("sha256", secret) .update(signedPayload) .digest("hex"); return timingSafeEqual(Buffer.from(signature), Buffer.from(expected)); } ``` **Python verification example:** ```python import hashlib import hmac def verify_webhook(payload: str, signature: str, timestamp: str, secret: str) -> bool: signed_payload = f"{timestamp}.{payload}" expected = hmac.new( secret.encode(), signed_payload.encode(), hashlib.sha256 ).hexdigest() return hmac.compare_digest(signature, expected) ``` ### Event Types | Event Type | Description | |-------------------------|--------------------------------------------------------| | `email.received` | New email arrived at an identity inbox | | `extraction.completed` | Authentication code or link extracted from email | | `identity.provisioned` | New identity created | | `identity.extended` | Identity lifecycle extended | | `identity.squashed` | Identity revoked | | `identity.expired` | Identity TTL elapsed | ### Payload Format ```json { "id": "evt_x1y2z3", "type": "extraction.completed", "timestamp": "2026-04-06T10:05:02Z", "data": { "identity_id": "ident_a1b2c3d4e5", "extraction": { "type": "otp", "has_secret": true, "redacted_value": "***", "confidence": 0.99 } } } ``` ### Example: Express.js Webhook Handler ```typescript app.post("/webhooks/aidenid", (req, res) => { const signature = req.headers["x-signature"] as string; const timestamp = req.headers["x-timestamp"] as string; const payload = JSON.stringify(req.body); if (!verifyWebhookSignature(payload, signature, timestamp, WEBHOOK_SECRET)) { return res.status(401).json({ error: "Invalid signature" }); } const event = req.body; switch (event.type) { case "extraction.completed": console.log(`Extraction ready: ${event.data.extraction.type}`); break; case "identity.squashed": console.log(`Identity revoked: ${event.data.identity_id}`); break; case "email.received": console.log(`Email from ${event.data.from} to identity ${event.data.identity_id}`); break; } res.status(200).json({ received: true }); }); ``` --- ## 7. Error Handling All API errors follow a consistent JSON format: ```json { "code": "identity_not_found", "message": "The requested identity does not exist or has been squashed.", "retryable": false, "request_id": "req_x1y2z3" } ``` ### Error Codes | Code | HTTP Status | Description | Retryable | |------------------------------|-------------|-------------------------------------------------|-----------| | `invalid_request` | 400 | Request body validation failed | No | | `missing_idempotency_key` | 400 | Mutation request missing Idempotency-Key header | No | | `invalid_cursor` | 400 | Realtime or pagination cursor is invalid | No | | `bad_request` | 400 | General bad request (e.g., missing Stripe sig) | No | | `unauthorized` | 401 | Invalid or missing API key / session token | No | | `forbidden` | 403 | API key lacks required scope or permission | No | | `feature_disabled` | 403 | Feature flag is disabled for this project | No | | `not_found` | 404 | Resource does not exist | No | | `identity_not_found` | 404 | Identity does not exist | No | | `identity_already_squashed` | 409 | Identity has already been revoked | No | | `rate_limited` | 429 | Too many requests | Yes | | `internal_error` | 500 | Unexpected server error | Yes | ### Retry Strategy For errors marked as `retryable: true`, implement exponential backoff: ```python import time import requests def api_request_with_retry(method, url, max_retries=5, **kwargs): for attempt in range(max_retries): resp = requests.request(method, url, **kwargs) if resp.status_code == 429: retry_after = int(resp.headers.get("Retry-After", 2 ** attempt)) time.sleep(retry_after) continue if resp.status_code >= 500: time.sleep(2 ** attempt) continue return resp raise Exception(f"Max retries exceeded for {method} {url}") ``` ```typescript async function fetchWithRetry(url: string, options: RequestInit, maxRetries = 5) { for (let attempt = 0; attempt < maxRetries; attempt++) { const resp = await fetch(url, options); if (resp.status === 429 || resp.status >= 500) { const wait = Math.pow(2, attempt) * 1000; await new Promise((r) => setTimeout(r, wait)); continue; } return resp; } throw new Error(`Max retries exceeded for ${url}`); } ``` --- ## 8. Rate Limits & Quotas ### Rate Limits by Plan | Plan | Requests/min | Burst (concurrent) | |------------|-------------|---------------------| | Free Tier | 10 | 3 | | Starter | 60 | 10 | | Growth | 300 | 50 | | Pro | 1,000 | 100 | | Business | 3,000 | 200 | | Scale | 10,000 | 500 | | Enterprise | Custom | Custom | ### Rate Limit Response Headers Every API response includes: | Header | Description | |-------------------------|------------------------------------------| | `X-RateLimit-Limit` | Max requests per window | | `X-RateLimit-Remaining` | Requests remaining in current window | | `X-RateLimit-Reset` | Unix timestamp when the window resets | | `Retry-After` | Seconds to wait (only on 429 responses) | ### Resource Quotas by Plan | Resource | Free Tier | Starter | Growth | Pro | Business | Scale | Enterprise | |------------------------|-----------|---------|--------|-------|----------|--------|------------| | Active identities | 1 | 10 | 50 | 200 | 500 | 2,000 | Unlimited | | Max TTL | 24h | 30 days | 90 days| 180 days| 365 days| 365 days| 365 days | | Custom domains | 0 | 0 | 3 | 10 | 25 | 100 | Unlimited | | Webhook endpoints | 0 | 2 | 10 | 50 | 100 | 500 | Unlimited | | Bulk create batch size | 0 | 5 | 20 | 50 | 200 | 1,000 | 10,000 | | Bulk squash batch size | 0 | 10 | 50 | 200 | 1,000 | 5,000 | 10,000 | | Export records limit | 0 | 100 | 500 | 2,000 | 5,000 | 5,000 | 5,000 | | Realtime SSE | No | No | Yes | Yes | Yes | Yes | Yes | | Reliability test runs | 0 | 5/day | 20/day | 100/day| 500/day | 2,000/day| Unlimited | --- ## 9. Response Headers Every API response includes the following headers for debugging and observability: | Header | Description | Example | |--------------------|-------------------------------------------------|------------------------------------| | `X-Request-Id` | Unique request identifier for support tickets | `req_a1b2c3d4e5` | | `X-Trace-Id` | Distributed trace identifier for observability | `trace_f6g7h8i9j0` | | `X-Root-Span-Id` | Root span ID for distributed tracing | `span_k1l2m3n4o5` | | `X-RateLimit-Limit` | Max requests per rate limit window | `300` | | `X-RateLimit-Remaining` | Remaining requests in current window | `297` | | `X-RateLimit-Reset` | Unix timestamp when rate limit window resets | `1712400000` | | `X-Idempotent-Replay` | Present when response is replayed from cache | `true` | --- ## 10. Pricing ### Supporting Identity Plans These legacy identity/inbox quotas support issuer, QA, demo, and inbox workflows around the clearance layer. | Plan | Monthly Price | Active Identities | Max TTL | Custom Domains | Webhooks | Trial | |------------|--------------|-------------------|-----------|----------------|----------|-----------| | Agent Free | Free | 1 | 24 hours | 0 | 0 | -- | | Starter | $49/mo | 10 | 30 days | 0 | 2 | 7-day free| | Growth | $199/mo | 50 | 90 days | 3 | 10 | 7-day free| | Pro | $599/mo | 200 | 180 days | 10 | 50 | 7-day free| | Business | $1,499/mo | 500 | 365 days | 25 | 100 | 7-day free| | Scale | $3,999/mo | 2,000 | 365 days | 100 | 500 | 7-day free| | Enterprise | Custom | Unlimited | 365 days | Unlimited | Unlimited| Custom | ### Supporting Human Inbox Plans | Plan | Monthly Price | Disposable Emails | TTL | OTP Deliveries | |--------------|--------------|-------------------|---------|----------------| | Free Trial | Free | 3 | 7 days | 3 total | | Personal | $29/mo | 10 | 30 days | 100/mo | All paid plans include: - Full API and SDK access - Dashboard access - Email support (Enterprise: dedicated support) ### Credits Credit-based billing is available for pay-as-you-go usage: - Minimum top-up: $5.00 (500 cents) - Maximum top-up: $100,000.00 (10,000,000 cents) - Credits are deducted per identity provisioned and per event processed - View balance via `GET /v1/billing/credits/balance` - View transaction history via `GET /v1/billing/credits/transactions` --- ## 11. MCP Server Integration AIdenID provides an MCP (Model Context Protocol) server that allows LLMs to use AIdenID tools directly through tool calling. ### Available MCP Tools | Tool | Description | |------------------------|--------------------------------------------------| | `create_identity` | Provision a new disposable email identity | | `get_identity` | Retrieve identity details and status | | `list_identities` | List identities with filtering | | `get_latest_extraction`| Get the most recent extraction result | | `extend_identity` | Extend an identity's TTL | | `squash_identity` | Revoke an identity | | `create_webhook` | Register a webhook endpoint | | `test_auth_flow` | Run an auth flow reliability test | ### MCP Configuration Add to your MCP client configuration (Claude Desktop, Cursor, etc.): ```json { "mcpServers": { "aidenid": { "command": "npx", "args": ["-y", "@aidenid/mcp-server"], "env": { "AIDENID_API_KEY": "aid_your_api_key", "AIDENID_ORG_ID": "org_abc123", "AIDENID_PROJECT_ID": "proj_def456" } } } } ``` ### Example MCP Tool Call When an LLM uses the MCP server, it can make calls like: ``` Tool: create_identity Arguments: { "aliasTemplate": "signup-bot", "ttlHours": 24, "tags": ["test"] } Result: { "id": "ident_...", "emailAddress": "signup-bot-abc@inbox.aidenid.com", ... } ``` --- ## 12. Links | Resource | URL | |----------------------|----------------------------------------------------| | Website | https://aidenid.com | | Free Tier | https://aidenid.com/free | | Consumer Signup | https://aidenid.com/consumer/signup | | Documentation | https://aidenid.com/docs | | API Reference | https://aidenid.com/docs/api-reference | | Free Tier Docs | https://aidenid.com/docs/api-reference/free-tier | | Consumer Docs | https://aidenid.com/docs/api-reference/consumer | | Trials Docs | https://aidenid.com/docs/api-reference/trials | | Billing Docs | https://aidenid.com/docs/api-reference/billing | | Realtime Docs | https://aidenid.com/docs/api-reference/realtime | | Marketplace Docs | https://aidenid.com/docs/api-reference/marketplace | | Domains Docs | https://aidenid.com/docs/api-reference/domains | | Quickstart | https://aidenid.com/docs/quickstart | | Human vs Agent | https://aidenid.com/docs/concepts/human-vs-agent | | Abuse Prevention | https://aidenid.com/docs/concepts/abuse-prevention | | Dashboard Guide | https://aidenid.com/docs/guides/dashboard | | Summary (llms.txt) | https://aidenid.com/llms.txt | | Full Reference | https://aidenid.com/llms-full.txt | | Sitemap | https://aidenid.com/sitemap.xml | --- ## Appendix: Complete Code Examples ### Python — Full Identity Lifecycle (Create, Poll, Squash) ```python import requests import time import uuid API = "https://api.aidenid.com" HEADERS = { "Authorization": "Bearer aid_your_api_key", "X-Org-Id": "org_abc123", "X-Project-Id": "proj_def456", "Content-Type": "application/json", } # 1. Create identity resp = requests.post( f"{API}/v1/identities", headers={**HEADERS, "Idempotency-Key": str(uuid.uuid4())}, json={"aliasTemplate": "signup-bot", "ttlHours": 24}, ) identity = resp.json() identity_id = identity["id"] email = identity["emailAddress"] print(f"Provisioned: {email}") # 2. Use the email address in your signup flow... # (Your automation triggers a signup on target service using this email) # 3. Poll for extraction for attempt in range(60): resp = requests.get( f"{API}/v1/identities/{identity_id}/latest-extraction", headers=HEADERS, ) if resp.status_code == 200: extraction = resp.json() if extraction["type"] == "otp": print(f"Extraction ready: {extraction['type']} (confidence: {extraction['confidence']})") else: print("Action link is available in the secure server-side path") break time.sleep(2) else: print("No extraction received within timeout") # 4. Squash when done requests.post( f"{API}/v1/identities/{identity_id}/squash", headers={**HEADERS, "Idempotency-Key": str(uuid.uuid4())}, ) print("Identity squashed") ``` ### TypeScript — Create Identity and Poll with Fetch ```typescript const API = "https://api.aidenid.com"; const headers = { "Authorization": "Bearer aid_your_api_key", "X-Org-Id": "org_abc123", "X-Project-Id": "proj_def456", "Content-Type": "application/json", }; async function createIdentityAndExtract(label: string) { // 1. Create identity const createResp = await fetch(`${API}/v1/identities`, { method: "POST", headers: { ...headers, "Idempotency-Key": crypto.randomUUID() }, body: JSON.stringify({ aliasTemplate: label, ttlHours: 24 }), }); const identity = await createResp.json(); console.log(`Email: ${identity.emailAddress}`); // 2. Poll for extraction for (let i = 0; i < 60; i++) { const resp = await fetch( `${API}/v1/identities/${identity.id}/latest-extraction`, { headers } ); if (resp.ok) { const extraction = await resp.json(); console.log(`Extracted ${extraction.type}: ${extraction.otp ?? extraction.primaryActionUrl}`); // 3. Squash await fetch(`${API}/v1/identities/${identity.id}/squash`, { method: "POST", headers: { ...headers, "Idempotency-Key": crypto.randomUUID() }, }); console.log("Identity squashed"); return extraction; } await new Promise((r) => setTimeout(r, 2000)); } throw new Error("Extraction timeout"); } ``` ### curl — End-to-End Free Tier Flow ```bash # 1. Create free identity (no auth needed) RESPONSE=$(curl -s -X POST https://api.aidenid.com/v1/free/identity) IDENTITY_ID=$(echo "$RESPONSE" | jq -r '.identityId') EMAIL=$(echo "$RESPONSE" | jq -r '.emailAddress') TOKEN=$(echo "$RESPONSE" | jq -r '.apiToken') echo "Email: $EMAIL" # 2. Use the email in an authorized customer-controlled flow... # (manual step or automated via your tooling) # 3. Poll for redacted extraction evidence while true; do RESULT=$(curl -s "https://api.aidenid.com/v1/free/identity/$IDENTITY_ID/extraction?token=$TOKEN") STATUS=$(echo "$RESULT" | jq -r '.status') if [ "$STATUS" = "ready" ]; then TYPE=$(echo "$RESULT" | jq -r '.type') echo "Extraction ready: $TYPE" break fi echo "Waiting..." sleep 5 done ``` --- *This document is the complete API reference for LLM consumption. For a high-level overview, see llms.txt. For interactive documentation, visit https://aidenid.com/docs/api-reference.*