Add Activepieces integration for workflow automation

- Add Activepieces fork with SmoothSchedule custom piece
- Create integrations app with Activepieces service layer
- Add embed token endpoint for iframe integration
- Create Automations page with embedded workflow builder
- Add sidebar visibility fix for embed mode
- Add list inactive customers endpoint to Public API
- Include SmoothSchedule triggers: event created/updated/cancelled
- Include SmoothSchedule actions: create/update/cancel events, list resources/services/customers

🤖 Generated with [Claude Code](https://claude.com/claude-code)

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
This commit is contained in:
poduck
2025-12-18 22:59:37 -05:00
co-authored by Claude Opus 4.5
parent 9848268d34
commit 3aa7199503
16292 changed files with 1284892 additions and 4708 deletions
@@ -0,0 +1,71 @@
import { createAction, Property } from "@activepieces/pieces-framework";
import { AuthenticationType, httpClient, HttpMethod } from "@activepieces/pieces-common";
import { emailOctopusAuth } from "../common/auth";
import { emailOctopusProps } from "../common/props";
export const addOrUpdateContact = createAction({
auth: emailOctopusAuth,
name: 'add_or_update_contact',
displayName: 'Add / Update Contact',
description: 'Adds a new contact to a list or updates an existing contact if one exists.',
props: {
list_id: emailOctopusProps.listId(),
email_address: Property.ShortText({
displayName: 'Email Address',
description: "The contact's email address.",
required: true,
}),
fields: emailOctopusProps.fields(),
tags: Property.Array({
displayName: 'Tags',
description: 'Tags to associate with the contact. Existing tags will not be removed.',
required: false,
}),
status: Property.StaticDropdown({
displayName: 'Status',
description: 'The status of the contact.',
required: false,
options: {
options: [
{ label: 'Subscribed', value: 'subscribed' },
{ label: 'Unsubscribed', value: 'unsubscribed' },
{ label: 'Pending', value: 'pending' },
],
},
}),
},
async run(context) {
const { list_id, email_address, fields, tags, status } = context.propsValue;
const body: Record<string, unknown> = {
email_address: email_address,
};
if (fields) {
body['fields'] = Object.fromEntries(
Object.entries(fields).filter(([, value]) => value !== null && value !== undefined && value !== '')
);
}
if (status) {
body['status'] = status;
}
if (tags && (tags as string[]).length > 0) {
body['tags'] = Object.fromEntries(
(tags as string[]).map(tag => [tag, true])
);
}
const response = await httpClient.sendRequest({
method: HttpMethod.PUT,
url: `https://api.emailoctopus.com/lists/${list_id}/contacts`,
body: body,
authentication: {
type: AuthenticationType.BEARER_TOKEN,
token: context.auth.secret_text,
},
});
return response.body;
},
});
@@ -0,0 +1,52 @@
import { createAction, Property } from "@activepieces/pieces-framework";
import { HttpMethod } from "@activepieces/pieces-common";
import { createHash } from "crypto";
import { emailOctopusAuth } from "../common/auth";
import { EmailOctopusClient } from "../common/client";
import { emailOctopusProps } from "../common/props";
export const addTagToContact = createAction({
auth: emailOctopusAuth,
name: 'add_tag_to_contact',
displayName: 'Add Tag to Contact',
description: 'Add one or more tags to a contact in a specified list.',
props: {
list_id: emailOctopusProps.listId(),
email_address: Property.ShortText({
displayName: 'Email Address',
description: "The contact's email address.",
required: true,
}),
tags: Property.Array({
displayName: 'Tags',
description: 'The tags to add to the contact.',
required: true,
}),
},
async run(context) {
const { list_id, email_address, tags } = context.propsValue;
const client = new EmailOctopusClient(context.auth.secret_text);
const contactId = createHash('md5')
.update(email_address.toLowerCase())
.digest('hex');
const tagsObject = Object.fromEntries(
(tags as string[]).map(tag => [tag, true])
);
const body = {
tags: tagsObject,
};
return await client.makeRequest(
HttpMethod.PUT,
`/lists/${list_id}/contacts/${contactId}`,
body
);
},
});
@@ -0,0 +1,34 @@
import { createAction, Property } from "@activepieces/pieces-framework";
import { HttpMethod } from "@activepieces/pieces-common";
import { emailOctopusAuth } from "../common/auth";
import { EmailOctopusClient } from "../common/client";
export const createList = createAction({
auth: emailOctopusAuth,
name: 'create_list',
displayName: 'Create List',
description: 'Creates a new mailing list.',
props: {
name: Property.ShortText({
displayName: 'List Name',
description: 'The name for the new list.',
required: true,
}),
},
async run(context) {
const { name } = context.propsValue;
const client = new EmailOctopusClient(context.auth.secret_text);
const body = {
name,
};
return await client.makeRequest(
HttpMethod.POST,
`/lists`,
body
);
},
});
@@ -0,0 +1,52 @@
import { createAction, Property } from "@activepieces/pieces-framework";
// 👇 1. Remove `isAxiosError` and import `HttpError` instead
import { HttpError, HttpMethod } from "@activepieces/pieces-common";
import { createHash } from "crypto";
import { emailOctopusAuth } from "../common/auth";
import { EmailOctopusClient } from "../common/client";
import { emailOctopusProps } from "../common/props";
export const findContact = createAction({
auth: emailOctopusAuth,
name: 'find_contact',
displayName: 'Find Contact',
description: 'Finds a contact by email address within a given list.',
props: {
list_id: emailOctopusProps.listId(),
email_address: Property.ShortText({
displayName: 'Email Address',
description: 'The email address of the contact to find.',
required: true,
}),
},
async run(context) {
const { list_id, email_address } = context.propsValue;
const client = new EmailOctopusClient(context.auth.secret_text);
const contactId = createHash('md5')
.update(email_address.toLowerCase())
.digest('hex');
try {
const response = await client.makeRequest(
HttpMethod.GET,
`/lists/${list_id}/contacts/${contactId}`
);
return {
found:true,
result:response
}
} catch (error) {
if (error instanceof HttpError && error.response.status === 404) {
return {
found:false,
result:{}
};
}
throw error;
}
},
});
@@ -0,0 +1,52 @@
import { createAction, Property } from "@activepieces/pieces-framework";
import { HttpMethod } from "@activepieces/pieces-common";
import { createHash } from "crypto";
import { emailOctopusAuth } from "../common/auth";
import { EmailOctopusClient } from "../common/client";
import { emailOctopusProps } from "../common/props";
export const removeTagFromContact = createAction({
auth: emailOctopusAuth,
name: 'remove_tag_from_contact',
displayName: 'Remove Tag from Contact',
description: 'Remove one or more tags from a contact in a specified list.',
props: {
list_id: emailOctopusProps.listId(),
email_address: Property.ShortText({
displayName: 'Email Address',
description: "The email address of the contact to modify.",
required: true,
}),
tags: Property.Array({
displayName: 'Tags',
description: 'The tags to remove from the contact.',
required: true,
}),
},
async run(context) {
const { list_id, email_address, tags } = context.propsValue;
const client = new EmailOctopusClient(context.auth.secret_text);
const contactId = createHash('md5')
.update(email_address.toLowerCase())
.digest('hex');
const tagsObject = Object.fromEntries(
(tags as string[]).map(tag => [tag, false])
);
const body = {
tags: tagsObject,
};
return await client.makeRequest(
HttpMethod.PUT,
`/lists/${list_id}/contacts/${contactId}`,
body
);
},
});
@@ -0,0 +1,42 @@
import { createAction, Property } from "@activepieces/pieces-framework";
import { HttpMethod } from "@activepieces/pieces-common";
import { createHash } from "crypto";
import { emailOctopusAuth } from "../common/auth";
import { EmailOctopusClient } from "../common/client";
import { emailOctopusProps } from "../common/props";
export const unsubscribeContact = createAction({
auth: emailOctopusAuth,
name: 'unsubscribe_contact',
displayName: 'Unsubscribe Contact',
description: 'Sets a contact\'s status to "Unsubscribed" in a specific list.',
props: {
list_id: emailOctopusProps.listId(),
email_address: Property.ShortText({
displayName: 'Email Address',
description: "The email address of the contact to unsubscribe.",
required: true,
}),
},
async run(context) {
const { list_id, email_address } = context.propsValue;
const client = new EmailOctopusClient(context.auth.secret_text);
const contactId = createHash('md5')
.update(email_address.toLowerCase())
.digest('hex');
const body = {
status: 'unsubscribed',
};
return await client.makeRequest(
HttpMethod.PUT,
`/lists/${list_id}/contacts/${contactId}`,
body
);
},
});
@@ -0,0 +1,47 @@
import { createAction, Property } from "@activepieces/pieces-framework";
import { HttpMethod } from "@activepieces/pieces-common";
import { createHash } from "crypto";
import { emailOctopusAuth } from "../common/auth";
import { EmailOctopusClient } from "../common/client";
import { emailOctopusProps } from "../common/props";
export const updateContactEmail = createAction({
auth: emailOctopusAuth,
name: 'update_contact_email',
displayName: "Update Contact's Email Address",
description: "Change the email address of a contact in a list.",
props: {
list_id: emailOctopusProps.listId(),
current_email_address: Property.ShortText({
displayName: 'Current Email Address',
description: "The contact's current email address used to find them.",
required: true,
}),
new_email_address: Property.ShortText({
displayName: 'New Email Address',
description: "The new email address for the contact.",
required: true,
}),
},
async run(context) {
const { list_id, current_email_address, new_email_address } = context.propsValue;
const client = new EmailOctopusClient(context.auth.secret_text);
const contactId = createHash('md5')
.update(current_email_address.toLowerCase())
.digest('hex');
const body = {
email_address: new_email_address,
};
return await client.makeRequest(
HttpMethod.PUT,
`/lists/${list_id}/contacts/${contactId}`,
body
);
},
});
@@ -0,0 +1,37 @@
import { PieceAuth } from '@activepieces/pieces-framework';
import { httpClient, HttpMethod, AuthenticationType } from '@activepieces/pieces-common';
// The base URL for the EmailOctopus API
const emailOctopusApiUrl = 'https://api.emailoctopus.com';
export const emailOctopusAuth = PieceAuth.SecretText({
displayName: 'API Key',
description: `
To get your API key:
1. Log in to your EmailOctopus account.
2. Go to your **account settings**.
3. Generate a new API key.
**Note:** If you have a 'legacy' key, you must generate a new one for API v2.
`,
required: true,
validate: async ({ auth }) => {
try {
await httpClient.sendRequest({
method: HttpMethod.GET,
url: `${emailOctopusApiUrl}/lists`,
authentication: {
type: AuthenticationType.BEARER_TOKEN,
token: auth,
},
});
return {
valid: true,
};
} catch (e) {
return {
valid: false,
error: 'Invalid API key.',
};
}
},
});
@@ -0,0 +1,70 @@
import { httpClient, HttpMethod, HttpRequest } from "@activepieces/pieces-common";
export const emailOctopusApiUrl = 'https://api.emailoctopus.com';
export interface EmailOctopusListDetails extends EmailOctopusList {
fields: {
tag: string;
type: 'text' | 'number' | 'date'|'choice_single'|'choice_multiple'
label: string;
choices:string[]
}[];
}
export class EmailOctopusClient {
constructor(private apiKey: string) {}
async makeRequest<T>(method: HttpMethod, url: string, body?: object): Promise<T> {
const request: HttpRequest<object> = {
method,
url: `${emailOctopusApiUrl}${url}`,
body: body,
headers: {
"Accept": "application/json",
"Content-Type": "application/json",
"Authorization":`Bearer ${this.apiKey}`
},
};
const { body: responseBody } = await httpClient.sendRequest<T>(request);
return responseBody;
}
async getLists(): Promise<EmailOctopusList[]> {
const response = await this.makeRequest<{ data: EmailOctopusList[] }>(
HttpMethod.GET,
'/lists'
);
return response.data;
}
async getList(listId: string): Promise<EmailOctopusListDetails> {
return await this.makeRequest<EmailOctopusListDetails>(
HttpMethod.GET,
`/lists/${listId}`
);
}
async getCampaigns(): Promise<EmailOctopusCampaign[]> {
const response = await this.makeRequest<{ data: EmailOctopusCampaign[] }>(
HttpMethod.GET,
'/campaigns'
);
return response.data;
}
}
export interface EmailOctopusList {
id: string;
name: string;
created_at: string;
}
export interface EmailOctopusCampaign {
id: string;
name: string;
status: string;
created_at: string;
}
@@ -0,0 +1,143 @@
import {
Property,
DynamicPropsValue,
DropdownState,
InputPropertyMap,
PropertyContext,
} from '@activepieces/pieces-framework';
import { EmailOctopusClient } from './client';
import { emailOctopusAuth } from './auth';
type AuthAndProps = {
auth: string | undefined;
propsValue: Record<string, unknown>;
};
export const emailOctopusProps = {
listId: (required = true) =>
Property.Dropdown({
auth: emailOctopusAuth,
displayName: 'List',
description: 'The mailing list to use.',
required: required,
refreshers: [],
options: async (context) => {
const { auth } = context;
if (!auth) {
return {
disabled: true,
placeholder: 'Connect your account first',
options: [],
};
}
const client = new EmailOctopusClient(auth.secret_text);
const lists = await client.getLists();
return {
disabled: false,
options: lists.map((list) => ({
label: list.name,
value: list.id,
})),
};
},
}),
campaignId: (required = false) =>
Property.Dropdown({
auth: emailOctopusAuth,
displayName: 'Campaign',
description:
'Select a campaign to filter events. Leave blank to trigger for all campaigns.',
required: required,
refreshers: [],
options: async (context) => {
const { auth } = context;
if (!auth) {
return {
disabled: true,
placeholder: 'Connect your account first',
options: [],
};
}
const client = new EmailOctopusClient(auth.secret_text);
const campaigns = await client.getCampaigns();
return {
disabled: false,
options: campaigns.map((campaign) => ({
label: campaign.name,
value: campaign.id,
})),
};
},
}),
fields: () =>
Property.DynamicProperties({
auth: emailOctopusAuth,
displayName: 'Fields',
description: "The contact's custom fields.",
required: true,
refreshers: ['list_id'],
props: async ({ auth, list_id }): Promise<InputPropertyMap> => {
if (!auth || !list_id) {
return {};
}
const client = new EmailOctopusClient(auth.secret_text);
const listDetails = await client.getList(list_id as unknown as string);
const fields: DynamicPropsValue = {};
for (const field of listDetails.fields) {
if (field.tag === 'EmailAddress') continue;
switch (field.type) {
case 'number':
fields[field.tag] = Property.Number({
displayName: field.label,
required: false,
});
break;
case 'date':
fields[field.tag] = Property.ShortText({
displayName: field.label,
description: 'Date in YYYY-MM-DD format.',
required: false,
});
break;
case 'text':
fields[field.tag] = Property.ShortText({
displayName: field.label,
required: false,
});
break;
case 'choice_single':
fields[field.tag] = Property.StaticDropdown({
displayName: field.label,
required: false,
options: {
disabled: false,
options: field.choices
? field.choices.map((opt) => ({ label: opt, value: opt }))
: [],
},
});
break;
case 'choice_multiple':
fields[field.tag] = Property.StaticMultiSelectDropdown({
displayName: field.label,
required: false,
options: {
disabled: false,
options: field.choices
? field.choices.map((opt) => ({ label: opt, value: opt }))
: [],
},
});
break;
default:
break;
}
}
return fields;
},
}),
};
@@ -0,0 +1,88 @@
import { Property, createTrigger, TriggerStrategy } from '@activepieces/pieces-framework';
import { emailOctopusAuth } from '../common/auth';
import { emailOctopusProps } from '../common/props';
import { MarkdownVariant } from '@activepieces/shared';
interface EmailOctopusEvent {
type: string;
id: string;
contact_email_address: string;
contact_fields?: Record<string, string>;
contact_tags?: string[];
contact_status?: string;
list_id?: string;
occurred_at?: string;
}
export const contactUnsubscribes = createTrigger({
auth: emailOctopusAuth,
name: 'contactUnsubscribes',
displayName: 'Contact Unsubscribes',
description: 'Triggers when a contact unsubscribes from a list.',
props: {
list_id: emailOctopusProps.listId(true),
liveMarkdown: Property.MarkDown({
value: `
**Live URL:**
\`\`\`text
{{webhookUrl}}
\`\`\``,
variant: MarkdownVariant.BORDERLESS,
}),
instructions: Property.MarkDown({
value: `
**Manual Setup Required**
1. Go to your EmailOctopus Dashboard.
2. Navigate to **API & Integrations → Webhooks**.
3. Click **Add webhook**.
4. Paste the Above URL:
5. Select the **Email unsubscribed** event.
6. (Optional) Restrict to the specific list chosen above.
7. Save the webhook.
`,
}),
},
sampleData: {
id: '42636763-73f9-463e-af8b-3f720bb3d889',
type: 'contact.unsubscribed',
list_id: 'fa482fa2-5ac4-11ed-9f7a-67da1c836cf8',
contact_id: 'e3ab8c80-5f65-11ed-835e-030e4bb63150',
occurred_at: '2022-11-18T15:20:23+00:00',
contact_fields: {
LastName: 'Example',
FirstName: 'Claire',
},
contact_status: 'unsubscribed',
contact_email_address: 'claire@example.com',
contact_tags: ['vip'],
},
type: TriggerStrategy.WEBHOOK,
async onEnable() {
return;
},
async onDisable() {
return;
},
async run(context) {
const events = context.payload.body;
const listIdFilter = context.propsValue.list_id;
if (Array.isArray(events)) {
return events.filter(
(event: EmailOctopusEvent) =>
event.type === 'contact.unsubscribed' &&
(!listIdFilter || event.list_id === listIdFilter)
);
}
if (
(events as EmailOctopusEvent)?.type === 'contact.unsubscribed' &&
(!listIdFilter || (events as EmailOctopusEvent).list_id === listIdFilter)
) {
return [events];
}
return [];
},
});
@@ -0,0 +1,82 @@
import { Property, createTrigger, TriggerStrategy } from '@activepieces/pieces-framework';
import { emailOctopusProps } from '../common/props';
import { emailOctopusAuth } from '../common/auth';
import { MarkdownVariant } from '@activepieces/shared';
interface EmailOctopusEvent {
type: string;
id: string;
contact_email_address: string;
campaign_id?: string;
list_id?: string;
contact_id?: string;
occurred_at?: string;
}
export const emailClicked = createTrigger({
auth: emailOctopusAuth,
name: 'emailClicked',
displayName: 'Email Clicked',
description: 'Triggers when a link inside a specific campaign email is clicked.',
props: {
campaign_id: emailOctopusProps.campaignId(),
liveMarkdown: Property.MarkDown({
value: `
**Live URL:**
\`\`\`text
{{webhookUrl}}
\`\`\``,
variant: MarkdownVariant.BORDERLESS,
}),
instructions: Property.MarkDown({
value: `
**Manual Setup Required**
1. Go to your EmailOctopus Dashboard.
2. Navigate to **API & Integrations** → **Webhooks**.
3. Click **Add webhook**.
4. Paste the Above URL into the **URL** field:
5. Select the **Email clicked** event.
6. (Optional) Choose the campaign you want to filter on in this trigger.
7. Save the webhook.
`,
}),
},
sampleData: {
id: '42636763-73f9-463e-af8b-3f720bb3d889',
type: 'contact.clicked',
list_id: 'fa482fa2-5ac4-11ed-9f7a-67da1c836cf8',
contact_id: 'e3ab8c80-5f65-11ed-835e-030e4bb63150',
occurred_at: '2022-11-18T15:20:23+00:00',
contact_email_address: 'user@example.com',
campaign_id: '12345678-1234-1234-1234-123456789abc',
},
type: TriggerStrategy.WEBHOOK,
async onEnable() {
return;
},
async onDisable() {
return;
},
async run(context) {
const events = context.payload.body;
const campaignIdFilter = context.propsValue.campaign_id;
if (Array.isArray(events)) {
return events.filter(
(event: EmailOctopusEvent) =>
event.type === 'contact.clicked' &&
(!campaignIdFilter || event.campaign_id === campaignIdFilter)
);
}
if (
(events as EmailOctopusEvent)?.type === 'contact.clicked' &&
(!campaignIdFilter || (events as EmailOctopusEvent).campaign_id === campaignIdFilter)
) {
return [events];
}
return [];
},
});
@@ -0,0 +1,63 @@
import { Property, TriggerStrategy, createTrigger } from "@activepieces/pieces-framework";
import { emailOctopusAuth } from "../common/auth";
import { emailOctopusProps } from "../common/props";
import { MarkdownVariant } from "@activepieces/shared";
export const emailBounced = createTrigger({
auth: emailOctopusAuth,
name: 'email_bounced',
displayName: 'Email Bounced',
description: 'Triggers when an email to a recipient bounces from a specific campaign.',
props: {
campaign_id: emailOctopusProps.campaignId(),
liveMarkdown: Property.MarkDown({
value: `
**Live URL:**
\`\`\`text
{{webhookUrl}}
\`\`\``,
variant: MarkdownVariant.BORDERLESS,
}),
instructions: Property.MarkDown({
value: `
**Manual Setup Required**
1. Go to your EmailOctopus Dashboard.
2. Navigate to **API & Integrations**, then select the **Webhooks** tab.
3. Click **Add webhook**.
4. Paste the Above URL below into the **URL** field:
5. Select the **Email bounced** event.
6. Click **Add webhook**.
`,
}),
},
type: TriggerStrategy.WEBHOOK,
sampleData: {
"id": "42636763-73f9-463e-af8b-3f720bb3d889",
"type": "contact.bounced",
"list_id": "fa482fa2-5ac4-11ed-9f7a-67da1c836cf8",
"contact_id": "e3ab8c80-5f65-11ed-835e-030e4bb63150",
"occurred_at": "2022-11-18T15:20:23+00:00",
"contact_email_address": "user@example.com",
"contact_status": "BOUNCED",
"campaign_id": "12345678-1234-1234-1234-123456789abc"
},
async onEnable(context) { return },
async onDisable(context) { return },
async run(context) {
const payloadBody = context.payload.body as { type: string; campaign_id: string };
const campaignIdFilter = context.propsValue.campaign_id;
if (payloadBody.type !== 'contact.bounced') {
return [];
}
if (campaignIdFilter && payloadBody.campaign_id !== campaignIdFilter) {
return [];
}
return [payloadBody];
},
});
@@ -0,0 +1,76 @@
import {
Property,
TriggerStrategy,
createTrigger,
} from '@activepieces/pieces-framework';
import { emailOctopusAuth } from '../common/auth';
import { emailOctopusProps } from '../common/props';
import { MarkdownVariant } from '@activepieces/shared';
export const emailOpened = createTrigger({
auth: emailOctopusAuth,
name: 'email_opened',
displayName: 'Email Opened',
description:
'Triggers when a recipient opens an email from a specified campaign.',
props: {
campaign_id: emailOctopusProps.campaignId(),
liveMarkdown: Property.MarkDown({
value: `
**Live URL:**
\`\`\`text
{{webhookUrl}}
\`\`\``,
variant: MarkdownVariant.BORDERLESS,
}),
instructions: Property.MarkDown({
variant: MarkdownVariant.INFO,
value: `
**Manual Setup Required**
1. Go to your EmailOctopus Dashboard.
2. Navigate to **API & Integrations**, then select the **Webhooks** tab.
3. Click **Add webhook**.
4. Paste the Above URL into the **URL** field:
5. Select the **Email opened** event.
6. Click **Add webhook**.
`,
}),
},
type: TriggerStrategy.WEBHOOK,
sampleData: {
id: '42636763-73f9-463e-af8b-3f720bb3d889',
type: 'contact.opened',
list_id: 'fa482fa2-5ac4-11ed-9f7a-67da1c836cf8',
contact_id: 'e3ab8c80-5f65-11ed-835e-030e4bb63150',
occurred_at: '2022-11-18T15:20:23+00:00',
contact_email_address: 'user@example.com',
campaign_id: '12345678-1234-1234-1234-123456789abc',
},
async onEnable(context) {
return;
},
async onDisable(context) {
return;
},
async run(context) {
const payloadBody = context.payload.body as {
type: string;
campaign_id: string;
};
const campaignIdFilter = context.propsValue.campaign_id;
if (payloadBody.type !== 'contact.opened') {
return [];
}
if (campaignIdFilter && payloadBody.campaign_id !== campaignIdFilter) {
return [];
}
return [payloadBody];
},
});
@@ -0,0 +1,93 @@
import {
Property,
createTrigger,
TriggerStrategy,
} from '@activepieces/pieces-framework';
import { emailOctopusAuth } from '../common/auth';
import { emailOctopusProps } from '../common/props';
import { MarkdownVariant } from '@activepieces/shared';
interface EmailOctopusEvent {
type: string;
id: string;
contact_email_address: string;
contact_fields?: Record<string, string>;
contact_tags?: string[];
contact_status?: string;
list_id?: string;
occurred_at?: string;
}
export const newContact = createTrigger({
auth: emailOctopusAuth,
name: 'newContact',
displayName: 'New Contact',
description: 'Triggers when a new contact is added to a particular list.',
props: {
list_id: emailOctopusProps.listId(true),
liveMarkdown: Property.MarkDown({
value: `
**Live URL:**
\`\`\`text
{{webhookUrl}}
\`\`\``,
variant: MarkdownVariant.BORDERLESS,
}),
instructions: Property.MarkDown({
variant: MarkdownVariant.INFO,
value: `
**Manual Setup Required**
1. Go to your EmailOctopus Dashboard.
2. Navigate to **API & Integrations → Webhooks**.
3. Click **Add webhook**.
4. Paste the Above URL.
5. Select the **Contact created** event.
6. (Optional) Restrict to the specific list chosen above.
7. Save the webhook.
`,
}),
},
sampleData: {
id: '42636763-73f9-463e-af8b-3f720bb3d889',
type: 'contact.created',
list_id: 'fa482fa2-5ac4-11ed-9f7a-67da1c836cf8',
contact_id: 'e3ab8c80-5f65-11ed-835e-030e4bb63150',
occurred_at: '2022-11-18T15:20:23+00:00',
contact_fields: {
LastName: 'Example',
FirstName: 'Claire',
},
contact_status: 'subscribed',
contact_email_address: 'claire@example.com',
contact_tags: ['vip'],
},
type: TriggerStrategy.WEBHOOK,
async onEnable() {
return;
},
async onDisable() {
return;
},
async run(context) {
const events = context.payload.body;
const listIdFilter = context.propsValue.list_id;
if (Array.isArray(events)) {
return events.filter(
(event: EmailOctopusEvent) =>
event.type === 'contact.created' &&
(!listIdFilter || event.list_id === listIdFilter)
);
}
if (
(events as EmailOctopusEvent)?.type === 'contact.created' &&
(!listIdFilter || (events as EmailOctopusEvent).list_id === listIdFilter)
) {
return [events];
}
return [];
},
});