@dropp.cc/payment-sdk 1.0.24 → 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,537 +1,2079 @@
1
- # Dropp Payment SDK for Web
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
- A secure, production-ready JavaScript SDK for integrating Dropp payments into web applications.
140
+ ## 4.1 Sandbox
4
141
 
5
- ## Features
142
+ Use Sandbox for:
6
143
 
7
- - 🔒 **Secure** - Origin validation, message authentication, session correlation
8
- - 🎯 **Framework-agnostic** - Works with React, Vue, Angular.
9
- - 📱 **Responsive** - Optimized for desktop and mobile browsers
10
- - **Lightweight** - Minimal bundle size, no dependencies
11
- - 📦 **TypeScript** - Full TypeScript definitions included
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
- ## Installation
198
+ ---
15
199
 
16
- Install the SDK using npm:
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
- ## Initialization
23
-
24
- ### `Dropp.init(config)`
208
+ ## 5.2 Yarn
25
209
 
26
- Initializes the SDK with the required configuration.
210
+ ```bash
211
+ yarn add @dropp.cc/payment-sdk
212
+ ```
27
213
 
28
- **Parameters:**
214
+ ---
29
215
 
30
- - `config` (Object):
31
- - `merchantId` (String) **Required**: Your Dropp merchant identifier, Will get from Dropp Merchant Portal after KYC.
32
- - `apiKey` (String) **Required**: API key issued for your merchant, Will get from Dropp Merchant Portal after KYC.
33
- - `packageName` (String) **Required**: Your app/package name (for example, `app.dropp.cc`), will need to update in your account on the Dropp Merchant Portal.
34
- - `environment` (String) **Required**: The environment to use. Options: `'production'`, `'qa'`, `'sandbox'`.
35
- - `getServerAuthToken` (Function) **Optional**: Async callback that returns a short-lived server-issued token.
36
- - `requireServerAuthToken` (Boolean) **Optional**: Require server token for payment initialization. Defaults to `true` in production.
216
+ # 6. Initialize the SDK
37
217
 
218
+ The SDK must be initialized before calling payment, account, dashboard, or custom-page APIs.
38
219
 
39
- ### Example:
220
+ ```js
221
+ import { Dropp } from '@dropp.cc/payment-sdk';
40
222
 
41
- ```javascript
42
223
  Dropp.init({
43
224
  merchantId: 'YOUR_MERCHANT_ID',
44
225
  apiKey: 'YOUR_API_KEY',
45
- packageName: 'com.example.webapp',
46
- environment: 'production',
47
- getServerAuthToken: async (context) => {
48
- const response = await fetch('https://your-backend.com/dropp/auth-token', {
49
- method: 'POST',
50
- headers: { 'Content-Type': 'application/json' },
51
- body: JSON.stringify(context)
52
- });
53
- const body = await response.json();
54
- return body.authToken;
55
- }
226
+ environment: 'sandbox'
56
227
  });
57
228
  ```
58
229
 
59
- ## Payment
230
+ ## 6.1 Initialization Parameters
60
231
 
61
- ### `Dropp.pay(options)`
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`. |
62
237
 
63
- Initiates a payment process.
238
+ > The exact application identifier configured in the Merchant Portal must match the host application configuration expected by the SDK.
64
239
 
65
- **Parameters:**
240
+ ---
66
241
 
67
- - `options` (Object):
68
- - `merchantAccount` (String) **Required**: The merchant's Hedera account ID (e.g., `'0.0.123456'`).
69
- - `amount` (Number) **Required**: The payment amount.
70
- - `currency` (String) **Required**: The currency code (e.g., `'USD'`, `'HBAR'`, `'USDC'`). For `paymentType: 'preauth'`, only `'USD'` is allowed.
71
- - `itemName` (String) **Required**: The name of the item or service.
72
- - `paymentType` (String) **Required**: The type of payment. Options: `'standard'`, `'preauth'`, `'recurring'`.
73
- - `authHoldTimeInSeconds` (Number) **Required in Preauth Payments**: For preauth payments, the hold time in seconds.
74
- - `callbackUrl` (String) **Required in Preauth & Recurring**: The server URL on which the PreAuth and Recurring requests will be send for signing.
75
- - `recurringEndDate` (ISO datetime) **Optional in Recurring Payments**: The date on which the recurring authorization will expire.
76
- - `serverAuthToken` (String) **Optional**: A short-lived token issued by your backend for this payment.
242
+ # 7. Payments
77
243
 
