Rename vendors to third parties

Renames the user-facing 'vendor' concept to 'third party' across the
entire codebase. The shared common_third_parties reference table is
unchanged.

Migration. Renames the vendor_category enum, the vendors and
vendor_<entity> tables (contacts, services, compliance_reports,
business_associate_agreements, data_privacy_agreements,
risk_assessments) and their vendor_id columns, the asset_vendors /
data_vendors / processing_activity_vendors junction tables,
generated_documents.vendors_document_id, the webhook_event_type
'vendor:<verb>' values, and the snapshots_type 'VENDORS' value.

Backend. Renames coredata models and SQL queries, probo services,
GraphQL / MCP API surface, console / trust / webhook resolvers and
types, the CLI (prb vendor* -> prb third-party*; pkg/cmd/vendormgmt
-> pkg/cmd/thirdpartymgmt), the document generator, vetting agent
prompts, and the common-third-parties-import command.

Frontend, packages, n8n, e2e. Renames apps/console pages, components,
hooks, routes, dialogs, and tabs; the shared @probo/vendors package
(now @probo/third-parties); the @probo/ui Vendors atoms (now
ThirdParties, VendorLogo -> ThirdPartyLogo); the n8n community node
actions/vendor folder (now actions/thirdParty); and the e2e Go test
suite (console and MCP). Filesystem and URL paths use kebab-case
(third-parties), GraphQL fields and TypeScript identifiers use
camelCase (thirdParty / thirdParties), Go types use PascalCase
(ThirdParty), and human-facing text uses 'third party' with a space.

Co-authored-by: Bryan Frimin <bryan@getprobo.com>
Signed-off-by: Bryan Frimin <bryan@getprobo.com>
Signed-off-by: Sacha Al Himdani <sacha@getprobo.com>
This commit is contained in:
Sacha Al Himdani
2026-05-13 16:15:33 +02:00
parent 9eed0d71c8
commit eecbe4c46c
281 changed files with 8491 additions and 8425 deletions

View File

@@ -0,0 +1,320 @@
// Copyright (c) 2025 Probo Inc <hello@getprobo.com>.
//
// Permission to use, copy, modify, and/or distribute this software for any
// purpose with or without fee is hereby granted, provided that the above
// copyright notice and this permission notice appear in all copies.
//
// THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES WITH
// REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY
// AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT,
// INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM
// LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR
// OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
// PERFORMANCE OF THIS SOFTWARE.
import type { INodeProperties, IExecuteFunctions, INodeExecutionData } from 'n8n-workflow';
import { proboApiRequest } from '../../GenericFunctions';
export const description: INodeProperties[] = [
{
displayName: 'Organization ID',
name: 'organizationId',
type: 'string',
displayOptions: {
show: {
resource: ['thirdParty'],
operation: ['create'],
},
},
default: '',
description: 'The ID of the organization',
required: true,
},
{
displayName: 'Name',
name: 'name',
type: 'string',
displayOptions: {
show: {
resource: ['thirdParty'],
operation: ['create'],
},
},
default: '',
description: 'The name of the thirdParty',
required: true,
},
{
displayName: 'Description',
name: 'description',
type: 'string',
typeOptions: {
rows: 4,
},
displayOptions: {
show: {
resource: ['thirdParty'],
operation: ['create'],
},
},
default: '',
description: 'The description of the thirdParty',
},
{
displayName: 'Category',
name: 'category',
type: 'string',
displayOptions: {
show: {
resource: ['thirdParty'],
operation: ['create'],
},
},
default: '',
description: 'The category of the thirdParty',
},
{
displayName: 'Website URL',
name: 'websiteUrl',
type: 'string',
displayOptions: {
show: {
resource: ['thirdParty'],
operation: ['create'],
},
},
default: '',
description: 'The website URL of the thirdParty',
},
{
displayName: 'Legal Name',
name: 'legalName',
type: 'string',
displayOptions: {
show: {
resource: ['thirdParty'],
operation: ['create'],
},
},
default: '',
description: 'The legal name of the thirdParty',
},
{
displayName: 'Headquarter Address',
name: 'headquarterAddress',
type: 'string',
displayOptions: {
show: {
resource: ['thirdParty'],
operation: ['create'],
},
},
default: '',
description: 'The headquarter address of the thirdParty',
},
{
displayName: 'Business Owner ID',
name: 'businessOwnerId',
type: 'string',
displayOptions: {
show: {
resource: ['thirdParty'],
operation: ['create'],
},
},
default: '',
description: 'The ID of the business owner (People ID)',
},
{
displayName: 'Security Owner ID',
name: 'securityOwnerId',
type: 'string',
displayOptions: {
show: {
resource: ['thirdParty'],
operation: ['create'],
},
},
default: '',
description: 'The ID of the security owner (People ID)',
},
{
displayName: 'Additional Fields',
name: 'additionalFields',
type: 'collection',
placeholder: 'Add Field',
default: {},
displayOptions: {
show: {
resource: ['thirdParty'],
operation: ['create'],
},
},
options: [
{
displayName: 'Business Associate Agreement URL',
name: 'businessAssociateAgreementUrl',
type: 'string',
default: '',
},
{
displayName: 'Certifications',
name: 'certifications',
type: 'string',
default: '',
description: 'Comma-separated list of certifications',
},
{
displayName: 'Countries',
name: 'countries',
type: 'string',
default: '',
description: 'Comma-separated list of country codes',
},
{
displayName: 'Data Processing Agreement URL',
name: 'dataProcessingAgreementUrl',
type: 'string',
default: '',
},
{
displayName: 'Privacy Policy URL',
name: 'privacyPolicyUrl',
type: 'string',
default: '',
},
{
displayName: 'Security Page URL',
name: 'securityPageUrl',
type: 'string',
default: '',
},
{
displayName: 'Service Level Agreement URL',
name: 'serviceLevelAgreementUrl',
type: 'string',
default: '',
},
{
displayName: 'Status Page URL',
name: 'statusPageUrl',
type: 'string',
default: '',
description: 'The status page URL of the thirdParty',
},
{
displayName: 'Subprocessors List URL',
name: 'subprocessorsListUrl',
type: 'string',
default: '',
},
{
displayName: 'Terms of Service URL',
name: 'termsOfServiceUrl',
type: 'string',
default: '',
},
{
displayName: 'Trust Page URL',
name: 'trustPageUrl',
type: 'string',
default: '',
},
],
},
];
export async function execute(
this: IExecuteFunctions,
itemIndex: number,
): Promise<INodeExecutionData> {
const organizationId = this.getNodeParameter('organizationId', itemIndex) as string;
const name = this.getNodeParameter('name', itemIndex) as string;
const description = this.getNodeParameter('description', itemIndex, '') as string;
const category = this.getNodeParameter('category', itemIndex, '') as string;
const websiteUrl = this.getNodeParameter('websiteUrl', itemIndex, '') as string;
const legalName = this.getNodeParameter('legalName', itemIndex, '') as string;
const headquarterAddress = this.getNodeParameter('headquarterAddress', itemIndex, '') as string;
const businessOwnerId = this.getNodeParameter('businessOwnerId', itemIndex, '') as string;
const securityOwnerId = this.getNodeParameter('securityOwnerId', itemIndex, '') as string;
const additionalFields = this.getNodeParameter('additionalFields', itemIndex, {}) as {
statusPageUrl?: string;
termsOfServiceUrl?: string;
privacyPolicyUrl?: string;
serviceLevelAgreementUrl?: string;
dataProcessingAgreementUrl?: string;
businessAssociateAgreementUrl?: string;
subprocessorsListUrl?: string;
securityPageUrl?: string;
trustPageUrl?: string;
certifications?: string;
countries?: string;
};
const query = `
mutation CreateThirdParty($input: CreateThirdPartyInput!) {
createThirdParty(input: $input) {
thirdPartyEdge {
node {
id
name
description
category
websiteUrl
legalName
headquarterAddress
statusPageUrl
termsOfServiceUrl
privacyPolicyUrl
serviceLevelAgreementUrl
dataProcessingAgreementUrl
businessAssociateAgreementUrl
subprocessorsListUrl
securityPageUrl
trustPageUrl
certifications
countries
showOnTrustCenter
createdAt
updatedAt
}
}
}
}
`;
const input: Record<string, unknown> = {
organizationId,
name,
};
if (description) input.description = description;
if (category) input.category = category;
if (websiteUrl) input.websiteUrl = websiteUrl;
if (legalName) input.legalName = legalName;
if (headquarterAddress) input.headquarterAddress = headquarterAddress;
if (businessOwnerId) input.businessOwnerId = businessOwnerId;
if (securityOwnerId) input.securityOwnerId = securityOwnerId;
if (additionalFields.statusPageUrl) input.statusPageUrl = additionalFields.statusPageUrl;
if (additionalFields.termsOfServiceUrl) input.termsOfServiceUrl = additionalFields.termsOfServiceUrl;
if (additionalFields.privacyPolicyUrl) input.privacyPolicyUrl = additionalFields.privacyPolicyUrl;
if (additionalFields.serviceLevelAgreementUrl) input.serviceLevelAgreementUrl = additionalFields.serviceLevelAgreementUrl;
if (additionalFields.dataProcessingAgreementUrl) input.dataProcessingAgreementUrl = additionalFields.dataProcessingAgreementUrl;
if (additionalFields.businessAssociateAgreementUrl) input.businessAssociateAgreementUrl = additionalFields.businessAssociateAgreementUrl;
if (additionalFields.subprocessorsListUrl) input.subprocessorsListUrl = additionalFields.subprocessorsListUrl;
if (additionalFields.securityPageUrl) input.securityPageUrl = additionalFields.securityPageUrl;
if (additionalFields.trustPageUrl) input.trustPageUrl = additionalFields.trustPageUrl;
if (additionalFields.certifications) {
input.certifications = additionalFields.certifications.split(',').map((c) => c.trim()).filter(Boolean);
}
if (additionalFields.countries) {
input.countries = additionalFields.countries.split(',').map((c) => c.trim()).filter(Boolean);
}
const responseData = await proboApiRequest.call(this, query, { input });
return {
json: responseData,
pairedItem: { item: itemIndex },
};
}

View File

