Developer Quickstart

Verify a signed KAIOS receipt

The shortest path from an issuer-signed receipt payload to a verified KAIOS verdict: serialize the payload, sign those exact UTF-8 bytes with Ed25519, and POST the envelope to POST /api/kaios/verify. The machine-readable API reference is GET /api/kaios/verify. For every field and edge case, see the full verification contract.

Open the verification troubleshooting FAQ

Start with the signed envelope

Send exactly three envelope fields: signature, payload_string, and payload. The payload carries issuer, issued_at, and disclosed_fields; ciphertext_bundle is explicitly optional opaque data.

FieldTypeDescription
signature string (hex) Ed25519 signature over `payload_string`, decoded from hex. Exactly 128 hex chars (64 bytes); Node hex encoding produces lowercase characters.
payload_string string A non-empty string whose exact UTF-8 bytes are verified as supplied. It must contain valid JSON whose parsed value equals `payload`; invalid JSON or a mismatch returns 400.
payload object Structured form of the receipt. Required fields inside: non-empty `issuer` string, valid ISO-8601 `issued_at` timestamp, and object-valued `disclosed_fields` (not null or an array). It must equal the parsed JSON in `payload_string`; `ciphertext_bundle` is optional in the response but must also match when present.
envelope.json
{
  "signature": "a2a840955190e68e1801646322b7abfdd54fb70b30ac9e23a4d1d777331e3225b20abee94c6e6846718cfe4f846ee16b51e450ae6fc7f9189004fcb4de74da01",
  "payload_string": "{\"issuer\":\"kaios.automa8.ai\",\"issued_at\":\"2026-07-24T12:00:00Z\",\"disclosed_fields\":{\"task\":\"undercollateralized-lending\",\"loan_size_usd\":75000}}",
  "payload": {
    "issuer": "kaios.automa8.ai",
    "issued_at": "2026-07-24T12:00:00Z",
    "disclosed_fields": {
      "task": "undercollateralized-lending",
      "loan_size_usd": 75000
    }
  }
}
TEST ONLY: This public key and signature are an isolated example fixture. Configure KAIOS_ISSUER_PUBLIC_KEY with this key only in a local/test verifier; do not use it for production receipts. This fixture succeeds only when the verifier uses the matching TEST ONLY public key.

Serialize the payload, then sign

This example uses JSON.stringify(payload) as its payload_string. The verifier checks the exact supplied UTF-8 bytes and parses the JSON; the parsed value must equal the structured payload. The issuer may choose another serialization, including different whitespace or object key order.

Endpoint behavior: the verifier checks the signature over the exact supplied bytes and requires their parsed JSON value to equal payload. Invalid JSON or a mismatch returns 400; a successful verdict binds returned fields to the signed content.

The displayed fixture requires its matching TEST ONLY public key, which is public in discovery; its private key is not included. For your own receipts, load your issuer-provided Ed25519 private key and configure the verifier with its matching public key. The PEM file path below is an example input; key delivery and storage belong to the issuer.

node — sign-and-envelope.js
const crypto = require('node:crypto');
const fs = require('node:fs');

const payload = {
  "issuer": "kaios.automa8.ai",
  "issued_at": "2026-07-24T12:00:00Z",
  "disclosed_fields": {
    "task": "undercollateralized-lending",
    "loan_size_usd": 75000
  }
};
const payloadString = JSON.stringify(payload);
const privateKey = crypto.createPrivateKey(fs.readFileSync('issuer-private-key.pem'));
const signature = crypto.sign(
  null,
  Buffer.from(payloadString, 'utf8'),
  privateKey
).toString('hex'); // lowercase hexadecimal

const envelope = { signature, payload_string: payloadString, payload };
console.log(JSON.stringify(envelope, null, 2));

Run this example with node sign-and-envelope.js > envelope.json to save its JSON output for the verification request below.

The issuer’s private key must correspond to the verifier deployment’s configured KAIOS_ISSUER_PUBLIC_KEY. Keep the private key on the issuer side.

POST the envelope to a local verifier

The page and the GET discovery document require no external credentials. A successful 200 response requires the verifier to have the matching KAIOS_ISSUER_PUBLIC_KEY configured. This TEST ONLY fixture is for local/test use.