78
- ### Example:
244
+ The SDK exposes a single payment entry point:
79
245
 
80
- ```javascript
81
- Dropp.pay({
82
- merchantAccount: '0.0.123456',
83
- amount: 100.00,
246
+ ```js
247
+ Dropp.pay(options)
248
+ ```
249
+
250
+ The `paymentType` determines which payment flow is started.
251
+
252
+ Supported values:
253
+
254
+ ```text
255
+ standard
256
+ preauth
257
+ recurring
258
+ ```
259
+
260
+ The payment flow opens the Dropp-managed payment UI and returns a Promise containing the payment result.
261
+
262
+ ## 7.1 Single Active Flow Constraint
263
+
264
+ The Web SDK allows only one active flow at a time (payment, hosted page, or status check).
265
+
266
+ If a second call starts before the first finishes, SDK returns `ALREADY_OPEN`.
267
+
268
+ Recommended host-app behavior:
269
+
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.
273
+
274
+ ## 7.2 Unicode Input Note
275
+
276
+ Current payload encoding in Web SDK versions that use browser `btoa` can fail for non-Latin1 characters.
277
+
278
+ Until UTF-8-safe encoding is available in your deployed SDK version:
279
+
280
+ 1. Use ASCII-safe `itemName` and `description` values, or
281
+ 2. Normalize/sanitize these fields before calling `Dropp.pay(...)`.
282
+
283
+ ---
284
+
285
+ # 8. Standard Payment
286
+
287
+ ## 8.1 Purpose
288
+
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,
84
310
  currency: 'USD',
85
- itemName: 'Premium Subscription',
311
+ itemName: 'Premium Product',
86
312
  paymentType: 'standard',
87
- callbackUrl: 'https://example.com/callback'
313
+ description: 'One-time product purchase',
314
+ invoiceId: 'ORDER-12345'
88
315
  });
89
316
  ```
90
317
 
91
- ## Pages
318
+ ## 8.3 Standard Payment Parameters
92
319
 
93
- The Web SDK can also open Dropp-hosted pages inside the same modal container.
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. |
94
331
 
95
- ### `Dropp.dashboard(options)`
332
+ ## 8.4 When to Use
96
333
 
97
- Open the dashboard/home page.
334
+ Use:
98
335
 
99
- Optional for this route:
336
+ ```text
337
+ paymentType: 'standard'
338
+ ```
100
339
 
101
- - `modules` (`string[]`): Restrict sidebar modules shown in webview.
340
+ when the transaction should represent a normal one-time payment.
102
341
 
103
- Supported section IDs:
342
+ ---
104
343
 
105
- - `funding`
106
- - `accounts`
107
- - `merchants`
108
- - `settings`
109
- - `support`
344
+ # 9. Pre-Authorization Payment
110
345
 
111
- Supported item IDs:
346
+ ## 9.1 Purpose
112
347
 
113
- - `fundnow`
114
- - `linkbank`
115
- - `linkcard`
116
- - `redeemnow`
117
- - `fundcrypto`
118
- - `transferusdc`
119
- - `usdchistory`
120
- - `redeemcrypto`
121
- - `manageaccounts`
122
- - `transactions`
123
- - `merchantlist`
124
- - `favorites`
125
- - `offers`
126
- - `profile`
127
- - `pinchange`
128
- - `unlinkaccount`
129
- - `accountsettings`
130
- - `about`
348
+ A **Pre-Authorization Payment** authorizes/reserves funds without immediately capturing the final amount.
131
349
 