@@ -0,0 +1,128 @@
// Copyright (c) 2026 Probo Inc <hello@getprobo.com>.
//
// Permission to use, copy, modify, and/or distribute this software for any
// purpose with or without fee is hereby granted, provided that the above
// copyright notice and this permission notice appear in all copies.
//
// THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES WITH
// REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY
// AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT,
// INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM
// LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR
// OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
// PERFORMANCE OF THIS SOFTWARE.
import type { INodeProperties, IExecuteFunctions, INodeExecutionData } from 'n8n-workflow';
import { proboApiRequest } from '../../GenericFunctions';
export const description: INodeProperties[] = [
{
displayName: 'ThirdParty ID',
name: 'thirdPartyId',
type: 'string',
displayOptions: {
show: {
resource: ['thirdParty'],
operation: ['createContact'],
},
},
default: '',
description: 'The ID of the thirdParty',
required: true,
},
{
displayName: 'Full Name',
name: 'fullName',
type: 'string',
displayOptions: {
show: {
resource: ['thirdParty'],
operation: ['createContact'],
},
},
default: '',
description: 'The full name of the contact',
},
{
displayName: 'Email',
name: 'email',
type: 'string',
placeholder: 'name@email.com',
displayOptions: {
show: {
resource: ['thirdParty'],
operation: ['createContact'],
},
},
default: '',
description: 'The email address of the contact',
},
{
displayName: 'Phone',
name: 'phone',
type: 'string',
displayOptions: {
show: {
resource: ['thirdParty'],
operation: ['createContact'],
},
},
default: '',
description: 'The phone number of the contact',
},
{
displayName: 'Role',
name: 'role',
type: 'string',
displayOptions: {
show: {
resource: ['thirdParty'],
operation: ['createContact'],
},
},
default: '',
description: 'The role of the contact',
},
];
export async function execute(
this: IExecuteFunctions,
itemIndex: number,
): Promise<INodeExecutionData> {
const thirdPartyId = this.getNodeParameter('thirdPartyId', itemIndex) as string;
const fullName = this.getNodeParameter('fullName', itemIndex, '') as string;
const email = this.getNodeParameter('email', itemIndex, '') as string;
const phone = this.getNodeParameter('phone', itemIndex, '') as string;
const role = this.getNodeParameter('role', itemIndex, '') as string;
const query = `
mutation CreateThirdPartyContact($input: CreateThirdPartyContactInput!) {
createThirdPartyContact(input: $input) {
thirdPartyContactEdge {
node {
id
fullName
email
phone
role
createdAt
updatedAt
}
}
}
}
`;
const input: Record<string, unknown> = { thirdPartyId };
if (fullName) input.fullName = fullName;
if (email) input.email = email;
if (phone) input.phone = phone;
if (role) input.role = role;
const responseData = await proboApiRequest.call(this, query, { input });
return {
json: responseData,
pairedItem: { item: itemIndex },
};
}

View File

@@ -0,0 +1,151 @@
// Copyright (c) 2025 Probo Inc <hello@getprobo.com>.
//
// Permission to use, copy, modify, and/or distribute this software for any
// purpose with or without fee is hereby granted, provided that the above
// copyright notice and this permission notice appear in all copies.
//
// THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES WITH
// REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY
// AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT,
// INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM
// LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR
// OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
// PERFORMANCE OF THIS SOFTWARE.
import type { INodeProperties, IExecuteFunctions, INodeExecutionData } from 'n8n-workflow';
import { proboApiRequest } from '../../GenericFunctions';
export const description: INodeProperties[] = [
{
displayName: 'ThirdParty ID',
name: 'thirdPartyId',
type: 'string',
displayOptions: {
show: {
resource: ['thirdParty'],
operation: ['createRiskAssessment'],
},
},
default: '',
description: 'The ID of the thirdParty',
required: true,
},
{
displayName: 'Expires At',
name: 'expiresAt',
type: 'dateTime',
displayOptions: {
show: {
resource: ['thirdParty'],
operation: ['createRiskAssessment'],
},
},
default: '',
description: 'The expiration date of the risk assessment',
required: true,
},
{
displayName: 'Data Sensitivity',
name: 'dataSensitivity',
type: 'options',
displayOptions: {
show: {
resource: ['thirdParty'],
operation: ['createRiskAssessment'],
},
},
options: [
{ name: 'Critical', value: 'CRITICAL' },
{ name: 'High', value: 'HIGH' },
{ name: 'Low', value: 'LOW' },
{ name: 'Medium', value: 'MEDIUM' },
{ name: 'None', value: 'NONE' },
],
default: 'LOW',
description: 'The data sensitivity level',
required: true,
},
{
displayName: 'Business Impact',
name: 'businessImpact',
type: 'options',
displayOptions: {
show: {
resource: ['thirdParty'],
operation: ['createRiskAssessment'],
},
},
options: [
{ name: 'Critical', value: 'CRITICAL' },
{ name: 'High', value: 'HIGH' },
{ name: 'Low', value: 'LOW' },
{ name: 'Medium', value: 'MEDIUM' },
],
default: 'LOW',
description: 'The business impact level',
required: true,
},
{
displayName: 'Notes',
name: 'notes',
type: 'string',
typeOptions: {
rows: 4,
},
displayOptions: {
show: {
resource: ['thirdParty'],
operation: ['createRiskAssessment'],
},
},
default: '',
description: 'Additional notes for the risk assessment',
},
];
export async function execute(
this: IExecuteFunctions,
itemIndex: number,
): Promise<INodeExecutionData> {
const thirdPartyId = this.getNodeParameter('thirdPartyId', itemIndex) as string;
const expiresAtRaw = this.getNodeParameter('expiresAt', itemIndex) as string;
const dataSensitivity = this.getNodeParameter('dataSensitivity', itemIndex) as string;
const businessImpact = this.getNodeParameter('businessImpact', itemIndex) as string;
const notes = this.getNodeParameter('notes', itemIndex, '') as string;
// Ensure expiresAt is in RFC3339 format
const expiresAt = new Date(expiresAtRaw).toISOString();
const query = `
mutation CreateThirdPartyRiskAssessment($input: CreateThirdPartyRiskAssessmentInput!) {
createThirdPartyRiskAssessment(input: $input) {
thirdPartyRiskAssessmentEdge {
node {
id
expiresAt
dataSensitivity
businessImpact
notes
createdAt
updatedAt
}
}
}
}
`;
const input: Record<string, unknown> = {
thirdPartyId,
expiresAt,
dataSensitivity,
businessImpact,
};
if (notes) input.notes = notes;
const responseData = await proboApiRequest.call(this, query, { input });
return {
json: responseData,
pairedItem: { item: itemIndex },
};
}

View File

@@ -0,0 +1,101 @@
// Copyright (c) 2025 Probo Inc <hello@getprobo.com>.
//
// Permission to use, copy, modify, and/or distribute this software for any
// purpose with or without fee is hereby granted, provided that the above
// copyright notice and this permission notice appear in all copies.
//
// THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES WITH
// REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY
// AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT,
// INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM
// LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR
// OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
// PERFORMANCE OF THIS SOFTWARE.
import type { INodeProperties, IExecuteFunctions, INodeExecutionData } from 'n8n-workflow';
import { proboApiRequest } from '../../GenericFunctions';
export const description: INodeProperties[] = [
{
displayName: 'ThirdParty ID',
name: 'thirdPartyId',
type: 'string',
displayOptions: {
show: {
resource: ['thirdParty'],
operation: ['createService'],
},
},
default: '',
description: 'The ID of the thirdParty',
required: true,
},
{
displayName: 'Name',
name: 'name',
type: 'string',
displayOptions: {
show: {
resource: ['thirdParty'],
operation: ['createService'],
},
},
default: '',
description: 'The name of the thirdParty service',
required: true,
},
{
displayName: 'Description',
name: 'description',
type: 'string',
typeOptions: {
rows: 4,
},
displayOptions: {
show: {
resource: ['thirdParty'],
operation: ['createService'],
},
},
default: '',
description: 'The description of the thirdParty service',
},
];
export async function execute(
this: IExecuteFunctions,
itemIndex: number,
): Promise<INodeExecutionData> {
const thirdPartyId = this.getNodeParameter('thirdPartyId', itemIndex) as string;
const name = this.getNodeParameter('name', itemIndex) as string;
const description = this.getNodeParameter('description', itemIndex, '') as string;
const query = `
mutation CreateThirdPartyService($input: CreateThirdPartyServiceInput!) {
createThirdPartyService(input: $input) {
thirdPartyServiceEdge {
node {
id
name
description
createdAt
updatedAt
}
}
}
}
`;
const input: Record<string, unknown> = {
thirdPartyId,
name,
};
if (description) input.description = description;
const responseData = await proboApiRequest.call(this, query, { input });
return {
json: responseData,
pairedItem: { item: itemIndex },
};
}

View File

@@ -0,0 +1,56 @@
// Copyright (c) 2025 Probo Inc <hello@getprobo.com>.
//
// Permission to use, copy, modify, and/or distribute this software for any
// purpose with or without fee is hereby granted, provided that the above
// copyright notice and this permission notice appear in all copies.
//
// THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES WITH
// REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY
// AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT,
// INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM
// LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR
// OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
// PERFORMANCE OF THIS SOFTWARE.
import type { INodeProperties, IExecuteFunctions, INodeExecutionData } from 'n8n-workflow';
import { proboApiRequest } from '../../GenericFunctions';
export const description: INodeProperties[] = [
{
displayName: 'ThirdParty ID',
name: 'thirdPartyId',
type: 'string',
displayOptions: {
show: {
resource: ['thirdParty'],
operation: ['delete'],
},
},
default: '',
description: 'The ID of the thirdParty to delete',
required: true,
},
];
export async function execute(
this: IExecuteFunctions,
itemIndex: number,
): Promise<INodeExecutionData> {
const thirdPartyId = this.getNodeParameter('thirdPartyId', itemIndex) as string;
const query = `
mutation DeleteThirdParty($input: DeleteThirdPartyInput!) {
deleteThirdParty(input: $input) {
deletedThirdPartyId
}
}
`;
const responseData = await proboApiRequest.call(this, query, { input: { thirdPartyId } });
return {
json: responseData,
pairedItem: { item: itemIndex },
};
}

View File

@@ -0,0 +1,55 @@
// Copyright (c) 2025-2026 Probo Inc <hello@getprobo.com>.
//
// Permission to use, copy, modify, and/or distribute this software for any
// purpose with or without fee is hereby granted, provided that the above
// copyright notice and this permission notice appear in all copies.
//
// THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES WITH
// REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY
// AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT,
// INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM
// LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR
// OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
// PERFORMANCE OF THIS SOFTWARE.
import type { INodeProperties, IExecuteFunctions, INodeExecutionData } from 'n8n-workflow';
import { proboApiRequest } from '../../GenericFunctions';
export const description: INodeProperties[] = [
{
displayName: 'ThirdParty ID',
name: 'thirdPartyId',
type: 'string',
displayOptions: {
show: {
resource: ['thirdParty'],
operation: ['deleteBusinessAssociateAgreement'],
},
},
default: '',
description: 'The ID of the thirdParty',
required: true,
},
];
export async function execute(
this: IExecuteFunctions,
itemIndex: number,
): Promise<INodeExecutionData> {
const thirdPartyId = this.getNodeParameter('thirdPartyId', itemIndex) as string;
const query = `
mutation DeleteThirdPartyBusinessAssociateAgreement($input: DeleteThirdPartyBusinessAssociateAgreementInput!) {
deleteThirdPartyBusinessAssociateAgreement(input: $input) {
deletedThirdPartyBusinessAssociateAgreementId
}
}
`;
const responseData = await proboApiRequest.call(this, query, { input: { thirdPartyId } });
return {
json: responseData,
pairedItem: { item: itemIndex },
};
}

View File

