Merchant API — 1.0.0

The serviceNode-facing HTTP surface (R5): verify an allowance aimed at you, read remaining headroom and rate, read the finality state of a settlement, and manage webhook subscriptions. The OpenAPI document (openapi.json) is a versioned artifact at 1.0.0 — regenerated on every build, changed only under the versioning policy (R8).

Surface

EndpointWhat it answers
POST /v1/allowances/verify"Is this credential real, live, and aimed at ME?" — offline JWS check, fail closed
GET /v1/streams/{id}/verify"Is this stream open and payable to me?"
GET /v1/streams/{id}/headroomRemaining cap and network units, rate, degradation stage
GET /v1/streams/{id}/finalitySettled-frontier finality + billed truth (the last SIGNED voucher)
POST /v1/webhooks · GET /v1/webhooks · DELETE /v1/webhooks/{id}Subscribe / list / revoke event delivery
GET /openapi.jsonThe versioned contract itself

Credit on final only (R2)

checkpointed settlements are visible but pending; only settlement.final (webhook) or finality: "final" (poll) is a credit signal. Everything before that is information, not money.

Posture

nothing. Escrow needs a wallet holding the asset. Card needs one Stripe TEST/platform onboarding — payees are connected accounts. No mode requires the others' credentials.

the webhooks report is micro units of the funding asset — never integrator-defined units, which price work, not money.

Stripe TEST vs live and local anvil vs a public chain: same endpoints, same schemas, same finality semantics. Code written against the sandbox runs unchanged against production rails; only keys and RPC endpoints change.

Auth

Per-serviceNode bearer tokens, ownership-scoped: a caller can never see or affect another node's streams or subscriptions — unknown-or-not-yours answers 404, never 403, so existence is not leaked.

Example

curl -s -X POST http://localhost:8402/v1/allowances/verify \
  -H "Authorization: Bearer $SERVICE_NODE_TOKEN" \
  -H "content-type: application/json" \
  -d '{"credential": "<the JWS the caller presented>"}'

A valid, live, aimed-at-you credential returns its payload (stream, budget, cap, expiry); everything else returns a named refusal. The same check is available fully offline via the SDK and every gateway plugin — the HTTP form exists for stacks that prefer a service call over an embedded verifier, and it is never on the paid request path.