n8n-nodes-whmcs 1.0.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (48) hide show
  1. package/LICENSE.md +21 -0
  2. package/README.md +87 -0
  3. package/dist/credentials/WhmcsApi.credentials.d.ts +9 -0
  4. package/dist/credentials/WhmcsApi.credentials.js +102 -0
  5. package/dist/credentials/WhmcsApi.credentials.js.map +1 -0
  6. package/dist/nodes/Whmcs/GenericFunctions.d.ts +4 -0
  7. package/dist/nodes/Whmcs/GenericFunctions.js +73 -0
  8. package/dist/nodes/Whmcs/GenericFunctions.js.map +1 -0
  9. package/dist/nodes/Whmcs/Whmcs.node.d.ts +5 -0
  10. package/dist/nodes/Whmcs/Whmcs.node.js +213 -0
  11. package/dist/nodes/Whmcs/Whmcs.node.js.map +1 -0
  12. package/dist/nodes/Whmcs/WhmcsTrigger.node.d.ts +12 -0
  13. package/dist/nodes/Whmcs/WhmcsTrigger.node.js +102 -0
  14. package/dist/nodes/Whmcs/WhmcsTrigger.node.js.map +1 -0
  15. package/dist/nodes/Whmcs/descriptions/ClientDescription.d.ts +3 -0
  16. package/dist/nodes/Whmcs/descriptions/ClientDescription.js +97 -0
  17. package/dist/nodes/Whmcs/descriptions/ClientDescription.js.map +1 -0
  18. package/dist/nodes/Whmcs/descriptions/CustomDescription.d.ts +3 -0
  19. package/dist/nodes/Whmcs/descriptions/CustomDescription.js +43 -0
  20. package/dist/nodes/Whmcs/descriptions/CustomDescription.js.map +1 -0
  21. package/dist/nodes/Whmcs/descriptions/DomainDescription.d.ts +3 -0
  22. package/dist/nodes/Whmcs/descriptions/DomainDescription.js +98 -0
  23. package/dist/nodes/Whmcs/descriptions/DomainDescription.js.map +1 -0
  24. package/dist/nodes/Whmcs/descriptions/InvoiceDescription.d.ts +3 -0
  25. package/dist/nodes/Whmcs/descriptions/InvoiceDescription.js +100 -0
  26. package/dist/nodes/Whmcs/descriptions/InvoiceDescription.js.map +1 -0
  27. package/dist/nodes/Whmcs/descriptions/OrderDescription.d.ts +3 -0
  28. package/dist/nodes/Whmcs/descriptions/OrderDescription.js +79 -0
  29. package/dist/nodes/Whmcs/descriptions/OrderDescription.js.map +1 -0
  30. package/dist/nodes/Whmcs/descriptions/ProductDescription.d.ts +3 -0
  31. package/dist/nodes/Whmcs/descriptions/ProductDescription.js +95 -0
  32. package/dist/nodes/Whmcs/descriptions/ProductDescription.js.map +1 -0
  33. package/dist/nodes/Whmcs/descriptions/SharedFields.d.ts +3 -0
  34. package/dist/nodes/Whmcs/descriptions/SharedFields.js +52 -0
  35. package/dist/nodes/Whmcs/descriptions/SharedFields.js.map +1 -0
  36. package/dist/nodes/Whmcs/descriptions/SystemDescription.d.ts +3 -0
  37. package/dist/nodes/Whmcs/descriptions/SystemDescription.js +61 -0
  38. package/dist/nodes/Whmcs/descriptions/SystemDescription.js.map +1 -0
  39. package/dist/nodes/Whmcs/descriptions/TicketDescription.d.ts +3 -0
  40. package/dist/nodes/Whmcs/descriptions/TicketDescription.js +99 -0
  41. package/dist/nodes/Whmcs/descriptions/TicketDescription.js.map +1 -0
  42. package/dist/nodes/Whmcs/descriptions/index.d.ts +8 -0
  43. package/dist/nodes/Whmcs/descriptions/index.js +25 -0
  44. package/dist/nodes/Whmcs/descriptions/index.js.map +1 -0
  45. package/dist/nodes/Whmcs/whmcs.svg +4 -0
  46. package/dist/tsconfig.tsbuildinfo +1 -0
  47. package/index.js +3 -0
  48. package/package.json +63 -0
