Developer Documentation

Zero to first gate call
in under 10 minutes.

One endpoint. One header. POST before each step — the gate returns ALLOW or DENY. Your agent only proceeds on ALLOW. Every ALLOW writes a cryptographic receipt — a signed, chained record of what ran, when, in what order, written before the action executed. The same gate answers the engineering question and the compliance question.

Wrapper live — https://api.agenticrail.nz/v1/evaluate

Three steps. No magic.

Every gate call follows the same path. Your agent sends a request. The gate enforces sequence. You get a receipt or a halt.

01
Send request

POST to /v1/evaluate with your agent's current step, a unique nonce, and a timestamp. Auth via the Authorization: Bearer header.

02
Gate enforces sequence

The gate validates step order, checks the nonce for replay, verifies function and action_type against the policy for this step, and confirms the sequence is not sealed. All checks must pass.

03
Receive receipt or halt

On pass: a cryptographic receipt with decision ALLOW — HMAC-signed, chained, stored immutably in R2. That receipt is your compliance record: structural proof of what ran, when, in what order. On failure: a DENY with a reason code. Your agent only proceeds on ALLOW.

One header. Every request.

All requests to the wrapper require the Authorization: Bearer header. The demo key is public and rate-limited — use it to test without signing up.

Demo key — public, free to use
DEMO-AGENTICRAIL-PUBLIC-2026

Add to every request: Authorization: Bearer DEMO-AGENTICRAIL-PUBLIC-2026
The wrapper expects the Authorization header; the gate uses x-slp8-key.

For production use, contact hello@agenticrail.nz for a private key with no rate limits.

Wrapper, Gate, and Report

AgenticRail deploys three public services:

01
Wrapper (front door)

Endpoint: https://api.agenticrail.nz/v1/evaluate
Auth: Authorization: Bearer <key>
Adds API key management, rate limiting, D1 logging, and demo key bypass. All client requests should use this endpoint.

02
Gate (enforcement)

Pure sequence enforcement layer — validates step order, nonce, function/action_type policy, and sequence seal. Called internally by the wrapper via service binding. Not publicly accessible — all client traffic enters through the wrapper.

03
Report (compliance)

Endpoint: https://report.agenticrail.nz/report
Auth: x-slp8-key: <key>
Generates HTML/JSON compliance reports for any sequence. Read-only; no state mutation.

Demo key DEMO-AGENTICRAIL-PUBLIC-2026 works with all three services. Wrapper prefixes demo sequence IDs with demo- and isolates receipts.

Fields, one by one.

All requests are Content-Type: application/json via POST. Fields are validated in order — a missing required field halts at gate step 1.

Field Type Description
schema_version string Always "1.0"
sequence_id string Unique per sequence — e.g. a UUID or session ID. Groups steps together.
step string Your step name — must match function. Must be a valid step in your configured sequence, called in the defined order. e.g. "verify_identity", "assess_risk", "execute_transfer".
function string Canonical function name — must equal step. e.g. "verify_identity", "assess_risk". Used for policy lookup.
action_type string Canonical action type for this step. Must be in the allowed set for the function. e.g. "CHECK_STATE", "RECORD_RESULT", "WAIT_FOR_SIGNAL".
model_id string Your agent identifier — e.g. "my-agent-v2". When using the demo key, the wrapper transforms this to "client:demo" before passing to the gate.
nonce string Unique string per request (any format). Used for replay protection — never reuse.
action string Descriptive action label for this step. e.g. "verify identity", "assess risk".
ts_ms number Unix timestamp in milliseconds. Required — use Date.now() or equivalent. Must be within ±300 seconds of current time when received by the gate.
inputs object Optional. Any context you want to log alongside the step.
attestation object Optional. Evidence object signed into the receipt at this step — e.g. {"aml_check": "passed", "approved_by": "risk-committee-id"}. The full object is stored immutably in R2 alongside the receipt. Use it to embed proof of deliverables, external check results, or human approvals directly in the audit trail. Can contain hashes, IDs, and long strings — excluded from poison hardening.
step_order string[] Required on every call. Array of all step names in execution order — e.g. ["verify_identity", "assess_risk", "execute_transfer"]. The gate reads it from each payload to resolve the step's position. The gate does not store it between calls.

Timestamp freshness: The gate enforces a ±300 second window around the current time. If your request arrives more than 5 minutes early or late, it will be rejected with reason STALE_TIMESTAMP. Always generate ts_ms fresh using Date.now() or equivalent.

