@cedros/pay-react 0.1.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (190) hide show
  1. package/LICENSE +21 -0
  2. package/README.md +1731 -0
  3. package/dist/CedrosContext-B3iCqN6e.js +11 -0
  4. package/dist/CedrosContext-vX9uqZKp.mjs +1796 -0
  5. package/dist/ar-LVoQZTFI.js +1 -0
  6. package/dist/ar-w27mU-4x.mjs +19 -0
  7. package/dist/bn-BR5Cv1T4.js +1 -0
  8. package/dist/bn-Ba_k3Kex.mjs +19 -0
  9. package/dist/components/CedrosPay.d.ts +54 -0
  10. package/dist/components/CedrosPay.d.ts.map +1 -0
  11. package/dist/components/CryptoButton.d.ts +26 -0
  12. package/dist/components/CryptoButton.d.ts.map +1 -0
  13. package/dist/components/PaymentModal.d.ts +28 -0
  14. package/dist/components/PaymentModal.d.ts.map +1 -0
  15. package/dist/components/ProductPrice.d.ts +56 -0
  16. package/dist/components/ProductPrice.d.ts.map +1 -0
  17. package/dist/components/PurchaseButton.d.ts +52 -0
  18. package/dist/components/PurchaseButton.d.ts.map +1 -0
  19. package/dist/components/StripeButton.d.ts +27 -0
  20. package/dist/components/StripeButton.d.ts.map +1 -0
  21. package/dist/context/CedrosContext.d.ts +46 -0
  22. package/dist/context/CedrosContext.d.ts.map +1 -0
  23. package/dist/context/ThemeContext.d.ts +30 -0
  24. package/dist/context/ThemeContext.d.ts.map +1 -0
  25. package/dist/context/index.d.ts +3 -0
  26. package/dist/context/index.d.ts.map +1 -0
  27. package/dist/crypto-only.d.ts +33 -0
  28. package/dist/crypto-only.d.ts.map +1 -0
  29. package/dist/crypto-only.js +1 -0
  30. package/dist/crypto-only.mjs +35 -0
  31. package/dist/de-CoZiPFN7.mjs +19 -0
  32. package/dist/de-pQxy-oD1.js +1 -0
  33. package/dist/en-CSsJl3nf.mjs +19 -0
  34. package/dist/en-D-uY3ltT.js +1 -0
  35. package/dist/es-BWGIBp2f.mjs +19 -0
  36. package/dist/es-D24cg8dD.js +1 -0
  37. package/dist/fil-BOBft9G-.js +1 -0
  38. package/dist/fil-Czo27xmj.mjs +19 -0
  39. package/dist/fr-Ct9ub8Fa.js +1 -0
  40. package/dist/fr-DQ-2ThBv.mjs +19 -0
  41. package/dist/he-DpV1WnBQ.mjs +19 -0
  42. package/dist/he-DtQqRKRq.js +1 -0
  43. package/dist/hooks/usePaymentMode.d.ts +39 -0
  44. package/dist/hooks/usePaymentMode.d.ts.map +1 -0
  45. package/dist/hooks/useRefundVerification.d.ts +30 -0
  46. package/dist/hooks/useRefundVerification.d.ts.map +1 -0
  47. package/dist/hooks/useStripeCheckout.d.ts +20 -0
  48. package/dist/hooks/useStripeCheckout.d.ts.map +1 -0
  49. package/dist/hooks/useX402Payment.d.ts +24 -0
  50. package/dist/hooks/useX402Payment.d.ts.map +1 -0
  51. package/dist/i18n/index.d.ts +107 -0
  52. package/dist/i18n/index.d.ts.map +1 -0
  53. package/dist/i18n/useTranslation.d.ts +55 -0
  54. package/dist/i18n/useTranslation.d.ts.map +1 -0
  55. package/dist/id-BJMqsu19.mjs +19 -0
  56. package/dist/id-CiM2mL7C.js +1 -0
  57. package/dist/in-BxgxKLQH.mjs +19 -0
  58. package/dist/in-Bzcjmxcc.js +1 -0
  59. package/dist/index.d.ts +33 -0
  60. package/dist/index.d.ts.map +1 -0
  61. package/dist/index.js +1 -0
  62. package/dist/index.mjs +626 -0
  63. package/dist/it-Blb_pIJl.js +1 -0
  64. package/dist/it-DZFFPALf.mjs +19 -0
  65. package/dist/jp-9NHyIuwY.js +1 -0
  66. package/dist/jp-ZExTrlHK.mjs +19 -0
  67. package/dist/kr-DHX3i4Ht.mjs +19 -0
  68. package/dist/kr-DvzJ-0yX.js +1 -0
  69. package/dist/managers/ManagerCache.d.ts +49 -0
  70. package/dist/managers/ManagerCache.d.ts.map +1 -0
  71. package/dist/managers/RouteDiscoveryManager.d.ts +72 -0
  72. package/dist/managers/RouteDiscoveryManager.d.ts.map +1 -0
  73. package/dist/managers/StripeManager.d.ts +110 -0
  74. package/dist/managers/StripeManager.d.ts.map +1 -0
  75. package/dist/managers/WalletManager.d.ts +150 -0
  76. package/dist/managers/WalletManager.d.ts.map +1 -0
  77. package/dist/managers/X402Manager.d.ts +176 -0
  78. package/dist/managers/X402Manager.d.ts.map +1 -0
  79. package/dist/ms-BOAu5pUB.js +1 -0
  80. package/dist/ms-Cv1fdIi2.mjs +19 -0
  81. package/dist/nl-BmGonsKb.mjs +19 -0
  82. package/dist/nl-WHh_DfO8.js +1 -0
  83. package/dist/pa-B7kIhZCF.js +1 -0
  84. package/dist/pa-BfwcJIar.mjs +19 -0
  85. package/dist/pay-react.css +1 -0
  86. package/dist/pl-DE5IB9xv.mjs +19 -0
  87. package/dist/pl-H0hBKdvF.js +1 -0
  88. package/dist/pt-CLzkqDzf.mjs +19 -0
  89. package/dist/pt-DwGrViQ3.js +1 -0
  90. package/dist/ru-CB2m0UDT.js +1 -0
  91. package/dist/ru-DM6-oUR0.mjs +19 -0
  92. package/dist/stripe-only.d.ts +31 -0
  93. package/dist/stripe-only.d.ts.map +1 -0
  94. package/dist/stripe-only.js +1 -0
  95. package/dist/stripe-only.mjs +33 -0
  96. package/dist/styles-D3XGpsqb.js +1 -0
  97. package/dist/styles-zgmHs6Hs.mjs +1601 -0
  98. package/dist/ta-A5HnrGb5.mjs +19 -0
  99. package/dist/ta-CAS197uN.js +1 -0
  100. package/dist/telemetry.d.ts +27 -0
  101. package/dist/telemetry.d.ts.map +1 -0
  102. package/dist/telemetry.js +1 -0
  103. package/dist/telemetry.mjs +127 -0
  104. package/dist/testing/__tests__/providers.test.d.ts +10 -0
  105. package/dist/testing/__tests__/providers.test.d.ts.map +1 -0
  106. package/dist/testing/helpers.d.ts +242 -0
  107. package/dist/testing/helpers.d.ts.map +1 -0
  108. package/dist/testing/index.d.ts +12 -0
  109. package/dist/testing/index.d.ts.map +1 -0
  110. package/dist/testing/index.js +1 -0
  111. package/dist/testing/index.mjs +374 -0
  112. package/dist/testing/mocks.d.ts +225 -0
  113. package/dist/testing/mocks.d.ts.map +1 -0
  114. package/dist/testing/providers.d.ts +89 -0
  115. package/dist/testing/providers.d.ts.map +1 -0
  116. package/dist/th-3fbB3Ytp.mjs +19 -0
  117. package/dist/th-Cpz2cFcg.js +1 -0
  118. package/dist/tr-BrgfFFdq.mjs +19 -0
  119. package/dist/tr-hQrEFk86.js +1 -0
  120. package/dist/types/componentOptions.d.ts +138 -0
  121. package/dist/types/componentOptions.d.ts.map +1 -0
  122. package/dist/types/errors.d.ts +213 -0
  123. package/dist/types/errors.d.ts.map +1 -0
  124. package/dist/types/index.d.ts +248 -0
  125. package/dist/types/index.d.ts.map +1 -0
  126. package/dist/uk-0hFun_g_.mjs +19 -0
  127. package/dist/uk-DrK2Sv8C.js +1 -0
  128. package/dist/ur-CaOjJXai.mjs +19 -0
  129. package/dist/ur-D5-7mN9a.js +1 -0
  130. package/dist/utils/__tests__/cspHelper.test.d.ts +9 -0
  131. package/dist/utils/__tests__/cspHelper.test.d.ts.map +1 -0
  132. package/dist/utils/__tests__/fetchWithTimeout.test.d.ts +11 -0
  133. package/dist/utils/__tests__/fetchWithTimeout.test.d.ts.map +1 -0
  134. package/dist/utils/cartHelpers.d.ts +105 -0
  135. package/dist/utils/cartHelpers.d.ts.map +1 -0
  136. package/dist/utils/circuitBreaker.d.ts +112 -0
  137. package/dist/utils/circuitBreaker.d.ts.map +1 -0
  138. package/dist/utils/couponHelpers.d.ts +50 -0
  139. package/dist/utils/couponHelpers.d.ts.map +1 -0
  140. package/dist/utils/cspHelper.d.ts +162 -0
  141. package/dist/utils/cspHelper.d.ts.map +1 -0
  142. package/dist/utils/deprecation.d.ts +128 -0
  143. package/dist/utils/deprecation.d.ts.map +1 -0
  144. package/dist/utils/errorHandling.d.ts +30 -0
  145. package/dist/utils/errorHandling.d.ts.map +1 -0
  146. package/dist/utils/errorMessages.d.ts +47 -0
  147. package/dist/utils/errorMessages.d.ts.map +1 -0
  148. package/dist/utils/errorParser.d.ts +37 -0
  149. package/dist/utils/errorParser.d.ts.map +1 -0
  150. package/dist/utils/eventEmitter.d.ts +119 -0
  151. package/dist/utils/eventEmitter.d.ts.map +1 -0
  152. package/dist/utils/exponentialBackoff.d.ts +104 -0
  153. package/dist/utils/exponentialBackoff.d.ts.map +1 -0
  154. package/dist/utils/fetchWithTimeout.d.ts +13 -0
  155. package/dist/utils/fetchWithTimeout.d.ts.map +1 -0
  156. package/dist/utils/index.d.ts +15 -0
  157. package/dist/utils/index.d.ts.map +1 -0
  158. package/dist/utils/logger.d.ts +76 -0
  159. package/dist/utils/logger.d.ts.map +1 -0
  160. package/dist/utils/modalStyles.d.ts +13 -0
  161. package/dist/utils/modalStyles.d.ts.map +1 -0
  162. package/dist/utils/rateLimiter.d.ts +88 -0
  163. package/dist/utils/rateLimiter.d.ts.map +1 -0
  164. package/dist/utils/requestDeduplication.d.ts +124 -0
  165. package/dist/utils/requestDeduplication.d.ts.map +1 -0
  166. package/dist/utils/securityValidation.d.ts +75 -0
  167. package/dist/utils/securityValidation.d.ts.map +1 -0
  168. package/dist/utils/solanaCheck.d.ts +10 -0
  169. package/dist/utils/solanaCheck.d.ts.map +1 -0
  170. package/dist/utils/telemetry.d.ts +277 -0
  171. package/dist/utils/telemetry.d.ts.map +1 -0
  172. package/dist/utils/tokenMintValidator.d.ts +77 -0
  173. package/dist/utils/tokenMintValidator.d.ts.map +1 -0
  174. package/dist/utils/uuid.d.ts +13 -0
  175. package/dist/utils/uuid.d.ts.map +1 -0
  176. package/dist/utils/validateConfig.d.ts +13 -0
  177. package/dist/utils/validateConfig.d.ts.map +1 -0
  178. package/dist/utils/walletDetection.d.ts +6 -0
  179. package/dist/utils/walletDetection.d.ts.map +1 -0
  180. package/dist/utils/walletPool.d.ts +57 -0
  181. package/dist/utils/walletPool.d.ts.map +1 -0
  182. package/dist/uuid-C0iMjdcc.js +1 -0
  183. package/dist/uuid-UlzrVY8Y.mjs +17 -0
  184. package/dist/vn-0nlIZFLP.mjs +19 -0
  185. package/dist/vn-B_iut9YL.js +1 -0
  186. package/dist/walletDetection-JZR3UCOa.mjs +27 -0
  187. package/dist/walletDetection-bNmV5ItZ.js +1 -0
  188. package/dist/zh-B4Endr1F.mjs +19 -0
  189. package/dist/zh-PR82dCHr.js +1 -0
  190. package/package.json +139 -0
