Documentation
Receipts & webhooks
What a settled payment hands back, and how to receive events when value moves.
Every settled payment produces a signed, on-chain receipt. Webhooks push those events to your backend so you can react the moment value moves. Payloads below are conceptual shapes with placeholder values.
The receipt object
A receipt is the canonical record of a payment. It links the amount and recipient back to the policy that authorized it, which is what makes spend auditable.
| Param | Type | Description |
|---|---|---|
| id | string | Stable receipt id, e.g. "rcpt_8fK2c9Qd". |
| agent | address | The paying agent's wallet address. |
| to | string | Destination service:// or agent:// address. |
| amount | string | Settled amount, in the receipt's currency. |
| currency | string | Settlement asset, e.g. "USDC". |
| policyId | string | The policy that authorized this payment. |
| settled | boolean | True once value has settled on-chain. |
| tx | string | On-chain transaction hash. |
| signature | string | Signature over the receipt contents. |
{
"id": "rcpt_8fK2c9Qd",
"agent": "0xAgent7d2…",
"to": "service://api.search",
"amount": "0.02",
"currency": "USDC",
"network": "solana",
"policyId": "pol_2u9X…",
"settled": true,
"tx": "0x9b1f…c20a",
"signature": "0xsig…",
"createdAt": "2025-01-01T00:00:00Z"
}Event types
Railo emits a small set of events over the lifecycle of a payment:
payment.settled- a payment passed the gate and settled successfully.payment.rejected- a payment was denied at the policy gate (with the failing rule).policy.updated- an agent's policy was changed by its owner.
Webhook payload shape
Each event is delivered as a JSON envelope with a type, an event id, and a data object carrying the relevant record.
{
"type": "payment.settled",
"id": "evt_3aZ…",
"data": {
"receiptId": "rcpt_8fK2c9Qd",
"agent": "0xAgent7d2…",
"to": "service://api.search",
"amount": "0.02",
"currency": "USDC",
"tx": "0x9b1f…c20a"
},
"createdAt": "2025-01-01T00:00:00Z"
}Verifying webhooks
Every delivery is signed. Verify the railo-signature header against your endpoint secret before trusting an event - this prevents spoofed deliveries.
import { Railo } from "@railo/sdk";
// Verify the signature before trusting an event.
export function handler(req: Request, body: string) {
const ok = Railo.webhooks.verify({
payload: body,
signature: req.headers.get("railo-signature") ?? "",
secret: process.env.RAILO_WEBHOOK_SECRET!,
});
if (!ok) return new Response("bad signature", { status: 400 });
// …handle event
return new Response("ok");
}