n8n-nodes-linq 0.1.16 → 0.2.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.
package/LICENSE.md CHANGED
@@ -1,21 +1,21 @@
1
- MIT License
2
-
3
- Copyright (c) 2025 Alex
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
1
+ MIT License
2
+
3
+ Copyright (c) 2025 Alex
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
21
  SOFTWARE.
package/README.md CHANGED
@@ -1,193 +1,194 @@
1
- # n8n-nodes-linq
2
-
3
- Linq Partner API (v2) community node for n8n. This node lets you manage chats, messages, phone numbers, webhooks, and contacts in Linq from your n8n workflows.
4
-
5
- - Package: `n8n-nodes-linq`
6
- - Node icon: included (SVG)
7
- - API version: v2
8
- - Auth: Integration Token (`X-LINQ-INTEGRATION-TOKEN`)
9
-
10
- ## Installation (in n8n)
11
-
12
- - Using the n8n UI:
13
- 1) Settings → Community Nodes → Install
14
- 2) Enter: `n8n-nodes-linq`
15
- 3) Restart n8n if prompted
16
-
17
- - Headless / environment variable:
18
- - Add `n8n-nodes-linq` to `N8N_COMMUNITY_PACKAGES` (or install with npm in your instance) and restart n8n.
19
-
20
- ## Credentials
21
-
22
- Create a new credential of type "Linq API" and set your Integration Token:
23
-
24
- - Header used: `X-LINQ-INTEGRATION-TOKEN: <your token>`
25
- - The field is hidden in the UI (password type).
26
-
27
- Where it's defined:
28
- - [class LinqApi implements ICredentialType](credentials/LinqApi.credentials.ts:1)
29
-
30
- ## Node usage
31
-
32
- Add the "Linq" node to your workflow. The node provides Resources and Operations that map 1:1 to the documented Linq Partner API endpoints.
33
-
34
- - Node implementation:
35
- - [class Linq implements INodeType](nodes/Linq/Linq.node.ts:1)
36
- - Icon is configured at the node-level: `icon: 'file:linq.svg'`
37
- - SVG file: [linq.svg](nodes/Linq/linq.svg:1)
38
-
39
- ### Supported resources and operations
40
-
41
- The node implements all endpoints from your Linq Partner API documentation (v2):
42
-
43
- - Resource: Chat
44
- - Operations:
45
- - Get Many → GET `/chats` (with pagination, optional `phone_number`)
46
- - Get One → GET `/chats/:id`
47
- - Find → GET `/chats/find` (by `phone_number`)
48
- - Create → POST `/chats` (supports group chats via `phone_numbers[]`, and optional `send_from`, and initial `message.text`)
49
- - Share Contact → POST `/chats/share-contact` (feature must be enabled by Linq)
50
-
51
- - Resource: Chat Message
52
- - Operations:
53
- - Get Many → GET `/chat_messages?chat_id=:chatId`
54
- - Get One → GET `/chat_messages/:id`
55
- - Create → POST `/chat_messages` (`chat_id`, `text`)
56
- - Delete → DELETE `/chat_messages/:id`
57
- - Edit → POST `/chat_messages/:id/edit` (`text`)
58
- - React → POST `/chat_messages/:id/react` (`reaction`)
59
- - Get Reaction → GET `/chat_messages/:id/reaction`
60
-
61
- - Resource: Phone Number
62
- - Operations:
63
- - Get Many → GET `/phone_numbers`
64
- - Check iMessage Availability GET `/phone_numbers/:phoneNumber/check_imessage`
65
-
66
- - Resource: Webhook Subscription
67
- - Operations:
68
- - Get Many → GET `/webhook_subscriptions`
69
- - Get One → GET `/webhook_subscriptions/:id`
70
- - Create → POST `/webhook_subscriptions`
71
- - Update → PUT `/webhook_subscriptions/:id`
72
- - Delete → DELETE `/webhook_subscriptions/:id`
73
-
74
- - Resource: Contact
75
- - Operations:
76
- - Create → POST `/contacts`
77
- - Get One → GET `/contacts/:id`
78
- - Update → PUT `/contacts/:id`
79
- - Delete → DELETE `/contacts/:id`
80
-
81
- ### Linq Trigger Node
82
-
83
- Add the "Linq Trigger" node to automatically start workflows when Linq events occur. The node automatically registers a webhook with Linq when the workflow is activated.
84
-
85
- - Supported Events:
86
- - Message Sent (`message.sent`)
87
- - Message Received (`message.received`)
88
- - Message Read (`message.read`)
89
- - Call Completed (`call.completed`)
90
- - Contact Created (`contact.created`)
91
- - Contact Updated (`contact.updated`)
92
- - Contact Deleted (`contact.deleted`)
93
-
94
- - Configuration:
95
- 1. Add the "Linq Trigger" node to your workflow
96
- 2. Select which events should trigger the workflow
97
- 3. Activate the workflow (this registers the webhook with Linq)
98
- 4. Linq will send events to your workflow when they occur
99
-
100
- - Security:
101
- - The node verifies the signature of incoming events using HMAC-SHA256
102
- - Requires the same Linq API credentials as the main node
103
-
104
- ### Example workflows
105
-
106
- 1) Send a group message
107
- - Resource: Chat
108
- - Operation: Create
109
- - Fields:
110
- - Send From (optional): `+13175551234`
111
- - Display Name (optional): `Project A`
112
- - Phone Numbers: `+13341234567, +13347654321`
113
- - Message Text: `Hello from n8n!`
114
-
115
- 2) Check iMessage availability
116
- - Resource: Phone Number
117
- - Operation: Check iMessage Availability
118
- - Field:
119
- - Phone Number: `+13341234567`
120
-
121
- 3) Create a contact
122
- - Resource: Contact
123
- - Operation: Create
124
- - Fields:
125
- - First Name: `John`
126
- - Last Name: `Doe`
127
- - Email: `john@example.com`
128
- - Phone Number: `+15551234567`
129
-
130
- 4) Manage webhook subscriptions
131
- - Resource: Webhook Subscription
132
- - Operation: Create
133
- - Fields:
134
- - Webhook URL: `https://example.com/webhooks/linq`
135
- - Events: `message.sent, message.received, contact.created`
136
- - Version: `2`
137
- - Active: `true`
138
-
139
- ## Development
140
-
141
- Requirements:
142
- - Node.js ≥ 20
143
- - npm or pnpm (npm commands shown below)
144
- - n8n local instance if testing end-to-end
145
-
146
- Install and build:
147
- ```bash
148
- cd n8n-nodes-linq
149
- npm install
150
- npm run build
151
- npm run lint
152
- ```
153
-
154
- Local link for testing in a local n8n:
155
- ```bash
156
- # in this folder
157
- npm link
158
- # in your n8n folder
159
- npm link n8n-nodes-linq
160
- # restart n8n, then add "Linq" node
161
- ```
162
-
163
- Project files of interest:
164
- - Node: [Linq.node.ts](nodes/Linq/Linq.node.ts:1)
165
- - Credentials: [LinqApi.credentials.ts](credentials/LinqApi.credentials.ts:1)
166
- - Gulp (copies icons): [gulpfile.js](gulpfile.js:1)
167
- - TypeScript config: [tsconfig.json](tsconfig.json:1)
168
- - Index shim: [index.js](index.js:1)
169
-
170
- ## Publishing to npm
171
-
172
- 1) Ensure metadata is correct in [package.json](package.json:1)
173
- - name: `n8n-nodes-linq`
174
- - version: increment for each release, e.g. `0.1.0`
175
- - author: `"alexautomates"`
176
- - keywords include: `n8n-community-node-package`
177
- - `files: ["dist"]` to publish only built files
178
- - `n8n` block lists built nodes and credentials in `dist/`
179
-
180
- 2) Build and publish:
181
- ```bash
182
- npm run build
183
- npm publish --access public
184
- ```
185
-
186
- 3) Users can install from the n8n UI (Community Nodes) by typing `n8n-nodes-linq`.
187
-
188
- ## Icon / Branding
189
-
190
- - Icon file is included at: [nodes/Linq/linq.svg](nodes/Linq/linq.svg:1)
191
- - Node description references it as `icon: 'file:linq.svg'`, so it renders in the n8n UI.
192
-
193
- ## License
1
+ # n8n-nodes-linq
2
+
3
+ Linq Partner API (v2) community node for n8n. This node lets you manage chats, messages (with attachments), phone numbers, webhooks, and contacts in Linq from your n8n workflows.
4
+
5
+ - Package: `n8n-nodes-linq`
6
+ - Node icon: included (SVG)
7
+ - API version: v2
8
+ - Auth: Integration Token (`X-LINQ-INTEGRATION-TOKEN`)
9
+
10
+ ## Installation (in n8n)
11
+
12
+ - Using the n8n UI:
13
+ 1) Settings → Community Nodes → Install
14
+ 2) Enter: `n8n-nodes-linq`
15
+ 3) Restart n8n if prompted
16
+
17
+ - Headless / environment variable:
18
+ - Add `n8n-nodes-linq` to `N8N_COMMUNITY_PACKAGES` (or install with npm in your instance) and restart n8n.
19
+
20
+ ## Credentials
21
+
22
+ Create a new credential of type "Linq API" and set your Integration Token:
23
+
24
+ - Header used: `X-LINQ-INTEGRATION-TOKEN: <your token>`
25
+ - The field is hidden in the UI (password type).
26
+
27
+ Where it's defined:
28
+ - [class LinqApi implements ICredentialType](credentials/LinqApi.credentials.ts:1)
29
+
30
+ ## Node usage
31
+
32
+ Add the "Linq" node to your workflow. The node provides Resources and Operations that map 1:1 to the documented Linq Partner API endpoints.
33
+
34
+ - Node implementation:
35
+ - [class Linq implements INodeType](nodes/Linq/Linq.node.ts:1)
36
+ - Icon is configured at the node-level: `icon: 'file:linq.svg'`
37
+ - SVG file: [linq.svg](nodes/Linq/linq.svg:1)
38
+
39
+ ### Supported resources and operations
40
+
41
+ The node implements all endpoints from your Linq Partner API documentation (v2):
42
+
43
+ - Resource: Chat
44
+ - Operations:
45
+ - Get Many → GET `/chats` (requires `phone_number`; pagination supported)
46
+ - Get One → GET `/chats/:id`
47
+ - Find → GET `/chats/find` (requires your `phone_number` and `phone_numbers[]` of participants)
48
+ - Create → POST `/chats` (requires `send_from`, supports group chats via `phone_numbers[]`, optional display name, initial `message.text`)
49
+ - Share Contact → POST `/chats/{chat_id}/share_contact` (chat_id required; feature must be enabled by Linq)
50
+
51
+ - Resource: Chat Message
52
+ - Operations:
53
+ - Get Many → GET `/chats/{chat_id}/chat_messages`
54
+ - Get One → GET `/chat_messages/:id`
55
+ - Create → POST `/chats/{chat_id}/chat_messages` (supports `text`, optional `attachment_urls[]`, optional `idempotency_key`)
56
+ - Delete → DELETE `/chat_messages/:id`
57
+ - Edit → POST `/chat_messages/:id/edit` (`text`)
58
+ - React → POST `/chat_messages/:id/reactions` (`reaction`)
59
+ - Get Reaction → GET `/chat_message_reactions/:reaction_id`
60
+
61
+ - Resource: Phone Number
62
+ - Operations:
63
+ - Get Many → GET `/phone_numbers`
64
+ - UpdatePUT `/phone_numbers/:id` (optional `forward_to`, optional `label`)
65
+
66
+ - Resource: Webhook Subscription
67
+ - Operations:
68
+ - Get Many → GET `/webhook_subscriptions`
69
+ - Get One → GET `/webhook_subscriptions/:id`
70
+ - Create → POST `/webhook_subscriptions`
71
+ - Update → PUT `/webhook_subscriptions/:id`
72
+ - Delete → DELETE `/webhook_subscriptions/:id`
73
+
74
+ - Resource: Contact
75
+ - Operations:
76
+ - Create → POST `/contacts`
77
+ - Get One → GET `/contacts/:id`
78
+ - Update → PUT `/contacts/:id`
79
+ - Delete → DELETE `/contacts/:id`
80
+
81
+ ### Linq Trigger Node
82
+
83
+ Add the "Linq Trigger" node to automatically start workflows when Linq events occur. The node automatically registers a webhook with Linq when the workflow is activated.
84
+
85
+ - Supported Events:
86
+ - Message Sent (`message.sent`)
87
+ - Message Received (`message.received`)
88
+ - Message Read (`message.read`)
89
+ - Call Completed (`call.completed`)
90
+ - Contact Created (`contact.created`)
91
+ - Contact Updated (`contact.updated`)
92
+ - Contact Deleted (`contact.deleted`)
93
+
94
+ - Configuration:
95
+ 1. Add the "Linq Trigger" node to your workflow
96
+ 2. Select which events should trigger the workflow
97
+ 3. Activate the workflow (this registers the webhook with Linq)
98
+ 4. Linq will send events to your workflow when they occur
99
+
100
+ - Security:
101
+ - The node verifies the signature of incoming events using HMAC-SHA256
102
+ - Requires the same Linq API credentials as the main node
103
+
104
+ ### Example workflows
105
+
106
+ 1) Send a group message
107
+ - Resource: Chat
108
+ - Operation: Create
109
+ - Fields:
110
+ - Send From (required): `+13175551234`
111
+ - Display Name (optional): `Project A`
112
+ - Phone Numbers: `+13341234567, +13347654321`
113
+ - Message Text: `Hello from n8n!`
114
+
115
+ 2) Create a contact
116
+ - Resource: Contact
117
+ - Operation: Create
118
+ - Fields:
119
+ - First Name: `John`
120
+ - Last Name: `Doe`
121
+ - Email: `john@example.com`
122
+ - Phone Number: `+15551234567`
123
+ 3) Manage webhook subscriptions
124
+ - Resource: Webhook Subscription
125
+ - Operation: Create
126
+ - Fields:
127
+ - Webhook URL: `https://example.com/webhooks/linq`
128
+ - Events: `message.sent, message.received, contact.created`
129
+ - Version: `2`
130
+ - Active: `true`
131
+
132
+ 4) Update phone number forwarding
133
+ - Resource: Phone Number
134
+ - Operation: Update
135
+ - Fields:
136
+ - Phone Number ID: `<id>`
137
+ - Forward To (optional): `+15551230000`
138
+ - Label (optional): `Support Line`
139
+
140
+ ## Development
141
+
142
+ Requirements:
143
+ - Node.js 20
144
+ - npm or pnpm (npm commands shown below)
145
+ - n8n local instance if testing end-to-end
146
+
147
+ Install and build:
148
+ ```bash
149
+ cd n8n-nodes-linq
150
+ npm install
151
+ npm run build
152
+ npm run lint
153
+ ```
154
+
155
+ Local link for testing in a local n8n:
156
+ ```bash
157
+ # in this folder
158
+ npm link
159
+ # in your n8n folder
160
+ npm link n8n-nodes-linq
161
+ # restart n8n, then add "Linq" node
162
+ ```
163
+
164
+ Project files of interest:
165
+ - Node: [Linq.node.ts](nodes/Linq/Linq.node.ts:1)
166
+ - Credentials: [LinqApi.credentials.ts](credentials/LinqApi.credentials.ts:1)
167
+ - Gulp (copies icons): [gulpfile.js](gulpfile.js:1)
168
+ - TypeScript config: [tsconfig.json](tsconfig.json:1)
169
+ - Index shim: [index.js](index.js:1)
170
+
171
+ ## Publishing to npm
172
+
173
+ 1) Ensure metadata is correct in [package.json](package.json:1)
174
+ - name: `n8n-nodes-linq`
175
+ - version: increment for each release, e.g. `0.1.0`
176
+ - author: `"alexautomates"`
177
+ - keywords include: `n8n-community-node-package`
178
+ - `files: ["dist"]` to publish only built files
179
+ - `n8n` block lists built nodes and credentials in `dist/`
180
+
181
+ 2) Build and publish:
182
+ ```bash
183
+ npm run build
184
+ npm publish --access public
185
+ ```
186
+
187
+ 3) Users can install from the n8n UI (Community Nodes) by typing `n8n-nodes-linq`.
188
+
189
+ ## Icon / Branding
190
+
191
+ - Icon file is included at: [nodes/Linq/linq.svg](nodes/Linq/linq.svg:1)
192
+ - Node description references it as `icon: 'file:linq.svg'`, so it renders in the n8n UI.
193
+
194
+ ## License
@@ -5,7 +5,7 @@ class LinqApi {
5
5
  constructor() {
6
6
  this.name = 'linqApi';
7
7
  this.displayName = 'Linq API';
8
- this.documentationUrl = 'https://docs.linqapp.com';
8
+ this.documentationUrl = 'https://apidocs.linqapp.com/reference/';
9
9
  this.properties = [
10
10
  {
11
11
  displayName: 'Integration Token',
@@ -129,16 +129,16 @@ class Linq {
129
129
  noDataExpression: true,
130
130
  displayOptions: { show: { resource: ['phoneNumber'] } },
131
131
  options: [
132
- {
133
- name: 'Check iMessage Availability',
134
- value: 'checkIMessageAvailability',
135
- action: 'Check imessage availability'
136
- },
137
132
  {
138
133
  name: 'Get Many',
139
134
  value: 'getAll',
140
135
  action: 'Get many phone numbers'
141
136
  },
137
+ {
138
+ name: 'Update',
139
+ value: 'update',
140
+ action: 'Update a phone number'
141
+ },
142
142
  ],
143
143
  default: 'getAll',
144
144
  },
@@ -214,7 +214,7 @@ class Linq {
214
214
  displayName: 'Chat ID',
215
215
  name: 'chatId',
216
216
  type: 'string',
217
- displayOptions: { show: { resource: ['chat'], operation: ['getOne'] } },
217
+ displayOptions: { show: { resource: ['chat'], operation: ['getOne', 'shareContact'] } },
218
218
  default: '',
219
219
  description: 'The ID of the chat to retrieve',
220
220
  },
@@ -224,7 +224,15 @@ class Linq {
224
224
  type: 'string',
225
225
  displayOptions: { show: { resource: ['chat'], operation: ['getAll'] } },
226
226
  default: '',
227
- description: 'Filter chats by phone number',
227
+ description: 'Required: your Linq phone number (phone_number)',
228
+ },
229
+ {
230
+ displayName: 'From Phone Number',
231
+ name: 'fromPhoneNumber',
232
+ type: 'string',
233
+ displayOptions: { show: { resource: ['chat'], operation: ['find'] } },
234
+ default: '',
235
+ description: 'Required: your Linq phone number (phone_number)',
228
236
  },
229
237
  {
230
238
  displayName: 'Phone Numbers',
@@ -288,7 +296,7 @@ class Linq {
288
296
  displayName: 'Chat Message ID',
289
297
  name: 'chatMessageId',
290
298
  type: 'string',
291
- displayOptions: { show: { resource: ['chatMessage'], operation: ['getOne', 'delete', 'edit', 'react', 'getReaction'] } },
299
+ displayOptions: { show: { resource: ['chatMessage'], operation: ['getOne', 'delete', 'edit', 'react'] } },
292
300
  default: '',
293
301
  description: 'The ID of the chat message',
294
302
  },
@@ -308,6 +316,22 @@ class Linq {
308
316
  default: '',
309
317
  description: 'The text of the message',
310
318
  },
319
+ {
320
+ displayName: 'Attachment URLs',
321
+ name: 'attachmentUrls',
322
+ type: 'string',
323
+ displayOptions: { show: { resource: ['chatMessage'], operation: ['create'] } },
324
+ default: '',
325
+ description: 'Comma-separated list of attachment URLs (attachment_urls[])',
326
+ },
327
+ {
328
+ displayName: 'Idempotency Key',
329
+ name: 'idempotencyKey',
330
+ type: 'string',
331
+ displayOptions: { show: { resource: ['chatMessage'], operation: ['create'] } },
332
+ default: '',
333
+ description: 'Optional idempotency key for message creation',
334
+ },
311
335
  {
312
336
  displayName: 'Reaction',
313
337
  name: 'reaction',
@@ -316,14 +340,38 @@ class Linq {
316
340
  default: '',
317
341
  description: 'The reaction to add',
318
342
  },
343
+ {
344
+ displayName: 'Reaction ID',
345
+ name: 'reactionId',
346
+ type: 'string',
347
+ displayOptions: { show: { resource: ['chatMessage'], operation: ['getReaction'] } },
348
+ default: '',
349
+ description: 'The reaction ID to retrieve',
350
+ },
319
351
  // Phone Number parameters
320
352
  {
321
- displayName: 'Phone Number',
322
- name: 'phoneNumber',
353
+ displayName: 'Phone Number ID',
354
+ name: 'phoneNumberId',
355
+ type: 'string',
356
+ displayOptions: { show: { resource: ['phoneNumber'], operation: ['update'] } },
357
+ default: '',
358
+ description: 'The ID of the phone number to update',
359
+ },
360
+ {
361
+ displayName: 'Forward To',
362
+ name: 'forwardTo',
363
+ type: 'string',
364
+ displayOptions: { show: { resource: ['phoneNumber'], operation: ['update'] } },
365
+ default: '',
366
+ description: 'Optional forwarding destination phone number',
367
+ },
368
+ {
369
+ displayName: 'Label',
370
+ name: 'label',
323
371
  type: 'string',
324
- displayOptions: { show: { resource: ['phoneNumber'], operation: ['checkIMessageAvailability'] } },
372
+ displayOptions: { show: { resource: ['phoneNumber'], operation: ['update'] } },
325
373
  default: '',
326
- description: 'The phone number to check',
374
+ description: 'Optional label for the phone number',
327
375
  },
328
376
  // Webhook Subscription parameters
329
377
  {
@@ -451,13 +499,16 @@ class Linq {
451
499
  const phoneNumber = this.getNodeParameter('phoneNumber', i, '');
452
500
  const page = this.getNodeParameter('page', i);
453
501
  const perPage = this.getNodeParameter('perPage', i);
502
+ if (!phoneNumber) {
503
+ throw new n8n_workflow_1.ApplicationError('phone_number is required by Linq API');
504
+ }
454
505
  const qs = {};
506
+ qs.phone_number = formatPhoneNumber(phoneNumber);
455
507
  if (page && page !== 1)
456
508
  qs.page = page;
457
509
  if (perPage && perPage !== 25)
458
510
  qs.per_page = perPage;
459
- if (phoneNumber)
460
- qs.phone_number = formatPhoneNumber(phoneNumber);
511
+ qs.phone_number = formatPhoneNumber(phoneNumber);
461
512
  responseData = await this.helpers.request({
462
513
  method: 'GET',
463
514
  url: 'https://api.linqapp.com/api/partner/v2/chats',
@@ -482,19 +533,16 @@ class Linq {
482
533
  });
483
534
  }
484
535
  if (operation === 'find') {
536
+ const fromPhoneNumber = this.getNodeParameter('fromPhoneNumber', i, '');
485
537
  const phoneNumbers = this.getNodeParameter('phoneNumbers', i, '');
538
+ if (!fromPhoneNumber) {
539
+ throw new n8n_workflow_1.ApplicationError('phone_number is required when finding chats');
540
+ }
486
541
  const qs = {};
487
542
  if (phoneNumbers) {
488
543
  // Check if we have a single phone number or multiple
489
544
  const phoneNumbersArray = phoneNumbers.split(',').map(p => formatPhoneNumber(p.trim()));
490
- if (phoneNumbersArray.length === 1) {
491
- // For single phone number, use 'phone' parameter
492
- qs.phone = phoneNumbersArray[0];
493
- }
494
- else {
495
- // For multiple phone numbers, use 'phone_numbers[]' parameter
496
- qs['phone_numbers[]'] = phoneNumbersArray;
497
- }
545
+ qs['phone_numbers[]'] = phoneNumbersArray;
498
546
  }
499
547
  responseData = await this.helpers.request({
500
548
  method: 'GET',
@@ -512,6 +560,9 @@ class Linq {
512
560
  const displayName = this.getNodeParameter('displayName', i);
513
561
  const phoneNumbers = this.getNodeParameter('phoneNumbers', i);
514
562
  const messageText = this.getNodeParameter('messageText', i);
563
+ if (!sendFrom) {
564
+ throw new n8n_workflow_1.ApplicationError('send_from is required by Linq when creating chats');
565
+ }
515
566
  const body = {
516
567
  chat: {
517
568
  phone_numbers: phoneNumbers.split(',').map(p => formatPhoneNumber(p.trim()))
@@ -520,9 +571,7 @@ class Linq {
520
571
  text: messageText
521
572
  }
522
573
  };
523
- if (sendFrom) {
524
- body.send_from = formatPhoneNumber(sendFrom);
525
- }
574
+ body.send_from = formatPhoneNumber(sendFrom);
526
575
  if (displayName) {
527
576
  body.chat.display_name = displayName;
528
577
  }
@@ -532,16 +581,20 @@ class Linq {
532
581
  headers: {
533
582
  'X-LINQ-INTEGRATION-TOKEN': credentials.integrationToken,
534
583
  'Content-Type': 'application/json',
535
- 'Accept': 'application/pdf'
584
+ 'Accept': 'application/json'
536
585
  },
537
586
  body: body,
538
587
  json: true,
539
588
  });
540
589
  }
541
590
  if (operation === 'shareContact') {
591
+ const chatId = this.getNodeParameter('chatId', i);
592
+ if (!chatId) {
593
+ throw new n8n_workflow_1.ApplicationError('chatId is required to share contact');
594
+ }
542
595
  responseData = await this.helpers.request({
543
596
  method: 'POST',
544
- url: 'https://api.linqapp.com/api/partner/v2/chats/share-contact',
597
+ url: `https://api.linqapp.com/api/partner/v2/chats/${chatId}/share_contact`,
545
598
  headers: {
546
599
  'X-LINQ-INTEGRATION-TOKEN': credentials.integrationToken,
547
600
  'Content-Type': 'application/json',
@@ -555,10 +608,12 @@ class Linq {
555
608
  if (resource === 'chatMessage') {
556
609
  if (operation === 'getAll') {
557
610
  const chatId = this.getNodeParameter('chatId', i);
611
+ if (!chatId) {
612
+ throw new n8n_workflow_1.ApplicationError('chatId is required to list chat messages');
613
+ }
558
614
  responseData = await this.helpers.request({
559
615
  method: 'GET',
560
- url: `https://api.linqapp.com/api/partner/v2/chat_messages`,
561
- qs: { chat_id: chatId },
616
+ url: `https://api.linqapp.com/api/partner/v2/chats/${chatId}/chat_messages`,
562
617
  headers: {
563
618
  'X-LINQ-INTEGRATION-TOKEN': credentials.integrationToken,
564
619
  'Accept': 'application/json'
@@ -581,13 +636,26 @@ class Linq {
581
636
  if (operation === 'create') {
582
637
  const chatId = this.getNodeParameter('chatId', i);
583
638
  const messageText = this.getNodeParameter('messageText', i);
639
+ const attachmentUrls = this.getNodeParameter('attachmentUrls', i, '');
640
+ const idempotencyKey = this.getNodeParameter('idempotencyKey', i, '');
641
+ if (!chatId) {
642
+ throw new n8n_workflow_1.ApplicationError('chatId is required to create a chat message');
643
+ }
584
644
  const body = {
585
- chat_id: chatId,
586
645
  text: messageText
587
646
  };
647
+ if (attachmentUrls) {
648
+ const parsed = attachmentUrls.split(',').map(u => u.trim()).filter(Boolean);
649
+ if (parsed.length) {
650
+ body.attachment_urls = parsed;
651
+ }
652
+ }
653
+ if (idempotencyKey) {
654
+ body.idempotency_key = idempotencyKey;
655
+ }
588
656
  responseData = await this.helpers.request({
589
657
  method: 'POST',
590
- url: 'https://api.linqapp.com/api/partner/v2/chat_messages',
658
+ url: `https://api.linqapp.com/api/partner/v2/chats/${chatId}/chat_messages`,
591
659
  headers: {
592
660
  'X-LINQ-INTEGRATION-TOKEN': credentials.integrationToken,
593
661
  'Content-Type': 'application/json',
@@ -635,7 +703,7 @@ class Linq {
635
703
  };
636
704
  responseData = await this.helpers.request({
637
705
  method: 'POST',
638
- url: `https://api.linqapp.com/api/partner/v2/chat_messages/${chatMessageId}/react`,
706
+ url: `https://api.linqapp.com/api/partner/v2/chat_messages/${chatMessageId}/reactions`,
639
707
  headers: {
640
708
  'X-LINQ-INTEGRATION-TOKEN': credentials.integrationToken,
641
709
  'Content-Type': 'application/json',
@@ -646,10 +714,13 @@ class Linq {
646
714
  });
647
715
  }
648
716
  if (operation === 'getReaction') {
649
- const chatMessageId = this.getNodeParameter('chatMessageId', i);
717
+ const reactionId = this.getNodeParameter('reactionId', i);
718
+ if (!reactionId) {
719
+ throw new n8n_workflow_1.ApplicationError('reactionId is required to get reaction');
720
+ }
650
721
  responseData = await this.helpers.request({
651
722
  method: 'GET',
652
- url: `https://api.linqapp.com/api/partner/v2/chat_messages/${chatMessageId}/reaction`,
723
+ url: `https://api.linqapp.com/api/partner/v2/chat_message_reactions/${reactionId}`,
653
724
  headers: {
654
725
  'X-LINQ-INTEGRATION-TOKEN': credentials.integrationToken,
655
726
  'Accept': 'application/json'
@@ -671,20 +742,29 @@ class Linq {
671
742
  json: true,
672
743
  });
673
744
  }
674
- if (operation === 'checkIMessageAvailability') {
675
- const phoneNumber = this.getNodeParameter('phoneNumber', i);
676
- const body = {
677
- phone_number: formatPhoneNumber(phoneNumber)
678
- };
745
+ if (operation === 'update') {
746
+ const phoneNumberId = this.getNodeParameter('phoneNumberId', i);
747
+ const forwardTo = this.getNodeParameter('forwardTo', i, '');
748
+ const label = this.getNodeParameter('label', i, '');
749
+ if (!phoneNumberId) {
750
+ throw new n8n_workflow_1.ApplicationError('phoneNumberId is required to update phone number');
751
+ }
752
+ const body = { phone_number: {} };
753
+ if (forwardTo) {
754
+ body.phone_number.forward_to = formatPhoneNumber(forwardTo);
755
+ }
756
+ if (label) {
757
+ body.phone_number.label = label;
758
+ }
679
759
  responseData = await this.helpers.request({
680
- method: 'POST',
681
- url: 'https://api.linqapp.com/api/partner/v2/i_message_availability/check',
760
+ method: 'PUT',
761
+ url: `https://api.linqapp.com/api/partner/v2/phone_numbers/${phoneNumberId}`,
682
762
  headers: {
683
763
  'X-LINQ-INTEGRATION-TOKEN': credentials.integrationToken,
684
764
  'Content-Type': 'application/json',
685
765
  'Accept': 'application/json'
686
766
  },
687
- body: body,
767
+ body,
688
768
  json: true,
689
769
  });
690
770
  }
package/index.js CHANGED
@@ -1,2 +1,2 @@
1
- // This file is intentionally left blank.
1
+ // This file is intentionally left blank.
2
2
  // It is required by n8n for community nodes.
package/package.json CHANGED
@@ -1,54 +1,59 @@
1
- {
2
- "name": "n8n-nodes-linq",
3
- "version": "0.1.16",
4
- "description": "Linq API integration for n8n",
5
- "keywords": [
6
- "n8n-community-node-package",
7
- "n8n",
8
- "linq",
9
- "automation"
10
- ],
11
- "license": "MIT",
12
- "homepage": "https://www.npmjs.com/package/n8n-nodes-linq",
13
- "author": {
14
- "name": "alexautomates"
15
- },
16
- "repository": {
17
- "type": "git",
18
- "url": "https://github.com/your-username/n8n-nodes-linq.git"
19
- },
20
- "engines": {
21
- "node": ">=20.15"
22
- },
23
- "main": "index.js",
24
- "scripts": {
25
- "build": "npx rimraf dist && tsc && gulp build:icons",
26
- "lint": "eslint nodes credentials",
27
- "lintfix": "eslint nodes credentials --fix",
28
- "prepublishOnly": "npm run build && npm run lint -c .eslintrc.prepublish.js nodes credentials"
29
- },
30
- "files": [
31
- "dist"
32
- ],
33
- "n8n": {
34
- "n8nNodesApiVersion": 1,
35
- "credentials": [
36
- "dist/credentials/LinqApi.credentials.js"
37
- ],
38
- "nodes": [
39
- "dist/nodes/Linq/Linq.node.js",
40
- "dist/nodes/LinqTrigger/LinqTrigger.node.js"
41
- ]
42
- },
43
- "devDependencies": {
44
- "@typescript-eslint/parser": "~8.32.0",
45
- "eslint": "^8.57.0",
46
- "eslint-plugin-n8n-nodes-base": "^1.16.3",
47
- "gulp": "^5.0.0",
48
- "prettier": "^3.5.3",
49
- "typescript": "^5.8.2"
50
- },
51
- "peerDependencies": {
52
- "n8n-workflow": "*"
53
- }
54
- }
1
+ {
2
+ "name": "n8n-nodes-linq",
3
+ "version": "0.2.0",
4
+ "description": "Linq API integration for n8n",
5
+ "keywords": [
6
+ "n8n-community-node-package",
7
+ "n8n",
8
+ "linq",
9
+ "automation"
10
+ ],
11
+ "license": "MIT",
12
+ "homepage": "https://www.npmjs.com/package/n8n-nodes-linq",
13
+ "author": {
14
+ "name": "alexautomates"
15
+ },
16
+ "repository": {
17
+ "type": "git",
18
+ "url": "git+https://github.com/AutomatorAlex/linq-n8n.git",
19
+ "directory": "n8n-nodes-linq"
20
+ },
21
+ "bugs": {
22
+ "url": "https://github.com/AutomatorAlex/linq-n8n/issues"
23
+ },
24
+ "engines": {
25
+ "node": ">=20.15"
26
+ },
27
+ "main": "index.js",
28
+ "scripts": {
29
+ "build": "npx rimraf dist && tsc && gulp build:icons",
30
+ "lint": "eslint nodes credentials",
31
+ "lintfix": "eslint nodes credentials --fix",
32
+ "prepublishOnly": "npm run build && npm run lint -c .eslintrc.prepublish.js nodes credentials"
33
+ },
34
+ "files": [
35
+ "dist"
36
+ ],
37
+ "n8n": {
38
+ "n8nNodesApiVersion": 1,
39
+ "credentials": [
40
+ "dist/credentials/LinqApi.credentials.js"
41
+ ],
42
+ "nodes": [
43
+ "dist/nodes/Linq/Linq.node.js",
44
+ "dist/nodes/LinqTrigger/LinqTrigger.node.js"
45
+ ]
46
+ },
47
+ "devDependencies": {
48
+ "@types/node": "^24.3.3",
49
+ "@typescript-eslint/parser": "~8.32.0",
50
+ "eslint": "^8.57.0",
51
+ "eslint-plugin-n8n-nodes-base": "^1.16.3",
52
+ "gulp": "^5.0.0",
53
+ "prettier": "^3.5.3",
54
+ "typescript": "^5.8.2"
55
+ },
56
+ "peerDependencies": {
57
+ "n8n-workflow": "*"
58
+ }
59
+ }