@chargebee/chargebee-apps-libs 0.0.2

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.
Files changed (49) hide show
  1. package/LICENSE +24 -0
  2. package/README.md +270 -0
  3. package/SECURITY.md +8 -0
  4. package/config/README.md +83 -0
  5. package/config/allowed-modules.json +24 -0
  6. package/dist/config/config-loader.d.ts +24 -0
  7. package/dist/config/config-loader.js +95 -0
  8. package/dist/index.d.ts +4 -0
  9. package/dist/index.js +21 -0
  10. package/dist/libs/port-service.d.ts +18 -0
  11. package/dist/libs/port-service.js +27 -0
  12. package/dist/logger/cb-public-logger.d.ts +59 -0
  13. package/dist/logger/cb-public-logger.js +158 -0
  14. package/dist/sandbox/public-sandbox-wrapper.d.ts +41 -0
  15. package/dist/sandbox/public-sandbox-wrapper.js +208 -0
  16. package/package.json +44 -0
  17. package/templates/serverless-node-starter-app/.env +4 -0
  18. package/templates/serverless-node-starter-app/README.md +290 -0
  19. package/templates/serverless-node-starter-app/handler/handler.js +34 -0
  20. package/templates/serverless-node-starter-app/jsconfig.json +35 -0
  21. package/templates/serverless-node-starter-app/manifest.json +15 -0
  22. package/templates/serverless-node-starter-app/test_data/customer_created.json +51 -0
  23. package/templates/serverless-node-starter-app/test_data/invoice_generated.json +112 -0
  24. package/templates/serverless-node-starter-app/test_data/subscription_created.json +173 -0
  25. package/templates/serverless-node-starter-app/types/types.d.ts +45 -0
  26. package/templates/serverless-node-starter-app-with-iparams/.env +4 -0
  27. package/templates/serverless-node-starter-app-with-iparams/README.md +717 -0
  28. package/templates/serverless-node-starter-app-with-iparams/handler/handler.js +39 -0
  29. package/templates/serverless-node-starter-app-with-iparams/iparams.json +41 -0
  30. package/templates/serverless-node-starter-app-with-iparams/iparams.local.json +9 -0
  31. package/templates/serverless-node-starter-app-with-iparams/jsconfig.json +35 -0
  32. package/templates/serverless-node-starter-app-with-iparams/manifest.json +15 -0
  33. package/templates/serverless-node-starter-app-with-iparams/test_data/customer_created.json +51 -0
  34. package/templates/serverless-node-starter-app-with-iparams/test_data/invoice_generated.json +112 -0
  35. package/templates/serverless-node-starter-app-with-iparams/test_data/subscription_created.json +173 -0
  36. package/templates/serverless-node-starter-app-with-iparams/types/types.d.ts +63 -0
  37. package/ui/README.md +118 -0
  38. package/ui/web/assets/css/main.css +1121 -0
  39. package/ui/web/assets/images/Chargebee-logo.png +0 -0
  40. package/ui/web/assets/js/main.js +61 -0
  41. package/ui/web/assets/js/modules/api.js +97 -0
  42. package/ui/web/assets/js/modules/constants.js +33 -0
  43. package/ui/web/assets/js/modules/editors.js +41 -0
  44. package/ui/web/assets/js/modules/events.js +195 -0
  45. package/ui/web/assets/js/modules/form-utils.js +70 -0
  46. package/ui/web/assets/js/modules/iparams-inputs.js +495 -0
  47. package/ui/web/assets/js/modules/iparams.js +82 -0
  48. package/ui/web/assets/js/modules/ui-utils.js +87 -0
  49. package/ui/web/index.html +164 -0
