@inflow_pay/sdk 0.7.0 → 1.0.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.
package/README.md CHANGED
@@ -1,6 +1,14 @@
1
- # InflowPay Iframe-based Payment SDK
1
+ # InflowPay SDK v2
2
2
 
3
- Accept card payments with a pre-built, secure payment form. Uses an iframe-based architecture for enhanced security and easy integration.
3
+ Accept card payments with a secure, iframe-based payment form. This version delivers **enhanced security**, a **built-in success UI**, and **automatic 3D Secure handling** - all with just a few lines of code.
4
+
5
+ ## What's Best in This Version
6
+
7
+ - 🔒 **Iframe Architecture**: Card data never touches your server (PCI compliant)
8
+ - ✨ **Built-in Success UI**: Beautiful success screen automatically shown after payment - fully customizable or replaceable
9
+ - 🎯 **Auto 3D Secure**: SDK handles authentication modals automatically
10
+ - 🚀 **Zero Configuration**: Works out of the box with sensible defaults
11
+ - 🎨 **Fully Customizable**: Match your brand with comprehensive styling options
4
12
 
5
13
  ## Installation
6
14
 
@@ -8,80 +16,165 @@ Accept card payments with a pre-built, secure payment form. Uses an iframe-based
8
16
  npm install @inflow_pay/sdk
9
17
  ```
10
18
 
11
- Or use via CDN (jsDelivr) - **for vanilla HTML pages only**:
19
+ **CDN Option** (vanilla HTML pages only):
12
20
 
13
21
  ```html
14
- <!-- Main SDK (vanilla JavaScript) -->
15
- <script src="https://cdn.jsdelivr.net/npm/@inflow_pay/sdk@0.7.0/dist/sdk.umd.js"></script>
22
+ <script src="https://cdn.jsdelivr.net/npm/@inflow_pay/sdk@1.0.0/dist/sdk.umd.js"></script>
23
+ ```
24
+
25
+ ## Complete Example
26
+
27
+ ### Backend: Create Payment
28
+
29
+ ```javascript
30
+ // backend/api/create-payment.js
31
+ app.post('/api/create-payment', async (req, res) => {
32
+ const response = await fetch('https://api.inflowpay.xyz/api/server/payment', {
33
+ method: 'POST',
34
+ headers: {
35
+ 'Content-Type': 'application/json',
36
+ 'X-Inflow-Api-Key': process.env.INFLOW_PRIVATE_KEY
37
+ },
38
+ body: JSON.stringify({
39
+ products: [{ name: 'Product', price: 4999, quantity: 1 }],
40
+ currency: 'EUR',
41
+ customerEmail: 'customer@example.com',
42
+ firstName: 'John',
43
+ lastName: 'Doe',
44
+ billingCountry: 'FR',
45
+ postalCode: '75001'
46
+ })
47
+ });
48
+
49
+ const data = await response.json();
50
+ res.json({ paymentId: data.payment.id });
51
+ });
52
+ ```
53
+
54
+ ### Frontend: React
55
+
56
+ ```tsx
57
+ import { InflowPayProvider, CardElement, PaymentResultStatus } from '@inflow_pay/sdk/react';
58
+
59
+ export default function CheckoutPage() {
60
+ const [paymentId, setPaymentId] = useState<string | null>(null);
61
+
62
+ useEffect(() => {
63
+ fetch('/api/create-payment', { method: 'POST' })
64
+ .then(res => res.json())
65
+ .then(data => setPaymentId(data.paymentId));
66
+ }, []);
67
+
68
+ if (!paymentId) return <div>Loading...</div>;
69
+
70
+ return (
71
+ <InflowPayProvider config={{ publicKey: 'inflow_pub_xxx' }}>
72
+ <CardElement
73
+ paymentId={paymentId}
74
+ showDefaultSuccessUI={true}
75
+ onComplete={(result) => {
76
+ if (result.status === PaymentResultStatus.SUCCESS) {
77
+ setTimeout(() => window.location.href = '/confirmation', 2000);
78
+ }
79
+ }}
80
+ style={{
81
+ fontFamily: 'Inter',
82
+ button: { backgroundColor: '#0070F3', textColor: '#FFFFFF' }
83
+ }}
84
+ />
85
+ </InflowPayProvider>
86
+ );
87
+ }
88
+ ```
89
+
90
+ ### Frontend: Vanilla JavaScript
91
+
92
+ ```html
93
+ <div id="card-container"></div>
94
+
95
+ <script src="https://cdn.jsdelivr.net/npm/@inflow_pay/sdk@0.8.0/dist/sdk.umd.js"></script>
16
96
  <script>
