Decisions API
Query, aggregate, and log validation decisions, the audit trail for every tool call.
Every tool call validated by Veto produces a decision record. These endpoints let you query, aggregate, and log decisions.
GET /v1/decisions
List decisions with pagination and filtering.
Headers
| Header | Required | Description |
|---|---|---|
X-Veto-API-Key or Authorization | Yes | API key or Bearer JWT |
Query parameters
| Parameter | Type | Default | Description |
|---|---|---|---|
limit | number | 50 | Results per page (1–100) |
offset | number | 0 | Skip this many results |
projectId | string (UUID) | Filter by project | |
toolName | string | Filter by tool name | |
decision | "allow" | "deny" | Filter by decision | |
startDate | ISO 8601 date | Filter from this date | |
endDate | ISO 8601 date | Filter until this date |
Response
{
"data": [
{
"id": "d7f2a1b3-4c5e-6f78-9a0b-1c2d3e4f5a6b",
"toolName": "transfer_funds",
"arguments": { "amount": 500, "to": "vendor-123" },
"context": { "session_id": "sess_abc123", "source": "client" },
"decision": "allow",
"mode": "deterministic",
"reason": "All constraints passed",
"failedArgument": null,
"matchedException": null,
"validations": null,
"latencyMs": 2,
"receipt": {
"receipt_id": "rcp_000000000000000000000001",
"receipt_hash": "sha256:1111111111111111111111111111111111111111111111111111111111111111",
"previous_receipt_hash": "sha256:e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855",
"merkle_root": "sha256:2222222222222222222222222222222222222222222222222222222222222222"
},
"createdAt": "2025-01-15T10:30:00Z"
}
],
"pagination": {
"total": 1247,
"limit": 50,
"offset": 0,
"hasMore": true
}
}GET /v1/decisions/stats
Aggregated decision statistics over a time period.
Headers
| Header | Required | Description |
|---|---|---|
X-Veto-API-Key or Authorization | Yes | API key or Bearer JWT |
Query parameters
| Parameter | Type | Default | Description |
|---|---|---|---|
days | number | 7 | Lookback period (1–90) |
projectId | string (UUID) | Filter by project |
Response
{
"period": { "days": 7 },
"summary": {
"total": 1247,
"allowed": 1180,
"denied": 67,
"deterministic": 1100,
"llm": 147
},
"breakdown": [
{
"date": "2025-01-15",
"allowed": 180,
"denied": 12,
"deterministic": 160,
"llm": 32
}
]
}GET /v1/decisions/:id
Get a single decision by ID.
Headers
| Header | Required | Description |
|---|---|---|
X-Veto-API-Key or Authorization | Yes | API key or Bearer JWT |
Path parameters
| Parameter | Type | Description |
|---|---|---|
id | string (UUID) | Decision ID |
Response
Same shape as individual items in the GET /v1/decisions data array.
GET /v1/decisions/:id/receipt
Get the canonical veto.receipt/1 payload for a single decision.
Headers
| Header | Required | Description |
|---|---|---|
X-Veto-API-Key or Authorization | Yes | API key or Bearer JWT |
Path parameters
| Parameter | Type | Description |
|---|---|---|
id | string (UUID) | Decision ID |
Response
Returns the full receipt payload, including tool_name, argument_hash, previous_receipt_hash, merkle_root, and timestamp.
See Receipts API for the full schema, NDJSON export, and offline verification.
Errors
| Status | Description |
|---|---|
| 400 | Invalid UUID format |
| 404 | Decision not found |
POST /v1/decisions
Log a client-side validation decision. Keeps the dashboard audit trail complete when the SDK validates locally.
Called automatically by the SDK, you do not need to call this directly.
Headers
| Header | Required | Description |
|---|---|---|
X-Veto-API-Key | Yes | API key scoped to a project |
Content-Type | Yes | application/json |
Body
{
"tool_name": "transfer_funds",
"arguments": { "amount": 500, "to": "vendor-123" },
"decision": "allow",
"reason": "All constraints passed",
"mode": "deterministic",
"latency_ms": 2,
"source": "client",
"context": {
"session_id": "sess_abc123",
"agent_id": "agent_1"
}
}| Field | Type | Required | Description |
|---|---|---|---|
tool_name | string | Yes | Name of the tool that was validated |
arguments | object | Yes | Arguments that were validated |
decision | "allow" | "deny" | Yes | Validation result |
reason | string | No | Explanation of the decision |
mode | "deterministic" | Yes | Validation mode used |
latency_ms | number | Yes | Client-side validation time in milliseconds |
source | "client" | Yes | Must be "client" |
context | object | No | Additional metadata (session_id, agent_id, etc.) |
Response (201)
{
"success": true,
"id": "d7f2a1b3-4c5e-6f78-9a0b-1c2d3e4f5a6b"
}Errors
| Status | Code | Description |
|---|---|---|
| 400 | missing_project | API key must be scoped to a project |
Rate limiting
120 requests per 60 seconds per API key.
SDK behavior
The SDK calls POST /v1/decisions automatically after every client-side deterministic validation. The call is fire-and-forget, errors are silently swallowed so they never block tool execution.
The TypeScript SDK uses this behavior. Python agents can call the same endpoint directly or use the Python preview package when local validation is enough:
// TypeScript — called internally by tryLocalDeterministic()
client.logDecision({
tool_name: 'send_email',
arguments: { to: 'user@example.com' },
decision: 'allow',
mode: 'deterministic',
latency_ms: 2,
source: 'client',
});# Python preview or direct client call
client.log_decision({
"tool_name": "send_email",
"arguments": {"to": "user@example.com"},
"decision": "allow",
"mode": "deterministic",
"latency_ms": 2,
"source": "client",
})Decisions logged via this endpoint appear in the dashboard alongside server-side decisions. They are marked with source: "client" in the context field.

