SDK architecture
Understand the public package, internal protocol core, runtime boundaries, gateway contract, and chain source of truth.
x402-paysdk is one versioned npm package with three deliberately separate entry points. The separation is a security boundary, not naming convenience.
x402-paysdk/payPayer runtimeWallet signer · offer verification · settlement
x402-paysdk/receiveReceiver runtimePaymentRef creation and lifecycle
x402-paysdk/merchantBackend onlyCredentials · orders · notify · reconciliation
Public package and internal modules
| Layer | Public? | Responsibility |
|---|---|---|
x402-paysdk/pay | Yes | Payer negotiation, wallet signing, settlement, receipt verification, recovery, tx queries |
x402-paysdk/receive | Yes | Receiver-side PaymentRef creation, inspection, listing, and revocation |
x402-paysdk/merchant | Yes | Backend merchant auth, refs, orders, refunds, notify, receipts, tx history, reconciliation |
| Shared protocol core | No direct subpath | URL parsing, x402 payloads, signed offers, validation, bounded HTTP readers |
| Gateway core | HTTP contract | Resolve refs, bind context, relay facilitator, issue receipts, query chain |
The repository keeps role-specific source workspaces so their dependency direction remains reviewable. The release build packages those compiled modules into one standalone npm artifact and rewrites internal references to local package paths.
Runtime boundaries
Payer runtime
The payer runtime can receive public payment context and a host-provided WalletSigner. It must never receive merchant API keys, notify keys, or backend order credentials.
Receiver runtime
The receiver runtime creates and manages PaymentRef records. It does not sign payer payments and does not decide merchant fulfillment.
Merchant backend
The merchant runtime holds server credentials and integrates with the merchant database. It verifies evidence and returns findings; application code owns the atomic transition from unpaid to fulfilled.
Dependency direction
Textpay ──────┐receive ──┼──> internal protocol core ──> gateway HTTP contract ──> chainmerchant ─┘
No TypeScript SDK depends on a Rust crate. The gateway does not import an SDK. They meet through versioned schemas, HTTP routes, signed envelopes, and receipt fields.
State ownership
| State | Owner | Why |
|---|---|---|
| Wallet keys | Wallet host | Signing authority never crosses into SDK or gateway |
| Ref metadata | Gateway RefStore | Resolve expiry, revocation, and payment context |
| Payment finality | Chain plus receipt archive | Default gateway has no payment-state table |
| Merchant order | Merchant database | Fulfillment policy is application-specific |
| Optional gateway order | Tenant-scoped OrderStore | Only when order mode is explicitly enabled |
| Notify nonce | Merchant shared store | Prevent replay across backend instances |
Extension rules
- Add shared protocol behavior to the internal core, then expose it through the role that owns the operation.
- Do not export merchant credentials or order mutation from
x402-paysdk/pay. - Do not add a direct transfer fallback to any entry point.
- New chain families require dedicated signing, replay, settlement, and finality analysis.
- A signed receipt authenticates gateway output; it does not replace chain confirmation.