@revobus/n8n-nodes-kajabi 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 (73) hide show
  1. package/LICENSE.md +21 -0
  2. package/README.md +161 -0
  3. package/dist/credentials/KajabiApi.credentials.d.ts +11 -0
  4. package/dist/credentials/KajabiApi.credentials.d.ts.map +1 -0
  5. package/dist/credentials/KajabiApi.credentials.js +50 -0
  6. package/dist/credentials/KajabiApi.credentials.js.map +1 -0
  7. package/dist/credentials/KajabiOAuth2Api.credentials.d.ts +12 -0
  8. package/dist/credentials/KajabiOAuth2Api.credentials.d.ts.map +1 -0
  9. package/dist/credentials/KajabiOAuth2Api.credentials.js +88 -0
  10. package/dist/credentials/KajabiOAuth2Api.credentials.js.map +1 -0
  11. package/dist/nodes/Kajabi/GenericFunctions.d.ts +30 -0
  12. package/dist/nodes/Kajabi/GenericFunctions.d.ts.map +1 -0
  13. package/dist/nodes/Kajabi/GenericFunctions.js +161 -0
  14. package/dist/nodes/Kajabi/GenericFunctions.js.map +1 -0
  15. package/dist/nodes/Kajabi/Kajabi.node.d.ts +5 -0
  16. package/dist/nodes/Kajabi/Kajabi.node.d.ts.map +1 -0
  17. package/dist/nodes/Kajabi/Kajabi.node.js +176 -0
  18. package/dist/nodes/Kajabi/Kajabi.node.js.map +1 -0
  19. package/dist/nodes/Kajabi/descriptions/BlogPostDescription.d.ts +4 -0
  20. package/dist/nodes/Kajabi/descriptions/BlogPostDescription.d.ts.map +1 -0
  21. package/dist/nodes/Kajabi/descriptions/BlogPostDescription.js +205 -0
  22. package/dist/nodes/Kajabi/descriptions/BlogPostDescription.js.map +1 -0
  23. package/dist/nodes/Kajabi/descriptions/ContactDescription.d.ts +4 -0
  24. package/dist/nodes/Kajabi/descriptions/ContactDescription.d.ts.map +1 -0
  25. package/dist/nodes/Kajabi/descriptions/ContactDescription.js +759 -0
  26. package/dist/nodes/Kajabi/descriptions/ContactDescription.js.map +1 -0
  27. package/dist/nodes/Kajabi/descriptions/ContactNoteDescription.d.ts +4 -0
  28. package/dist/nodes/Kajabi/descriptions/ContactNoteDescription.d.ts.map +1 -0
  29. package/dist/nodes/Kajabi/descriptions/ContactNoteDescription.js +127 -0
  30. package/dist/nodes/Kajabi/descriptions/ContactNoteDescription.js.map +1 -0
  31. package/dist/nodes/Kajabi/descriptions/ContactTagDescription.d.ts +4 -0
  32. package/dist/nodes/Kajabi/descriptions/ContactTagDescription.d.ts.map +1 -0
  33. package/dist/nodes/Kajabi/descriptions/ContactTagDescription.js +114 -0
  34. package/dist/nodes/Kajabi/descriptions/ContactTagDescription.js.map +1 -0
  35. package/dist/nodes/Kajabi/descriptions/CourseDescription.d.ts +4 -0
  36. package/dist/nodes/Kajabi/descriptions/CourseDescription.d.ts.map +1 -0
  37. package/dist/nodes/Kajabi/descriptions/CourseDescription.js +197 -0
  38. package/dist/nodes/Kajabi/descriptions/CourseDescription.js.map +1 -0
  39. package/dist/nodes/Kajabi/descriptions/CustomerDescription.d.ts +4 -0
  40. package/dist/nodes/Kajabi/descriptions/CustomerDescription.d.ts.map +1 -0
  41. package/dist/nodes/Kajabi/descriptions/CustomerDescription.js +358 -0
  42. package/dist/nodes/Kajabi/descriptions/CustomerDescription.js.map +1 -0
  43. package/dist/nodes/Kajabi/descriptions/FormDescription.d.ts +4 -0
  44. package/dist/nodes/Kajabi/descriptions/FormDescription.d.ts.map +1 -0
  45. package/dist/nodes/Kajabi/descriptions/FormDescription.js +381 -0
  46. package/dist/nodes/Kajabi/descriptions/FormDescription.js.map +1 -0
  47. package/dist/nodes/Kajabi/descriptions/FormSubmissionDescription.d.ts +4 -0
  48. package/dist/nodes/Kajabi/descriptions/FormSubmissionDescription.d.ts.map +1 -0
  49. package/dist/nodes/Kajabi/descriptions/FormSubmissionDescription.js +166 -0
  50. package/dist/nodes/Kajabi/descriptions/FormSubmissionDescription.js.map +1 -0
  51. package/dist/nodes/Kajabi/descriptions/LandingPageDescription.d.ts +4 -0
  52. package/dist/nodes/Kajabi/descriptions/LandingPageDescription.d.ts.map +1 -0
  53. package/dist/nodes/Kajabi/descriptions/LandingPageDescription.js +210 -0
  54. package/dist/nodes/Kajabi/descriptions/LandingPageDescription.js.map +1 -0
  55. package/dist/nodes/Kajabi/descriptions/OfferDescription.d.ts +4 -0
  56. package/dist/nodes/Kajabi/descriptions/OfferDescription.d.ts.map +1 -0
  57. package/dist/nodes/Kajabi/descriptions/OfferDescription.js +201 -0
  58. package/dist/nodes/Kajabi/descriptions/OfferDescription.js.map +1 -0
  59. package/dist/nodes/Kajabi/descriptions/PayoutDescription.d.ts +4 -0
  60. package/dist/nodes/Kajabi/descriptions/PayoutDescription.d.ts.map +1 -0
  61. package/dist/nodes/Kajabi/descriptions/PayoutDescription.js +200 -0
  62. package/dist/nodes/Kajabi/descriptions/PayoutDescription.js.map +1 -0
  63. package/dist/nodes/Kajabi/descriptions/UserDescription.d.ts +4 -0
  64. package/dist/nodes/Kajabi/descriptions/UserDescription.d.ts.map +1 -0
  65. package/dist/nodes/Kajabi/descriptions/UserDescription.js +46 -0
  66. package/dist/nodes/Kajabi/descriptions/UserDescription.js.map +1 -0
  67. package/dist/nodes/Kajabi/kajabi.svg +5 -0
  68. package/dist/nodes/KajabiTrigger/KajabiTrigger.node.d.ts +13 -0
  69. package/dist/nodes/KajabiTrigger/KajabiTrigger.node.d.ts.map +1 -0
  70. package/dist/nodes/KajabiTrigger/KajabiTrigger.node.js +152 -0
  71. package/dist/nodes/KajabiTrigger/KajabiTrigger.node.js.map +1 -0
  72. package/dist/nodes/KajabiTrigger/kajabi.svg +5 -0
  73. package/package.json +67 -0