@@ -0,0 +1,55 @@
// Copyright (c) 2025-2026 Probo Inc <hello@getprobo.com>.
//
// Permission to use, copy, modify, and/or distribute this software for any
// purpose with or without fee is hereby granted, provided that the above
// copyright notice and this permission notice appear in all copies.
//
// THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES WITH
// REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY
// AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT,
// INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM
// LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR
// OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
// PERFORMANCE OF THIS SOFTWARE.
import type { INodeProperties, IExecuteFunctions, INodeExecutionData } from 'n8n-workflow';
import { proboApiRequest } from '../../GenericFunctions';
export const description: INodeProperties[] = [
{
displayName: 'ThirdParty Compliance Report ID',
name: 'thirdPartyComplianceReportId',
type: 'string',
displayOptions: {
show: {
resource: ['thirdParty'],
operation: ['deleteComplianceReport'],
},
},
default: '',
description: 'The ID of the thirdParty compliance report to delete',
required: true,
},
];
export async function execute(
this: IExecuteFunctions,
itemIndex: number,
): Promise<INodeExecutionData> {
const thirdPartyComplianceReportId = this.getNodeParameter('thirdPartyComplianceReportId', itemIndex) as string;
const query = `
mutation DeleteThirdPartyComplianceReport($input: DeleteThirdPartyComplianceReportInput!) {
deleteThirdPartyComplianceReport(input: $input) {
deletedThirdPartyComplianceReportId
}
}
`;
const responseData = await proboApiRequest.call(this, query, { input: { thirdPartyComplianceReportId } });
return {
json: responseData,
pairedItem: { item: itemIndex },
};
}

View File

@@ -0,0 +1,55 @@
// Copyright (c) 2026 Probo Inc <hello@getprobo.com>.
//
// Permission to use, copy, modify, and/or distribute this software for any
// purpose with or without fee is hereby granted, provided that the above
// copyright notice and this permission notice appear in all copies.
//
// THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES WITH
// REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY
// AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT,
// INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM
// LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR
// OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
// PERFORMANCE OF THIS SOFTWARE.
import type { INodeProperties, IExecuteFunctions, INodeExecutionData } from 'n8n-workflow';
import { proboApiRequest } from '../../GenericFunctions';
export const description: INodeProperties[] = [
{
displayName: 'ThirdParty Contact ID',
name: 'thirdPartyContactId',
type: 'string',
displayOptions: {
show: {
resource: ['thirdParty'],
operation: ['deleteContact'],
},
},
default: '',
description: 'The ID of the thirdParty contact to delete',
required: true,
},
];
export async function execute(
this: IExecuteFunctions,
itemIndex: number,
): Promise<INodeExecutionData> {
const thirdPartyContactId = this.getNodeParameter('thirdPartyContactId', itemIndex) as string;
const query = `
mutation DeleteThirdPartyContact($input: DeleteThirdPartyContactInput!) {
deleteThirdPartyContact(input: $input) {
deletedThirdPartyContactId
}
}
`;
const responseData = await proboApiRequest.call(this, query, { input: { thirdPartyContactId } });
return {
json: responseData,
pairedItem: { item: itemIndex },
};
}

View File

@@ -0,0 +1,55 @@
// Copyright (c) 2025-2026 Probo Inc <hello@getprobo.com>.
//
// Permission to use, copy, modify, and/or distribute this software for any
// purpose with or without fee is hereby granted, provided that the above
// copyright notice and this permission notice appear in all copies.
//
// THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES WITH
// REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY
// AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT,
// INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM
// LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR
// OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
// PERFORMANCE OF THIS SOFTWARE.
import type { INodeProperties, IExecuteFunctions, INodeExecutionData } from 'n8n-workflow';
import { proboApiRequest } from '../../GenericFunctions';
export const description: INodeProperties[] = [
{
displayName: 'ThirdParty ID',
name: 'thirdPartyId',
type: 'string',
displayOptions: {
show: {
resource: ['thirdParty'],
operation: ['deleteDataPrivacyAgreement'],
},
},
default: '',
description: 'The ID of the thirdParty',
required: true,
},
];
export async function execute(
this: IExecuteFunctions,
itemIndex: number,
): Promise<INodeExecutionData> {
const thirdPartyId = this.getNodeParameter('thirdPartyId', itemIndex) as string;
const query = `
mutation DeleteThirdPartyDataPrivacyAgreement($input: DeleteThirdPartyDataPrivacyAgreementInput!) {
deleteThirdPartyDataPrivacyAgreement(input: $input) {
deletedThirdPartyDataPrivacyAgreementId
}
}
`;
const responseData = await proboApiRequest.call(this, query, { input: { thirdPartyId } });
return {
json: responseData,
pairedItem: { item: itemIndex },
};
}

View File

@@ -0,0 +1,55 @@
// Copyright (c) 2025 Probo Inc <hello@getprobo.com>.
//
// Permission to use, copy, modify, and/or distribute this software for any
// purpose with or without fee is hereby granted, provided that the above
// copyright notice and this permission notice appear in all copies.
//
// THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES WITH
// REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY
// AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT,
// INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM
// LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR
// OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
// PERFORMANCE OF THIS SOFTWARE.
import type { INodeProperties, IExecuteFunctions, INodeExecutionData } from 'n8n-workflow';
import { proboApiRequest } from '../../GenericFunctions';
export const description: INodeProperties[] = [
{
displayName: 'ThirdParty Service ID',
name: 'thirdPartyServiceId',
type: 'string',
displayOptions: {
show: {
resource: ['thirdParty'],
operation: ['deleteService'],
},
},
default: '',
description: 'The ID of the thirdParty service to delete',
required: true,
},
];
export async function execute(
this: IExecuteFunctions,
itemIndex: number,
): Promise<INodeExecutionData> {
const thirdPartyServiceId = this.getNodeParameter('thirdPartyServiceId', itemIndex) as string;
const query = `
mutation DeleteThirdPartyService($input: DeleteThirdPartyServiceInput!) {
deleteThirdPartyService(input: $input) {
deletedThirdPartyServiceId
}
}
`;
const responseData = await proboApiRequest.call(this, query, { input: { thirdPartyServiceId } });
return {
json: responseData,
pairedItem: { item: itemIndex },
};
}

View File

@@ -0,0 +1,149 @@
// Copyright (c) 2025 Probo Inc <hello@getprobo.com>.
//
// Permission to use, copy, modify, and/or distribute this software for any
// purpose with or without fee is hereby granted, provided that the above
// copyright notice and this permission notice appear in all copies.
//
// THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES WITH
// REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY
// AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT,
// INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM
// LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR
// OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
// PERFORMANCE OF THIS SOFTWARE.
import type { INodeProperties, IExecuteFunctions, INodeExecutionData } from 'n8n-workflow';
import { proboApiRequest } from '../../GenericFunctions';
export const description: INodeProperties[] = [
{
displayName: 'ThirdParty ID',
name: 'thirdPartyId',
type: 'string',
displayOptions: {
show: {
resource: ['thirdParty'],
operation: ['get'],
},
},
default: '',
description: 'The ID of the thirdParty',
required: true,
},
{
displayName: 'Options',
name: 'options',
type: 'collection',
placeholder: 'Add Option',
default: {},
displayOptions: {
show: {
resource: ['thirdParty'],
operation: ['get'],
},
},
options: [
{
displayName: 'Include Organization',
name: 'includeOrganization',
type: 'boolean',
default: false,
description: 'Whether to include organization in the response',
},
{
displayName: 'Include Business Owner',
name: 'includeBusinessOwner',
type: 'boolean',
default: false,
description: 'Whether to include business owner in the response',
},
{
displayName: 'Include Security Owner',
name: 'includeSecurityOwner',
type: 'boolean',
default: false,
description: 'Whether to include security owner in the response',
},
],
},
];
export async function execute(
this: IExecuteFunctions,
itemIndex: number,
): Promise<INodeExecutionData> {
const thirdPartyId = this.getNodeParameter('thirdPartyId', itemIndex) as string;
const options = this.getNodeParameter('options', itemIndex, {}) as {
includeOrganization?: boolean;
includeBusinessOwner?: boolean;
includeSecurityOwner?: boolean;
};
const organizationFragment = options.includeOrganization
? `organization {
id
name
}`
: '';
const businessOwnerFragment = options.includeBusinessOwner
? `businessOwner {
id
fullName
emailAddress
}`
: '';
const securityOwnerFragment = options.includeSecurityOwner
? `securityOwner {
id
fullName
emailAddress
}`
: '';
const query = `
query GetThirdParty($thirdPartyId: ID!) {
node(id: $thirdPartyId) {
... on ThirdParty {
id
name
description
category
websiteUrl
legalName
headquarterAddress
statusPageUrl
termsOfServiceUrl
privacyPolicyUrl
serviceLevelAgreementUrl
dataProcessingAgreementUrl
businessAssociateAgreementUrl
subprocessorsListUrl
securityPageUrl
trustPageUrl
certifications
countries
showOnTrustCenter
${organizationFragment}
${businessOwnerFragment}
${securityOwnerFragment}
createdAt
updatedAt
}
}
}
`;
const variables = {
thirdPartyId,
};
const responseData = await proboApiRequest.call(this, query, variables);
return {
json: responseData,
pairedItem: { item: itemIndex },
};
}

View File

