@dropp.cc/payment-sdk 1.0.25 → 1.0.26
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,631 +1,2079 @@
|
|
|
1
|
-
# Dropp Payment SDK
|
|
1
|
+
# Dropp Web Payment SDK — Developer Integration Guide
|
|
2
|
+
|
|
3
|
+
## 1. Overview
|
|
4
|
+
|
|
5
|
+
The **Dropp Web Payment SDK** enables a merchant's web application to integrate Dropp payment and wallet functionality without implementing the complete Dropp payment UI and wallet-management experience themselves.
|
|
6
|
+
|
|
7
|
+
The SDK is framework-agnostic and can be integrated with:
|
|
8
|
+
|
|
9
|
+
- React
|
|
10
|
+
- Vue
|
|
11
|
+
- Angular
|
|
12
|
+
- Next.js
|
|
13
|
+
- Vanilla JavaScript
|
|
14
|
+
|
|
15
|
+
The SDK currently supports three payment models:
|
|
16
|
+
|
|
17
|
+
1. **Standard Payment** — immediate, one-time payment.
|
|
18
|
+
2. **Pre-Authorization Payment (PreAuth)** — temporarily reserves/authorizes funds before the final amount is known.
|
|
19
|
+
3. **Recurring Payment** — creates a recurring authorization for subscription-style billing.
|
|
20
|
+
|
|
21
|
+
In addition to payments, the SDK provides APIs for:
|
|
22
|
+
|
|
23
|
+
- SDK initialization
|
|
24
|
+
- Wallet/account status
|
|
25
|
+
- Account/funding-source linking and unlinking
|
|
26
|
+
- Dashboard access
|
|
27
|
+
- Direct access to individual wallet-management pages
|
|
28
|
+
- Payment-window management
|
|
29
|
+
- SDK/environment information
|
|
30
|
+
- Unified payment callbacks
|
|
31
|
+
|
|
32
|
+
---
|
|
33
|
+
|
|
34
|
+
# 2. Integration Flow
|
|
35
|
+
|
|
36
|
+
A merchant should generally integrate the SDK in the following order:
|
|
37
|
+
|
|
38
|
+
```text
|
|
39
|
+
1. Prerequisites & Merchant Configuration
|
|
40
|
+
↓
|
|
41
|
+
2. Install and Initialize SDK
|
|
42
|
+
↓
|
|
43
|
+
3. Payment APIs
|
|
44
|
+
├── Standard Payment
|
|
45
|
+
├── PreAuth Payment + Backend Callback
|
|
46
|
+
└── Recurring Payment + Backend Callback
|
|
47
|
+
↓
|
|
48
|
+
4. Account APIs
|
|
49
|
+
├── Link Account / Funding Source
|
|
50
|
+
├── Unlink Account / Funding Source
|
|
51
|
+
└── Status
|
|
52
|
+
↓
|
|
53
|
+
5. Custom Pages
|
|
54
|
+
├── Dashboard
|
|
55
|
+
└── Direct Module / Page Access
|
|
56
|
+
↓
|
|
57
|
+
6. Handle Responses, Errors & Callbacks
|
|
58
|
+
↓
|
|
59
|
+
7. Backend Verification & Production Readiness
|
|
60
|
+
```
|
|
61
|
+
|
|
62
|
+
The recommended implementation is to complete the prerequisites and initialization first, then integrate the required payment flow, followed by account-management and custom-page functionality.
|
|
63
|
+
|
|
64
|
+
---
|
|
65
|
+
|
|
66
|
+
# 3. Prerequisites
|
|
67
|
+
|
|
68
|
+
Before integrating the SDK, the merchant must complete the required Dropp merchant configuration.
|
|
69
|
+
|
|
70
|
+
## 3.1 Merchant Requirements
|
|
71
|
+
|
|
72
|
+
The merchant should have:
|
|
73
|
+
|
|
74
|
+
- An active Dropp Merchant Account.
|
|
75
|
+
- Completed merchant KYC approval.
|
|
76
|
+
- A Merchant ID issued by Dropp.
|
|
77
|
+
- An API Key issued by Dropp.
|
|
78
|
+
- An approved Package Name / Application Identifier / Domain registered in the Dropp Merchant Portal.
|
|
79
|
+
|
|
80
|
+
## 3.2 Technical Requirements
|
|
81
|
+
|
|
82
|
+
The integration requires:
|
|
83
|
+
|
|
84
|
+
- Node.js 18+ for package-based integrations.
|
|
85
|
+
- A modern web browser.
|
|
86
|
+
- HTTPS for production deployments.
|
|
87
|
+
|
|
88
|
+
---
|
|
89
|
+
|
|
90
|
+
## 3.3 Register the Host Application
|
|
91
|
+
|
|
92
|
+
Before initializing the SDK, register the host application in the Dropp Merchant Portal.
|
|
93
|
+
|
|
94
|
+
1. Log in to the Dropp Merchant Portal.
|
|
95
|
+
2. Navigate to **Profile**.
|
|
96
|
+
3. Open **Embedded Application Integration**.
|
|
97
|
+
4. Click the **Edit** icon.
|
|
98
|
+
5. Configure:
|
|
99
|
+
- Platform — for example Web.
|
|
100
|
+
- Tag — optional where applicable.
|
|
101
|
+
- Package Name / Bundle Identifier / Domain.
|
|
102
|
+
6. For a Web application, enter the domain without `https://` and without a path.
|
|
103
|
+
|
|
104
|
+
Example:
|
|
105
|
+
|
|
106
|
+
```text
|
|
107
|
+
example.com
|
|
108
|
+
```
|
|
109
|
+
|
|
110
|
+
Do not configure:
|
|
111
|
+
|
|
112
|
+
```text
|
|
113
|
+
https://example.com
|
|
114
|
+
https://example.com/payment
|
|
115
|
+
```
|
|
116
|
+
|
|
117
|
+
For local development, `localhost` or `127.0.0.1` can be registered. The host application must then be accessed using the configured domain/IP.
|
|
118
|
+
|
|
119
|
+
Important: for Web SDK validation, the runtime host is derived from the active browser URL host. Ensure the exact host you open in browser (for example `localhost` vs `127.0.0.1`) is registered in the Merchant Portal.
|
|
120
|
+
|
|
121
|
+
6. Save the application configuration.
|
|
122
|
+
7. Generate an API Key.
|
|
123
|
+
|
|
124
|
+
### API Key Important Notes
|
|
125
|
+
|
|
126
|
+
The API key is displayed only once.
|
|
127
|
+
|
|
128
|
+
Store it securely immediately after generation because it cannot be viewed again.
|
|
129
|
+
|
|
130
|
+
An API key can be rotated or deleted. Once a key is rotated or deleted, the previous key becomes permanently invalid and cannot be used again.
|
|
131
|
+
|
|
132
|
+
> **Security:** Never expose private signing keys or other backend secrets in frontend code.
|
|
133
|
+
|
|
134
|
+
---
|
|
135
|
+
|
|
136
|
+
# 4. Environment Configuration
|
|
137
|
+
|
|
138
|
+
The SDK supports two environments.
|
|
2
139
|
|
|
3
|
-
|
|
140
|
+
## 4.1 Sandbox
|
|
4
141
|
|
|
5
|
-
|
|
142
|
+
Use Sandbox for:
|
|
6
143
|
|
|
7
|
-
-
|
|
8
|
-
-
|
|
9
|
-
-
|
|
10
|
-
-
|
|
11
|
-
-
|
|
144
|
+
- Initial SDK integration.
|
|
145
|
+
- Development.
|
|
146
|
+
- Payment-flow testing.
|
|
147
|
+
- Testing account linking.
|
|
148
|
+
- Testing PreAuth and recurring flows.
|
|
12
149
|
|
|
150
|
+
```js
|
|
151
|
+
environment: 'sandbox'
|
|
152
|
+
```
|
|
153
|
+
|
|
154
|
+
## 4.2 Production
|
|
155
|
+
|
|
156
|
+
Production is used for real customer payments.
|
|
157
|
+
|
|
158
|
+
```js
|
|
159
|
+
environment: 'production'
|
|
160
|
+
```
|
|
161
|
+
|
|
162
|
+
Do not move to production until the complete payment and backend-signing flows have been tested successfully.
|
|
163
|
+
|
|
164
|
+
---
|
|
165
|
+
|
|
166
|
+
## 4.4 Sandbox Wallet Configuration
|
|
167
|
+
|
|
168
|
+
For Sandbox testing, the Dropp Wallet and merchant SDK must use the Sandbox environment.
|
|
169
|
+
|
|
170
|
+
1. Open the Dropp Wallet mobile application.
|
|
171
|
+
2. Recover the wallet account used for testing.
|
|
172
|
+
3. Navigate to **Settings → Developer Options**.
|
|
173
|
+
4. Enable **Switch to Test Mode**.
|
|
174
|
+
5. Configure the SDK with the Sandbox Merchant ID and Sandbox API Key.
|
|
175
|
+
6. Start the application/payment flow.
|
|
176
|
+
7. The SDK may display a QR code for authentication.
|
|
177
|
+
8. Scan the QR code using the Dropp Wallet configured for Sandbox.
|
|
178
|
+
9. Enter the wallet passphrase when prompted.
|
|
179
|
+
10. Continue testing after successful authentication.
|
|
180
|
+
|
|
181
|
+
## 4.5 Wallet Persistence and Browser Storage Caveats
|
|
182
|
+
|
|
183
|
+
Wallet-link persistence for Web SDK flows depends on hosted Dropp browser storage for the embedded experience.
|
|
184
|
+
|
|
185
|
+
Important behavior to account for during testing and production rollout:
|
|
186
|
+
|
|
187
|
+
1. Link state can be scoped to the top-level host origin. For example, `localhost`, `127.0.0.1`, and a tunnel URL are treated as different contexts.
|
|
188
|
+
2. Browser privacy settings, third-party cookie restrictions, and storage partitioning can cause users to re-link more frequently.
|
|
189
|
+
3. Opening the same app under different hostnames can appear like separate wallet-link sessions.
|
|
190
|
+
|
|
191
|
+
Recommendations:
|
|
192
|
+
|
|
193
|
+
1. Use one stable host/domain during test cycles.
|
|
194
|
+
2. Keep host/domain registration in Merchant Portal aligned with the actual browser hostname used at runtime.
|
|
195
|
+
3. Include relinking fallback UX and account-status checks using `Dropp.status()`.
|
|
196
|
+
4. Validate behavior across your supported browser matrix with default privacy settings.
|
|
13
197
|
|
|
14
|
-
|
|
198
|
+
---
|
|
15
199
|
|
|
16
|
-
Install the SDK
|
|
200
|
+
# 5. Install the SDK
|
|
201
|
+
|
|
202
|
+
## 5.1 npm
|
|
17
203
|
|
|
18
204
|
```bash
|
|
19
205
|
npm install @dropp.cc/payment-sdk
|
|
20
206
|
```
|
|
21
207
|
|
|
22
|
-
|
|
208
|
+
## 5.2 Yarn
|
|
209
|
+
|
|
210
|
+
```bash
|
|
211
|
+
yarn add @dropp.cc/payment-sdk
|
|
212
|
+
```
|
|
213
|
+
|
|
214
|
+
---
|
|
215
|
+
|
|
216
|
+
# 6. Initialize the SDK
|
|
23
217
|
|
|
24
|
-
|
|
218
|
+
The SDK must be initialized before calling payment, account, dashboard, or custom-page APIs.
|
|
25
219
|
|
|
26
|
-
```
|
|
220
|
+
```js
|
|
27
221
|
import { Dropp } from '@dropp.cc/payment-sdk';
|
|
28
222
|
|
|
29
|
-
|
|
223
|
+
Dropp.init({
|
|
30
224
|
merchantId: 'YOUR_MERCHANT_ID',
|
|
31
225
|
apiKey: 'YOUR_API_KEY',
|
|
32
|
-
environment: '
|
|
226
|
+
environment: 'sandbox'
|
|
33
227
|
});
|
|
228
|
+
```
|
|
34
229
|
|
|
35
|
-
|
|
36
|
-
amount: 19.99,
|
|
37
|
-
currency: 'USD',
|
|
38
|
-
itemName: 'Test Product'
|
|
39
|
-
});
|
|
230
|
+
## 6.1 Initialization Parameters
|
|
40
231
|
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
232
|
+
| Parameter | Required | Description |
|
|
233
|
+
|---|---|---|
|
|
234
|
+
| `merchantId` | Yes | Merchant account ID (for example `0.0.123456`) provided by Dropp. |
|
|
235
|
+
| `apiKey` | Yes | API key generated for the registered host application. |
|
|
236
|
+
| `environment` | Yes | SDK environment: `sandbox` or `production`. |
|
|
237
|
+
|
|
238
|
+
> The exact application identifier configured in the Merchant Portal must match the host application configuration expected by the SDK.
|
|
239
|
+
|
|
240
|
+
---
|
|
241
|
+
|
|
242
|
+
# 7. Payments
|
|
243
|
+
|
|
244
|
+
The SDK exposes a single payment entry point:
|
|
245
|
+
|
|
246
|
+
```js
|
|
247
|
+
Dropp.pay(options)
|
|
44
248
|
```
|
|
45
249
|
|
|
46
|
-
|
|
250
|
+
The `paymentType` determines which payment flow is started.
|
|
47
251
|
|
|
48
|
-
|
|
49
|
-
| --- | --- | --- |
|
|
50
|
-
| `Dropp.init(config)` | Initialize SDK and validate merchant credentials | `Promise<{ status, code, message, sdk }>` |
|
|
51
|
-
| `Dropp.pay(options)` | Start payment flow | `Promise<PaymentResult>` |
|
|
52
|
-
| `Dropp.dashboard(options?)` | Open hosted dashboard | `Promise<{ status, route }>` |
|
|
53
|
-
| `Dropp.open(moduleId, options?)` | Open supported hosted module | `Promise<{ status, route }>` |
|
|
54
|
-
| `Dropp.unlinkAccount(options?)` | Open unlink account page | `Promise<{ status, route }>` |
|
|
55
|
-
| `Dropp.transactions(options?)` | Open transactions page | `Promise<{ status, route }>` |
|
|
56
|
-
| `Dropp.offers(options?)` | Open offers page | `Promise<{ status, route }>` |
|
|
57
|
-
| `Dropp.status()` | Fetch account link status via hidden iframe | `Promise<{ type, data }>` |
|
|
58
|
-
| `Dropp.getInstance()` | Get current initialized SDK instance | `DroppPaymentSDK \| null` |
|
|
252
|
+
Supported values:
|
|
59
253
|
|
|
60
|
-
|
|
254
|
+
```text
|
|
255
|
+
standard
|
|
256
|
+
preauth
|
|
257
|
+
recurring
|
|
258
|
+
```
|
|
61
259
|
|
|
62
|
-
|
|
260
|
+
The payment flow opens the Dropp-managed payment UI and returns a Promise containing the payment result.
|
|
63
261
|
|
|
64
|
-
|
|
262
|
+
## 7.1 Single Active Flow Constraint
|
|
65
263
|
|
|
66
|
-
|
|
264
|
+
The Web SDK allows only one active flow at a time (payment, hosted page, or status check).
|
|
67
265
|
|
|
68
|
-
|
|
69
|
-
- `merchantId` (String) **Required**: Your Dropp merchant identifier, Will get from Dropp Merchant Portal after KYC.
|
|
70
|
-
- `apiKey` (String) **Required**: API key issued for your merchant, Will get from Dropp Merchant Portal after KYC.
|
|
71
|
-
- `host domain` (Automatic): SDK auto-detects the current host domain (for example, `localhost` in local dev) and passes it for merchant validation.
|
|
72
|
-
- `environment` (String) **Optional**: The environment to use. Options: `'production'`, `'qa'`, `'sandbox'`. Defaults to `'qa'`.
|
|
73
|
-
- `getServerAuthToken` (Function) **Optional**: Async callback that returns a short-lived server-issued token.
|
|
74
|
-
- `requireServerAuthToken` (Boolean) **Optional**: Require server token for payment initialization. Defaults to `true` in production.
|
|
266
|
+
If a second call starts before the first finishes, SDK returns `ALREADY_OPEN`.
|
|
75
267
|
|
|
268
|
+
Recommended host-app behavior:
|
|
76
269
|
|
|
77
|
-
|
|
270
|
+
1. Disable actions that call Dropp APIs while a flow is active.
|
|
271
|
+
2. Re-enable on success, failure, cancel, or close.
|
|
272
|
+
3. In React (including StrictMode), deduplicate mount-time `Dropp.status()` calls.
|
|
78
273
|
|
|
79
|
-
|
|
80
|
-
Dropp.init({
|
|
81
|
-
merchantId: 'YOUR_MERCHANT_ID',
|
|
82
|
-
apiKey: 'YOUR_API_KEY',
|
|
83
|
-
environment: 'production',
|
|
84
|
-
getServerAuthToken: async (context) => {
|
|
85
|
-
const response = await fetch('https://your-backend.com/dropp/auth-token', {
|
|
86
|
-
method: 'POST',
|
|
87
|
-
headers: { 'Content-Type': 'application/json' },
|
|
88
|
-
body: JSON.stringify(context)
|
|
89
|
-
});
|
|
90
|
-
const body = await response.json();
|
|
91
|
-
return body.authToken;
|
|
92
|
-
}
|
|
93
|
-
});
|
|
94
|
-
```
|
|
274
|
+
## 7.2 Unicode Input Note
|
|
95
275
|
|
|
96
|
-
|
|
276
|
+
Current payload encoding in Web SDK versions that use browser `btoa` can fail for non-Latin1 characters.
|
|
97
277
|
|
|
98
|
-
|
|
278
|
+
Until UTF-8-safe encoding is available in your deployed SDK version:
|
|
99
279
|
|
|
100
|
-
|
|
280
|
+
1. Use ASCII-safe `itemName` and `description` values, or
|
|
281
|
+
2. Normalize/sanitize these fields before calling `Dropp.pay(...)`.
|
|
101
282
|
|
|
102
|
-
|
|
283
|
+
---
|
|
103
284
|
|
|
104
|
-
|
|
105
|
-
- `merchantAccount` (String) **Not required**: Merchant account is derived from `Dropp.init({ merchantId })`.
|
|
106
|
-
- `amount` (Number) **Required**: The payment amount.
|
|
107
|
-
- `currency` (String) **Required**: The currency code (e.g., `'USD'`, `'HBAR'`, `'USDC'`). For `paymentType: 'preauth'`, only `'USD'` is allowed.
|
|
108
|
-
- `itemName` (String) **Required**: The name of the item or service.
|
|
109
|
-
- `paymentType` (String) **Optional**: The type of payment. Options: `'standard'`, `'preauth'`, `'recurring'`. Defaults to `'standard'`.
|
|
110
|
-
- `authHoldTimeInSeconds` (Number) **Required in Preauth Payments**: For preauth payments, the hold time in seconds.
|
|
111
|
-
- `callbackUrl` (String) **Required in Preauth & Recurring**: Backend HTTPS callback endpoint used for signing. This must not be a frontend route.
|
|
112
|
-
- `frequency` (String) **Required in Recurring Payments**: One of `'NONE'`, `'HALF_HOURLY'`, `'HOURLY'`, `'DAILY'`, `'WEEKLY'`, `'MONTHLY'`, `'YEARLY'`.
|
|
113
|
-
- `recurringEndDate` (ISO datetime) **Required in Recurring Payments**: The date on which the recurring authorization will expire.
|
|
114
|
-
- `serverAuthToken` (String) **Optional**: A short-lived token issued by your backend for this payment.
|
|
285
|
+
# 8. Standard Payment
|
|
115
286
|
|
|
116
|
-
|
|
287
|
+
## 8.1 Purpose
|
|
117
288
|
|
|
118
|
-
|
|
119
|
-
|
|
120
|
-
|
|
289
|
+
A **Standard Payment** is a one-time payment where the customer pays for a product or service immediately.
|
|
290
|
+
|
|
291
|
+
Use Standard Payment when:
|
|
292
|
+
|
|
293
|
+
- The amount is known at checkout.
|
|
294
|
+
- The customer should be charged once.
|
|
295
|
+
- No future authorization is required.
|
|
296
|
+
|
|
297
|
+
Typical examples:
|
|
298
|
+
|
|
299
|
+
- Product purchase.
|
|
300
|
+
- Parking payment.
|
|
301
|
+
- One-time service payment.
|
|
302
|
+
- Invoice payment.
|
|
303
|
+
- Digital product purchase.
|
|
304
|
+
|
|
305
|
+
## 8.2 Example
|
|
306
|
+
|
|
307
|
+
```js
|
|
308
|
+
const result = await Dropp.pay({
|
|
309
|
+
amount: 49.99,
|
|
121
310
|
currency: 'USD',
|
|
122
|
-
itemName: 'Premium
|
|
311
|
+
itemName: 'Premium Product',
|
|
123
312
|
paymentType: 'standard',
|
|
124
|
-
|
|
313
|
+
description: 'One-time product purchase',
|
|
314
|
+
invoiceId: 'ORDER-12345'
|
|
125
315
|
});
|
|
126
316
|
```
|
|
127
317
|
|
|
128
|
-
##
|
|
318
|
+
## 8.3 Standard Payment Parameters
|
|
129
319
|
|
|
130
|
-
|
|
320
|
+
| Field | Type | Required | Description |
|
|
321
|
+
|---|---|---|---|
|
|
322
|
+
| `paymentType` | string | Yes | Must be `standard`. |
|
|
323
|
+
| `amount` | number | Yes | Payment amount. |
|
|
324
|
+
| `currency` | string | Yes | Currency code such as `USD`. |
|
|
325
|
+
| `itemName` | string | Yes | Name of the purchased item/service. |
|
|
326
|
+
| `description` | string | No | Payment description. |
|
|
327
|
+
| `invoiceId` | string | No (recommended) | Merchant order/reference identifier. If omitted, SDK generates `INV-<timestamp>`. |
|
|
328
|
+
| `acceptPaymentDelay` | boolean | No | Allows delayed payment processing. Default is false when not supplied. |
|
|
329
|
+
| `noOffers` | boolean | No | Disables promotional offers when set to true. |
|
|
330
|
+
| `isSkipCrypto` | boolean \| null | No | Controls whether the cryptocurrency payment option is skipped. |
|
|
131
331
|
|
|
132
|
-
|
|
332
|
+
## 8.4 When to Use
|
|
133
333
|
|
|
134
|
-
|
|
334
|
+
Use:
|
|
135
335
|
|
|
136
|
-
|
|
336
|
+
```text
|
|
337
|
+
paymentType: 'standard'
|
|
338
|
+
```
|
|
137
339
|
|
|
138
|
-
|
|
340
|
+
when the transaction should represent a normal one-time payment.
|
|
139
341
|
|
|
140
|
-
|
|
342
|
+
---
|
|
141
343
|
|
|
142
|
-
-
|
|
143
|
-
- `accounts`
|
|
144
|
-
- `merchants`
|
|
145
|
-
- `settings`
|
|
146
|
-
- `support`
|
|
344
|
+
# 9. Pre-Authorization Payment
|
|
147
345
|
|
|
148
|
-
|
|
346
|
+
## 9.1 Purpose
|
|
149
347
|
|
|
150
|
-
-
|
|
151
|
-
- `linkbank`
|
|
152
|
-
- `linkcard`
|
|
153
|
-
- `redeemnow`
|
|
154
|
-
- `fundcrypto`
|
|
155
|
-
- `transferusdc`
|
|
156
|
-
- `usdchistory`
|
|
157
|
-
- `redeemcrypto`
|
|
158
|
-
- `manageaccounts`
|
|
159
|
-
- `transactions`
|
|
160
|
-
- `merchantlist`
|
|
161
|
-
- `favorites`
|
|
162
|
-
- `offers`
|
|
163
|
-
- `profile`
|
|
164
|
-
- `pinchange`
|
|
165
|
-
- `aboutus`
|
|
348
|
+
A **Pre-Authorization Payment** authorizes/reserves funds without immediately capturing the final amount.
|
|
166
349
|
|
|
167
|
-
|
|
350
|
+
Use PreAuth when the final amount may be determined later or when a temporary authorization is required.
|
|
168
351
|
|
|
169
|
-
|
|
352
|
+
Typical use cases:
|
|
170
353
|
|
|
171
|
-
|
|
354
|
+
- Hotels.
|
|
355
|
+
- Vehicle rentals.
|
|
356
|
+
- Security deposits.
|
|
357
|
+
- Event reservations.
|
|
358
|
+
- Any transaction where a maximum amount needs to be authorized before final capture.
|
|
172
359
|
|
|
173
|
-
|
|
360
|
+
## 9.2 Important Difference from Standard Payment
|
|
174
361
|
|
|
175
|
-
|
|
176
|
-
|
|
177
|
-
-
|
|
178
|
-
|
|
179
|
-
|
|
180
|
-
|
|
181
|
-
- `usdchistory`
|
|
182
|
-
- `redeemcrypto`
|
|
183
|
-
- `manageaccounts`
|
|
184
|
-
- `transactions`
|
|
185
|
-
- `merchantlist`
|
|
186
|
-
- `favorites`
|
|
187
|
-
- `offers`
|
|
188
|
-
- `profile`
|
|
189
|
-
- `pinchange`
|
|
190
|
-
- `aboutus`
|
|
362
|
+
| Standard | PreAuth |
|
|
363
|
+
|---|---|
|
|
364
|
+
| Immediate one-time payment | Authorization/hold |
|
|
365
|
+
| Final payment occurs during the flow | Final amount may be determined later |
|
|
366
|
+
| No backend signing callback required by the documented standard flow | Merchant backend callback is required |
|
|
367
|
+
| Suitable for known purchase amount | Suitable when funds need to be reserved |
|
|
191
368
|
|
|
192
|
-
|
|
369
|
+
---
|
|
193
370
|
|
|
194
|
-
|
|
371
|
+
## 9.3 Example
|
|
195
372
|
|
|
196
|
-
|
|
373
|
+
```js
|
|
374
|
+
const result = await Dropp.pay({
|
|
375
|
+
amount: 100.00,
|
|
376
|
+
currency: 'USD',
|
|
377
|
+
itemName: 'Hotel Reservation',
|
|
378
|
+
paymentType: 'preauth',
|
|
379
|
+
description: 'Hotel reservation authorization',
|
|
380
|
+
invoiceId: 'RESERVATION-12345',
|
|
381
|
+
authHoldTimeInSeconds: 3600,
|
|
382
|
+
callbackUrl: 'https://merchant.example.com/pre-auth-post-callback'
|
|
383
|
+
});
|
|
384
|
+
```
|
|
197
385
|
|
|
198
|
-
|
|
386
|
+
## 9.4 PreAuth Parameters
|
|
387
|
+
|
|
388
|
+
| Field | Type | Required | Description |
|
|
389
|
+
|---|---|---|---|
|
|
390
|
+
| `paymentType` | string | Yes | Must be `preauth`. |
|
|
391
|
+
| `amount` | number | Yes | Maximum amount that may be authorized. |
|
|
392
|
+
| `currency` | string | Yes | Currency code. |
|
|
393
|
+
| `itemName` | string | Yes | Authorization name. |
|
|
394
|
+
| `description` | string | No | Authorization description. |
|
|
395
|
+
| `invoiceId` | string | No (recommended) | Merchant order/reference identifier. If omitted, SDK generates `INV-<timestamp>`. |
|
|
396
|
+
| `authHoldTimeInSeconds` | number | Yes | Duration for which the authorization remains valid. |
|
|
397
|
+
| `callbackUrl` | string | Yes | Public HTTPS endpoint on the merchant backend used for the callback request/response contract. |
|
|
398
|
+
|
|
399
|
+
---
|
|
400
|
+
|
|
401
|
+
# 10. PreAuth Host Server Requirement
|
|
402
|
+
|
|
403
|
+
PreAuth requires a merchant backend server.
|
|
404
|
+
|
|
405
|
+
The backend must be:
|
|
406
|
+
|
|
407
|
+
- Publicly reachable.
|
|
408
|
+
- Accessible through HTTPS.
|
|
409
|
+
- Configured with the Dropp Backend SDK.
|
|
410
|
+
- Able to receive signing requests.
|
|
411
|
+
- Able to sign the required transaction payload.
|
|
412
|
+
- Able to return the signed response.
|
|
413
|
+
|
|
414
|
+
The frontend must **not** contain the merchant's private signing key.
|
|
415
|
+
|
|
416
|
+
## 10.1 PreAuth Callback Flow
|
|
417
|
+
|
|
418
|
+
```text
|
|
419
|
+
Host Application
|
|
420
|
+
|
|
|
421
|
+
| Dropp.pay({ paymentType: 'preauth', callbackUrl })
|
|
422
|
+
↓
|
|
423
|
+
Dropp Payment Flow
|
|
424
|
+
|
|
|
425
|
+
| Signing request
|
|
426
|
+
↓
|
|
427
|
+
Merchant Backend
|
|
428
|
+
|
|
|
429
|
+
| Validate request
|
|
430
|
+
| Sign transaction
|
|
431
|
+
| Return signed response
|
|
432
|
+
↓
|
|
433
|
+
Dropp Payment Flow
|
|
434
|
+
|
|
|
435
|
+
↓
|
|
436
|
+
PreAuth Result
|
|
437
|
+
|
|
|
438
|
+
↓
|
|
439
|
+
Host Application
|
|
440
|
+
```
|
|
199
441
|
|
|
200
|
-
|
|
442
|
+
## 10.2 Callback URL
|
|
201
443
|
|
|
202
|
-
|
|
444
|
+
The `callbackUrl` must point to the merchant backend application where the Dropp Backend SDK is integrated.
|
|
203
445
|
|
|
204
|
-
|
|
446
|
+
Example:
|
|
205
447
|
|
|
206
|
-
|
|
448
|
+
```text
|
|
449
|
+
https://merchant.example.com/pre-auth-post-callback
|
|
450
|
+
```
|
|
207
451
|
|
|
208
|
-
|
|
209
|
-
- `onClose` (Function) **Optional**: Callback invoked when the modal is closed.
|
|
210
|
-
- `onCancel` (Function) **Optional**: Callback invoked when the hosted page is cancelled.
|
|
211
|
-
- `onFailed` (Function) **Optional**: Callback invoked for hosted page failure.
|
|
212
|
-
- `onAccountChanged` (Function) **Optional**: Callback invoked for account changes.
|
|
213
|
-
- `onPageFailed` (Function) **Optional**: Callback invoked for page-level failure.
|
|
214
|
-
- `modules` (`string[]`) **Optional**: firsttimeflow sidebar modules.
|
|
452
|
+
A sample merchant backend application is available from the integration material:
|
|
215
453
|
|
|
216
|
-
|
|
454
|
+
```text
|
|
455
|
+
https://drive.google.com/drive/u/1/folders/1pWrBFQwnznhpRFPnsU_5qiy0TRp5dGUr
|
|
456
|
+
```
|
|
217
457
|
|
|
218
|
-
|
|
219
|
-
await Dropp.dashboard({
|
|
220
|
-
onClose: () => {
|
|
221
|
-
console.log('Dashboard modal closed');
|
|
222
|
-
},
|
|
223
|
-
modules: ['funding', 'accounts', 'merchants', 'settings', 'support']
|
|
224
|
-
});
|
|
458
|
+
### Running the Sample Backend
|
|
225
459
|
|
|
226
|
-
|
|
227
|
-
|
|
228
|
-
|
|
460
|
+
1. Download and extract the sample project.
|
|
461
|
+
2. Update `.env` with the Merchant ID and Signing Key.
|
|
462
|
+
3. Start the backend application locally.
|
|
463
|
+
4. Expose the local server through ngrok or deploy it to a public HTTPS server.
|
|
464
|
+
5. Use the public callback URL in `Dropp.pay()`.
|
|
229
465
|
|
|
230
|
-
|
|
231
|
-
modules: ['funding', 'profile', 'aboutus']
|
|
232
|
-
});
|
|
466
|
+
Example:
|
|
233
467
|
|
|
234
|
-
|
|
235
|
-
|
|
468
|
+
```text
|
|
469
|
+
https://<your-ngrok-url>/pre-auth-post-callback
|
|
236
470
|
```
|
|
237
471
|
|
|
238
|
-
|
|
472
|
+
> The callback endpoint must be publicly accessible over HTTPS.
|
|
239
473
|
|
|
240
|
-
|
|
241
|
-
|
|
242
|
-
|
|
243
|
-
|
|
244
|
-
|
|
245
|
-
|
|
474
|
+
---
|
|
475
|
+
|
|
476
|
+
# 11. Recurring Payment
|
|
477
|
+
|
|
478
|
+
## 11.1 Purpose
|
|
479
|
+
|
|
480
|
+
A **Recurring Payment** creates a recurring authorization for subscription or periodic billing.
|
|
481
|
+
|
|
482
|
+
Use recurring payments when a merchant needs to charge a customer repeatedly according to a defined schedule.
|
|
246
483
|
|
|
247
|
-
|
|
248
|
-
|
|
249
|
-
|
|
484
|
+
Typical use cases:
|
|
485
|
+
|
|
486
|
+
- SaaS subscriptions.
|
|
487
|
+
- Memberships.
|
|
488
|
+
- Streaming services.
|
|
489
|
+
- Monthly plans.
|
|
490
|
+
- Periodic service billing.
|
|
491
|
+
|
|
492
|
+
## 11.2 Example
|
|
493
|
+
|
|
494
|
+
```js
|
|
495
|
+
const result = await Dropp.pay({
|
|
496
|
+
amount: 9.99,
|
|
497
|
+
currency: 'USD',
|
|
498
|
+
itemName: 'Monthly Subscription',
|
|
499
|
+
paymentType: 'recurring',
|
|
500
|
+
description: 'Monthly subscription',
|
|
501
|
+
invoiceId: 'SUBSCRIPTION-12345',
|
|
502
|
+
callbackUrl: 'https://merchant.example.com/rps-callback',
|
|
503
|
+
recurringEndDate: new Date(
|
|
504
|
+
Date.now() + 365 * 24 * 60 * 60 * 1000
|
|
505
|
+
).toISOString()
|
|
250
506
|
});
|
|
251
|
-
await sdk.open('fundnow');
|
|
252
|
-
await sdk.open('transactions');
|
|
253
|
-
await sdk.unlinkAccount();
|
|
254
|
-
await sdk.transactions();
|
|
255
|
-
await sdk.offers();
|
|
256
507
|
```
|
|
257
508
|
|
|
258
|
-
##
|
|
509
|
+
## 11.3 Recurring Parameters
|
|
510
|
+
|
|
511
|
+
| Field | Type | Required | Description |
|
|
512
|
+
|---|---|---|---|
|
|
513
|
+
| `paymentType` | string | Yes | Must be `recurring`. |
|
|
514
|
+
| `amount` | number \| null | Conditional | Maximum or fixed recurring charge amount depending on the recurring configuration. |
|
|
515
|
+
| `currency` | string | Yes | Currency code. |
|
|
516
|
+
| `frequency` | RecurringInterval \| null | Conditional | Recurring interval. When supplied, amount is treated as a fixed amount; otherwise it represents the maximum amount according to the documented behavior. |
|
|
517
|
+
| `itemName` | string | Yes | Subscription name. |
|
|
518
|
+
| `description` | string | No | Payment description. |
|
|
519
|
+
| `invoiceId` | string | No (recommended) | Merchant order/reference identifier. If omitted, SDK generates `INV-<timestamp>`. |
|
|
520
|
+
| `recurringEndDate` | string | Yes | Expiry date in ISO-8601 format. |
|
|
521
|
+
| `callbackUrl` | string | Yes | Public HTTPS backend callback endpoint. |
|
|
522
|
+
|
|
523
|
+
## 11.4 Supported Frequencies
|
|
524
|
+
|
|
525
|
+
| Frequency | Meaning |
|
|
526
|
+
|---|---|
|
|
527
|
+
| `HALF_HOURLY` | Every 30 minutes |
|
|
528
|
+
| `HOURLY` | Every hour |
|
|
529
|
+
| `DAILY` | Every day |
|
|
530
|
+
| `WEEKLY` | Every week |
|
|
531
|
+
| `MONTHLY` | Every month |
|
|
532
|
+
| `YEARLY` | Every year |
|
|
533
|
+
| `NONE` | No recurring interval; used for the documented maximum-amount behavior |
|
|
534
|
+
|
|
535
|
+
---
|
|
536
|
+
|
|
537
|
+
# 12. Recurring Payment Host Server Requirement
|
|
538
|
+
|
|
539
|
+
Recurring payments require a merchant backend callback endpoint.
|
|
540
|
+
|
|
541
|
+
The backend is responsible for receiving recurring authorization requests and signing the required payload using the Dropp Backend SDK.
|
|
542
|
+
|
|
543
|
+
## 12.1 Recurring Callback Flow
|
|
544
|
+
|
|
545
|
+
```text
|
|
546
|
+
Host Application
|
|
547
|
+
|
|
|
548
|
+
| Create recurring authorization
|
|
549
|
+
↓
|
|
550
|
+
Dropp Payment Flow
|
|
551
|
+
|
|
|
552
|
+
| Signing request
|
|
553
|
+
↓
|
|
554
|
+
Merchant Backend
|
|
555
|
+
|
|
|
556
|
+
| Validate request
|
|
557
|
+
| Sign authorization
|
|
558
|
+
| Return signed response
|
|
559
|
+
↓
|
|
560
|
+
Dropp
|
|
561
|
+
|
|
|
562
|
+
↓
|
|
563
|
+
Recurring Authorization Result
|
|
564
|
+
```
|
|
259
565
|
|
|
260
|
-
|
|
566
|
+
## 12.2 Callback URL
|
|
261
567
|
|
|
262
|
-
|
|
568
|
+
Example:
|
|
263
569
|
|
|
264
|
-
|
|
570
|
+
```text
|
|
571
|
+
https://merchant.example.com/rps-callback
|
|
572
|
+
```
|
|
265
573
|
|
|
266
|
-
|
|
267
|
-
|
|
268
|
-
|
|
269
|
-
|
|
270
|
-
|
|
271
|
-
|
|
272
|
-
}
|
|
273
|
-
}
|
|
574
|
+
The callback URL must point to the merchant backend application where the Dropp Backend SDK is integrated.
|
|
575
|
+
|
|
576
|
+
Sample backend:
|
|
577
|
+
|
|
578
|
+
```text
|
|
579
|
+
https://drive.google.com/drive/u/1/folders/1pWrBFQwnznhpRFPnsU_5qiy0TRp5dGUr
|
|
274
580
|
```
|
|
275
581
|
|
|
276
|
-
|
|
582
|
+
For local testing:
|
|
277
583
|
|
|
278
|
-
```
|
|
279
|
-
|
|
280
|
-
console.log('Account status:', status);
|
|
584
|
+
```text
|
|
585
|
+
https://<your-ngrok-url>/rps-callback
|
|
281
586
|
```
|
|
282
587
|
|
|
283
|
-
|
|
588
|
+
The endpoint must be publicly accessible over HTTPS.
|
|
284
589
|
|
|
285
|
-
|
|
286
|
-
const { sdk } = await Dropp.init({
|
|
287
|
-
merchantId: 'YOUR_MERCHANT_ID',
|
|
288
|
-
apiKey: 'YOUR_API_KEY',
|
|
289
|
-
environment: 'production'
|
|
290
|
-
});
|
|
590
|
+
## 12.3 Callback Transport and Envelope (Important)
|
|
291
591
|
|
|
292
|
-
|
|
293
|
-
console.log(status);
|
|
294
|
-
```
|
|
592
|
+
For current hosted flows, callback transport differs by payment type:
|
|
295
593
|
|
|
296
|
-
|
|
594
|
+
| Payment Type | Request Transport to `callbackUrl` | Main Payload Carrier |
|
|
595
|
+
|---|---|---|
|
|
596
|
+
| `recurring` | Browser `GET` | `RecurringData` query parameter |
|
|
597
|
+
| `preauth` | Browser `POST` | JSON request body |
|
|
297
598
|
|
|
298
|
-
|
|
599
|
+
The signed envelope should be handled as opaque and forwarded server-side:
|
|
299
600
|
|
|
300
|
-
```
|
|
601
|
+
```json
|
|
301
602
|
{
|
|
302
|
-
|
|
303
|
-
|
|
304
|
-
|
|
603
|
+
"data": "<base64 payload>",
|
|
604
|
+
"signatures": {
|
|
605
|
+
"payer": "<hex signature>"
|
|
606
|
+
}
|
|
305
607
|
}
|
|
306
608
|
```
|
|
307
609
|
|
|
308
|
-
|
|
610
|
+
Do not approve only from browser callback receipt. The merchant backend must first submit the payer-signed envelope to the authoritative Dropp backend path for the payment type, validate success, persist returned authorization/token metadata, then respond to hosted flow.
|
|
309
611
|
|
|
310
|
-
|
|
311
|
-
|
|
312
|
-
|
|
313
|
-
|
|
314
|
-
|
|
315
|
-
|
|
612
|
+
## 12.4 Trust Boundary Requirement
|
|
613
|
+
|
|
614
|
+
The callback request originates via the payer browser. Treat it as untrusted transport until the backend completes authoritative validation/forwarding.
|
|
615
|
+
|
|
616
|
+
Minimum requirement:
|
|
617
|
+
|
|
618
|
+
1. Receive callback on merchant backend.
|
|
619
|
+
2. Validate request shape and merchant context.
|
|
620
|
+
3. Forward payer-signed envelope to authoritative Dropp backend API for that flow.
|
|
621
|
+
4. Approve hosted callback response only after authoritative success.
|
|
622
|
+
5. Persist returned token/reference details needed for future preauth/recurring lifecycle operations.
|
|
623
|
+
|
|
624
|
+
---
|
|
625
|
+
|
|
626
|
+
# 13. Server Authentication
|
|
627
|
+
|
|
628
|
+
Server Authentication protects payment requests from client-side tampering.
|
|
629
|
+
|
|
630
|
+
The signing process should remain on the merchant backend.
|
|
631
|
+
|
|
632
|
+
The general model is:
|
|
633
|
+
|
|
634
|
+
```text
|
|
635
|
+
Frontend
|
|
636
|
+
|
|
|
637
|
+
| Payment request
|
|
638
|
+
↓
|
|
639
|
+
Dropp
|
|
640
|
+
|
|
|
641
|
+
| Request server-side authorization/signing
|
|
642
|
+
↓
|
|
643
|
+
Merchant Backend
|
|
644
|
+
|
|
|
645
|
+
| Private signing key
|
|
646
|
+
| Sign payload
|
|
647
|
+
↓
|
|
648
|
+
Dropp
|
|
649
|
+
|
|
|
650
|
+
| Validate signature
|
|
651
|
+
↓
|
|
652
|
+
Payment continues
|
|
316
653
|
```
|
|
317
654
|
|
|
318
|
-
|
|
655
|
+
## Security Rule
|
|
319
656
|
|
|
320
|
-
|
|
321
|
-
|
|
322
|
-
|
|
323
|
-
|
|
324
|
-
|
|
657
|
+
Never put a private signing key, signing secret, or equivalent backend credential in frontend JavaScript.
|
|
658
|
+
|
|
659
|
+
The merchant backend should:
|
|
660
|
+
|
|
661
|
+
1. Receive the signing request.
|
|
662
|
+
2. Validate the request.
|
|
663
|
+
3. Sign the required payload.
|
|
664
|
+
4. Return the signed response.
|
|
665
|
+
|
|
666
|
+
---
|
|
667
|
+
|
|
668
|
+
# 14. Payment Response Handling
|
|
669
|
+
|
|
670
|
+
`Dropp.pay()` returns a Promise.
|
|
671
|
+
|
|
672
|
+
Always handle both:
|
|
673
|
+
|
|
674
|
+
- A returned unsuccessful result.
|
|
675
|
+
- A rejected Promise/error.
|
|
676
|
+
|
|
677
|
+
```js
|
|
678
|
+
try {
|
|
679
|
+
const result = await Dropp.pay(paymentOptions);
|
|
680
|
+
|
|
681
|
+
if (result && result.success === true) {
|
|
682
|
+
// Update application/order state
|
|
683
|
+
} else {
|
|
684
|
+
// Handle unsuccessful payment
|
|
685
|
+
}
|
|
686
|
+
} catch (error) {
|
|
687
|
+
console.error('Payment error', error);
|
|
325
688
|
}
|
|
326
689
|
```
|
|
327
690
|
|
|
328
|
-
|
|
691
|
+
The merchant should verify the payment on the backend before fulfilling an order.
|
|
692
|
+
|
|
693
|
+
Recommended flow:
|
|
694
|
+
|
|
695
|
+
```text
|
|
696
|
+
Customer initiates payment
|
|
697
|
+
↓
|
|
698
|
+
Dropp payment window opens
|
|
699
|
+
↓
|
|
700
|
+
Customer completes payment
|
|
701
|
+
↓
|
|
702
|
+
SDK returns payment response
|
|
703
|
+
↓
|
|
704
|
+
Merchant backend verifies payment
|
|
705
|
+
↓
|
|
706
|
+
Order/subscription is updated
|
|
707
|
+
↓
|
|
708
|
+
Merchant fulfills the order
|
|
709
|
+
```
|
|
329
710
|
|
|
330
|
-
|
|
711
|
+
---
|
|
331
712
|
|
|
332
|
-
|
|
333
|
-
- `'qa'`: For quality assurance testing.
|
|
334
|
-
- `'sandbox'`: For development and testing.
|
|
713
|
+
# 15. Account APIs
|
|
335
714
|
|
|
336
|
-
|
|
715
|
+
Account APIs are used when the host application needs to give the user access to their Dropp wallet/funding-source management without building those screens itself.
|
|
337
716
|
|
|
717
|
+
The account-management area covers:
|
|
338
718
|
|
|
339
|
-
|
|
340
|
-
|
|
719
|
+
- Linking a dropp account.
|
|
720
|
+
- Unlinking a linked dropp account.
|
|
721
|
+
- Checking whether an account is linked.
|
|
341
722
|
|
|
342
|
-
|
|
343
|
-
merchantId: 'YOUR_MERCHANT_ID',
|
|
344
|
-
apiKey: 'YOUR_API_KEY',
|
|
345
|
-
environment: 'sandbox' // For testing payments (testnet)
|
|
346
|
-
});
|
|
723
|
+
---
|
|
347
724
|
|
|
725
|
+
# 16. Link Account
|
|
348
726
|
|
|
349
|
-
|
|
350
|
-
|
|
351
|
-
|
|
352
|
-
|
|
353
|
-
|
|
727
|
+
## 16.1 Purpose
|
|
728
|
+
|
|
729
|
+
The SDK does not expose a separate `Dropp.linkAccount()` method.
|
|
730
|
+
|
|
731
|
+
To allow a user to link an account, the host application should open the **Dropp Dashboard**. The Dashboard provides the Dropp-managed account and experience where the user can complete the required linking flow.
|
|
732
|
+
|
|
733
|
+
Use:
|
|
734
|
+
|
|
735
|
+
```js
|
|
736
|
+
Dropp.dashboard();
|
|
354
737
|
```
|
|
355
738
|
|
|
356
|
-
|
|
739
|
+
The host application should not implement a separate account-linking UI when the intention is to use the Dropp-managed experience.
|
|
357
740
|
|
|
358
|
-
|
|
741
|
+
## 16.2 When to Use
|
|
359
742
|
|
|
360
|
-
|
|
361
|
-
|
|
362
|
-
|
|
363
|
-
|
|
364
|
-
|
|
365
|
-
|
|
366
|
-
|
|
367
|
-
|
|
743
|
+
Use the Dashboard for account linking when:
|
|
744
|
+
|
|
745
|
+
- The user needs to connect an account.
|
|
746
|
+
- The host application wants to provide the complete Dropp-managed wallet experience.
|
|
747
|
+
- The user may need to perform other wallet actions in addition to linking.
|
|
748
|
+
- The host application does not need to recreate Dropp's account-management UI.
|
|
749
|
+
|
|
750
|
+
Example:
|
|
751
|
+
|
|
752
|
+
```text
|
|
753
|
+
Merchant Application
|
|
754
|
+
↓
|
|
755
|
+
"Link Account" / "Manage Wallet"
|
|
756
|
+
↓
|
|
757
|
+
Dropp.dashboard()
|
|
758
|
+
↓
|
|
759
|
+
Dropp-managed Dashboard
|
|
760
|
+
↓
|
|
761
|
+
User completes account-linking flow
|
|
762
|
+
↓
|
|
763
|
+
Host application can check the result/state with Dropp.status()
|
|
368
764
|
```
|
|
369
765
|
|
|
370
|
-
|
|
766
|
+
## 16.3 Recommended Account-Linking Flow
|
|
371
767
|
|
|
372
|
-
|
|
373
|
-
|
|
374
|
-
|
|
375
|
-
|
|
376
|
-
|
|
377
|
-
|
|
378
|
-
|
|
379
|
-
|
|
380
|
-
authHoldTimeInSeconds: 3600, // 1 hour hold
|
|
381
|
-
callbackUrl: 'https://your-server.com/payment-callback'
|
|
382
|
-
});
|
|
768
|
+
A host application can first check the account state and then open the Dashboard when linking is required:
|
|
769
|
+
|
|
770
|
+
```js
|
|
771
|
+
const status = await Dropp.status();
|
|
772
|
+
|
|
773
|
+
if (!status?.data?.linked) {
|
|
774
|
+
Dropp.dashboard();
|
|
775
|
+
}
|
|
383
776
|
```
|
|
384
777
|
|
|
385
|
-
|
|
778
|
+
This keeps the account-linking experience inside the Dropp-managed UI while allowing the host application to control when the Dashboard should be presented.
|
|
386
779
|
|
|
387
|
-
|
|
388
|
-
|
|
389
|
-
|
|
390
|
-
|
|
391
|
-
|
|
392
|
-
|
|
393
|
-
|
|
394
|
-
|
|
395
|
-
|
|
396
|
-
|
|
397
|
-
|
|
780
|
+
---
|
|
781
|
+
|
|
782
|
+
# 17. Unlink Account
|
|
783
|
+
|
|
784
|
+
## 17.1 Purpose
|
|
785
|
+
|
|
786
|
+
`Dropp.unlinkAccount(options)` opens the unlink-account page.
|
|
787
|
+
|
|
788
|
+
It is used to allow the user to safely remove a linked funding source from their Dropp wallet.
|
|
789
|
+
|
|
790
|
+
```js
|
|
791
|
+
Dropp.unlinkAccount(options);
|
|
398
792
|
```
|
|
399
|
-
### React Integration
|
|
400
793
|
|
|
401
|
-
|
|
402
|
-
import { useEffect, useState } from 'react';
|
|
403
|
-
import { Dropp } from '@dropp.cc/payment-sdk';
|
|
794
|
+
## 17.2 When to Use
|
|
404
795
|
|
|
405
|
-
|
|
406
|
-
const [isProcessing, setIsProcessing] = useState(false);
|
|
796
|
+
Use the unlink flow when:
|
|
407
797
|
|
|
408
|
-
|
|
409
|
-
|
|
410
|
-
|
|
411
|
-
|
|
412
|
-
environment: 'production'
|
|
413
|
-
});
|
|
414
|
-
}, []);
|
|
798
|
+
- The user wants to remove a bank account.
|
|
799
|
+
- The user wants to remove a card/funding source.
|
|
800
|
+
- The host application provides an account-management or settings experience.
|
|
801
|
+
- The merchant wants users to manage linked funding sources through Dropp's UI.
|
|
415
802
|
|
|
416
|
-
|
|
417
|
-
setIsProcessing(true);
|
|
803
|
+
The SDK manages the unlink UI instead of requiring the host application to recreate the Dropp account-management screen.
|
|
418
804
|
|
|
419
|
-
|
|
420
|
-
const result = await Dropp.pay({
|
|
421
|
-
amount: 99.99,
|
|
422
|
-
currency: 'USD',
|
|
423
|
-
itemName: 'Product Purchase',
|
|
424
|
-
paymentType: 'standard'
|
|
425
|
-
});
|
|
805
|
+
---
|
|
426
806
|
|
|
427
|
-
|
|
428
|
-
alert('Payment successful!');
|
|
429
|
-
}
|
|
430
|
-
} catch (error) {
|
|
431
|
-
console.error('Payment error:', error);
|
|
432
|
-
} finally {
|
|
433
|
-
setIsProcessing(false);
|
|
434
|
-
}
|
|
435
|
-
};
|
|
807
|
+
# 18. Account Status API
|
|
436
808
|
|
|
437
|
-
|
|
438
|
-
|
|
439
|
-
|
|
440
|
-
|
|
441
|
-
|
|
809
|
+
## 18.1 `Dropp.status()`
|
|
810
|
+
|
|
811
|
+
The Status API allows the host application to determine the current linked-account state.
|
|
812
|
+
|
|
813
|
+
```js
|
|
814
|
+
const status = await Dropp.status();
|
|
815
|
+
|
|
816
|
+
console.log(status);
|
|
817
|
+
```
|
|
818
|
+
|
|
819
|
+
The documented response format is:
|
|
820
|
+
|
|
821
|
+
```js
|
|
822
|
+
{
|
|
823
|
+
type: 'ACCOUNT_STATUS',
|
|
824
|
+
data: {
|
|
825
|
+
linked: true,
|
|
826
|
+
method: 'keypair'
|
|
827
|
+
}
|
|
442
828
|
}
|
|
443
829
|
```
|
|
444
830
|
|
|
831
|
+
## 18.2 Purpose
|
|
445
832
|
|
|
446
|
-
|
|
833
|
+
The status API is useful when the host application needs to know whether the user already has a linked Dropp wallet/account before deciding what UI or action to show.
|
|
447
834
|
|
|
448
|
-
|
|
835
|
+
For example:
|
|
449
836
|
|
|
450
|
-
```
|
|
451
|
-
|
|
452
|
-
|
|
453
|
-
|
|
454
|
-
|
|
455
|
-
|
|
456
|
-
|
|
457
|
-
|
|
458
|
-
|
|
459
|
-
|
|
460
|
-
|
|
461
|
-
|
|
462
|
-
|
|
463
|
-
<script src="https://unpkg.com/@dropp.cc/payment-sdk/dist/dropp-payment-sdk.js"></script>
|
|
464
|
-
<script>
|
|
465
|
-
const { Dropp } = window.DroppPaymentSDK;
|
|
466
|
-
|
|
467
|
-
Dropp.init({
|
|
468
|
-
merchantId: 'YOUR_MERCHANT_ID',
|
|
469
|
-
apiKey: 'YOUR_API_KEY',
|
|
470
|
-
environment: 'production'
|
|
471
|
-
});
|
|
837
|
+
```text
|
|
838
|
+
Application starts
|
|
839
|
+
↓
|
|
840
|
+
Dropp.status()
|
|
841
|
+
↓
|
|
842
|
+
Is account linked?
|
|
843
|
+
/ \
|
|
844
|
+
Yes No
|
|
845
|
+
↓ ↓
|
|
846
|
+
Show wallet Show link/authentication
|
|
847
|
+
actions flow
|
|
848
|
+
```
|
|
472
849
|
|
|
473
|
-
|
|
474
|
-
await Dropp.pay({
|
|
475
|
-
amount: 49.99,
|
|
476
|
-
currency: 'USD',
|
|
477
|
-
itemName: 'One-time Purchase',
|
|
478
|
-
paymentType: 'standard'
|
|
479
|
-
});
|
|
480
|
-
});
|
|
850
|
+
## 18.3 Example
|
|
481
851
|
|
|
482
|
-
|
|
483
|
-
|
|
484
|
-
amount: 100.00,
|
|
485
|
-
currency: 'USD',
|
|
486
|
-
itemName: 'Hotel Reservation',
|
|
487
|
-
paymentType: 'preauth',
|
|
488
|
-
authHoldTimeInSeconds: 3600,
|
|
489
|
-
callbackUrl: 'https://your-server.com/payment-callback'
|
|
490
|
-
});
|
|
491
|
-
});
|
|
852
|
+
```js
|
|
853
|
+
const status = await Dropp.status();
|
|
492
854
|
|
|
493
|
-
|
|
494
|
-
|
|
495
|
-
|
|
496
|
-
|
|
497
|
-
|
|
498
|
-
paymentType: 'recurring',
|
|
499
|
-
frequency: 'monthly',
|
|
500
|
-
recurringEndDate: new Date(Date.now() + 365 * 24 * 60 * 60 * 1000).toISOString(),
|
|
501
|
-
callbackUrl: 'https://your-server.com/recurring-callback'
|
|
502
|
-
});
|
|
503
|
-
});
|
|
504
|
-
</script>
|
|
505
|
-
</body>
|
|
506
|
-
</html>
|
|
855
|
+
if (status?.data?.linked) {
|
|
856
|
+
console.log('Dropp account is linked');
|
|
857
|
+
} else {
|
|
858
|
+
console.log('Dropp account is not linked');
|
|
859
|
+
}
|
|
507
860
|
```
|
|
508
861
|
|
|
509
|
-
|
|
862
|
+
The documented implementation performs the status check through a hidden iframe.
|
|
510
863
|
|
|
511
|
-
|
|
864
|
+
## 18.4 Failure and Timeout Behavior
|
|
512
865
|
|
|
513
|
-
|
|
514
|
-
✅ **Session Correlation** - Each session has a unique ID to prevent replay attacks
|
|
515
|
-
✅ **Message Authentication** - All messages are validated for structure and content
|
|
516
|
-
✅ **Iframe Sandboxing** - Payment app runs in a sandboxed iframe
|
|
517
|
-
✅ **No Sensitive Data** - SDK never handles sensitive payment data directly
|
|
518
|
-
✅ **Secure Communication** - All data transmission uses HTTPS
|
|
866
|
+
`Dropp.status()` may reject instead of returning a status object.
|
|
519
867
|
|
|
520
|
-
|
|
868
|
+
Common cases:
|
|
521
869
|
|
|
522
|
-
1.
|
|
523
|
-
2.
|
|
524
|
-
3.
|
|
525
|
-
4. **Use invoice IDs** to track and deduplicate payments
|
|
526
|
-
5. **Implement proper error handling**
|
|
870
|
+
1. Another SDK flow is active (`ALREADY_OPEN`).
|
|
871
|
+
2. Status iframe initialization timed out (`INIT_TIMEOUT`).
|
|
872
|
+
3. Status flow closed before response (`UNKNOWN_ERROR` depending on close path).
|
|
527
873
|
|
|
528
|
-
|
|
874
|
+
Recommended handling:
|
|
529
875
|
|
|
530
|
-
|
|
876
|
+
```js
|
|
877
|
+
try {
|
|
878
|
+
const status = await Dropp.status();
|
|
879
|
+
const isLinked = status?.data?.linked === true;
|
|
880
|
+
console.log('linked?', isLinked);
|
|
881
|
+
} catch (error) {
|
|
882
|
+
console.error('status failed', {
|
|
883
|
+
code: error?.code,
|
|
884
|
+
message: error?.message,
|
|
885
|
+
details: error?.details
|
|
886
|
+
});
|
|
887
|
+
}
|
|
888
|
+
```
|
|
531
889
|
|
|
532
|
-
|
|
533
|
-
| --- | --- | --- |
|
|
534
|
-
| `INVALID_CONFIG` | Input or merchant validation failed | Check required fields, environment, credentials, callback URL |
|
|
535
|
-
| `ALREADY_OPEN` | Another SDK flow is active | Wait for active flow to finish, then retry |
|
|
536
|
-
| `INIT_TIMEOUT` | Payment app/status flow did not initialize in time | Check environment URL/connectivity, retry |
|
|
537
|
-
| `PAYMENT_TIMEOUT` | Payment did not complete within timeout | Ask user to retry and verify backend state |
|
|
538
|
-
| `UNKNOWN_ERROR` | Unexpected runtime/processing error | Log details, retry, contact support if persistent |
|
|
539
|
-
| `SDK_NOT_INITIALIZED` | `Dropp` global method used before `Dropp.init(...)` | Initialize first, then call `pay`/`dashboard`/`open`/`status` |
|
|
890
|
+
---
|
|
540
891
|
|
|
541
|
-
|
|
892
|
+
# 19. Link vs Unlink vs Status
|
|
542
893
|
|
|
543
|
-
|
|
894
|
+
| API / Flow | Purpose | Typical Use |
|
|
895
|
+
|---|---|---|
|
|
896
|
+
| `Dropp.dashboard()` | Open the Dropp-managed account/wallet experience | User needs to link an account or manage wallet functionality |
|
|
897
|
+
| `Dropp.unlinkAccount(options)` | Open unlink-account UI | User wants to remove a funding source |
|
|
898
|
+
| `Dropp.status()` | Check linked-account status | Host needs to determine current account state |
|
|
544
899
|
|
|
545
|
-
|
|
546
|
-
- `MESSAGE_VALIDATION_FAILED`
|
|
547
|
-
- `IFRAME_BLOCKED`
|
|
900
|
+
A typical host application can use them together:
|
|
548
901
|
|
|
549
|
-
|
|
902
|
+
```js
|
|
903
|
+
const status = await Dropp.status();
|
|
904
|
+
|
|
905
|
+
if (!status?.data?.linked) {
|
|
906
|
+
await Dropp.open('linkbank');
|
|
907
|
+
}
|
|
908
|
+
```
|
|
909
|
+
|
|
910
|
+
---
|
|
911
|
+
|
|
912
|
+
# 20. Custom Pages and Modules
|
|
550
913
|
|
|
551
|
-
|
|
914
|
+
The SDK allows the host application to open Dropp-managed pages directly.
|
|
552
915
|
|
|
553
|
-
|
|
916
|
+
This is useful when the merchant wants to provide access to specific wallet functionality while keeping the Dropp UI/UX.
|
|
554
917
|
|
|
555
|
-
|
|
556
|
-
- Missing constructor credentials (`merchantId`, `apiKey`).
|
|
557
|
-
- Modal iframe creation failure.
|
|
918
|
+
There are two main APIs:
|
|
558
919
|
|
|
559
|
-
|
|
920
|
+
```js
|
|
921
|
+
Dropp.dashboard(options);
|
|
922
|
+
```
|
|
923
|
+
|
|
924
|
+
and:
|
|
925
|
+
|
|
926
|
+
```js
|
|
927
|
+
Dropp.open(moduleId, options);
|
|
928
|
+
```
|
|
560
929
|
|
|
561
|
-
|
|
562
|
-
- Firefox 88+
|
|
563
|
-
- Safari 14+
|
|
564
|
-
- Edge 90+
|
|
930
|
+
### Hosted Page Options (SDK Supported)
|
|
565
931
|
|
|
566
|
-
|
|
932
|
+
Hosted page APIs support an options object used for lifecycle callbacks and page customization.
|
|
567
933
|
|
|
568
|
-
|
|
934
|
+
| Option | Type | Used By | Description |
|
|
935
|
+
|---|---|---|---|
|
|
936
|
+
| `onClose` | function | `dashboard`, `open`, `unlinkAccount`, `transactions`, `offers` | Called when modal closes. |
|
|
937
|
+
| `onCancel` | function | Hosted flows and payment flows | Called on cancellation/user close paths. |
|
|
938
|
+
| `onFailed` | function | Hosted flows | Called when hosted flow reports a general failure. |
|
|
939
|
+
| `onPageFailed` | function | Hosted flows | Called when a hosted page-level failure event is received. |
|
|
940
|
+
| `onAccountChanged` | function | Hosted flows | Called for account-link state changes coming from hosted page events. |
|
|
941
|
+
| `modules` | string[] | `dashboard` | Optional first-time-flow modules to display in sidebar. |
|
|
569
942
|
|
|
570
|
-
|
|
571
|
-
|
|
572
|
-
|
|
943
|
+
Example:
|
|
944
|
+
|
|
945
|
+
```js
|
|
946
|
+
Dropp.dashboard({
|
|
947
|
+
modules: ['funding', 'profile', 'support'],
|
|
948
|
+
onAccountChanged: payload => console.log('account changed', payload),
|
|
949
|
+
onPageFailed: err => console.error('dashboard page failed', err),
|
|
950
|
+
onClose: () => console.log('dashboard closed')
|
|
951
|
+
});
|
|
952
|
+
```
|
|
953
|
+
|
|
954
|
+
---
|
|
955
|
+
|
|
956
|
+
# 21. Dashboard
|
|
957
|
+
|
|
958
|
+
## `Dropp.dashboard(options)`
|
|
959
|
+
|
|
960
|
+
### Purpose
|
|
961
|
+
|
|
962
|
+
Opens the complete Dropp dashboard.
|
|
963
|
+
|
|
964
|
+
The dashboard is intended to be the central wallet-management experience where users can access the sections and pages enabled by the host application.
|
|
965
|
+
|
|
966
|
+
Use the dashboard when:
|
|
967
|
+
|
|
968
|
+
- The host wants to give the user broad access to Dropp wallet features.
|
|
969
|
+
- A dedicated wallet-management screen is not required in the host application.
|
|
970
|
+
- Multiple Dropp modules need to be exposed together.
|
|
971
|
+
|
|
972
|
+
## Example
|
|
973
|
+
|
|
974
|
+
```js
|
|
975
|
+
Dropp.dashboard({
|
|
976
|
+
modules: [
|
|
977
|
+
'funding',
|
|
978
|
+
'accounts',
|
|
979
|
+
'merchants',
|
|
980
|
+
'settings',
|
|
981
|
+
'support'
|
|
982
|
+
]
|
|
983
|
+
});
|
|
984
|
+
```
|
|
985
|
+
|
|
986
|
+
A smaller dashboard can be configured:
|
|
987
|
+
|
|
988
|
+
```js
|
|
989
|
+
Dropp.dashboard({
|
|
990
|
+
modules: [
|
|
991
|
+
'funding',
|
|
992
|
+
'profile',
|
|
993
|
+
'about'
|
|
994
|
+
]
|
|
995
|
+
});
|
|
996
|
+
```
|
|
997
|
+
|
|
998
|
+
`modules` is an optional list of section/item IDs that determines what is displayed in the sidebar.
|
|
999
|
+
|
|
1000
|
+
---
|
|
1001
|
+
|
|
1002
|
+
# 22. Direct Page Access
|
|
1003
|
+
|
|
1004
|
+
## `Dropp.open(moduleId, options)`
|
|
1005
|
+
|
|
1006
|
+
### Purpose
|
|
1007
|
+
|
|
1008
|
+
Opens a specific Dropp module/page directly instead of opening the full dashboard.
|
|
1009
|
+
|
|
1010
|
+
This is useful for:
|
|
1011
|
+
|
|
1012
|
+
- Deep linking.
|
|
1013
|
+
- Providing a direct "Link Bank" action.
|
|
1014
|
+
- Providing a direct "Transactions" action.
|
|
1015
|
+
- Opening profile/settings functionality.
|
|
1016
|
+
- Sending the user directly to a specific Dropp task.
|
|
1017
|
+
|
|
1018
|
+
Example:
|
|
1019
|
+
|
|
1020
|
+
```js
|
|
1021
|
+
Dropp.open('linkbank');
|
|
1022
|
+
Dropp.open('profile');
|
|
1023
|
+
Dropp.open('transactions');
|
|
1024
|
+
```
|
|
1025
|
+
|
|
1026
|
+
---
|
|
1027
|
+
|
|
1028
|
+
# 23. Supported Section IDs
|
|
1029
|
+
|
|
1030
|
+
The documented section IDs are:
|
|
1031
|
+
|
|
1032
|
+
| Section ID | Purpose |
|
|
1033
|
+
|---|---|
|
|
1034
|
+
| `funding` | Funding-related wallet functionality. |
|
|
1035
|
+
| `accounts` | Account/funding-source management functionality. |
|
|
1036
|
+
| `merchants` | Merchant-related functionality. |
|
|
1037
|
+
| `settings` | User and wallet settings. |
|
|
1038
|
+
| `support` | Support-related functionality. |
|
|
1039
|
+
|
|
1040
|
+
These IDs can be used with `Dropp.dashboard()` and the supported navigation model.
|
|
1041
|
+
|
|
1042
|
+
---
|
|
1043
|
+
|
|
1044
|
+
# 24. Supported Item/Page IDs
|
|
1045
|
+
|
|
1046
|
+
The following item IDs are documented.
|
|
1047
|
+
|
|
1048
|
+
| Item ID | Page Purpose |
|
|
1049
|
+
|---|---|
|
|
1050
|
+
| `fundnow` | Opens the funding-now experience so the user can fund the wallet. |
|
|
1051
|
+
| `linkbank` | Opens the bank-account linking flow. |
|
|
1052
|
+
| `linkcard` | Opens the card-linking flow. |
|
|
1053
|
+
| `redeemnow` | Opens the redeem-now experience. |
|
|
1054
|
+
| `fundcrypto` | Opens the cryptocurrency funding experience. |
|
|
1055
|
+
| `transferusdc` | Opens the USDC transfer experience. |
|
|
1056
|
+
| `usdchistory` | Opens USD transaction/history functionality. |
|
|
1057
|
+
| `redeemcrypto` | Opens the cryptocurrency redemption experience. |
|
|
1058
|
+
| `manageaccounts` | Opens account-management functionality. |
|
|
1059
|
+
| `transactions` | Opens transaction history. |
|
|
1060
|
+
| `merchantlist` | Opens the merchant list. |
|
|
1061
|
+
| `favorites` | Opens the user's favorite merchants/items where supported. |
|
|
1062
|
+
| `offers` | Opens available offers and promotions. |
|
|
1063
|
+
| `profile` | Opens the user's profile. |
|
|
1064
|
+
| `pinchange` | Opens the PIN-change functionality. |
|
|
1065
|
+
| `aboutus` | Opens the About Us page. |
|
|
1066
|
+
|
|
1067
|
+
> The page descriptions above describe the purpose implied by the documented module names and the existing SDK documentation. Any additional page-specific request parameters or callbacks should be documented from the SDK implementation if they are supported.
|
|
1068
|
+
|
|
1069
|
+
---
|
|
1070
|
+
|
|
1071
|
+
# 25. Custom Page Usage Examples
|
|
1072
|
+
|
|
1073
|
+
## Open Funding
|
|
1074
|
+
|
|
1075
|
+
```js
|
|
1076
|
+
Dropp.open('fundnow');
|
|
1077
|
+
```
|
|
1078
|
+
|
|
1079
|
+
Use when the host application wants the user to directly access wallet funding.
|
|
1080
|
+
|
|
1081
|
+
## Link Bank
|
|
1082
|
+
|
|
1083
|
+
```js
|
|
1084
|
+
Dropp.open('linkbank');
|
|
1085
|
+
```
|
|
1086
|
+
|
|
1087
|
+
Use when the user needs to connect a bank account.
|
|
1088
|
+
|
|
1089
|
+
## Link Card
|
|
1090
|
+
|
|
1091
|
+
```js
|
|
1092
|
+
Dropp.open('linkcard');
|
|
1093
|
+
```
|
|
1094
|
+
|
|
1095
|
+
Use when the user needs to connect a card.
|
|
1096
|
+
|
|
1097
|
+
## Transactions
|
|
1098
|
+
|
|
1099
|
+
```js
|
|
1100
|
+
Dropp.open('transactions');
|
|
1101
|
+
```
|
|
1102
|
+
|
|
1103
|
+
Use when the host application wants to show the user's transaction history.
|
|
1104
|
+
|
|
1105
|
+
## Profile
|
|
1106
|
+
|
|
1107
|
+
```js
|
|
1108
|
+
Dropp.open('profile');
|
|
1109
|
+
```
|
|
1110
|
+
|
|
1111
|
+
Use when the host application wants to send the user directly to profile management.
|
|
1112
|
+
|
|
1113
|
+
## Offers
|
|
1114
|
+
|
|
1115
|
+
```js
|
|
1116
|
+
Dropp.open('offers');
|
|
1117
|
+
```
|
|
1118
|
+
|
|
1119
|
+
Use when the merchant wants the user to view available promotions and offers.
|
|
1120
|
+
|
|
1121
|
+
## About
|
|
1122
|
+
|
|
1123
|
+
```js
|
|
1124
|
+
Dropp.open('aboutus');
|
|
1125
|
+
```
|
|
1126
|
+
|
|
1127
|
+
Use to open the Dropp About Us page.
|
|
1128
|
+
|
|
1129
|
+
---
|
|
1130
|
+
|
|
1131
|
+
# 26. Choosing Between Dashboard and `open()`
|
|
1132
|
+
|
|
1133
|
+
Use `Dropp.dashboard()` when:
|
|
1134
|
+
|
|
1135
|
+
```text
|
|
1136
|
+
The user needs access to multiple wallet functions.
|
|
1137
|
+
```
|
|
1138
|
+
|
|
1139
|
+
Use `Dropp.open()` when:
|
|
1140
|
+
|
|
1141
|
+
```text
|
|
1142
|
+
The host application knows exactly which task the user needs to perform.
|
|
1143
|
+
```
|
|
1144
|
+
|
|
1145
|
+
Example:
|
|
1146
|
+
|
|
1147
|
+
```text
|
|
1148
|
+
Host App
|
|
1149
|
+
|
|
|
1150
|
+
+-- "Wallet" button
|
|
1151
|
+
| ↓
|
|
1152
|
+
| Dropp.dashboard()
|
|
1153
|
+
|
|
|
1154
|
+
+-- "Link Bank" button
|
|
1155
|
+
| ↓
|
|
1156
|
+
| Dropp.open('linkbank')
|
|
1157
|
+
|
|
|
1158
|
+
+-- "Transactions" button
|
|
1159
|
+
↓
|
|
1160
|
+
Dropp.open('transactions')
|
|
1161
|
+
```
|
|
1162
|
+
|
|
1163
|
+
---
|
|
1164
|
+
|
|
1165
|
+
# 27. Utility APIs
|
|
1166
|
+
|
|
1167
|
+
The SDK also exposes utility functions.
|
|
1168
|
+
|
|
1169
|
+
## 27.1 `getInstance()`
|
|
1170
|
+
|
|
1171
|
+
Returns the current initialized SDK instance.
|
|
1172
|
+
|
|
1173
|
+
```js
|
|
1174
|
+
const instance = Dropp.getInstance();
|
|
1175
|
+
```
|
|
1176
|
+
|
|
1177
|
+
The documented return type is:
|
|
1178
|
+
|
|
1179
|
+
```text
|
|
1180
|
+
DroppPaymentSDK | null
|
|
1181
|
+
```
|
|
1182
|
+
|
|
1183
|
+
It returns `null` when an initialized SDK instance is not available.
|
|
1184
|
+
|
|
1185
|
+
Use this primarily for SDK state/diagnostic purposes rather than as the primary integration API.
|
|
1186
|
+
|
|
1187
|
+
---
|
|
1188
|
+
|
|
1189
|
+
# 28. Unified Callbacks
|
|
1190
|
+
|
|
1191
|
+
The SDK uses callbacks to notify the host application about payment-flow state.
|
|
1192
|
+
|
|
1193
|
+
| Callback | When It Is Triggered |
|
|
1194
|
+
|---|---|
|
|
1195
|
+
| `onSuccess` | Payment or authorization completed successfully. |
|
|
1196
|
+
| `onFailure` | Transaction failed, for example due to insufficient funds or technical errors. |
|
|
1197
|
+
| `onCancel` | User explicitly closed the payment window without completing the payment. |
|
|
1198
|
+
|
|
1199
|
+
A host application should use these callbacks, where configured/supported by the SDK integration, to update its own UI and application state.
|
|
1200
|
+
|
|
1201
|
+
---
|
|
1202
|
+
|
|
1203
|
+
# 29. Payment Response — Standard
|
|
1204
|
+
|
|
1205
|
+
A Standard Payment returns a response similar to:
|
|
1206
|
+
|
|
1207
|
+
```js
|
|
1208
|
+
{
|
|
1209
|
+
success: true,
|
|
1210
|
+
paymentType: 'PAYMENT',
|
|
1211
|
+
title: 'Payment Successful!',
|
|
1212
|
+
message: 'Payment successful!',
|
|
1213
|
+
transactionId: 'ABCS-38947835',
|
|
1214
|
+
invoiceId: 'ABC-29388474',
|
|
1215
|
+
reference: 'ORDER-12345',
|
|
1216
|
+
merchantAccount: '0.0.100010',
|
|
1217
|
+
amount: 50,
|
|
1218
|
+
currency: 'USD',
|
|
1219
|
+
paidAmount: 50,
|
|
1220
|
+
paidCurrency: 'USD',
|
|
1221
|
+
itemName: 'PARKING BILL',
|
|
1222
|
+
description: 'Parking Meter Bill for 30min',
|
|
1223
|
+
paymentRef: 'response.data.paymentRef',
|
|
1224
|
+
iso20022Response: '<?xml version="1.0"...',
|
|
1225
|
+
sessionDuration: 9425
|
|
1226
|
+
}
|
|
1227
|
+
```
|
|
1228
|
+
|
|
1229
|
+
Important response fields:
|
|
1230
|
+
|
|
1231
|
+
| Field | Type | Description |
|
|
1232
|
+
|---|---|---|
|
|
1233
|
+
| `success` | boolean | Whether the payment succeeded. |
|
|
1234
|
+
| `paymentType` | string | `PAYMENT` for Standard Payment. |
|
|
1235
|
+
| `message` | string | Payment status message. |
|
|
1236
|
+
| `transactionId` | string | Transaction reference. |
|
|
1237
|
+
| `reference` | string | Merchant-side reference. |
|
|
1238
|
+
| `merchantAccount` | string | Merchant account ID. |
|
|
1239
|
+
| `amount` | number | Requested payment amount. |
|
|
1240
|
+
| `currency` | string | Requested currency. |
|
|
1241
|
+
| `paidAmount` | string/number | Actual amount paid. |
|
|
1242
|
+
| `paidCurrency` | string | Currency used for payment. |
|
|
1243
|
+
| `itemName` | string | Item name. |
|
|
1244
|
+
| `description` | string | Payment description. |
|
|
1245
|
+
| `receiptURL` | string/null | Receipt URL when available. |
|
|
1246
|
+
| `timestamp` | string/null | Payment timestamp when available. |
|
|
1247
|
+
|
|
1248
|
+
---
|
|
1249
|
+
|
|
1250
|
+
# 30. Payment Response — PreAuth
|
|
1251
|
+
|
|
1252
|
+
A successful PreAuth response is similar to:
|
|
1253
|
+
|
|
1254
|
+
```js
|
|
1255
|
+
{
|
|
1256
|
+
success: true,
|
|
1257
|
+
paymentType: 'PREAUTH',
|
|
1258
|
+
title: 'Pre-Auth Approved!',
|
|
1259
|
+
message: 'Pre-auth approved successfully!',
|
|
1260
|
+
transactionId: 'ABCD-1238838',
|
|
1261
|
+
reference: 'RESERVATION-12345',
|
|
1262
|
+
invoiceId: 'ABCD-20384774',
|
|
1263
|
+
merchantAccount: '0.0.001000',
|
|
1264
|
+
amount: 50,
|
|
1265
|
+
currency: 'USD',
|
|
1266
|
+
approvedAmount: 32,
|
|
1267
|
+
approvedCurrency: 'USD',
|
|
1268
|
+
iso20022Response: '<?xml version="1.0"...',
|
|
1269
|
+
sessionDuration: 8959
|
|
1270
|
+
}
|
|
1271
|
+
```
|
|
1272
|
+
|
|
1273
|
+
Important fields:
|
|
1274
|
+
|
|
1275
|
+
| Field | Type | Description |
|
|
1276
|
+
|---|---|---|
|
|
1277
|
+
| `success` | boolean | Whether authorization succeeded. |
|
|
1278
|
+
| `paymentType` | string | `PREAUTH`. |
|
|
1279
|
+
| `message` | string | Authorization status. |
|
|
1280
|
+
| `transactionId` | string | Transaction reference. |
|
|
1281
|
+
| `reference` | string | Merchant-side reference. |
|
|
1282
|
+
| `merchantAccount` | string | Merchant account ID. |
|
|
1283
|
+
| `amount` | number | Requested authorization amount. |
|
|
1284
|
+
| `currency` | string | Requested currency. |
|
|
1285
|
+
| `approvedAmount` | string/number | Authorized amount. |
|
|
1286
|
+
| `approvedCurrency` | string | Currency of the authorized amount. |
|
|
1287
|
+
|
|
1288
|
+
---
|
|
1289
|
+
|
|
1290
|
+
# 31. Recurring Payment Response
|
|
1291
|
+
|
|
1292
|
+
A successful recurring response is similar to:
|
|
1293
|
+
|
|
1294
|
+
```js
|
|
1295
|
+
{
|
|
1296
|
+
success: true,
|
|
1297
|
+
paymentType: 'RECURRING',
|
|
1298
|
+
title: 'Recurring Approved!',
|
|
1299
|
+
message: 'Recurring payment approved successfully!',
|
|
1300
|
+
transactionId: '1687-20260602',
|
|
1301
|
+
recurringToken: null,
|
|
1302
|
+
reference: null,
|
|
1303
|
+
invoiceId: 'INV-RECURRING-1780388213609',
|
|
1304
|
+
receiptURL: 'https://qa.pay.dropp.cc/receipts/1687-20260602',
|
|
1305
|
+
timestamp: '2026-06-02T08:17:03.539270201Z',
|
|
1306
|
+
merchantAccount: '0.0.4646049',
|
|
1307
|
+
amount: 1,
|
|
1308
|
+
currency: 'USD',
|
|
1309
|
+
approvedAmount: 1,
|
|
1310
|
+
approvedCurrency: 'USD',
|
|
1311
|
+
frequency: 'MONTHLY',
|
|
1312
|
+
iso20022Response: '<?xml version="1.0"...'
|
|
1313
|
+
}
|
|
1314
|
+
```
|
|
1315
|
+
|
|
1316
|
+
Important fields:
|
|
1317
|
+
|
|
1318
|
+
| Field | Type | Description |
|
|
1319
|
+
|---|---|---|
|
|
1320
|
+
| `success` | boolean | Whether recurring authorization succeeded. |
|
|
1321
|
+
| `paymentType` | string | `RECURRING`. |
|
|
1322
|
+
| `message` | string | Authorization status. |
|
|
1323
|
+
| `transactionId` | string | Transaction reference. |
|
|
1324
|
+
| `reference` | string | Merchant-side reference. |
|
|
1325
|
+
| `merchantAccount` | string | Merchant account ID. |
|
|
1326
|
+
| `amount` | number | Requested amount. |
|
|
1327
|
+
| `currency` | string | Requested currency. |
|
|
1328
|
+
| `approvedAmount` | string/number | Approved recurring amount. |
|
|
1329
|
+
| `approvedCurrency` | string | Currency of the approved amount. |
|
|
1330
|
+
| `frequency` | string | Recurring interval. |
|
|
1331
|
+
|
|
1332
|
+
For recurring flows, the merchant backend is responsible for securely storing the recurring token where applicable because it is required for future captures/recurring authorization according to the documented flow.
|
|
1333
|
+
|
|
1334
|
+
---
|
|
1335
|
+
|
|
1336
|
+
# 32. Failed Payment Handling
|
|
1337
|
+
|
|
1338
|
+
A payment can fail in two ways:
|
|
1339
|
+
|
|
1340
|
+
1. `Dropp.pay()` returns an unsuccessful response.
|
|
1341
|
+
2. `Dropp.pay()` rejects the Promise.
|
|
1342
|
+
|
|
1343
|
+
Always handle both.
|
|
1344
|
+
|
|
1345
|
+
```js
|
|
1346
|
+
try {
|
|
1347
|
+
const result = await Dropp.pay(paymentOptions);
|
|
1348
|
+
|
|
1349
|
+
const isSuccess = result?.success === true || result?.status === 'success';
|
|
1350
|
+
if (!isSuccess) {
|
|
1351
|
+
console.error('Payment unsuccessful');
|
|
1352
|
+
// Show failure UI
|
|
1353
|
+
}
|
|
1354
|
+
} catch (error) {
|
|
1355
|
+
console.error('Payment error', error);
|
|
1356
|
+
// Handle SDK/runtime error
|
|
1357
|
+
}
|
|
1358
|
+
```
|
|
1359
|
+
|
|
1360
|
+
Do not fulfill an order solely because the payment window closed or because the Promise was returned. Verify the payment state on the merchant backend.
|
|
1361
|
+
|
|
1362
|
+
---
|
|
1363
|
+
|
|
1364
|
+
# 33. Error Handling
|
|
1365
|
+
|
|
1366
|
+
The SDK documents the following error codes.
|
|
1367
|
+
|
|
1368
|
+
| Error Code | Meaning | Recommended Action |
|
|
1369
|
+
|---|---|---|
|
|
1370
|
+
| `INVALID_CONFIG` | Input or merchant validation failed. | Check required fields, environment, credentials, callback URL, and application configuration. |
|
|
1371
|
+
| `ALREADY_OPEN` | Another SDK flow is already active. | Wait for the active flow to finish or close it before starting another flow. |
|
|
1372
|
+
| `INIT_TIMEOUT` | Payment/status flow did not initialize within the expected time. | Check environment URL/connectivity and retry. |
|
|
1373
|
+
| `PAYMENT_TIMEOUT` | Payment did not complete within the expected time. | Ask the user to retry and verify backend payment state. |
|
|
1374
|
+
| `UNKNOWN_ERROR` | Unexpected runtime/processing error. | Log the details, retry if appropriate, and contact support if persistent. |
|
|
1375
|
+
| `SDK_NOT_INITIALIZED` | SDK method was called before `Dropp.init()`. | Initialize the SDK before using payment/account/page APIs. |
|
|
1376
|
+
|
|
1377
|
+
### 33.1 Merchant Validation Error Details
|
|
1378
|
+
|
|
1379
|
+
When merchant validation fails, SDK errors include structured fields in `error.details`, including backend response payload where available.
|
|
1380
|
+
|
|
1381
|
+
Use both top-level message and details when logging:
|
|
1382
|
+
|
|
1383
|
+
```js
|
|
1384
|
+
try {
|
|
1385
|
+
await Dropp.init({ merchantId, apiKey, environment: 'sandbox' });
|
|
1386
|
+
} catch (error) {
|
|
1387
|
+
console.error('Dropp init failed:', error?.message);
|
|
1388
|
+
console.error('Dropp init details:', error?.details);
|
|
1389
|
+
}
|
|
1390
|
+
```
|
|
1391
|
+
|
|
1392
|
+
The SDK message for validation failures may include HTTP status, backend `responseCode`, and a backend-reported reason when present.
|
|
1393
|
+
|
|
1394
|
+
---
|
|
1395
|
+
|
|
1396
|
+
# 34. Reserved Error Codes
|
|
1397
|
+
|
|
1398
|
+
The SDK defines the following codes for compatibility/extension, but the documented implementation does not currently emit them as SDK errors:
|
|
1399
|
+
|
|
1400
|
+
- `ORIGIN_MISMATCH`
|
|
1401
|
+
- `MESSAGE_VALIDATION_FAILED`
|
|
1402
|
+
- `IFRAME_BLOCKED`
|
|
1403
|
+
|
|
1404
|
+
For these conditions, the SDK currently logs warnings/errors and ignores invalid messages.
|
|
1405
|
+
|
|
1406
|
+
---
|
|
1407
|
+
|
|
1408
|
+
# 35. Additional Errors
|
|
1409
|
+
|
|
1410
|
+
Some SDK paths may throw standard JavaScript `Error` objects rather than the SDK's structured error format.
|
|
1411
|
+
|
|
1412
|
+
Examples include:
|
|
1413
|
+
|
|
1414
|
+
- SDK used outside a browser environment.
|
|
1415
|
+
- Missing constructor credentials such as `merchantId` or `apiKey`.
|
|
1416
|
+
- Failure while creating the modal iframe.
|
|
1417
|
+
|
|
1418
|
+
The host application should therefore use `try/catch` around asynchronous SDK operations and should not assume every error has a Dropp-specific error code.
|
|
1419
|
+
|
|
1420
|
+
---
|
|
1421
|
+
|
|
1422
|
+
# 36. React Integration
|
|
1423
|
+
|
|
1424
|
+
```js
|
|
1425
|
+
import { useEffect } from 'react';
|
|
1426
|
+
import { Dropp } from '@dropp.cc/payment-sdk';
|
|
1427
|
+
|
|
1428
|
+
function App() {
|
|
1429
|
+
useEffect(() => {
|
|
1430
|
+
Dropp.init({
|
|
1431
|
+
merchantId: 'YOUR_MERCHANT_ID',
|
|
1432
|
+
apiKey: 'YOUR_API_KEY',
|
|
1433
|
+
environment: 'production'
|
|
1434
|
+
});
|
|
1435
|
+
}, []);
|
|
1436
|
+
|
|
1437
|
+
const handlePayment = async () => {
|
|
1438
|
+
try {
|
|
1439
|
+
const result = await Dropp.pay({
|
|
1440
|
+
amount: 99.99,
|
|
1441
|
+
currency: 'USD',
|
|
1442
|
+
itemName: 'Product Purchase',
|
|
1443
|
+
paymentType: 'standard',
|
|
1444
|
+
description: 'Product purchase',
|
|
1445
|
+
invoiceId: 'ORDER-12345'
|
|
1446
|
+
});
|
|
1447
|
+
|
|
1448
|
+
console.log(result);
|
|
1449
|
+
} catch (error) {
|
|
1450
|
+
console.error(error);
|
|
1451
|
+
}
|
|
1452
|
+
};
|
|
1453
|
+
|
|
1454
|
+
return (
|
|
1455
|
+
<button onClick={handlePayment}>
|
|
1456
|
+
Pay with Dropp
|
|
1457
|
+
</button>
|
|
1458
|
+
);
|
|
1459
|
+
}
|
|
1460
|
+
```
|
|
1461
|
+
|
|
1462
|
+
---
|
|
1463
|
+
|
|
1464
|
+
# 37. Vanilla JavaScript Integration
|
|
1465
|
+
|
|
1466
|
+
Include the SDK:
|
|
1467
|
+
|
|
1468
|
+
```html
|
|
1469
|
+
<script src="https://unpkg.com/@dropp.cc/payment-sdk/dist/dropp-payment-sdk.js"></script>
|
|
1470
|
+
```
|
|
1471
|
+
|
|
1472
|
+
Initialize:
|
|
1473
|
+
|
|
1474
|
+
```js
|
|
1475
|
+
const { Dropp } = window.DroppPaymentSDK;
|
|
1476
|
+
|
|
1477
|
+
Dropp.init({
|
|
1478
|
+
merchantId: 'YOUR_MERCHANT_ID',
|
|
1479
|
+
apiKey: 'YOUR_API_KEY',
|
|
1480
|
+
environment: 'production'
|
|
1481
|
+
});
|
|
1482
|
+
```
|
|
1483
|
+
|
|
1484
|
+
Execute a payment:
|
|
1485
|
+
|
|
1486
|
+
```js
|
|
1487
|
+
const result = await Dropp.pay({
|
|
1488
|
+
amount: 49.99,
|
|
1489
|
+
currency: 'USD',
|
|
1490
|
+
itemName: 'One-time Purchase',
|
|
1491
|
+
paymentType: 'standard',
|
|
1492
|
+
description: 'One-time purchase',
|
|
1493
|
+
invoiceId: 'ORDER-12345'
|
|
1494
|
+
});
|
|
1495
|
+
```
|
|
1496
|
+
|
|
1497
|
+
---
|
|
1498
|
+
|
|
1499
|
+
# 38. Complete Host Application Example
|
|
1500
|
+
|
|
1501
|
+
A typical host application can combine initialization, status, custom pages, and payments:
|
|
1502
|
+
|
|
1503
|
+
```js
|
|
1504
|
+
import { Dropp } from '@dropp.cc/payment-sdk';
|
|
1505
|
+
|
|
1506
|
+
Dropp.init({
|
|
1507
|
+
merchantId: 'YOUR_MERCHANT_ID',
|
|
1508
|
+
apiKey: 'YOUR_API_KEY',
|
|
1509
|
+
environment: 'sandbox'
|
|
1510
|
+
});
|
|
1511
|
+
|
|
1512
|
+
async function openWallet() {
|
|
1513
|
+
Dropp.dashboard({
|
|
1514
|
+
modules: [
|
|
1515
|
+
'funding',
|
|
1516
|
+
'accounts',
|
|
1517
|
+
'transactions',
|
|
1518
|
+
'settings',
|
|
1519
|
+
'support'
|
|
1520
|
+
]
|
|
1521
|
+
});
|
|
1522
|
+
}
|
|
1523
|
+
|
|
1524
|
+
async function checkAccount() {
|
|
1525
|
+
const status = await Dropp.status();
|
|
1526
|
+
|
|
1527
|
+
if (status?.data?.linked) {
|
|
1528
|
+
console.log('Account is linked');
|
|
1529
|
+
} else {
|
|
1530
|
+
console.log('Account is not linked');
|
|
1531
|
+
}
|
|
1532
|
+
}
|
|
1533
|
+
|
|
1534
|
+
async function linkBank() {
|
|
1535
|
+
Dropp.open('linkbank');
|
|
1536
|
+
}
|
|
1537
|
+
|
|
1538
|
+
async function unlinkAccount() {
|
|
1539
|
+
Dropp.unlinkAccount();
|
|
1540
|
+
}
|
|
1541
|
+
|
|
1542
|
+
async function pay() {
|
|
1543
|
+
try {
|
|
1544
|
+
const result = await Dropp.pay({
|
|
1545
|
+
amount: 49.99,
|
|
1546
|
+
currency: 'USD',
|
|
1547
|
+
itemName: 'Product Purchase',
|
|
1548
|
+
paymentType: 'standard',
|
|
1549
|
+
description: 'Product purchase',
|
|
1550
|
+
invoiceId: 'ORDER-12345'
|
|
1551
|
+
});
|
|
1552
|
+
|
|
1553
|
+
if (result?.status === 'success' || result?.success === true) {
|
|
1554
|
+
console.log('Payment successful');
|
|
1555
|
+
} else {
|
|
1556
|
+
console.log('Payment unsuccessful');
|
|
1557
|
+
}
|
|
1558
|
+
} catch (error) {
|
|
1559
|
+
console.error('Payment error', error);
|
|
1560
|
+
}
|
|
1561
|
+
}
|
|
1562
|
+
```
|
|
1563
|
+
|
|
1564
|
+
---
|
|
1565
|
+
|
|
1566
|
+
# 39. Security Requirements
|
|
1567
|
+
|
|
1568
|
+
The host application must follow these security practices:
|
|
1569
|
+
|
|
1570
|
+
### Required
|
|
1571
|
+
|
|
1572
|
+
- Use HTTPS in production.
|
|
1573
|
+
- Keep API credentials secure.
|
|
1574
|
+
- Keep private signing keys on the backend.
|
|
1575
|
+
- Verify transactions on the merchant backend.
|
|
1576
|
+
- Store merchant-side order/reference identifiers.
|
|
1577
|
+
- Use unique invoice/order identifiers.
|
|
1578
|
+
- Log payment events for auditing.
|
|
1579
|
+
- Validate payment status before fulfilling an order.
|
|
1580
|
+
|
|
1581
|
+
### Do Not
|
|
1582
|
+
|
|
1583
|
+
- Expose private signing keys in frontend code.
|
|
1584
|
+
- Hard-code backend signing secrets into browser JavaScript.
|
|
1585
|
+
- Trust only client-side payment state for order fulfillment.
|
|
1586
|
+
- Reuse invoice identifiers.
|
|
1587
|
+
|
|
1588
|
+
---
|
|
1589
|
+
|
|
1590
|
+
# 40. Backend Verification
|
|
1591
|
+
|
|
1592
|
+
After a successful payment/authorization response, the merchant backend should:
|
|
1593
|
+
|
|
1594
|
+
1. Verify the payment status.
|
|
1595
|
+
2. Validate transaction details.
|
|
1596
|
+
3. Match the payment with the merchant's order/reference.
|
|
1597
|
+
4. Update the order or subscription.
|
|
1598
|
+
5. Fulfill the order or activate the subscription.
|
|
1599
|
+
|
|
1600
|
+
For recurring payments, the merchant should also maintain the subscription/authorization state and securely handle the recurring authorization information required for future billing.
|
|
1601
|
+
|
|
1602
|
+
---
|
|
1603
|
+
|
|
1604
|
+
# 41. Message/Event Flow
|
|
1605
|
+
|
|
1606
|
+
Communication between the host application and the Dropp frame follows the documented message flow:
|
|
1607
|
+
|
|
1608
|
+
```text
|
|
1609
|
+
READY
|
|
1610
|
+
↓
|
|
1611
|
+
Frame is loaded
|
|
1612
|
+
|
|
1613
|
+
PAYMENT_INIT
|
|
1614
|
+
↓
|
|
1615
|
+
Host sends payment data
|
|
1616
|
+
|
|
1617
|
+
PAYMENT_SUCCESS / PAYMENT_FAILED
|
|
1618
|
+
↓
|
|
1619
|
+
Dropp frame returns the result
|
|
1620
|
+
```
|
|
1621
|
+
|
|
1622
|
+
The SDK is responsible for the iframe communication layer. The host application should consume the SDK APIs and callbacks rather than implementing the iframe messaging protocol directly.
|
|
1623
|
+
|
|
1624
|
+
---
|
|
1625
|
+
|
|
1626
|
+
# 42. Recommended Integration Patterns
|
|
1627
|
+
|
|
1628
|
+
## Pattern A — One-Time Checkout
|
|
1629
|
+
|
|
1630
|
+
Use:
|
|
1631
|
+
|
|
1632
|
+
```js
|
|
1633
|
+
Dropp.init(...)
|
|
1634
|
+
Dropp.pay({
|
|
1635
|
+
paymentType: 'standard',
|
|
1636
|
+
...
|
|
1637
|
+
})
|
|
1638
|
+
```
|
|
1639
|
+
|
|
1640
|
+
Recommended for normal checkout.
|
|
1641
|
+
|
|
1642
|
+
---
|
|
1643
|
+
|
|
1644
|
+
## Pattern B — Temporary Authorization
|
|
1645
|
+
|
|
1646
|
+
Use:
|
|
1647
|
+
|
|
1648
|
+
```js
|
|
1649
|
+
Dropp.init(...)
|
|
1650
|
+
Dropp.pay({
|
|
1651
|
+
paymentType: 'preauth',
|
|
1652
|
+
callbackUrl: 'https://merchant.example.com/pre-auth-post-callback',
|
|
1653
|
+
...
|
|
1654
|
+
})
|
|
1655
|
+
```
|
|
1656
|
+
|
|
1657
|
+
Recommended when the merchant needs authorization before the final charge.
|
|
1658
|
+
|
|
1659
|
+
The merchant must provide the backend callback/signing infrastructure.
|
|
1660
|
+
|
|
1661
|
+
---
|
|
1662
|
+
|
|
1663
|
+
## Pattern C — Subscription
|
|
1664
|
+
|
|
1665
|
+
Use:
|
|
1666
|
+
|
|
1667
|
+
```js
|
|
1668
|
+
Dropp.init(...)
|
|
1669
|
+
Dropp.pay({
|
|
1670
|
+
paymentType: 'recurring',
|
|
1671
|
+
callbackUrl: 'https://merchant.example.com/rps-callback',
|
|
1672
|
+
...
|
|
1673
|
+
})
|
|
1674
|
+
```
|
|
1675
|
+
|
|
1676
|
+
Recommended for recurring/subscription billing.
|
|
1677
|
+
|
|
1678
|
+
The merchant must provide the backend callback/signing infrastructure.
|
|
1679
|
+
|
|
1680
|
+
---
|
|
1681
|
+
|
|
1682
|
+
## Pattern D — Wallet Management
|
|
1683
|
+
|
|
1684
|
+
Use:
|
|
1685
|
+
|
|
1686
|
+
```js
|
|
1687
|
+
Dropp.dashboard(...)
|
|
1688
|
+
```
|
|
1689
|
+
|
|
1690
|
+
when the user needs access to several wallet features.
|
|
1691
|
+
|
|
1692
|
+
---
|
|
1693
|
+
|
|
1694
|
+
## Pattern E — Deep Link
|
|
1695
|
+
|
|
1696
|
+
Use:
|
|
1697
|
+
|
|
1698
|
+
```js
|
|
1699
|
+
Dropp.open('transactions');
|
|
1700
|
+
Dropp.open('linkbank');
|
|
1701
|
+
Dropp.open('profile');
|
|
1702
|
+
```
|
|
1703
|
+
|
|
1704
|
+
when the host application wants to take the user directly to a specific page.
|
|
1705
|
+
|
|
1706
|
+
---
|
|
1707
|
+
|
|
1708
|
+
## Pattern F — Account State Check
|
|
1709
|
+
|
|
1710
|
+
Use:
|
|
1711
|
+
|
|
1712
|
+
```js
|
|
1713
|
+
const status = await Dropp.status();
|
|
1714
|
+
```
|
|
1715
|
+
|
|
1716
|
+
when the host application needs to determine whether the user's Dropp account is linked before presenting the next action.
|
|
1717
|
+
|
|
1718
|
+
---
|
|
1719
|
+
|
|
1720
|
+
# 43. Testing Checklist
|
|
1721
|
+
|
|
1722
|
+
## Prerequisites
|
|
1723
|
+
|
|
1724
|
+
- [ ] Merchant account is active.
|
|
1725
|
+
- [ ] KYC is completed.
|
|
1726
|
+
- [ ] Correct Merchant ID is available.
|
|
1727
|
+
- [ ] API Key is generated.
|
|
1728
|
+
- [ ] Host domain/package name is registered.
|
|
1729
|
+
- [ ] Package/domain configuration matches the host application.
|
|
1730
|
+
|
|
1731
|
+
## SDK Initialization
|
|
1732
|
+
|
|
1733
|
+
- [ ] Correct environment selected.
|
|
1734
|
+
- [ ] Correct Merchant ID configured.
|
|
1735
|
+
- [ ] Correct API Key configured.
|
|
1736
|
+
- [ ] Package Name/Domain configured.
|
|
1737
|
+
- [ ] SDK initializes without errors.
|
|
1738
|
+
|
|
1739
|
+
## Standard Payment
|
|
1740
|
+
|
|
1741
|
+
- [ ] Successful payment tested.
|
|
1742
|
+
- [ ] Failed payment tested.
|
|
1743
|
+
- [ ] Cancelled payment tested.
|
|
1744
|
+
- [ ] Backend verification tested.
|
|
1745
|
+
- [ ] Order fulfillment tested.
|
|
1746
|
+
|
|
1747
|
+
## PreAuth
|
|
1748
|
+
|
|
1749
|
+
- [ ] Public HTTPS callback URL configured.
|
|
1750
|
+
- [ ] Merchant backend is running.
|
|
1751
|
+
- [ ] Dropp Backend SDK is configured.
|
|
1752
|
+
- [ ] Signing flow verified.
|
|
1753
|
+
- [ ] Authorization hold duration tested.
|
|
1754
|
+
- [ ] Authorization expiration tested.
|
|
1755
|
+
- [ ] Failed callback/signing scenario tested.
|
|
1756
|
+
|
|
1757
|
+
## Recurring
|
|
1758
|
+
|
|
1759
|
+
- [ ] Public HTTPS callback URL configured.
|
|
1760
|
+
- [ ] Merchant backend is running.
|
|
1761
|
+
- [ ] Recurring authorization signing verified.
|
|
1762
|
+
- [ ] Supported frequency tested.
|
|
1763
|
+
- [ ] `recurringEndDate` tested.
|
|
1764
|
+
- [ ] Recurring authorization response handled.
|
|
1765
|
+
- [ ] Future authorization/capture handling verified.
|
|
1766
|
+
|
|
1767
|
+
## Account APIs
|
|
1768
|
+
|
|
1769
|
+
- [ ] `status()` tested for linked account.
|
|
1770
|
+
- [ ] `status()` tested for unlinked account.
|
|
1771
|
+
- [ ] Bank linking tested.
|
|
1772
|
+
- [ ] Card linking tested.
|
|
1773
|
+
- [ ] Unlink flow tested.
|
|
1774
|
+
|
|
1775
|
+
## Custom Pages
|
|
1776
|
+
|
|
1777
|
+
- [ ] Dashboard opens correctly.
|
|
1778
|
+
- [ ] Configured modules appear correctly.
|
|
1779
|
+
- [ ] Direct page navigation tested.
|
|
1780
|
+
- [ ] Transactions page tested.
|
|
1781
|
+
- [ ] Profile page tested.
|
|
1782
|
+
- [ ] Funding pages tested.
|
|
1783
|
+
- [ ] Offers page tested.
|
|
1784
|
+
|
|
1785
|
+
## Security
|
|
1786
|
+
|
|
1787
|
+
- [ ] HTTPS enabled.
|
|
1788
|
+
- [ ] Private signing key remains on backend.
|
|
1789
|
+
- [ ] Backend payment verification implemented.
|
|
1790
|
+
- [ ] Secrets are not exposed to frontend.
|
|
1791
|
+
- [ ] Unique order/reference identifiers are used.
|
|
1792
|
+
|
|
1793
|
+
---
|
|
1794
|
+
|
|
1795
|
+
# 44. Troubleshooting
|
|
1796
|
+
|
|
1797
|
+
## Payment Window Does Not Open
|
|
1798
|
+
|
|
1799
|
+
Verify:
|
|
1800
|
+
|
|
1801
|
+
- SDK initialization completed successfully.
|
|
1802
|
+
- Required parameters are present.
|
|
1803
|
+
- Merchant ID is correct.
|
|
1804
|
+
- API Key is correct.
|
|
1805
|
+
- Environment matches the credentials.
|
|
1806
|
+
- Host domain/package name is correctly registered.
|
|
1807
|
+
- Browser console contains no errors.
|
|
1808
|
+
- Another SDK flow is not already active.
|
|
1809
|
+
|
|
1810
|
+
---
|
|
1811
|
+
|
|
1812
|
+
## `SDK_NOT_INITIALIZED`
|
|
1813
|
+
|
|
1814
|
+
Cause:
|
|
1815
|
+
|
|
1816
|
+
```text
|
|
1817
|
+
Dropp.pay()
|
|
1818
|
+
Dropp.status()
|
|
1819
|
+
Dropp.dashboard()
|
|
1820
|
+
Dropp.open()
|
|
1821
|
+
```
|
|
1822
|
+
|
|
1823
|
+
or another SDK API was called before initialization.
|
|
1824
|
+
|
|
1825
|
+
Solution:
|
|
1826
|
+
|
|
1827
|
+
```js
|
|
1828
|
+
Dropp.init({
|
|
1829
|
+
merchantId: 'YOUR_MERCHANT_ID',
|
|
1830
|
+
apiKey: 'YOUR_API_KEY',
|
|
1831
|
+
environment: 'sandbox'
|
|
1832
|
+
});
|
|
1833
|
+
```
|
|
1834
|
+
|
|
1835
|
+
Call SDK functionality only after initialization has completed.
|
|
1836
|
+
|
|
1837
|
+
---
|
|
1838
|
+
|
|
1839
|
+
## Callback Not Triggered
|
|
1840
|
+
|
|
1841
|
+
For PreAuth and recurring payments, verify:
|
|
1842
|
+
|
|
1843
|
+
- Callback URL is correct.
|
|
1844
|
+
- Callback URL is publicly accessible.
|
|
1845
|
+
- HTTPS is enabled.
|
|
1846
|
+
- Backend application is running.
|
|
1847
|
+
- Backend endpoint is mapped to the expected callback route.
|
|
1848
|
+
- Backend returns the expected signed response.
|
|
1849
|
+
- Merchant ID and signing key are correctly configured.
|
|
1850
|
+
|
|
1851
|
+
---
|
|
1852
|
+
|
|
1853
|
+
## Invalid Merchant Error
|
|
1854
|
+
|
|
1855
|
+
Verify:
|
|
1856
|
+
|
|
1857
|
+
- Merchant ID is correct.
|
|
1858
|
+
- API Key belongs to the same environment.
|
|
1859
|
+
- Host application/domain configuration is registered.
|
|
1860
|
+
- Host application is running on the registered domain.
|
|
1861
|
+
- Sandbox credentials are not being used against production.
|
|
1862
|
+
|
|
1863
|
+
---
|
|
1864
|
+
|
|
1865
|
+
## Environment Mismatch
|
|
1866
|
+
|
|
1867
|
+
Verify that credentials and wallets match the environment:
|
|
1868
|
+
|
|
1869
|
+
```text
|
|
1870
|
+
Sandbox → Sandbox Merchant ID + Sandbox API Key + Sandbox Wallet
|
|
1871
|
+
Production → Production Merchant ID + Production API Key + Production Wallet
|
|
1872
|
+
```
|
|
1873
|
+
|
|
1874
|
+
---
|
|
1875
|
+
|
|
1876
|
+
# 45. Browser Support
|
|
1877
|
+
|
|
1878
|
+
| Browser | Minimum Version |
|
|
1879
|
+
|---|---:|
|
|
1880
|
+
| Chrome | 90+ |
|
|
1881
|
+
| Firefox | 88+ |
|
|
1882
|
+
| Safari | 14+ |
|
|
1883
|
+
| Edge | 90+ |
|
|
1884
|
+
|
|
1885
|
+
---
|
|
1886
|
+
|
|
1887
|
+
# 46. Go-Live Checklist
|
|
1888
|
+
|
|
1889
|
+
Before launching the SDK integration in production:
|
|
1890
|
+
|
|
1891
|
+
- [ ] KYC approved.
|
|
1892
|
+
- [ ] Production Merchant ID received.
|
|
1893
|
+
- [ ] Production API Key generated.
|
|
1894
|
+
- [ ] Production host domain/package name approved.
|
|
1895
|
+
- [ ] Production environment selected.
|
|
1896
|
+
- [ ] Backend payment verification implemented.
|
|
1897
|
+
- [ ] PreAuth callback endpoint tested, if applicable.
|
|
1898
|
+
- [ ] Recurring callback endpoint tested, if applicable.
|
|
1899
|
+
- [ ] Successful Standard Payment tested.
|
|
1900
|
+
- [ ] Failed/cancelled payment scenarios tested.
|
|
1901
|
+
- [ ] Account linking tested.
|
|
1902
|
+
- [ ] Account unlinking tested.
|
|
1903
|
+
- [ ] Status API tested.
|
|
1904
|
+
- [ ] Custom dashboard/pages tested.
|
|
1905
|
+
- [ ] HTTPS enabled.
|
|
1906
|
+
- [ ] Private signing credentials remain on the backend.
|
|
1907
|
+
- [ ] End-to-end payment verification completed.
|
|
1908
|
+
|
|
1909
|
+
---
|
|
1910
|
+
|
|
1911
|
+
# 47. SDK API Quick Reference
|
|
1912
|
+
|
|
1913
|
+
| API | Purpose | When to Use |
|
|
1914
|
+
|---|---|---|
|
|
1915
|
+
| `Dropp.init()` | Initialize SDK | Always, before using SDK functionality |
|
|
1916
|
+
| `Dropp.pay()` | Start payment | Standard, PreAuth, or recurring payment |
|
|
1917
|
+
| `Dropp.status()` | Check linked account status | Before account-dependent UI/actions |
|
|
1918
|
+
| `Dropp.open()` | Open a specific Dropp page | Deep-link to a particular task |
|
|
1919
|
+
| `Dropp.dashboard()` | Open full/selected wallet dashboard | Give user access to wallet functions, including account linking |
|
|
1920
|
+
| `Dropp.unlinkAccount()` | Open unlink-account UI | Remove a linked funding source |
|
|
1921
|
+
| `Dropp.closePayment()` | Close payment window | Programmatic payment-window control |
|
|
1922
|
+
| `Dropp.getVersion()` | Get SDK version | Diagnostics/support |
|
|
1923
|
+
| `Dropp.getEnvironments()` | Get supported environment strings | Environment/diagnostic logic |
|
|
1924
|
+
| `Dropp.getInstance()` | Get initialized SDK instance | SDK state/diagnostics |
|
|
1925
|
+
|
|
1926
|
+
### Account Linking Quick Reference
|
|
1927
|
+
|
|
1928
|
+
```js
|
|
1929
|
+
// Open Dashboard for account linking / wallet management
|
|
1930
|
+
Dropp.dashboard();
|
|
1931
|
+
|
|
1932
|
+
// Check account status
|
|
1933
|
+
const status = await Dropp.status();
|
|
1934
|
+
|
|
1935
|
+
// Unlink funding source
|
|
1936
|
+
Dropp.unlinkAccount();
|
|
1937
|
+
```
|
|
1938
|
+
|
|
1939
|
+
### Custom Page Quick Reference
|
|
1940
|
+
|
|
1941
|
+
```js
|
|
1942
|
+
Dropp.open('fundnow');
|
|
1943
|
+
Dropp.open('linkbank');
|
|
1944
|
+
Dropp.open('linkcard');
|
|
1945
|
+
Dropp.open('redeemnow');
|
|
1946
|
+
Dropp.open('fundcrypto');
|
|
1947
|
+
Dropp.open('transferusdc');
|
|
1948
|
+
Dropp.open('usdchistory');
|
|
1949
|
+
Dropp.open('redeemcrypto');
|
|
1950
|
+
Dropp.open('manageaccounts');
|
|
1951
|
+
Dropp.open('transactions');
|
|
1952
|
+
Dropp.open('merchantlist');
|
|
1953
|
+
Dropp.open('favorites');
|
|
1954
|
+
Dropp.open('offers');
|
|
1955
|
+
Dropp.open('profile');
|
|
1956
|
+
Dropp.open('pinchange');
|
|
1957
|
+
Dropp.open('aboutus');
|
|
1958
|
+
```
|
|
1959
|
+
|
|
1960
|
+
# 48. Support
|
|
1961
|
+
|
|
1962
|
+
For technical assistance, contact:
|
|
1963
|
+
|
|
1964
|
+
```text
|
|
1965
|
+
support@dropp.cc
|
|
1966
|
+
```
|
|
1967
|
+
|
|
1968
|
+
Include the following information when reporting an issue:
|
|
1969
|
+
|
|
1970
|
+
- Merchant ID.
|
|
1971
|
+
- Environment.
|
|
1972
|
+
- SDK version.
|
|
1973
|
+
- Error code/message.
|
|
1974
|
+
- Browser and browser version.
|
|
1975
|
+
- Host application/framework.
|
|
1976
|
+
- Payment type.
|
|
1977
|
+
- Reproduction steps.
|
|
1978
|
+
- Relevant request/response details that do not expose secrets.
|
|
1979
|
+
|
|
1980
|
+
---
|
|
1981
|
+
|
|
1982
|
+
# 49. Important Documentation Note
|
|
1983
|
+
|
|
1984
|
+
This guide is based on the currently supplied SDK integration documentation.
|
|
1985
|
+
|
|
1986
|
+
The supplied material explicitly documents:
|
|
1987
|
+
|
|
1988
|
+
- `Dropp.init()`
|
|
1989
|
+
- `Dropp.pay()`
|
|
1990
|
+
- `Dropp.status()`
|
|
1991
|
+
- `Dropp.dashboard()`
|
|
1992
|
+
- `Dropp.open()`
|
|
1993
|
+
- `Dropp.unlinkAccount()`
|
|
1994
|
+
- `Dropp.closePayment()`
|
|
1995
|
+
- `Dropp.getVersion()`
|
|
1996
|
+
- `Dropp.getEnvironments()`
|
|
1997
|
+
- `Dropp.getInstance()`
|
|
1998
|
+
|
|
1999
|
+
The SDK does **not** expose a separate `Dropp.linkAccount()` method. Account linking is handled through the Dropp Dashboard, which should be opened using `Dropp.dashboard()`. The host application can use `Dropp.status()` to determine whether the account is already linked.
|
|
2000
|
+
|
|
2001
|
+
Similarly, custom-page-specific parameters/callbacks should only be added when they are supported by the SDK implementation.
|
|
2002
|
+
|
|
2003
|
+
This keeps the documentation aligned with the actual SDK contract and avoids promising APIs that are not currently documented.
|
|
2004
|
+
|
|
2005
|
+
---
|
|
2006
|
+
|
|
2007
|
+
# 50. Platform Constraints and Advanced Contracts
|
|
2008
|
+
|
|
2009
|
+
This section documents current behavior and integration constraints that are important for production readiness.
|
|
2010
|
+
|
|
2011
|
+
## 50.1 Refund API Availability
|
|
2012
|
+
|
|
2013
|
+
The Web SDK currently does not expose a dedicated refund API method.
|
|
2014
|
+
|
|
2015
|
+
If your product requires refunds, implement refund operations through your backend/payment operations workflow.
|
|
2016
|
+
|
|
2017
|
+
## 50.2 PreAuth Lifecycle Coverage
|
|
2018
|
+
|
|
2019
|
+
Current documented SDK flow covers creating a pre-authorization hold.
|
|
2020
|
+
|
|
2021
|
+
Capture/settlement and explicit release/void operations are backend lifecycle operations and must be implemented using backend contracts for your environment.
|
|
2022
|
+
|
|
2023
|
+
Sandbox behavior can enforce one active preauth hold per payer until completion/expiry/cancellation.
|
|
2024
|
+
|
|
2025
|
+
## 50.3 Callback Envelope and Submission Contract
|
|
2026
|
+
|
|
2027
|
+
For recurring and preauth callback routes, host backend should normalize incoming payload to a common envelope:
|
|
2028
|
+
|
|
2029
|
+
```json
|
|
2030
|
+
{
|
|
2031
|
+
"data": "<base64 payload>",
|
|
2032
|
+
"signatures": {
|
|
2033
|
+
"payer": "<payer signature>"
|
|
2034
|
+
}
|
|
2035
|
+
}
|
|
2036
|
+
```
|
|
573
2037
|
|
|
574
|
-
|
|
2038
|
+
Then submit server-to-server to the authoritative backend endpoint for that flow, persist authoritative response data, and only then return callback approval.
|
|
575
2039
|
|
|
576
|
-
|
|
577
|
-
- Verify origin validation isn't blocking legitimate messages
|
|
578
|
-
- Check browser console for message validation errors
|
|
2040
|
+
## 50.4 Recurring Token Handling
|
|
579
2041
|
|
|
580
|
-
|
|
2042
|
+
Recurring callback/SDK responses can vary by environment and flow outcome. `recurringToken` preserve that token in respect of user account.
|
|
581
2043
|
|
|
582
|
-
|
|
583
|
-
- If you use TypeScript types, import them from `@dropp.cc/payment-sdk`
|
|
2044
|
+
Always treat backend authoritative submission response as source of truth for token persistence and future recurring lifecycle operations.
|
|
584
2045
|
|
|
585
|
-
|
|
2046
|
+
## 50.5 Known Limits and Constraints
|
|
586
2047
|
|
|
587
|
-
|
|
588
|
-
- If another flow is active, calls may fail with `ALREADY_OPEN` / "A Dropp session is already in progress".
|
|
589
|
-
- Wait for the active flow to complete before launching a new one.
|
|
2048
|
+
Known limits to account for in product design/testing:
|
|
590
2049
|
|
|
591
|
-
|
|
2050
|
+
1. PreAuth hold duration is time-limited and should be treated as short-lived authorization.
|
|
2051
|
+
2. `authHoldTimeInSeconds` is typically constrained to 86400 seconds (24 hours).
|
|
2052
|
+
3. payment amount can be constrained to 1000 (environment policy).
|
|
2053
|
+
4. Concurrent SDK flows are blocked by single-session locking (`ALREADY_OPEN`).
|
|
592
2054
|
|
|
593
|
-
|
|
594
|
-
- Email: support@dropp.cc
|
|
2055
|
+
Validate these constraints in your target environment before go-live.
|
|
595
2056
|
|
|
2057
|
+
## 50.6 Server-Side Verification Requirement
|
|
596
2058
|
|
|
597
|
-
|
|
2059
|
+
Do not treat client callback success alone as final settlement/authorization proof.
|
|
598
2060
|
|
|
599
|
-
|
|
2061
|
+
Backend must verify and persist authoritative transaction state before order fulfillment.
|
|
600
2062
|
|
|
601
|
-
|
|
602
|
-
- Initial release
|
|
603
|
-
- Standard, preauth, and recurring payment support
|
|
604
|
-
- Secure postMessage communication
|
|
605
|
-
- Framework-agnostic design
|
|
606
|
-
- Full TypeScript definitions
|
|
2063
|
+
## 50.7 Sandbox Display Name Behavior
|
|
607
2064
|
|
|
608
|
-
|
|
609
|
-
- Added Support for the Home/Dashboard.
|
|
2065
|
+
In sandbox, hosted transaction UIs may show merchant display name configured in sandbox merchant profile rather than host-app branding.
|
|
610
2066
|
|
|
611
|
-
|
|
612
|
-
- Added Support for the Unlink account.
|
|
2067
|
+
Treat this as environment behavior and verify production branding/configuration separately.
|
|
613
2068
|
|
|
614
|
-
|
|
615
|
-
- Added Support for the Transactions.
|
|
616
|
-
- Added Support for the Offers.
|
|
617
|
-
- Added Support for Security before open any customized method.
|
|
2069
|
+
## 50.8 PreAuth One-Active Rule and Cancellation
|
|
618
2070
|
|
|
619
|
-
|
|
620
|
-
- Added Support for the 404 methods.
|
|
621
|
-
- Added Support for the status check.
|
|
2071
|
+
If an environment enforces one active preauth per payer, repeated preauth attempts can fail until existing hold is completed, expired, or cancelled.
|
|
622
2072
|
|
|
623
|
-
|
|
624
|
-
- Added qa and sandbox api gateway support.
|
|
625
|
-
- Whitelabeling of the merchants.
|
|
2073
|
+
Ensure your backend includes handling for:
|
|
626
2074
|
|
|
627
|
-
|
|
628
|
-
|
|
2075
|
+
1. Active-hold conflict responses.
|
|
2076
|
+
2. Cancellation/release operations where supported by your backend contract.
|
|
2077
|
+
3. Reconciliation between hosted approval UI and backend authoritative hold state.
|
|
629
2078
|
|
|
630
|
-
|
|
631
|
-
- Added stricter SDK-level session/concurrency guards.
|
|
2079
|
+
Observed sandbox integrations have used a release/cancel path such as `/api/rps/v1/payments/preAuth/p2p/process` with `action: "CANCEL"`; validate official contract availability for your target environment before production use.
|