17
- // SDK is available as window.InflowPaySDK
18
97
  const provider = new InflowPaySDK.InflowPayProvider({
19
- config: { apiKey: 'inflow_pub_xxx' }
98
+ config: { publicKey: 'inflow_pub_xxx' }
20
99
  });
100
+
101
+ fetch('/api/create-payment', { method: 'POST' })
102
+ .then(res => res.json())
103
+ .then(data => {
104
+ const cardElement = provider.createCardElement({
105
+ paymentId: data.paymentId,
106
+ container: '#card-container',
107
+ showDefaultSuccessUI: true,
108
+ onComplete: (result) => {
109
+ if (result.status === InflowPaySDK.PaymentResultStatus.SUCCESS) {
110
+ setTimeout(() => window.location.href = '/confirmation', 2000);
111
+ }
112
+ }
113
+ });
114
+ cardElement.mount();
115
+ });
21
116
  </script>
22
117
  ```
23
118
 
24
- **Note:**
25
- - The example uses exact version `@0.7.0` for production safety (prevents unexpected changes)
26
- - You can update to newer versions manually when ready (e.g., `@0.7.0`)
27
- - If you're building a React app (create-react-app, Next.js, etc.), use `npm install` instead of CDN. See [Migration from React SDK](#migration-from-react-sdk) section.
119
+ ## Built-in Success UI Explained
28
120
 
29
- ## Quick Start
121
+ The SDK includes a polished success screen that appears automatically after successful payment:
30
122
 
31
- Get started with the iframe-based SDK:
123
+ **What it shows:**
124
+ - ✅ Success icon and "Payment successful!" message
125
+ - 💳 Payment amount (when available from your payment data)
126
+ - 🎨 Automatically matches your brand colors and theme
127
+ - 🌙 Dark mode support
32
128
 
33
- ```javascript
34
- import { InflowPayProvider } from '@inflow_pay/sdk';
129
+ **How to use it:**
35
130
 
