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.
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.
| Field | Type | Description |
|---|---|---|
| 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. |
{
"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
}
}
}
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.
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.
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.
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.
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
}
}
}'
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.
payload_string, then configure the verifier with the corresponding public key.
On 200, the endpoint returns exactly the fields below.
disclosed_fields is the signed structured disclosure; the verifier does not infer anything beyond it.
{
"ok": true,
"valid": true,
"issuer": "string",
"issued_at": "ISO-8601 string",
"disclosed_fields": "object"
}
| Status | Body | When |
|---|---|---|
| 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. |
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.