Copy. Paste. Run.

This example works against the live wrapper right now. Each snippet generates a fresh timestamp, a unique nonce, and a unique sequence ID on every run, so it returns ALLOW the moment you paste it.

Have an API key? Use the Workflow Builder → — pick an industry template, paste your key, get a ready-to-run curl command in 30 seconds.
curl — bash / mac / linux
# Paste the whole block. Fresh timestamp, unique nonce + sequence id - runs every time.
TS=$(( $(date +%s) * 1000 ))
NONCE=$(openssl rand -hex 8)
SEQ="my-seq-$(date +%s)"

curl -X POST https://api.agenticrail.nz/v1/evaluate \
  -H 'Content-Type: application/json' \
  -H 'Authorization: Bearer DEMO-AGENTICRAIL-PUBLIC-2026' \
  -d "{
    \"schema_version\": \"1.0\",
    \"model_id\":       \"my-agent\",
    \"sequence_id\":    \"$SEQ\",
    \"step\":           \"verify_identity\",
    \"function\":       \"verify_identity\",
    \"action_type\":    \"CHECK_STATE\",
    \"action\":         \"verify identity\",
    \"nonce\":          \"$NONCE\",
    \"ts_ms\":          $TS,
    \"inputs\":         {},
    \"step_order\":     [\"verify_identity\", \"assess_risk\", \"execute_transfer\", \"audit_ledger\"]
  }"