132
- The SDK passes this as a comma-separated query param in the webview URL for `#/firsttimeflow`.
350
+ Use PreAuth when the final amount may be determined later or when a temporary authorization is required.
133
351
 
134
- ### `Dropp.open(moduleId, options)`
352
+ Typical use cases:
135
353
 
136
- Open a specific supported firsttimeflow item page directly.
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.
137
359
 
138
- Supported item IDs:
360
+ ## 9.2 Important Difference from Standard Payment
139
361
 
140
- - `fundnow`
141
- - `linkbank`
142
- - `linkcard`
143
- - `redeemnow`
144
- - `fundcrypto`
145
- - `transferusdc`
146
- - `usdchistory`
147
- - `redeemcrypto`
148
- - `manageaccounts`
149
- - `transactions`
150
- - `merchantlist`
151
- - `favorites`
152
- - `offers`
153
- - `profile`
154
- - `pinchange`
155
- - `unlinkaccount`
156
- - `accountsettings`
157
- - `about`
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 |
158
368
 
159
- This opens the module route directly as `#/${moduleId}`.
369
+ ---
160
370
 
161
- ### `Dropp.unlinkAccount(options)`
371
+ ## 9.3 Example
162
372
 
163
- Loads the account unlink page.
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
+ ```
164
385
 
165
- ### `Dropp.transactions(options)`
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
+ ```
166
441
 
167
- Loads the transactions page.
442
+ ## 10.2 Callback URL
168
443
 
169
- ### `Dropp.offers(options)`
444
+ The `callbackUrl` must point to the merchant backend application where the Dropp Backend SDK is integrated.
170
445
 
171
- Loads the offers page.
446
+ Example:
172
447
 
173
- **Parameters:**
448
+ ```text
449
+ https://merchant.example.com/pre-auth-post-callback
450
+ ```
174
451
 
175
- - `options` (Object) Optional:
176
- - `onClose` (Function) **Optional**: Callback invoked when the modal is closed.
452
+ A sample merchant backend application is available from the integration material:
177
453
 
178
- ### Hosted Page Example:
454
+ ```text
455
+ https://drive.google.com/drive/u/1/folders/1pWrBFQwnznhpRFPnsU_5qiy0TRp5dGUr
456
+ ```
179
457
 
180
- ```javascript
181
- await Dropp.dashboard({
182
- onClose: () => {
183
- console.log('Dashboard modal closed');
184
- },
185
- modules: ['funding', 'accounts', 'merchants', 'settings', 'support']
186
- });
458
+ ### Running the Sample Backend
187
459
 
188
- await Dropp.unlinkAccount();
189
- await Dropp.transactions();
190
- await Dropp.offers();
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()`.
191
465
 
192
- await Dropp.dashboard({
193
- modules: ['funding', 'profile', 'about']
194
- });
466
+ Example:
195
467
 
196
- await Dropp.open('linkbank');
197
- await Dropp.open('profile');
468
+ ```text
469
+ https://<your-ngrok-url>/pre-auth-post-callback
198
470
  ```
199
471
 
200
- ### SDK Instance Example:
472
+ > The callback endpoint must be publicly accessible over HTTPS.
201
473
 
202
- ```javascript
203
- const { sdk } = await Dropp.init({
204
- merchantId: 'YOUR_MERCHANT_ID',
205
- apiKey: 'YOUR_API_KEY',
206
- packageName: 'com.example.webapp',
207
- environment: 'production'
208
- });
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.
483
+
484
+ Typical use cases:
485
+
486
+ - SaaS subscriptions.
487
+ - Memberships.
488
+ - Streaming services.
489
+ - Monthly plans.
490
+ - Periodic service billing.
209
491
 
210
- await sdk.dashboard();
211
- await sdk.dashboard({
212
- modules: ['funding', 'accounts', 'merchants', 'settings', 'support']
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()
213
506
  });
214
- await sdk.open('fundnow');
215
- await sdk.open('transactions');
216
- await sdk.unlinkAccount();
217
- await sdk.transactions();
218
- await sdk.offers();
219
507
  ```
