n8n-nodes-idb2b 3.2.5 → 3.2.7
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/README.md
CHANGED
|
@@ -47,13 +47,23 @@ npm install n8n-nodes-idb2b
|
|
|
47
47
|
| Update | Update an existing company |
|
|
48
48
|
| Delete | Delete a company |
|
|
49
49
|
|
|
50
|
+
### Activity
|
|
51
|
+
|
|
52
|
+
| Operation | Description |
|
|
53
|
+
|-----------|-------------|
|
|
54
|
+
| Get All | Retrieve all activities for a specific company/lead |
|
|
55
|
+
| Get | Fetch a single activity by ID |
|
|
56
|
+
| Create | Create a new activity linked to a company or contact |
|
|
57
|
+
| Update | Update an existing activity |
|
|
58
|
+
| Delete | Delete an activity |
|
|
59
|
+
|
|
50
60
|
## How to Use
|
|
51
61
|
|
|
52
62
|
### Basic workflow
|
|
53
63
|
|
|
54
|
-
1. Add the **IDB2B
|
|
64
|
+
1. Add the **IDB2B API** node to your workflow
|
|
55
65
|
2. Select your saved credential under **Credential to connect with**
|
|
56
|
-
3. Choose a **Resource** (Contact or Company)
|
|
66
|
+
3. Choose a **Resource** (Activity, Contact, or Company)
|
|
57
67
|
4. Choose an **Operation** (Get All, Get, Create, Update, Delete)
|
|
58
68
|
5. Fill in the required parameters and execute
|
|
59
69
|
|
|
@@ -90,7 +100,31 @@ Required:
|
|
|
90
100
|
- **Name**: Company name
|
|
91
101
|
|
|
92
102
|
Optional (under Additional Fields):
|
|
93
|
-
-
|
|
103
|
+
- **Website**, **Description**, **Industry ID**, **Size ID**, **Status ID**, **Source ID**, **Owner ID**
|
|
104
|
+
|
|
105
|
+
### Get All Activities
|
|
106
|
+
|
|
107
|
+
Required:
|
|
108
|
+
- **Company ID**: The company/lead to list activities for
|
|
109
|
+
- **Limit** / **Page**: Pagination controls
|
|
110
|
+
|
|
111
|
+
### Create Activity
|
|
112
|
+
|
|
113
|
+
Required:
|
|
114
|
+
- **Subject**: Title of the activity
|
|
115
|
+
- **Associate With**: Choose **Company** or **Contact**
|
|
116
|
+
- **Company ID** or **Contact ID** depending on the above
|
|
117
|
+
|
|
118
|
+
Optional (under Additional Fields):
|
|
119
|
+
- **Description**, **Date & Time**, **Icon**, **User ID**
|
|
120
|
+
|
|
121
|
+
### Update Activity
|
|
122
|
+
|
|
123
|
+
Required:
|
|
124
|
+
- **Activity ID**
|
|
125
|
+
|
|
126
|
+
Optional (under Additional Fields):
|
|
127
|
+
- Any fields to change: **Subject**, **Description**, **Date & Time**, **Icon**, **User ID**
|
|
94
128
|
|
|
95
129
|
## Example Workflows
|
|
96
130
|
|
|
@@ -110,6 +144,17 @@ Webhook → IDB2B Create Contact
|
|
|
110
144
|
- Additional Fields.LinkedIn URL: {{ $json.linkedin_url }}
|
|
111
145
|
```
|
|
112
146
|
|
|
147
|
+
### Log a call activity after a deal closes
|
|
148
|
+
|
|
149
|
+
```
|
|
150
|
+
Webhook → IDB2B Create Activity
|
|
151
|
+
- Subject: "Call with {{ $json.contact_name }}"
|
|
152
|
+
- Associate With: Company
|
|
153
|
+
- Company ID: {{ $json.company_id }}
|
|
154
|
+
- Additional Fields.Description: {{ $json.call_notes }}
|
|
155
|
+
- Additional Fields.Date & Time: {{ $json.call_time }}
|
|
156
|
+
```
|
|
157
|
+
|
|
113
158
|
### Paginate through all contacts
|
|
114
159
|
|
|
115
160
|
```
|
|
@@ -136,6 +181,15 @@ npm run lint
|
|
|
136
181
|
|
|
137
182
|
## Version History
|
|
138
183
|
|
|
184
|
+
### v3.2.5
|
|
185
|
+
- Added **Activity** resource with full CRUD operations (Get All, Get, Create, Update, Delete)
|
|
186
|
+
- Activities can be linked to a company or a contact
|
|
187
|
+
- Get All Activities scoped to a specific company via `GET /leads/:id/activities`
|
|
188
|
+
|
|
189
|
+
### v3.2.4
|
|
190
|
+
- Added LinkedIn URL and social links support for contacts
|
|
191
|
+
- Included socials in response data for create/update operations
|
|
192
|
+
|
|
139
193
|
### v2.0.3
|
|
140
194
|
- Fixed endpoint paths (`/contacts`, `/companies`)
|
|
141
195
|
- Fixed access token parsing from login response
|
|
@@ -89,6 +89,7 @@ class IDB2B {
|
|
|
89
89
|
let body = undefined;
|
|
90
90
|
let qs = {};
|
|
91
91
|
let initialBody = undefined;
|
|
92
|
+
let useFormData = false;
|
|
92
93
|
if (resource === "contact") {
|
|
93
94
|
if (operation === "getAll") {
|
|
94
95
|
method = "GET";
|
|
@@ -154,10 +155,17 @@ class IDB2B {
|
|
|
154
155
|
else if (resource === "activity") {
|
|
155
156
|
if (operation === "getAll") {
|
|
156
157
|
method = "GET";
|
|
157
|
-
const
|
|
158
|
+
const getAllScope = this.getNodeParameter("getAllScope", i);
|
|
158
159
|
const limit = this.getNodeParameter("limit", i, constants_1.PAGINATION.DEFAULT_LIMIT);
|
|
159
160
|
const page = this.getNodeParameter("page", i, constants_1.PAGINATION.DEFAULT_PAGE);
|
|
160
|
-
|
|
161
|
+
if (getAllScope === "contact") {
|
|
162
|
+
const contactId = this.getNodeParameter("getAllContactId", i);
|
|
163
|
+
endpoint = `/contacts/${(0, common_1.sanitizeId)(contactId)}/activities`;
|
|
164
|
+
}
|
|
165
|
+
else {
|
|
166
|
+
const companyId = this.getNodeParameter("companyId", i);
|
|
167
|
+
endpoint = `/leads/${(0, common_1.sanitizeId)(companyId)}/activities`;
|
|
168
|
+
}
|
|
161
169
|
qs.limit = limit;
|
|
162
170
|
qs.page = page;
|
|
163
171
|
}
|
|
@@ -175,29 +183,41 @@ class IDB2B {
|
|
|
175
183
|
if (!subject || !subject.trim()) {
|
|
176
184
|
throw new Error("Subject is required to create an activity");
|
|
177
185
|
}
|
|
178
|
-
|
|
186
|
+
// Must send as multipart/form-data — the /activities endpoint uses
|
|
187
|
+
// FilesInterceptor which does not parse JSON bodies reliably
|
|
188
|
+
const formPayload = { subject: subject.trim() };
|
|
179
189
|
if (associateWith === "company") {
|
|
180
190
|
const companyId = this.getNodeParameter("activityCompanyId", i);
|
|
181
|
-
|
|
191
|
+
formPayload.company_id = companyId;
|
|
182
192
|
}
|
|
183
193
|
else {
|
|
184
194
|
const contactId = this.getNodeParameter("activityContactId", i);
|
|
185
|
-
|
|
195
|
+
formPayload.contact_id = contactId;
|
|
186
196
|
}
|
|
187
|
-
|
|
197
|
+
// Merge optional additional fields
|
|
198
|
+
Object.entries(additionalFields).forEach(([key, value]) => {
|
|
199
|
+
if (value !== undefined && value !== "" && key !== "subject") {
|
|
200
|
+
formPayload[key] = value;
|
|
201
|
+
}
|
|
202
|
+
});
|
|
203
|
+
body = formPayload;
|
|
204
|
+
initialBody = formPayload;
|
|
205
|
+
useFormData = true;
|
|
188
206
|
}
|
|
189
207
|
else if (operation === "update") {
|
|
190
208
|
method = "PATCH";
|
|
191
209
|
const activityId = this.getNodeParameter("activityId", i);
|
|
192
210
|
endpoint = `${constants_1.ENDPOINTS.ACTIVITIES}/${(0, common_1.sanitizeId)(activityId)}`;
|
|
193
211
|
const additionalFields = this.getNodeParameter("additionalFields", i, {});
|
|
194
|
-
|
|
212
|
+
const updatePayload = {};
|
|
195
213
|
Object.entries(additionalFields).forEach(([key, value]) => {
|
|
196
214
|
if (value !== undefined && value !== "") {
|
|
197
|
-
|
|
215
|
+
updatePayload[key] = value;
|
|
198
216
|
}
|
|
199
217
|
});
|
|
200
|
-
|
|
218
|
+
body = updatePayload;
|
|
219
|
+
initialBody = updatePayload;
|
|
220
|
+
useFormData = true;
|
|
201
221
|
}
|
|
202
222
|
else if (operation === "delete") {
|
|
203
223
|
method = "DELETE";
|
|
@@ -263,16 +283,9 @@ class IDB2B {
|
|
|
263
283
|
endpoint = `${constants_1.ENDPOINTS.COMPANIES}/${(0, common_1.sanitizeId)(companyId)}`;
|
|
264
284
|
}
|
|
265
285
|
}
|
|
266
|
-
const response = await httpClient.makeRequest({
|
|
267
|
-
method,
|
|
268
|
-
url: `${credentials.baseUrl}${endpoint}`,
|
|
269
|
-
headers: {
|
|
286
|
+
const response = await httpClient.makeRequest(Object.assign(Object.assign({ method, url: `${credentials.baseUrl}${endpoint}`, headers: {
|
|
270
287
|
Authorization: `Bearer ${accessToken}`,
|
|
271
|
-
},
|
|
272
|
-
body,
|
|
273
|
-
qs,
|
|
274
|
-
json: true,
|
|
275
|
-
});
|
|
288
|
+
} }, (useFormData ? { formData: body } : { body })), { qs, json: true }));
|
|
276
289
|
let processedResponse = (0, common_1.processResponse)(response, operation, initialBody);
|
|
277
290
|
// Apply field filtering for getAll operations
|
|
278
291
|
if (operation === "getAll") {
|
|
@@ -61,7 +61,25 @@ exports.activityFields = [
|
|
|
61
61
|
},
|
|
62
62
|
description: 'ID of the activity',
|
|
63
63
|
},
|
|
64
|
-
//
|
|
64
|
+
// Scope selector for getAll
|
|
65
|
+
{
|
|
66
|
+
displayName: 'Scope',
|
|
67
|
+
name: 'getAllScope',
|
|
68
|
+
type: 'options',
|
|
69
|
+
default: 'company',
|
|
70
|
+
required: true,
|
|
71
|
+
displayOptions: {
|
|
72
|
+
show: {
|
|
73
|
+
resource: ['activity'],
|
|
74
|
+
operation: ['getAll'],
|
|
75
|
+
},
|
|
76
|
+
},
|
|
77
|
+
options: [
|
|
78
|
+
{ name: 'Company', value: 'company' },
|
|
79
|
+
{ name: 'Contact', value: 'contact' },
|
|
80
|
+
],
|
|
81
|
+
description: 'Whether to list activities for a company or a contact',
|
|
82
|
+
},
|
|
65
83
|
{
|
|
66
84
|
displayName: 'Company ID',
|
|
67
85
|
name: 'companyId',
|
|
@@ -72,10 +90,26 @@ exports.activityFields = [
|
|
|
72
90
|
show: {
|
|
73
91
|
resource: ['activity'],
|
|
74
92
|
operation: ['getAll'],
|
|
93
|
+
getAllScope: ['company'],
|
|
75
94
|
},
|
|
76
95
|
},
|
|
77
96
|
description: 'ID of the company/lead to list activities for',
|
|
78
97
|
},
|
|
98
|
+
{
|
|
99
|
+
displayName: 'Contact ID',
|
|
100
|
+
name: 'getAllContactId',
|
|
101
|
+
type: 'string',
|
|
102
|
+
default: '',
|
|
103
|
+
required: true,
|
|
104
|
+
displayOptions: {
|
|
105
|
+
show: {
|
|
106
|
+
resource: ['activity'],
|
|
107
|
+
operation: ['getAll'],
|
|
108
|
+
getAllScope: ['contact'],
|
|
109
|
+
},
|
|
110
|
+
},
|
|
111
|
+
description: 'ID of the contact to list activities for',
|
|
112
|
+
},
|
|
79
113
|
// Subject — required for create
|
|
80
114
|
{
|
|
81
115
|
displayName: 'Subject',
|