powershell — windows
# Paste the whole block into PowerShell
$ts    = [DateTimeOffset]::UtcNow.ToUnixTimeMilliseconds()
$nonce = -join ((1..16) | ForEach-Object { '0123456789abcdef'[(Get-Random -Maximum 16)] })
$seq   = "my-seq-$ts"
$body = '{"schema_version":"1.0","model_id":"my-agent","sequence_id":"' + $seq + '","step":"verify_identity","function":"verify_identity","action_type":"CHECK_STATE","action":"verify identity","nonce":"' + $nonce + '","ts_ms":' + $ts + ',"inputs":{},"step_order":["verify_identity","assess_risk","execute_transfer","audit_ledger"]}'
$headers = @{ "Content-Type" = "application/json"; "Authorization" = "Bearer DEMO-AGENTICRAIL-PUBLIC-2026" }
(Invoke-WebRequest -UseBasicParsing -Uri https://api.agenticrail.nz/v1/evaluate -Method POST -Headers $headers -Body $body).Content

ts_ms is a required field — the current Unix time in milliseconds, within 300 seconds of server time. The snippets generate it for you. Note: date +%s%3N is GNU-only; the cross-platform form $(( $(date +%s) * 1000 )) works on macOS and Linux.

javascript
// One gate call — adapt into your agent loop
const res = await fetch('https://api.agenticrail.nz/v1/evaluate', {
  method: 'POST',
  headers: {
    'Content-Type': 'application/json',
    'Authorization':    'Bearer DEMO-AGENTICRAIL-PUBLIC-2026',
  },
  body: JSON.stringify({
    schema_version: '1.0',
    model_id:       'my-agent',
    sequence_id:    'my-seq-' + Date.now(),
    step:           'verify_identity',
    function:       'verify_identity',
    action_type:    'CHECK_STATE',
    action:         'verify identity',
    nonce:          crypto.randomUUID().replace(/-/g, '').slice(0, 16),
    ts_ms:          Date.now(),
    inputs:         {},
    step_order:     ['verify_identity', 'assess_risk', 'execute_transfer', 'audit_ledger'],
  }),
});

const gate = await res.json();

if (gate.decision === 'ALLOW') {
  // Proceed with your step
} else {
  // Halt — do not proceed
  console.error('DENY:', gate.reasons);
}

ALLOW or DENY. Nothing in between.

The wrapper returns a flattened response with all decision details at the top level. There is no pack wrapper — the decision, reasons, and executed fields are directly in the response object. The nested receipt object carries the receipt metadata for that decision — key_id, signature_alg, payload_hash, and version.

✓ ALLOW — step accepted
{
  "decision": "ALLOW",
  "executed": true,
  "pack_id": "80fe6e6887ca024d2325260f83224c86c3d2157b10ef60cc73ee8fded4661552",
  "reasons": [],
  "sequence_id": "demo-test-seq-001",
  "step": "verify_identity",
  "function": "verify_identity",
  "action_type": "CHECK_STATE",
  "model_id": "client:demo",
  "result": {
    "status": "submitted",
    "data": {
      "state": null
    }
  },
  "receipt": {
    "pack_id": "80fe6e6887ca024d2325260f83224c86c3d2157b10ef60cc73ee8fded4661552",
    "key_id": "k2_2026-06-07_ed25519",
    "signature": null,
    "signature_alg": "Ed25519",
    "payload_hash": "201031e1bce583b179f7b9b8b9c794de2cd8514da84adae974232ed3f2ff0774",
    "prev_receipt_id": null,
    "ts_ms": 1780732058107,
    "version": "slp8_receipt_v2",
    "attestation": null
  },
  "log": {
    "ok": true,
    "error": null
  }
}
✗ DENY — sequence violation
{
  "decision": "DENY",
  "executed": false,
  "pack_id": "1493ba42f5e0ffb81227e700eda1e03e762058fd9da4080f320c432b6fa23c2f",
  "reasons": ["SEQUENCE_VIOLATION"],
  "sequence_id": "demo-replay-test-seq",
  "step": "execute_transfer",
  "function": "execute_transfer",
  "action_type": "CHECK_STATE",
  "model_id": "client:demo",
  "result": {
    "status": "skipped",
    "message": "No execution triggered"
  },
  "receipt": {
    "pack_id": "1493ba42f5e0ffb81227e700eda1e03e762058fd9da4080f320c432b6fa23c2f",
    "key_id": "k2_2026-06-07_ed25519",
    "signature": null,
    "signature_alg": "Ed25519",
    "payload_hash": "9f2c1a77b4e83d0516a8c4f9e2b7d3061c5a8e94f0b2d6713a9e4c8051f7b2d4",
    "prev_receipt_id": "80fe6e6887ca024d2325260f83224c86c3d2157b10ef60cc73ee8fded4661552",
    "ts_ms": 1780732061488,
    "version": "slp8_receipt_v2",
    "attestation": null
  },
  "log": {
    "ok": true,
    "error": null
  }
}

About the signature. The inline receipt carries the decision metadata and the payload_hash. The HMAC signature itself is finalized in the durable, immutable receipt written to storage — it is not echoed in the synchronous response. To confirm a receipt is signed and the chain is intact, verify it at report.agenticrail.nz, which returns verification_status: VERIFIED_INTACT along with the signing key_id and signature_alg — proving a valid signature exists without exposing it.

Reason code
Meaning
SEQUENCE_VIOLATION
Step arrived out of order — e.g. execute_transfer before verify_identity has completed.
REPLAY_NONCE
Nonce has already been used. Generate a fresh nonce per request.
STALE_TIMESTAMP
Timestamp (ts_ms) is outside the allowed ±300 second window from current time. Always generate ts_ms fresh using Date.now() or equivalent.
SEALED_SEQUENCE
This sequence has already been completed. Start a new sequence_id.
ACTION_NOT_ALLOWED
action_type is not in the allowed set for this function/step.
NO_POLICY_MATCH
function value is not a recognised step name.
FUNCTION_STEP_MISMATCH
function and step fields do not match.
missing_*
Required field absent — e.g. missing_function, missing_action_type, missing_nonce.
BAD_JSON
Request body is not valid JSON. Check your JSON syntax.
BAD_CONTENT_TYPE
Content-Type header is missing or not application/json.
BODY_TOO_LARGE
Request body exceeds the size limit.
METHOD_NOT_ALLOWED
Request was not a POST. Only POST is accepted.
UNAUTHORIZED
Missing or invalid Authorization: Bearer header (wrapper) or x-slp8-key header (gate).

The rules the gate enforces.

These aren't soft guidelines. A violation on any one of them returns DENY immediately.

Steps must run in the configured order. No skipping. Each step must follow the one before it — for example, verify_identityassess_riskrequest_approvalexecute_transfer. An out-of-order step returns SEQUENCE_VIOLATION.
Nonces are single-use. Each request must supply a unique nonce. Reusing any nonce — even from a prior sequence — returns REPLAY_NONCE.
function and action_type must be valid. function must match step. action_type must be in the allowed set for that function. Invalid combinations return ACTION_NOT_ALLOWED or FUNCTION_STEP_MISMATCH.
Sequences seal after completion. Once settle is accepted, the sequence locks. Any further request on that sequence_id returns SEALED_SEQUENCE. Start a new sequence with a fresh ID.
Only POST is accepted. GET, PUT, PATCH and all other methods return METHOD_NOT_ALLOWED immediately.

Embed evidence in the receipt.

Each step can carry an attestation object — arbitrary evidence that travels with the request and gets signed into the R2 receipt. Use it to prove what happened at each step: an AML check passed, a human approved the action, an external system returned a specific result.

The attestation is stored immutably alongside the receipt and appears in every compliance report generated for that sequence. It's not a separate log entry — it's part of the cryptographic chain.

Python — attestation per step
from agenticrail import RailClient
import time

client = RailClient(api_key="DEMO-AGENTICRAIL-PUBLIC-2026")
seq = client.sequence("payment-run-001", [
    "verify_identity", "assess_risk", "request_approval",
    "execute_transfer", "audit_ledger"
])

# Attach evidence at each step — signed into the receipt
seq.next("verify_identity", attestation={
    "kyc_provider": "acme-kyc",
    "result": "pass",
    "checked_at": int(time.time() * 1000),
})

seq.next("assess_risk", attestation={
    "risk_score": 23,
    "threshold": 50,
    "decision": "below_threshold",
})

seq.next("request_approval", attestation={
    "approved_by": "risk-committee-id-7f3a",
    "approval_ref": "APR-2026-00412",
})

seq.next("execute_transfer")   # attestation optional — omit if nothing to prove
seq.next("audit_ledger")       # seals sequence — all attestations locked in chain
JavaScript — attestation per step
import { RailClient } from "@agenticrail/core";

const client = new RailClient({ apiKey: "DEMO-AGENTICRAIL-PUBLIC-2026" });
const seq = client.sequence("payment-run-001", [
  "verify_identity", "assess_risk", "request_approval",
  "execute_transfer", "audit_ledger"
]);

// Attach evidence at each step — signed into the receipt
await seq.next("verify_identity", {
  attestation: { kyc_provider: "acme-kyc", result: "pass", checked_at: Date.now() }
});

await seq.next("assess_risk", {
  attestation: { risk_score: 23, threshold: 50, decision: "below_threshold" }
});

await seq.next("request_approval", {
  attestation: { approved_by: "risk-committee-id-7f3a", approval_ref: "APR-2026-00412" }
});

await seq.next("execute_transfer");  // attestation optional
await seq.next("audit_ledger");       // seals sequence — all attestations locked in chain

The attestation field accepts any plain JSON object. Values can include strings, numbers, and nested objects. Large binary blobs are not supported — store those in your own system and include a reference ID or hash here instead.

One command. Full provenance report.

The report worker reads every receipt for a sequence, verifies the cryptographic chain, and produces a human-readable compliance report. This is the deliverable your lawyer, auditor, or regulator asks for — proof of what ran, verified independently of what the agent claims.

Not a log export. Chain-verified receipt evidence, generated on demand for any sequence.

01
Request a report

Endpoint: POST https://report.agenticrail.nz/report
Headers: Content-Type: application/json, x-slp8-key: <key>
Body: { "sequence_id": "your‑sequence", "format": "html"|"json" }
Demo key restricts to sequences prefixed demo‑. Production key accesses any sequence.

02
Report generation

Worker scans R2 for all receipts matching the sequence ID, verifies each pack ID hash (multi‑generation logic), validates the receipt chain, and builds a compliance narrative via Claude (if ANTHROPIC_API_KEY configured).

03
Output formats

HTML: Full‑page report with cover, sequence summary, enforcement log, chain proof, and compliance narrative.
JSON: Structured data containing all verified receipts and verification results.
Read‑only; no state mutation.

curl — generate HTML report
# Replace SEQUENCE_ID with your sequence (demo‑ prefix for demo key)
curl -X POST https://report.agenticrail.nz/report \
  -H 'Content-Type: application/json' \
  -H 'x-slp8-key: DEMO-AGENTICRAIL-PUBLIC-2026' \
  -d '{
    "sequence_id": "demo‑my‑seq‑001",
    "format": "html"
  }'