@@ -0,0 +1,717 @@
1
+ # Serverless Node.js App Template With iParams
2
+
3
+ This is a serverless Node.js application template that demonstrates how to build and test serverless functions with event-driven architecture and iParams-based configuration. This template provides a foundation for creating scalable serverless applications with built-in testing capabilities and configurable parameters.
4
+
5
+ ## Features
6
+
7
+ - **Event-Driven Architecture**: Configure multiple event handlers in `manifest.json`
8
+ - **iParams Support**: Define app configuration schema in `iparams.json` and provide local values in `iparams.local.json`
9
+ - **Handler Functions**: Implement your business logic in `handler.js`
10
+ - **Test Data**: Sample event data for local development and testing
11
+ - **Local Testing UI**: Interactive web interface to test your handlers
12
+ - **Logging**: Built-in logging system for debugging and monitoring
13
+
14
+ ## How It Works
15
+
16
+ 1. **Event Configuration**: The `manifest.json` file maps event types to their corresponding handler functions
17
+ 2. **Handler Implementation**: Each event type has its handler function in `handler.js`
18
+ 3. **iParams Configuration**: Define parameter schema in `iparams.json` and provide local values in `iparams.local.json`
19
+ 4. **Test Data**: Sample JSON files in `test_data/` folder match your event names (e.g., `onCustomerCreate.json`)
20
+ 5. **Local Testing**: Use the CLI tool to start a local testing server with a web UI
21
+ 6. **Interactive Testing**: Select event types from the dropdown and click "Test Data" to execute handlers
22
+ 7. **Real-time Logs**: View execution logs directly in your terminal
23
+
24
+ ## Quick Start
25
+
26
+ 1. **Create your app**: `chargebee-apps create <app_directory>`
27
+ 2. **Navigate to app**: `cd <app_directory>`
28
+ 3. **Configure parameters** (optional): You can set the values for the system env vars in the `.env` file if required ([supported system env vars](#environment-variables-system-provided)). For other config, define iparams in `iparams.json` and provide values in `iparams.local.json` (local) or through the web UI (production). See [Installation Parameters (iParams)](#installation-parameters-iparams) for details.
29
+ 4. **Start local server**: `chargebee-apps run <app_directory>`
30
+ 5. **Open browser**: Visit `http://localhost:15000`
31
+ 6. **Test handlers**: Select an event type and click "Test Data"
32
+ 7. **View logs**: Check your terminal for execution output
33
+ 8. **Package your app**: `chargebee-apps package <app_directory>`
34
+
35
+ ## Project Structure
36
+
37
+ ```
38
+ ├── handler/handler.js # Main serverless function handler
39
+ ├── test_data/ # Test data directory
40
+ ├── types/types.d.ts # Recognised types that can be used as JSDoc inside handler function
41
+ ├── .env # Environment variables (API keys, site domain)
42
+ ├── iparams.json # Parameter definitions (schema)
43
+ ├── iparams.local.json # Parameter values for local testing
44
+ ├── jsconfig.json # JS config for dev
45
+ ├── manifest.json # Project configuration
46
+ └── README.md # Read me file
47
+ ```
48
+
49
+ ## Configuration
50
+
51
+ ### Manifest.json
52
+
53
+ The `manifest.json` file is the core configuration file for your serverless application. It defines:
54
+
55
+ 1. **Event Handlers**: Maps Chargebee webhook events to your handler functions
56
+ 2. **Application Metadata**: Basic information about your application
57
+ 3. **Dependencies**: Custom npm packages your application requires
58
+
59
+ #### Basic Structure
60
+
61
+ ```json
62
+ {
63
+ "name": "my-app",
64
+ "version": "1.0.0",
65
+ "description": "A custom app",
66
+ "events": {
67
+ "customer_created": {
68
+ "handler": "customerCreateHandler"
69
+ },
70
+ "subscription_created": {
71
+ "handler": "subscriptionCreatedHandler"
72
+ },
73
+ "invoice_generated": {
74
+ "handler": "invoiceGeneratedHandler"
75
+ }
76
+ },
77
+ "dependencies": {
78
+ "lodash": "^4.17.21",
79
+ "axios": "^1.6.0"
80
+ }
81
+ }
82
+ ```
83
+
84
+ #### Event Handler Configuration
85
+
86
+ Each event in the `events` object maps a Chargebee webhook event to a handler function:
87
+
88
+ ```json
89
+ {
90
+ "events": {
91
+ "customer_created": {
92
+ "handler": "customerCreateHandler"
93
+ }
94
+ }
95
+ }
96
+ ```
97
+
98
+ The handler function must be exported from `handler/handler.js`. Each handler receives a single `payload` argument with `payload.event` (the webhook event) and `payload.iparams` (installation parameters grouped by section):
99
+
100
+ ```javascript
101
+ // handler/handler.js
102
+ module.exports = {
103
+ customerCreateHandler: function(/** @type {import('../types/types.d.ts').HandlerPayload} */payload) {
104
+ console.log('Event type:', payload.event.event_type);
105
+ console.log('Customer created:', payload.event.content.customer.email);
106
+
107
+ // Access iparams by section and parameter name
108
+ const feePercent = payload.iparams.processing_fee_configuration.fee_percentage;
109
+ console.log('Processing fee (%):', feePercent);
110
+ }
111
+ };
112
+ ```
113
+
114
+ #### Custom Dependencies
115
+
116
+ You can add custom npm packages to your application by including them in the `dependencies` section:
117
+
118
+ ```json
119
+ {
120
+ "dependencies": {
121
+ "lodash": "^4.17.21",
122
+ "axios": "^1.6.0",
123
+ "uuid": "^9.0.0"
124
+ }
125
+ }
126
+ ```
127
+
128
+ Then use them in your handler functions:
129
+
130
+ ```javascript
131
+ // handler/handler.js
132
+ const _ = require('lodash');
133
+ const axios = require('axios');
134
+ const moment = require('moment');
135
+ const { v4: uuidv4 } = require('uuid');
136
+
137
+ module.exports = {
138
+ customerCreateHandler: function(/** @type {import('../types/types.d.ts').HandlerPayload} */payload) {
139
+ // Use lodash for data manipulation
140
+ const customerData = _.pick(payload.event.content.customer, ['email', 'first_name', 'last_name']);
141
+
142
+ // Generate unique ID
143
+ const customerId = uuidv4();
144
+
145
+ // Make HTTP requests
146
+ axios.post('https://api.example.com/customers', {
147
+ id: customerId,
148
+ ...customerData,
149
+ created_at: moment().toISOString()
150
+ }).then(response => {
151
+ console.log('Customer synced to external system:', response.data);
152
+ }).catch(error => {
153
+ console.error('Failed to sync customer:', error.message);
154
+ });
155
+ },
156
+
157
+ subscriptionCreatedHandler: function(/** @type {import('../types/types.d.ts').HandlerPayload} */payload) {
158
+ // Use moment for date formatting
159
+ const subscriptionDate = moment(payload.event.content.subscription.created_at * 1000);
160
+ const formattedDate = subscriptionDate.format('MMMM Do YYYY, h:mm:ss a');
161
+
162
+ console.log(`New subscription created on ${formattedDate}`);
163
+
164
+ // Use lodash for data validation
165
+ const requiredFields = ['id', 'customer_id', 'plan_id'];
166
+ const missingFields = _.difference(requiredFields, Object.keys(payload.event.content.subscription));
167
+
168
+ if (missingFields.length > 0) {
169
+ console.warn('Missing subscription fields:', missingFields);
170
+ }
171
+ }
172
+ };
173
+ ```
174
+
175
+ #### Supported Event Types
176
+ Chargebee Apps supports all the event types that are provided in the Chargebee's [documentation](https://apidocs.chargebee.com/docs/api/events#event_types).
177
+
178
+ ### Environment Variables (system-provided)
179
+
180
+ The CLI exposes **only these three** variables via `process.env`; no other environment variables are available to your handlers:
181
+
182
+ | Variable | Description |
183
+ |----------|-------------|
184
+ | `MKPLC_CB_READ_ONLY_API` | Chargebee read-only API key |
185
+ | `MKPLC_CB_READ_WRITE_API` | Chargebee read-write API key |
186
+ | `MKPLC_SITE_DOMAIN` | Chargebee site domain |
187
+
188
+ - **Production:** The system provides these values at runtime. You do not configure them in production.
189
+ - **Local development:** You must provide these values in the `.env` file so your handlers can run locally.
190
+
191
+ **Other configuration** (API keys, secrets, custom settings) must use [Iparams](#installation-parameters-iparams)—either through the Chargebee Apps UI or via `iparams.json` and `iparams.local.json`.
192
+
193
+ #### Setting up .env for local development
194
+
195
+ 1. **Open the `.env` file** in your project root.
196
+ 2. **Replace only the placeholder values** for the three variables above. Do not add new env vars—only these three are supported, and the `.env` file is **not packaged** with your app. Any other variables you add in `.env` will not be available when the app runs in production.
197
+
198
+ ```env
199
+ MKPLC_CB_READ_ONLY_API=your_read_only_api_key_here
200
+ MKPLC_CB_READ_WRITE_API=your_read_write_api_key_here
201
+ MKPLC_SITE_DOMAIN=yousite123
202
+ ```
203
+
204
+ #### Using these variables in your handlers
205
+
206
+ ```javascript
207
+ // handler/handler.js – only these three vars are available from process.env
208
+ const readOnlyApiKey = process.env.MKPLC_CB_READ_ONLY_API;
209
+ const readWriteApiKey = process.env.MKPLC_CB_READ_WRITE_API;
210
+ const siteDomain = process.env.MKPLC_SITE_DOMAIN;
211
+ ```
212
+
213
+ #### Security notes
214
+
215
+ - **Never commit real API keys** to version control.
216
+ - Replace the placeholder values in `.env` with your actual values only for local testing.
217
+
218
+ ## Local Testing
219
+
220
+ Use the CLI tool to test your functions locally with an interactive web interface:
221
+
222
+ ```bash
223
+ # Start the testing server on a specific port
224
+ chargebee-apps run <app_directory> --port <port>
225
+ # Example:
226
+ chargebee-apps run ./sample_app_v0 --port 16000
227
+
228
+ # Open http://localhost:16000 in your browser
229
+ # Select event types from the dropdown and click "Test Data" to execute handlers
230
+ # View real-time logs in your terminal
231
+ ```
232
+
233
+ ## Testing
234
+
235
+ Test data files are located in the `test_data/` directory. Each file is named after its corresponding event type (e.g., `customer_created.json`, `customer_updated.json`). These JSON files contain sample event data that you can use to test your handlers during local development.
236
+
237
+ The test data structure should match the expected input format for your handler functions. You can modify these files to test different scenarios or add new test data files for additional event types.
238
+
239
+ ## Packaging
240
+
241
+ The package command bundles your serverless application into a zip file for deployment.
242
+
243
+ ### Basic Usage
244
+
245
+ ```bash
246
+ # Package with default name (app directory name)
247
+ chargebee-apps package <app_directory>
248
+
249
+ # Package with custom name
250
+ chargebee-apps package <app_directory> --name my-app-v1.0.0
251
+ ```
252
+
253
+ ### Examples
254
+
255
+ ```bash
256
+ # Package current directory
257
+ chargebee-apps package .
258
+
259
+ # Package specific directory
260
+ chargebee-apps package ./my-app
261
+
262
+ # Package with versioned name
263
+ chargebee-apps package ./my-app --name my-app-v1.0.0
264
+ ```
265
+
266
+
267
+ ## Installation Parameters (Iparams)
268
+
269
+ Installation parameters allow you to configure your serverless application with user-provided values that can be used in your handler functions. These parameters are defined in `iparams.json` and their values are provided in `iparams.local.json` (for local testing) or through the Chargebee Apps UI (for production).
270
+
271
+ ### Overview
272
+
273
+ Installation parameters provide a way to:
274
+ - **Configure your app**: Allow users to customize your application behavior
275
+ - **Store credentials**: Securely store API keys, secrets, and configuration values
276
+ - **Organize settings**: Group related parameters into named sections
277
+ - **Provide defaults**: Set sensible default values that users can override
278
+ - **Validate inputs**: Ensure users provide valid values for required parameters
279
+
280
+ ### File Structure
281
+
282
+ - **`iparams.json`**: Defines the parameter schema — sections and their parameter definitions
283
+ - **`iparams.local.json`**: Contains parameter values for local testing, keyed by section name
284
+
285
+ An empty object (`{}`) in either file means no installation parameters are defined.
286
+
287
+ ### Schema Overview
288
+
289
+ Parameters are organized into **sections**. Each section has a name, display metadata, and a list of parameters. In handlers, access values as `payload.iparams.<section_name>.<param_name>`.
290
+
291
+ ```json
292
+ {
293
+ "installation_parameters": {
294
+ "sections": [
295
+ {
296
+ "name": "processing_fee_configuration",
297
+ "display_name": "Processing Fee Configuration",
298
+ "description": "Settings for processing fees",
299
+ "parameters": [
300
+ {
301
+ "name": "fee_percentage",
302
+ "display_name": "Fee Percentage",
303
+ "description": "Processing fee percentage",
304
+ "type": "NUMBER",
305
+ "required": true
306
+ }
307
+ ]
308
+ }
309
+ ]
310
+ }
311
+ }
312
+ ```
313
+
314
+ Corresponding values in `iparams.local.json`:
315
+
316
+ ```json
317
+ {
318
+ "processing_fee_configuration": {
319
+ "fee_percentage": 2.5
320
+ }
321
+ }
322
+ ```
323
+
324
+ ### Defining Sections and Parameters (iparams.json)
325
+
326
+ The root of `iparams.json` may only contain `installation_parameters`. Inside that object, only `sections` is allowed.
327
+
328
+ #### Section Fields
329
+
330
+ | Field | Type | Required | Description |
331
+ |-------|------|----------|-------------|
332
+ | `name` | string | Yes | Unique section identifier (used as the key in `iparams.local.json` and in `payload.iparams.<name>`). Same naming rules as parameter names. |
333
+ | `display_name` | string | Yes | Human-readable section title shown in the UI. Maximum 50 characters. |
334
+ | `description` | string | Yes | Description of what this section configures. Maximum 250 characters. |
335
+ | `parameters` | array | Yes | Non-empty array of parameter definitions (see below). |
336
+
337
+ #### Parameter Fields
338
+
339
+ Each entry in a section's `parameters` array is an object with the following fields:
340
+
341
+ | Field | Type | Required | Description |
342
+ |-------|------|----------|-------------|
343
+ | `name` | string | Yes | Parameter identifier within the section (used as key in inputs). Must be 1–50 characters, start with a letter or underscore, and contain only alphanumeric characters, underscores, and hyphens. Unique within a section; the same name may appear in different sections. |
344
+ | `display_name` | string | Yes | Human-readable name shown in the UI. Maximum 50 characters. |
345
+ | `description` | string | Yes | Description of what the parameter is used for. Maximum 250 characters. |
346
+ | `type` | string | Yes | Data type of the parameter. See [Supported Types](#supported-parameter-types) below. |
347
+ | `required` | boolean | No | Whether the parameter is required. Defaults to `false` if not specified. **Note**: If a parameter has a `default` value, setting `required: true` has no practical effect since the default will always be used. |
348
+ | `default` | varies | No | Default value for the parameter. If present and not `null`, must be a valid value for the parameter type. |
349
+ | `options` | string[] | Conditional | Required for `DROPDOWN` and `MULTISELECT_DROPDOWN` types. Array of valid option values. |
350
+
351
+ #### Validation Rules
352
+
353
+ - **Empty schema**: `{}` is valid — no installation parameters are defined.
354
+ - **Sections required**: When `installation_parameters` is present, `sections` must be a non-empty array.
355
+ - **Parameters required**: Each section must contain at least one parameter.
356
+ - **Uniqueness**: Section names must be unique across the file. Parameter names must be unique within a section.
357
+ - **Limit**: At most **20 parameters** in total across all sections.
358
+ - **Strict keys**: Only `installation_parameters` is allowed at the root; only `sections` is allowed inside `installation_parameters`.
359
+
360
+
361
+ ### Supported Parameter Types
362
+
363
+ #### 1. `TEXT`
364
+
365
+ **Purpose**: Use for API keys, names, descriptions, or any string value.
366
+
367
+ **Input**: String values (maximum 250 characters)
368
+
369
+ **Example:**
370
+ ```json
371
+ {
372
+ "name": "api_key",
373
+ "display_name": "API Key",
374
+ "description": "Your API key for external service",
375
+ "type": "TEXT",
376
+ "required": true
377
+ }
378
+ ```
379
+
380
+ #### 2. `SECRET`
381
+
382
+ **Purpose**: Use for sensitive data like passwords or API secrets. Values are stored encrypted. **Cannot have a default value** for security reasons.
383
+
384
+ **Input**: String values (same as text, but treated as sensitive data)
385
+
386
+ **Example:**
387
+ ```json
388
+ {
389
+ "name": "api_secret",
390
+ "display_name": "API Secret",
391
+ "description": "Your API secret key",
392
+ "type": "SECRET",
393
+ "required": true
394
+ }
395
+ ```
396
+
397
+ #### 3. `URL`
398
+
399
+ **Purpose**: Use for webhook URLs, API endpoints, or any URL value.
400
+
401
+ **Input**: Valid URL strings (maximum 250 characters)
402
+
403
+ **Example:**
404
+ ```json
405
+ {
406
+ "name": "webhook_url",
407
+ "display_name": "Webhook URL",
408
+ "description": "URL for webhook notifications",
409
+ "type": "URL",
410
+ "required": true
411
+ }
412
+ ```
413
+
414
+ #### 4. `NUMBER`
415
+
416
+ **Purpose**: Use for counts, percentages, timeouts, or any numeric configuration.
417
+
418
+ **Input**: Numbers (integers or decimals)
419
+
420
+ **Example:**
421
+ ```json
422
+ {
423
+ "name": "max_retries",
424
+ "display_name": "Max Retries",
425
+ "description": "Maximum number of retry attempts",
426
+ "type": "NUMBER",
427
+ "required": true
428
+ }
429
+ ```
430
+
431
+ #### 5. `BOOLEAN`
432
+
433
+ **Purpose**: Use for feature flags, enable/disable toggles, or any yes/no configuration.
434
+
435
+ **Input**: Boolean values (`true` or `false`)
436
+
437
+ **Example:**
438
+ ```json
439
+ {
440
+ "name": "enable_notifications",
441
+ "display_name": "Enable Notifications",
442
+ "description": "Enable email notifications",
443
+ "type": "BOOLEAN",
444
+ "required": false
445
+ }
446
+ ```
447
+
448
+ #### 6. `DROPDOWN`
449
+
450
+ **Purpose**: Use when you want users to choose one value from a fixed set of choices.
451
+
452
+ **Input**: One string value from the `options` array (maximum 250 characters per option)
453
+
454
+ **Example:**
455
+ ```json
456
+ {
457
+ "name": "environment",
458
+ "display_name": "Environment",
459
+ "description": "Select the environment",
460
+ "type": "DROPDOWN",
461
+ "required": true,
462
+ "default": "production",
463
+ "options": ["development", "staging", "production"]
464
+ }
465
+ ```
466
+
467
+ #### 7. `MULTISELECT_DROPDOWN`
468
+
469
+ **Purpose**: Use when users need to select one or more values from a fixed set of choices.
470
+
471
+ **Input**: Array of strings, where each string is from the `options` array (maximum 250 characters per option)
472
+
473
+ **Example:**
474
+ ```json
475
+ {
476
+ "name": "regions",
477
+ "display_name": "Regions",
478
+ "description": "Select regions where the service is available",
479
+ "type": "MULTISELECT_DROPDOWN",
480
+ "required": false,
481
+ "default": ["US", "EU"],
482
+ "options": ["US", "EU", "APAC", "LATAM", "MEA"]
483
+ }
484
+ ```
485
+
486
+ #### 8. `DATE`
487
+
488
+ **Purpose**: Use for expiry dates, start dates, or any date-based configuration.
489
+
490
+ **Input**: Date strings in `YYYY-MM-DD` format (e.g., `2025-12-31`)
491
+
492
+ **Example:**
493
+ ```json
494
+ {
495
+ "name": "expiry_date",
496
+ "display_name": "Expiry Date",
497
+ "description": "Expiration date for the subscription",
498
+ "type": "DATE",
499
+ "required": false,
500
+ "default": "2025-12-31"
501
+ }
502
+ ```
503
+
504
+ ### Important Notes About Default Values
505
+
506
+ 1. **Default values are always applied**: If a parameter has a `default` value (and it's not `null`), that default will be used whenever the user doesn't provide a value, regardless of whether the parameter is `required` or not.
507
+
508
+ 2. **`required: true` with `default` has no practical meaning**: If a parameter has both `required: true` and a `default` value, the default will always be used when no value is provided, so the parameter will never be "missing". Setting `required: true` in this case doesn't add any validation benefit.
509
+
510
+ 3. **When to use `required: true`**: Only use `required: true` when you want to **force** the user to provide a value and you don't have a default. This ensures the parameter will fail validation if not provided.
511
+
512
+ 4. **When to use `default`**: Use `default` when you want to provide a sensible fallback value that users can override if needed. This is especially useful for optional parameters.
513
+
514
+
515
+
516
+ ### Providing Parameter Values
517
+
518
+ #### For Local Testing (iparams.local.json)
519
+
520
+ Values are grouped by section name. Each section key maps to an object of parameter name → value:
521
+
522
+ ```json
523
+ {
524
+ "processing_fee_configuration": {
525
+ "fee_percentage": 2.5,
526
+ "fee_limit": 50
527
+ },
528
+ "late_payment_fee_configuration": {
529
+ "fee_percentage": 1.5
530
+ },
531
+ "external_api": {
532
+ "api_key": "test-api-key-12345",
533
+ "api_secret": "test-secret-key",
534
+ "api_url": "https://api.test.example.com",
535
+ "default_currency": "EUR",
536
+ "regions": ["US", "APAC"],
537
+ "enable_feature_x": true,
538
+ "expiry_date": "2026-12-31"
539
+ }
540
+ }
541
+ ```
542
+
543
+ An empty object (`{}`) is valid when no local values are needed.
544
+
545
+
546
+
547
+ #### Using the Web UI
548
+
549
+ When you run `chargebee-apps run`, a web interface is available at `http://localhost:15000` with tabs:
550
+
551
+ 1. **"Iparams" Tab**:
552
+ - Edit the `iparams.json` schema (sections and parameters)
553
+ - Define sections with their parameters, types, descriptions, and defaults
554
+ - Click "Edit" to enable editing, then "Save Iparams" to save changes
555
+
556
+ 2. **"Iparams Inputs" Tab**:
557
+ - View parameters grouped by section in a form or JSON view
558
+ - Provide values for your parameters
559
+ - Values are saved to `iparams.local.json` keyed by section name
560
+ - Default values are automatically loaded and displayed
561
+ - Click "Switch to JSON" to toggle between form view and JSON view
562
+ - Click "Edit" to enable editing, then "Save Inputs" to save your values
563
+
564
+
565
+ ### Using Parameters in Your Handlers
566
+
567
+ Each handler receives a single `payload` argument. Use `payload.event` for the webhook event and `payload.iparams.<section>.<param>` for installation parameters:
568
+
569
+ ```javascript
570
+ // handler/handler.js
571
+ module.exports = {
572
+ customerCreateHandler: function(
573
+ /** @type {import('../types/types.d.ts').HandlerPayload} */payload
574
+ ) {
575
+ const processingFees = payload.iparams.processing_fee_configuration;
576
+ const apiConfig = payload.iparams.external_api;
577
+
578
+ const feePercent = processingFees.fee_percentage;
579
+ const feeLimit = processingFees.fee_limit;
580
+ const apiKey = apiConfig?.api_key;
581
+ const regions = apiConfig?.regions; // Array for MULTISELECT_DROPDOWN
582
+
583
+ console.log('Processing fee (%):', feePercent);
584
+ console.log('Fee limit:', feeLimit);
585
+ console.log('Regions:', regions);
586
+
587
+ if (apiConfig?.enable_feature_x) {
588
+ console.log('Feature X is enabled');
589
+ }
590
+
591
+ const axios = require('axios');
592
+ if (apiKey && apiConfig.api_url) {
593
+ axios.post(`${apiConfig.api_url}/customers`, { apiKey, regions });
594
+ }
595
+ }
596
+ };
597
+ ```
598
+
599
+ ### Complete Example
600
+
601
+ Here's a complete `iparams.json` example with two sections and all parameter types:
602
+
603
+ ```json
604
+ {
605
+ "installation_parameters": {
606
+ "sections": [
607
+ {
608
+ "name": "external_api",
609
+ "display_name": "External API",
610
+ "description": "Configuration for external API integration",
611
+ "parameters": [
612
+ {
613
+ "name": "api_key",
614
+ "display_name": "External API Key",
615
+ "description": "API key for external service integration",
616
+ "type": "TEXT",
617
+ "required": true
618
+ },
619
+ {
620
+ "name": "api_secret",
621
+ "display_name": "External API Secret",
622
+ "description": "Secret for external service",
623
+ "type": "SECRET",
624
+ "required": true
625
+ },
626
+ {
627
+ "name": "api_url",
628
+ "display_name": "External API URL",
629
+ "description": "Base URL for external API",
630
+ "type": "URL",
631
+ "default": "https://api.example.com"
632
+ },
633
+ {
634
+ "name": "default_currency",
635
+ "display_name": "Default Currency",
636
+ "description": "Default currency code for transactions",
637
+ "type": "DROPDOWN",
638
+ "default": "USD",
639
+ "options": ["USD", "EUR", "GBP", "INR"]
640
+ },
641
+ {
642
+ "name": "regions",
643
+ "display_name": "Regions",
644
+ "description": "Select regions where the service is available",
645
+ "type": "MULTISELECT_DROPDOWN",
646
+ "default": ["US", "EU"],
647
+ "options": ["US", "EU", "APAC", "LATAM", "MEA"]
648
+ },
649
+ {
650
+ "name": "additional_fee_percent",
651
+ "display_name": "Additional Fee (%)",
652
+ "description": "Additional fee percentage to be applied",
653
+ "type": "NUMBER",
654
+ "required": true
655
+ },
656
+ {
657
+ "name": "enable_feature_x",
658
+ "display_name": "Enable Feature X",
659
+ "description": "Enable advanced feature X",
660
+ "type": "BOOLEAN",
661
+ "default": false
662
+ },
663
+ {
664
+ "name": "expiry_date",
665
+ "display_name": "Expiry Date",
666
+ "description": "Expiration date for the subscription",
667
+ "type": "DATE",
668
+ "default": "2025-12-31"
669
+ }
670
+ ]
671
+ },
672
+ {
673
+ "name": "processing_fee_configuration",
674
+ "display_name": "Processing Fee Configuration",
675
+ "description": "Settings for processing fees on invoices",
676
+ "parameters": [
677
+ {
678
+ "name": "fee_percentage",
679
+ "display_name": "Fee Percentage",
680
+ "description": "Processing fee percentage",
681
+ "type": "NUMBER",
682
+ "required": true
683
+ },
684
+ {
685
+ "name": "fee_limit",
686
+ "display_name": "Fee Limit",
687
+ "description": "Maximum processing fee amount",
688
+ "type": "NUMBER",
689
+ "default": 100
690
+ }
691
+ ]
692
+ }
693
+ ]
694
+ }
695
+ }
696
+ ```
697
+
698
+ Matching `iparams.local.json`:
699
+
700
+ ```json
701
+ {
702
+ "external_api": {
703
+ "api_key": "test-api-key-12345",
704
+ "api_secret": "test-secret-key",
705
+ "api_url": "https://api.test.example.com",
706
+ "default_currency": "EUR",
707
+ "regions": ["US", "APAC"],
708
+ "additional_fee_percent": 5.5,
709
+ "enable_feature_x": true,
710
+ "expiry_date": "2026-12-31"
711
+ },
712
+ "processing_fee_configuration": {
713
+ "fee_percentage": 2.5,
714
+ "fee_limit": 50
715
+ }
716
+ }
717
+ ```