---
name: outcome-verified-settlement-verifier
description: Releases streaming payment only for delivered units that provably match a hash committed up front (identity + integrity + delivery), and returns a signed, offline-verifiable receipt. Use when one agent must pay another for delivered work, data, or artifacts and wants to pay only for items that exactly match what was agreed.
version: "1.0"
author: ChainAIM
github: chainaim-nisha
metadata:
openclaw:
requires:
bins: [curl]
---
# Outcome-Verified Settlement Verifier
**Pay for delivery — but only for work that provably matches what was agreed, and refuse to pay for anything that doesn't.**
An agent releases money one unit at a time as each delivered item is verified against a hash committed up front. A matching item is paid; a missing, corrupted, or swapped item is refused and the stream closes with the rest of the budget unspent. It checks **identity + integrity + delivery only** — all business judgement (grade, quantity, date, schema) is decided upstream and frozen into the committed hash before it ever reaches this service.
**Use this when** one agent owes another for delivered work, data, or artifacts and wants a guarantee it pays *only* for items that exactly match what was committed — plus a signed, independently re-checkable receipt of who was paid and why. Pairs naturally with a negotiation/certifier agent upstream (which decides the terms and produces the committed hashes) and an escrow or marketplace agent downstream (which acts on the signed verdict).
**Verified end-to-end:** given only this file's URL, a stock OpenClaw agent fetched the document, made the single `GET /demo/settlement` call, and printed the settlement transcript — no human steps.
**Tags:** settlement · payments · streaming · verification · trust · integrity · ed25519 · receipts · agents
## Base URL
https://chainaim-outcome-verified-settlement-ext-production.up.railway.app
## Quick start — one call, no setup
No keys, no input, no human step:
```
curl "https://chainaim-outcome-verified-settlement-ext-production.up.railway.app/demo/settlement"
```
The `display` field comes back as a plain-English transcript anyone can read:
```
Settlement complete: deal 174b5d7a…
Rule: pay 100 per delivered item, only if it exactly matches what was promised.
Item 0: PAID - genuine, matched what was promised.
Item 1: PAID - genuine, matched what was promised.
Total paid: 200 | Budget unspent: 300 | Status: FINISHED
```
Add `?case=bad` to see the failure path — one item is a *different* artifact carrying an honest checksum, so it passes the integrity check but fails the identity check; payment stops and the remainder stays unspent:
```
Item 0: PAID - genuine, matched what was promised.
Item 1: NOT PAID - did not match what was promised; payment stopped here.
Total paid: 100 | Budget unspent: 400 | Status: FINISHED
```
## How the agent should use this
1. Call `GET /demo/settlement` (add `?case=bad` for the failure path).
2. Print the `display` field **verbatim** — it is already a complete, plain-English transcript of the whole settlement (which items were paid, which were refused and why, the totals, and the final status). Do not summarise or reformat it.
To settle a real deal instead of the demo: `POST /settle/open` (commit the expected hashes) → `POST /settle/advance` once per delivered unit → `POST /settle/close`. Exact request/response shapes are below.
## Judge test (runnable from this file alone, no setup)
Any agent or human can validate this skill with two calls:
1. `GET /demo/settlement` — the good path. Expect both items `"verdict":"pass"`, `settled_total` **200**, and a `display` ending `Total paid: 200 | Budget unspent: 300 | Status: FINISHED`.
2. `GET /demo/settlement?case=bad` — the failure path. Expect item 1 `"verdict":"fail"` with `"reason":"artifact-mismatch"`, `remainder_unspent` **400**, and a `display` line reading `Item 1: NOT PAID - ...; payment stopped here.`
Passing both proves the core property in under ten seconds: it pays for what matches and refuses what doesn't.
## Endpoints
The demo and the settle endpoints all return the **same object** (`SettleOut`):
| field | meaning |
|---|---|
| `per_unit` | each unit's `{seq, verdict: pass\|fail, reason}` (machine-readable tokens) |
| `settled_total` | total released so far (= rate × units paid) |
| `remainder_unspent` | budget never spent (`max_total − settled_total`) |
| `trace` | a replayable log the total can be reconstructed from |
| `verdict_signature` | Ed25519 signature over the receipt (set in the `signed` tier; `null` in `hash-only`) |
| `display` | the printable, plain-English transcript |
### `GET /health` — liveness
```
curl "/health"
→ {"status":"ok","service":"settlement-verifier"}
```
### `GET /skill.md` — this document (served as markdown)
### `GET /pubkey` — the verifier's Ed25519 verdict-signing public key
```
curl "/pubkey"
→ {"pubkey":"ed2412b5…","algo":"ed25519"}
```
### `GET /demo/settlement?case=good|bad` — self-contained match-vs-mismatch demo
```
curl "/demo/settlement?case=bad"
→ { "per_unit":[ {"seq":0,"verdict":"pass","reason":"artifact-match"},
{"seq":1,"verdict":"fail","reason":"artifact-mismatch"} ],
"settled_total":100, "remainder_unspent":400,
"trace":[ "stream-open:…", "ack:…", "gate:…:pass", "tick:…", "gate:…:fail", "stream-close:…:artifact-mismatch" ],
"verdict_signature":null,
"display":"Settlement complete: deal 174b5d7a…\nRule: pay 100 per delivered item, only if it exactly matches what was promised.\n Item 0: PAID - genuine, matched what was promised.\n Item 1: NOT PAID - did not match what was promised; payment stopped here.\nTotal paid: 100 | Budget unspent: 400 | Status: FINISHED" }
```
### `POST /settle/open` — open a metered stream
Commit up front the sha256 of each unit you expect. `expected` maps `"" → `; `task_id` must equal `ref`.
```
curl -X POST "/settle/open" -H "Content-Type: application/json" -d '{
"ref": "",
"rate": 100, // released per verified unit
"max_total": 500, // spending cap; the rest stays unspent
"attestor": "hash-only", // "hash-only" (default) or "signed"
"committed_reference": {
"criterion": "artifact_match", // artifact_match | checksum | ack_received
"task_id": "", // must equal ref
"expected": { "0": "", "1": "" }
}
}'
→ SettleOut (stream opened; nothing settled yet)
```
### `POST /settle/advance` — submit one delivered unit
`payload_hex` = hex of the delivered chunk's raw bytes; `declared_checksum` = its sha256. A passing unit releases `rate`; a failing unit closes the stream so the remainder is never spent.
```
curl -X POST "/settle/advance" -H "Content-Type: application/json" -d '{
"ref": "",
"unit": { "seq": 0, "payload_hex": "", "declared_checksum": "" }
// "attestation": {"signer_pubkey":"…","sig":"…"} // required only when attestor="signed"
}'
→ SettleOut (this unit's verdict + running totals)
```
### `POST /settle/close` — finalize the stream
```
curl -X POST "/settle/close" -H "Content-Type: application/json" -d '{ "ref": "" }'
→ SettleOut (totals frozen; verdict_signature set in the signed tier)
```
### `POST /verify` — re-check a returned verdict offline
Verifies the verifier's own Ed25519 signature over `{receipt, trace}` against the key at `/pubkey`. In `hash-only` there is no signature, so this returns `{"valid":false,"reason":"no-signature"}`; use the `signed` tier to get a verifiable `verdict_signature`.
```
curl -X POST "/verify" -H "Content-Type: application/json" -d '{ "receipt": {…}, "trace": [ … ], "verdict_signature": "" }'
→ {"valid":true,"reason":"signature-valid"}
```
## How it works — the gate ladder (per delivered unit)
The plain-English `display` is a view of these machine-checked verdicts; the exact tokens (`artifact-match`, `artifact-mismatch`, …) stay in `per_unit[].reason` and in the `trace` for programmatic checking.
1. **L1 ack** — the unit arrived.
2. **L2 checksum** — `sha256(chunk)` equals the seller's declared checksum (constant-time compare; a null checksum never settles).
3. **L3 artifact_match** — `sha256(chunk)` equals the committed hash for that `seq`, **and** the deal `ref` is embedded in the payload.
`criterion` chooses how far the ladder runs: `artifact_match` = L1+L2+L3, `checksum` = L1+L2, `ack_received` = L1 only. L2 short-circuits L3, so a unit with an honest checksum for the **wrong** bytes still fails identity — the exact case a checksum alone cannot catch, and the reason `?case=bad` fails.
## Attestor tiers (the `attestor` flag)
- **`hash-only`** (default) — no fulfillment signature; identity and integrity come from the hash alone. Best for self-verifying deliverables the buyer can re-hash.
- **`signed`** — the delivery carries an Ed25519 attestation from a **non-payee** key; the verifier checks that signature against its trusted-key allow-list **before** releasing, and returns a `verdict_signature` over `{receipt, trace}` that anyone can re-check via `/verify`. This is signature *verification* against a published key — not key matching.
- **`zkpret` / `vlei`** — the same seam with a stronger proof. Out of scope here — contact ChainAIM.
## The guarantee
`billed ≤ rate × verified_units`, and the billed amount is reconstructable from the emitted `trace`, not from any hidden internal balance. Nothing that isn't delivered, intact, and identical to what was committed is ever paid — and in the `signed` tier every verdict ships with an offline-verifiable receipt.