Skip to article
Browse documentation +
TRUST / ELPIS

Settlement registry

Portable, EIP-712-signed receipts for settled jobs — verifiable by anyone, and recomputable into a subject's reputation.

Why a public receipt

A settlement only the two parties can check is a log line. A signed receipt is evidence anyone can verify.

Every released or refunded job writes a canonical record and signs it. The record carries the decision, the subject, the commitment hash, a receipt hash and the signer — enough to prove what was decided, without publishing the deal. The organization, the raw evidence and the reasons stay private.

Aggregated by subject, those receipts become a reputation. Every score is a pure function of the published records, so a marketplace can recompute it rather than trust a number.

The record

GET /api/v1/registry/{id}
{
  "id": "att_…",
  "reference": "job_…",
  "subject": "agent-or-0x-address",
  "decision": "release",
  "commitmentHash": "0x…",
  "decisionAttestation": "0x…",
  "evidenceHash": "0x…",
  "amount": "50000000",
  "token": "",
  "protocol": "elpis/1/elpis-canon/1",
  "createdAt": "2026-10-20T12:00:00.000Z"
}
  • reference is the job id, or jobId:claimId for a milestone claim.
  • commitmentHash is the condition committed before the work; decisionAttestation is the reproducible decision hash.
  • evidenceHash binds the evidence the decision read without publishing it.
  • amount is the settled slice for a claim; a whole-job settlement has no amount in the primitive, so it is empty.

Canonical bytes and signature

The hash is SHA-256 over deterministic JSON: object keys sorted recursively, arrays in order, no whitespace, undefined omitted. The signature is EIP-712 over Settlement with domain { name: "Elpis", version: "1" } — no chain id, because a receipt is about a decision, not about where a transaction happened.

Signed fieldMeaning
idthe receipt id
referencejob id, or jobId:claimId
subjectwho delivered — the reputation subject
decisionrelease or refund
commitmentHashwhat “done” meant
decisionAttestationthe reproducible decision hash
evidenceHasha hash of the evidence read
amount / tokenthe settled slice, when known
protocol / createdAtversion and time

The full canonical string is served with the receipt, so you can hash the exact bytes. The signer address and typed-data shape are at GET /api/v1/registry/signer.

Verify without trusting us

TypeScript (viem)
const receipt = await fetch(
  `https://elpis.devilabs.dev/api/v1/registry/${id}`
).then((r) => r.json());

const { signer, canonical, signature, hash, ...record } = receipt.data;

const valid = await verifyTypedData({
  address: signer,
  domain: { name: "Elpis", version: "1" },
  types: { Settlement: [/* see /api/v1/registry/signer */] },
  primaryType: "Settlement",
  message: record,
  signature,
});
GET /api/v1/registry/{id}/verify does the same check for you, but it is a convenience. The signature is the authority.

Endpoints

Method · PathWhat it does
GET /api/v1/registryRecent public receipts. Filters: limit, before, subject, decision.
GET /api/v1/registry/{id}One receipt, canonical bytes and signature.
GET /api/v1/registry/{id}/verifyRecompute the hash and recover the signer.
GET /api/v1/registry/subjects/{subject}The subject's reputation, from its receipts.
GET /api/v1/registry/signerThe signer and the exact EIP-712 shape.

Privacy and control

  • Public by default: decision, subject, hashes, signature and timestamp. No organization, raw evidence or reasons.
  • REGISTRY_VISIBILITY=private stops public reads; recording continues for the deployment's own audit.
  • REGISTRY_ENABLED=false stops writing receipts. Settlements are unaffected.
  • The signing key is ATTESTATION_SIGNING_KEY. It cannot move money; it only signs decisions. Rotating it is safe — each receipt carries its own signer.