package/README.md ADDED
@@ -0,0 +1,1731 @@
1
+ # Cedros Pay
2
+
3
+ [![npm version](https://badge.fury.io/js/%40cedros%2Fpay-react.svg)](https://www.npmjs.com/package/@cedros/pay-react)
4
+ [![License: MIT](https://img.shields.io/badge/License-MIT-yellow.svg)](https://opensource.org/licenses/MIT)
5
+ [![TypeScript](https://img.shields.io/badge/TypeScript-5.4-blue.svg)](https://www.typescriptlang.org/)
6
+ [![Bundle Size](https://img.shields.io/bundlephobia/minzip/@cedros/pay-react)](https://bundlephobia.com/package/@cedros/pay-react)
7
+ [![Stripe-only: <100KB](https://img.shields.io/badge/stripe--only-%3C100KB-success)]()
8
+ [![Tests](https://img.shields.io/badge/tests-55%20passed-brightgreen)](https://github.com/cedros-tech/pay-react)
9
+
10
+ > **Unified payments for humans and agents — from Solana Beach to the web.**
11
+
12
+ ## ⚠️ BREAKING CHANGES (v2.0.0+)
13
+
14
+ **Version 2.0.0 introduces security improvements that require backend updates.**
15
+
16
+ ### What Changed
17
+
18
+ - **NEW:** API v1 versioning (`/paywall/v1/*` endpoints) for stable API contracts
19
+ - **NEW:** Generic endpoints (`/paywall/v1/quote`, `/paywall/v1/verify`) prevent resource ID leakage
20
+ - **REMOVED:** Resource-specific endpoints (`/paywall/{resource}`, `/paywall/cart/{id}`)
21
+ - **SECURITY:** Resource IDs now sent in request bodies and X-PAYMENT headers (not URLs)
22
+
23
+ ## 🌅 Why Cedros Pay?
24
+
25
+ Built as a nod to **Solana Beach’s Cedros Avenue**, Cedros Pay embodies the connection between **old-world payments and new-world rails** — Stripe’s fiat system and Solana’s instant, decentralized network.
26
+
27
+ Whether you're building a paywalled blog, an agentic API, or a marketplace, Cedros Pay handles both sides:
28
+
29
+ - Stripe-hosted checkout for credit/debit cards.
30
+ - x402-verified USDC payments for instant crypto settlement.
31
+
32
+ ---
33
+
34
+ ## 🧩 Architecture
35
+
36
+ ```
37
+ Frontend (React) → Cedros Server → Stripe & Solana RPC
38
+ | |
39
+ |---- x402 headers ----> |---- Stripe webhooks ----> DB
40
+ ```
41
+
42
+ **Frontend**
43
+
44
+ - React SDK (`@cedros/pay-react`) for drop-in payment buttons.
45
+ - Uses wallet adapters for Solana and Stripe JS SDK for fiat.
46
+
47
+ **Backend**
48
+
49
+ - Go service handling session creation, webhooks, x402 verification, and route protection.
50
+ - Deploy standalone or embed into existing backend.
51
+
52
+ ---
53
+
54
+ ## 💳 Key Features
55
+
56
+ - 🪙 **Dual payment support** — Card + Crypto
57
+ - ⚡ **Instant agentic payments** — Pay per request via x402
58
+ - 🔐 **Stateless & secure** — No need for user accounts or deposit addresses
59
+ - 🌍 **Open source** — MIT-licensed and extensible
60
+ - 🧱 **Minimal integration** — Middleware or proxy for Go APIs
61
+
62
+ ---
63
+
64
+ ## 🚀 Quick Start
65
+
66
+ ### Installation
67
+
68
+ **Option 1: Stripe + Crypto (Full Features)**
69
+
70
+ ```bash
71
+ npm install @cedros/pay-react \
72
+ @solana/web3.js \
73
+ @solana/spl-token \
74
+ @solana/wallet-adapter-base \
75
+ @solana/wallet-adapter-react \
76
+ @solana/wallet-adapter-react-ui \
77
+ @solana/wallet-adapter-wallets
78
+ ```
79
+
80
+ **Option 2: Stripe Only (Smaller Bundle - ~75KB)**
81
+
82
+ ```bash
83
+ npm install @cedros/pay-react
84
+ ```
85
+
86
+ Use the `stripe-only` entry point to get a dramatically smaller bundle:
87
+
88
+ ```tsx
89
+ import { CedrosProvider, StripeButton } from "@cedros/pay-react/stripe-only";
90
+ import "@cedros/pay-react/style.css";
91
+
92
+ function App() {
93
+ return (
94
+ <CedrosProvider
95
+ config={{
96
+ stripePublicKey: "pk_test_...",
97
+ serverUrl: window.location.origin,
98
+ solanaCluster: "mainnet-beta",
99
+ }}
100
+ >
101
+ <StripeButton resource="item-id" />
102
+ </CedrosProvider>
103
+ );
104
+ }
105
+ ```
106
+
107
+ **Bundle Size Comparison:**
108
+
109
+ - `@cedros/pay-react` (full): ~100KB + 850KB Solana peer deps
110
+ - `@cedros/pay-react/stripe-only`: ~75KB (no Solana deps)
111
+ - `@cedros/pay-react/crypto-only`: ~100KB + 850KB Solana peer deps
112
+
113
+ ### CDN Usage (Optional)
114
+
115
+ For zero-build prototyping or simple sites, you can import directly from a CDN:
116
+
117
+ ```html
118
+ <!-- Styles -->
119
+ <link
120
+ rel="stylesheet"
121
+ href="https://unpkg.com/@cedros/pay-react@0.1.0/dist/style.css"
122
+ />
123
+
124
+ <!-- Library (ESM) -->
125
+ <script type="module">
126
+ import {
127
+ CedrosProvider,
128
+ StripeButton,
129
+ } from "https://unpkg.com/@cedros/pay-react@0.1.0/dist/index.mjs";
130
+ // Your code here
131
+ </script>
132
+ ```
133
+
134
+ **CDN Options:**
135
+
136
+ - [unpkg.com](https://unpkg.com/@cedros/pay-react) - Fast, reliable, global CDN
137
+ - [jsdelivr.com](https://cdn.jsdelivr.net/npm/@cedros/pay-react) - Multi-CDN with fallback
138
+
139
+ **Performance Notes:**
140
+
141
+ - CDN providers (unpkg, jsdelivr) automatically serve with immutable cache headers (`Cache-Control: public, max-age=31536000, immutable`)
142
+ - For self-hosted deployments, set the same cache headers on `/dist/*` assets for optimal performance
143
+ - Pin to specific version (`@0.1.0`) in production to ensure stability
144
+
145
+ **Option 3: Crypto Only**
146
+
147
+ If you only need Solana crypto payments:
148
+
149
+ ```bash
150
+ npm install @cedros/pay-react \
151
+ @solana/web3.js \
152
+ @solana/spl-token \
153
+ @solana/wallet-adapter-base \
154
+ @solana/wallet-adapter-react \
155
+ @solana/wallet-adapter-react-ui \
156
+ @solana/wallet-adapter-wallets
157
+ ```
158
+
159
+ Then use the `crypto-only` entry point:
160
+
161
+ ```tsx
162
+ import { CedrosProvider, CryptoButton } from "@cedros/pay-react/crypto-only";
163
+ import "@cedros/pay-react/style.css";
164
+
165
+ function App() {
166
+ return (
167
+ <CedrosProvider
168
+ config={{
169
+ stripePublicKey: "pk_test_...", // Required even for crypto-only (use a placeholder)
170
+ serverUrl: window.location.origin,
171
+ solanaCluster: "mainnet-beta",
172
+ }}
173
+ >
174
+ <CryptoButton resource="item-id" />
175
+ </CedrosProvider>
176
+ );
177
+ }
178
+ ```
179
+
180
+ **Note:** Even when using the `crypto-only` entry point, `stripePublicKey` is still required in the config (use a test/placeholder key if you don't have Stripe integration). This is a known limitation that will be addressed in a future version.
181
+
182
+ **Using the full bundle but hiding crypto button:**
183
+
184
+ ```tsx
185
+ <CedrosPay resource="item-id" display={{ showCrypto: false }} />
186
+ ```
187
+
188
+ ### Basic Usage
189
+
190
+ ```tsx
191
+ import { CedrosPay, CedrosProvider } from "@cedros/pay-react";
192
+ import "@cedros/pay-react/style.css";
193
+
194
+ function App() {
195
+ return (
196
+ <CedrosProvider
197
+ config={{
198
+ stripePublicKey: "pk_test_...",
199
+ serverUrl: window.location.origin,
200
+ solanaCluster: "mainnet-beta",
201
+ // serverUrl defaults to window.location.origin
202
+ // Only needed if your backend is on a different domain
203
+ }}
204
+ >
205
+ <CedrosPay
206
+ resource="demo-item-id-1"
207
+ callbacks={{
208
+ onPaymentSuccess: (result) =>
209
+ console.log("Payment successful!", result.transactionId),
210
+ onPaymentError: (error) =>
211
+ console.error("Payment failed:", error.message),
212
+ }}
213
+ />
214
+ </CedrosProvider>
215
+ );
216
+ }
217
+ ```
218
+
219
+ **Cross-Domain Backend (Optional):**
220
+ If your backend is on a different domain (e.g., `api.example.com` while your frontend is on `example.com`), explicitly set `serverUrl`:
221
+
222
+ ```tsx
223
+ <CedrosProvider
224
+ config={{
225
+ stripePublicKey: "pk_test_...",
226
+ serverUrl: "https://api.example.com", // Explicit URL for cross-domain
227
+ solanaCluster: "mainnet-beta",
228
+ }}
229
+ >
230
+ {/* ... */}
231
+ </CedrosProvider>
232
+ ```
233
+
234
+ ### Backend Setup
235
+
236
+ Your backend must implement the Cedros Pay API endpoints:
237
+
238
+ ```bash
239
+ go get github.com/cedros-pay/server
240
+ ```
241
+
242
+ **Required Endpoints (v2.0.0+):**
243
+
244
+ - `GET /cedros-health` - Health check and route discovery
245
+ - `POST /paywall/v1/quote` - x402 payment quote (resource ID in body)
246
+ - `POST /paywall/v1/verify` - Payment verification (resource ID in X-PAYMENT header)
247
+ - `POST /paywall/v1/stripe-session` - Create Stripe checkout (single item)
248
+ - `POST /paywall/v1/cart/checkout` - Create Stripe checkout (cart)
249
+ - `POST /paywall/v1/cart/quote` - Get x402 quote for cart items
250
+ - `POST /paywall/v1/gasless-transaction` - Build gasless transaction (optional)
251
+ - `POST /paywall/v1/nonce` - Generate nonce for admin authentication
252
+ - `POST /paywall/v1/refunds/request` - Create refund request (requires signature from original payer or admin)
253
+ - `POST /paywall/v1/refunds/pending` - Get all pending refunds (admin-only, requires nonce)
254
+ - `POST /paywall/v1/refunds/approve` - Get fresh quote for pending refund (admin-only)
255
+ - `POST /paywall/v1/refunds/deny` - Deny pending refund (admin-only)
256
+
257
+ **Example - Quote Request:**
258
+
259
+ ```bash
260
+ POST /paywall/v1/quote
261
+ Content-Type: application/json
262
+
263
+ {
264
+ "resource": "premium-article",
265
+ "couponCode": "SAVE20" # optional
266
+ }
267
+
268
+ # Response: 402 Payment Required with x402 quote
269
+ ```
270
+
271
+ **Example - Payment Verification:**
272
+
273
+ ```bash
274
+ POST /paywall/v1/verify
275
+ X-PAYMENT: <base64-encoded-payment-proof>
276
+
277
+ # Payment proof includes resource ID and type
278
+ # No resource IDs in URL path (security improvement)
279
+ ```
280
+
281
+ **Example - Refund Request:**
282
+
283
+ ```bash
284
+ POST /paywall/v1/refunds/request
285
+ Content-Type: application/json
286
+ X-Signature: <base64-encoded-signature>
287
+ X-Message: request-refund:<transaction-signature>
288
+ X-Signer: <wallet-address>
289
+
290
+ {
291
+ "originalPurchaseId": "5jHxP...2QvK", // Original transaction signature
292
+ "recipientWallet": "9xQeW...Yhq",
293
+ "amount": 10.5,
294
+ "token": "USDC",
295
+ "reason": "Customer requested refund"
296
+ }
297
+
298
+ # Signer must be the original payer OR admin wallet
299
+ # Recipient wallet must match the payer from original transaction
300
+ # Only one refund allowed per transaction signature
301
+ ```
302
+
303
+ **Example - Get Pending Refunds (Admin - Nonce Required):**
304
+
305
+ ```bash
306
+ # Step 1: Generate nonce
307
+ POST /paywall/v1/nonce
308
+ Content-Type: application/json
309
+
310
+ {
311
+ "purpose": "list-pending-refunds"
312
+ }
313
+ # Response: { "nonce": "abc123...", "expiresAt": 1234567890 }
314
+
315
+ # Step 2: Fetch pending refunds with nonce
316
+ POST /paywall/v1/refunds/pending
317
+ Content-Type: application/json
318
+ X-Signature: <base64-encoded-signature>
319
+ X-Message: list-pending-refunds:<nonce>
320
+ X-Signer: <admin-wallet-address>
321
+
322
+ # Returns array of pending refund requests
323
+ # Response: [{ refundId, originalPurchaseId, recipientWallet, amount, token, reason, ... }]
324
+ ```
325
+
326
+ See [Backend Integration](https://github.com/CedrosPay/server) and `@backend-migration-resource-leakage.md` for complete API reference and migration guide.
327
+
328
+ ---
329
+
330
+ ## 🔒 Production Deployment
331
+
332
+ ### Content Security Policy (CSP) Headers
333
+
334
+ **⚠️ Important:** Cedros Pay requires specific Content Security Policy directives to function correctly in production. Without these, Stripe and Solana RPC calls will be blocked by the browser.
335
+
336
+ #### Required CSP Directives
337
+
338
+ ```http
339
+ Content-Security-Policy:
340
+ script-src 'self' https://js.stripe.com;
341
+ connect-src 'self' https://api.stripe.com https://*.stripe.com https://api.mainnet-beta.solana.com https://*.solana.com;
342
+ frame-src https://js.stripe.com https://checkout.stripe.com;
343
+ ```
344
+
345
+ **Breakdown:**
346
+
347
+ - `script-src` - Allows Stripe.js to load and execute
348
+ - `connect-src` - Allows API calls to Stripe and Solana RPC endpoints
349
+ - `frame-src` - Allows Stripe Checkout iframe to load
350
+
351
+ #### Framework-Specific Examples
352
+
353
+ **Next.js (App Router)**
354
+
355
+ ```typescript
356
+ // next.config.js
357
+ const nextConfig = {
358
+ async headers() {
359
+ return [
360
+ {
361
+ source: "/(.*)",
362
+ headers: [
363
+ {
364
+ key: "Content-Security-Policy",
365
+ value: [
366
+ "script-src 'self' 'unsafe-inline' 'unsafe-eval' https://js.stripe.com",
367
+ "connect-src 'self' https://api.stripe.com https://*.stripe.com https://api.mainnet-beta.solana.com https://*.solana.com https://*.helius-rpc.com https://*.quicknode.pro",
368
+ "frame-src https://js.stripe.com https://checkout.stripe.com",
369
+ ].join("; "),
370
+ },
371
+ ],
372
+ },
373
+ ];
374
+ },
375
+ };
376
+ ```
377
+
378
+ **Next.js (Pages Router with Middleware)**
379
+
380
+ ```typescript
381
+ // middleware.ts
382
+ import { NextResponse } from "next/server";
383
+ import type { NextRequest } from "next/server";
384
+
385
+ export function middleware(request: NextRequest) {
386
+ const response = NextResponse.next();
387
+
388
+ response.headers.set(
389
+ "Content-Security-Policy",
390
+ [
391
+ "script-src 'self' 'unsafe-inline' 'unsafe-eval' https://js.stripe.com",
392
+ "connect-src 'self' https://api.stripe.com https://*.stripe.com https://api.mainnet-beta.solana.com https://*.solana.com",
393
+ "frame-src https://js.stripe.com https://checkout.stripe.com",
394
+ ].join("; ")
395
+ );
396
+
397
+ return response;
398
+ }
399
+ ```
400
+
401
+ **Vite (Development)**
402
+
403
+ ```typescript
404
+ // vite.config.ts
405
+ import { defineConfig } from "vite";
406
+
407
+ export default defineConfig({
408
+ server: {
409
+ headers: {
410
+ "Content-Security-Policy": [
411
+ "script-src 'self' 'unsafe-inline' https://js.stripe.com",
412
+ "connect-src 'self' https://api.stripe.com https://*.stripe.com https://api.mainnet-beta.solana.com https://*.solana.com",
413
+ "frame-src https://js.stripe.com https://checkout.stripe.com",
414
+ ].join("; "),
415
+ },
416
+ },
417
+ });
418
+ ```
419
+
420
+ **Nginx**
421
+
422
+ ```nginx
423
+ # nginx.conf
424
+ location / {
425
+ add_header Content-Security-Policy "script-src 'self' https://js.stripe.com; connect-src 'self' https://api.stripe.com https://*.stripe.com https://api.mainnet-beta.solana.com https://*.solana.com; frame-src https://js.stripe.com https://checkout.stripe.com;" always;
426
+ }
427
+ ```
428
+
429
+ **Express.js**
430
+
431
+ ```javascript
432
+ // server.js
433
+ const helmet = require("helmet");
434
+
435
+ app.use(
436
+ helmet.contentSecurityPolicy({
437
+ directives: {
438
+ scriptSrc: ["'self'", "https://js.stripe.com"],
439
+ connectSrc: [
440
+ "'self'",
441
+ "https://api.stripe.com",
442
+ "https://*.stripe.com",
443
+ "https://api.mainnet-beta.solana.com",
444
+ "https://*.solana.com",
445
+ ],
446
+ frameSrc: ["https://js.stripe.com", "https://checkout.stripe.com"],
447
+ },
448
+ })
449
+ );
450
+ ```
451
+
452
+ **HTML Meta Tag (Not Recommended)**
453
+
454
+ ```html
455
+ <!-- Use server headers instead when possible -->
456
+ <meta
457
+ http-equiv="Content-Security-Policy"
458
+ content="script-src 'self' https://js.stripe.com; connect-src 'self' https://api.stripe.com https://*.stripe.com https://api.mainnet-beta.solana.com https://*.solana.com; frame-src https://js.stripe.com https://checkout.stripe.com;"
459
+ />
460
+ ```
461
+
462
+ #### Custom RPC Endpoints
463
+
464
+ If you're using a custom Solana RPC provider (Helius, QuickNode, etc.), add their domains to `connect-src`:
465
+
466
+ ```http
467
+ connect-src 'self'
468
+ https://api.stripe.com
469
+ https://*.stripe.com
470
+ https://mainnet.helius-rpc.com
471
+ https://*.quicknode.pro
472
+ https://rpc.ankr.com;
473
+ ```
474
+
475
+ #### Devnet/Testnet
476
+
477
+ For development against Solana devnet or testnet:
478
+
479
+ ```http
480
+ connect-src 'self'
481
+ https://api.stripe.com
482
+ https://*.stripe.com
483
+ https://api.devnet.solana.com
484
+ https://api.testnet.solana.com;
485
+ ```
486
+
487
+ ### Troubleshooting CSP Issues
488
+
489
+ **Symptom:** Stripe Checkout doesn't load or throws CORS errors
490
+
491
+ ```
492
+ Refused to load the script 'https://js.stripe.com/v3/' because it violates the following Content Security Policy directive: "script-src 'self'"
493
+ ```
494
+
495
+ **Fix:** Add `https://js.stripe.com` to `script-src`
496
+
497
+ ---
498
+
499
+ **Symptom:** Solana RPC calls fail with network errors
500
+
501
+ ```
502
+ Refused to connect to 'https://api.mainnet-beta.solana.com' because it violates the following Content Security Policy directive: "connect-src 'self'"
503
+ ```
504
+
505
+ **Fix:** Add your Solana RPC endpoint to `connect-src`
506
+
507
+ ---
508
+
509
+ **Symptom:** Stripe Checkout redirects fail or show blank page
510
+
511
+ ```
512
+ Refused to display 'https://checkout.stripe.com' in a frame because it violates the following Content Security Policy directive: "frame-src 'self'"
513
+ ```
514
+
515
+ **Fix:** Add `https://checkout.stripe.com` to `frame-src`
516
+
517
+ ---
518
+
519
+ ### Testing CSP in Development
520
+
521
+ 1. Open browser DevTools → Console
522
+ 2. Look for CSP violation warnings (usually in red)
523
+ 3. Check the Network tab for blocked requests
524
+ 4. Add blocked domains to appropriate CSP directives
525
+
526
+ **Chrome DevTools Example:**
527
+
528
+ ```
529
+ [Report Only] Refused to connect to 'https://api.stripe.com/v1/tokens'
530
+ because it violates the document's Content Security Policy.
531
+ ```
532
+
533
+ ### Best Practices
534
+
535
+ ✅ **DO:**
536
+
537
+ - Use server-side headers (not meta tags) for CSP
538
+ - Test CSP in staging before deploying to production
539
+ - Use wildcards sparingly (`*.stripe.com` is okay, `*` is not)
540
+ - Include your custom RPC provider domains
541
+
542
+ ❌ **DON'T:**
543
+
544
+ - Use `'unsafe-inline'` in production unless necessary
545
+ - Block Stripe or Solana domains
546
+ - Forget to add `frame-src` for Stripe Checkout
547
+ - Use overly permissive directives like `* 'unsafe-eval'`
548
+
549
+ ---
550
+
551
+ ### CSP Helper Generator
552
+
553
+ **⚠️ RECOMMENDED:** Use the `generateCSP()` helper to automatically generate correct CSP directives for your configuration. This prevents common misconfigurations that break payment widgets.
554
+
555
+ #### Quick Start
556
+
557
+ ```typescript
558
+ import { generateCSP, RPC_PROVIDERS } from "@cedros/pay-react";
559
+
560
+ // Generate CSP for production with custom RPC
561
+ const csp = generateCSP({
562
+ solanaCluster: "mainnet-beta",
563
+ solanaEndpoint: "https://mainnet.helius-rpc.com",
564
+ allowUnsafeScripts: true, // Required for Next.js
565
+ });
566
+
567
+ // Use in your framework
568
+ response.setHeader("Content-Security-Policy", csp);
569
+ ```
570
+
571
+ #### Configuration Options
572
+
573
+ ```typescript
574
+ interface CSPConfig {
575
+ solanaCluster?: "mainnet-beta" | "devnet" | "testnet";
576
+ solanaEndpoint?: string; // Custom RPC URL
577
+ customRpcProviders?: string[]; // Additional RPC providers
578
+ allowUnsafeScripts?: boolean; // For Next.js, etc.
579
+ additionalScriptSrc?: string[];
580
+ additionalConnectSrc?: string[];
581
+ additionalFrameSrc?: string[];
582
+ includeStripe?: boolean; // Set false for crypto-only
583
+ }
584
+ ```
585
+
586
+ #### Framework Examples
587
+
588
+ **Next.js App Router:**
589
+
590
+ ```typescript
591
+ // next.config.js
592
+ import { generateCSP } from "@cedros/pay-react";
593
+
594
+ const csp = generateCSP({
595
+ solanaCluster: "mainnet-beta",
596
+ solanaEndpoint: process.env.SOLANA_RPC_URL,
597
+ allowUnsafeScripts: true,
598
+ });
599
+
600
+ const nextConfig = {
601
+ async headers() {
602
+ return [
603
+ {
604
+ source: "/(.*)",
605
+ headers: [{ key: "Content-Security-Policy", value: csp }],
606
+ },
607
+ ];
608
+ },
609
+ };
610
+
611
+ export default nextConfig;
612
+ ```
613
+
614
+ **Express with Helmet:**
615
+
616
+ ```typescript
617
+ import { generateCSP } from "@cedros/pay-react";
618
+ import helmet from "helmet";
619
+
620
+ const cspDirectives = generateCSP(
621
+ {
622
+ solanaCluster: "mainnet-beta",
623
+ solanaEndpoint: process.env.SOLANA_RPC_URL,
624
+ },
625
+ "helmet" // Returns object format for helmet
626
+ );
627
+
628
+ app.use(helmet.contentSecurityPolicy({ directives: cspDirectives }));
629
+ ```
630
+
631
+ **Vite Development:**
632
+
633
+ ```typescript
634
+ // vite.config.ts
635
+ import { defineConfig } from "vite";
636
+ import { generateCSP } from "@cedros/pay-react";
637
+
638
+ const csp = generateCSP({
639
+ solanaCluster: "devnet",
640
+ allowUnsafeScripts: true,
641
+ });
642
+
643
+ export default defineConfig({
644
+ server: {
645
+ headers: {
646
+ "Content-Security-Policy": csp,
647
+ },
648
+ },
649
+ });
650
+ ```
651
+
652
+ #### Presets
653
+
654
+ Use presets for common scenarios:
655
+
656
+ ```typescript
657
+ import { generateCSP, CSP_PRESETS } from "@cedros/pay-react";
658
+
659
+ // Production mainnet with custom RPC
660
+ const csp1 = generateCSP(
661
+ CSP_PRESETS.MAINNET_CUSTOM_RPC("https://mainnet.helius-rpc.com")
662
+ );
663
+
664
+ // Next.js with mainnet
665
+ const csp2 = generateCSP(
666
+ CSP_PRESETS.MAINNET_NEXTJS("https://mainnet.helius-rpc.com")
667
+ );
668
+
669
+ // Devnet testing
670
+ const csp3 = generateCSP(CSP_PRESETS.DEVNET());
671
+
672
+ // Crypto-only (no Stripe)
673
+ const csp4 = generateCSP(CSP_PRESETS.CRYPTO_ONLY());
674
+
675
+ // Stripe-only (no Solana)
676
+ const csp5 = generateCSP(CSP_PRESETS.STRIPE_ONLY());
677
+ ```
678
+
679
+ #### Common RPC Providers
680
+
681
+ ```typescript
682
+ import { RPC_PROVIDERS } from "@cedros/pay-react";
683
+
684
+ const csp = generateCSP({
685
+ customRpcProviders: [
686
+ RPC_PROVIDERS.HELIUS, // https://*.helius-rpc.com
687
+ RPC_PROVIDERS.QUICKNODE, // https://*.quicknode.pro
688
+ RPC_PROVIDERS.ALCHEMY, // https://*.alchemy.com
689
+ RPC_PROVIDERS.ANKR, // https://rpc.ankr.com
690
+ RPC_PROVIDERS.TRITON, // https://*.rpcpool.com
691
+ ],
692
+ });
693
+ ```
694
+
695
+ #### Output Formats
696
+
697
+ The helper supports multiple output formats:
698
+
699
+ ```typescript
700
+ // HTTP header format (default)
701
+ const header = generateCSP(config, "header");
702
+ // "script-src 'self' https://js.stripe.com; connect-src ..."
703
+
704
+ // HTML meta tag format
705
+ const meta = generateCSP(config, "meta");
706
+
707
+ // Next.js config format
708
+ const nextjs = generateCSP(config, "nextjs");
709
+
710
+ // Express helmet format (object)
711
+ const helmet = generateCSP(config, "helmet");
712
+ // { scriptSrc: [...], connectSrc: [...], frameSrc: [...] }
713
+
714
+ // Nginx config format
715
+ const nginx = generateCSP(config, "nginx");
716
+
717
+ // Raw directives object
718
+ const directives = generateCSP(config, "directives");
719
+ ```
720
+
721
+ #### Why Use the Helper?
722
+
723
+ ✅ **Prevents common errors:**
724
+
725
+ - Forgetting Solana RPC endpoints
726
+ - Missing Stripe iframe domains
727
+ - Wrong cluster URLs (devnet vs mainnet)
728
+
729
+ ✅ **Type-safe configuration:**
730
+
731
+ - TypeScript autocomplete for all options
732
+ - Validates cluster names
733
+ - Catches typos at compile time
734
+
735
+ ✅ **Framework-agnostic:**
736
+
737
+ - Works with Next.js, Express, Vite, Nginx, etc.
738
+ - Multiple output formats
739
+ - No dependencies
740
+
741
+ ---
742
+
743
+ ### Security Best Practices
744
+
745
+ #### Subresource Integrity (SRI) for Stripe.js
746
+
747
+ **⚠️ IMPORTANT: Cedros Pay does NOT use SRI hashes for Stripe.js, and this is intentional.**
748
+
749
+ **Why SRI is NOT used:**
750
+
751
+ - **Stripe updates frequently** - Security patches and bug fixes are pushed without URL changes
752
+ - **SRI breaks automatic updates** - Hardcoded hashes prevent receiving critical security fixes
753
+ - **Stripe's official recommendation** - Stripe explicitly advises against using SRI
754
+ - **Alternative protection** - Content Security Policy (CSP) provides the security layer
755
+
756
+ **From Stripe's documentation:**
757
+
758
+ > "We do not recommend using Subresource Integrity (SRI) with Stripe.js. Stripe.js is served from a highly-available CDN, and we regularly update the library to address security issues and improve functionality. Using SRI would prevent you from receiving these automatic updates."
759
+
760
+ **How Cedros Pay Protects Against CDN Compromise:**
761
+
762
+ 1. **Content Security Policy (CSP)**
763
+
764
+ ```http
765
+ Content-Security-Policy: script-src 'self' https://js.stripe.com
766
+ ```
767
+
768
+ - Prevents loading scripts from unauthorized domains
769
+ - Blocks inline scripts and eval()
770
+ - Works with Stripe's automatic updates
771
+
772
+ 2. **Package Integrity via npm**
773
+
774
+ ```json
775
+ {
776
+ "dependencies": {
777
+ "@stripe/stripe-js": "^2.4.0"
778
+ }
779
+ }
780
+ ```
781
+
782
+ - `package-lock.json` contains integrity hashes for npm packages
783
+ - npm verifies package integrity on installation
784
+ - Protects against tampering with the loader
785
+
786
+ 3. **HTTPS Enforcement**
787
+
788
+ - Stripe.js is loaded over HTTPS only
789
+ - Modern browsers enforce secure connections
790
+ - Certificate pinning via browser trust store
791
+
792
+ 4. **Version Pinning** (optional)
793
+ ```json
794
+ {
795
+ "dependencies": {
796
+ "@stripe/stripe-js": "2.4.0" // Exact version (no caret)
797
+ }
798
+ }
799
+ ```
800
+ - Prevents unexpected updates
801
+ - Review changelog before upgrading
802
+ - Balance security updates vs. stability
803
+
804
+ **Recommended Security Checklist:**
805
+
806
+ ✅ **DO:**
807
+
808
+ - Use CSP headers with `script-src https://js.stripe.com`
809
+ - Keep `@stripe/stripe-js` updated for security patches
810
+ - Use HTTPS for all connections
811
+ - Enable npm package auditing (`npm audit`)
812
+ - Review Stripe's changelog before major updates
813
+ - Monitor Stripe's security advisories
814
+
815
+ ❌ **DON'T:**
816
+
817
+ - Add SRI hashes to Stripe.js (breaks updates)
818
+ - Allow `script-src *` in CSP (too permissive)
819
+ - Use outdated versions of @stripe/stripe-js
820
+ - Load Stripe.js from third-party CDNs
821
+ - Disable HTTPS enforcement
822
+
823
+ **Alternative: Self-Hosting Stripe.js (NOT RECOMMENDED)**
824
+
825
+ While technically possible to self-host Stripe.js with SRI, Stripe strongly discourages this:
826
+
827
+ - ❌ Miss critical security updates
828
+ - ❌ Break PCI DSS compliance requirements
829
+ - ❌ Lose Stripe's CDN performance benefits
830
+ - ❌ Violate Stripe's Terms of Service
831
+
832
+ **For maximum security, follow Stripe's recommendations and use CSP instead of SRI.**
833
+
834
+ ---
835
+
836
+ ## 🌍 Internationalization (i18n)
837
+
838
+ Cedros Pay supports multiple languages with automatic browser locale detection and zero-configuration setup.
839
+
840
+ ### Supported Languages
841
+
842
+ Currently available (auto-detected from `src/i18n/translations/` folder):
843
+
844
+ - 🇺🇸 **English** (en) - Default
845
+ - 🇪🇸 **Spanish** (es)
846
+
847
+ ### Usage
848
+
849
+ **Automatic (recommended):**
850
+
851
+ ```tsx
852
+ import { useTranslation } from "@cedros/pay-react";
853
+
854
+ function PaymentButton() {
855
+ const { t } = useTranslation(); // Auto-detects browser language
856
+
857
+ return (
858
+ <button>{t("ui.pay_with_card")}</button> // "Pay with Card" or "Pagar con Tarjeta"
859
+ );
860
+ }
861
+ ```
862
+
863
+ **Manual locale override:**
864
+
865
+ ```tsx
866
+ function SpanishOnlyButton() {
867
+ const { t } = useTranslation("es"); // Force Spanish
868
+ return <button>{t("ui.pay_with_card")}</button>; // Always "Pagar con Tarjeta"
869
+ }
870
+ ```
871
+
872
+ **Error messages (automatic):**
873
+
874
+ ```tsx
875
+ import { PaymentError } from "@cedros/pay-react";
876
+
877
+ // Errors are automatically localized based on user's browser language
878
+ error.getUserMessage(); // Returns localized message + action
879
+ error.getShortMessage(); // Returns just the message (no action)
880
+ error.getAction(); // Returns just the action guidance
881
+ ```
882
+
883
+ ### Available Translation Keys
884
+
885
+ **UI Labels:**
886
+
887
+ - `ui.pay_with_card` - "Pay with Card"
888
+ - `ui.pay_with_crypto` - "Pay with USDC"
889
+ - `ui.connect_wallet` - "Connect Wallet"
890
+ - `ui.processing` - "Processing..."
891
+ - `ui.loading` - "Loading..."
892
+ - `ui.close` - "Close"
893
+ - `ui.cancel` - "Cancel"
894
+ - `ui.confirm` - "Confirm"
895
+ - `ui.retry` - "Try Again"
896
+ - `ui.contact_support` - "Contact Support"
897
+
898
+ **Error Messages:**
899
+
900
+ ```tsx
901
+ t("errors.insufficient_funds_token.message"); // "Insufficient balance in your wallet"
902
+ t("errors.insufficient_funds_token.action"); // "Add more funds to your wallet and try again."
903
+ ```
904
+
905
+ **Wallet Messages:**
906
+
907
+ ```tsx
908
+ t("wallet.no_wallet_detected"); // "No Solana wallet detected"
909
+ t("wallet.install_wallet"); // "Please install a Solana wallet..."
910
+ t("wallet.wallet_connection_failed"); // "Failed to connect wallet"
911
+ ```
912
+
913
+ ### Adding New Languages
914
+
915
+ 1. **Create translation file** in `src/i18n/translations/{locale}.json`:
916
+
917
+ ```json
918
+ // src/i18n/translations/fr.json
919
+ {
920
+ "locale": "fr",
921
+ "ui": {
922
+ "pay_with_card": "Payer par Carte",
923
+ "pay_with_crypto": "Payer avec USDC",
924
+ ...
925
+ },
926
+ "errors": { ... }
927
+ }
928
+ ```
929
+
930
+ 2. **That's it!** The system automatically detects new files and loads them.
931
+
932
+ See `src/i18n/TRANSLATION_INSTRUCTIONS.md` for detailed translation guidelines.
933
+
934
+ ### Dynamic Language Loading
935
+
936
+ The i18n system:
937
+
938
+ - ✅ Auto-detects available languages from file system
939
+ - ✅ Only loads the language the user needs (tree-shakeable)
940
+ - ✅ Falls back to English if translation missing
941
+ - ✅ Zero configuration required
942
+
943
+ ---
944
+
945
+ ## 🔄 Type Versioning Policy
946
+
947
+ Cedros Pay uses **semantic versioning for TypeScript types** to prevent breaking changes from affecting your code.
948
+
949
+ ### How It Works
950
+
951
+ All types are exported in versioned namespaces (`v1`, `v2`, etc.):
952
+
953
+ ```tsx
954
+ // Recommended: Use top-level exports (always points to current stable version)
955
+ import { X402Requirement, PaymentResult } from "@cedros/pay-react";
956
+
957
+ // Explicit version (locks to v1, won't break on v2 release)
958
+ import { v1 } from "@cedros/pay-react";
959
+ const requirement: v1.X402Requirement = {
960
+ /* ... */
961
+ };
962
+
963
+ // Future: When v2 is released, you can migrate gradually
964
+ import { v2 } from "@cedros/pay-react";
965
+ const newRequirement: v2.X402Requirement = {
966
+ /* ... */
967
+ };
968
+ ```
969
+
970
+ ### Breaking Change Example
971
+
972
+ If we need to change `X402Requirement.maxAmountRequired` from `string` to `bigint`:
973
+
974
+ 1. **v1 namespace remains unchanged** - Your existing code keeps working
975
+ 2. **v2 namespace** is created with the new type
976
+ 3. **Top-level exports** point to v2 (with major version bump)
977
+ 4. You can migrate at your own pace:
978
+
979
+ ```tsx
980
+ // Your old code still works with v1
981
+ import { v1 } from "@cedros/pay-react";
982
+ const oldReq: v1.X402Requirement = { maxAmountRequired: "1000000" };
983
+
984
+ // New code uses v2
985
+ import { v2 } from "@cedros/pay-react";
986
+ const newReq: v2.X402Requirement = { maxAmountRequired: 1000000n };
987
+ ```
988
+
989
+ ### Stability Guarantee
990
+
991
+ - **v1 types are frozen** - No breaking changes, ever
992
+ - **Top-level exports** may change across major versions
993
+ - **Older versions remain available** for backward compatibility
994
+ - **Clear migration path** when breaking changes are necessary
995
+
996
+ ---
997
+
998
+ ## 📖 Core Concepts
999
+
1000
+ ### Single Item Purchase
1001
+
1002
+ ```tsx
1003
+ <CedrosPay
1004
+ resource="article-123"
1005
+ callbacks={{
1006
+ onPaymentSuccess: (result) => unlockContent(result.transactionId),
1007
+ }}
1008
+ />
1009
+ ```
1010
+
1011
+ ### Cart Checkout (Multiple Items)
1012
+
1013
+ ```tsx
1014
+ <CedrosPay
1015
+ items={[
1016
+ { resource: "product-1", quantity: 2 },
1017
+ { resource: "product-2", quantity: 1 },
1018
+ ]}
1019
+ callbacks={{
1020
+ onPaymentSuccess: (result) => processOrder(result.transactionId),
1021
+ }}
1022
+ />
1023
+ ```
1024
+
1025
+ ### Coupon Codes
1026
+
1027
+ ```tsx
1028
+ <CedrosPay
1029
+ resource="premium-content"
1030
+ checkout={{
1031
+ couponCode: "LAUNCH50", // Pass from user input or auto-apply
1032
+ }}
1033
+ />
1034
+ ```
1035
+
1036
+ **Coupon Stacking Supported!** Unlimited auto-apply coupons can stack with 1 manual coupon code. Percentage discounts apply first (multiplicatively), then fixed discounts are subtracted.
1037
+
1038
+ #### Two-Phase Coupon System
1039
+
1040
+ Coupons are applied in two phases to provide clear pricing transparency:
1041
+
1042
+ 1. **Catalog-level coupons** - Product-specific discounts shown on product pages
1043
+
1044
+ - Configured with `applies_at: catalog` and specific `product_ids`
1045
+ - Example: "20% off this specific item"
1046
+ - Discounted price shown immediately when viewing the product
1047
+
1048
+ 2. **Checkout-level coupons** - Site-wide promotions applied at cart
1049
+ - Configured with `applies_at: checkout` and `scope: all`
1050
+ - Example: "10% off your entire order"
1051
+ - Applied after catalog discounts at checkout
1052
+
1053
+ **Single Product Quote Response:**
1054
+
1055
+ ```json
1056
+ {
1057
+ "crypto": {
1058
+ "maxAmountRequired": "184000", // Actual amount to charge (atomic units)
1059
+ "extra": {
1060
+ "original_amount": "1.000000",
1061
+ "discounted_amount": "0.184000",
1062
+ "applied_coupons": "PRODUCT20,SITE10,CRYPTO5AUTO,FIXED5", // All applied
1063
+ "catalog_coupons": "PRODUCT20", // Product-specific
1064
+ "checkout_coupons": "SITE10,CRYPTO5AUTO,FIXED5", // Site-wide
1065
+ "decimals": 6
1066
+ }
1067
+ }
1068
+ }
1069
+ ```
1070
+
1071
+ **Cart Quote Response:**
1072
+
1073
+ ```json
1074
+ {
1075
+ "totalAmount": 2.7661,
1076
+ "metadata": {
1077
+ "subtotal_after_catalog": "3.820000",
1078
+ "discounted_amount": "2.766100",
1079
+ "catalog_coupons": "PRODUCT20",
1080
+ "checkout_coupons": "SITE10,CRYPTO5AUTO,FIXED5",
1081
+ "coupon_codes": "PRODUCT20,SITE10,CRYPTO5AUTO,FIXED5"
1082
+ },
1083
+ "items": [
1084
+ {
1085
+ "resource": "item-1",
1086
+ "priceAmount": 0.8, // After catalog discount
1087
+ "originalPrice": 1.0,
1088
+ "appliedCoupons": ["PRODUCT20"]
1089
+ }
1090
+ ]
1091
+ }
1092
+ ```
1093
+
1094
+ **Display Guidelines:**
1095
+
1096
+ - **Product pages:** Show strikethrough original price with catalog discount
1097
+ - **Cart:** Show catalog discounts on items, checkout discounts in summary
1098
+ - **Always use `maxAmountRequired` for actual transactions** - `extra` fields are display-only
1099
+
1100
+ Coupons are configured server-side with:
1101
+
1102
+ - Percentage or fixed amount discounts
1103
+ - Expiration dates
1104
+ - Usage limits
1105
+ - Auto-apply functionality
1106
+ - Payment method filtering (Stripe-only, x402-only, or both)
1107
+ - Phase configuration (`applies_at: catalog` or `checkout`)
1108
+
1109
+ After a successful x402 payment, parse applied coupons from the settlement response:
1110
+
1111
+ ```tsx
1112
+ import {
1113
+ parseCouponCodes,
1114
+ calculateDiscountPercentage,
1115
+ } from "@cedros/pay-react";
1116
+
1117
+ // Parse applied coupons
1118
+ const appliedCoupons = parseCouponCodes(settlement.metadata);
1119
+ // ["SITE10", "CRYPTO5AUTO", "SAVE20"]
1120
+
1121
+ // Calculate total discount percentage
1122
+ const discountPercent = calculateDiscountPercentage(
1123
+ parseFloat(settlement.metadata.original_amount),
1124
+ parseFloat(settlement.metadata.discounted_amount)
1125
+ );
1126
+ ```
1127
+
1128
+ ### Theme Customization
1129
+
1130
+ ```tsx
1131
+ <CedrosProvider
1132
+ config={{
1133
+ stripePublicKey: "pk_test_...",
1134
+ serverUrl: window.location.origin,
1135
+ solanaCluster: "mainnet-beta",
1136
+ theme: "dark", // "light" or "dark"
1137
+ themeOverrides: {
1138
+ stripeBackground: "#6366f1",
1139
+ cryptoBackground: "#0ea5e9",
1140
+ buttonBorderRadius: "12px",
1141
+ },
1142
+ }}
1143
+ >
1144
+ {/* Your app */}
1145
+ </CedrosProvider>
1146
+ ```
1147
+
1148
+ ### Unstyled Mode (Custom Design Systems)
1149
+
1150
+ For complete control over styling, use the `unstyled` prop to disable all default styles:
1151
+
1152
+ ```tsx
1153
+ <CedrosProvider
1154
+ config={{
1155
+ stripePublicKey: "pk_test_...",
1156
+ serverUrl: window.location.origin,
1157
+ solanaCluster: "mainnet-beta",
1158
+ unstyled: true, // Disables all default CSS classes and styles
1159
+ }}
1160
+ >
1161
+ <CedrosPay
1162
+ resource="item-id"
1163
+ display={{ className: "my-custom-button-class" }}
1164
+ />
1165
+ </CedrosProvider>
1166
+ ```
1167
+
1168
+ **Why use unstyled mode?**
1169
+
1170
+ - Build custom design systems without fighting CSS specificity
1171
+ - Use your own CSS framework (Tailwind, Material UI, etc.)
1172
+ - Full control over component appearance and behavior
1173
+ - No need to override or reset default styles
1174
+
1175
+ **What gets disabled:**
1176
+
1177
+ - All `cedros-theme__*` CSS classes
1178
+ - Default inline styles from theme tokens
1179
+ - Button styling (stripe/crypto gradients, hover effects)
1180
+ - Error/success message styling
1181
+
1182
+ **What you still get:**
1183
+
1184
+ - All payment logic and wallet integration
1185
+ - Event handlers and callbacks
1186
+ - Component structure and behavior
1187
+ - Props like `className` for your custom styling
1188
+
1189
+ ---
1190
+
1191
+ ## 🎛️ Props Reference
1192
+
1193
+ ### CedrosProvider Configuration
1194
+
1195
+ | Prop | Type | Description |
1196
+ | ----------------------------- | ----------------------------------------- | -------------------------------------------------------------------------------------------------------------------------------------------------------------- |
1197
+ | `stripePublicKey` | `string` | Stripe publishable key (required) |
1198
+ | `solanaCluster` | `'mainnet-beta' \| 'devnet' \| 'testnet'` | Solana network (required) |
1199
+ | `serverUrl` | `string` | Backend API URL (defaults to current origin) |
1200
+ | `theme` | `'light' \| 'dark'` | Theme mode (default: 'light') |
1201
+ | `themeOverrides` | `Partial<CedrosThemeTokens>` | Custom theme token overrides |
1202
+ | `unstyled` | `boolean` | Disable all default styles (default: false) |
1203
+ | `solanaEndpoint` | `string` | Custom Solana RPC endpoint |
1204
+ | `tokenMint` | `string` | SPL token mint address (default: USDC) - see [Token Mint Validation](#-token-mint-validation) |
1205
+ | `dangerouslyAllowUnknownMint` | `boolean` | Allow unknown token mints (default: false) - ⚠️ WARNING: Only enable after triple-checking mint address - see [Token Mint Validation](#-token-mint-validation) |
1206
+ | `logLevel` | `LogLevel` | Logging verbosity (default: `LogLevel.WARN` in production, `LogLevel.DEBUG` in development) - see [Logging](#-logging) |
1207
+
1208
+ ### CedrosPay Component
1209
+
1210
+ | Prop | Type | Description |
1211
+ | ----------- | ----------------- | ------------------------------------------------------------ |
1212
+ | `resource` | `string` | Single resource ID (use this OR items) |
1213
+ | `items` | `CartItem[]` | Array of cart items (use this OR resource) |
1214
+ | `checkout` | `CheckoutOptions` | Customer email, coupons, redirects, metadata |
1215
+ | `display` | `DisplayOptions` | Labels, visibility (showCard, showCrypto), layout, className |
1216
+ | `callbacks` | `CallbackOptions` | onPaymentSuccess, onPaymentError, onPaymentAttempt |
1217
+ | `advanced` | `AdvancedOptions` | Custom wallets, autoDetectWallets, testPageUrl |
1218
+
1219
+ #### Checkout Options
1220
+
1221
+ | Field | Type | Description |
1222
+ | --------------- | ------------------------ | ---------------------------------- |
1223
+ | `customerEmail` | `string` | Pre-fill email for Stripe checkout |
1224
+ | `couponCode` | `string` | Coupon code to apply |
1225
+ | `successUrl` | `string` | Stripe redirect URL on success |
1226
+ | `cancelUrl` | `string` | Stripe redirect URL on cancel |
1227
+ | `metadata` | `Record<string, string>` | Custom tracking data |
1228
+
1229
+ #### Display Options
1230
+
1231
+ | Field | Type | Description |
1232
+ | ------------- | ---------------------------- | ----------------------------------- |
1233
+ | `cardLabel` | `string` | Stripe button label |
1234
+ | `cryptoLabel` | `string` | Crypto button label |
1235
+ | `showCard` | `boolean` | Show Stripe button (default: true) |
1236
+ | `showCrypto` | `boolean` | Show crypto button (default: true) |
1237
+ | `layout` | `'vertical' \| 'horizontal'` | Button layout (default: 'vertical') |
1238
+ | `className` | `string` | Custom CSS class |
1239
+
1240
+ #### Callback Options
1241
+
1242
+ | Field | Type | Description |
1243
+ | ------------------ | ---------------------------------------- | ---------------------------- |
1244
+ | `onPaymentSuccess` | `(result: PaymentSuccessResult) => void` | Called on successful payment |
1245
+ | `onPaymentError` | `(error: PaymentErrorDetail) => void` | Called on payment error |
1246
+ | `onPaymentAttempt` | `(method: 'stripe' \| 'crypto') => void` | Called when payment starts |
1247
+
1248
+ [Full API Reference →](https://github.com/CedrosPay/react/tree/main/stories)
1249
+
1250
+ ---
1251
+
1252
+ ## ⚠️ Token Mint Validation
1253
+
1254
+ **CRITICAL:** Typos in token mint addresses result in payments being sent to the wrong token, causing **permanent loss of funds**.
1255
+
1256
+ Cedros Pay includes **strict validation** against known stablecoin addresses to prevent catastrophic misconfigurations. If you specify a `tokenMint` that doesn't match a known stablecoin, **initialization will fail with an error**.
1257
+
1258
+ ### Known Stablecoins (mainnet-beta)
1259
+
1260
+ | Symbol | Mint Address |
1261
+ | ------ | ---------------------------------------------- |
1262
+ | USDC | `EPjFWdd5AufqSSqeM2qN1xzybapC8G4wEGGkZwyTDt1v` |
1263
+ | USDT | `Es9vMFrzaCERmJfrF4H2FYD4KCoNkY11McCe8BenwNYB` |
1264
+ | PYUSD | `2b1kV6DkPAnxd5ixfnxCpjxmKwqjjaYmCZfHsFu24GXo` |
1265
+ | CASH | `CASHx9KJUStyftLFWGvEVf59SGeG9sh5FfcnZMVPCASH` |
1266
+
1267
+ ### Strict Mode (Default)
1268
+
1269
+ By default, unknown token mints throw an error:
1270
+
1271
+ ```tsx
1272
+ <CedrosProvider
1273
+ config={{
1274
+ stripePublicKey: "pk_test_...",
1275
+ serverUrl: window.location.origin,
1276
+ solanaCluster: "mainnet-beta",
1277
+ tokenMint: "EPjFWdd5AufqSSqeM2qN1xzybapC8G4wEGGkZwyTDt1v" // ✅ USDC - works
1278
+ }}
1279
+ >
1280
+ {/* ... */}
1281
+ </CedrosProvider>
1282
+
1283
+ // Using an unknown token mint throws an error:
1284
+ <CedrosProvider
1285
+ config={{
1286
+ stripePublicKey: "pk_test_...",
1287
+ serverUrl: window.location.origin,
1288
+ solanaCluster: "devnet",
1289
+ tokenMint: "CustomTokenMint123..." // ❌ Throws error: SAFETY ERROR
1290
+ }}
1291
+ >
1292
+ {/* ... */}
1293
+ </CedrosProvider>
1294
+ ```
1295
+
1296
+ **Error Message:**
1297
+
1298
+ ```
1299
+ SAFETY ERROR: Unrecognized token mint address in CedrosConfig.tokenMint
1300
+ Provided: CustomTokenMint123...
1301
+
1302
+ This token mint does not match any known stablecoin addresses.
1303
+ Using an unknown token mint can result in PERMANENT LOSS OF FUNDS if it's a typo.
1304
+
1305
+ Known stablecoin mints (mainnet-beta):
1306
+ USDC: EPjFWdd5AufqSSqeM2qN1xzybapC8G4wEGGkZwyTDt1v
1307
+ USDT: Es9vMFrzaCERmJfrF4H2FYD4KCoNkY11McCe8BenwNYB
1308
+ PYUSD: 2b1kV6DkPAnxd5ixfnxCpjxmKwqjjaYmCZfHsFu24GXo
1309
+ CASH: CASHx9KJUStyftLFWGvEVf59SGeG9sh5FfcnZMVPCASH
1310
+
1311
+ If you are CERTAIN this is the correct mint address (custom token, testnet, or new stablecoin),
1312
+ set dangerouslyAllowUnknownMint={true} in your CedrosProvider config.
1313
+ ```
1314
+
1315
+ ### Permissive Mode (Opt-in)
1316
+
1317
+ For custom tokens, testnet tokens, or new stablecoins, you must explicitly opt-in:
1318
+
1319
+ ```tsx
1320
+ <CedrosProvider
1321
+ config={{
1322
+ stripePublicKey: "pk_test_...",
1323
+ serverUrl: window.location.origin,
1324
+ solanaCluster: "devnet",
1325
+ tokenMint: "CustomTokenMint123...", // Custom token
1326
+ dangerouslyAllowUnknownMint: true, // ⚠️ Explicit opt-in required
1327
+ }}
1328
+ >
1329
+ {/* ... */}
1330
+ </CedrosProvider>
1331
+ ```
1332
+
1333
+ **⚠️ WARNING:** Only enable `dangerouslyAllowUnknownMint` if you have **TRIPLE-CHECKED** the mint address. A typo will result in permanent loss of funds.
1334
+
1335
+ ### Validation Points
1336
+
1337
+ Strict validation runs at **three points** to protect against fund loss:
1338
+
1339
+ 1. **Config initialization** - When `<CedrosProvider>` mounts
1340
+ 2. **Payment quote** - When backend returns x402 quote with `asset` field
1341
+ 3. **Runtime** - When building Solana transactions
1342
+
1343
+ **Best Practices:**
1344
+
1345
+ 1. ✅ Use known stablecoin mints in production (USDC, USDT, PYUSD, CASH)
1346
+ 2. ✅ Triple-check any custom mint addresses before enabling `dangerouslyAllowUnknownMint`
1347
+ 3. ✅ Test thoroughly on devnet before deploying to mainnet
1348
+ 4. ❌ Never copy-paste mint addresses without verification
1349
+ 5. ❌ Never use `dangerouslyAllowUnknownMint` unless absolutely necessary
1350
+
1351
+ ---
1352
+
1353
+ ## 📊 Logging
1354
+
1355
+ Cedros Pay includes structured logging with configurable log levels to control verbosity and keep production logs clean.
1356
+
1357
+ ### Log Levels
1358
+
1359
+ ```typescript
1360
+ import { LogLevel } from "@cedros/pay-react";
1361
+
1362
+ export enum LogLevel {
1363
+ DEBUG = 0, // Detailed debug information (verbose)
1364
+ INFO = 1, // Informational messages
1365
+ WARN = 2, // Warnings and potentially problematic situations
1366
+ ERROR = 3, // Error messages only
1367
+ SILENT = 4, // No logging
1368
+ }
1369
+ ```
1370
+
1371
+ ### Default Behavior
1372
+
1373
+ - **Development:** `LogLevel.DEBUG` (show all logs)
1374
+ - **Production:** `LogLevel.WARN` (warnings and errors only)
1375
+
1376
+ ### Configuration
1377
+
1378
+ Control logging verbosity via the `logLevel` prop:
1379
+
1380
+ ```typescript
1381
+ import { CedrosProvider, LogLevel } from '@cedros/pay-react';
1382
+
1383
+ // Production: Only show errors
1384
+ <CedrosProvider
1385
+ config={{
1386
+ stripePublicKey: "pk_live_...",
1387
+ serverUrl: window.location.origin,
1388
+ solanaCluster: "mainnet-beta",
1389
+ logLevel: LogLevel.ERROR
1390
+ }}
1391
+ >
1392
+ <App />
1393
+ </CedrosProvider>
1394
+
1395
+ // Development: Show all logs (default)
1396
+ <CedrosProvider
1397
+ config={{
1398
+ stripePublicKey: "pk_test_...",
1399
+ serverUrl: window.location.origin,
1400
+ solanaCluster: "devnet",
1401
+ logLevel: LogLevel.DEBUG
1402
+ }}
1403
+ >
1404
+ <App />
1405
+ </CedrosProvider>
1406
+
1407
+ // CI/Testing: Silence all logs
1408
+ <CedrosProvider
1409
+ config={{
1410
+ stripePublicKey: "pk_test_...",
1411
+ serverUrl: window.location.origin,
1412
+ solanaCluster: "devnet",
1413
+ logLevel: LogLevel.SILENT
1414
+ }}
1415
+ >
1416
+ <App />
1417
+ </CedrosProvider>
1418
+ ```
1419
+
1420
+ ### Advanced Usage
1421
+
1422
+ For custom logging or integration with your logging infrastructure:
1423
+
1424
+ ```typescript
1425
+ import { createLogger, LogLevel } from "@cedros/pay-react";
1426
+
1427
+ // Create a custom logger instance
1428
+ const logger = createLogger({
1429
+ level: LogLevel.INFO,
1430
+ prefix: "[MyApp]", // Optional prefix for all logs
1431
+ });
1432
+
1433
+ // Use directly
1434
+ logger.debug("Debug message");
1435
+ logger.info("Info message");
1436
+ logger.warn("Warning message");
1437
+ logger.error("Error message");
1438
+
1439
+ // Update log level dynamically
1440
+ logger.setLevel(LogLevel.ERROR);
1441
+ ```
1442
+
1443
+ ### Log Format
1444
+
1445
+ All logs include timestamps and severity levels:
1446
+
1447
+ ```
1448
+ [2025-11-09T10:43:12.345Z] [CedrosPay] [WARN] Token mint validation warning...
1449
+ [2025-11-09T10:43:15.678Z] [CedrosPay] [ERROR] Payment verification failed
1450
+ ```
1451
+
1452
+ ### Best Practices
1453
+
1454
+ 1. **Production:** Use `LogLevel.ERROR` or `LogLevel.WARN` to avoid exposing sensitive data
1455
+ 2. **Development:** Use `LogLevel.DEBUG` to troubleshoot payment flows
1456
+ 3. **CI/Testing:** Use `LogLevel.SILENT` to keep test output clean
1457
+ 4. **Monitoring:** Integrate with your logging infrastructure (Datadog, Sentry, etc.)
1458
+
1459
+ ---
1460
+
1461
+ ## 🪄 Example Use Cases
1462
+
1463
+ - Paywalled blog or API monetization
1464
+ - Agent-to-agent microtransactions
1465
+ - Subscription and one-time digital content unlocks
1466
+ - AI service pay-per-call endpoints
1467
+
1468
+ ---
1469
+
1470
+ ## 🔒 API Stability & Versioning
1471
+
1472
+ Cedros Pay is designed for enterprise use with a strong commitment to API stability.
1473
+
1474
+ ### Semantic Versioning
1475
+
1476
+ We follow [Semantic Versioning](https://semver.org/):
1477
+
1478
+ - **Major (x.0.0)**: Breaking changes, API removals
1479
+ - **Minor (0.x.0)**: New features, backwards-compatible additions
1480
+ - **Patch (0.0.x)**: Bug fixes, no API changes
1481
+
1482
+ ### Stable API Surface
1483
+
1484
+ **These exports are guaranteed stable** and follow semantic versioning:
1485
+
1486
+ - ✅ **Components** - All exported React components (CedrosPay, StripeButton, CryptoButton, etc.)
1487
+ - ✅ **Hooks** - useCedrosContext, useStripeCheckout, useX402Payment, etc.
1488
+ - ✅ **Manager Interfaces** - IStripeManager, IX402Manager, IWalletManager, IRouteDiscoveryManager
1489
+ - ✅ **Types** - All types exported via versioned namespaces (v1, v2, etc.)
1490
+ - ✅ **Utilities** - validateConfig, parseCouponCodes, rate limiters, logging, events
1491
+
1492
+ **Use interfaces, not concrete classes:**
1493
+
1494
+ ```typescript
1495
+ // ✅ CORRECT: Use interface from context
1496
+ import { useCedrosContext } from '@cedros/pay-react';
1497
+
1498
+ function MyComponent() {
1499
+ const { stripeManager } = useCedrosContext();
1500
+ // stripeManager is typed as IStripeManager (stable)
1501
+ await stripeManager.processPayment({ ... });
1502
+ }
1503
+
1504
+ // ❌ WRONG: Direct class import (unsupported)
1505
+ import { StripeManager } from '@cedros/pay-react'; // Not exported
1506
+ const manager = new StripeManager(...); // Will break
1507
+ ```
1508
+
1509
+ ### Deprecation Process
1510
+
1511
+ When APIs are deprecated:
1512
+
1513
+ 1. **Deprecation Notice** - Warning logged, replacement documented
1514
+ 2. **Minimum 3 months** - Grace period for migration
1515
+ 3. **Migration Guide** - Step-by-step upgrade instructions
1516
+ 4. **Major Version** - Removal in next major release only
1517
+
1518
+ **Example Timeline:**
1519
+
1520
+ - v2.1.0: Deprecate oldAPI, introduce newAPI
1521
+ - v2.2.0 - v2.x: Both supported, warnings logged
1522
+ - v3.0.0: Remove oldAPI, only newAPI available
1523
+
1524
+ ### Type Versioning
1525
+
1526
+ Types use versioned namespaces to prevent breaking changes:
1527
+
1528
+ ```typescript
1529
+ // Top-level exports (current stable version)
1530
+ import { X402Requirement } from '@cedros/pay-react';
1531
+
1532
+ // Explicit version (locks to v1, won't break on v2)
1533
+ import { v1 } from '@cedros/pay-react';
1534
+ const req: v1.X402Requirement = { ... };
1535
+
1536
+ // Future version
1537
+ import { v2 } from '@cedros/pay-react';
1538
+ const newReq: v2.X402Requirement = { ... };
1539
+ ```
1540
+
1541
+ **Read more:** See [API_STABILITY.md](./API_STABILITY.md) for our complete stability policy.
1542
+
1543
+ ---
1544
+
1545
+ ## 📡 Error Telemetry (Optional)
1546
+
1547
+ Cedros Pay includes **opt-in error telemetry** with correlation IDs for production debugging. Telemetry is **disabled by default** and requires explicit configuration.
1548
+
1549
+ ### Privacy-First Design
1550
+
1551
+ - ✅ **Opt-in only** - No data sent without your explicit configuration
1552
+ - ✅ **User-controlled** - You choose what service to use (Sentry, Datadog, custom, or none)
1553
+ - ✅ **PII sanitization** - Private keys, wallet addresses, emails automatically redacted
1554
+ - ✅ **No hidden network calls** - Data only sent via your callback function
1555
+
1556
+ ### Quick Start
1557
+
1558
+ ```typescript
1559
+ import { configureTelemetry, ErrorSeverity } from "@cedros/pay-react";
1560
+ import * as Sentry from "@sentry/react";
1561
+
1562
+ // Enable telemetry with Sentry
1563
+ configureTelemetry({
1564
+ enabled: true,
1565
+ sdkVersion: "2.0.0",
1566
+ environment: process.env.NODE_ENV,
1567
+ sanitizePII: true, // ALWAYS keep enabled
1568
+ onError: (error) => {
1569
+ Sentry.captureException(error.error, {
1570
+ extra: {
1571
+ correlationId: error.correlationId,
1572
+ paymentContext: error.paymentContext,
1573
+ },
1574
+ tags: error.tags,
1575
+ level: error.severity,
1576
+ });
1577
+ },
1578
+ });
1579
+ ```
1580
+
1581
+ ### Features
1582
+
1583
+ - **Correlation IDs** - Track errors across distributed systems
1584
+ - **Error Enrichment** - Add payment context (method, stage, amount) without PII
1585
+ - **PII Sanitization** - 15+ patterns including:
1586
+ - Private keys (Solana, Ethereum)
1587
+ - Wallet addresses
1588
+ - Seed phrases
1589
+ - API keys, JWT tokens
1590
+ - Credit cards, emails, phone numbers
1591
+ - **Integration Examples** - Sentry, Datadog, custom backends
1592
+
1593
+ ### Security Guarantees
1594
+
1595
+ ```typescript
1596
+ /**
1597
+ * SECURITY GUARANTEE:
1598
+ * - NEVER logs private keys, seed phrases, or wallet credentials
1599
+ * - NEVER sends data without explicit user configuration
1600
+ * - Sanitization ENABLED BY DEFAULT and cannot be fully disabled
1601
+ * - All sensitive crypto data patterns are redacted automatically
1602
+ */
1603
+ ```
1604
+
1605
+ ### Correlation IDs for Support
1606
+
1607
+ ```typescript
1608
+ import { generateCorrelationId } from "@cedros/pay-react";
1609
+
1610
+ function PaymentButton() {
1611
+ const [correlationId] = useState(generateCorrelationId());
1612
+
1613
+ const handleError = (error: Error) => {
1614
+ reportError(error, { correlationId });
1615
+
1616
+ // Show correlation ID to user for support
1617
+ alert(`Payment failed. Support ID: ${correlationId}`);
1618
+ };
1619
+ }
1620
+ ```
1621
+
1622
+ **Full Integration Guide:** See [TELEMETRY_INTEGRATIONS.md](./TELEMETRY_INTEGRATIONS.md) for complete examples with Sentry, Datadog, and custom backends.
1623
+
1624
+ ---
1625
+
1626
+ ## 🧭 Roadmap
1627
+
1628
+ - Stripe + x402 unified dashboard
1629
+ - Subscription management
1630
+ - Facilitator integrations (PayAI, Kora)
1631
+ - Typed SDKs for Go, Node, and Python agents
1632
+
1633
+ ---
1634
+
1635
+ **Cedros Pay** — _rooted in Solana, built for the web._
1636
+
1637
+ ## 🎨 Storybook Development
1638
+
1639
+ ### Setup
1640
+
1641
+ 1. **Copy the environment template:**
1642
+
1643
+ ```bash
1644
+ cp .env.example .env
1645
+ ```
1646
+
1647
+ 2. **Configure your credentials:**
1648
+
1649
+ Edit `.env` and add your keys:
1650
+
1651
+ ```bash
1652
+ # Stripe test key (required for card payments)
1653
+ VITE_STRIPE_PUBLIC_KEY=pk_test_your_key_here
1654
+
1655
+ # Solana RPC endpoint (required for crypto payments)
1656
+ VITE_SOLANA_RPC_URL=https://your-rpc-endpoint/
1657
+
1658
+ # Backend server URL
1659
+ VITE_SERVER_URL=http://localhost:8080
1660
+ ```
1661
+
1662
+ **⚠️ Required for testing:**
1663
+
1664
+ - **Stripe:** Get a test key from [Stripe Dashboard](https://dashboard.stripe.com/test/apikeys)
1665
+ - **Solana RPC:** Public RPCs have strict rate limits. Get a free endpoint from:
1666
+ - [Helius](https://www.helius.dev/) (recommended)
1667
+ - [QuickNode](https://www.quicknode.com/)
1668
+ - [Alchemy](https://www.alchemy.com/)
1669
+
1670
+ 3. **Run Storybook:**
1671
+ ```bash
1672
+ npm run storybook
1673
+ ```
1674
+
1675
+ ### Troubleshooting
1676
+
1677
+ **Error: "Endpoint URL must start with `http:` or `https:`"**
1678
+
1679
+ This means `VITE_SOLANA_RPC_URL` or `VITE_STORYBOOK_SOLANA_ENDPOINT` is missing or empty in your `.env` file.
1680
+
1681
+ **Fix:**
1682
+ ```bash
1683
+ # Add to .env
1684
+ VITE_SOLANA_RPC_URL=https://api.devnet.solana.com
1685
+ # Or for Storybook-specific override:
1686
+ VITE_STORYBOOK_SOLANA_ENDPOINT=https://api.devnet.solana.com
1687
+ ```
1688
+
1689
+ **Error: "Invalid Cedros configuration: serverUrl must be a non-empty string"**
1690
+
1691
+ The `VITE_SERVER_URL` or `VITE_STORYBOOK_SERVER_URL` is missing.
1692
+
1693
+ **Fix:**
1694
+ ```bash
1695
+ # Add to .env
1696
+ VITE_SERVER_URL=http://localhost:8080
1697
+ ```
1698
+
1699
+ ### Environment Variables
1700
+
1701
+ | Variable | Description | Required |
1702
+ | -------------------------------- | --------------------------------- | ------------------------------------- |
1703
+ | `VITE_STRIPE_PUBLIC_KEY` | Stripe publishable key | ✅ For card payments |
1704
+ | `VITE_SERVER_URL` | Backend API endpoint | ✅ (default: `http://localhost:8080`) |
1705
+ | `VITE_SOLANA_CLUSTER` | Solana network | Optional (default: `mainnet-beta`) |
1706
+ | `VITE_SOLANA_RPC_URL` | Custom Solana RPC | ✅ For crypto payments |
1707
+ | `VITE_STORYBOOK_SERVER_URL` | Override server URL for Storybook | Optional |
1708
+ | `VITE_STORYBOOK_SOLANA_ENDPOINT` | Override RPC for Storybook | Optional |
1709
+
1710
+ ## 🤝 Contributing
1711
+
1712
+ We welcome contributions! Please see [CONTRIBUTING.md](./CONTRIBUTING.md) for guidelines on:
1713
+
1714
+ - Development setup and workflow
1715
+ - Code standards and architecture principles
1716
+ - Testing requirements
1717
+ - PR submission process
1718
+ - Security guidelines
1719
+
1720
+ Before submitting a PR, make sure all tests pass:
1721
+
1722
+ ```bash
1723
+ npm run lint
1724
+ npm run type-check
1725
+ npm test
1726
+ npm run test:coverage
1727
+ ```
1728
+
1729
+ ## 📄 License
1730
+
1731
+ MIT License - see [LICENSE](./LICENSE) for details.