package/LICENSE.md ADDED
@@ -0,0 +1,21 @@
1
+ MIT License
2
+
3
+ Copyright (c) 2026 Anthony Tuberville
4
+
5
+ Permission is hereby granted, free of charge, to any person obtaining a copy
6
+ of this software and associated documentation files (the "Software"), to deal
7
+ in the Software without restriction, including without limitation the rights
8
+ to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9
+ copies of the Software, and to permit persons to whom the Software is
10
+ furnished to do so, subject to the following conditions:
11
+
12
+ The above copyright notice and this permission notice shall be included in all
13
+ copies or substantial portions of the Software.
14
+
15
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16
+ IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17
+ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18
+ AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19
+ LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20
+ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21
+ SOFTWARE.
package/README.md ADDED
@@ -0,0 +1,87 @@
1
+ # n8n-nodes-whmcs
2
+
3
+ A community node package that brings the [WHMCS](https://www.whmcs.com/) billing &
4
+ automation API into [n8n](https://n8n.io/) as native nodes.
5
+
6
+ It ships two nodes:
7
+
8
+ - **WHMCS** — an action node covering Clients, Orders, Invoices, Products/Services,
9
+ Tickets, Domains and System operations, plus a *Custom API Call* escape hatch that
10
+ can invoke any of the 200+ documented WHMCS actions.
11
+ - **WHMCS Trigger** — a webhook node that starts workflows from WHMCS hook events
12
+ (new order, invoice paid, ticket opened, …) via a small PHP bridge file.
13
+
14
+ > Full design, endpoint, authentication and workflow documentation lives in
15
+ > [`WHMCS-n8n-Node-Technical-Documentation.md`](./WHMCS-n8n-Node-Technical-Documentation.md)
16
+ > (in the parent folder).
17
+
18
+ ## Installation
19
+
20
+ ### Via the n8n UI (recommended)
21
+ 1. In n8n go to **Settings → Community Nodes → Install**.
22
+ 2. Enter `n8n-nodes-whmcs` and confirm.
23
+
24
+ ### Manual / self-hosted
25
+ ```bash
26
+ cd ~/.n8n/nodes # or your N8N_CUSTOM_EXTENSIONS path
27
+ npm install n8n-nodes-whmcs
28
+ ```
29
+
30
+ ### Build from source
31
+ ```bash
32
+ git clone https://github.com/Falcyn/n8n-nodes-whmcs.git
33
+ cd n8n-nodes-whmcs
34
+ npm install
35
+ npm run build # tsc + copies icons into dist/
36
+ npm run lint # eslint with eslint-plugin-n8n-nodes-base
37
+ ```
38
+ The compiled output in `dist/` is what n8n loads (see the `n8n` block in `package.json`).
39
+
40
+ ## Credentials
41
+
42
+ Create an API credential in WHMCS first:
43
+
44
+ 1. **Configuration → System Settings → Manage API Credentials → Generate New API Credential.**
45
+ 2. Pick an admin role that has the **API Access** permission.
46
+ 3. Copy the **Identifier** and **Secret** (the secret is shown only once).
47
+
48
+ Then in n8n add a **WHMCS API** credential:
49
+
50
+ | Field | Example | Notes |
51
+ |-------|---------|-------|
52
+ | WHMCS Base URL | `https://billing.example.com` | No trailing slash |
53
+ | API Path | `/includes/api.php` | Default; change only for sub-dir installs |
54
+ | API Identifier | `D4j1dKYE…` | From WHMCS |
55
+ | API Secret | `F1CKGXRI…` | From WHMCS |
56
+ | Access Key | *(optional)* | Matches `$api_access_key` in `configuration.php`; bypasses IP allow-listing |
57
+ | Ignore SSL Issues | off | Enable only for trusted internal hosts |
58
+
59
+ The credential **Test** button calls the harmless `WhmcsDetails` action to confirm the
60
+ identifier/secret and IP/access-key configuration.
61
+
62
+ ## Trigger setup (optional)
63
+
64
+ 1. Add a **WHMCS Trigger** node and copy its **Production URL**.
65
+ 2. Copy `bridge/whmcs-hook-bridge.php` into your WHMCS `includes/hooks/` directory.
66
+ 3. Edit the file: set `$n8nWebhookUrl` to the Production URL, optionally set
67
+ `$sharedSecret`, and list the events in `$forwardEvents`.
68
+ 4. Set the same secret in the node's **Shared Secret** field.
69
+
70
+ ## Quick example
71
+
72
+ *Get every unpaid invoice for client 42:*
73
+
74
+ - Resource **Invoice** → Operation **Get Many**
75
+ - Filters → Client ID `42`, Status `Unpaid`
76
+
77
+ ## Disclaimer
78
+
79
+ This is an unofficial, community-maintained project. It is **not affiliated with,
80
+ endorsed by, or sponsored by WHMCS Limited**. "WHMCS" is a trademark of WHMCS Limited
81
+ and is used here only to describe API compatibility. This package contains **no WHMCS
82
+ source code** — it communicates with WHMCS solely through its public, documented API.
83
+ The software is provided "as is", without warranty of any kind (see [LICENSE](LICENSE.md)).
84
+
85
+ ## License
86
+
87
+ [MIT](LICENSE.md) © Anthony Tuberville
@@ -0,0 +1,9 @@
1
+ import type { ICredentialDataDecryptedObject, ICredentialTestRequest, ICredentialType, IHttpRequestOptions, INodeProperties } from 'n8n-workflow';
2
+ export declare class WhmcsApi implements ICredentialType {
3
+ name: string;
4
+ displayName: string;
5
+ documentationUrl: string;
6
+ properties: INodeProperties[];
7
+ authenticate(credentials: ICredentialDataDecryptedObject, requestOptions: IHttpRequestOptions): Promise<IHttpRequestOptions>;
8
+ test: ICredentialTestRequest;
9
+ }
@@ -0,0 +1,102 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.WhmcsApi = void 0;
4
+ class WhmcsApi {
5
+ constructor() {
6
+ this.name = 'whmcsApi';
7
+ this.displayName = 'WHMCS API';
8
+ this.documentationUrl = 'https://developers.whmcs.com/api/';
9
+ this.properties = [
10
+ {
11
+ displayName: 'WHMCS Base URL',
12
+ name: 'baseUrl',
13
+ type: 'string',
14
+ default: '',
15
+ placeholder: 'https://billing.example.com',
16
+ required: true,
17
+ description: 'Root URL of your WHMCS installation, without a trailing slash. The node appends the API path automatically.',
18
+ },
19
+ {
20
+ displayName: 'API Path',
21
+ name: 'apiPath',
22
+ type: 'string',
23
+ default: '/includes/api.php',
24
+ required: true,
25
+ description: 'Path to the WHMCS external API endpoint relative to the base URL. Only change this if your installation lives in a sub-directory.',
26
+ },
27
+ {
28
+ displayName: 'API Identifier',
29
+ name: 'identifier',
30
+ type: 'string',
31
+ default: '',
32
+ required: true,
33
+ description: 'The API Identifier generated in WHMCS under Configuration > System Settings > Manage API Credentials.',
34
+ },
35
+ {
36
+ displayName: 'API Secret',
37
+ name: 'secret',
38
+ type: 'string',
39
+ typeOptions: { password: true },
40
+ default: '',
41
+ required: true,
42
+ description: 'The API Secret paired with the identifier above. Store it securely — WHMCS only shows it once.',
43
+ },
44
+ {
45
+ displayName: 'Access Key',
46
+ name: 'accessKey',
47
+ type: 'string',
48
+ typeOptions: { password: true },
49
+ default: '',
50
+ description: 'Optional. The value of $api_access_key from configuration.php. Set this if your n8n host IP is not whitelisted under Setup > General Settings > Security and you want to bypass IP restrictions.',
51
+ },
52
+ {
53
+ displayName: 'Ignore SSL Issues',
54
+ name: 'allowUnauthorizedCerts',
55
+ type: 'boolean',
56
+ default: false,
57
+ description: 'Whether to connect even if SSL certificate validation fails. Only enable for trusted internal/staging hosts.',
58
+ },
59
+ ];
60
+ this.test = {
61
+ request: {
62
+ baseURL: '={{$credentials.baseUrl.replace(new RegExp("/$"), "")}}',
63
+ url: '={{$credentials.apiPath}}',
64
+ method: 'POST',
65
+ body: {
66
+ action: 'WhmcsDetails',
67
+ responsetype: 'json',
68
+ },
69
+ },
70
+ rules: [
71
+ {
72
+ type: 'responseSuccessBody',
73
+ properties: {
74
+ key: 'result',
75
+ value: 'error',
76
+ message: 'WHMCS rejected the credentials. Check the identifier/secret, the API Access role permission, and IP/access-key restrictions.',
77
+ },
78
+ },
79
+ ],
80
+ };
81
+ }
82
+ async authenticate(credentials, requestOptions) {
83
+ var _a;
84
+ const body = (_a = requestOptions.body) !== null && _a !== void 0 ? _a : {};
85
+ body.identifier = credentials.identifier;
86
+ body.secret = credentials.secret;
87
+ if (credentials.accessKey) {
88
+ body.accesskey = credentials.accessKey;
89
+ }
90
+ if (!body.responsetype) {
91
+ body.responsetype = 'json';
92
+ }
93
+ requestOptions.body = body;
94
+ requestOptions.headers = {
95
+ ...requestOptions.headers,
96
+ 'Content-Type': 'application/x-www-form-urlencoded',
97
+ };
98
+ return requestOptions;
99
+ }
100
+ }
101
+ exports.WhmcsApi = WhmcsApi;
102
+ //# sourceMappingURL=WhmcsApi.credentials.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"WhmcsApi.credentials.js","sourceRoot":"","sources":["../../credentials/WhmcsApi.credentials.ts"],"names":[],"mappings":";;;AAoBA,MAAa,QAAQ;IAArB;QACC,SAAI,GAAG,UAAU,CAAC;QAElB,gBAAW,GAAG,WAAW,CAAC;QAE1B,qBAAgB,GAAG,mCAAmC,CAAC;QAEvD,eAAU,GAAsB;YAC/B;gBACC,WAAW,EAAE,gBAAgB;gBAC7B,IAAI,EAAE,SAAS;gBACf,IAAI,EAAE,QAAQ;gBACd,OAAO,EAAE,EAAE;gBACX,WAAW,EAAE,6BAA6B;gBAC1C,QAAQ,EAAE,IAAI;gBACd,WAAW,EACV,6GAA6G;aAC9G;YACD;gBACC,WAAW,EAAE,UAAU;gBACvB,IAAI,EAAE,SAAS;gBACf,IAAI,EAAE,QAAQ;gBACd,OAAO,EAAE,mBAAmB;gBAC5B,QAAQ,EAAE,IAAI;gBACd,WAAW,EACV,mIAAmI;aACpI;YACD;gBACC,WAAW,EAAE,gBAAgB;gBAC7B,IAAI,EAAE,YAAY;gBAClB,IAAI,EAAE,QAAQ;gBACd,OAAO,EAAE,EAAE;gBACX,QAAQ,EAAE,IAAI;gBACd,WAAW,EACV,uGAAuG;aACxG;YACD;gBACC,WAAW,EAAE,YAAY;gBACzB,IAAI,EAAE,QAAQ;gBACd,IAAI,EAAE,QAAQ;gBACd,WAAW,EAAE,EAAE,QAAQ,EAAE,IAAI,EAAE;gBAC/B,OAAO,EAAE,EAAE;gBACX,QAAQ,EAAE,IAAI;gBACd,WAAW,EAAE,gGAAgG;aAC7G;YACD;gBACC,WAAW,EAAE,YAAY;gBACzB,IAAI,EAAE,WAAW;gBACjB,IAAI,EAAE,QAAQ;gBACd,WAAW,EAAE,EAAE,QAAQ,EAAE,IAAI,EAAE;gBAC/B,OAAO,EAAE,EAAE;gBACX,WAAW,EACV,kMAAkM;aACnM;YACD;gBACC,WAAW,EAAE,mBAAmB;gBAChC,IAAI,EAAE,wBAAwB;gBAC9B,IAAI,EAAE,SAAS;gBACf,OAAO,EAAE,KAAK;gBACd,WAAW,EACV,8GAA8G;aAC/G;SACD,CAAC;QAkCF,SAAI,GAA2B;YAC9B,OAAO,EAAE;gBACR,OAAO,EAAE,yDAAyD;gBAClE,GAAG,EAAE,2BAA2B;gBAChC,MAAM,EAAE,MAAM;gBACd,IAAI,EAAE;oBACL,MAAM,EAAE,cAAc;oBACtB,YAAY,EAAE,MAAM;iBACpB;aACD;YACD,KAAK,EAAE;gBACN;oBACC,IAAI,EAAE,qBAAqB;oBAC3B,UAAU,EAAE;wBACX,GAAG,EAAE,QAAQ;wBACb,KAAK,EAAE,OAAO;wBACd,OAAO,EACN,8HAA8H;qBAC/H;iBACD;aACD;SACD,CAAC;IACH,CAAC;IAlDA,KAAK,CAAC,YAAY,CACjB,WAA2C,EAC3C,cAAmC;;QAEnC,MAAM,IAAI,GAAG,MAAC,cAAc,CAAC,IAAgC,mCAAI,EAAE,CAAC;QAEpE,IAAI,CAAC,UAAU,GAAG,WAAW,CAAC,UAAU,CAAC;QACzC,IAAI,CAAC,MAAM,GAAG,WAAW,CAAC,MAAM,CAAC;QACjC,IAAI,WAAW,CAAC,SAAS,EAAE,CAAC;YAC3B,IAAI,CAAC,SAAS,GAAG,WAAW,CAAC,SAAS,CAAC;QACxC,CAAC;QACD,IAAI,CAAC,IAAI,CAAC,YAAY,EAAE,CAAC;YACxB,IAAI,CAAC,YAAY,GAAG,MAAM,CAAC;QAC5B,CAAC;QAED,cAAc,CAAC,IAAI,GAAG,IAAI,CAAC;QAC3B,cAAc,CAAC,OAAO,GAAG;YACxB,GAAG,cAAc,CAAC,OAAO;YACzB,cAAc,EAAE,mCAAmC;SACnD,CAAC;QAEF,OAAO,cAAc,CAAC;IACvB,CAAC;CA4BD;AAtHD,4BAsHC"}
@@ -0,0 +1,4 @@
1
+ import type { IDataObject, IExecuteFunctions, IHookFunctions, ILoadOptionsFunctions } from 'n8n-workflow';
2
+ export declare function whmcsApiRequest(this: IExecuteFunctions | ILoadOptionsFunctions | IHookFunctions, action: string, body?: IDataObject): Promise<IDataObject>;
3
+ export declare function parseCustomParameters(raw: IDataObject | undefined): IDataObject;
4
+ export declare function maybeJsonToObject(this: IExecuteFunctions, value: string | IDataObject, fieldName: string, itemIndex: number): IDataObject;
@@ -0,0 +1,73 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.whmcsApiRequest = whmcsApiRequest;
4
+ exports.parseCustomParameters = parseCustomParameters;
5
+ exports.maybeJsonToObject = maybeJsonToObject;
6
+ const n8n_workflow_1 = require("n8n-workflow");
7
+ async function whmcsApiRequest(action, body = {}) {
8
+ var _a;
9
+ const credentials = await this.getCredentials('whmcsApi');
10
+ const baseUrl = credentials.baseUrl.replace(/\/$/, '');
11
+ const apiPath = credentials.apiPath || '/includes/api.php';
12
+ const form = { action, responsetype: 'json' };
13
+ for (const [key, value] of Object.entries(body)) {
14
+ if (value === undefined || value === null || value === '') {
15
+ continue;
16
+ }
17
+ form[key] = value;
18
+ }
19
+ const options = {
20
+ method: 'POST',
21
+ url: `${baseUrl}${apiPath}`,
22
+ body: form,
23
+ headers: { 'Content-Type': 'application/x-www-form-urlencoded' },
24
+ json: true,
25
+ skipSslCertificateValidation: credentials.allowUnauthorizedCerts === true,
26
+ };
27
+ let response;
28
+ try {
29
+ response = (await this.helpers.httpRequestWithAuthentication.call(this, 'whmcsApi', options));
30
+ }
31
+ catch (error) {
32
+ throw new n8n_workflow_1.NodeApiError(this.getNode(), error);
33
+ }
34
+ if (typeof response === 'string') {
35
+ try {
36
+ response = JSON.parse(response);
37
+ }
38
+ catch {
39
+ throw new n8n_workflow_1.NodeOperationError(this.getNode(), `WHMCS returned a non-JSON response for action "${action}". Confirm responsetype=json is permitted.`);
40
+ }
41
+ }
42
+ if (response.result === 'error') {
43
+ throw new n8n_workflow_1.NodeOperationError(this.getNode(), `WHMCS API error on "${action}": ${(_a = response.message) !== null && _a !== void 0 ? _a : 'Unknown error'}`, { description: 'Check the action parameters and the API role permissions in WHMCS.' });
44
+ }
45
+ return response;
46
+ }
47
+ function parseCustomParameters(raw) {
48
+ var _a;
49
+ const out = {};
50
+ if (!raw)
51
+ return out;
52
+ const params = (_a = raw.parameter) !== null && _a !== void 0 ? _a : [];
53
+ for (const p of params) {
54
+ if (p.name !== undefined && p.name !== '') {
55
+ out[p.name] = p.value;
56
+ }
57
+ }
58
+ return out;
59
+ }
60
+ function maybeJsonToObject(value, fieldName, itemIndex) {
61
+ if (typeof value !== 'string')
62
+ return value;
63
+ const trimmed = value.trim();
64
+ if (trimmed === '')
65
+ return {};
66
+ try {
67
+ return JSON.parse(trimmed);
68
+ }
69
+ catch {
70
+ throw new n8n_workflow_1.NodeOperationError(this.getNode(), `The field "${fieldName}" must contain valid JSON.`, { itemIndex });
71
+ }
72
+ }
73
+ //# sourceMappingURL=GenericFunctions.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"GenericFunctions.js","sourceRoot":"","sources":["../../../nodes/Whmcs/GenericFunctions.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,5 @@
1
+ import type { IExecuteFunctions, INodeExecutionData, INodeType, INodeTypeDescription } from 'n8n-workflow';
2
+ export declare class Whmcs implements INodeType {
3
+ description: INodeTypeDescription;
4
+ execute(this: IExecuteFunctions): Promise<INodeExecutionData[][]>;
5
+ }
@@ -0,0 +1,213 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.Whmcs = void 0;
4
+ const n8n_workflow_1 = require("n8n-workflow");
5
+ const GenericFunctions_1 = require("./GenericFunctions");
6
+ const descriptions_1 = require("./descriptions");
7
+ const ACTION_MAP = {
8
+ client: {
9
+ create: 'AddClient',
10
+ get: 'GetClientsDetails',
11
+ getAll: 'GetClients',
12
+ update: 'UpdateClient',
13
+ delete: 'DeleteClient',
14
+ close: 'CloseClient',
15
+ getProducts: 'GetClientsProducts',
16
+ getDomains: 'GetClientsDomains',
17
+ },
18
+ order: {
19
+ create: 'AddOrder',
20
+ getAll: 'GetOrders',
21
+ accept: 'AcceptOrder',
22
+ pending: 'PendingOrder',
23
+ cancel: 'CancelOrder',
24
+ delete: 'DeleteOrder',
25
+ fraud: 'FraudOrder',
26
+ },
27
+ invoice: {
28
+ create: 'CreateInvoice',
29
+ get: 'GetInvoice',
30
+ getAll: 'GetInvoices',
31
+ update: 'UpdateInvoice',
32
+ addPayment: 'AddInvoicePayment',
33
+ applyCredit: 'ApplyCredit',
34
+ generate: 'GenInvoices',
35
+ },
36
+ product: {
37
+ getCatalogue: 'GetProducts',
38
+ getServices: 'GetClientsProducts',
39
+ update: 'UpdateClientProduct',
40
+ upgrade: 'UpgradeProduct',
41
+ suspend: 'ModuleSuspend',
42
+ unsuspend: 'ModuleUnsuspend',
43
+ terminate: 'ModuleTerminate',
44
+ },
45
+ ticket: {
46
+ create: 'OpenTicket',
47
+ get: 'GetTicket',
48
+ getAll: 'GetTickets',
49
+ reply: 'AddTicketReply',
50
+ update: 'UpdateTicket',
51
+ delete: 'DeleteTicket',
52
+ getDepartments: 'GetSupportDepartments',
53
+ },
54
+ domain: {
55
+ getAll: 'GetClientsDomains',
56
+ register: 'DomainRegister',
57
+ renew: 'DomainRenew',
58
+ transfer: 'DomainTransfer',
59
+ getNameservers: 'DomainGetNameservers',
60
+ updateNameservers: 'DomainUpdateNameservers',
61
+ toggleIdProtect: 'DomainToggleIdProtect',
62
+ update: 'UpdateClientDomain',
63
+ },
64
+ system: {
65
+ getStats: 'GetStats',
66
+ details: 'WhmcsDetails',
67
+ sendEmail: 'SendEmail',
68
+ getActivityLog: 'GetActivityLog',
69
+ getCurrencies: 'GetCurrencies',
70
+ getPaymentMethods: 'GetPaymentMethods',
71
+ },
72
+ };
73
+ const FLATTEN_COLLECTIONS = [
74
+ 'additionalFields',
75
+ 'updateFields',
76
+ 'filters',
77
+ 'paymentFields',
78
+ 'replyOptions',
79
+ 'acceptOptions',
80
+ 'orderItems',
81
+ 'registerFields',
82
+ 'upgradeFields',
83
+ 'updateNameservers',
84
+ 'nameservers',
85
+ 'serviceFilters',
86
+ 'catalogueFilters',
87
+ 'logFilters',
88
+ 'emailFields',
89
+ ];
90
+ class Whmcs {
91
+ constructor() {
92
+ this.description = {
93
+ displayName: 'WHMCS',
94
+ name: 'whmcs',
95
+ icon: 'file:whmcs.svg',
96
+ group: ['transform'],
97
+ version: 1,
98
+ subtitle: '={{$parameter["operation"] + ": " + $parameter["resource"]}}',
99
+ description: 'Interact with the WHMCS billing & automation API',
100
+ defaults: { name: 'WHMCS' },
101
+ inputs: ['main'],
102
+ outputs: ['main'],
103
+ credentials: [{ name: 'whmcsApi', required: true }],
104
+ properties: [
105
+ {
106
+ displayName: 'Resource',
107
+ name: 'resource',
108
+ type: 'options',
109
+ noDataExpression: true,
110
+ options: [
111
+ { name: 'Client', value: 'client' },
112
+ { name: 'Custom API Call', value: 'custom' },
113
+ { name: 'Domain', value: 'domain' },
114
+ { name: 'Invoice', value: 'invoice' },
115
+ { name: 'Order', value: 'order' },
116
+ { name: 'Product / Service', value: 'product' },
117
+ { name: 'System', value: 'system' },
118
+ { name: 'Ticket', value: 'ticket' },
119
+ ],
120
+ default: 'client',
121
+ },
122
+ ...descriptions_1.clientOperations,
123
+ ...descriptions_1.clientFields,
124
+ ...descriptions_1.orderOperations,
125
+ ...descriptions_1.orderFields,
126
+ ...descriptions_1.invoiceOperations,
127
+ ...descriptions_1.invoiceFields,
128
+ ...descriptions_1.productOperations,
129
+ ...descriptions_1.productFields,
130
+ ...descriptions_1.ticketOperations,
131
+ ...descriptions_1.ticketFields,
132
+ ...descriptions_1.domainOperations,
133
+ ...descriptions_1.domainFields,
134
+ ...descriptions_1.systemOperations,
135
+ ...descriptions_1.systemFields,
136
+ ...descriptions_1.customOperations,
137
+ ...descriptions_1.customFields,
138
+ ],
139
+ };
140
+ }
141
+ async execute() {
142
+ var _a;
143
+ const items = this.getInputData();
144
+ const returnData = [];
145
+ const resource = this.getNodeParameter('resource', 0);
146
+ const operation = this.getNodeParameter('operation', 0);
147
+ for (let i = 0; i < items.length; i++) {
148
+ try {
149
+ let action;
150
+ const body = {};
151
+ if (resource === 'custom') {
152
+ action = this.getNodeParameter('action', i);
153
+ const rawParams = this.getNodeParameter('parameters', i, {});
154
+ const parsed = typeof rawParams === 'string' ? JSON.parse(rawParams || '{}') : rawParams;
155
+ Object.assign(body, parsed);
156
+ }
157
+ else {
158
+ action = (_a = ACTION_MAP[resource]) === null || _a === void 0 ? void 0 : _a[operation];
159
+ if (!action) {
160
+ throw new n8n_workflow_1.NodeOperationError(this.getNode(), `Unsupported operation "${operation}" for resource "${resource}".`);
161
+ }
162
+ const SIMPLE_FIELDS = [
163
+ 'firstname', 'lastname', 'email', 'password2', 'clientid', 'userid',
164
+ 'orderid', 'paymentmethod', 'invoiceid', 'transid', 'amount',
165
+ 'serviceid', 'suspendreason', 'deptid', 'subject', 'message', 'ticketid',
166
+ 'domainid', 'regperiod', 'eppcode', 'idprotect', 'messagename',
167
+ ];
168
+ for (const field of SIMPLE_FIELDS) {
169
+ const value = this.getNodeParameter(field, i, undefined);
170
+ if (value !== undefined && value !== '' && value !== 0) {
171
+ body[field] = value;
172
+ }
173
+ else if (value === 0 && ['clientid', 'invoiceid', 'orderid', 'ticketid', 'domainid', 'serviceid', 'userid', 'deptid'].includes(field)) {
174
+ continue;
175
+ }
176
+ }
177
+ for (const coll of FLATTEN_COLLECTIONS) {
178
+ const value = this.getNodeParameter(coll, i, {});
179
+ if (value && typeof value === 'object') {
180
+ Object.assign(body, value);
181
+ }
182
+ }
183
+ const returnAll = this.getNodeParameter('returnAll', i, false);
184
+ if (operation === 'getAll') {
185
+ if (!returnAll) {
186
+ body.limitnum = this.getNodeParameter('limit', i, 25);
187
+ }
188
+ else {
189
+ body.limitnum = 1000;
190
+ }
191
+ }
192
+ const custom = this.getNodeParameter('customParameters', i, {});
193
+ Object.assign(body, (0, GenericFunctions_1.parseCustomParameters)(custom));
194
+ }
195
+ const response = await GenericFunctions_1.whmcsApiRequest.call(this, action, body);
196
+ returnData.push({
197
+ json: response,
198
+ pairedItem: { item: i },
199
+ });
200
+ }
201
+ catch (error) {
202
+ if (this.continueOnFail()) {
203
+ returnData.push({ json: { error: error.message }, pairedItem: { item: i } });
204
+ continue;
205
+ }
206
+ throw error;
207
+ }
208
+ }
209
+ return [returnData];
210
+ }
211
+ }
212
+ exports.Whmcs = Whmcs;
213
+ //# sourceMappingURL=Whmcs.node.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"Whmcs.node.js","sourceRoot":"","sources":["../../../nodes/Whmcs/Whmcs.node.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,12 @@
1
+ import type { IHookFunctions, INodeType, INodeTypeDescription, IWebhookFunctions, IWebhookResponseData } from 'n8n-workflow';
2
+ export declare class WhmcsTrigger implements INodeType {
3
+ description: INodeTypeDescription;
4
+ webhookMethods: {
5
+ default: {
6
+ checkExists(this: IHookFunctions): Promise<boolean>;
7
+ create(this: IHookFunctions): Promise<boolean>;
8
+ delete(this: IHookFunctions): Promise<boolean>;
9
+ };
10
+ };
11
+ webhook(this: IWebhookFunctions): Promise<IWebhookResponseData>;
12
+ }
@@ -0,0 +1,102 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.WhmcsTrigger = void 0;
4
+ class WhmcsTrigger {
5
+ constructor() {
6
+ this.description = {
7
+ displayName: 'WHMCS Trigger',
8
+ name: 'whmcsTrigger',
9
+ icon: 'file:whmcs.svg',
10
+ group: ['trigger'],
11
+ version: 1,
12
+ subtitle: '={{$parameter["events"].join(", ")}}',
13
+ description: 'Starts a workflow when WHMCS fires a hook event (via the PHP hook bridge)',
14
+ defaults: { name: 'WHMCS Trigger' },
15
+ inputs: [],
16
+ outputs: ['main'],
17
+ webhooks: [
18
+ {
19
+ name: 'default',
20
+ httpMethod: 'POST',
21
+ responseMode: 'onReceived',
22
+ path: 'whmcs',
23
+ },
24
+ ],
25
+ properties: [
26
+ {
27
+ displayName: 'Install the bundled <code>whmcs-hook-bridge.php</code> file into your WHMCS <code>/includes/hooks/</code> directory and set its <code>$n8nWebhookUrl</code> to the Production URL shown below.',
28
+ name: 'setupNotice',
29
+ type: 'notice',
30
+ default: '',
31
+ },
32
+ {
33
+ displayName: 'Events',
34
+ name: 'events',
35
+ type: 'multiOptions',
36
+ description: 'WHMCS hook point(s) that should trigger this workflow. Must match the events the PHP bridge is configured to forward.',
37
+ options: [
38
+ { name: 'After Module Create', value: 'AfterModuleCreate' },
39
+ { name: 'After Module Suspend', value: 'AfterModuleSuspend' },
40
+ { name: 'After Module Terminate', value: 'AfterModuleTerminate' },
41
+ { name: 'Any Event', value: '*' },
42
+ { name: 'Client Add', value: 'ClientAdd' },
43
+ { name: 'Client Close', value: 'ClientClose' },
44
+ { name: 'Invoice Created', value: 'InvoiceCreated' },
45
+ { name: 'Invoice Paid', value: 'InvoicePaid' },
46
+ { name: 'Order Accepted', value: 'AcceptOrder' },
47
+ { name: 'Order Pending', value: 'OrderPaid' },
48
+ { name: 'Ticket Open', value: 'TicketOpen' },
49
+ { name: 'Ticket Reply', value: 'TicketUserReply' },
50
+ ],
51
+ default: ['*'],
52
+ },
53
+ {
54
+ displayName: 'Shared Secret',
55
+ name: 'sharedSecret',
56
+ type: 'string',
57
+ typeOptions: { password: true },
58
+ default: '',
59
+ description: 'Optional. If set, the PHP bridge must send the same value in the X-WHMCS-Secret header. Requests with a missing or wrong secret are rejected with 401.',
60
+ },
61
+ ],
62
+ };
63
+ this.webhookMethods = {
64
+ default: {
65
+ async checkExists() {
66
+ return true;
67
+ },
68
+ async create() {
69
+ return true;
70
+ },
71
+ async delete() {
72
+ return true;
73
+ },
74
+ },
75
+ };
76
+ }
77
+ async webhook() {
78
+ var _a, _b, _c;
79
+ const req = this.getRequestObject();
80
+ const headers = this.getHeaderData();
81
+ const body = ((_a = req.body) !== null && _a !== void 0 ? _a : {});
82
+ const sharedSecret = this.getNodeParameter('sharedSecret', '');
83
+ if (sharedSecret) {
84
+ const provided = (_b = headers['x-whmcs-secret']) !== null && _b !== void 0 ? _b : '';
85
+ if (provided !== sharedSecret) {
86
+ const res = this.getResponseObject();
87
+ res.status(401).json({ message: 'Invalid WHMCS shared secret' });
88
+ return { noWebhookResponse: true };
89
+ }
90
+ }
91
+ const events = this.getNodeParameter('events', []);
92
+ const incomingEvent = (_c = body.event) !== null && _c !== void 0 ? _c : '';
93
+ if (!events.includes('*') && incomingEvent && !events.includes(incomingEvent)) {
94
+ return { webhookResponse: JSON.stringify({ received: true, ignored: incomingEvent }) };
95
+ }
96
+ return {
97
+ workflowData: [this.helpers.returnJsonArray([body])],
98
+ };
99
+ }
100
+ }
101
+ exports.WhmcsTrigger = WhmcsTrigger;
102
+ //# sourceMappingURL=WhmcsTrigger.node.js.map