220
508
 
221
- ## Account Status
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
+ ```
565
+
566
+ ## 12.2 Callback URL
567
+
568
+ Example:
569
+
570
+ ```text
571
+ https://merchant.example.com/rps-callback
572
+ ```
573
+
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
580
+ ```
581
+
582
+ For local testing:
583
+
584
+ ```text
585
+ https://<your-ngrok-url>/rps-callback
586
+ ```
587
+
588
+ The endpoint must be publicly accessible over HTTPS.
222
589
 
223
- Use `Dropp.status()` to fetch account linkage status.
590
+ ## 12.3 Callback Transport and Envelope (Important)
224
591
 
225
- ### `Dropp.status()`
592
+ For current hosted flows, callback transport differs by payment type:
226
593
 
227
- Returns:
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 |
228
598
 
229
- ```javascript
599
+ The signed envelope should be handled as opaque and forwarded server-side:
600
+
601
+ ```json
230
602
  {
231
- type: 'ACCOUNT_STATUS',
232
- data: {
233
- linked: true,
234
- method: 'keypair'
603
+ "data": "<base64 payload>",
604
+ "signatures": {
605
+ "payer": "<hex signature>"
235
606
  }
236
607
  }
237
608
  ```
238
609
 
239
- ### Example:
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.
240
611
 
241
- ```javascript
242
- const status = await Dropp.status();
243
- console.log('Account status:', status);
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
244
653
  ```
245
654
 
246
- ### SDK Instance Example:
655
+ ## Security Rule
247
656
 
248
- ```javascript
249
- const { sdk } = await Dropp.init({
250
- merchantId: 'YOUR_MERCHANT_ID',
251
- apiKey: 'YOUR_API_KEY',
252
- packageName: 'com.example.webapp',
253
- environment: 'production'
254
- });
657
+ Never put a private signing key, signing secret, or equivalent backend credential in frontend JavaScript.
255
658
 
256
- const status = await sdk.status();
257
- console.log(status);
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);
688
+ }
258
689
  ```
259
690
 
260
- ## Environments
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
+ ```
261
710
 
262
- The SDK supports the following environments:
711
+ ---
263
712
 
264
- - `'production'`: For live transactions.
265
- - `'qa'`: For quality assurance testing.
266
- - `'sandbox'`: For development and testing.
713
+ # 15. Account APIs
267
714
 
268
- Ensure you use the appropriate environment for your use case.
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.
269
716
 
717
+ The account-management area covers:
270
718
 
271
- ```javascript
272
- import '@dropp/payment-sdk';
719
+ - Linking a dropp account.
720
+ - Unlinking a linked dropp account.
721
+ - Checking whether an account is linked.
273
722
 
274
- Dropp.init({
275
- merchantId: 'YOUR_MERCHANT_ID',
276
- apiKey: 'YOUR_API_KEY',
277
- packageName: 'com.example.webapp',
278
- environment: 'sandbox' // For testing payments (testnet)
279
- });
723
+ ---
280
724
 
281
- Dropp.init({
282
- merchantId: 'YOUR_MERCHANT_ID',
283
- apiKey: 'YOUR_API_KEY',
284
- packageName: 'com.example.webapp',
285
- environment: 'qa' // For QA
286
- });
725
+ # 16. Link Account
287
726
 
288
- Dropp.init({
289
- merchantId: 'YOUR_MERCHANT_ID',
290
- apiKey: 'YOUR_API_KEY',
291
- packageName: 'com.example.webapp',
292
- environment: 'production' // For live payments (mainnet)
293
- });
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();
294
737
  ```
295
738
 
296
- ## Payment Examples
739
+ The host application should not implement a separate account-linking UI when the intention is to use the Dropp-managed experience.
297
740
 
298
- ### Standard Payment
741
+ ## 16.2 When to Use
299
742
 
