# VeriPass Enterprise API Reference

**Base URL:** `https://app.veripass.ai`
**API Version:** v1
**Protocol:** HTTPS only

---

## Table of Contents

1. [Quick Start](#quick-start)
2. [Authentication](#authentication)
3. [Core Endpoints](#core-endpoints)
   - [Certify](#certify)
   - [Verify Gate](#verify-gate)
   - [Deployments](#deployments)
   - [API Keys](#api-keys)
   - [Batch Certification](#batch-certification)
   - [Agent Sessions](#agent-sessions)
   - [Audit Records](#audit-records)
4. [Response Format](#response-format)
5. [Error Codes](#error-codes)
6. [Rate Limits](#rate-limits)

---

## Quick Start

Get your first certification in 60 seconds.

### 1. Create an API Key

```bash
# Log in and get a JWT token
curl -X POST https://app.veripass.ai/api/v1/auth/login \
  -H "Content-Type: application/json" \
  -d '{"email": "you@company.com", "password": "YourPassword123"}'

# Use the token to create a scoped API key
curl -X POST https://app.veripass.ai/api/v1/auth/keys \
  -H "Content-Type: application/json" \
  -H "Authorization: Bearer <your-jwt-token>" \
  -d '{"label": "production", "scope": "certify_only"}'
```

Save the `key` from the response. It starts with `vp_live_` and is shown only once.

### 2. Certify an AI Response

```bash
curl -X POST https://app.veripass.ai/api/v1/certify \
  -H "Content-Type: application/json" \
  -H "Authorization: Bearer vp_live_your_key_here" \
  -d '{
    "prompt": "What is the capital of France?",
    "response": "The capital of France is Paris.",
    "deployment_id": "your-deployment-uuid"
  }'
```

### 3. Verify the Certification

```bash
# No authentication required
curl https://app.veripass.ai/api/v1/verify/<certification_id>
```

---

## Authentication

VeriPass supports two authentication methods. Both work on all authenticated endpoints.

### Method 1: JWT Bearer Token

Obtained from `POST /api/v1/auth/login`. Passed via the `Authorization` header.

```
Authorization: Bearer eyJhbGciOiJIUzI1NiIs...
```

### Method 2: API Key

Scoped API keys start with `vp_live_`. They can be passed via **either** header format:

```
X-API-Key: vp_live_abc123def456...
```

```
Authorization: Bearer vp_live_abc123def456...
```

Both formats are equivalent. The middleware detects the `vp_` prefix and routes to API key authentication automatically.

### API Key Scopes

| Scope | Permissions |
|-------|-------------|
| `full_access` | All operations (default) |
| `certify_only` | `POST /api/v1/certify` only |
| `read_only` | Read-only access to all endpoints |

### Login

```
POST /api/v1/auth/login
```

**Request Body:**

| Field | Type | Required | Description |
|-------|------|----------|-------------|
| `email` | string | Yes | Email address (max 255 chars) |
| `password` | string | Yes | Account password |

**Response (200):**

```json
{
  "token": "eyJhbG...",
  "refresh_token": "eyJhbG...",
  "user": {
    "id": "uuid",
    "email": "you@company.com",
    "role": "admin",
    "org_name": "Acme Corp"
  },
  "api_key_prefix": "vp_abc1"
}
```

**Error Responses:**

| Status | Code | Description |
|--------|------|-------------|
| 400 | `VALIDATION_ERROR` | Email and password required |
| 401 | `INVALID_CREDENTIALS` | Invalid credentials |
| 423 | `ACCOUNT_LOCKED` | Account locked after 5 failed attempts (15 min lockout) |

### Refresh Token

```
POST /api/v1/auth/refresh
```

| Field | Type | Required | Description |
|-------|------|----------|-------------|
| `refresh_token` | string | Yes | Refresh token from login |

**Response (200):**

```json
{
  "token": "eyJhbG...",
  "refresh_token": "eyJhbG..."
}
```

---

## Core Endpoints

### Certify

The core certification endpoint. Evaluates an AI prompt/response pair across behavioral dimensions, assigns a Behavioral Certification Score (BCS), and returns a cryptographically signed certification record.

#### POST /api/v1/certify

**Authentication:** Required
**Roles:** `super_admin`, `admin`, `operator`, `analyst`, `sandbox`

**Request Body:**

| Field | Type | Required | Constraints | Description |
|-------|------|----------|-------------|-------------|
| `prompt` | string | Yes | 1 - 50,000 chars | The user prompt sent to the AI |
| `response` | string | Yes | 1 - 100,000 chars | The AI-generated response |
| `deployment_id` | string | No | Max 255 chars | UUID of the deployment to certify against |
| `model` | string | No | Max 100 chars | Model name (e.g., `claude-sonnet-4-20250514`) |
| `provider` | string | No | Max 100 chars | Provider name (e.g., `anthropic`, `openai`) |
| `model_version` | string | No | Max 100 chars | Specific model version identifier |
| `system_fingerprint` | string | No | Max 255 chars | Provider system fingerprint |
| `context` | object | No | | Arbitrary context passed to the evaluation engine |
| `enable_judge` | boolean | No | | Set `false` to skip the async LLM judge |
| `timestamp` | string | No | Max 50 chars | ISO 8601 timestamp override (admin/super_admin only) |
| `metadata` | object | No | | Arbitrary metadata stored with the record |
| `clinical_context` | object | No | | Clinical context for healthcare-specific policy adjustments |

**Query Parameters:**

| Param | Type | Default | Description |
|-------|------|---------|-------------|
| `wait_for_judge` | string | `false` | Set to `"true"` for synchronous T1+T2+T3 evaluation (slower, includes LLM judge scores) |

**Response (200):**

```json
{
  "certification_id": "vp_cert_abc123...",
  "deployment_id": "uuid-of-deployment",
  "timestamp": "2026-03-25T12:00:00.000Z",
  "dimensions": {
    "factual_grounding": { "score": 0.923, "tier1": 0.91, "tier2": 0.94, "tier3": null, "consensus": "agree", "flags": [] },
    "boundary_compliance": { "score": 0.891, "tier1": 0.88, "tier2": 0.90, "tier3": null, "consensus": "agree", "flags": [] },
    "semantic_fidelity": { "score": 0.945, "tier1": 0.93, "tier2": 0.96, "tier3": null, "consensus": "agree", "flags": [] },
    "response_stability": { "score": 0.867, "tier1": 0.85, "tier2": 0.88, "tier3": null, "consensus": "agree", "flags": [] },
    "topical_adherence": { "score": 0.912, "tier1": 0.90, "tier2": 0.92, "tier3": null, "consensus": "agree", "flags": [] },
    "information_safety": { "score": 0.956, "tier1": 0.95, "tier2": 0.96, "tier3": null, "consensus": "agree", "flags": [] }
  },
  "rrc": {
    "coherence": 0.91,
    "tiers": { ... },
    "intent_type": "factual_query",
    "entity_report": { ... }
  },
  "bcs": 0.916,
  "decision": "certified",
  "action": "log",
  "flags": [],
  "critical_flags": [],
  "floor_violations": [],
  "content_hash": "sha256hex...",
  "signature": "ed25519hex...",
  "signed": true,
  "public_key": "ed25519pubhex...",
  "compliance": {},
  "model_identity": {
    "provider": "anthropic",
    "model": "claude-sonnet-4-20250514",
    "drift_detected": false
  },
  "judge": null,
  "judge_status": "async",
  "status": "preliminary",
  "judge_pending": true,
  "detection_confidence": 0.92,
  "performance": {
    "deployment_lookup_ms": 1.2,
    "history_fetch_ms": 0.8,
    "tier1_tier2_ms": 3.4,
    "tier3_llm_judge_ms": 0,
    "crypto_signing_ms": 0.3,
    "db_write_ms": 2.1,
    "total_ms": 8.9
  }
}
```

**Response Headers:**

| Header | Example | Description |
|--------|---------|-------------|
| `X-VeriPass-Timing` | `total=9ms;t1=2ms;t2=1ms;t3=pending;db=2ms;judge=async` | Performance breakdown |
| `X-VeriPass-Artifact` | `vp_cert_abc123...` | Certification ID |
| `X-VeriPass-Status` | `CERTIFIED` | Decision in uppercase |
| `X-VeriPass-BCS` | `92` | BCS as integer percentage |
| `X-VeriPass-Verify` | `https://app.veripass.ai/api/v1/verify/vp_cert_abc123...` | Public verification URL |

**Decisions:**

| Decision | Meaning |
|----------|---------|
| `certified` | BCS meets threshold, no floor violations |
| `flagged` | BCS meets threshold but has dimension floor violations or behavioral flags |
| `failed` | BCS below threshold |

**Two-Phase Architecture:**

By default, the certify endpoint uses a two-phase approach:
- **Phase 1 (synchronous):** Tier 1 (pattern) + Tier 2 (NLP) evaluation. Returns `status: "preliminary"` in under 500ms.
- **Phase 2 (async):** Tier 3 LLM judge runs in the background. Results are pushed via SSE and stored in the database.

To get the full T1+T2+T3 result synchronously, add `?wait_for_judge=true`.

**Example:**

```bash
curl -X POST https://app.veripass.ai/api/v1/certify \
  -H "Content-Type: application/json" \
  -H "X-API-Key: vp_live_abc123def456..." \
  -d '{
    "prompt": "Summarize the Q3 earnings report",
    "response": "Revenue grew 12% year-over-year to $4.2B...",
    "deployment_id": "d1234567-89ab-cdef-0123-456789abcdef",
    "model": "claude-sonnet-4-20250514",
    "provider": "anthropic"
  }'
```

**Synchronous mode (includes LLM judge):**

```bash
curl -X POST "https://app.veripass.ai/api/v1/certify?wait_for_judge=true" \
  -H "Content-Type: application/json" \
  -H "X-API-Key: vp_live_abc123def456..." \
  -d '{
    "prompt": "What medications interact with warfarin?",
    "response": "Common warfarin interactions include...",
    "deployment_id": "d1234567-89ab-cdef-0123-456789abcdef"
  }'
```

---

### Verify Gate

Public, unauthenticated verification endpoint. Any system can verify a VeriPass certification artifact before proceeding -- no API key required.

#### GET /api/v1/verify/:artifactId

**Authentication:** None required
**CORS:** Enabled for all origins

**Response (200):**

```json
{
  "valid": true,
  "artifact_id": "vp_cert_abc123...",
  "record_type": "Behavioral Certification",
  "status": "CERTIFIED",
  "bcs": 92,
  "tier": "gold",
  "deployment": "Customer Support Bot",
  "issued_at": "2026-03-25T12:00:00.000Z",
  "signature_verified": true,
  "hash_chain_intact": true,
  "vcas_version": "2.0",
  "chain": {
    "block_number": 42,
    "merkle_root": "abc123...",
    "leaf_index": 7,
    "block_timestamp": "2026-03-25T12:05:00.000Z"
  }
}
```

**Response (404):**

```json
{
  "valid": false,
  "error": "ARTIFACT_NOT_FOUND",
  "message": "No VCAS artifact found with this ID"
}
```

**Trust Tiers:**

| Tier | BCS Range | Meaning |
|------|-----------|---------|
| `platinum` | 97-100 | Exceptional behavioral compliance |
| `gold` | 90-96 | Strong behavioral compliance |
| `silver` | 80-89 | Acceptable behavioral compliance |
| `bronze` | 70-79 | Marginal behavioral compliance |
| `flagged` | N/A | Decision was FLAGGED |
| `failed` | Below 70 | Below certification threshold |

#### POST /api/v1/verify/batch

**Authentication:** None required

Verify multiple artifacts in a single request with chain integrity validation.

**Request Body:**

| Field | Type | Required | Constraints | Description |
|-------|------|----------|-------------|-------------|
| `artifacts` | string[] | Yes | 1 - 100 items | Array of certification artifact IDs |

**Response (200):**

```json
{
  "results": [
    {
      "artifact_id": "vp_cert_abc...",
      "valid": true,
      "status": "CERTIFIED",
      "bcs": 92,
      "signature_verified": true,
      "hash_chain_intact": true
    }
  ],
  "chain_valid": true
}
```

If any artifact in the batch is invalid, `chain_valid` will be `false` and `chain_break` will indicate the first failing artifact.

**Example:**

```bash
curl -X POST https://app.veripass.ai/api/v1/verify/batch \
  -H "Content-Type: application/json" \
  -d '{
    "artifacts": [
      "vp_cert_abc123...",
      "vp_cert_def456..."
    ]
  }'
```

---

### Deployments

Manage AI deployments (agents, models, applications) that are being certified.

#### GET /api/v1/deployments

**Authentication:** Required

List all active deployments. Paginated.

**Query Parameters:**

| Param | Type | Default | Constraints | Description |
|-------|------|---------|-------------|-------------|
| `page` | integer | 1 | Min 1 | Page number |
| `limit` | integer | 50 | 1 - 200 | Results per page |

**Response Headers:**

| Header | Description |
|--------|-------------|
| `X-Total-Count` | Total number of deployments |

**Response (200):**

```json
{
  "deployments": [
    {
      "id": "uuid",
      "name": "Customer Support Bot",
      "industry": "fintech",
      "risk_level": "high",
      "enforcement_mode": "shadow",
      "model_provider": "anthropic",
      "model_name": "claude-sonnet-4-20250514",
      "stage": "development",
      "compliance_modules": ["SOC2", "HIPAA"],
      "policy_overrides": {},
      "provider_config": {},
      "cert_count": 1247,
      "failed_count": 3,
      "avg_bcs": 0.912,
      "owner_email": "admin@company.com",
      "created_at": "2026-03-20T10:00:00.000Z"
    }
  ],
  "total": 12,
  "page": 1,
  "limit": 50
}
```

#### POST /api/v1/deployments

**Authentication:** Required
**Roles:** `super_admin`, `admin`, `operator`, `sandbox`

Create a new deployment.

**Request Body:**

| Field | Type | Required | Constraints | Description |
|-------|------|----------|-------------|-------------|
| `name` | string | Yes | 1 - 255 chars | Deployment name |
| `industry` | string | No | Max 100 chars | Industry vertical (default: `"general"`) |
| `risk_level` | enum | No | | One of: `low`, `medium`, `high`, `critical`, `standard` (default: `"standard"`) |
| `enforcement_mode` | enum | No | | One of: `shadow`, `inline`, `async`, `advisory`, `enforce`, `enforcement` (default: `"shadow"`) |
| `model_provider` | string | No | Max 50 chars | Provider name (default: `"anthropic"`) |
| `model_name` | string | No | Max 100 chars | Model identifier (default: `"claude-sonnet-4-20250514"`) |
| `system_prompt` | string | No | Max 10,000 chars | System prompt for the deployment |
| `fallback_response` | string | No | Max 2,000 chars | Response used when certification fails in enforcement mode |
| `compliance_modules` | string[] | No | | Array of compliance module IDs (e.g., `["SOC2", "HIPAA"]`) |
| `policy_overrides` | object | No | | Policy overrides for this deployment |
| `provider_config` | object | No | | Provider-specific configuration |

**Response (201):**

```json
{
  "deployment_id": "uuid",
  "name": "Customer Support Bot",
  "message": "Deployment created"
}
```

**Example:**

```bash
curl -X POST https://app.veripass.ai/api/v1/deployments \
  -H "Content-Type: application/json" \
  -H "Authorization: Bearer vp_live_abc123def456..." \
  -d '{
    "name": "Customer Support Bot",
    "industry": "fintech",
    "risk_level": "high",
    "enforcement_mode": "shadow",
    "model_provider": "anthropic",
    "model_name": "claude-sonnet-4-20250514",
    "compliance_modules": ["SOC2"]
  }'
```

#### GET /api/v1/deployments/:id

**Authentication:** Required

Get a single deployment with certification statistics.

**Response (200):**

```json
{
  "id": "uuid",
  "name": "Customer Support Bot",
  "industry": "fintech",
  "risk_level": "high",
  "enforcement_mode": "shadow",
  "stage": "development",
  "cert_count": 1247,
  "failed_count": 3,
  "avg_bcs": 0.912,
  "compliance_modules": ["SOC2"],
  "policy_overrides": {},
  "provider_config": {},
  "owner_email": "admin@company.com",
  "created_at": "2026-03-20T10:00:00.000Z",
  "updated_at": "2026-03-25T08:00:00.000Z"
}
```

#### PUT /api/v1/deployments/:id

**Authentication:** Required
**Roles:** `super_admin`, `admin`, `operator`

Update a deployment. All fields from POST are accepted and optional.

**Response (200):**

```json
{
  "message": "Deployment updated",
  "deployment_id": "uuid"
}
```

#### DELETE /api/v1/deployments/:id

**Authentication:** Required
**Roles:** `super_admin`, `admin`

Soft-delete (deactivate) a deployment.

**Response (200):**

```json
{
  "message": "Deployment deactivated"
}
```

#### POST /api/v1/deployments/:id/promote

**Authentication:** Required
**Roles:** `super_admin`, `admin`

Promote a deployment to the next lifecycle stage.

**Lifecycle Stages (in order):** `development` -> `staging` -> `shadow` -> `inline` -> `enforcement` -> `retired`

**Stage Gates:**

| Target Stage | Requirement |
|--------------|-------------|
| `staging` | At least 10 certifications |
| `shadow` | Average BCS >= 0.75 |
| `inline` | Zero failed certifications |
| `enforcement` | Zero failed certifications |

**Response (200):**

```json
{
  "deployment_id": "uuid",
  "stage": "staging",
  "previous": "development"
}
```

**Error (400):**

```json
{
  "error": { "code": "STAGE_GATE_FAILED", "message": "Staging requires at least 10 certifications" },
  "current": 3
}
```

#### POST /api/v1/deployments/:id/rollback

**Authentication:** Required
**Roles:** `super_admin`, `admin`

Rollback a deployment to the previous lifecycle stage.

**Response (200):**

```json
{
  "deployment_id": "uuid",
  "stage": "development",
  "previous": "staging"
}
```

#### GET /api/v1/deployments/:id/envelope

**Authentication:** Required

Get the behavioral envelope (baseline statistics) for a deployment.

---

### API Keys

Create and manage scoped API keys for programmatic access.

#### POST /api/v1/auth/keys

**Authentication:** Required

Create a new scoped API key. The raw key is returned **once** in the response and is never stored in plaintext.

**Request Body:**

| Field | Type | Required | Constraints | Description |
|-------|------|----------|-------------|-------------|
| `label` | string | Yes | | Human-readable label for the key |
| `scope` | enum | No | | One of: `full_access`, `certify_only`, `read_only` (default: `"full_access"`) |

**Response (201):**

```json
{
  "id": "uuid",
  "label": "production",
  "key": "vp_live_abc123def456789012345678",
  "key_prefix": "vp_live_abc1",
  "scope": "certify_only",
  "message": "API key created \u2014 copy the key now, it will not be shown again"
}
```

**Example:**

```bash
curl -X POST https://app.veripass.ai/api/v1/auth/keys \
  -H "Content-Type: application/json" \
  -H "Authorization: Bearer <jwt-token>" \
  -d '{"label": "production-certifier", "scope": "certify_only"}'
```

#### GET /api/v1/auth/keys

**Authentication:** Required

List all API keys for the authenticated user. Keys are masked (only prefix shown).

**Response (200):**

```json
{
  "keys": [
    {
      "id": "uuid",
      "label": "production",
      "key_prefix": "vp_live_abc1",
      "scope": "certify_only",
      "created_at": "2026-03-20T10:00:00.000Z",
      "last_used_at": "2026-03-25T08:00:00.000Z",
      "request_count": 4521,
      "status": "active"
    }
  ]
}
```

#### DELETE /api/v1/auth/keys/:id

**Authentication:** Required

Revoke an API key. Only the key owner can revoke their own keys.

**Response (200):**

```json
{
  "message": "API key revoked",
  "id": "uuid"
}
```

**Error (404):**

```json
{
  "error": { "code": "NOT_FOUND", "message": "API key not found" }
}
```

---

### Batch Certification

#### POST /api/v1/certify/batch

**Authentication:** Required

Certify multiple AI prompt/response pairs in a single request. Each item is independently certified, signed, and stored.

**Request Body:**

| Field | Type | Required | Constraints | Description |
|-------|------|----------|-------------|-------------|
| `items` | array | Yes | 1 - 100 items | Array of certification items |
| `items[].prompt` | string | Yes | 1 - 50,000 chars | The user prompt sent to the AI |
| `items[].response` | string | Yes | 1 - 100,000 chars | The AI-generated response |
| `items[].deployment_id` | string | No | Max 255 chars | UUID of the deployment to certify against |
| `items[].model` | string | No | Max 100 chars | Model name |
| `items[].provider` | string | No | Max 100 chars | Provider name |
| `items[].timestamp` | string | No | Max 50 chars | ISO 8601 timestamp override |

**Response (200):**

```json
{
  "results": [
    {
      "certification_id": "vp_cert_abc123...",
      "deployment_id": "uuid-or-null",
      "bcs": 0.916,
      "decision": "certified",
      "dimensions": {
        "factual_grounding": { "score": 0.923, "tier1": 0.91, "tier2": 0.94, "tier3": null, "consensus": "agree", "flags": [] },
        "boundary_compliance": { "score": 0.891, "tier1": 0.88, "tier2": 0.90, "tier3": null, "consensus": "agree", "flags": [] }
      },
      "timestamp": "2026-03-25T12:00:00.000Z"
    },
    {
      "error": "prompt and response are required",
      "index": 1
    }
  ],
  "summary": {
    "total": 2,
    "certified": 1,
    "flagged": 0,
    "failed": 0,
    "errors": 1
  }
}
```

Items that fail validation return an `error` string and `index` in the results array instead of a certification result.

**Example:**

```bash
curl -X POST https://app.veripass.ai/api/v1/certify/batch \
  -H "Content-Type: application/json" \
  -H "X-API-Key: vp_live_abc123def456..." \
  -d '{
    "items": [
      { "prompt": "What is 2+2?", "response": "4.", "deployment_id": "uuid" },
      { "prompt": "Capital of France?", "response": "Paris." }
    ]
  }'
```

---

### Agent Sessions

Certify multi-step AI agent workflows. An agent session tracks each step of an agent's execution and produces an aggregate Behavioral Certification Score.

#### POST /api/v1/agents

**Authentication:** Required
**Roles:** `super_admin`, `admin`, `analyst`, `sandbox`
**Feature Gate:** `agents_tab`

Create a new agent session.

**Request Body:**

| Field | Type | Required | Description |
|-------|------|----------|-------------|
| `deployment_id` | string | No | Deployment UUID to certify against |
| `name` | string | No | Human-readable session name |
| `timestamp` | string | No | ISO 8601 timestamp override (admin/super_admin only) |

**Response (200):**

```json
{
  "session": {
    "id": "uuid",
    "name": "research-agent-v2",
    "deployment_id": "uuid-or-null",
    "status": "active",
    "aggregate_bcs": 1.0,
    "total_steps": 0,
    "certified_steps": 0,
    "flagged_steps": 0,
    "failed_steps": 0,
    "created_by": "user-uuid",
    "created_at": "2026-03-25T12:00:00.000Z",
    "updated_at": "2026-03-25T12:00:00.000Z"
  }
}
```

**Note:** The session object is nested under the `session` key. The session ID is at `session.id`.

**Example:**

```bash
curl -X POST https://app.veripass.ai/api/v1/agents \
  -H "Content-Type: application/json" \
  -H "X-API-Key: vp_live_abc123def456..." \
  -d '{
    "deployment_id": "d1234567-89ab-cdef-0123-456789abcdef",
    "name": "research-agent-v2"
  }'
```

#### POST /api/v1/agents/:sessionId/steps

**Authentication:** Required
**Roles:** `super_admin`, `admin`, `analyst`, `sandbox`
**Feature Gate:** `agents_tab`

Submit a step for certification within an active agent session. If the step includes both `prompt` and `response`, it is run through the full certification engine. Steps without prompt/response (e.g., tool invocations) are tracked but not individually certified.

**Request Body:**

| Field | Type | Required | Description |
|-------|------|----------|-------------|
| `step_type` | enum | Yes | One of: `llm_call`, `tool_use`, `tool_result`, `decision`, `code_execution`, `web_browse`, `human_handoff` |
| `prompt` | string | No | Step prompt (required for certification) |
| `response` | string | No | Step response (required for certification) |
| `provider` | string | No | LLM provider name |
| `model` | string | No | Model name |
| `tool_name` | string | No | Name of tool invoked |
| `tool_input` | string | No | Input passed to the tool |
| `parent_step_id` | string | No | UUID of the parent step (for branching workflows) |
| `metadata` | object | No | Arbitrary step metadata |

**Response (200):**

```json
{
  "step": {
    "id": "uuid",
    "session_id": "uuid",
    "step_number": 1,
    "step_type": "llm_call",
    "provider": "anthropic",
    "model": "claude-sonnet-4-20250514",
    "tool_name": null,
    "tool_input": null,
    "prompt": "Summarize the Q3 report",
    "response": "Revenue grew 12%...",
    "certification_id": "vp_cert_abc123...",
    "bcs": 0.916,
    "decision": "certified",
    "flags": [],
    "parent_step_id": null,
    "metadata": {}
  },
  "certification": {
    "certification_id": "vp_cert_abc123...",
    "bcs": 0.916,
    "decision": "certified",
    "dimensions": {
      "factual_grounding": {
        "score": 0.923,
        "tier1": 0.91,
        "tier2": 0.94,
        "tier3": null,
        "consensus": "agree",
        "flags": []
      },
      "boundary_compliance": {
        "score": 0.891,
        "tier1": 0.88,
        "tier2": 0.90,
        "tier3": null,
        "consensus": "agree",
        "flags": []
      }
    },
    "flags": [],
    "action": "log",
    "content_hash": "sha256hex...",
    "timestamp": "2026-03-25T12:00:00.000Z"
  }
}
```

**Note:** The `decision` field (not "verdict") indicates the certification outcome: `certified`, `flagged`, or `failed`. Each dimension in `dimensions` is a nested object with `score`, `tier1`, `tier2`, `tier3`, `consensus`, and `flags` fields -- not a bare number.

If the step has no `prompt`/`response`, the `certification` field will be `null` and `step.bcs`, `step.decision`, and `step.certification_id` will also be `null`.

**Error Responses:**

| Status | Code | Description |
|--------|------|-------------|
| 400 | `VALIDATION_ERROR` | Invalid step_type or missing required fields |
| 404 | `NOT_FOUND` | Session not found |
| 409 | `VALIDATION_ERROR` | Session is not active |

#### POST /api/v1/agents/:sessionId/terminate

**Authentication:** Required
**Roles:** `super_admin`, `admin`, `analyst`, `sandbox`
**Feature Gate:** `agents_tab`

Terminate an active agent session.

**Request Body:**

| Field | Type | Required | Description |
|-------|------|----------|-------------|
| `reason` | string | Yes | Reason for termination |

**Response (200):**

```json
{
  "session": {
    "id": "uuid",
    "name": "research-agent-v2",
    "deployment_id": "uuid-or-null",
    "status": "terminated",
    "aggregate_bcs": 0.891,
    "total_steps": 5,
    "certified_steps": 4,
    "flagged_steps": 1,
    "failed_steps": 0,
    "termination_reason": "Task completed",
    "created_by": "user-uuid",
    "created_at": "2026-03-25T12:00:00.000Z",
    "updated_at": "2026-03-25T12:05:00.000Z"
  }
}
```

**Note:** The aggregate BCS is at `session.aggregate_bcs` (not `chain_bcs`). The full session object is returned under the `session` key with status updated to `terminated`.

**Error Responses:**

| Status | Code | Description |
|--------|------|-------------|
| 400 | `VALIDATION_ERROR` | reason is required |
| 404 | `NOT_FOUND` | Session not found |
| 409 | `VALIDATION_ERROR` | Session is not active |

#### GET /api/v1/agents/:sessionId

**Authentication:** Required
**Roles:** `super_admin`, `admin`, `analyst`, `sandbox`
**Feature Gate:** `agents_tab`

Get session detail with all steps and chain analysis.

**Response (200):**

```json
{
  "session": { "id": "uuid", "status": "active", "aggregate_bcs": 0.912, "..." : "..." },
  "steps": [
    {
      "id": "uuid",
      "step_number": 1,
      "step_type": "llm_call",
      "bcs": 0.916,
      "decision": "certified",
      "flags": [],
      "metadata": {}
    }
  ],
  "chain_analysis": {
    "chain_health": "healthy",
    "flags": [],
    "bcs_trend": "stable",
    "tool_frequency": { "llm_call": 3, "tool_use": 2 },
    "step_analysis": [
      { "step_number": 1, "step_type": "llm_call", "bcs": 0.916, "decision": "certified", "flags": [], "tool_name": null }
    ]
  }
}
```

#### GET /api/v1/agents

**Authentication:** Required
**Roles:** `super_admin`, `admin`, `analyst`, `sandbox`
**Feature Gate:** `agents_tab`

List agent sessions with filtering.

**Query Parameters:**

| Param | Type | Default | Constraints | Description |
|-------|------|---------|-------------|-------------|
| `status` | string | | | Filter by status (`active`, `terminated`) |
| `deployment_id` | string | | | Filter by deployment |
| `limit` | integer | 50 | Max 200 | Results per page |

**Response (200):**

```json
{
  "sessions": [ { "id": "uuid", "name": "...", "status": "active", "aggregate_bcs": 0.912, "..." : "..." } ]
}
```

#### GET /api/v1/agents/:sessionId/report

**Authentication:** Required

Get a full session report with chain analysis and summary.

**Response (200):**

```json
{
  "session": { "id": "uuid", "..." : "..." },
  "steps": [ { "..." : "..." } ],
  "chain_analysis": { "chain_health": "healthy", "..." : "..." },
  "summary": {
    "total_steps": 5,
    "certified": 4,
    "flagged": 1,
    "failed": 0,
    "aggregate_bcs": 0.891
  }
}
```

---

### Audit Records

Access the immutable certification evidence vault.

#### GET /api/v1/audit/records

**Authentication:** Required

List certification records with filtering and pagination.

**Query Parameters:**

| Param | Type | Default | Constraints | Description |
|-------|------|---------|-------------|-------------|
| `deployment_id` | string | | | Filter by deployment |
| `decision` | string | | | Filter by decision: `certified`, `flagged`, `failed` |
| `from` | string | | ISO 8601 | Start date filter |
| `to` | string | | ISO 8601 | End date filter |
| `limit` | integer | 50 | Max 500 | Results per page |
| `offset` | integer | 0 | | Pagination offset |

**Response (200):**

```json
{
  "records": [
    {
      "id": "vp_cert_abc123...",
      "deployment_id": "uuid",
      "deployment_name": "Customer Support Bot",
      "timestamp": "2026-03-25T12:00:00.000Z",
      "bcs": 0.916,
      "decision": "certified",
      "action": "log",
      "content_hash": "sha256hex...",
      "signature": "ed25519hex...",
      "rrc_score": 0.91,
      "dimensions": "{...}",
      "created_by": "user-uuid"
    }
  ],
  "total": 1247,
  "limit": 50,
  "offset": 0
}
```

**Example:**

```bash
curl "https://app.veripass.ai/api/v1/audit/records?deployment_id=uuid&decision=failed&limit=20" \
  -H "Authorization: Bearer vp_live_abc123def456..."
```

#### GET /api/v1/audit/records/:id

**Authentication:** Required

Get a single certification record with full details, including parsed dimensions, policy snapshot, and root cause analysis.

**Response (200):**

```json
{
  "id": "vp_cert_abc123...",
  "deployment_id": "uuid",
  "deployment_name": "Customer Support Bot",
  "timestamp": "2026-03-25T12:00:00.000Z",
  "prompt": "...",
  "response": "...",
  "bcs": 0.916,
  "decision": "certified",
  "action": "log",
  "dimensions": {
    "factual_grounding": { "score": 0.923 },
    "boundary_compliance": { "score": 0.891 }
  },
  "policy_snapshot": {
    "min_bcs": 0.75,
    "enforcement_mode": "shadow"
  },
  "metadata": {},
  "content_hash": "sha256hex...",
  "signature": "ed25519hex...",
  "root_cause_analysis": null
}
```

#### POST /api/v1/audit/records/:id/root-cause

**Authentication:** Required

Generate or regenerate root cause analysis for a certification.

**Response (200):**

```json
{
  "root_cause_analysis": "The response exhibited boundary non-compliance..."
}
```

#### POST /api/v1/audit/verify

**Authentication:** Required

Verify the cryptographic signature of a certification record.

**Request Body:**

| Field | Type | Required | Description |
|-------|------|----------|-------------|
| `certification_id` | string | Yes | The certification ID to verify |

---

## Response Format

All API responses use JSON with a consistent structure.

### Success Responses

Success responses return the requested data directly at the top level:

```json
{
  "certification_id": "...",
  "bcs": 0.916,
  "decision": "certified"
}
```

### Error Responses

All errors follow this structure:

```json
{
  "error": {
    "code": "ERROR_CODE",
    "message": "Human-readable description",
    "details": ["Optional array of specific issues"]
  }
}
```

---

## Error Codes

| Code | HTTP Status | Description |
|------|-------------|-------------|
| `VALIDATION_ERROR` | 400 | Invalid or missing request fields. `details` array lists each issue. |
| `UNAUTHORIZED` | 401 | No valid authentication provided |
| `INVALID_CREDENTIALS` | 401 | Wrong email or password |
| `INVALID_TOKEN` | 401 | Invalid or expired refresh token |
| `FORBIDDEN` | 403 | Authenticated but insufficient permissions |
| `NOT_FOUND` | 404 | Resource does not exist |
| `CONFLICT` | 409 | Resource already exists (e.g., duplicate email) |
| `ACCOUNT_LOCKED` | 423 | Too many failed login attempts |
| `RATE_LIMITED` | 429 | Per-key rate limit exceeded (100 req/min per API key) |
| `RATE_LIMIT_EXCEEDED` | 429 | Global or endpoint-specific rate limit exceeded |
| `STAGE_GATE_FAILED` | 400 | Deployment promotion blocked by gate requirements |
| `CHAIN_NOT_ACTIVE` | 409 | Chain is already completed, cannot add steps |
| `CHAIN_ERROR` | 400/500 | General chain operation error |
| `MISSING_FIELD` | 400 | A required field is missing |
| `INTERNAL_ERROR` | 500 | Unexpected server error |

---

## Rate Limits

| Scope | Limit | Window |
|-------|-------|--------|
| Global (unauthenticated) | 120 requests | 1 minute |
| Global (authenticated) | 600 requests | 1 minute |
| Per API key (certify) | 100 requests | 1 minute |
| Login attempts | 15 requests | 15 minutes |
| Sandbox registration | 5 requests | 1 hour |
| Per-IP sandbox accounts | 3 accounts | 1 hour |
| Public verification | 60 requests | 1 minute |

Rate limit headers follow the [RateLimit standard](https://datatracker.ietf.org/doc/draft-ietf-httpapi-ratelimit-headers/):

```
RateLimit-Limit: 120
RateLimit-Remaining: 117
RateLimit-Reset: 1711368060
```

---

## Behavioral Dimensions

Each certification evaluates the AI response across these dimensions:

| Dimension | Key | Description |
|-----------|-----|-------------|
| Factual Grounding | `factual_grounding` | Accuracy and evidence basis of claims |
| Boundary Compliance | `boundary_compliance` | Adherence to defined behavioral boundaries |
| Semantic Fidelity | `semantic_fidelity` | Faithfulness to the user's intent |
| Response Stability | `response_stability` | Consistency with historical responses |
| Topical Adherence | `topical_adherence` | Relevance to the prompt topic |
| Information Safety | `information_safety` | Absence of sensitive information disclosure |
| Tool Safety | `tool_safety` | Safe use of tools and function calls (when applicable) |

Each dimension is a nested object with the following fields:

| Field | Type | Description |
|-------|------|-------------|
| `score` | number | Blended score between 0.0 and 1.0 |
| `tier1` | number | Tier 1 (pattern-based) score |
| `tier2` | number | Tier 2 (NLP-based) score |
| `tier3` | number/null | Tier 3 (LLM judge) score, `null` until judge completes |
| `consensus` | string | Agreement level between tiers (e.g., `"agree"`, `"split"`) |
| `flags` | string[] | Behavioral flags detected for this dimension |

---

## Cryptographic Verification

Every certification is cryptographically signed using Ed25519 (with optional ML-DSA-65 post-quantum signatures).

**Signature payload format:**
```
{certification_id}|{bcs}|{decision}|{content_hash}
```

**Content hash format (SHA-256):**
```
SHA-256({certification_id}|{deployment_id}|{bcs}|{decision}|{timestamp})
```

The server's Ed25519 public key is included in every certification response (`public_key` field) and can be fetched independently for offline verification.

---

## Full Workflow Example

```bash
# 1. Login
TOKEN=$(curl -s -X POST https://app.veripass.ai/api/v1/auth/login \
  -H "Content-Type: application/json" \
  -d '{"email":"you@company.com","password":"YourPassword123"}' | jq -r '.token')

# 2. Create API key
API_KEY=$(curl -s -X POST https://app.veripass.ai/api/v1/auth/keys \
  -H "Content-Type: application/json" \
  -H "Authorization: Bearer $TOKEN" \
  -d '{"label":"my-app","scope":"certify_only"}' | jq -r '.key')

# 3. Create deployment
DEPLOY_ID=$(curl -s -X POST https://app.veripass.ai/api/v1/deployments \
  -H "Content-Type: application/json" \
  -H "Authorization: Bearer $TOKEN" \
  -d '{"name":"My AI Assistant","risk_level":"medium","enforcement_mode":"shadow"}' | jq -r '.deployment_id')

# 4. Certify a response
CERT=$(curl -s -X POST https://app.veripass.ai/api/v1/certify \
  -H "Content-Type: application/json" \
  -H "X-API-Key: $API_KEY" \
  -d "{\"prompt\":\"What is 2+2?\",\"response\":\"2+2 equals 4.\",\"deployment_id\":\"$DEPLOY_ID\"}")

CERT_ID=$(echo $CERT | jq -r '.certification_id')
echo "BCS: $(echo $CERT | jq '.bcs') | Decision: $(echo $CERT | jq -r '.decision')"

# 5. Publicly verify (no auth needed)
curl -s "https://app.veripass.ai/api/v1/verify/$CERT_ID" | jq '.valid, .status, .bcs'
```
