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.
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.
POST to /evaluate with your agent's current step, a unique nonce, and a timestamp. Auth via the x-slp8-key header.
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.
On pass: a cryptographic receipt with decision ALLOW. On failure: a DENY with a reason code. Your agent only proceeds on ALLOW.
One header. Every request.
All requests require the x-slp8-key header. The demo key is public and rate-limited — use it to test without signing up.
Add to every request: x-slp8-key: DEMO-AGENTICRAIL-PUBLIC-2026
For production use, contact hello@agenticrail.nz for a private key with no rate limits.
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 | Canonical step name — must match function. Sequence: intake → disruption → instability → state_read → internal_driver → execution → boundary → settle. Must run in order. No skipping. |
| function | string | Canonical function name — must equal step. e.g. "intake", "execution". 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". |
| nonce | string | Unique hex string per request. Used for replay protection — never reuse. |
| action | string | Descriptive action label for this step. e.g. "run intake", "run execution". |
| ts_ms | number | Unix timestamp in milliseconds. Required — use Date.now() or equivalent. |
| inputs | object | Optional. Any context you want to log alongside the step. |
Copy. Paste. Run.
This example works against the live gate right now. Replace ts_ms with the current Unix timestamp in milliseconds before running.
# Get current timestamp: date +%s%3N curl -X POST https://agenticrail.nz/evaluate \\ -H 'Content-Type: application/json' \\ -H 'x-slp8-key: DEMO-AGENTICRAIL-PUBLIC-2026' \\ -d '{ "schema_version": "1.0", "model_id": "my-agent", "sequence_id": "my-seq-001", "step": "intake", "function": "intake", "action_type": "CHECK_STATE", "action": "run intake", "nonce": "a1b2c3d4e5f6", "ts_ms": 1741654800000, "inputs": {} }'
# Paste all four lines at once into PowerShell $ts = [DateTimeOffset]::UtcNow.ToUnixTimeMilliseconds() $body = '{"schema_version":"1.0","model_id":"my-agent","sequence_id":"my-seq-001","step":"intake","function":"intake","action_type":"CHECK_STATE","action":"run intake","nonce":"a1b2c3d4e5f6","ts_ms":' + $ts + ',"inputs":{}}' $headers = @{ "Content-Type" = "application/json"; "x-slp8-key" = "DEMO-AGENTICRAIL-PUBLIC-2026" } (Invoke-WebRequest -UseBasicParsing -Uri https://agenticrail.nz/evaluate -Method POST -Headers $headers -Body $body).Content
ts_ms is a required field — pass the current Unix timestamp in milliseconds. On Mac/Linux: date +%s%3N. On Windows: [DateTimeOffset]::UtcNow.ToUnixTimeMilliseconds() as shown above.
// One gate call — adapt into your agent loop const res = await fetch('https://agenticrail.nz/evaluate', { method: 'POST', headers: { 'Content-Type': 'application/json', 'x-slp8-key': 'DEMO-AGENTICRAIL-PUBLIC-2026', }, body: JSON.stringify({ schema_version: '1.0', model_id: 'my-agent', sequence_id: 'my-seq-001', step: 'intake', function: 'intake', action_type: 'CHECK_STATE', action: 'run intake', nonce: crypto.randomUUID().replace(/-/g, '').slice(0, 16), ts_ms: Date.now(), inputs: {}, }), }); const gate = await res.json(); if (gate.pack?.decision === 'ALLOW') { // Proceed with your step } else { // Halt — do not proceed console.error('DENY:', gate.pack?.reasons); }
ALLOW or DENY. Nothing in between.
Every response has a top-level status of "OK" or "HALT", and a pack object with the decision details.
{ "status": "OK", "pack": { "decision": "ALLOW", "reasons": [], "executed": true, "meta": { "step": "intake", "function": "intake", "action_type": "CHECK_STATE" } }, "pack_id": "a7f3c2d4...e91b" }
{ "status": "OK", "pack": { "decision": "DENY", "reasons": ["SEQUENCE_VIOLATION"], "executed": false }, "pack_id": "c9f2d1a3...f82e" }
instability before disruption.sequence_id.action_type is not in the allowed set for this function/step.function value is not a recognised step name.function and step fields do not match.missing_function, missing_action_type, missing_nonce.x-slp8-key header.The rules the gate enforces.
These aren't soft guidelines. A violation on any one of them returns DENY immediately.
intake → disruption → instability → state_read → internal_driver → execution → boundary → settle. No skipping. An out-of-order step returns SEQUENCE_VIOLATION.REPLAY_NONCE.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.settle is accepted, the sequence locks. Any further request on that sequence_id returns SEALED_SEQUENCE. Start a new sequence with a fresh ID.METHOD_NOT_ALLOWED immediately.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.
SDK integrations and language-specific wrappers are in progress. Watch the GitHub repo or subscribe to the blog for updates.