@@ -0,0 +1,198 @@
// Copyright (c) 2025 Probo Inc <hello@getprobo.com>.
//
// Permission to use, copy, modify, and/or distribute this software for any
// purpose with or without fee is hereby granted, provided that the above
// copyright notice and this permission notice appear in all copies.
//
// THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES WITH
// REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY
// AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT,
// INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM
// LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR
// OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
// PERFORMANCE OF THIS SOFTWARE.
import type { INodeProperties, IExecuteFunctions, INodeExecutionData, IDataObject } from 'n8n-workflow';
import { proboApiRequestAllItems } from '../../GenericFunctions';
export const description: INodeProperties[] = [
{
displayName: 'Organization ID',
name: 'organizationId',
type: 'string',
displayOptions: {
show: {
resource: ['thirdParty'],
operation: ['getAll'],
},
},
default: '',
description: 'The ID of the organization',
required: true,
},
{
displayName: 'Return All',
name: 'returnAll',
type: 'boolean',
displayOptions: {
show: {
resource: ['thirdParty'],
operation: ['getAll'],
},
},
default: false,
description: 'Whether to return all results or only up to a given limit',
},
{
displayName: 'Limit',
name: 'limit',
type: 'number',
displayOptions: {
show: {
resource: ['thirdParty'],
operation: ['getAll'],
returnAll: [false],
},
},
typeOptions: {
minValue: 1,
},
default: 50,
description: 'Max number of results to return',
},
{
displayName: 'Options',
name: 'options',
type: 'collection',
placeholder: 'Add Option',
default: {},
displayOptions: {
show: {
resource: ['thirdParty'],
operation: ['getAll'],
},
},
options: [
{
displayName: 'Include Organization',
name: 'includeOrganization',
type: 'boolean',
default: false,
description: 'Whether to include organization in the response',
},
{
displayName: 'Include Business Owner',
name: 'includeBusinessOwner',
type: 'boolean',
default: false,
description: 'Whether to include business owner in the response',
},
{
displayName: 'Include Security Owner',
name: 'includeSecurityOwner',
type: 'boolean',
default: false,
description: 'Whether to include security owner in the response',
},
],
},
];
export async function execute(
this: IExecuteFunctions,
itemIndex: number,
): Promise<INodeExecutionData> {
const organizationId = this.getNodeParameter('organizationId', itemIndex) as string;
const returnAll = this.getNodeParameter('returnAll', itemIndex) as boolean;
const limit = this.getNodeParameter('limit', itemIndex, 50) as number;
const options = this.getNodeParameter('options', itemIndex, {}) as {
includeOrganization?: boolean;
includeBusinessOwner?: boolean;
includeSecurityOwner?: boolean;
};
const organizationFragment = options.includeOrganization
? `organization {
id
name
}`
: '';
const businessOwnerFragment = options.includeBusinessOwner
? `businessOwner {
id
fullName
emailAddress
}`
: '';
const securityOwnerFragment = options.includeSecurityOwner
? `securityOwner {
id
fullName
emailAddress
}`
: '';
const query = `
query GetThirdParties($organizationId: ID!, $first: Int, $after: CursorKey) {
node(id: $organizationId) {
... on Organization {
thirdParties(first: $first, after: $after) {
edges {
node {
id
name
description
category
websiteUrl
legalName
headquarterAddress
statusPageUrl
termsOfServiceUrl
privacyPolicyUrl
serviceLevelAgreementUrl
dataProcessingAgreementUrl
businessAssociateAgreementUrl
subprocessorsListUrl
securityPageUrl
trustPageUrl
certifications
countries
showOnTrustCenter
${organizationFragment}
${businessOwnerFragment}
${securityOwnerFragment}
createdAt
updatedAt
}
}
pageInfo {
hasNextPage
endCursor
}
}
}
}
}
`;
const thirdParties = await proboApiRequestAllItems.call(
this,
query,
{ organizationId },
(response) => {
const data = response?.data as IDataObject | undefined;
const node = data?.node as IDataObject | undefined;
return node?.thirdParties as IDataObject | undefined;
},
returnAll,
limit,
);
return {
json: { thirdParties },
pairedItem: { item: itemIndex },
};
}

View File

@@ -0,0 +1,115 @@
// Copyright (c) 2025-2026 Probo Inc <hello@getprobo.com>.
//
// Permission to use, copy, modify, and/or distribute this software for any
// purpose with or without fee is hereby granted, provided that the above
// copyright notice and this permission notice appear in all copies.
//
// THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES WITH
// REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY
// AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT,
// INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM
// LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR
// OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
// PERFORMANCE OF THIS SOFTWARE.
import type { INodeProperties, IExecuteFunctions, INodeExecutionData, IDataObject } from 'n8n-workflow';
import { proboApiRequestAllItems } from '../../GenericFunctions';
export const description: INodeProperties[] = [
{
displayName: 'ThirdParty ID',
name: 'thirdPartyId',
type: 'string',
displayOptions: {
show: {
resource: ['thirdParty'],
operation: ['getAllComplianceReports'],
},
},
default: '',
description: 'The ID of the thirdParty',
required: true,
},
{
displayName: 'Return All',
name: 'returnAll',
type: 'boolean',
displayOptions: {
show: {
resource: ['thirdParty'],
operation: ['getAllComplianceReports'],
},
},
default: false,
description: 'Whether to return all results or only up to a given limit',
},
{
displayName: 'Limit',
name: 'limit',
type: 'number',
displayOptions: {
show: {
resource: ['thirdParty'],
operation: ['getAllComplianceReports'],
returnAll: [false],
},
},
typeOptions: {
minValue: 1,
},
default: 50,
description: 'Max number of results to return',
},
];
export async function execute(
this: IExecuteFunctions,
itemIndex: number,
): Promise<INodeExecutionData> {
const thirdPartyId = this.getNodeParameter('thirdPartyId', itemIndex) as string;
const returnAll = this.getNodeParameter('returnAll', itemIndex) as boolean;
const limit = this.getNodeParameter('limit', itemIndex, 50) as number;
const query = `
query GetThirdPartyComplianceReports($thirdPartyId: ID!, $first: Int, $after: CursorKey) {
node(id: $thirdPartyId) {
... on ThirdParty {
complianceReports(first: $first, after: $after) {
edges {
node {
id
reportDate
validUntil
reportName
createdAt
updatedAt
}
}
pageInfo {
hasNextPage
endCursor
}
}
}
}
}
`;
const thirdPartyComplianceReports = await proboApiRequestAllItems.call(
this,
query,
{ thirdPartyId },
(response) => {
const data = response?.data as IDataObject | undefined;
const node = data?.node as IDataObject | undefined;
return node?.complianceReports as IDataObject | undefined;
},
returnAll,
limit,
);
return {
json: { thirdPartyComplianceReports },
pairedItem: { item: itemIndex },
};
}

View File

@@ -0,0 +1,149 @@
// Copyright (c) 2026 Probo Inc <hello@getprobo.com>.
//
// Permission to use, copy, modify, and/or distribute this software for any
// purpose with or without fee is hereby granted, provided that the above
// copyright notice and this permission notice appear in all copies.
//
// THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES WITH
// REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY
// AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT,
// INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM
// LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR
// OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
// PERFORMANCE OF THIS SOFTWARE.
import type { INodeProperties, IExecuteFunctions, INodeExecutionData, IDataObject } from 'n8n-workflow';
import { proboApiRequestAllItems } from '../../GenericFunctions';
export const description: INodeProperties[] = [
{
displayName: 'ThirdParty ID',
name: 'thirdPartyId',
type: 'string',
displayOptions: {
show: {
resource: ['thirdParty'],
operation: ['getAllContacts'],
},
},
default: '',
description: 'The ID of the thirdParty',
required: true,
},
{
displayName: 'Return All',
name: 'returnAll',
type: 'boolean',
displayOptions: {
show: {
resource: ['thirdParty'],
operation: ['getAllContacts'],
},
},
default: false,
description: 'Whether to return all results or only up to a given limit',
},
{
displayName: 'Limit',
name: 'limit',
type: 'number',
displayOptions: {
show: {
resource: ['thirdParty'],
operation: ['getAllContacts'],
returnAll: [false],
},
},
typeOptions: {
minValue: 1,
},
default: 50,
description: 'Max number of results to return',
},
{
displayName: 'Options',
name: 'options',
type: 'collection',
placeholder: 'Add Option',
default: {},
displayOptions: {
show: {
resource: ['thirdParty'],
operation: ['getAllContacts'],
},
},
options: [
{
displayName: 'Include ThirdParty',
name: 'includeThirdParty',
type: 'boolean',
default: false,
description: 'Whether to include thirdParty in the response',
},
],
},
];
export async function execute(
this: IExecuteFunctions,
itemIndex: number,
): Promise<INodeExecutionData> {
const thirdPartyId = this.getNodeParameter('thirdPartyId', itemIndex) as string;
const returnAll = this.getNodeParameter('returnAll', itemIndex) as boolean;
const limit = this.getNodeParameter('limit', itemIndex, 50) as number;
const options = this.getNodeParameter('options', itemIndex, {}) as {
includeThirdParty?: boolean;
};
const thirdPartyFragment = options.includeThirdParty
? `thirdParty {
id
name
}`
: '';
const query = `
query GetThirdPartyContacts($thirdPartyId: ID!, $first: Int, $after: CursorKey) {
node(id: $thirdPartyId) {
... on ThirdParty {
contacts(first: $first, after: $after) {
edges {
node {
id
fullName
email
phone
role
${thirdPartyFragment}
createdAt
updatedAt
}
}
pageInfo {
hasNextPage
endCursor
}
}
}
}
}
`;
const thirdPartyContacts = await proboApiRequestAllItems.call(
this,
query,
{ thirdPartyId },
(response) => {
const data = response?.data as IDataObject | undefined;
const node = data?.node as IDataObject | undefined;
return node?.contacts as IDataObject | undefined;
},
returnAll,
limit,
);
return {
json: { thirdPartyContacts },
pairedItem: { item: itemIndex },
};
}

View File

@@ -0,0 +1,149 @@
// Copyright (c) 2025 Probo Inc <hello@getprobo.com>.
//
// Permission to use, copy, modify, and/or distribute this software for any
// purpose with or without fee is hereby granted, provided that the above
// copyright notice and this permission notice appear in all copies.
//
// THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES WITH
// REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY
// AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT,
// INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM
// LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR
// OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
// PERFORMANCE OF THIS SOFTWARE.
import type { INodeProperties, IExecuteFunctions, INodeExecutionData, IDataObject } from 'n8n-workflow';
import { proboApiRequestAllItems } from '../../GenericFunctions';
export const description: INodeProperties[] = [
{
displayName: 'ThirdParty ID',
name: 'thirdPartyId',
type: 'string',
displayOptions: {
show: {
resource: ['thirdParty'],
operation: ['getAllRiskAssessments'],
},
},
default: '',
description: 'The ID of the thirdParty',
required: true,
},
{
displayName: 'Return All',
name: 'returnAll',
type: 'boolean',
displayOptions: {
show: {
resource: ['thirdParty'],
operation: ['getAllRiskAssessments'],
},
},
default: false,
description: 'Whether to return all results or only up to a given limit',
},
{
displayName: 'Limit',
name: 'limit',
type: 'number',
displayOptions: {
show: {
resource: ['thirdParty'],
operation: ['getAllRiskAssessments'],
returnAll: [false],
},
},
typeOptions: {
minValue: 1,
},
default: 50,
description: 'Max number of results to return',
},
{
displayName: 'Options',
name: 'options',
type: 'collection',
placeholder: 'Add Option',
default: {},
displayOptions: {
show: {
resource: ['thirdParty'],
operation: ['getAllRiskAssessments'],
},
},
options: [
{
displayName: 'Include ThirdParty',
name: 'includeThirdParty',
type: 'boolean',
default: false,
description: 'Whether to include thirdParty in the response',
},
],
},
];
export async function execute(
this: IExecuteFunctions,
itemIndex: number,
): Promise<INodeExecutionData> {
const thirdPartyId = this.getNodeParameter('thirdPartyId', itemIndex) as string;
const returnAll = this.getNodeParameter('returnAll', itemIndex) as boolean;
const limit = this.getNodeParameter('limit', itemIndex, 50) as number;
const options = this.getNodeParameter('options', itemIndex, {}) as {
includeThirdParty?: boolean;
};
const thirdPartyFragment = options.includeThirdParty
? `thirdParty {
id
name
}`
: '';
const query = `
query GetThirdPartyRiskAssessments($thirdPartyId: ID!, $first: Int, $after: CursorKey) {
node(id: $thirdPartyId) {
... on ThirdParty {
riskAssessments(first: $first, after: $after) {
edges {
node {
id
expiresAt
dataSensitivity
businessImpact
notes
${thirdPartyFragment}
createdAt
updatedAt
}
}
pageInfo {
hasNextPage
endCursor
}
}
}
}
}
`;
const thirdPartyRiskAssessments = await proboApiRequestAllItems.call(
this,
query,
{ thirdPartyId },
(response) => {
const data = response?.data as IDataObject | undefined;
const node = data?.node as IDataObject | undefined;
return node?.riskAssessments as IDataObject | undefined;
},
returnAll,
limit,
);
return {
json: { thirdPartyRiskAssessments },
pairedItem: { item: itemIndex },
};
}

