Docs
Open in panel → /app · credits
Credits
PostMTA Hosted uses prepaid credit holds to gate SMTP and HTTP API sends.
One credit covers one billable recipient (to + cc + bcc, deduplicated,
case-insensitive).
RPC contract
Three Postgres RPCs, defined in supabase/migrations/20260712000000_credits_foundation.sql and extended in 20260712000001_credit_commit_void_membership.sql:
| RPC | Purpose | Returns / errors |
|---|---|---|
credit_hold(workspace_id, amount, idempotency_key, source) |
Reserve amount credits |
INSUFFICIENT, DUPLICATE |
credit_commit(workspace_id, idempotency_key) |
Convert the hold into a debit | HOLD_NOT_FOUND |
credit_void(workspace_id, idempotency_key) |
Refund the hold (rejected recipient, upstream failure) | HOLD_NOT_FOUND |
credit_grant(workspace_id, amount, reason) |
Admin grant (panel Credits panel) | n/a |
Idempotency key uniqueness is enforced per workspace
(unique(workspace_id, idempotency_key) on credit_ledger). The same
idempotency key across hold → commit then a re-issued send returns 409 from
the API without double-charging.
Operational flow
POST /v1/send(or/v1/panel/send) validatesfromand recipient count.runSendin apps/api/src/app.ts callscredits.hold(workspaceId, amount, idempotencyKey, 'api').- On
INSUFFICIENT→ 402, onDUPLICATE→ 409. - After Kumo inject returns 2xx →
credits.commit. On non-2xx →credits.void.
Panel surface
Creditspanel section shows realtime wallet balance (Supabase Realtime onwallets).- Owners/admins can call
POST /v1/panel/credits/grant(matrix M11).
Related
- docs/build/domains.md — verified-From gate (PMH-SEC).
- docs/build/access.md — API key + SMTP credential pairs that consume credits on send.
- docs/build/suppressions.md — release B suppression list reuse for void paths.
Last verified: Sat Jul 11 2026 17:00:00 GMT-0700 (Pacific Daylight Time). Cross-link maintained byscripts/check-docs-drift.sh (M54).