package/LICENSE.md ADDED
@@ -0,0 +1,21 @@
1
+ MIT License
2
+
3
+ Copyright (c) 2024
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,161 @@
1
+ # @revobus/n8n-nodes-kajabi
2
+
3
+ This is an n8n community node package for [Kajabi](https://kajabi.com) - the all-in-one platform for online courses, memberships, and digital products.
4
+
5
+ [n8n](https://n8n.io/) is a [fair-code licensed](https://docs.n8n.io/reference/license/) workflow automation platform.
6
+
7
+ [Installation](#installation)
8
+ [Operations](#operations)
9
+ [Credentials](#credentials)
10
+ [Compatibility](#compatibility)
11
+ [Resources](#resources)
12
+
13
+ ## Installation
14
+
15
+ Follow the [installation guide](https://docs.n8n.io/integrations/community-nodes/installation/) in the n8n community nodes documentation.
16
+
17
+ In n8n, go to **Settings → Community Nodes → Install** and enter:
18
+
19
+ ```
20
+ @revobus/n8n-nodes-kajabi
21
+ ```
22
+
23
+ Or via npm:
24
+
25
+ ```bash
26
+ npm install @revobus/n8n-nodes-kajabi
27
+ ```
28
+
29
+ ## Operations
30
+
31
+ ### Kajabi Node
32
+
33
+ The main Kajabi node supports the following resources and operations:
34
+
35
+ #### Contact
36
+ - **Create** - Create a new contact
37
+ - **Get** - Get a contact by ID
38
+ - **Get Many** - Get all contacts with filters
39
+ - **Update** - Update a contact
40
+ - **Delete** - Delete a contact
41
+ - **Add Tags** - Add tags to a contact
42
+ - **Remove Tags** - Remove tags from a contact
43
+ - **Grant Offers** - Grant offers to a contact
44
+ - **List Offers** - List all offers for a contact
45
+ - **Revoke Offers** - Revoke offers from a contact
46
+
47
+ #### Customer
48
+ - **Get** - Get a customer by ID
49
+ - **Get Many** - Get all customers with filters
50
+ - **Grant Offers** - Grant offers to a customer
51
+ - **List Offers** - List all offers for a customer
52
+ - **Replace Offers** - Replace all offers for a customer
53
+ - **Revoke Offers** - Revoke offers from a customer
54
+
55
+ #### Offer
56
+ - **Get** - Get an offer by ID
57
+ - **Get Many** - Get all offers
58
+ - **List Products** - List all products included in an offer
59
+
60
+ #### Course
61
+ - **Get** - Get a course by ID
62
+ - **Get Many** - Get all courses
63
+
64
+ #### Form
65
+ - **Get** - Get a form by ID
66
+ - **Get Many** - Get all forms
67
+ - **Submit** - Submit a form programmatically
68
+
69
+ #### Form Submission
70
+ - **Get** - Get a form submission by ID
71
+ - **Get Many** - Get all form submissions
72
+
73
+ #### Blog Post
74
+ - **Get** - Get a blog post by ID
75
+ - **Get Many** - Get all blog posts
76
+
77
+ #### Landing Page
78
+ - **Get** - Get a landing page by ID
79
+ - **Get Many** - Get all landing pages
80
+
81
+ #### Payout
82
+ - **Get** - Get a payout by ID
83
+ - **Get Many** - Get all payouts
84
+
85
+ #### Contact Tag
86
+ - **Get Many** - Get all contact tags
87
+
88
+ #### Contact Note
89
+ - **Get Many** - Get all contact notes
90
+
91
+ #### User
92
+ - **Get Current** - Get the current authenticated user
93
+
94
+ ### Kajabi Trigger Node
95
+
96
+ The trigger node listens for webhooks from Kajabi:
97
+
98
+ - **Form Submission** - Triggered when a Kajabi form is submitted
99
+ - **Any Webhook** - Receives any webhook payload from Kajabi
100
+
101
+ ## Credentials
102
+
103
+ ### OAuth2 (Recommended)
104
+
105
+ 1. Go to your Kajabi Dashboard
106
+ 2. Navigate to **Settings > Integrations > Public API**
107
+ 3. Create a new API application
108
+ 4. Copy the **Client ID** and **Client Secret**
109
+ 5. In n8n, create new Kajabi OAuth2 credentials
110
+ 6. Enter your Client ID and Client Secret
111
+ 7. Optionally enter your Site ID (required for multi-site accounts)
112
+
113
+ ### API Key
114
+
115
+ 1. Go to your Kajabi Dashboard
116
+ 2. Navigate to **Settings > Integrations > Public API**
117
+ 3. Create a new **User API Key**
118
+ 4. Copy the generated API key
119
+ 5. In n8n, create new Kajabi API credentials
120
+ 6. Enter your API key
121
+ 7. Optionally enter your Site ID (required for multi-site accounts)
122
+
123
+ ## Compatibility
124
+
125
+ - Tested with n8n version 1.0.0 and later
126
+ - Requires Kajabi API V1 access
127
+
128
+ ## Usage Notes
129
+
130
+ ### Multi-Site Accounts
131
+
132
+ If you have multiple sites in your Kajabi account, you must specify the `Site ID` in your credentials or use the `filter[site_id]` parameter in your queries.
133
+
134
+ ### Pagination
135
+
136
+ All "Get Many" operations support pagination:
137
+ - Use "Return All" to fetch all results automatically
138
+ - Use "Limit" to set the maximum number of results per page (1-100)
139
+
140
+ ### JSON:API Format
141
+
142
+ Kajabi API uses JSON:API format. The node automatically:
143
+ - Extracts the `data` property from responses
144
+ - Formats request bodies in JSON:API format for create/update operations
145
+
146
+ ### Rate Limits
147
+
148
+ If you receive `429 Too Many Requests` errors:
149
+ - Implement delays between requests
150
+ - Use the built-in "Return All" with smaller page sizes
151
+ - Cache frequently accessed data
152
+
153
+ ## Resources
154
+
155
+ * [n8n community nodes documentation](https://docs.n8n.io/integrations/community-nodes/)
156
+ * [Kajabi API Documentation](https://developers.kajabi.com/docs)
157
+ * [Kajabi Help Center](https://help.kajabi.com/)
158
+
159
+ ## License
160
+
161
+ [MIT](LICENSE.md)
@@ -0,0 +1,11 @@
1
+ import type { IAuthenticateGeneric, ICredentialTestRequest, ICredentialType, INodeProperties } from 'n8n-workflow';
2
+ export declare class KajabiApi implements ICredentialType {
3
+ name: string;
4
+ displayName: string;
5
+ documentationUrl: string;
6
+ icon: "file:../nodes/Kajabi/kajabi.svg";
7
+ properties: INodeProperties[];
8
+ authenticate: IAuthenticateGeneric;
9
+ test: ICredentialTestRequest;
10
+ }
11
+ //# sourceMappingURL=KajabiApi.credentials.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"KajabiApi.credentials.d.ts","sourceRoot":"","sources":["../../credentials/KajabiApi.credentials.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EACX,oBAAoB,EACpB,sBAAsB,EACtB,eAAe,EACf,eAAe,EACf,MAAM,cAAc,CAAC;AAEtB,qBAAa,SAAU,YAAW,eAAe;IAChD,IAAI,SAAe;IACnB,WAAW,SAAgB;IAC3B,gBAAgB,SAAgD;IAChE,IAAI,EAAG,iCAAiC,CAAU;IAElD,UAAU,EAAE,eAAe,EAAE,CAmB3B;IAEF,YAAY,EAAE,oBAAoB,CAShC;IAEF,IAAI,EAAE,sBAAsB,CAQ1B;CACF"}
@@ -0,0 +1,50 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.KajabiApi = void 0;
4
+ class KajabiApi {
5
+ name = 'kajabiApi';
6
+ displayName = 'Kajabi API';
7
+ documentationUrl = 'httpsDevelopersKajabiComDocsAuthentication';
8
+ icon = 'file:../nodes/Kajabi/kajabi.svg';
9
+ properties = [
10
+ {
11
+ displayName: 'API Key',
12
+ name: 'apiKey',
13
+ type: 'string',
14
+ typeOptions: {
15
+ password: true,
16
+ },
17
+ default: '',
18
+ required: true,
19
+ description: 'Your Kajabi User API Key. Create one in Kajabi Dashboard under Settings > Public API.',
20
+ },
21
+ {
22
+ displayName: 'Site ID',
23
+ name: 'siteId',
24
+ type: 'string',
25
+ default: '',
26
+ description: 'Your Kajabi Site ID. Required for multi-site accounts.',
27
+ },
28
+ ];
29
+ authenticate = {
30
+ type: 'generic',
31
+ properties: {
32
+ headers: {
33
+ Authorization: '=Bearer {{$credentials.apiKey}}',
34
+ Accept: 'application/vnd.api+json',
35
+ 'Content-Type': 'application/vnd.api+json',
36
+ },
37
+ },
38
+ };
39
+ test = {
40
+ request: {
41
+ baseURL: 'https://api.kajabi.com',
42
+ url: '/v1/me',
43
+ headers: {
44
+ Accept: 'application/vnd.api+json',
45
+ },
46
+ },
47
+ };
48
+ }
49
+ exports.KajabiApi = KajabiApi;
50
+ //# sourceMappingURL=KajabiApi.credentials.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"KajabiApi.credentials.js","sourceRoot":"","sources":["../../credentials/KajabiApi.credentials.ts"],"names":[],"mappings":";;;AAOA,MAAa,SAAS;IACrB,IAAI,GAAG,WAAW,CAAC;IACnB,WAAW,GAAG,YAAY,CAAC;IAC3B,gBAAgB,GAAG,4CAA4C,CAAC;IAChE,IAAI,GAAG,iCAA0C,CAAC;IAElD,UAAU,GAAsB;QAC/B;YACC,WAAW,EAAE,SAAS;YACtB,IAAI,EAAE,QAAQ;YACd,IAAI,EAAE,QAAQ;YACd,WAAW,EAAE;gBACZ,QAAQ,EAAE,IAAI;aACd;YACD,OAAO,EAAE,EAAE;YACX,QAAQ,EAAE,IAAI;YACd,WAAW,EAAE,uFAAuF;SACpG;QACD;YACC,WAAW,EAAE,SAAS;YACtB,IAAI,EAAE,QAAQ;YACd,IAAI,EAAE,QAAQ;YACd,OAAO,EAAE,EAAE;YACX,WAAW,EAAE,wDAAwD;SACrE;KACD,CAAC;IAEF,YAAY,GAAyB;QACpC,IAAI,EAAE,SAAS;QACf,UAAU,EAAE;YACX,OAAO,EAAE;gBACR,aAAa,EAAE,iCAAiC;gBAChD,MAAM,EAAE,0BAA0B;gBAClC,cAAc,EAAE,0BAA0B;aAC1C;SACD;KACD,CAAC;IAEF,IAAI,GAA2B;QAC9B,OAAO,EAAE;YACR,OAAO,EAAE,wBAAwB;YACjC,GAAG,EAAE,QAAQ;YACb,OAAO,EAAE;gBACR,MAAM,EAAE,0BAA0B;aAClC;SACD;KACD,CAAC;CACF;AA/CD,8BA+CC"}
@@ -0,0 +1,12 @@
1
+ import type { IAuthenticateGeneric, ICredentialTestRequest, ICredentialType, INodeProperties } from 'n8n-workflow';
2
+ export declare class KajabiOAuth2Api implements ICredentialType {
3
+ name: string;
4
+ displayName: string;
5
+ documentationUrl: string;
6
+ extends: string[];
7
+ icon: "file:../nodes/Kajabi/kajabi.svg";
8
+ properties: INodeProperties[];
9
+ authenticate: IAuthenticateGeneric;
10
+ test: ICredentialTestRequest;
11
+ }
12
+ //# sourceMappingURL=KajabiOAuth2Api.credentials.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"KajabiOAuth2Api.credentials.d.ts","sourceRoot":"","sources":["../../credentials/KajabiOAuth2Api.credentials.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EACX,oBAAoB,EACpB,sBAAsB,EACtB,eAAe,EACf,eAAe,EACf,MAAM,cAAc,CAAC;AAEtB,qBAAa,eAAgB,YAAW,eAAe;IACtD,IAAI,SAAqB;IACzB,WAAW,SAAuB;IAClC,gBAAgB,SAAgD;IAChE,OAAO,WAAiB;IACxB,IAAI,EAAG,iCAAiC,CAAU;IAElD,UAAU,EAAE,eAAe,EAAE,CAyD3B;IAEF,YAAY,EAAE,oBAAoB,CAQhC;IAEF,IAAI,EAAE,sBAAsB,CAQ1B;CACF"}
@@ -0,0 +1,88 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.KajabiOAuth2Api = void 0;
4
+ class KajabiOAuth2Api {
5
+ name = 'kajabiOAuth2Api';
6
+ displayName = 'Kajabi OAuth2 API';
7
+ documentationUrl = 'httpsDevelopersKajabiComDocsAuthentication';
8
+ extends = ['oAuth2Api'];
9
+ icon = 'file:../nodes/Kajabi/kajabi.svg';
10
+ properties = [
11
+ {
12
+ displayName: 'Grant Type',
13
+ name: 'grantType',
14
+ type: 'hidden',
15
+ default: 'clientCredentials',
16
+ },
17
+ {
18
+ displayName: 'Access Token URL',
19
+ name: 'accessTokenUrl',
20
+ type: 'hidden',
21
+ default: 'https://api.kajabi.com/v1/oauth/token',
22
+ },
23
+ {
24
+ displayName: 'Client ID',
25
+ name: 'clientId',
26
+ type: 'string',
27
+ default: '',
28
+ required: true,
29
+ description: 'The Client ID from your Kajabi API application',
30
+ },
31
+ {
32
+ displayName: 'Client Secret',
33
+ name: 'clientSecret',
34
+ type: 'string',
35
+ typeOptions: {
36
+ password: true,
37
+ },
38
+ default: '',
39
+ required: true,
40
+ description: 'The Client Secret from your Kajabi API application',
41
+ },
42
+ {
43
+ displayName: 'Scope',
44
+ name: 'scope',
45
+ type: 'hidden',
46
+ default: '',
47
+ },
48
+ {
49
+ displayName: 'Auth URI Query Parameters',
50
+ name: 'authQueryParameters',
51
+ type: 'hidden',
52
+ default: '',
53
+ },
54
+ {
55
+ displayName: 'Authentication',
56
+ name: 'authentication',
57
+ type: 'hidden',
58
+ default: 'body',
59
+ },
60
+ {
61
+ displayName: 'Site ID',
62
+ name: 'siteId',
63
+ type: 'string',
64
+ default: '',
65
+ description: 'Your Kajabi Site ID. Required for multi-site accounts. Find it in Kajabi Dashboard under Settings.',
66
+ },
67
+ ];
68
+ authenticate = {
69
+ type: 'generic',
70
+ properties: {
71
+ headers: {
72
+ Accept: 'application/vnd.api+json',
73
+ 'Content-Type': 'application/vnd.api+json',
74
+ },
75
+ },
76
+ };
77
+ test = {
78
+ request: {
79
+ baseURL: 'https://api.kajabi.com',
80
+ url: '/v1/me',
81
+ headers: {
82
+ Accept: 'application/vnd.api+json',
83
+ },
84
+ },
85
+ };
86
+ }
87
+ exports.KajabiOAuth2Api = KajabiOAuth2Api;
88
+ //# sourceMappingURL=KajabiOAuth2Api.credentials.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"KajabiOAuth2Api.credentials.js","sourceRoot":"","sources":["../../credentials/KajabiOAuth2Api.credentials.ts"],"names":[],"mappings":";;;AAOA,MAAa,eAAe;IAC3B,IAAI,GAAG,iBAAiB,CAAC;IACzB,WAAW,GAAG,mBAAmB,CAAC;IAClC,gBAAgB,GAAG,4CAA4C,CAAC;IAChE,OAAO,GAAG,CAAC,WAAW,CAAC,CAAC;IACxB,IAAI,GAAG,iCAA0C,CAAC;IAElD,UAAU,GAAsB;QAC/B;YACC,WAAW,EAAE,YAAY;YACzB,IAAI,EAAE,WAAW;YACjB,IAAI,EAAE,QAAQ;YACd,OAAO,EAAE,mBAAmB;SAC5B;QACD;YACC,WAAW,EAAE,kBAAkB;YAC/B,IAAI,EAAE,gBAAgB;YACtB,IAAI,EAAE,QAAQ;YACd,OAAO,EAAE,uCAAuC;SAChD;QACD;YACC,WAAW,EAAE,WAAW;YACxB,IAAI,EAAE,UAAU;YAChB,IAAI,EAAE,QAAQ;YACd,OAAO,EAAE,EAAE;YACX,QAAQ,EAAE,IAAI;YACd,WAAW,EAAE,gDAAgD;SAC7D;QACD;YACC,WAAW,EAAE,eAAe;YAC5B,IAAI,EAAE,cAAc;YACpB,IAAI,EAAE,QAAQ;YACd,WAAW,EAAE;gBACZ,QAAQ,EAAE,IAAI;aACd;YACD,OAAO,EAAE,EAAE;YACX,QAAQ,EAAE,IAAI;YACd,WAAW,EAAE,oDAAoD;SACjE;QACD;YACC,WAAW,EAAE,OAAO;YACpB,IAAI,EAAE,OAAO;YACb,IAAI,EAAE,QAAQ;YACd,OAAO,EAAE,EAAE;SACX;QACD;YACC,WAAW,EAAE,2BAA2B;YACxC,IAAI,EAAE,qBAAqB;YAC3B,IAAI,EAAE,QAAQ;YACd,OAAO,EAAE,EAAE;SACX;QACD;YACC,WAAW,EAAE,gBAAgB;YAC7B,IAAI,EAAE,gBAAgB;YACtB,IAAI,EAAE,QAAQ;YACd,OAAO,EAAE,MAAM;SACf;QACD;YACC,WAAW,EAAE,SAAS;YACtB,IAAI,EAAE,QAAQ;YACd,IAAI,EAAE,QAAQ;YACd,OAAO,EAAE,EAAE;YACX,WAAW,EAAE,oGAAoG;SACjH;KACD,CAAC;IAEF,YAAY,GAAyB;QACpC,IAAI,EAAE,SAAS;QACf,UAAU,EAAE;YACX,OAAO,EAAE;gBACR,MAAM,EAAE,0BAA0B;gBAClC,cAAc,EAAE,0BAA0B;aAC1C;SACD;KACD,CAAC;IAEF,IAAI,GAA2B;QAC9B,OAAO,EAAE;YACR,OAAO,EAAE,wBAAwB;YACjC,GAAG,EAAE,QAAQ;YACb,OAAO,EAAE;gBACR,MAAM,EAAE,0BAA0B;aAClC;SACD;KACD,CAAC;CACF;AArFD,0CAqFC"}
@@ -0,0 +1,30 @@
1
+ import type { IDataObject, IExecuteFunctions, IHookFunctions, IHttpRequestMethods, ILoadOptionsFunctions } from 'n8n-workflow';
2
+ /**
3
+ * Make an authenticated request to the Kajabi API
4
+ */
5
+ export declare function kajabiApiRequest(this: IExecuteFunctions | ILoadOptionsFunctions | IHookFunctions, method: IHttpRequestMethods, endpoint: string, body?: IDataObject, qs?: IDataObject, uri?: string): Promise<IDataObject>;
6
+ /**
7
+ * Make an authenticated request and return all items (handles pagination)
8
+ */
9
+ export declare function kajabiApiRequestAllItems(this: IExecuteFunctions | ILoadOptionsFunctions, method: IHttpRequestMethods, endpoint: string, body?: IDataObject, qs?: IDataObject): Promise<IDataObject[]>;
10
+ /**
11
+ * Format tag IDs for JSON:API relationship format
12
+ */
13
+ export declare function formatTagsForJsonApi(tagIds: string): IDataObject[];
14
+ /**
15
+ * Format offer IDs for JSON:API relationship format
16
+ */
17
+ export declare function formatOffersForJsonApi(offerIds: string): IDataObject[];
18
+ /**
19
+ * Transform JSON:API response to flat structure
20
+ */
21
+ export declare function flattenJsonApiResponse(item: IDataObject): IDataObject;
22
+ /**
23
+ * Build JSON:API request body for creating/updating resources
24
+ */
25
+ export declare function buildJsonApiBody(resourceType: string, attributes: IDataObject, relationships?: IDataObject, id?: string): IDataObject;
26
+ /**
27
+ * Handle Kajabi error responses
28
+ */
29
+ export declare function handleKajabiError(error: IDataObject): string;
30
+ //# sourceMappingURL=GenericFunctions.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"GenericFunctions.d.ts","sourceRoot":"","sources":["../../../nodes/Kajabi/GenericFunctions.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EACX,WAAW,EACX,iBAAiB,EACjB,cAAc,EACd,mBAAmB,EACnB,qBAAqB,EAGrB,MAAM,cAAc,CAAC;AAGtB;;GAEG;AACH,wBAAsB,gBAAgB,CACrC,IAAI,EAAE,iBAAiB,GAAG,qBAAqB,GAAG,cAAc,EAChE,MAAM,EAAE,mBAAmB,EAC3B,QAAQ,EAAE,MAAM,EAChB,IAAI,GAAE,WAAgB,EACtB,EAAE,GAAE,WAAgB,EACpB,GAAG,CAAC,EAAE,MAAM,GACV,OAAO,CAAC,WAAW,CAAC,CA2BtB;AAED;;GAEG;AACH,wBAAsB,wBAAwB,CAC7C,IAAI,EAAE,iBAAiB,GAAG,qBAAqB,EAC/C,MAAM,EAAE,mBAAmB,EAC3B,QAAQ,EAAE,MAAM,EAChB,IAAI,GAAE,WAAgB,EACtB,EAAE,GAAE,WAAgB,GAClB,OAAO,CAAC,WAAW,EAAE,CAAC,CAqCxB;AAED;;GAEG;AACH,wBAAgB,oBAAoB,CAAC,MAAM,EAAE,MAAM,GAAG,WAAW,EAAE,CAQlE;AAED;;GAEG;AACH,wBAAgB,sBAAsB,CAAC,QAAQ,EAAE,MAAM,GAAG,WAAW,EAAE,CAQtE;AAED;;GAEG;AACH,wBAAgB,sBAAsB,CAAC,IAAI,EAAE,WAAW,GAAG,WAAW,CA2BrE;AAED;;GAEG;AACH,wBAAgB,gBAAgB,CAC/B,YAAY,EAAE,MAAM,EACpB,UAAU,EAAE,WAAW,EACvB,aAAa,CAAC,EAAE,WAAW,EAC3B,EAAE,CAAC,EAAE,MAAM,GACT,WAAW,CAeb;AAED;;GAEG;AACH,wBAAgB,iBAAiB,CAAC,KAAK,EAAE,WAAW,GAAG,MAAM,CAa5D"}
@@ -0,0 +1,161 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.kajabiApiRequest = kajabiApiRequest;
4
+ exports.kajabiApiRequestAllItems = kajabiApiRequestAllItems;
5
+ exports.formatTagsForJsonApi = formatTagsForJsonApi;
6
+ exports.formatOffersForJsonApi = formatOffersForJsonApi;
7
+ exports.flattenJsonApiResponse = flattenJsonApiResponse;
8
+ exports.buildJsonApiBody = buildJsonApiBody;
9
+ exports.handleKajabiError = handleKajabiError;
10
+ const n8n_workflow_1 = require("n8n-workflow");
11
+ /**
12
+ * Make an authenticated request to the Kajabi API
13
+ */
14
+ async function kajabiApiRequest(method, endpoint, body = {}, qs = {}, uri) {
15
+ const authenticationMethod = this.getNodeParameter('authentication', 0, 'oAuth2');
16
+ const options = {
17
+ method,
18
+ qs,
19
+ uri: uri || `https://api.kajabi.com${endpoint}`,
20
+ json: true,
21
+ headers: {
22
+ Accept: 'application/vnd.api+json',
23
+ 'Content-Type': 'application/vnd.api+json',
24
+ },
25
+ };
26
+ if (Object.keys(body).length > 0) {
27
+ options.body = body;
28
+ }
29
+ try {
30
+ if (authenticationMethod === 'oAuth2') {
31
+ return await this.helpers.requestOAuth2.call(this, 'kajabiOAuth2Api', options);
32
+ }
33
+ else {
34
+ return await this.helpers.requestWithAuthentication.call(this, 'kajabiApi', options);
35
+ }
36
+ }
37
+ catch (error) {
38
+ throw new n8n_workflow_1.NodeApiError(this.getNode(), error);
39
+ }
40
+ }
41
+ /**
42
+ * Make an authenticated request and return all items (handles pagination)
43
+ */
44
+ async function kajabiApiRequestAllItems(method, endpoint, body = {}, qs = {}) {
45
+ const returnData = [];
46
+ let page = 1;
47
+ let hasMorePages = true;
48
+ qs['page[size]'] = 100;
49
+ while (hasMorePages) {
50
+ qs['page[number]'] = page;
51
+ const response = await kajabiApiRequest.call(this, method, endpoint, body, qs);
52
+ if (response.data && Array.isArray(response.data)) {
53
+ returnData.push(...response.data);
54
+ }
55
+ // Check if there are more pages
56
+ const meta = response.meta;
57
+ const links = response.links;
58
+ if (meta && typeof meta.total_pages === 'number') {
59
+ hasMorePages = page < meta.total_pages;
60
+ }
61
+ else if (links && links.next === null) {
62
+ hasMorePages = false;
63
+ }
64
+ else if (!links?.next) {
65
+ hasMorePages = false;
66
+ }
67
+ page++;
68
+ // Safety limit to prevent infinite loops
69
+ if (page > 1000) {
70
+ hasMorePages = false;
71
+ }
72
+ }
73
+ return returnData;
74
+ }
75
+ /**
76
+ * Format tag IDs for JSON:API relationship format
77
+ */
78
+ function formatTagsForJsonApi(tagIds) {
79
+ if (!tagIds || tagIds.trim() === '') {
80
+ return [];
81
+ }
82
+ return tagIds.split(',').map((id) => ({
83
+ id: id.trim(),
84
+ type: 'contact_tags',
85
+ }));
86
+ }
87
+ /**
88
+ * Format offer IDs for JSON:API relationship format
89
+ */
90
+ function formatOffersForJsonApi(offerIds) {
91
+ if (!offerIds || offerIds.trim() === '') {
92
+ return [];
93
+ }
94
+ return offerIds.split(',').map((id) => ({
95
+ id: id.trim(),
96
+ type: 'offers',
97
+ }));
98
+ }
99
+ /**
100
+ * Transform JSON:API response to flat structure
101
+ */
102
+ function flattenJsonApiResponse(item) {
103
+ const result = {
104
+ id: item.id,
105
+ type: item.type,
106
+ };
107
+ // Flatten attributes
108
+ if (item.attributes && typeof item.attributes === 'object') {
109
+ Object.assign(result, item.attributes);
110
+ }
111
+ // Include relationship IDs
112
+ if (item.relationships && typeof item.relationships === 'object') {
113
+ const relationships = item.relationships;
114
+ for (const [key, value] of Object.entries(relationships)) {
115
+ const rel = value;
116
+ if (rel.data) {
117
+ if (Array.isArray(rel.data)) {
118
+ result[`${key}_ids`] = rel.data.map((d) => d.id);
119
+ }
120
+ else if (typeof rel.data === 'object') {
121
+ result[`${key}_id`] = rel.data.id;
122
+ }
123
+ }
124
+ }
125
+ }
126
+ return result;
127
+ }
128
+ /**
129
+ * Build JSON:API request body for creating/updating resources
130
+ */
131
+ function buildJsonApiBody(resourceType, attributes, relationships, id) {
132
+ const data = {
133
+ type: resourceType,
134
+ attributes,
135
+ };
136
+ if (id) {
137
+ data.id = id;
138
+ }
139
+ if (relationships && Object.keys(relationships).length > 0) {
140
+ data.relationships = relationships;
141
+ }
142
+ return { data };
143
+ }
144
+ /**
145
+ * Handle Kajabi error responses
146
+ */
147
+ function handleKajabiError(error) {
148
+ if (error.errors && Array.isArray(error.errors)) {
149
+ const errors = error.errors;
150
+ return errors
151
+ .map((e) => {
152
+ const status = e.status || 'Unknown';
153
+ const title = e.title || 'Error';
154
+ const detail = e.detail || 'An error occurred';
155
+ return `[${status}] ${title}: ${detail}`;
156
+ })
157
+ .join('; ');
158
+ }
159
+ return 'An unknown error occurred';
160
+ }
161
+ //# sourceMappingURL=GenericFunctions.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"GenericFunctions.js","sourceRoot":"","sources":["../../../nodes/Kajabi/GenericFunctions.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,5 @@
1
+ import type { INodeType, INodeTypeDescription } from 'n8n-workflow';
2
+ export declare class Kajabi implements INodeType {
3
+ description: INodeTypeDescription;
4
+ }
5
+ //# sourceMappingURL=Kajabi.node.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"Kajabi.node.d.ts","sourceRoot":"","sources":["../../../nodes/Kajabi/Kajabi.node.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,SAAS,EAAE,oBAAoB,EAAE,MAAM,cAAc,CAAC;AAepE,qBAAa,MAAO,YAAW,SAAS;IACvC,WAAW,EAAE,oBAAoB,CA4J/B;CACF"}