POST /execute

Runs a payload through all nine pipeline stages and returns the sealed ExecutionManifest plus a server-side run_id.

Request

POST /execute
Content-Type: application/json
X-Verdifax-Key: vfx_...                  (required once any key has been created)

Body

The request body contains:

{
  "program_id":           "string, 64-char lowercase hex (required)",
  "route_id":             "string, non-empty (required)",
  "registry_record_hash": "string, 64-char lowercase hex (required)",
  "payload":              "string, UTF-8 plaintext (required, or use payload_text)",
  "payload_text":         "string, alternative to payload (required, or use payload)",
  "attested_context":     "object (optional), caller-supplied attestation metadata",
  "request_substance":    "object (optional), category 1: prompt, output, post-processing, cost, latency, origin and authentication records",
  "authorization_chain":  "object (optional), AttestedContext category 2: approvals, delegation, audit trail",
  "regulatory_scaffolding": "object (optional), AttestedContext category 3: data classification, export control",
  "causal_graph":         "object (optional), AttestedContext category 4: side effects and external actions",
  "reproducibility_context": "object (optional), caller-declared runtime, dependencies, seeds and platform",
  "ai_output_text":       "string (optional), AI output to send to the AIVP-T4 governance review"
}

Payload variants: Supply payload or payload_text (alternative name for the same field); if both are present, payload_text is used. program_id, route_id and registry_record_hash are required. The six context objects (including reproducibility_context) and ai_output_text are optional, and keys the server does not recognize are ignored, not sealed. When ai_output_text is present, the hosted API sends it to the Anthropic Claude API for the AIVP-T4 governance review and seals its SHA-256 hash and the review's result; the raw text is not stored after the review. Without it, the review records a release with no AI output to govern.

request_substance fields: prompt, output, post_processing, cost, latency, origin and authentication. From run 247 on, the server computes origin.source_ip_hash and origin.user_agent_hash itself and refuses a request that supplies either one.

attested_context schema (only these fields):

  • attested (boolean)
  • actor_id (string)
  • actor_role (string)
  • authorization_policy (string)
  • actor_signature (string, base64)
  • model_provider (string)
  • model_name (string)
  • model_version (string)
  • model_temperature (float)
  • prompt_hash (string, 64-hex)
  • decision_kind (string)
  • decision_result (string)
  • decision_note (string)

Example request (financial disbursement scenario)

{
  "program_id": "aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa",
  "route_id": "payments-disbursement-demo",
  "registry_record_hash": "bbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbb",
  "payload": "Evaluate payment request: $250K USD wire to vendor acme-corp for Q2 services contract #4521.",
  "attested_context": {
    "attested": true,
    "actor_id": "tenant-demo-acme",
    "actor_role": "ops_manager",
    "model_provider": "openai",
    "model_name": "gpt-4o-mini",
    "model_version": "2024-07-18",
    "model_temperature": 0.1,
    "prompt_hash": "cccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccc",
    "decision_kind": "financial_disbursement",
    "decision_result": "approved",
    "decision_note": "vendor in approved list, amount within limit, contract exists"
  },
  "request_substance": {
    "prompt": {
      "hash": "cccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccc",
      "template_id": "approve_transaction_v3"
    },
    "cost": {"input_tokens": 812, "output_tokens": 164, "total_tokens": 976}
  },
  "authorization_chain": {
    "approvers": [
      {
        "order": 1,
        "actor_id": "finance-team",
        "actor_role": "finance_reviewer",
        "approved_at": "2026-05-03T14:22:10Z",
        "approved_request_hash": "dddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddd",
        "signature": "...",
        "comment": "Amount authorized"
      }
    ],
    "threshold_checks": [{"name": "transaction_amount_usd", "threshold_value": 100000, "observed_value": 250000, "unit": "USD", "operator": ">", "breached": true}],
    "human_in_loop": {
      "required": true,
      "performed": true,
      "performed_by": "compliance-officer",
      "performed_at": "2026-05-03T14:23:45Z",
      "review_mode": "automated_with_exception",
      "review_outcome": "approved"
    }
  },
  "regulatory_scaffolding": {
    "data_classification": {
      "commercial": ["PII", "FINANCIAL_DATA"]
    }
  },
  "causal_graph": {
    "effect_log": [
      {
        "effect_kind": "payment_instruction",
        "target": "stripe_api_v3",
        "status": "queued",
        "issued_at": "2026-05-03T14:24:00Z",
        "ack_hash": "eeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeee"
      }
    ]
  }
}