Reports are deterministic — the same sequence always yields identical output. Verification uses multi‑generation hash checking to handle Gen‑1 and Gen‑2 receipts.

What the receipt chain proves — and to whom.

Every gate call produces enforcement output (ALLOW/DENY). It also produces a compliance record — a signed, chained, immutable receipt that answers the question regulators and lawyers actually ask: "Can you prove what the AI did?"

These are the same facts. Different audience, different frame.

Engineering question

"Did the agent proceed correctly? Was the step blocked? Why?"

Answered by the gate decision: ALLOW, DENY, reason codes.

Compliance question

"Can you prove what the AI did last Tuesday — not what it reported, what it actually executed?"

Answered by the receipt chain: signed, chained, tamper-evident.

Receipt field reference — what each field proves

Receipt field What it proves
pack_id Unique identifier for this enforcement decision — the canonical reference for this chain link.
signature (Ed25519) Tamper evidence. An Ed25519 signature (base64) over the canonical receipt, verifiable offline against the published public key (/spec/receipt-public-keys.json). If the receipt was altered after writing, verification fails. Legacy receipts before 2026-06-07 use HMAC-SHA256.
prev_receipt_id Chain linkage. Proves step ordering — the sequence cannot be reordered or have steps inserted after the fact. A broken chain link invalidates the report.
ts_ms Timestamp to the millisecond — when the gate decision was made. Written at enforcement time, not retrieved or reconstructed later.
payload_hash SHA-256 of the raw request body — the fingerprint of your payload, not the payload itself. Your agent's input data never enters immutable storage. An auditor can verify the receipt is cryptographically bound to a specific payload without ever seeing that payload's contents.
attestation Per-step evidence signed into the receipt — AML check results, human approval tokens, risk scores, KYC references. Proves what justified this specific decision.

