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