View File

@@ -0,0 +1,147 @@
// Copyright (c) 2025 Probo Inc <hello@getprobo.com>.
//
// Permission to use, copy, modify, and/or distribute this software for any
// purpose with or without fee is hereby granted, provided that the above
// copyright notice and this permission notice appear in all copies.
//
// THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES WITH
// REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY
// AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT,
// INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM
// LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR
// OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
// PERFORMANCE OF THIS SOFTWARE.
import type { INodeProperties, IExecuteFunctions, INodeExecutionData, IDataObject } from 'n8n-workflow';
import { proboApiRequestAllItems } from '../../GenericFunctions';
export const description: INodeProperties[] = [
{
displayName: 'ThirdParty ID',
name: 'thirdPartyId',
type: 'string',
displayOptions: {
show: {
resource: ['thirdParty'],
operation: ['getAllServices'],
},
},
default: '',
description: 'The ID of the thirdParty',
required: true,
},
{
displayName: 'Return All',
name: 'returnAll',
type: 'boolean',
displayOptions: {
show: {
resource: ['thirdParty'],
operation: ['getAllServices'],
},
},
default: false,
description: 'Whether to return all results or only up to a given limit',
},
{
displayName: 'Limit',
name: 'limit',
type: 'number',
displayOptions: {
show: {
resource: ['thirdParty'],
operation: ['getAllServices'],
returnAll: [false],
},
},
typeOptions: {
minValue: 1,
},
default: 50,
description: 'Max number of results to return',
},
{
displayName: 'Options',
name: 'options',
type: 'collection',
placeholder: 'Add Option',
default: {},
displayOptions: {
show: {
resource: ['thirdParty'],
operation: ['getAllServices'],
},
},
options: [
{
displayName: 'Include ThirdParty',
name: 'includeThirdParty',
type: 'boolean',
default: false,
description: 'Whether to include thirdParty in the response',
},
],
},
];
export async function execute(
this: IExecuteFunctions,
itemIndex: number,
): Promise<INodeExecutionData> {
const thirdPartyId = this.getNodeParameter('thirdPartyId', itemIndex) as string;
const returnAll = this.getNodeParameter('returnAll', itemIndex) as boolean;
const limit = this.getNodeParameter('limit', itemIndex, 50) as number;
const options = this.getNodeParameter('options', itemIndex, {}) as {
includeThirdParty?: boolean;
};
const thirdPartyFragment = options.includeThirdParty
? `thirdParty {
id
name
}`
: '';
const query = `
query GetThirdPartyServices($thirdPartyId: ID!, $first: Int, $after: CursorKey) {
node(id: $thirdPartyId) {
... on ThirdParty {
services(first: $first, after: $after) {
edges {
node {
id
name
description
${thirdPartyFragment}
createdAt
updatedAt
}
}
pageInfo {
hasNextPage
endCursor
}
}
}
}
}
`;
const thirdPartyServices = await proboApiRequestAllItems.call(
this,
query,
{ thirdPartyId },
(response) => {
const data = response?.data as IDataObject | undefined;
const node = data?.node as IDataObject | undefined;
return node?.services as IDataObject | undefined;
},
returnAll,
limit,
);
return {
json: { thirdPartyServices },
pairedItem: { item: itemIndex },
};
}

View File

@@ -0,0 +1,66 @@
// Copyright (c) 2025-2026 Probo Inc <hello@getprobo.com>.
//
// Permission to use, copy, modify, and/or distribute this software for any
// purpose with or without fee is hereby granted, provided that the above
// copyright notice and this permission notice appear in all copies.
//
// THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES WITH
// REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY
// AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT,
// INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM
// LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR
// OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
// PERFORMANCE OF THIS SOFTWARE.
import type { INodeProperties, IExecuteFunctions, INodeExecutionData } from 'n8n-workflow';
import { proboApiRequest } from '../../GenericFunctions';
export const description: INodeProperties[] = [
{
displayName: 'ThirdParty ID',
name: 'thirdPartyId',
type: 'string',
displayOptions: {
show: {
resource: ['thirdParty'],
operation: ['getBusinessAssociateAgreement'],
},
},
default: '',
description: 'The ID of the thirdParty',
required: true,
},
];
export async function execute(
this: IExecuteFunctions,
itemIndex: number,
): Promise<INodeExecutionData> {
const thirdPartyId = this.getNodeParameter('thirdPartyId', itemIndex) as string;
const query = `
query GetThirdPartyBusinessAssociateAgreement($thirdPartyId: ID!) {
node(id: $thirdPartyId) {
... on ThirdParty {
businessAssociateAgreement {
id
validFrom
validUntil
fileName
fileUrl
fileSize
createdAt
updatedAt
}
}
}
}
`;
const responseData = await proboApiRequest.call(this, query, { thirdPartyId });
return {
json: responseData,
pairedItem: { item: itemIndex },
};
}

View File

@@ -0,0 +1,96 @@
// Copyright (c) 2026 Probo Inc <hello@getprobo.com>.
//
// Permission to use, copy, modify, and/or distribute this software for any
// purpose with or without fee is hereby granted, provided that the above
// copyright notice and this permission notice appear in all copies.
//
// THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES WITH
// REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY
// AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT,
// INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM
// LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR
// OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
// PERFORMANCE OF THIS SOFTWARE.
import type { INodeProperties, IExecuteFunctions, INodeExecutionData } from 'n8n-workflow';
import { proboApiRequest } from '../../GenericFunctions';
export const description: INodeProperties[] = [
{
displayName: 'ThirdParty Contact ID',
name: 'thirdPartyContactId',
type: 'string',
displayOptions: {
show: {
resource: ['thirdParty'],
operation: ['getContact'],
},
},
default: '',
description: 'The ID of the thirdParty contact',
required: true,
},
{
displayName: 'Options',
name: 'options',
type: 'collection',
placeholder: 'Add Option',
default: {},
displayOptions: {
show: {
resource: ['thirdParty'],
operation: ['getContact'],
},
},
options: [
{
displayName: 'Include ThirdParty',
name: 'includeThirdParty',
type: 'boolean',
default: false,
description: 'Whether to include thirdParty in the response',
},
],
},
];
export async function execute(
this: IExecuteFunctions,
itemIndex: number,
): Promise<INodeExecutionData> {
const thirdPartyContactId = this.getNodeParameter('thirdPartyContactId', itemIndex) as string;
const options = this.getNodeParameter('options', itemIndex, {}) as {
includeThirdParty?: boolean;
};
const thirdPartyFragment = options.includeThirdParty
? `thirdParty {
id
name
}`
: '';
const query = `
query GetThirdPartyContact($thirdPartyContactId: ID!) {
node(id: $thirdPartyContactId) {
... on ThirdPartyContact {
id
fullName
email
phone
role
${thirdPartyFragment}
createdAt
updatedAt
}
}
}
`;
const responseData = await proboApiRequest.call(this, query, { thirdPartyContactId });
return {
json: responseData,
pairedItem: { item: itemIndex },
};
}

View File

@@ -0,0 +1,66 @@
// Copyright (c) 2025-2026 Probo Inc <hello@getprobo.com>.
//
// Permission to use, copy, modify, and/or distribute this software for any
// purpose with or without fee is hereby granted, provided that the above
// copyright notice and this permission notice appear in all copies.
//
// THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES WITH
// REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY
// AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT,
// INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM
// LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR
// OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
// PERFORMANCE OF THIS SOFTWARE.
import type { INodeProperties, IExecuteFunctions, INodeExecutionData } from 'n8n-workflow';
import { proboApiRequest } from '../../GenericFunctions';
export const description: INodeProperties[] = [
{
displayName: 'ThirdParty ID',
name: 'thirdPartyId',
type: 'string',
displayOptions: {
show: {
resource: ['thirdParty'],
operation: ['getDataPrivacyAgreement'],
},
},
default: '',
description: 'The ID of the thirdParty',
required: true,
},
];
export async function execute(
this: IExecuteFunctions,
itemIndex: number,
): Promise<INodeExecutionData> {
const thirdPartyId = this.getNodeParameter('thirdPartyId', itemIndex) as string;
const query = `
query GetThirdPartyDataPrivacyAgreement($thirdPartyId: ID!) {
node(id: $thirdPartyId) {
... on ThirdParty {
dataPrivacyAgreement {
id
validFrom
validUntil
fileName
fileUrl
fileSize
createdAt
updatedAt
}
}
}
}
`;
const responseData = await proboApiRequest.call(this, query, { thirdPartyId });
return {
json: responseData,
pairedItem: { item: itemIndex },
};
}

View File

@@ -0,0 +1,100 @@
// Copyright (c) 2025 Probo Inc <hello@getprobo.com>.
//
// Permission to use, copy, modify, and/or distribute this software for any
// purpose with or without fee is hereby granted, provided that the above
// copyright notice and this permission notice appear in all copies.
//
// THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES WITH
// REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY
// AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT,
// INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM
// LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR
// OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
// PERFORMANCE OF THIS SOFTWARE.
import type { INodeProperties, IExecuteFunctions, INodeExecutionData } from 'n8n-workflow';
import { proboApiRequest } from '../../GenericFunctions';
export const description: INodeProperties[] = [
{
displayName: 'ThirdParty Risk Assessment ID',
name: 'thirdPartyRiskAssessmentId',
type: 'string',
displayOptions: {
show: {
resource: ['thirdParty'],
operation: ['getRiskAssessment'],
},
},
default: '',
description: 'The ID of the thirdParty risk assessment',
required: true,
},
{
displayName: 'Options',
name: 'options',
type: 'collection',
placeholder: 'Add Option',
default: {},
displayOptions: {
show: {
resource: ['thirdParty'],
operation: ['getRiskAssessment'],
},
},
options: [
{
displayName: 'Include ThirdParty',
name: 'includeThirdParty',
type: 'boolean',
default: false,
description: 'Whether to include thirdParty in the response',
},
],
},
];
export async function execute(
this: IExecuteFunctions,
itemIndex: number,
): Promise<INodeExecutionData> {
const thirdPartyRiskAssessmentId = this.getNodeParameter('thirdPartyRiskAssessmentId', itemIndex) as string;
const options = this.getNodeParameter('options', itemIndex, {}) as {
includeThirdParty?: boolean;
};
const thirdPartyFragment = options.includeThirdParty
? `thirdParty {
id
name
}`
: '';
const query = `
query GetThirdPartyRiskAssessment($thirdPartyRiskAssessmentId: ID!) {
node(id: $thirdPartyRiskAssessmentId) {
... on ThirdPartyRiskAssessment {
id
expiresAt
dataSensitivity
businessImpact
notes
${thirdPartyFragment}
createdAt
updatedAt
}
}
}
`;
const variables = {
thirdPartyRiskAssessmentId,
};
const responseData = await proboApiRequest.call(this, query, variables);
return {
json: responseData,
pairedItem: { item: itemIndex },
};
}