300
- ```javascript
301
- Dropp.pay({
302
- merchantAccount: '0.0.123456',
303
- amount: 49.99,
304
- currency: 'USD',
305
- itemName: 'Premium Plan',
306
- description: 'One-time purchase',
307
- invoiceId: 'INV-2024-001'
308
- });
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()
309
764
  ```
310
765
 
311
- ### Pre-Authorization Payment
766
+ ## 16.3 Recommended Account-Linking Flow
312
767
 
313
- ```javascript
314
- Dropp.pay({
315
- merchantAccount: '0.0.123456',
316
- amount: 100.00,
317
- currency: 'USD',
318
- itemName: 'Hotel Reservation',
319
- description: 'Authorization hold for booking',
320
- invoiceId: 'PREAUTH-001',
321
- paymentType: 'preauth',
322
- authHoldTimeInSeconds: 3600, // 1 hour hold
323
- callbackUrl: 'https://your-server.com/payment-callback'
324
- });
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
+ }
325
776
  ```
326
777
 
327
- ### Recurring Payment
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.
328
779
 
329
- ```javascript
330
- Dropp.pay({
331
- merchantAccount: '0.0.123456',
332
- amount: 9.99,
333
- currency: 'USD',
334
- itemName: 'Monthly Subscription',
335
- description: 'Recurring monthly payment',
336
- paymentType: 'recurring',
337
- frequency: 'monthly', // Frequency of the recurring payment
338
- recurringEndDate: new Date(Date.now() + 365 * 24 * 60 * 60 * 1000).toISOString(), // (optional) the date onwhich the recurring authentication will end.
339
- callbackUrl: 'https://your-server.com/recurring-callback'
340
- });
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);
341
792
  ```
342
- ### React Integration
343
793
 
344
- ```jsx
345
- import { useEffect, useState } from 'react';
346
- import { Dropp } from '@dropp/payment-sdk';
794
+ ## 17.2 When to Use
347
795
 
348
- function CheckoutButton() {
349
- const [isProcessing, setIsProcessing] = useState(false);
796
+ Use the unlink flow when:
350
797
 
351
- useEffect(() => {
352
- Dropp.init({
353
- merchantId: 'YOUR_MERCHANT_ID',
354
- apiKey: 'YOUR_API_KEY',
355
- packageName: 'com.example.webapp',
356
- environment: 'production'
357
- });
358
- }, []);
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.
359
802
 
360
- const handlePayment = async () => {
361
- setIsProcessing(true);
803
+ The SDK manages the unlink UI instead of requiring the host application to recreate the Dropp account-management screen.
362
804
 
363
- try {
364
- const result = await Dropp.pay({
365
- merchantAccount: '0.0.123456',
366
- amount: 99.99,
367
- currency: 'USD',
368
- itemName: 'Product Purchase',
369
- paymentType: 'standard'
370
- });
805
+ ---
371
806
 
372
- if (result.status === 'success') {
373
- alert('Payment successful!');
374
- }
375
- } catch (error) {
376
- console.error('Payment error:', error);
377
- } finally {
378
- setIsProcessing(false);
379
- }
380
- };
807
+ # 18. Account Status API
381
808
 
382
- return (
383
- <button onClick={handlePayment} disabled={isProcessing}>
384
- {isProcessing ? 'Processing...' : 'Pay Now'}
385
- </button>
386
- );
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
+ }
387
828
  }
388
829
  ```
389
830
 
831
+ ## 18.2 Purpose
390
832
 
391
- ### Vanilla JavaScript Integration
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.
392
834
 
393
- Use this when you are not using React/Vue/Angular.
835
+ For example:
394
836
 
