@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/CHANGELOG.md +7 -0
- package/README.md +254 -587
- 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 +37 -39
- package/dist/react.cjs +1 -1
- package/dist/react.cjs.map +1 -1
- package/dist/react.esm.js +8 -89
- 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 +43 -160
- package/dist/sdk.esm.js +21 -24
- 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-CvXfOxY6.js +0 -178
- package/dist/payment-sdk-CvXfOxY6.js.map +0 -1
- package/dist/payment-sdk-DK3VOIGL.mjs +0 -546
- package/dist/payment-sdk-DK3VOIGL.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
|
-
|
|
15
|
-
|
|
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: {
|
|
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.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
|
-
|
|
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,343 +183,125 @@ if (result.status === 'CHECKOUT_SUCCESS' ||
|
|
|
90
183
|
```javascript
|
|
91
184
|
const provider = new InflowPayProvider({
|
|
92
185
|
config: {
|
|
93
|
-
|
|
94
|
-
|
|
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
|
|
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
|
-
//
|
|
109
|
-
|
|
110
|
-
|
|
111
|
-
|
|
112
|
-
|
|
113
|
-
|
|
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
|
|
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
|
-
|
|
138
|
-
//
|
|
139
|
-
if (result.error) {
|
|
140
|
-
console.error(result.error.message);
|
|
141
|
-
}
|
|
219
|
+
onError: (error) => {
|
|
220
|
+
// SDK-level errors
|
|
142
221
|
},
|
|
143
222
|
|
|
144
|
-
|
|
145
|
-
|
|
146
|
-
|
|
223
|
+
// Styling (optional)
|
|
224
|
+
style: {
|
|
225
|
+
fontFamily: 'Inter',
|
|
226
|
+
button: {
|
|
227
|
+
backgroundColor: '#0070F3',
|
|
228
|
+
textColor: '#FFFFFF'
|
|
229
|
+
}
|
|
147
230
|
},
|
|
148
231
|
|
|
149
|
-
|
|
150
|
-
|
|
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
|
-
###
|
|
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
|
-
```
|
|
165
|
-
|
|
166
|
-
|
|
167
|
-
|
|
168
|
-
|
|
169
|
-
|
|
170
|
-
|
|
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
|
-
|
|
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
|
-
|
|
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
|
-
|
|
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
|
-
|
|
423
|
-
|
|
424
|
-
|
|
425
|
-
},
|
|
271
|
+
fontFamily: 'Inter', // 'DM Sans' | 'Inter' | 'Poppins' | 'Nunito' | etc.
|
|
272
|
+
fillParent: true,
|
|
273
|
+
|
|
274
|
+
// Input container
|
|
426
275
|
inputContainer: {
|
|
427
|
-
backgroundColor: '#
|
|
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
|
-
|
|
312
|
+
placeholderColor: '#959499'
|
|
438
313
|
},
|
|
439
314
|
button: {
|
|
440
315
|
backgroundColor: '#0066CC'
|
|
@@ -443,272 +318,64 @@ style: {
|
|
|
443
318
|
}
|
|
444
319
|
```
|
|
445
320
|
|
|
446
|
-
|
|
321
|
+
**Available style properties:** `inputContainer`, `input`, `button`, `generalError`, `generalSuccess`, `disclaimerColor`, `fieldErrorColor`, `dark` (for dark mode overrides)
|
|
447
322
|
|
|
448
|
-
|
|
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
|
-
|
|
325
|
+
## Error Handling
|
|
465
326
|
|
|
466
|
-
|
|
327
|
+
```javascript
|
|
328
|
+
import { PaymentResultStatus, PaymentResultErrorCode } from '@inflow_pay/sdk';
|
|
467
329
|
|
|
468
|
-
|
|
469
|
-
|
|
470
|
-
|
|
471
|
-
|
|
472
|
-
|
|
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
|
-
|
|
339
|
+
**Common error codes:** `THREE_DS_FAILED`, `PAYMENT_PROCESSING_ERROR`
|
|
561
340
|
|
|
562
|
-
|
|
563
|
-
placeholders: {
|
|
564
|
-
cardNumber: '1234 5678 9012 3456',
|
|
565
|
-
expiry: 'MM/YY',
|
|
566
|
-
cvc: 'CVC'
|
|
567
|
-
}
|
|
568
|
-
```
|
|
341
|
+
## 3D Secure
|
|
569
342
|
|
|
570
|
-
|
|
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
|
-
|
|
573
|
-
buttonText: 'Pay Now'
|
|
574
|
-
```
|
|
345
|
+
## Migration from React SDK
|
|
575
346
|
|
|
576
|
-
|
|
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
|
-
|
|
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
|
-
|
|
582
|
-
|
|
583
|
-
|
|
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
|
-
|
|
355
|
+
```typescript
|
|
356
|
+
import { InflowPayProvider, PaymentResultStatus } from '@inflow_pay/sdk';
|
|
357
|
+
import type { PaymentResult, PaymentError } from '@inflow_pay/sdk';
|
|
689
358
|
|
|
690
|
-
|
|
691
|
-
|
|
692
|
-
|
|
693
|
-
|
|
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
|
-
- ✅
|
|
699
|
-
- ✅
|
|
700
|
-
- ✅
|
|
701
|
-
- ✅
|
|
702
|
-
- ✅
|
|
703
|
-
- ✅
|
|
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
|
-
- **
|
|
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:**
|
|
378
|
+
- **Changelog:** [CHANGELOG.md](./CHANGELOG.md)
|
|
712
379
|
|
|
713
380
|
## License
|
|
714
381
|
|