36
- // Step 1: Create InflowPayProvider (same as React's <InflowPayProvider>)
37
- const provider = new InflowPayProvider({
38
- config: { apiKey: 'inflow_pub_xxx' }
131
+ ```javascript
132
+ // Option 1: Use default success UI (recommended)
133
+ const cardElement = provider.createCardElement({
134
+ paymentId: 'pay_xxx',
135
+ container: '#card-container',
136
+ showDefaultSuccessUI: true, // Shows built-in success screen
137
+ onComplete: (result) => {
138
+ if (result.status === PaymentResultStatus.SUCCESS) {
139
+ // Success UI is already showing in the iframe
140
+ // Optional: redirect after 2 seconds
141
+ setTimeout(() => window.location.href = '/confirmation', 2000);
142
+ }
143
+ }
39
144
  });
40
145
 
41
- // Step 2: Create CardElement (same as React's <CardElement>)
146
+ // Option 2: Use your own custom success UI
42
147
  const cardElement = provider.createCardElement({
43
- paymentId: 'pay_xxx', // From your backend
148
+ paymentId: 'pay_xxx',
44
149
  container: '#card-container',
150
+ showDefaultSuccessUI: false, // Iframe unmounts on success
45
151
  onComplete: (result) => {
46
- if (result.status === 'CHECKOUT_SUCCESS') {
47
- window.location.href = '/success';
152
+ if (result.status === PaymentResultStatus.SUCCESS) {
153
+ // Show your custom success UI
154
+ document.getElementById('card-container').innerHTML = `
155
+ <div class="custom-success">
156
+ <h2>Thank you for your purchase!</h2>
157
+ <p>Order ID: ${result.paymentId}</p>
158
+ </div>
159
+ `;
48
160
  }
49
161
  }
50
162
  });
51
-
52
- // Step 3: Mount the CardElement
53
- cardElement.mount();
54
163
  ```
55
164
 
56
- ## How It Works
57
-
58
- 1. **Backend**: Create a payment with billing info (your private key)
59
- 2. **Frontend**: Create `InflowPayProvider` with your API key
60
- 3. **Frontend**: Create `CardElement` with the `paymentId`
61
- 4. **User**: Enters card details and submits
62
- 5. **SDK**: Handles tokenization, 3DS, and payment completion
63
- 6. **Your app**: Receives success/error via callback
64
-
65
- ## Payment Status
165
+ **When to use each option:**
166
+ - **Default UI** (`showDefaultSuccessUI: true`): Quick integration, consistent experience, looks great out of the box
167
+ - **Custom UI** (`showDefaultSuccessUI: false`): Full control when you need custom branding or additional information
66
168
 
67
- Payments progress through these statuses:
169
+ ## Payment Flow
68
170
 
69
- | Status | Description | Success? |
70
- |--------|-------------|----------|
71
- | `CHECKOUT_SUCCESS` | Payment confirmed | Yes |
72
- | `PAYMENT_RECEIVED` | Funds received | ✅ Yes |
73
- | `PAYMENT_SUCCESS` | Complete | Yes |
74
- | `PAYMENT_FAILED` | Failed | No |
75
-
76
- **Check for success:**
77
-
78
- ```javascript
79
- if (result.status === 'CHECKOUT_SUCCESS' ||
80
- result.status === 'PAYMENT_RECEIVED' ||
81
- result.status === 'PAYMENT_SUCCESS') {
82
- // Payment successful
83
- }
84
- ```
171
+ 1. Backend creates payment returns `paymentId`
172
+ 2. Frontend initializes SDK with `paymentId` and public key
173
+ 3. User enters card details in secure iframe
174
+ 4. SDK tokenizes card and processes payment
175
+ 5. 3D Secure authentication (if required) - automatic modal
176
+ 6. Success UI displays (built-in or custom)
177
+ 7. `onComplete` callback fires → redirect or update UI
85
178
 
86
179
  ## API Reference
87
180
 
@@ -90,343 +183,125 @@ if (result.status === 'CHECKOUT_SUCCESS' ||
90
183
  ```javascript
91
184
  const provider = new InflowPayProvider({
92
185
  config: {
93
- apiKey: 'inflow_pub_xxx', // Required
94
- iframeUrl: 'https://...', // Optional, auto-detected from API key
95
- timeout: 30000, // Optional, default: 30000
96
- debug: false // Optional, default: false
186
+ publicKey: 'inflow_pub_xxx', // Required
187
+ locale: 'en' // Optional - defaults to browser language
97
188
  }
98
189
  });
99
190
  ```
100
191
 
192
+ **Supported locales:** `en`, `de`, `es`, `fr`, `it`, `nl`, `pl`, `pt`
193
+
101
194
  ### CardElement
102
195
 
103
196
  ```javascript
104
197
  const cardElement = provider.createCardElement({
105
- paymentId: 'pay_xxx', // Required
106
- container: '#card-container', // Required (CSS selector or HTMLElement)
198
+ paymentId: 'pay_xxx', // Required - from your backend
199
+ container: '#card-container', // Required - CSS selector or HTMLElement
200
+ showDefaultSuccessUI: true, // Optional - default true
107
201
 
108
- // Styling (optional)
109
- style: {
110
- fontFamily: 'Inter',
111
- button: {
112
- backgroundColor: '#0070F3',
113
- textColor: '#FFFFFF'
202
+ // Callbacks
203
+ onComplete: (result) => {
204
+ if (result.status === PaymentResultStatus.SUCCESS) {
205
+ // Payment successful
206
+ } else if (result.status === PaymentResultStatus.FAILED) {
207
+ // Payment failed - result.error contains details
114
208
  }
115
209
  },
116
210
 
117
- // Custom button text (optional)
118
- buttonText: 'Complete Payment',
119
-
120
- // Custom placeholders (optional)
121
- placeholders: {
122
- cardNumber: '1234 5678 9012 3456',
123
- expiry: 'MM/YY',
124
- cvc: 'CVC'
125
- },
126
-
127
- // Callbacks (same as React SDK)
128
211
  onReady: () => {
129
- // Card element is mounted and ready
212
+ // Card element mounted and ready
130
213
  },
131
214
 
132
215
  onChange: (state) => {
133
- // Track validation state
134
216
  // state.complete - whether form is valid
135
217
  },
136
218
 
137
- onComplete: (result) => {
138
- // Payment complete (success or failure)
139
- if (result.error) {
140
- console.error(result.error.message);
141
- }
219
+ onError: (error) => {
220
+ // SDK-level errors
142
221
  },
143
222
 
144
- onError: (error) => {
145
- // SDK-level errors (network, validation)
146
- console.error(error);
223
+ // Styling (optional)
224
+ style: {
225
+ fontFamily: 'Inter',
226
+ button: {
227
+ backgroundColor: '#0070F3',
228
+ textColor: '#FFFFFF'
229
+ }
147
230
  },
148
231
 
149
- onClose: () => {
150
- // User closed the payment
232
+ // Custom text (optional)
233
+ buttonText: 'Pay Now',
234
+ placeholders: {
235
+ cardNumber: '1234 5678 9012 3456',
236
+ expiry: 'MM/YY',
237
+ cvc: 'CVC'
151
238
  }
152
239
  });
153
240
 
154
- // Mount the CardElement
155
241
  cardElement.mount();
156
242
  ```
157
243
 
158
- ### CardElement Methods
159
-
160
- #### `mount(): void`
161
-
162
- Mounts the CardElement to the DOM. This will create and display the iframe.
244
+ ### Payment Result
163
245
 
164
- ```javascript
165
- cardElement.mount();
166
- ```
167
-
168
- #### `destroy(): void`
169
-
170
- Destroys the CardElement and cleans up resources.
171
-
172
- ```javascript
173
- cardElement.destroy();
174
- ```
175
-
176
- ## HTML Example
177
-
178
- ```html
179
- <!DOCTYPE html>
180
- <html>
181
- <head>
182
- <title>My Payment Page</title>
183
- </head>
184
- <body>
185
- <div id="card-container"></div>
186
-
187
- <script src="https://cdn.jsdelivr.net/npm/@inflow_pay/sdk@0.7.0/dist/sdk.umd.js"></script>
188
- <script>
189
- // SDK is available as window.InflowPaySDK
190
- const provider = new InflowPaySDK.InflowPayProvider({
191
- config: { apiKey: 'inflow_pub_xxx' }
192
- });
193
-
194
- const cardElement = provider.createCardElement({
195
- paymentId: 'pay_xxx',
196
- container: '#card-container',
197
- onComplete: (result) => {
198
- if (result.status === InflowPaySDK.PaymentStatus.CHECKOUT_SUCCESS) {
199
- alert('Payment successful!');
200
- }
201
- }
202
- });
203
-
204
- cardElement.mount();
205
- </script>
206
- </body>
207
- </html>
208
- ```
209
-
210
- ## Error Handling
211
-
212
- Errors are automatically mapped to user-friendly messages:
213
-
214
- ```javascript
215
- cardElement.onComplete = (result) => {
216
- if (result.error) {
217
- console.log(result.error.message); // User-friendly
218
- console.log(result.error.retryable); // Can retry?
246
+ ```typescript
247
+ interface PaymentResult {
248
+ status: 'SUCCESS' | 'FAILED';
249
+ paymentId: string;
250
+ error?: {
251
+ code: string; // Error code (e.g., 'THREE_DS_FAILED')
252
+ message: string; // User-friendly message
253
+ retryable: boolean; // Can retry?
219
254
  }
220
- };
221
- ```
222
-
223
- **Common errors:**
224
-
225
- - `card_declined` - Card was declined
226
- - `insufficient_funds` - Not enough funds
227
- - `invalid_card_number` - Invalid card
228
- - `THREE_DS_FAILED` - 3DS authentication failed
229
-
230
- ## 3D Secure
231
-
232
- 3DS is handled automatically. When required:
233
-
234
- 1. SDK opens a modal with the authentication page
235
- 2. User completes authentication
236
- 3. Modal closes automatically
237
- 4. Your `onComplete` callback receives the final result
238
-
239
- **No setup required!** The SDK automatically handles 3DS redirects.
240
-
241
- ## Backend Integration
242
-
243
- Create payments on your backend with your **private key**:
244
-
245
- ```javascript
246
- // Your backend (Node.js example)
247
- const response = await fetch('https://api.inflowpay.xyz/api/server/payment', {
248
- method: 'POST',
249
- headers: {
250
- 'Accept': 'application/json',
251
- 'Content-Type': 'application/json',
252
- 'X-Inflow-Api-Key': 'inflow_priv_xxx' // Private key
253
- },
254
- body: JSON.stringify({
255
- products: [{ name: 'Product', price: 4999, quantity: 1 }],
256
- currency: 'EUR',
257
- customerEmail: 'customer@example.com',
258
- billingCountry: 'FR',
259
- postalCode: '75001',
260
- firstName: 'John',
261
- lastName: 'Doe',
262
- purchasingAsBusiness: false,
263
- successUrl: 'https://yourdomain.com/success',
264
- cancelUrl: 'https://yourdomain.com/cancel'
265
- })
266
- });
267
-
268
- const { payment } = await response.json();
269
- // Send payment.id to your frontend
270
- ```
271
-
272
- See [API documentation](https://docs.inflowpay.com/v0/reference/createpayment) for full backend API reference.
273
-
274
- ## Migration from React SDK
275
-
276
- The iframe-based SDK maintains similar component APIs, but **styling has changed**. You have two options:
277
-
278
- ### Option 1: Keep Using React (Recommended for React Apps)
279
-
280
- If you're using React, you can use the React components with a similar API:
281
-
282
- ```tsx
283
- // Change the import path
284
- import { InflowPayProvider, CardElement } from '@inflow_pay/sdk/react';
285
-
286
- function App() {
287
- return (
288
- <InflowPayProvider config={{ apiKey: 'inflow_pub_xxx' }}>
289
- <CardElement
290
- paymentId={paymentId}
291
- style={{
292
- // ⚠️ Styling API has changed - see Styling section below
293
- fontFamily: 'Inter',
294
- button: {
295
- backgroundColor: '#0070F3',
296
- textColor: '#FFFFFF'
297
- }
298
- }}
299
- onComplete={(result) => {
300
- if (result.status === 'CHECKOUT_SUCCESS') {
301
- window.location.href = '/success';
302
- }
303
- }}
304
- />
305
- </InflowPayProvider>
306
- );
307
255
  }
308
256
  ```
309
257
 
310
- **Important:** The component API is similar, but **styling customization has changed**. See the [Styling](#styling) section for the new styling structure.
311
-
312
- ### Option 2: Vanilla JavaScript (For Non-React Apps)
313
-
314
- If you're not using React, you can use the vanilla JavaScript API:
258
+ ### CardElement Methods
315
259
 
316
260
  ```javascript
317
- import { InflowPayProvider } from '@inflow_pay/sdk';
318
-
319
- const provider = new InflowPayProvider({
320
- config: { apiKey: 'inflow_pub_xxx' }
321
- });
322
-
323
- const cardElement = provider.createCardElement({
324
- paymentId: paymentId,
325
- container: '#card-container',
326
- onComplete: (result) => {
327
- if (result.status === 'CHECKOUT_SUCCESS') {
328
- window.location.href = '/success';
329
- }
330
- }
331
- });
332
-
333
- cardElement.mount();
334
- ```
335
-
336
- **Key differences from React version:**
337
- - No React required - works with vanilla JavaScript
338
- - Explicit `container` prop (CSS selector or HTMLElement) instead of JSX
339
- - Call `mount()` explicitly instead of automatic React mounting
340
- - Same callbacks, same status codes, same error handling
341
- - **Styling API has changed** - see [Styling](#styling) section for details
342
-
343
- ## TypeScript
344
-
345
- Full type definitions included:
346
-
347
- ```typescript
348
- import { InflowPayProvider, PaymentStatus } from '@inflow_pay/sdk';
349
- import type { PaymentResult, PaymentError } from '@inflow_pay/sdk';
350
-
351
- const provider = new InflowPayProvider({
352
- config: { apiKey: 'inflow_pub_xxx' }
353
- });
354
-
355
- const cardElement = provider.createCardElement({
356
- paymentId: 'pay_xxx',
357
- container: '#card-container',
358
- onComplete: (result: PaymentResult) => {
359
- if (result.status === PaymentStatus.CHECKOUT_SUCCESS) {
360
- // Success
361
- }
362
- },
363
- onError: (error: PaymentError) => {
364
- console.error(error);
365
- }
366
- });
261
+ cardElement.mount(); // Mount to DOM
262
+ cardElement.destroy(); // Cleanup and unmount
367
263
  ```
368
264
 
369
265
  ## Styling
370
266
 
371
- The iframe-based SDK provides a comprehensive styling API to match your brand. **Note: The styling structure is different from the original React SDK.** All styles are fully typed with TypeScript.
372
-
373
- ### Basic Styling
267
+ Customize the payment form to match your brand:
374
268
 
375
269
  ```javascript
376
- const cardElement = provider.createCardElement({
377
- paymentId: 'pay_xxx',
378
- container: '#card-container',
379
- style: {
380
- fontFamily: 'Inter',
381
- fillParent: true,
382
- inputContainer: {
383
- backgroundColor: '#F5F5F5',
384
- borderRadius: '8px',
385
- borderEnabled: true,
386
- borderColor: '#E0E0E0'
387
- },
388
- input: {
389
- textColor: '#1A1A1A',
390
- placeholderColor: '#999999'
391
- },
392
- button: {
393
- backgroundColor: '#0070F3',
394
- textColor: '#FFFFFF',
395
- borderRadius: '8px',
396
- fontSize: '16px',
397
- fontWeight: 600,
398
- opacity: 1,
399
- hover: {
400
- backgroundColor: '#0051CC'
401
- },
402
- disabled: {
403
- opacity: 0.5
404
- }
405
- },
406
- dark: {
407
- button: {
408
- backgroundColor: '#0066CC'
409
- }
410
- }
411
- }
412
- });
413
- ```
414
-
415
- ### Dark Mode
416
-
417
- Use the `dark` property to customize dark mode styles:
418
-
419
- ```tsx
420
270
  style: {
421
- fontFamily: 'Inter',
422
- button: {
423
- backgroundColor: '#0070F3',
424
- textColor: '#FFFFFF'
425
- },
271
+ fontFamily: 'Inter', // 'DM Sans' | 'Inter' | 'Poppins' | 'Nunito' | etc.
272
+ fillParent: true,
273
+
274
+ // Input container
426
275
  inputContainer: {
427
- backgroundColor: '#FFFFFF',
276
+ backgroundColor: '#F5F5F5',
277
+ borderRadius: '8px',
278
+ borderEnabled: true,
428
279
  borderColor: '#E0E0E0'
429
280
  },
281
+
282
+ // Input fields
283
+ input: {
284
+ textColor: '#1A1A1A',
285
+ placeholderColor: '#999999',
286
+ backgroundColor: 'transparent'
287
+ },
288
+
289
+ // Button
290
+ button: {
291
+ backgroundColor: '#0070F3',
292
+ textColor: '#FFFFFF',
293
+ borderRadius: '8px',
294
+ fontSize: '16px',
295
+ fontWeight: 600,
296
+ hover: {
297
+ backgroundColor: '#0051CC'
298
+ },
299
+ disabled: {
300
+ opacity: 0.5
301
+ }
302
+ },
303
+
304
+ // Dark mode
430
305
  dark: {
431
306
  inputContainer: {
432
307
  backgroundColor: '#1A1A1A',
@@ -434,7 +309,7 @@ style: {
434
309
  },
435
310
  input: {
436
311
  textColor: '#FFFFFF',
437
- backgroundColor: '#2A2A2A'
312
+ placeholderColor: '#959499'
438
313
  },
439
314
  button: {
440
315
  backgroundColor: '#0066CC'
@@ -443,272 +318,64 @@ style: {
443
318
  }
444
319
  ```
445
320
 
446
- ### Available Font Families
321
+ **Available style properties:** `inputContainer`, `input`, `button`, `generalError`, `generalSuccess`, `disclaimerColor`, `fieldErrorColor`, `dark` (for dark mode overrides)
447
322
 
448
- ```typescript
449
- type FontFamily =
450
- | 'DM Sans'
451
- | 'Inter'
452
- | 'Poppins'
453
- | 'Nunito'
454
- | 'Work Sans'
455
- | 'Manrope'
456
- | 'Rubik'
457
- | 'Karla'
458
- | 'Figtree'
459
- | 'Outfit'
460
- | 'Space Grotesk'
461
- | 'Urbanist';
462
- ```
323
+ See full TypeScript types in the package for all styling options.
463
324
 
464
- ### Complete Styling API
325
+ ## Error Handling
465
326
 
466
- All available styling properties:
327
+ ```javascript
328
+ import { PaymentResultStatus, PaymentResultErrorCode } from '@inflow_pay/sdk';
467
329
 
468
- ```tsx
469
- interface CSSProperties {
470
- // Global
471
- fontFamily?: FontFamily; // 'DM Sans' | 'Inter' | 'Poppins' | etc.
472
- fillParent?: boolean; // Make element fill parent container
473
-
474
- // Input container (wrapper around all card inputs)
475
- inputContainer?: {
476
- backgroundColor?: string;
477
- borderColor?: string;
478
- borderEnabled?: boolean; // Must be true to show border
479
- borderRadius?: string;
480
- };
481
-
482
- // Individual input fields
483
- input?: {
484
- backgroundColor?: string;
485
- borderColor?: string;
486
- borderEnabled?: boolean;
487
- borderRadius?: string;
488
- textColor?: string;
489
- placeholderColor?: string;
490
- };
491
-
492
- // Button styles
493
- button?: {
494
- backgroundColor?: string;
495
- textColor?: string;
496
- borderRadius?: string;
497
- borderColor?: string;
498
- borderEnabled?: boolean; // Must be true to show border
499
- fontSize?: string;
500
- fontWeight?: FontWeight; // 100-900 | 'normal' | 'bold' | 'lighter' | 'bolder'
501
- opacity?: Opacity; // number (0-1) | string ('0.5' | '50%')
502
- hover?: { // Hover state
503
- backgroundColor?: string;
504
- textColor?: string;
505
- borderRadius?: string;
506
- borderColor?: string;
507
- borderEnabled?: boolean;
508
- fontSize?: string;
509
- fontWeight?: FontWeight;
510
- opacity?: Opacity;
511
- };
512
- disabled?: { // Disabled state
513
- backgroundColor?: string;
514
- textColor?: string;
515
- borderRadius?: string;
516
- borderColor?: string;
517
- borderEnabled?: boolean;
518
- fontSize?: string;
519
- fontWeight?: FontWeight;
520
- opacity?: Opacity;
521
- };
522
- loaderColor?: string; // Loading spinner color
523
- };
524
-
525
- // General error message
526
- generalError?: {
527
- textColor?: string;
528
- backgroundColor?: string;
529
- borderEnabled?: boolean;
530
- borderRadius?: string;
531
- borderColor?: string;
532
- };
533
-
534
- // General success message
535
- generalSuccess?: {
536
- textColor?: string;
537
- backgroundColor?: string;
538
- borderEnabled?: boolean;
539
- borderRadius?: string;
540
- borderColor?: string;
541
- };
542
-
543
- // Other colors
544
- disclaimerColor?: string; // Disclaimer text and icon color
545
- fieldErrorColor?: string; // Field validation error text color
546
-
547
- // Dark mode overrides
548
- dark?: {
549
- inputContainer?: InputContainerStyles;
550
- input?: InputStyles;
551
- button?: ButtonStyles;
552
- disclaimerColor?: string;
553
- fieldErrorColor?: string;
554
- generalError?: GeneralMessageStyles;
555
- generalSuccess?: GeneralMessageStyles;
556
- };
330
+ onComplete: (result) => {
331
+ if (result.status === PaymentResultStatus.FAILED && result.error) {
332
+ console.log(result.error.code); // e.g., 'THREE_DS_FAILED'
333
+ console.log(result.error.message); // User-friendly message
334
+ console.log(result.error.retryable); // Can user retry?
335
+ }
557
336
  }
558
337
  ```
559
338
 
560
- ### Custom Placeholders
339
+ **Common error codes:** `THREE_DS_FAILED`, `PAYMENT_PROCESSING_ERROR`
561
340
 
562
- ```javascript
563
- placeholders: {
564
- cardNumber: '1234 5678 9012 3456',
565
- expiry: 'MM/YY',
566
- cvc: 'CVC'
567
- }
568
- ```
341
+ ## 3D Secure
569
342
 
570
- ### Custom Button Text
343
+ 3DS is handled automatically by the SDK. When required, a modal opens for bank authentication, then closes automatically. No setup needed.
571
344
 
572
- ```javascript
573
- buttonText: 'Pay Now'
574
- ```
345
+ ## Migration from React SDK
575
346
 
576
- ### React Example with All Styling Properties
347
+ **For React apps:** Import from `@inflow_pay/sdk/react` instead. The component API is similar, but the styling structure has changed (see [Styling](#styling) section).
577
348
 
578
- ```tsx
579
- import { InflowPayProvider, CardElement } from '@inflow_pay/sdk/react';
349
+ **For non-React apps:** Use the vanilla JavaScript API shown in the examples above.
580
350
 
581
- function App() {
582
- return (
583
- <InflowPayProvider config={{ apiKey: 'inflow_pub_xxx' }}>
584
- <CardElement
585
- paymentId="pay_xxx"
586
- style={{
587
- fontFamily: 'Inter',
588
- fillParent: true,
589
-
590
- // Input container
591
- inputContainer: {
592
- backgroundColor: '#F5F5F5',
593
- borderRadius: '8px',
594
- borderEnabled: true,
595
- borderColor: '#E0E0E0'
596
- },
597
-
598
- // Input fields
599
- input: {
600
- textColor: '#1A1A1A',
601
- placeholderColor: '#999999',
602
- backgroundColor: 'transparent',
603
- borderColor: '#CECECE',
604
- borderEnabled: true,
605
- borderRadius: '6px'
606
- },
607
-
608
- // Button
609
- button: {
610
- backgroundColor: '#0070F3',
611
- textColor: '#FFFFFF',
612
- borderRadius: '8px',
613
- fontSize: '16px',
614
- fontWeight: 600,
615
- opacity: 1,
616
- borderEnabled: false,
617
- hover: {
618
- backgroundColor: '#0051CC',
619
- opacity: 1
620
- },
621
- disabled: {
622
- opacity: 0.5
623
- },
624
- loaderColor: '#FFFFFF'
625
- },
626
-
627
- // General messages
628
- generalError: {
629
- textColor: '#FF443F',
630
- backgroundColor: '#ffd6cc',
631
- borderColor: '#FF443F',
632
- borderEnabled: true,
633
- borderRadius: '6px'
634
- },
635
-
636
- generalSuccess: {
637
- textColor: '#29a329',
638
- backgroundColor: '#d6f5d6',
639
- borderColor: '#29a329',
640
- borderEnabled: true,
641
- borderRadius: '6px'
642
- },
643
-
644
- // Other colors
645
- disclaimerColor: '#7A7A7A',
646
- fieldErrorColor: '#ef4444',
647
-
648
- // Dark mode
649
- dark: {
650
- inputContainer: {
651
- backgroundColor: '#2d2d2d',
652
- borderColor: '#7A7A7A'
653
- },
654
- input: {
655
- textColor: '#FFFFFF',
656
- placeholderColor: '#959499',
657
- borderColor: '#7A7A7A'
658
- },
659
- button: {
660
- backgroundColor: '#0066CC'
661
- },
662
- generalError: {
663
- textColor: '#ffc2b3',
664
- backgroundColor: '#991f00',
665
- borderColor: '#e62e00'
666
- },
667
- generalSuccess: {
668
- textColor: '#adebad',
669
- backgroundColor: '#196619',
670
- borderColor: '#2eb82e'
671
- },
672
- disclaimerColor: '#959499',
673
- fieldErrorColor: '#ef4444'
674
- }
675
- }}
676
- buttonText="Complete Payment"
677
- onComplete={(result) => {
678
- if (result.status === 'CHECKOUT_SUCCESS') {
679
- alert('Payment successful!');
680
- }
681
- }}
682
- />
683
- </InflowPayProvider>
684
- );
685
- }
686
- ```
351
+ ## TypeScript
352
+
353
+ Full type definitions included:
687
354
 
688
- ## Security
355
+ ```typescript
356
+ import { InflowPayProvider, PaymentResultStatus } from '@inflow_pay/sdk';
357
+ import type { PaymentResult, PaymentError } from '@inflow_pay/sdk';
689
358
 
690
- - Card data is tokenized before reaching your server (PCI compliant)
691
- - Public keys can be safely exposed in browser
692
- - ✅ Private keys should never be in frontend code
693
- - ✅ All requests over HTTPS
694
- - ✅ Iframe isolation for security
359
+ const provider = new InflowPayProvider({
360
+ config: { publicKey: 'inflow_pub_xxx' }
361
+ });
362
+ ```
695
363
 
696
364
  ## Features
697
365
 
698
- - ✅ **Dynamic Height**: Automatically adjusts iframe height based on content
699
- - ✅ **Skeleton Loader**: Beautiful loading state with shimmer effect
700
- - ✅ **Dark Mode Support**: Automatic theme detection with manual overrides
701
- - ✅ **TypeScript**: Full type definitions included
702
- - ✅ **Responsive**: Works on all screen sizes
703
- - ✅ **Accessible**: WCAG compliant
704
- - ✅ **Secure**: PCI compliant, iframe isolation
366
+ - ✅ Dynamic height adjustment
367
+ - ✅ Skeleton loader with shimmer effect
368
+ - ✅ Dark mode support
369
+ - ✅ Responsive design
370
+ - ✅ WCAG compliant
371
+ - ✅ Multi-language support
705
372
 
706
373
  ## Support
707
374
 
708
- - **Documentation:** https://docs.inflowpay.com/v0/reference/createpayment
375
+ - **Docs:** https://docs.inflowpay.com/v0/reference/createpayment
709
376
  - **Email:** support@inflowpay.com
710
377
  - **GitHub:** https://github.com/inflowpay/sdk
711
- - **Changelog:** See [CHANGELOG.md](./CHANGELOG.md) for version history
378
+ - **Changelog:** [CHANGELOG.md](./CHANGELOG.md)
712
379
 
713
380
  ## License
714
381