395
- ```html
396
- <!doctype html>
397
- <html>
398
- <head>
399
- <meta charset="utf-8" />
400
- <meta name="viewport" content="width=device-width, initial-scale=1" />
401
- <title>Dropp Vanilla JS Example</title>
402
- </head>
403
- <body>
404
- <button id="payStandard">Pay Standard</button>
405
- <button id="payPreauth">Pay Preauth</button>
406
- <button id="payRecurring">Pay Recurring</button>
407
-
408
- <script src="https://unpkg.com/@dropp/payment-sdk/dist/dropp-payment-sdk.js"></script>
409
- <script>
410
- const { Dropp } = window.DroppPaymentSDK;
411
-
412
- Dropp.init({
413
- merchantId: 'YOUR_MERCHANT_ID',
414
- apiKey: 'YOUR_API_KEY',
415
- packageName: 'app.dropp.cc',
416
- environment: 'production'
417
- });
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
+ ```
418
849
 
419
- document.getElementById('payStandard').addEventListener('click', async () => {
420
- await Dropp.pay({
421
- merchantAccount: '0.0.123456',
422
- amount: 49.99,
423
- currency: 'USD',
424
- itemName: 'One-time Purchase',
425
- paymentType: 'standard'
426
- });
427
- });
850
+ ## 18.3 Example
428
851
 
429
- document.getElementById('payPreauth').addEventListener('click', async () => {
430
- await Dropp.pay({
431
- merchantAccount: '0.0.123456',
432
- amount: 100.00,
433
- currency: 'USD',
434
- itemName: 'Hotel Reservation',
435
- paymentType: 'preauth',
436
- authHoldTimeInSeconds: 3600,
437
- callbackUrl: 'https://your-server.com/payment-callback'
438
- });
439
- });
852
+ ```js
853
+ const status = await Dropp.status();
440
854
 
441
- document.getElementById('payRecurring').addEventListener('click', async () => {
442
- await Dropp.pay({
443
- merchantAccount: '0.0.123456',
444
- amount: 9.99,
445
- currency: 'USD',
446
- itemName: 'Monthly Subscription',
447
- paymentType: 'recurring',
448
- frequency: 'monthly',
449
- recurringEndDate: new Date(Date.now() + 365 * 24 * 60 * 60 * 1000).toISOString(),
450
- callbackUrl: 'https://your-server.com/recurring-callback'
451
- });
452
- });
453
- </script>
454
- </body>
455
- </html>
855
+ if (status?.data?.linked) {
856
+ console.log('Dropp account is linked');
857
+ } else {
858
+ console.log('Dropp account is not linked');
859
+ }
456
860
  ```
457
861
 
458
- ## Security
862
+ The documented implementation performs the status check through a hidden iframe.
863
+
864
+ ## 18.4 Failure and Timeout Behavior
865
+
866
+ `Dropp.status()` may reject instead of returning a status object.
867
+
868
+ Common cases:
869
+
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).
873
+
874
+ Recommended handling:
875
+
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
+ ```
889
+
890
+ ---
891
+
892
+ # 19. Link vs Unlink vs Status
893
+
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 |
459
899
 
460
- The SDK implements multiple security layers:
900
+ A typical host application can use them together:
461
901
 
462
- ✅ **Origin Validation** - Strict validation of postMessage origins
463
- **Session Correlation** - Each session has a unique ID to prevent replay attacks
464
- ✅ **Message Authentication** - All messages are validated for structure and content
465
- **Iframe Sandboxing** - Payment app runs in a sandboxed iframe
466
- **No Sensitive Data** - SDK never handles sensitive payment data directly
467
- ✅ **Secure Communication** - All data transmission uses HTTPS
902
+ ```js
903
+ const status = await Dropp.status();
904
+
905
+ if (!status?.data?.linked) {
906
+ await Dropp.open('linkbank');
907
+ }
908
+ ```
468
909
 
469
- ### Security Best Practices
910
+ ---
470
911
 
471
- 1. **Never expose secrets in frontend code**
472
- 2. **Use server-side callbacks** for payment verification
473
- 3. **Validate payments on your backend** using the `callbackUrl`
474
- 4. **Use invoice IDs** to track and deduplicate payments
475
- 5. **Implement proper error handling**
912
+ # 20. Custom Pages and Modules
476
913
 
477
- ## Browser Support
914
+ The SDK allows the host application to open Dropp-managed pages directly.
915
+
916
+ This is useful when the merchant wants to provide access to specific wallet functionality while keeping the Dropp UI/UX.
917
+
918
+ There are two main APIs:
919
+
920
+ ```js
921
+ Dropp.dashboard(options);
922
+ ```
923
+
924
+ and:
925
+
926
+ ```js
927
+ Dropp.open(moduleId, options);
928
+ ```
929
+
930
+ ### Hosted Page Options (SDK Supported)
931
+
932
+ Hosted page APIs support an options object used for lifecycle callbacks and page customization.
933
+
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. |
942
+
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
+ ```
478
2037
 