View File

@@ -0,0 +1,98 @@
// Copyright (c) 2025 Probo Inc <hello@getprobo.com>.
//
// Permission to use, copy, modify, and/or distribute this software for any
// purpose with or without fee is hereby granted, provided that the above
// copyright notice and this permission notice appear in all copies.
//
// THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES WITH
// REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY
// AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT,
// INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM
// LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR
// OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
// PERFORMANCE OF THIS SOFTWARE.
import type { INodeProperties, IExecuteFunctions, INodeExecutionData } from 'n8n-workflow';
import { proboApiRequest } from '../../GenericFunctions';
export const description: INodeProperties[] = [
{
displayName: 'ThirdParty Service ID',
name: 'thirdPartyServiceId',
type: 'string',
displayOptions: {
show: {
resource: ['thirdParty'],
operation: ['getService'],
},
},
default: '',
description: 'The ID of the thirdParty service',
required: true,
},
{
displayName: 'Options',
name: 'options',
type: 'collection',
placeholder: 'Add Option',
default: {},
displayOptions: {
show: {
resource: ['thirdParty'],
operation: ['getService'],
},
},
options: [
{
displayName: 'Include ThirdParty',
name: 'includeThirdParty',
type: 'boolean',
default: false,
description: 'Whether to include thirdParty in the response',
},
],
},
];
export async function execute(
this: IExecuteFunctions,
itemIndex: number,
): Promise<INodeExecutionData> {
const thirdPartyServiceId = this.getNodeParameter('thirdPartyServiceId', itemIndex) as string;
const options = this.getNodeParameter('options', itemIndex, {}) as {
includeThirdParty?: boolean;
};
const thirdPartyFragment = options.includeThirdParty
? `thirdParty {
id
name
}`
: '';
const query = `
query GetThirdPartyService($thirdPartyServiceId: ID!) {
node(id: $thirdPartyServiceId) {
... on ThirdPartyService {
id
name
description
${thirdPartyFragment}
createdAt
updatedAt
}
}
}
`;
const variables = {
thirdPartyServiceId,
};
const responseData = await proboApiRequest.call(this, query, variables);
return {
json: responseData,
pairedItem: { item: itemIndex },
};
}

View File

@@ -0,0 +1,278 @@
// Copyright (c) 2025-2026 Probo Inc <hello@getprobo.com>.
//
// Permission to use, copy, modify, and/or distribute this software for any
// purpose with or without fee is hereby granted, provided that the above
// copyright notice and this permission notice appear in all copies.
//
// THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES WITH
// REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY
// AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT,
// INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM
// LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR
// OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
// PERFORMANCE OF THIS SOFTWARE.
import type { INodeProperties } from 'n8n-workflow';
import * as createOp from './create.operation';
import * as updateOp from './update.operation';
import * as deleteOp from './delete.operation';
import * as getOp from './get.operation';
import * as getAllOp from './getAll.operation';
import * as createContactOp from './createContact.operation';
import * as updateContactOp from './updateContact.operation';
import * as deleteContactOp from './deleteContact.operation';
import * as getContactOp from './getContact.operation';
import * as getAllContactsOp from './getAllContacts.operation';
import * as createServiceOp from './createService.operation';
import * as updateServiceOp from './updateService.operation';
import * as deleteServiceOp from './deleteService.operation';
import * as getServiceOp from './getService.operation';
import * as getAllServicesOp from './getAllServices.operation';
import * as createRiskAssessmentOp from './createRiskAssessment.operation';
import * as getRiskAssessmentOp from './getRiskAssessment.operation';
import * as getAllRiskAssessmentsOp from './getAllRiskAssessments.operation';
import * as getAllComplianceReportsOp from './getAllComplianceReports.operation';
import * as deleteComplianceReportOp from './deleteComplianceReport.operation';
import * as getBusinessAssociateAgreementOp from './getBusinessAssociateAgreement.operation';
import * as deleteBusinessAssociateAgreementOp from './deleteBusinessAssociateAgreement.operation';
import * as updateBusinessAssociateAgreementOp from './updateBusinessAssociateAgreement.operation';
import * as getDataPrivacyAgreementOp from './getDataPrivacyAgreement.operation';
import * as deleteDataPrivacyAgreementOp from './deleteDataPrivacyAgreement.operation';
import * as updateDataPrivacyAgreementOp from './updateDataPrivacyAgreement.operation';
import * as publishOp from './publish.operation';
export const description: INodeProperties[] = [
{
displayName: 'Operation',
name: 'operation',
type: 'options',
noDataExpression: true,
displayOptions: {
show: {
resource: ['thirdParty'],
},
},
options: [
{
name: 'Create',
value: 'create',
description: 'Create a new third party',
action: 'Create a third party',
},
{
name: 'Create Contact',
value: 'createContact',
description: 'Create a new third party contact',
action: 'Create a third party contact',
},
{
name: 'Create Risk Assessment',
value: 'createRiskAssessment',
description: 'Create a new third party risk assessment',
action: 'Create a third party risk assessment',
},
{
name: 'Create Service',
value: 'createService',
description: 'Create a new third party service',
action: 'Create a third party service',
},
{
name: 'Delete',
value: 'delete',
description: 'Delete a third party',
action: 'Delete a third party',
},
{
name: 'Delete Business Associate Agreement',
value: 'deleteBusinessAssociateAgreement',
description: 'Delete a third party business associate agreement',
action: 'Delete a third party business associate agreement',
},
{
name: 'Delete Compliance Report',
value: 'deleteComplianceReport',
description: 'Delete a third party compliance report',
action: 'Delete a third party compliance report',
},
{
name: 'Delete Contact',
value: 'deleteContact',
description: 'Delete a third party contact',
action: 'Delete a third party contact',
},
{
name: 'Delete Data Privacy Agreement',
value: 'deleteDataPrivacyAgreement',
description: 'Delete a third party data privacy agreement',
action: 'Delete a third party data privacy agreement',
},
{
name: 'Delete Service',
value: 'deleteService',
description: 'Delete a third party service',
action: 'Delete a third party service',
},
{
name: 'Get',
value: 'get',
description: 'Get a third party',
action: 'Get a third party',
},
{
name: 'Get Business Associate Agreement',
value: 'getBusinessAssociateAgreement',
description: 'Get a third party business associate agreement',
action: 'Get a third party business associate agreement',
},
{
name: 'Get Contact',
value: 'getContact',
description: 'Get a third party contact',
action: 'Get a third party contact',
},
{
name: 'Get Data Privacy Agreement',
value: 'getDataPrivacyAgreement',
description: 'Get a third party data privacy agreement',
action: 'Get a third party data privacy agreement',
},
{
name: 'Get Many',
value: 'getAll',
description: 'Get many third parties',
action: 'Get many third parties',
},
{
name: 'Get Many Compliance Reports',
value: 'getAllComplianceReports',
description: 'Get many third party compliance reports',
action: 'Get many third party compliance reports',
},
{
name: 'Get Many Contacts',
value: 'getAllContacts',
description: 'Get many third party contacts',
action: 'Get many third party contacts',
},
{
name: 'Get Many Risk Assessments',
value: 'getAllRiskAssessments',
description: 'Get many third party risk assessments',
action: 'Get many third party risk assessments',
},
{
name: 'Get Many Services',
value: 'getAllServices',
description: 'Get many third party services',
action: 'Get many third party services',
},
{
name: 'Get Risk Assessment',
value: 'getRiskAssessment',
description: 'Get a third party risk assessment',
action: 'Get a third party risk assessment',
},
{
name: 'Get Service',
value: 'getService',
description: 'Get a third party service',
action: 'Get a third party service',
},
{
name: 'Publish List',
value: 'publish',
description: 'Publish the third party register as a document version',
action: 'Publish the third party register',
},
{
name: 'Update',
value: 'update',
description: 'Update an existing third party',
action: 'Update a third party',
},
{
name: 'Update Business Associate Agreement',
value: 'updateBusinessAssociateAgreement',
description: 'Update a third party business associate agreement validity',
action: 'Update a third party business associate agreement',
},
{
name: 'Update Contact',
value: 'updateContact',
description: 'Update an existing third party contact',
action: 'Update a third party contact',
},
{
name: 'Update Data Privacy Agreement',
value: 'updateDataPrivacyAgreement',
description: 'Update a third party data privacy agreement validity',
action: 'Update a third party data privacy agreement',
},
{
name: 'Update Service',
value: 'updateService',
description: 'Update an existing third party service',
action: 'Update a third party service',
},
],
default: 'create',
},
...createOp.description,
...updateOp.description,
...deleteOp.description,
...getOp.description,
...getAllOp.description,
...createContactOp.description,
...updateContactOp.description,
...deleteContactOp.description,
...getContactOp.description,
...getAllContactsOp.description,
...createServiceOp.description,
...updateServiceOp.description,
...deleteServiceOp.description,
...getServiceOp.description,
...getAllServicesOp.description,
...createRiskAssessmentOp.description,
...getRiskAssessmentOp.description,
...getAllRiskAssessmentsOp.description,
...getAllComplianceReportsOp.description,
...deleteComplianceReportOp.description,
...getBusinessAssociateAgreementOp.description,
...deleteBusinessAssociateAgreementOp.description,
...updateBusinessAssociateAgreementOp.description,
...getDataPrivacyAgreementOp.description,
...deleteDataPrivacyAgreementOp.description,
...updateDataPrivacyAgreementOp.description,
...publishOp.description,
];
export {
createOp as create,
updateOp as update,
deleteOp as delete,
getOp as get,
getAllOp as getAll,
createContactOp as createContact,
updateContactOp as updateContact,
deleteContactOp as deleteContact,
getContactOp as getContact,
getAllContactsOp as getAllContacts,
createServiceOp as createService,
updateServiceOp as updateService,
deleteServiceOp as deleteService,
getServiceOp as getService,
getAllServicesOp as getAllServices,
createRiskAssessmentOp as createRiskAssessment,
getRiskAssessmentOp as getRiskAssessment,
getAllRiskAssessmentsOp as getAllRiskAssessments,
getAllComplianceReportsOp as getAllComplianceReports,
deleteComplianceReportOp as deleteComplianceReport,
getBusinessAssociateAgreementOp as getBusinessAssociateAgreement,
deleteBusinessAssociateAgreementOp as deleteBusinessAssociateAgreement,
updateBusinessAssociateAgreementOp as updateBusinessAssociateAgreement,
getDataPrivacyAgreementOp as getDataPrivacyAgreement,
deleteDataPrivacyAgreementOp as deleteDataPrivacyAgreement,
updateDataPrivacyAgreementOp as updateDataPrivacyAgreement,
publishOp as publish,
};

View File