GDPR obligations — answered structurally

These obligations apply to any AI system that processes personal data. AgenticRail satisfies them as a structural output of the enforcement layer — no extra instrumentation required.

Obligation How the receipt chain satisfies it
GDPR Art. 5(2) — Accountability Must demonstrate compliance, not just claim it. The signed receipt chain is the demonstration — facts written before actions executed, verifiable by anyone with the sequence ID.
GDPR Art. 22 — Automated decisions Transparency and documentation of automated decisions affecting people. Each gate decision is timestamped, preserved, and linked to the conditions under which it was made.
GDPR Art. 30 — Records of processing Systematic documentation of what the AI does. One receipt per action, one report per sequence — generated automatically, no manual record-keeping.
EU AI Act Art. 12 — Logging Immutable logging for high-risk AI systems. R2 receipts are tamper-evident by construction — written once, verifiable independently of the agent that generated the action.
Key distinction

Logs are self-reported — the AI agent tells you what it did. Receipts are structural — the gate wrote them before the agent acted, independent of the agent's own reporting. An auditor cannot distinguish a genuine log from a reconstructed one. They can verify a receipt chain cryptographically. That difference is what makes AgenticRail evidence rather than documentation.

Full compliance matrix — GDPR, EU AI Act, ISO 42001, NIST →

Ready to go further?

The demo key is open for testing. When you're ready for production — dedicated rate limits, private key, support — get in touch.

Get a production key

No rate limits. Private key. Direct support. Contact us and we'll have you set up within 24 hours.

hello@agenticrail.nz →

Official SDKs are live — drop-in clients for Python and JavaScript with LangGraph, CrewAI, and raw client support.

Python — pip
# Core client
pip install agenticrail

# With LangGraph support
pip install "agenticrail[langgraph]"

# With CrewAI support
pip install "agenticrail[crewai]"
Python — quick start
from agenticrail import RailClient

client = RailClient(api_key="DEMO-AGENTICRAIL-PUBLIC-2026")
seq = client.sequence("my-run-001", ["verify_identity", "assess_risk", "execute_transfer", "audit_ledger"])

seq.next("verify_identity")   # → ALLOW
seq.next("assess_risk")       # → ALLOW
seq.next("execute_transfer")  # → ALLOW
seq.next("audit_ledger")      # → ALLOW — seals sequence

# Optional: attach evidence per step — signed into the receipt
# seq.next("verify_identity", attestation={"kyc": "pass", "ref": "APR-001"})
JavaScript / TypeScript — npm
npm install @agenticrail/core
JavaScript — quick start
import { RailClient } from "@agenticrail/core";

const client = new RailClient({ apiKey: "DEMO-AGENTICRAIL-PUBLIC-2026" });
const seq = client.sequence("my-run-001", ["verify_identity", "assess_risk", "execute_transfer", "audit_ledger"]);

await seq.next("verify_identity");   // → ALLOW
await seq.next("assess_risk");       // → ALLOW
await seq.next("execute_transfer");  // → ALLOW
await seq.next("audit_ledger");      // → ALLOW — seals sequence

// Optional: attach evidence per step — signed into the receipt
// await seq.next("verify_identity", { attestation: { kyc: "pass", ref: "APR-001" } });

PyPI  ·  npm  ·  GitHub  ·  MIT