Verify
The core endpoint for AI governance — send a prompt, receive a decision.
Every governance decision starts here. Send a prompt; Palveron runs it through policies, NGE, and (optionally) LLM-assist; you get back a decision and a fully-attributed trace.
POST /api/v1/verify
curl -X POST https://gateway.palveron.com/api/v1/verify \
-H "Authorization: Bearer pv_live_..." \
-H "Content-Type: application/json" \
-d '{
"prompt": "My social security number is 123-45-6789.",
"agent_id": "agent_...",
"context": { "sourceSystem": "customer-support-ui" }
}'Request
| Field | Required | Description |
|---|---|---|
prompt | ✅ | The text to evaluate |
agent_id | — | Agent attribution (defaults to the project's anonymous agent) |
attachments | — | Array of multi-modal payloads (see Multi-modal) |
context | — | Free-form metadata (MCP server, tool name, source UI) — passed through to traces |
dry_run | — | If true, no trace is persisted (use only for client-side previewing) |
Response
{
"decision": "BLOCKED",
"reason": "PII detected: SSN",
"trace_id": "trc_01HVB...",
"integrity_hash": "sha256:...",
"modified_prompt": null,
"nge_policy_scores": {
"injection": 0.04,
"toxicity": 0.02,
"off_topic": 0.18,
"pii_density": 0.91
},
"detected_entities": [
{ "type": "SSN", "start": 26, "end": 37, "confidence": 0.99, "redacted": "[SSN]" }
],
"deterministic_results": {
"regex_matches": ["ssn_us"],
"keyword_matches": [],
"blocklist_hits": []
},
"engine": "nge_local",
"policies_evaluated": ["pol_pii_mask", "pol_no_pii"],
"latency_ms": 42
}Decisions
PASSED— Request allowed, original prompt forwarded.BLOCKED— Request rejected.reasonexplains why;modified_promptis null.MODIFIED— Request allowed with edits.modified_promptcontains the redacted version.FLAGGED— Request allowed; aLOG_ONLYpolicy fired and the violation is recorded in the trace.PENDING_APPROVAL— Request queued for a human approver. Poll the trace or the Approval Queue API to learn the outcome.ERROR— Internal failure. Retry; if persistent, contact support withtrace_id.
HTTP status codes
The HTTP status code mirrors the decision field, so load balancers, observability tools, and HTTP-aware clients (e.g. MCP / OpenClaw consumers) get a faithful signal without having to parse the JSON body.
| Status | Decision | Meaning |
|---|---|---|
200 OK | PASSED / MODIFIED / FLAGGED / POLICY_CHANGE | Request allowed. Forward the (possibly modified) prompt to your LLM. |
202 Accepted | PENDING_APPROVAL | Human approval required. The trace is persisted; the approval is tracked via trace_id. |
403 Forbidden | BLOCKED | Request denied by policy, capability model, or per-agent budget cap. Do not retry — inspect reason. |
429 Too Many Requests | no decision | Tier rate-limit hit. Honour Retry-After. Body shape is the rate-limit error, not a verify response. |
400 Bad Request | no decision | Malformed request: missing prompt, oversized attachment, invalid config. |
The JSON body is the source of truth. A response with a decision field is a verify response regardless of status (200 / 202 / 403). Clients should branch on decision, not on response.ok. Reserve HTTP-status branching for 429 (rate limits) and 5xx (transport errors).
NGE fields
| Field | Description |
|---|---|
nge_policy_scores | NLI-based confidence scores per policy intent (0.0 – 1.0). Populated when NGE mode is nge_local or nge_fallback. |
detected_entities[] | PII / named entity hits with byte offsets and confidence. Populated when NGE entity-detection is enabled. |
deterministic_results | Regex, Aho-Corasick keyword, and blocklist hits — always populated, NGE-independent. |
engine | Which engine produced the result: disabled, nge_local, nge_fallback, or llm_only. |
When engine is nge_fallback, the response also includes escalated_to_llm (true / false) — true means a borderline case was escalated to the cloud LLM for the final call.
See the Neural Governance Engine guide for the full pipeline and per-mode trade-offs.
Errors
Distinct from a governance BLOCKED (which is a successful 403 with a verify-shaped body), these statuses indicate the gateway could not process the request at all.
| Status | Code | Meaning |
|---|---|---|
400 | MISSING_PROMPT | Required prompt field omitted |
400 | INVALID_ATTACHMENT | Unsupported MIME type or oversized payload |
401 | INVALID_API_KEY | Missing or invalid API key |
429 | RATE_LIMIT_EXCEEDED | Per-key burst or monthly quota hit; honor Retry-After |
503 | NGE_RELOADING | Models are being reloaded (~2s); transient, retry once |
Tip: distinguish a transport error from a governance block by checking for the
decisionfield. If it's present, the response is a verify outcome (parse the body). If it's absent, treat the status code as a transport/auth error.
Retry behavior
POST /verify is not idempotent by default — retrying creates a second trace. The SDKs handle this by attaching a Idempotency-Key header (UUID v4) on every request and retrying only on idempotent-safe failures (timeouts and 5xx). Custom clients should do the same: set Idempotency-Key, retry transient errors with exponential backoff and jitter.
POST /api/v1/verify
Idempotency-Key: 4d6b9a40-...Palveron deduplicates by idempotency key for 24 hours — a retry within that window returns the original response without creating a duplicate trace.