Architecture
OID4Pay decomposes into five independently deployable services plus a family of merchant SDKs. Each service has a single role on the wire and a single set of stored secrets; the service boundaries match the trust boundaries.
Topology
+------------------------+ +------------------------+
| Agent / MCP server | | Wallet Portal |
| (Node, Python, Go) | | wallet.oid4pay.com |
| holds DPoP keys | | (SvelteKit + Bun) |
| | | OIDC RP to AS |
+-----------+------------+ +-----------+------------+
| |
| | OIDC login + consent
| |
| +--------------------v---------------------+
| | Authorization Server |
+--------->| as.oid4pay.com (FastAPI + joserfc) |
| PAR | issues JWT-AT, SD-JWT VC mandate |
| token | runs /oauth/{par,token,revoke,introspect,|
| | register,jwks.json,status-list} |
| | dedicated Postgres + Redis |
| +--------+--------+----------+-------------+
| | | |
| | | | SSF events
| | | v
| | | +----------------+
| | | | Billing engine |
| | | | (FastAPI, in- |
| | | | house ledger) |
| | | +-------+--------+
| | | |
| | | | monthly invoice
| | | v
| | | +----------------+
| | | | Stripe Connect |
| | | | settlement |
| | | +----------------+
| | |
v | v
+--------------------------+ | +----------------------+
| Merchant SDK | | | Discovery directory |
| (@oid4pay/oid4ac-merchant) | | discover.oid4pay.com |
| verify-offer, verify- | | | (Go + chi + pgx) |
| mandate, charge proxy | | | merchant identities, |
+-----------+--------------+ | | JWKS, catalog URLs |
| | +-----------+----------+
v | |
+---------------------+ | |
| Merchant storefront | | |
| /.well-known/ |<--------+----------------+
| oid4ac-catalog |
| /.well-known/jwks |
+---------------------+
Services
| Service | Host | Role on the wire |
|---|---|---|
| Authorization Server | as.oid4pay.com | Issues JWT-AT and SD-JWT VC mandates, validates DPoP, enforces algorithm whitelist, runs the audit chain. |
| Wallet Portal | wallet.oid4pay.com | Principal's control plane: agents, mandates, approvals, audit, disputes, policy. OIDC RP to the AS. |
| Discovery Directory | discover.oid4pay.com | Merchant identities only: JWKS, catalog URL, category tags. No SKU aggregation. |
| Billing Engine | as.oid4pay.com/billing | SSF-driven double-entry ledger; per-merchant per-rail tiered fees; monthly invoices. |
| Merchant SDKs | npm, PyPI, Go modules, CDN | Verify Offer + mandate + KB-JWT; proxy charge to the AS; identical wire shape across languages. |
| MCP server | npm @oid4pay/oid4pay-mcp | Model Context Protocol tools: agent_payment_initiate, agent_verify_mandate, discovery_list_merchants. |
Trust boundaries
- Agent vs AS: the agent never holds the principal's
credentials. The AS treats the agent as an RFC 7591 confidential client
with
private_key_jwtauthentication and a DPoP key separate from the client-assertion key. - AS vs merchant: the merchant verifies the JWT-AT and mandate against the AS JWKS. The AS does not see the merchant's secrets. The merchant settles through their own Stripe Connect account.
- Wallet vs AS: OIDC RP relationship. The wallet does not see the agent's DPoP keys; the agent does not see the principal's wallet session.
- Discovery vs AS: discovery stores merchant identity only. The directory does not see mandates, JWT-ATs, or charges.
- Billing vs AS: billing consumes the SSF event stream read-only. The billing engine cannot mint tokens or mandates.
Data ownership
| Data | Owner | Where it lives |
|---|---|---|
| Principal account | Wallet Portal | Wallet Postgres |
| Agent registration | AS | AS Postgres oid4pay_client |
| Mandate | AS issues; wallet stores | AS Postgres + wallet session cache |
| Offer + catalog | Merchant | Merchant storefront origin only |
| Charge ledger | Merchant Stripe Connect account | Stripe; mirrored to billing engine ledger |
| Audit chain | OID4Pay (per tenant) | AS Postgres oid4pay_audit_chain + S3 Object Lock |
Deployment shape
The production fleet runs on five Contabo VPSes joined by a WireGuard mesh, with Cloudflare in front for TLS termination and DNS. Postgres 16 is primary-only today; the standby is for observability only. See operations for the operator runbook and the deploy and disaster-recovery procedures.