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 +20 -20
- package/README.md +194 -193
- package/dist/credentials/LinqApi.credentials.js +1 -1
- package/dist/nodes/Linq/Linq.node.js +122 -42
- package/index.js +1 -1
- package/package.json +59 -54
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` (
|
|
46
|
-
- Get One → GET `/chats/:id`
|
|
47
|
-
- Find → GET `/chats/find` (
|
|
48
|
-
- Create → POST `/chats` (supports group chats via `phone_numbers[]`,
|
|
49
|
-
- Share Contact → POST `/chats/
|
|
50
|
-
|
|
51
|
-
- Resource: Chat Message
|
|
52
|
-
- Operations:
|
|
53
|
-
- Get Many → GET `/chat_messages
|
|
54
|
-
- Get One → GET `/chat_messages/:id`
|
|
55
|
-
- Create → POST `/chat_messages` (`
|
|
56
|
-
- Delete → DELETE `/chat_messages/:id`
|
|
57
|
-
- Edit → POST `/chat_messages/:id/edit` (`text`)
|
|
58
|
-
- React → POST `/chat_messages/:id/
|
|
59
|
-
- Get Reaction → GET `/
|
|
60
|
-
|
|
61
|
-
- Resource: Phone Number
|
|
62
|
-
- Operations:
|
|
63
|
-
- Get Many → GET `/phone_numbers`
|
|
64
|
-
-
|
|
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 (
|
|
111
|
-
- Display Name (optional): `Project A`
|
|
112
|
-
- Phone Numbers: `+13341234567, +13347654321`
|
|
113
|
-
- Message Text: `Hello from n8n!`
|
|
114
|
-
|
|
115
|
-
2)
|
|
116
|
-
- Resource:
|
|
117
|
-
- Operation:
|
|
118
|
-
-
|
|
119
|
-
-
|
|
120
|
-
|
|
121
|
-
|
|
122
|
-
-
|
|
123
|
-
|
|
124
|
-
-
|
|
125
|
-
|
|
126
|
-
|
|
127
|
-
-
|
|
128
|
-
-
|
|
129
|
-
|
|
130
|
-
|
|
131
|
-
|
|
132
|
-
|
|
133
|
-
-
|
|
134
|
-
|
|
135
|
-
|
|
136
|
-
-
|
|
137
|
-
-
|
|
138
|
-
|
|
139
|
-
|
|
140
|
-
|
|
141
|
-
|
|
142
|
-
|
|
143
|
-
-
|
|
144
|
-
-
|
|
145
|
-
|
|
146
|
-
|
|
147
|
-
|
|
148
|
-
|
|
149
|
-
|
|
150
|
-
npm
|
|
151
|
-
npm run
|
|
152
|
-
|
|
153
|
-
|
|
154
|
-
|
|
155
|
-
|
|
156
|
-
|
|
157
|
-
|
|
158
|
-
|
|
159
|
-
|
|
160
|
-
|
|
161
|
-
|
|
162
|
-
|
|
163
|
-
|
|
164
|
-
|
|
165
|
-
-
|
|
166
|
-
-
|
|
167
|
-
-
|
|
168
|
-
-
|
|
169
|
-
|
|
170
|
-
|
|
171
|
-
|
|
172
|
-
|
|
173
|
-
|
|
174
|
-
-
|
|
175
|
-
-
|
|
176
|
-
-
|
|
177
|
-
-
|
|
178
|
-
- `
|
|
179
|
-
|
|
180
|
-
|
|
181
|
-
|
|
182
|
-
|
|
183
|
-
npm
|
|
184
|
-
|
|
185
|
-
|
|
186
|
-
|
|
187
|
-
|
|
188
|
-
|
|
189
|
-
|
|
190
|
-
|
|
191
|
-
-
|
|
192
|
-
|
|
193
|
-
|
|
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
|
+
- Update → PUT `/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://
|
|
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: '
|
|
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'
|
|
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: '
|
|
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: ['
|
|
372
|
+
displayOptions: { show: { resource: ['phoneNumber'], operation: ['update'] } },
|
|
325
373
|
default: '',
|
|
326
|
-
description: '
|
|
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
|
-
|
|
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
|
-
|
|
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
|
-
|
|
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/
|
|
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:
|
|
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:
|
|
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}/
|
|
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
|
|
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/
|
|
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 === '
|
|
675
|
-
const
|
|
676
|
-
const
|
|
677
|
-
|
|
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: '
|
|
681
|
-
url:
|
|
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
|
|
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.
|
|
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/
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
"
|
|
25
|
-
"
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
"
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
"
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
"
|
|
39
|
-
|
|
40
|
-
"dist/
|
|
41
|
-
]
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
"
|
|
49
|
-
"typescript": "
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
"
|
|
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
|
+
}
|