POST URL
https://automa-labs-ai.polsia.app/api/kaios/verify
Base
https://automa-labs-ai.polsia.app
Schema
kai-verify-1
Discovery
GET https://automa-labs-ai.polsia.app/api/kaios/verify
Content-Type
application/json
bash — curl
VERIFY_URL="${VERIFY_URL:-http://localhost:3000/api/kaios/verify}"
curl -X POST "$VERIFY_URL" \
  -H "Content-Type: application/json" \
  -d '{
  "signature": "a2a840955190e68e1801646322b7abfdd54fb70b30ac9e23a4d1d777331e3225b20abee94c6e6846718cfe4f846ee16b51e450ae6fc7f9189004fcb4de74da01",
  "payload_string": "{\"issuer\":\"kaios.automa8.ai\",\"issued_at\":\"2026-07-24T12:00:00Z\",\"disclosed_fields\":{\"task\":\"undercollateralized-lending\",\"loan_size_usd\":75000}}",
  "payload": {
    "issuer": "kaios.automa8.ai",
    "issued_at": "2026-07-24T12:00:00Z",
    "disclosed_fields": {
      "task": "undercollateralized-lending",
      "loan_size_usd": 75000
    }
  }
}'
node — verify-receipt.js
const envelope = require('./envelope.json');

async function verifyReceipt() {
  const verifyUrl = process.env.VERIFY_URL || 'http://localhost:3000/api/kaios/verify';
  const response = await fetch(verifyUrl, {
    method: 'POST',
    headers: { 'Content-Type': 'application/json' },
    body: JSON.stringify(envelope)
  });
  const result = await response.json();

  console.log('HTTP status:', response.status);
  console.log(JSON.stringify(result, null, 2));
}

verifyReceipt().catch((error) => {
  console.error(error);
  process.exitCode = 1;
});

The outer envelope has signature (a 128-character hex Ed25519 signature), payload_string (the exact UTF-8 bytes signed), and payload (the structured receipt with issuer, issued_at, and disclosed_fields). Optional ciphertext_bundle is included in the payload equality check but is not returned. A successful response includes ok, valid, issuer, issued_at, and disclosed_fields; non-2xx responses return the documented error JSON.

The displayed 128-character signature is a TEST ONLY fixture and verifies only with its matching public key on a local/test verifier. For production, use your own issuer key to sign your receipt's exact UTF-8 payload_string, then configure the verifier with the corresponding public key.

Use the disclosed result

On 200, the endpoint returns exactly the fields below. disclosed_fields is the signed structured disclosure; the verifier does not infer anything beyond it.

200 — response.json
{
  "ok": true,
  "valid": true,
  "issuer": "string",
  "issued_at": "ISO-8601 string",
  "disclosed_fields": "object"
}
StatusBodyWhen
200 {"ok":true,"valid":true,"issuer":"string","issued_at":"ISO-8601 string","disclosed_fields":"object"} Signature verified and parsed payload_string matches payload; returns the disclosed receipt fields.
400 {"ok":false,"errors":["string"]} Malformed or incomplete envelope, invalid JSON or a payload mismatch, or the configured public key could not be parsed.
401 {"ok":false,"error":"Invalid signature"} The signature does not match payload_string under KAIOS_ISSUER_PUBLIC_KEY.
503 {"ok":false,"error":"Verification disabled: KAIOS_ISSUER_PUBLIC_KEY not configured"} KAIOS_ISSUER_PUBLIC_KEY is not configured on the deployment.

Verification is an attestation, not an interpretation

Only disclosed_fields are returned in the successful verdict. ciphertext_bundle is accepted as opaque data and included in the payload equality check when present; the verifier does not decrypt it or persist it. A valid signature attests that the issuer signed the disclosed data; it is not an interpretation of the sealed bundle and is not, by itself, a trust or business decision.

If you are working with sealed or encrypted receipt data, read the FHE workflow to understand how ciphertext stays private during agent computation and how commitments connect back to verification.

The endpoint is stateless and publishes the same live contract at https://automa-labs-ai.polsia.app/api/kaios/verify. Use the full contract reference when you need the complete discovery document.