Skip to content
/docs

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

HeaderRequiredDescription
X-Veto-API-Key or AuthorizationYesAPI key or Bearer JWT

Query parameters

ParameterTypeDefaultDescription
limitnumber50Results per page (1–100)
offsetnumber0Skip this many results
projectIdstring (UUID)Filter by project
toolNamestringFilter by tool name
decision"allow" | "deny"Filter by decision
startDateISO 8601 dateFilter from this date
endDateISO 8601 dateFilter 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

HeaderRequiredDescription
X-Veto-API-Key or AuthorizationYesAPI key or Bearer JWT

Query parameters

ParameterTypeDefaultDescription
daysnumber7Lookback period (1–90)
projectIdstring (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

HeaderRequiredDescription
X-Veto-API-Key or AuthorizationYesAPI key or Bearer JWT

Path parameters

ParameterTypeDescription
idstring (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

HeaderRequiredDescription
X-Veto-API-Key or AuthorizationYesAPI key or Bearer JWT

Path parameters

ParameterTypeDescription
idstring (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

StatusDescription
400Invalid UUID format
404Decision 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

HeaderRequiredDescription
X-Veto-API-KeyYesAPI key scoped to a project
Content-TypeYesapplication/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"
  }
}
FieldTypeRequiredDescription
tool_namestringYesName of the tool that was validated
argumentsobjectYesArguments that were validated
decision"allow" | "deny"YesValidation result
reasonstringNoExplanation of the decision
mode"deterministic"YesValidation mode used
latency_msnumberYesClient-side validation time in milliseconds
source"client"YesMust be "client"
contextobjectNoAdditional metadata (session_id, agent_id, etc.)

Response (201)

{
  "success": true,
  "id": "d7f2a1b3-4c5e-6f78-9a0b-1c2d3e4f5a6b"
}

Errors

StatusCodeDescription
400missing_projectAPI 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.