@@ -0,0 +1,115 @@
// Copyright (c) 2026 Probo Inc <hello@getprobo.com>.
//
// Permission to use, copy, modify, and/or distribute this software for any
// purpose with or without fee is hereby granted, provided that the above
// copyright notice and this permission notice appear in all copies.
//
// THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES WITH
// REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY
// AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT,
// INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM
// LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR
// OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
// PERFORMANCE OF THIS SOFTWARE.
import type { INodeProperties, IExecuteFunctions, INodeExecutionData } from 'n8n-workflow';
import { proboApiRequest } from '../../GenericFunctions';
export const description: INodeProperties[] = [
{
displayName: 'Organization ID',
name: 'organizationId',
type: 'string',
displayOptions: {
show: {
resource: ['thirdParty'],
operation: ['publish'],
},
},
default: '',
description: 'The ID of the organization whose thirdParty list to publish',
required: true,
},
{
displayName: 'Approver IDs',
name: 'approverIds',
type: 'string',
displayOptions: {
show: {
resource: ['thirdParty'],
operation: ['publish'],
},
},
default: '',
description: 'Comma-separated list of approver profile IDs',
},
{
displayName: 'Minor',
name: 'minor',
type: 'boolean',
displayOptions: {
show: {
resource: ['thirdParty'],
operation: ['publish'],
},
},
default: false,
description: 'Whether to publish as a minor version. Approvers are ignored when set. The list must already have a published major version.',
},
];
export async function execute(
this: IExecuteFunctions,
itemIndex: number,
): Promise<INodeExecutionData> {
const organizationId = this.getNodeParameter('organizationId', itemIndex) as string;
const approverIds = this.getNodeParameter('approverIds', itemIndex, '') as string;
const minor = this.getNodeParameter('minor', itemIndex, false) as boolean;
const query = `
mutation PublishThirdPartyList($input: PublishThirdPartyListInput!) {
publishThirdPartyList(input: $input) {
documentEdge {
node {
id
status
currentPublishedMajor
currentPublishedMinor
createdAt
updatedAt
}
}
documentVersionEdge {
node {
id
title
major
minor
status
classification
documentType
publishedAt
createdAt
updatedAt
}
}
}
}
`;
const input: Record<string, unknown> = { organizationId, minor };
if (approverIds) {
input.approverIds = approverIds
.split(',')
.map(id => id.trim())
.filter(Boolean);
}
const responseData = await proboApiRequest.call(this, query, { input });
return {
json: responseData,
pairedItem: { item: itemIndex },
};
}

View File

@@ -0,0 +1,338 @@
// Copyright (c) 2025 Probo Inc <hello@getprobo.com>.
//
// Permission to use, copy, modify, and/or distribute this software for any
// purpose with or without fee is hereby granted, provided that the above
// copyright notice and this permission notice appear in all copies.
//
// THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES WITH
// REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY
// AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT,
// INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM
// LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR
// OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
// PERFORMANCE OF THIS SOFTWARE.
import type { INodeProperties, IExecuteFunctions, INodeExecutionData } from 'n8n-workflow';
import { proboApiRequest } from '../../GenericFunctions';
export const description: INodeProperties[] = [
{
displayName: 'ThirdParty ID',
name: 'thirdPartyId',
type: 'string',
displayOptions: {
show: {
resource: ['thirdParty'],
operation: ['update'],
},
},
default: '',
description: 'The ID of the thirdParty to update',
required: true,
},
{
displayName: 'Name',
name: 'name',
type: 'string',
displayOptions: {
show: {
resource: ['thirdParty'],
operation: ['update'],
},
},
default: '',
description: 'The name of the thirdParty',
},
{
displayName: 'Description',
name: 'description',
type: 'string',
typeOptions: {
rows: 4,
},
displayOptions: {
show: {
resource: ['thirdParty'],
operation: ['update'],
},
},
default: '',
description: 'The description of the thirdParty',
},
{
displayName: 'Category',
name: 'category',
type: 'string',
displayOptions: {
show: {
resource: ['thirdParty'],
operation: ['update'],
},
},
default: '',
description: 'The category of the thirdParty',
},
{
displayName: 'Website URL',
name: 'websiteUrl',
type: 'string',
displayOptions: {
show: {
resource: ['thirdParty'],
operation: ['update'],
},
},
default: '',
description: 'The website URL of the thirdParty',
},
{
displayName: 'Legal Name',
name: 'legalName',
type: 'string',
displayOptions: {
show: {
resource: ['thirdParty'],
operation: ['update'],
},
},
default: '',
description: 'The legal name of the thirdParty',
},
{
displayName: 'Headquarter Address',
name: 'headquarterAddress',
type: 'string',
displayOptions: {
show: {
resource: ['thirdParty'],
operation: ['update'],
},
},
default: '',
description: 'The headquarter address of the thirdParty',
},
{
displayName: 'Business Owner ID',
name: 'businessOwnerId',
type: 'string',
displayOptions: {
show: {
resource: ['thirdParty'],
operation: ['update'],
},
},
default: '',
description: 'The ID of the business owner (People ID)',
},
{
displayName: 'Security Owner ID',
name: 'securityOwnerId',
type: 'string',
displayOptions: {
show: {
resource: ['thirdParty'],
operation: ['update'],
},
},
default: '',
description: 'The ID of the security owner (People ID)',
},
{
displayName: 'Show on Trust Center',
name: 'showOnTrustCenter',
type: 'boolean',
displayOptions: {
show: {
resource: ['thirdParty'],
operation: ['update'],
},
},
default: false,
description: 'Whether to show the thirdParty on the trust center',
},
{
displayName: 'Additional Fields',
name: 'additionalFields',
type: 'collection',
placeholder: 'Add Field',
default: {},
displayOptions: {
show: {
resource: ['thirdParty'],
operation: ['update'],
},
},
options: [
{
displayName: 'Business Associate Agreement URL',
name: 'businessAssociateAgreementUrl',
type: 'string',
default: '',
},
{
displayName: 'Certifications',
name: 'certifications',
type: 'string',
default: '',
description: 'Comma-separated list of certifications',
},
{
displayName: 'Countries',
name: 'countries',
type: 'string',
default: '',
description: 'Comma-separated list of country codes',
},
{
displayName: 'Data Processing Agreement URL',
name: 'dataProcessingAgreementUrl',
type: 'string',
default: '',
},
{
displayName: 'Privacy Policy URL',
name: 'privacyPolicyUrl',
type: 'string',
default: '',
},
{
displayName: 'Security Page URL',
name: 'securityPageUrl',
type: 'string',
default: '',
},
{
displayName: 'Service Level Agreement URL',
name: 'serviceLevelAgreementUrl',
type: 'string',
default: '',
},
{
displayName: 'Status Page URL',
name: 'statusPageUrl',
type: 'string',
default: '',
description: 'The status page URL of the thirdParty',
},
{
displayName: 'Subprocessors List URL',
name: 'subprocessorsListUrl',
type: 'string',
default: '',
},
{
displayName: 'Terms of Service URL',
name: 'termsOfServiceUrl',
type: 'string',
default: '',
},
{
displayName: 'Trust Page URL',
name: 'trustPageUrl',
type: 'string',
default: '',
},
],
},
];
export async function execute(
this: IExecuteFunctions,
itemIndex: number,
): Promise<INodeExecutionData> {
const thirdPartyId = this.getNodeParameter('thirdPartyId', itemIndex) as string;
const name = this.getNodeParameter('name', itemIndex, '') as string;
const description = this.getNodeParameter('description', itemIndex, '') as string;
const category = this.getNodeParameter('category', itemIndex, '') as string;
const websiteUrl = this.getNodeParameter('websiteUrl', itemIndex, '') as string;
const legalName = this.getNodeParameter('legalName', itemIndex, '') as string;
const headquarterAddress = this.getNodeParameter('headquarterAddress', itemIndex, '') as string;
const businessOwnerId = this.getNodeParameter('businessOwnerId', itemIndex, '') as string;
const securityOwnerId = this.getNodeParameter('securityOwnerId', itemIndex, '') as string;
const showOnTrustCenter = this.getNodeParameter('showOnTrustCenter', itemIndex) as boolean | undefined;
const additionalFields = this.getNodeParameter('additionalFields', itemIndex, {}) as {
statusPageUrl?: string;
termsOfServiceUrl?: string;
privacyPolicyUrl?: string;
serviceLevelAgreementUrl?: string;
dataProcessingAgreementUrl?: string;
businessAssociateAgreementUrl?: string;
subprocessorsListUrl?: string;
securityPageUrl?: string;
trustPageUrl?: string;
certifications?: string;
countries?: string;
};
const query = `
mutation UpdateThirdParty($input: UpdateThirdPartyInput!) {
updateThirdParty(input: $input) {
thirdParty {
id
name
description
category
websiteUrl
legalName
headquarterAddress
statusPageUrl
termsOfServiceUrl
privacyPolicyUrl
serviceLevelAgreementUrl
dataProcessingAgreementUrl
businessAssociateAgreementUrl
subprocessorsListUrl
securityPageUrl
trustPageUrl
certifications
countries
showOnTrustCenter
createdAt
updatedAt
}
}
}
`;
const input: Record<string, unknown> = { id: thirdPartyId };
if (name) input.name = name;
if (description !== undefined) input.description = description === '' ? null : description;
if (category) input.category = category;
if (websiteUrl !== undefined) input.websiteUrl = websiteUrl === '' ? null : websiteUrl;
if (legalName !== undefined) input.legalName = legalName === '' ? null : legalName;
if (headquarterAddress !== undefined) input.headquarterAddress = headquarterAddress === '' ? null : headquarterAddress;
if (businessOwnerId !== undefined) input.businessOwnerId = businessOwnerId === '' ? null : businessOwnerId;
if (securityOwnerId !== undefined) input.securityOwnerId = securityOwnerId === '' ? null : securityOwnerId;
if (showOnTrustCenter !== undefined) input.showOnTrustCenter = showOnTrustCenter;
if (additionalFields.statusPageUrl !== undefined) input.statusPageUrl = additionalFields.statusPageUrl === '' ? null : additionalFields.statusPageUrl;
if (additionalFields.termsOfServiceUrl !== undefined) input.termsOfServiceUrl = additionalFields.termsOfServiceUrl === '' ? null : additionalFields.termsOfServiceUrl;
if (additionalFields.privacyPolicyUrl !== undefined) input.privacyPolicyUrl = additionalFields.privacyPolicyUrl === '' ? null : additionalFields.privacyPolicyUrl;
if (additionalFields.serviceLevelAgreementUrl !== undefined) input.serviceLevelAgreementUrl = additionalFields.serviceLevelAgreementUrl === '' ? null : additionalFields.serviceLevelAgreementUrl;
if (additionalFields.dataProcessingAgreementUrl !== undefined) input.dataProcessingAgreementUrl = additionalFields.dataProcessingAgreementUrl === '' ? null : additionalFields.dataProcessingAgreementUrl;
if (additionalFields.businessAssociateAgreementUrl !== undefined) input.businessAssociateAgreementUrl = additionalFields.businessAssociateAgreementUrl === '' ? null : additionalFields.businessAssociateAgreementUrl;
if (additionalFields.subprocessorsListUrl !== undefined) input.subprocessorsListUrl = additionalFields.subprocessorsListUrl === '' ? null : additionalFields.subprocessorsListUrl;
if (additionalFields.securityPageUrl !== undefined) input.securityPageUrl = additionalFields.securityPageUrl === '' ? null : additionalFields.securityPageUrl;
if (additionalFields.trustPageUrl !== undefined) input.trustPageUrl = additionalFields.trustPageUrl === '' ? null : additionalFields.trustPageUrl;
if (additionalFields.certifications !== undefined) {
if (additionalFields.certifications === '') {
input.certifications = [];
} else {
input.certifications = additionalFields.certifications.split(',').map((c) => c.trim()).filter(Boolean);
}
}
if (additionalFields.countries !== undefined) {
if (additionalFields.countries === '') {
input.countries = [];
} else {
input.countries = additionalFields.countries.split(',').map((c) => c.trim()).filter(Boolean);
}
}
const responseData = await proboApiRequest.call(this, query, { input });
return {
json: responseData,
pairedItem: { item: itemIndex },
};
}

