HTTP API
Routes, authentication, errors, pagination and signed event delivery.
This manual targets 0.1.0-beta.3. Read the source and availability policy before installing. Historical reports retain their original scope.
Base URL: http://127.0.0.1:8787. The authenticated API belongs on the merchant’s private network. The OpenAPI document is generated from shared schemas; retrieve the running version at GET /v1/openapi.json with Bearer auth.
Create a payment request
POST /v1/intents requires Authorization: Bearer TOKEN, Content-Type: application/json and Idempotency-Key (8–128 letters, digits, dots, underscores, colons or hyphens).
| Field | Type | Meaning |
|---|---|---|
| externalReference | string, 1–512 non-blank characters | Local order/invoice reference; not exposed in the public request |
| amountAtomic | positive integer string | Expected amount in token atomic units |
| expiresAt | future integer Unix seconds | Persist once and reuse on retries |
Build the body with a current expiry:
const body = {
externalReference: "ORDER-9281",
amountAtomic: "25000000",
expiresAt: Math.floor(Date.now() / 1000) + 7200,
};
Save body before sending. A successful new request is HTTP 201; an exact key/body replay is 200; a changed body with the same key is 409.
The response is the intent object directly, with id, externalReference, chainId, tokenAddress, tokenSymbol, decimals, expectedAmountAtomic, receivedAmountAtomic, pendingAmountAtomic, overpaymentAmountAtomic, status, expiresAt, createdAt, revision, checkoutPath and payment. payment contains rail, recipient, memo and the signed descriptor. See OpenAPI’s Intent schema for exact types.
Routes
| Method | Path | Authentication / purpose |
|---|---|---|
| GET | /v1/live | Public process liveness |
| GET | /v1/ready | Public readiness; 503 until a recent complete scan |
| GET | /v1/health | Public redacted scan state |
| GET | /pay/:id | Public checkout |
| GET | /pay/:id/request.json | Public signed, metadata-minimal payer request |
| GET | /payer-guide | Public payer requirements |
| GET | /assets/pay.css, /assets/pay.js | Public checkout assets |
| POST | /v1/intents | Bearer; create/replay |
| GET | /v1/intents | Bearer; list |
| GET | /v1/intents/:id | Bearer; full intent |
| GET | /v1/intents/:id/status | Bearer; amounts, state, expiry and revision |
| GET | /v1/runtime | Bearer; redacted instance/profile identity |
| GET | /v1/settlements | Bearer; settlement facts |
| GET | /v1/events | Bearer; event history |
| GET | /v1/outbox | Bearer; attempts, delivery/dead-letter time and failure code |
| POST | /v1/outbox/:eventId/replay | Bearer; schedule a dead-lettered event only |
| POST | /v1/descriptors/verify | Bearer; verify against the daemon’s merchant signer |
| GET | /v1/metrics | Bearer; Prometheus text |
| GET | /v1/openapi.json | Bearer; machine-readable reference |
Demo and example-shop routes do not exist on the real daemon.
Public PayIn request (beta.3)
The request endpoint includes paymentStage and overpaymentAmountAtomic as additive presentation fields. paymentStage is AWAITING_PAYMENT, PAYMENT_DETECTED, PRIVACY_CHECKS_PENDING, PAYMENT_COMPLETE or PAYMENT_REVERTED. Intent statuses and merchant event names are unchanged. These mutable fields are not signed settlement proofs; the descriptor signs payment terms. See Payment Request v1 for signature/transport rules and PayIn for the checkout presentation.
Pagination
List routes return { items, limit, offset }. Default limit is 100, maximum 250; offset starts at zero. Continue with offset + items.length until a short page. There is no total count, status filter, intent filter or snapshot cursor.
Intents sort newest creation first, settlements newest observation first; events and outbox sort oldest event first. Concurrent inserts can shift offset pages. Deduplicate by stable ID during exports and do not treat a traversal as a transactional snapshot.
Errors
Errors use { error: { code, hint?, field?, issues? } }. Code is stable; clients must tolerate added diagnostic fields. Request values, provider URLs and secrets are not echoed.
Common outcomes: 400 invalid body/key/expiry, 401 unauthorized, 404 not found, 409 idempotency conflict or ineligible replay, 413 oversized body, 415 wrong content type, 429 rate limited (Retry-After header), 500 internal failure.
After a failed or timed-out create, preserve the original key and body. The body limit is 64 KiB. Limit requests and avoid logging authenticated payloads.
Events and signatures
Every event includes schemaVersion: 1, eventId, type, occurredAt, intentId, intentStatus, receivedAmountAtomic, expectedAmountAtomic and overpaymentAmountAtomic. settlementId is optional.
Headers: PPOps-Event-Id, PPOps-Timestamp, PPOps-Key-Id, PPOps-Signature.
Signature value: v1= followed by lowercase HMAC-SHA256 hex. The signed bytes are timestamp.keyId.eventId.rawBody. Decode the configured HMAC key from hex. Verify freshness, known key ID, exact bytes, event schema and matching header/body identity; then deduplicate durably. Delivery is at least once.
See merchant integration for executable verification and payment states for event semantics.
Versioning
HTTP paths and event schemas remain v1. New response fields may be added; consumers should tolerate them. Required-input or semantic changes need release notes and an explicit compatibility decision. Public beta.1 evidence does not automatically cover later code changes.