Response

The response shape depends on the outcome state. All responses include ok (boolean); persisted runs also return run_id (integer). Only an OK run returns 200; every deny or halt returns 422 with a sealed receipt.

OK (request admitted and executed)

200 OK:

{
  "ok": true,
  "run_id": 63,
  "duration_ms": 3,
  "manifest": {
    "EnvelopeID": "env-...",
    "EnvelopeHash": "...",
    "SequenceID": "seq-...",
    "TransportHash": "...",
    "EpaHash": "...",
    "EfaHash": "...",
    "ExecutionIDs": ["...", "...", "...", "...", "...", "..."],
    "AerHash": "...",
    "TranscriptHash": "...",
    "HardwareAttestationHash": "...",
    "LeakageBundleHash": "...",
    "FormalVerifierStatus": "<formal-verifier success token, scaffold today>",
    "ZkspBindingHash": "...",
    "MigrationTokenHash": "...",
    "ReplayFingerprint": "...",
    "PoteProofHash": "...",
    "LogEntryID": "...",
    "RegistryArtifactCount": 20,
    "FinalVfaHash": "...",
    "IndependentVerified": true,
    ...,
    "ManifestHash": "6c1428f81519c5bb..."
  },
  "allow_token": {
    "envelope_id": "env-...",
    "fired_rule_id": "baseline-permit",
    "decision_reason_code": "RULE_ALLOWED",
    "policy_hash": "...",
    "evaluation_hash": "...",
    "allow_clock": "2026-05-03T14:24:00Z",
    "evaluator_version": "pepg-0.3.0",
    "version": "vfa.allow_token.v1",
    "hash": "..."
  }
}

PEPG Deny (policy rejected before execution)

422 Unprocessable Entity with deny outcome:

{
  "ok": false,
  "run_id": 64,
  "duration_ms": 1,
  "error": "...",
  "error_stage": "PEPG",
  "partial_manifest": {
    "EnvelopeID": "env-...",
    "PepgOutcome": "deny",
    ...
  },
  "deny_receipt": {
    "anchor_required": true,
    "envelope_id": "env-...",
    "fired_rule_id": "mcd-llm-001",
    "decision_reason_code": "MCD_SIGNATURE_MATCH",
    "policy_hash": "...",
    "evaluation_hash": "...",
    "mcd_finding_hash": "...",
    "deny_clock": "2026-05-03T14:24:00Z",
    "evaluator_version": "pepg-0.3.0",
    "version": "vfa.deny_receipt.v1",
    "hash": "..."
  }
}

The hosted API runs one built-in policy whose single rule, baseline-permit, admits every request, so its only deny is a Malicious Code Defense (MCD) signature match: decision_reason_code is MCD_SIGNATURE_MATCH, fired_rule_id is the matched signature id (for example mcd-llm-001), and mcd_finding_hash is populated.

Receipts sealed by the hosted API since run 242 carry "anchor_required": true, as in the samples on this page; a deployment whose ledger does not anchor receipts on the public log omits the field. The GET /runs/{id}/... receipt endpoints also return the receipt's public-log entry as a sibling receipt_anchor; see Sealed artifacts.

CCV Halt (per-run budget breach)

CCV checks the run's caller-declared consumption (request_substance.cost.total_tokens; a run that reports none counts as zero) against the per-run budget once, at the post-DKEC boundary.

422 Unprocessable Entity with halt outcome:

{
  "ok": false,
  "run_id": 65,
  "duration_ms": 12,
  "error": "...",
  "error_stage": "CCV",
  "partial_manifest": {
    "EnvelopeID": "env-...",
    "CcvOutcome": "halted",
    ...
  },
  "ccv_halt_receipt": {
    "anchor_required": true,
    "envelope_id": "env-...",
    "halt_reason_code": "TOKEN_BUDGET_EXCEEDED",
    "constraint_type": "token_budget",
    "budget_limit": 100000,
    "consumed_at_halt": 100045,
    "budget_hash": "...",
    "allow_token_hash": "...",
    "partial_execution_hash": "...",
    "halt_clock": "2026-05-03T14:24:12Z",
    "evaluator_version": "ccv-0.3.0",
    "version": "vfa.ccv_halt.v1",
    "hash": "..."
  }
}

MACC Halt (cumulative budget breach)

MACC adds the same caller-declared consumption to a cumulative per-window total. From run 247 on, the budget bucket (tenant_id on the receipt) is the authenticated API key (api-key-N, or anonymous without a key); before run 247, it was the caller-declared attested_context.actor_id when supplied, falling back to api-key-N.

422 Unprocessable Entity with halt outcome:

{
  "ok": false,
  "run_id": 76,
  "duration_ms": 2,
  "error": "...",
  "error_stage": "MACC",
  "partial_manifest": {
    "EnvelopeID": "env-...",
    "MaccOutcome": "halted",
    ...
  },
  "macc_halt_receipt": {
    "anchor_required": true,
    "envelope_id": "env-...",
    "tenant_id": "api-key-7",
    "halt_reason_code": "CUMULATIVE_TOKEN_BUDGET_EXCEEDED",
    "constraint_type": "cumulative_token_budget",
    "budget_limit": 1000000,
    "cumulative_at_halt": 1000245,
    "per_run_consumption": 250,
    "window_start": "2026-05-03T00:00:00Z",
    "budget_hash": "...",
    "allow_token_hash": "...",
    "halt_clock": "2026-05-03T14:24:00Z",
    "evaluator_version": "macc-0.3.0",
    "version": "vfa.macc_halt.v1",
    "hash": "..."
  }
}

AIVP-T4 halt and attestation gap

Two more sealed outcomes return 422 with the same envelope: an AIVP-T4 Tier-4 governance halt (error_stage: "AIVP_T4", aivp_t4_halt_receipt and partial_manifest) and an admission-time attestation gap (error_stage: "PEPG_ADMISSION", attestation_gap_receipt, no manifest). An attestation gap fires only under a policy that requires attested fields; the hosted API's built-in policy requires none, so the hosted API does not currently return one.

Error responses

For validation errors and network issues:

400 Bad Request, invalid input (bad hex, missing field, malformed JSON). 401 Unauthorized, a key has been created on the deployment and the header is absent or invalid. 429 Too Many Requests, rate limit exceeded.

See Errors for the full envelope and stage-specific 422 responses.

Example

curl -s -X POST http://localhost:9090/execute \
  -H "Content-Type: application/json" \
  -H "X-Verdifax-Key: vfx_..." \
  -d '{
    "program_id": "aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa",
    "route_id": "payments-disbursement-demo",
    "registry_record_hash": "bbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbb",
    "payload": "Evaluate payment request: $250K USD wire to vendor acme-corp for Q2 services contract #4521.",
    "attested_context": {
      "attested": true,
      "actor_id": "tenant-demo-acme",
      "actor_role": "ops_manager",
      "model_provider": "openai",
      "model_name": "gpt-4o-mini",
      "decision_kind": "financial_disbursement",
      "decision_result": "approved"
    }
  }' | python3 -m json.tool

Determinism

Two calls with the same payload, program_id, route_id and registry_record_hash do not return the same ManifestHash. Every /execute call mints a fresh admission clock and a fresh per-run nonce, and both enter the manifest hash and the leaf anchored on the public Sigstore Rekor log, so each run is a distinct record with its own log entry.

What is deterministic is the pipeline's computation: replaying the same inputs under a pinned clock and nonce, with the public-log anchoring stage held fixed, reproduces the same ManifestHash byte-for-byte, and POST /execute/verify-determinism runs exactly that check. A production record's hash also binds its own unique public-log entry, so a production record is verified by recomputing its seals from its recorded fields, not by re-running it: a sealed run's stored manifest fields always re-derive to its recorded ManifestHash, which GET /runs/{id}/verify checks.

Continue