479
- - Chrome 90+
480
- - Firefox 88+
481
- - Safari 14+
482
- - Edge 90+
2038
+ Then submit server-to-server to the authoritative backend endpoint for that flow, persist authoritative response data, and only then return callback approval.
483
2039
 
484
- ## Troubleshooting
2040
+ ## 50.4 Recurring Token Handling
485
2041
 
486
- ### Payment modal doesn't open
2042
+ Recurring callback/SDK responses can vary by environment and flow outcome. `recurringToken` preserve that token in respect of user account.
487
2043
 
488
- - Check browser console for errors
489
- - Verify all required fields are provided
490
- - Ensure `merchantAccount` format is correct (`"0.0.123456"`)
2044
+ Always treat backend authoritative submission response as source of truth for token persistence and future recurring lifecycle operations.
491
2045
 
492
- ### Messages not received
2046
+ ## 50.5 Known Limits and Constraints
493
2047
 
494
- - Check that you're using the correct environment
495
- - Verify origin validation isn't blocking legitimate messages
496
- - Check browser console for message validation errors
2048
+ Known limits to account for in product design/testing:
497
2049
 
498
- ### TypeScript errors
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`).
499
2054
 
500
- - Ensure you have `@dropp/payment-sdk` installed
501
- - If you use TypeScript types, import them from `@dropp/payment-sdk`
2055
+ Validate these constraints in your target environment before go-live.
502
2056
 
503
- ## Support
2057
+ ## 50.6 Server-Side Verification Requirement
504
2058
 
505
- For issues or questions:
506
- - Email: support@dropp.cc
2059
+ Do not treat client callback success alone as final settlement/authorization proof.
507
2060
 
2061
+ Backend must verify and persist authoritative transaction state before order fulfillment.
508
2062
 
509
- MIT License - see LICENSE file for details
2063
+ ## 50.7 Sandbox Display Name Behavior
510
2064
 
511
- ## Changelog
2065
+ In sandbox, hosted transaction UIs may show merchant display name configured in sandbox merchant profile rather than host-app branding.
512
2066
 
513
- ### v1.0.0 (2026-06-01)
514
- - Initial release
515
- - Standard, preauth, and recurring payment support
516
- - Secure postMessage communication
517
- - Framework-agnostic design
518
- - Full TypeScript definitions
2067
+ Treat this as environment behavior and verify production branding/configuration separately.
519
2068
 
520
- ### v1.0.3 (2026-07-06)
521
- - Added Support for the Home/Dashboard.
2069
+ ## 50.8 PreAuth One-Active Rule and Cancellation
522
2070
 
523
- ### v1.0.4 (2026-07-07)
524
- - Added Support for the Unlink account.
2071
+ If an environment enforces one active preauth per payer, repeated preauth attempts can fail until existing hold is completed, expired, or cancelled.
525
2072
 
526
- ### v1.0.5 (2026-07-09)
527
- - Added Support for the Transactions.
528
- - Added Support for the Offers.
529
- - Added Support for Security before open any customized method.
2073
+ Ensure your backend includes handling for:
530
2074
 
531
- ### v1.0.10 (2026-07-10)
532
- - Added Support for the 404 methods.
533
- - Added Support for the status check.
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.
534
2078
 
535
- ### v1.0.20 (2026-07-27)
536
- - Added qa and sandbox api gateway support.
537
- - Whitelabeling of the merchants.
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.