The verdict API — govern without a gateway
Sometimes you don’t want a proxy in front of your agent — you just want to ask policy a question and act on the answer yourself. That’s the verdict API: one call, one decision, TapPass never touches your traffic.
This is the opposite deployment shape from TapPass as the gateway. Here TapPass is a policy oracle beside your app, not in the hot path.
Ask before you act
Section titled “Ask before you act”POST /v1/govern takes the action you’re about to perform and returns a decision:
curl -X POST https://tappass.example.com/v1/govern \ -H "Authorization: Bearer tp_dev_..." \ -H "Content-Type: application/json" \ -d '{ "type": "TOOL_CALL", "agent_id": "support-agent", "session_id": "ses_abc123", "payload": {"tool": "send_email", "args": {"to": "user@acme.com"}} }'{ "outcome": "allow", "reason": "", "behavior_id": "beh_…", "pipeline_id": "run_…", "decided_at": "2026-07-21T09:14:03Z", "mandate": "<signed-mandate-jwt>"}outcome is one of:
| Outcome | What you do |
|---|---|
allow |
Perform the action. The mandate is a short-lived signed token naming exactly what was authorized. |
block |
Don’t perform it — reason and details say why (the same evidence an auditor sees). |
needs_approval |
A human must approve. Resubmit the identical call once the approval is granted. |
You call this before the action. If it’s allow, you execute the tool / write / LLM call in your own code. TapPass recorded the decision either way.
What you can govern
Section titled “What you can govern”The type names what the agent is about to do. It’s not just tool calls — the verdict API governs the full range of agent behaviors:
type |
The action |
|---|---|
LLM_CALL / EMBEDDING_CALL |
A model or embedding request |
TOOL_CALL / TOOL_LIST / TOOL_RESULT |
Invoking a tool, discovering tools, or handing a tool result back |
SYSTEM_OF_RECORD_WRITE |
A write to a system of record (CRM, ledger, ticketing…) |
STATE_TRANSITION |
A change in your workflow’s state |
PROMPT_SUBMIT |
A user/agent prompt entering the loop |
CREDENTIAL_ACCESS / CODE_EXEC / SKILL_LOAD |
Reading a secret, executing code, loading a skill |
The payload carries the specifics for that type (e.g. tool + args, or model + messages). See behaviors for each shape.
Obligations: allow with conditions
Section titled “Obligations: allow with conditions”A decision isn’t only yes/no. An allow can arrive with obligations — things you must apply before proceeding, like redacting a detected secret or routing to a different model. When TapPass can apply the change itself it returns a modified_payload; otherwise the obligations list tells you what to do. Honour them, then act. See verdicts & obligations.
After you act
Section titled “After you act”Decision-only means TapPass didn’t see the result — so close the loop by reporting it. POST /v1/govern/execution (correlated by pipeline_id) records what happened — output, latency, tokens, cost — so the audit trail and trust score stay complete. When a call comes back needs_approval, an operator grants it via POST /v1/govern/approve (or the dashboard), and you resubmit the identical call.
From your agent code
Section titled “From your agent code”You rarely hand-write the curl. The Python SDK wraps /v1/govern around any framework’s tools or plain callables:
import tappassfrom tappass import GovernanceBlocked, ApprovalPending
tools = tappass.govern( [send_email], url="https://tappass.example.com", api_key="tp_dev_...", agent_id="support-agent", mode="enforce", # POST a TOOL_CALL to /v1/govern before running)
try: tools[0](to="cfo@acme.com", subject="Q4", body="…")except GovernanceBlocked as e: print(f"Blocked by policy: {e.reason}") # tool never executedexcept ApprovalPending as e: print(f"Suspended pending approval: {e.request_id}")govern() works with CrewAI, LangChain, LlamaIndex, Pydantic AI, and plain functions — see governance from code. In mode="enforce" an unreachable server fails closed by default; nothing runs unless policy said allow.
One line in a hook
Section titled “One line in a hook”Because it’s a single JSON call, /v1/govern drops into any pre-execution hook. The Claude Code integration is exactly this: every PreToolUse becomes a TOOL_CALL behavior posted to /v1/govern, and a block refuses the tool — no gateway involved.
Why choose the verdict API
Section titled “Why choose the verdict API”- Zero blast radius. TapPass being slow or down never stalls your traffic — you decide the fail-open/fail-closed policy in your own code.
- Governs non-LLM actions. Database writes, state transitions, tool calls — anything you can describe as a behavior, not just model calls.
- Cryptographic proof. An
allowmints a mandate your executor can verify offline against the published JWKS.
When you’d rather not touch every call site — and want provider key handling, streaming, and audit for free — put TapPass in the path as the gateway instead.
Next steps
Section titled “Next steps”- Verdicts, obligations & mandates — everything a decision contains
- HTTP API reference — the full
/v1/governfamily - Governance from code —
govern()modes and enforce-mode exceptions