Skip to article
Browse documentation +
BUILD ON IT / ELPIS

Webhooks

Signed delivery of treasury and settlement events, with retries and SSRF protection.

How delivery works

  • Register an HTTPS endpoint in the console; it receives a JSON POST per event.
  • Every delivery is signed, so a receiver can refuse a forged one. The secret is shown once at creation.
  • Failures are retried with backoff, and each attempt is recorded as a delivery row.
  • Delivery is asynchronous — it never delays or changes a treasury decision.

Verifying a delivery

header
Elpis-Signature: t=<unix>,v1=<hmac-sha256(t + "." + body)>

Compute the HMAC over timestamp + "." + rawBody, compare in constant time, and reject a timestamp outside your tolerance window to prevent replay. The bundled SDK exports a verifier:

sdk
import { verifyWebhookSignature } from "@devilabs/elpis";

const ok = await verifyWebhookSignature({
  secret, header: req.headers["elpis-signature"], body: rawBody,
});
Use the raw body. Re-serialising JSON changes the bytes and breaks the signature. The Python SDK ships the same verifier as verify_webhook_signature(body, header, secret).

Events

EventFires when
PAYMENT_PROPOSEDAn intent is created.
POLICY_CHECKEDAll controls have produced facts.
PAYMENT_STAGEDEscrow opened; the window started.
PAYMENT_CANCELLEDRecalled inside the window; escrow refunded.
PAYMENT_EXECUTEDThe transaction was submitted.
PAYMENT_VERIFIEDThe chain confirms the transfer.
PAYMENT_FINALIZEDSettled and irreversible.
ACTION_BLOCKEDA blocking rule refused it.
ACTION_FROZEN / ACTION_UNFROZENA freeze was applied or lifted.
ACTION_ESCALATEDA person was asked to decide.
ACTION_FAILED / ACTION_ROLLED_BACKExecution failed, or was unwound.
APPROVAL_REQUESTED / GRANTED / REJECTEDApproval lifecycle.
RECIPIENT_CHANGEDA recipient wallet change was detected.
RECONCILIATION_INCIDENTA books/chain discrepancy was found.
COMPENSATION_CREATED / SETTLEDA compensating action was raised or paid.
SUPERVISOR_REVIEWA supervisor verdict was recorded.
JOB_COMMITTEDA settlement job committed its condition.
EVIDENCE_RECEIVEDEvidence was recorded against a job.
SETTLED_RELEASE / SETTLED_REFUNDA settlement decided — released, or refunded.
HELDA settlement held; no money moved.
DEADLINE_PASSEDA job's deadline passed unsettled and it was refunded.
DISPUTE_OPENEDA dispute was opened; settlement is frozen.
WITNESS_UNRESPONSIVEA witness has not responded.

SSRF protection

Endpoint registration is a server-side request primitive, so it is fenced:

  • Only https is allowed.
  • Private, loopback and link-local addresses are refused — including alternate encodings (integer, hex, octal, IPv4-mapped IPv6) that bypass naive string checks.
  • The resolved address is re-checked at delivery time, so DNS rebinding cannot turn a valid host into a private target after registration.