View File

@@ -0,0 +1,91 @@
// Copyright (c) 2025-2026 Probo Inc <hello@getprobo.com>.
//
// Permission to use, copy, modify, and/or distribute this software for any
// purpose with or without fee is hereby granted, provided that the above
// copyright notice and this permission notice appear in all copies.
//
// THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES WITH
// REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY
// AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT,
// INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM
// LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR
// OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
// PERFORMANCE OF THIS SOFTWARE.
import type { INodeProperties, IExecuteFunctions, INodeExecutionData } from 'n8n-workflow';
import { proboApiRequest } from '../../GenericFunctions';
export const description: INodeProperties[] = [
{
displayName: 'ThirdParty ID',
name: 'thirdPartyId',
type: 'string',
displayOptions: {
show: {
resource: ['thirdParty'],
operation: ['updateBusinessAssociateAgreement'],
},
},
default: '',
description: 'The ID of the thirdParty',
required: true,
},
{
displayName: 'Valid From',
name: 'validFrom',
type: 'string',
displayOptions: {
show: {
resource: ['thirdParty'],
operation: ['updateBusinessAssociateAgreement'],
},
},
default: '',
description: 'The start date of the agreement validity (ISO 8601)',
},
{
displayName: 'Valid Until',
name: 'validUntil',
type: 'string',
displayOptions: {
show: {
resource: ['thirdParty'],
operation: ['updateBusinessAssociateAgreement'],
},
},
default: '',
description: 'The end date of the agreement validity (ISO 8601)',
},
];
export async function execute(
this: IExecuteFunctions,
itemIndex: number,
): Promise<INodeExecutionData> {
const thirdPartyId = this.getNodeParameter('thirdPartyId', itemIndex) as string;
const validFrom = this.getNodeParameter('validFrom', itemIndex, '') as string;
const validUntil = this.getNodeParameter('validUntil', itemIndex, '') as string;
const query = `
mutation UpdateThirdPartyBusinessAssociateAgreement($input: UpdateThirdPartyBusinessAssociateAgreementInput!) {
updateThirdPartyBusinessAssociateAgreement(input: $input) {
thirdPartyBusinessAssociateAgreement {
id
validFrom
validUntil
}
}
}
`;
const input: Record<string, unknown> = { thirdPartyId };
if (validFrom) input.validFrom = validFrom;
if (validUntil) input.validUntil = validUntil;
const responseData = await proboApiRequest.call(this, query, { input });
return {
json: responseData,
pairedItem: { item: itemIndex },
};
}

View File

@@ -0,0 +1,119 @@
// Copyright (c) 2026 Probo Inc <hello@getprobo.com>.
//
// Permission to use, copy, modify, and/or distribute this software for any
// purpose with or without fee is hereby granted, provided that the above
// copyright notice and this permission notice appear in all copies.
//
// THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES WITH
// REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY
// AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT,
// INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM
// LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR
// OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
// PERFORMANCE OF THIS SOFTWARE.
import type { INodeProperties, IExecuteFunctions, INodeExecutionData } from 'n8n-workflow';
import { proboApiRequest } from '../../GenericFunctions';
export const description: INodeProperties[] = [
{
displayName: 'ThirdParty Contact ID',
name: 'thirdPartyContactId',
type: 'string',
displayOptions: {
show: {
resource: ['thirdParty'],
operation: ['updateContact'],
},
},
default: '',
description: 'The ID of the thirdParty contact to update',
required: true,
},
{
displayName: 'Additional Fields',
name: 'additionalFields',
type: 'collection',
placeholder: 'Add Field',
default: {},
displayOptions: {
show: {
resource: ['thirdParty'],
operation: ['updateContact'],
},
},
options: [
{
displayName: 'Email',
name: 'email',
type: 'string',
placeholder: 'name@email.com',
default: '',
description: 'The email address of the contact',
},
{
displayName: 'Full Name',
name: 'fullName',
type: 'string',
default: '',
description: 'The full name of the contact',
},
{
displayName: 'Phone',
name: 'phone',
type: 'string',
default: '',
description: 'The phone number of the contact',
},
{
displayName: 'Role',
name: 'role',
type: 'string',
default: '',
description: 'The role of the contact',
},
],
},
];
export async function execute(
this: IExecuteFunctions,
itemIndex: number,
): Promise<INodeExecutionData> {
const thirdPartyContactId = this.getNodeParameter('thirdPartyContactId', itemIndex) as string;
const additionalFields = this.getNodeParameter('additionalFields', itemIndex, {}) as {
fullName?: string;
email?: string;
phone?: string;
role?: string;
};
const query = `
mutation UpdateThirdPartyContact($input: UpdateThirdPartyContactInput!) {
updateThirdPartyContact(input: $input) {
thirdPartyContact {
id
fullName
email
phone
role
createdAt
updatedAt
}
}
}
`;
const input: Record<string, unknown> = { id: thirdPartyContactId };
if (additionalFields.fullName !== undefined) input.fullName = additionalFields.fullName === '' ? null : additionalFields.fullName;
if (additionalFields.email !== undefined) input.email = additionalFields.email === '' ? null : additionalFields.email;
if (additionalFields.phone !== undefined) input.phone = additionalFields.phone === '' ? null : additionalFields.phone;
if (additionalFields.role !== undefined) input.role = additionalFields.role === '' ? null : additionalFields.role;
const responseData = await proboApiRequest.call(this, query, { input });
return {
json: responseData,
pairedItem: { item: itemIndex },
};
}

View File

@@ -0,0 +1,91 @@
// Copyright (c) 2025-2026 Probo Inc <hello@getprobo.com>.
//
// Permission to use, copy, modify, and/or distribute this software for any
// purpose with or without fee is hereby granted, provided that the above
// copyright notice and this permission notice appear in all copies.
//
// THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES WITH
// REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY
// AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT,
// INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM
// LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR
// OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
// PERFORMANCE OF THIS SOFTWARE.
import type { INodeProperties, IExecuteFunctions, INodeExecutionData } from 'n8n-workflow';
import { proboApiRequest } from '../../GenericFunctions';
export const description: INodeProperties[] = [
{
displayName: 'ThirdParty ID',
name: 'thirdPartyId',
type: 'string',
displayOptions: {
show: {
resource: ['thirdParty'],
operation: ['updateDataPrivacyAgreement'],
},
},
default: '',
description: 'The ID of the thirdParty',
required: true,
},
{
displayName: 'Valid From',
name: 'validFrom',
type: 'string',
displayOptions: {
show: {
resource: ['thirdParty'],
operation: ['updateDataPrivacyAgreement'],
},
},
default: '',
description: 'The start date of the agreement validity (ISO 8601)',
},
{
displayName: 'Valid Until',
name: 'validUntil',
type: 'string',
displayOptions: {
show: {
resource: ['thirdParty'],
operation: ['updateDataPrivacyAgreement'],
},
},
default: '',
description: 'The end date of the agreement validity (ISO 8601)',
},
];
export async function execute(
this: IExecuteFunctions,
itemIndex: number,
): Promise<INodeExecutionData> {
const thirdPartyId = this.getNodeParameter('thirdPartyId', itemIndex) as string;
const validFrom = this.getNodeParameter('validFrom', itemIndex, '') as string;
const validUntil = this.getNodeParameter('validUntil', itemIndex, '') as string;
const query = `
mutation UpdateThirdPartyDataPrivacyAgreement($input: UpdateThirdPartyDataPrivacyAgreementInput!) {
updateThirdPartyDataPrivacyAgreement(input: $input) {
thirdPartyDataPrivacyAgreement {
id
validFrom
validUntil
}
}
}
`;
const input: Record<string, unknown> = { thirdPartyId };
if (validFrom) input.validFrom = validFrom;
if (validUntil) input.validUntil = validUntil;
const responseData = await proboApiRequest.call(this, query, { input });
return {
json: responseData,
pairedItem: { item: itemIndex },
};
}

View File

@@ -0,0 +1,96 @@
// Copyright (c) 2025 Probo Inc <hello@getprobo.com>.
//
// Permission to use, copy, modify, and/or distribute this software for any
// purpose with or without fee is hereby granted, provided that the above
// copyright notice and this permission notice appear in all copies.
//
// THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES WITH
// REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY
// AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT,
// INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM
// LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR
// OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
// PERFORMANCE OF THIS SOFTWARE.
import type { INodeProperties, IExecuteFunctions, INodeExecutionData } from 'n8n-workflow';
import { proboApiRequest } from '../../GenericFunctions';
export const description: INodeProperties[] = [
{
displayName: 'ThirdParty Service ID',
name: 'thirdPartyServiceId',
type: 'string',
displayOptions: {
show: {
resource: ['thirdParty'],
operation: ['updateService'],
},
},
default: '',
description: 'The ID of the thirdParty service to update',
required: true,
},
{
displayName: 'Name',
name: 'name',
type: 'string',
displayOptions: {
show: {
resource: ['thirdParty'],
operation: ['updateService'],
},
},
default: '',
description: 'The name of the thirdParty service',
},
{
displayName: 'Description',
name: 'description',
type: 'string',
typeOptions: {
rows: 4,
},
displayOptions: {
show: {
resource: ['thirdParty'],
operation: ['updateService'],
},
},
default: '',
description: 'The description of the thirdParty service',
},
];
export async function execute(
this: IExecuteFunctions,
itemIndex: number,
): Promise<INodeExecutionData> {
const thirdPartyServiceId = this.getNodeParameter('thirdPartyServiceId', itemIndex) as string;
const name = this.getNodeParameter('name', itemIndex, '') as string;
const description = this.getNodeParameter('description', itemIndex, '') as string;
const query = `
mutation UpdateThirdPartyService($input: UpdateThirdPartyServiceInput!) {
updateThirdPartyService(input: $input) {
thirdPartyService {
id
name
description
createdAt
updatedAt
}
}
}
`;
const input: Record<string, unknown> = { id: thirdPartyServiceId };
if (name) input.name = name;
if (description !== undefined) input.description = description === '' ? null : description;
const responseData = await proboApiRequest.call(this, query, { input });
return {
json: responseData,
pairedItem: { item: itemIndex },
};
}