@dropp.cc/payment-sdk 1.0.25 → 1.0.27

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 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
- For a full end-to-end merchant flow (architecture, backend callbacks, verification, and go-live checklist), see [Dropp Web Payment SDK Integration Guide](./INTEGRATION_GUIDE.md).
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
- ## Quick Start (2 minutes)
218
+ The SDK must be initialized before calling payment, account, dashboard, or custom-page APIs.
25
219
 
26
- ```javascript
220
+ ```js
27
221
  import { Dropp } from '@dropp.cc/payment-sdk';
28
222
 
29
- await Dropp.init({
223
+ Dropp.init({
30
224
  merchantId: 'YOUR_MERCHANT_ID',
31
225
  apiKey: 'YOUR_API_KEY',
32
- environment: 'qa'
226
+ environment: 'sandbox'
33
227
  });
228
+ ```
34
229
 
35
- const result = await Dropp.pay({
36
- amount: 19.99,
37
- currency: 'USD',
38
- itemName: 'Test Product'
39
- });
230
+ ## 6.1 Initialization Parameters
40
231
 
41
- if (result.status === 'success') {
42
- // Verify on backend before fulfillment
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
- ## SDK Methods
250
+ The `paymentType` determines which payment flow is started.
47
251
 
48
- | Method | Description | Returns |
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
- ## Initialization
254
+ ```text
255
+ standard
256
+ preauth
257
+ recurring
258
+ ```
61
259
 
62
- ### `Dropp.init(config)`
260
+ The payment flow opens the Dropp-managed payment UI and returns a Promise containing the payment result.
63
261
 
64
- Initializes the SDK with the required configuration.
262
+ ## 7.1 Single Active Flow Constraint
65
263
 
66
- **Parameters:**
264
+ The Web SDK allows only one active flow at a time (payment, hosted page, or status check).
67
265
 
68
- - `config` (Object):
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
- ### Example:
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
- ```javascript
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
- ## Payment
276
+ Current payload encoding in Web SDK versions that use browser `btoa` can fail for non-Latin1 characters.
97
277
 
98
- ### `Dropp.pay(options)`
278
+ Until UTF-8-safe encoding is available in your deployed SDK version:
99
279
 
100
- Initiates a payment process.
280
+ 1. Use ASCII-safe `itemName` and `description` values, or
281
+ 2. Normalize/sanitize these fields before calling `Dropp.pay(...)`.
101
282
 
102
- **Parameters:**
283
+ ---
103
284
 
104
- - `options` (Object):
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
- ### Example:
287
+ ## 8.1 Purpose
117
288
 
118
- ```javascript
119
- Dropp.pay({
120
- amount: 100.00,
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 Subscription',
311
+ itemName: 'Premium Product',
123
312
  paymentType: 'standard',
124
- callbackUrl: 'https://example.com/callback'
313
+ description: 'One-time product purchase',
314
+ invoiceId: 'ORDER-12345'
125
315
  });
126
316
  ```
127
317
 
128
- ## Pages
318
+ ## 8.3 Standard Payment Parameters
129
319
 
130
- 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. |
131
331
 
132
- ### `Dropp.dashboard(options)`
332
+ ## 8.4 When to Use
133
333
 
134
- Open the dashboard/home page.
334
+ Use:
135
335
 
136
- Optional for this route:
336
+ ```text
337
+ paymentType: 'standard'
338
+ ```
137
339
 
138
- - `modules` (`string[]`): Restrict sidebar modules shown in webview.
340
+ when the transaction should represent a normal one-time payment.
139
341
 
140
- Supported section IDs:
342
+ ---
141
343
 
142
- - `funding`
143
- - `accounts`
144
- - `merchants`
145
- - `settings`
146
- - `support`
344
+ # 9. Pre-Authorization Payment
147
345
 
148
- Supported item IDs:
346
+ ## 9.1 Purpose
149
347
 
150
- - `fundnow`
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
- 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.
168
351
 
169
- ### `Dropp.open(moduleId, options)`
352
+ Typical use cases:
170
353
 
171
- 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.
172
359
 
173
- Supported item IDs:
360
+ ## 9.2 Important Difference from Standard Payment
174
361
 
175
- - `fundnow`
176
- - `linkbank`
177
- - `linkcard`
178
- - `redeemnow`
179
- - `fundcrypto`
180
- - `transferusdc`
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
- This opens the module route directly as `#/${moduleId}`.
369
+ ---
193
370
 
194
- ### `Dropp.unlinkAccount(options)`
371
+ ## 9.3 Example
195
372
 
196
- 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
+ ```
197
385
 
198
- ### `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
+ ```
199
441
 
200
- Loads the transactions page.
442
+ ## 10.2 Callback URL
201
443
 
202
- ### `Dropp.offers(options)`
444
+ The `callbackUrl` must point to the merchant backend application where the Dropp Backend SDK is integrated.
203
445
 
204
- Loads the offers page.
446
+ Example:
205
447
 
206
- **Parameters:**
448
+ ```text
449
+ https://merchant.example.com/pre-auth-post-callback
450
+ ```
207
451
 
208
- - `options` (Object) Optional:
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
- ### Hosted Page Example:
454
+ ```text
455
+ https://drive.google.com/drive/u/1/folders/1pWrBFQwnznhpRFPnsU_5qiy0TRp5dGUr
456
+ ```
217
457
 
218
- ```javascript
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
- await Dropp.unlinkAccount();
227
- await Dropp.transactions();
228
- 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()`.
229
465
 
230
- await Dropp.dashboard({
231
- modules: ['funding', 'profile', 'aboutus']
232
- });
466
+ Example:
233
467
 
234
- await Dropp.open('linkbank');
235
- await Dropp.open('profile');
468
+ ```text
469
+ https://<your-ngrok-url>/pre-auth-post-callback
236
470
  ```
237
471
 
238
- ### SDK Instance Example:
472
+ > The callback endpoint must be publicly accessible over HTTPS.
239
473
 
240
- ```javascript
241
- const { sdk } = await Dropp.init({
242
- merchantId: 'YOUR_MERCHANT_ID',
243
- apiKey: 'YOUR_API_KEY',
244
- environment: 'production'
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
- await sdk.dashboard();
248
- await sdk.dashboard({
249
- modules: ['funding', 'accounts', 'merchants', 'settings', 'support']
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
- ## 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
+ ```
259
565
 
260
- Use `Dropp.status()` to fetch account linkage status.
566
+ ## 12.2 Callback URL
261
567
 
262
- ### `Dropp.status()`
568
+ Example:
263
569
 
264
- Returns:
570
+ ```text
571
+ https://merchant.example.com/rps-callback
572
+ ```
265
573
 
266
- ```javascript
267
- {
268
- type: 'ACCOUNT_STATUS',
269
- data: {
270
- linked: true,
271
- method: 'keypair'
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
- ### Example:
582
+ For local testing:
277
583
 
278
- ```javascript
279
- const status = await Dropp.status();
280
- console.log('Account status:', status);
584
+ ```text
585
+ https://<your-ngrok-url>/rps-callback
281
586
  ```
282
587
 
283
- ### SDK Instance Example:
588
+ The endpoint must be publicly accessible over HTTPS.
284
589
 
285
- ```javascript
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
- const status = await sdk.status();
293
- console.log(status);
294
- ```
592
+ For current hosted flows, callback transport differs by payment type:
295
593
 
296
- ## Payment Result Shapes
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
- ### Standard / Preauth / Recurring success
599
+ The signed envelope should be handled as opaque and forwarded server-side:
299
600
 
300
- ```javascript
601
+ ```json
301
602
  {
302
- status: 'success',
303
- // plus payment app payload fields
304
- sessionDuration: 1234
603
+ "data": "<base64 payload>",
604
+ "signatures": {
605
+ "payer": "<hex signature>"
606
+ }
305
607
  }
306
608
  ```
307
609
 
308
- ### Failed payment (business failure, not SDK exception)
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
- ```javascript
311
- {
312
- status: 'failed',
313
- // plus failure payload fields
314
- sessionDuration: 1234
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
- ### Cancelled payment
655
+ ## Security Rule
319
656
 
320
- ```javascript
321
- {
322
- status: 'cancelled',
323
- reason: 'user_cancelled' | 'app_close' | 'sdk_close' | 'user_closed',
324
- sessionDuration: 1234
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
- ## 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
+ ```
329
710
 
330
- The SDK supports the following environments:
711
+ ---
331
712
 
332
- - `'production'`: For live transactions.
333
- - `'qa'`: For quality assurance testing.
334
- - `'sandbox'`: For development and testing.
713
+ # 15. Account APIs
335
714
 
336
- 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.
337
716
 
717
+ The account-management area covers:
338
718
 
339
- ```javascript
340
- import { Dropp } from '@dropp.cc/payment-sdk';
719
+ - Linking a dropp account.
720
+ - Unlinking a linked dropp account.
721
+ - Checking whether an account is linked.
341
722
 
342
- Dropp.init({
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
- Dropp.init({
350
- merchantId: 'YOUR_MERCHANT_ID',
351
- apiKey: 'YOUR_API_KEY',
352
- environment: 'production' // For live payments (mainnet)
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
- ## Payment Examples
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
- ### Standard Payment
741
+ ## 16.2 When to Use
359
742
 
360
- ```javascript
361
- Dropp.pay({
362
- amount: 49.99,
363
- currency: 'USD',
364
- itemName: 'Premium Plan',
365
- description: 'One-time purchase',
366
- invoiceId: 'INV-2024-001'
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
- ### Pre-Authorization Payment
766
+ ## 16.3 Recommended Account-Linking Flow
371
767
 
372
- ```javascript
373
- Dropp.pay({
374
- amount: 100.00,
375
- currency: 'USD',
376
- itemName: 'Hotel Reservation',
377
- description: 'Authorization hold for booking',
378
- invoiceId: 'PREAUTH-001',
379
- paymentType: 'preauth',
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
- ### 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.
386
779
 
387
- ```javascript
388
- Dropp.pay({
389
- amount: 9.99,
390
- currency: 'USD',
391
- itemName: 'Monthly Subscription',
392
- description: 'Recurring monthly payment',
393
- paymentType: 'recurring',
394
- frequency: 'monthly', // Frequency of the recurring payment
395
- recurringEndDate: new Date(Date.now() + 365 * 24 * 60 * 60 * 1000).toISOString(), // Required: recurring authorization end date.
396
- callbackUrl: 'https://your-server.com/recurring-callback'
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
- ```jsx
402
- import { useEffect, useState } from 'react';
403
- import { Dropp } from '@dropp.cc/payment-sdk';
794
+ ## 17.2 When to Use
404
795
 
405
- function CheckoutButton() {
406
- const [isProcessing, setIsProcessing] = useState(false);
796
+ Use the unlink flow when:
407
797
 
408
- useEffect(() => {
409
- Dropp.init({
410
- merchantId: 'YOUR_MERCHANT_ID',
411
- apiKey: 'YOUR_API_KEY',
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
- const handlePayment = async () => {
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
- try {
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
- if (result.status === 'success') {
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
- return (
438
- <button onClick={handlePayment} disabled={isProcessing}>
439
- {isProcessing ? 'Processing...' : 'Pay Now'}
440
- </button>
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
- ### 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.
447
834
 
448
- Use this when you are not using React/Vue/Angular.
835
+ For example:
449
836
 
450
- ```html
451
- <!doctype html>
452
- <html>
453
- <head>
454
- <meta charset="utf-8" />
455
- <meta name="viewport" content="width=device-width, initial-scale=1" />
456
- <title>Dropp Vanilla JS Example</title>
457
- </head>
458
- <body>
459
- <button id="payStandard">Pay Standard</button>
460
- <button id="payPreauth">Pay Preauth</button>
461
- <button id="payRecurring">Pay Recurring</button>
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
- document.getElementById('payStandard').addEventListener('click', async () => {
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
- document.getElementById('payPreauth').addEventListener('click', async () => {
483
- await Dropp.pay({
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
- document.getElementById('payRecurring').addEventListener('click', async () => {
494
- await Dropp.pay({
495
- amount: 9.99,
496
- currency: 'USD',
497
- itemName: 'Monthly Subscription',
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
- ## Security
862
+ The documented implementation performs the status check through a hidden iframe.
510
863
 
511
- The SDK implements multiple security layers:
864
+ ## 18.4 Failure and Timeout Behavior
512
865
 
513
- **Origin Validation** - Strict validation of postMessage origins
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
- ### Security Best Practices
868
+ Common cases:
521
869
 
522
- 1. **Never expose secrets in frontend code**
523
- 2. **Use server-side callbacks** for payment verification
524
- 3. **Validate payments on your backend** using the `callbackUrl`
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
- ## Error Codes
874
+ Recommended handling:
529
875
 
530
- The SDK may reject calls with these error codes:
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
- | Code | Meaning | Typical action |
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
- ### Reserved error codes (defined, not currently emitted as SDK errors)
892
+ # 19. Link vs Unlink vs Status
542
893
 
543
- The following codes are defined for compatibility/extension, but current implementation does not reject with these codes:
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
- - `ORIGIN_MISMATCH`
546
- - `MESSAGE_VALIDATION_FAILED`
547
- - `IFRAME_BLOCKED`
900
+ A typical host application can use them together:
548
901
 
549
- For these conditions, the SDK currently logs warnings/errors and ignores invalid messages.
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
- ### Additional plain `Error` throws
914
+ The SDK allows the host application to open Dropp-managed pages directly.
552
915
 
553
- Some paths throw plain `Error` objects (not `createError(...)` output), for example:
916
+ This is useful when the merchant wants to provide access to specific wallet functionality while keeping the Dropp UI/UX.
554
917
 
555
- - SDK used outside browser environment.
556
- - Missing constructor credentials (`merchantId`, `apiKey`).
557
- - Modal iframe creation failure.
918
+ There are two main APIs:
558
919
 
559
- ## Browser Support
920
+ ```js
921
+ Dropp.dashboard(options);
922
+ ```
923
+
924
+ and:
925
+
926
+ ```js
927
+ Dropp.open(moduleId, options);
928
+ ```
560
929
 
561
- - Chrome 90+
562
- - Firefox 88+
563
- - Safari 14+
564
- - Edge 90+
930
+ ### Hosted Page Options (SDK Supported)
565
931
 
566
- ## Troubleshooting
932
+ Hosted page APIs support an options object used for lifecycle callbacks and page customization.
567
933
 
568
- ### Payment modal doesn't open
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
- - Check browser console for errors
571
- - Verify all required fields are provided
572
- - Ensure `merchantId` passed to `Dropp.init(...)` is correct (`"0.0.123456"`)
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
- ### Messages not received
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
- - Check that you're using the correct environment
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
- ### TypeScript errors
2042
+ Recurring callback/SDK responses can vary by environment and flow outcome. `recurringToken` preserve that token in respect of user account.
581
2043
 
582
- - Ensure you have `@dropp.cc/payment-sdk` installed
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
- ### Session already in progress
2046
+ ## 50.5 Known Limits and Constraints
586
2047
 
587
- - SDK allows only one active flow at a time (payment, hosted page, or status check).
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
- ## Support
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
- For issues or questions:
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
- License: UNLICENSED
2059
+ Do not treat client callback success alone as final settlement/authorization proof.
598
2060
 
599
- ## Changelog
2061
+ Backend must verify and persist authoritative transaction state before order fulfillment.
600
2062
 
601
- ### v1.0.0 (2026-06-01)
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
- ### v1.0.3 (2026-07-06)
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
- ### v1.0.4 (2026-07-07)
612
- - Added Support for the Unlink account.
2067
+ Treat this as environment behavior and verify production branding/configuration separately.
613
2068
 
614
- ### v1.0.5 (2026-07-09)
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
- ### v1.0.10 (2026-07-10)
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
- ### v1.0.20 (2026-07-27)
624
- - Added qa and sandbox api gateway support.
625
- - Whitelabeling of the merchants.
2073
+ Ensure your backend includes handling for:
626
2074
 
627
- ### v1.0.23 (2026-08-04)
628
- - Added TypeScript declaration distribution in package dist.
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
- ### v1.0.24 (2026-08-07)
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.