From fd5dee462dc19c2457982a0e643b7609dfc18ed5 Mon Sep 17 00:00:00 2001 From: waleed Date: Thu, 27 Nov 2025 02:14:47 -0800 Subject: [PATCH 1/3] feat(tools): added zendesk, pylon, intercom, & mailchimp --- apps/docs/components/icons.tsx | 101 ++ apps/docs/components/ui/icon-mapping.ts | 8 + apps/docs/content/docs/en/tools/intercom.mdx | 361 ++++ apps/docs/content/docs/en/tools/mailchimp.mdx | 1481 +++++++++++++++++ apps/docs/content/docs/en/tools/meta.json | 4 + apps/docs/content/docs/en/tools/pylon.mdx | 763 +++++++++ apps/docs/content/docs/en/tools/zendesk.mdx | 636 +++++++ apps/sim/blocks/blocks/intercom.ts | 582 +++++++ apps/sim/blocks/blocks/mailchimp.ts | 1039 ++++++++++++ apps/sim/blocks/blocks/pylon.ts | 838 ++++++++++ apps/sim/blocks/blocks/zendesk.ts | 497 ++++++ apps/sim/blocks/registry.ts | 8 + apps/sim/components/icons.tsx | 101 ++ apps/sim/tools/intercom/create_company.ts | 162 ++ apps/sim/tools/intercom/create_contact.ts | 178 ++ apps/sim/tools/intercom/create_message.ts | 153 ++ apps/sim/tools/intercom/create_ticket.ts | 127 ++ apps/sim/tools/intercom/delete_contact.ts | 92 + apps/sim/tools/intercom/get_company.ts | 89 + apps/sim/tools/intercom/get_contact.ts | 89 + apps/sim/tools/intercom/get_conversation.ts | 102 ++ apps/sim/tools/intercom/get_ticket.ts | 87 + apps/sim/tools/intercom/index.ts | 23 + apps/sim/tools/intercom/list_companies.ts | 110 ++ apps/sim/tools/intercom/list_contacts.ts | 110 ++ apps/sim/tools/intercom/list_conversations.ts | 110 ++ apps/sim/tools/intercom/list_tickets.ts | 110 ++ apps/sim/tools/intercom/reply_conversation.ts | 137 ++ apps/sim/tools/intercom/search_contacts.ts | 130 ++ .../tools/intercom/search_conversations.ts | 129 ++ apps/sim/tools/intercom/types.ts | 47 + apps/sim/tools/intercom/update_contact.ts | 177 ++ apps/sim/tools/mailchimp/add_member.ts | 142 ++ apps/sim/tools/mailchimp/add_member_tags.ts | 114 ++ .../tools/mailchimp/add_or_update_member.ts | 150 ++ .../sim/tools/mailchimp/add_segment_member.ts | 111 ++ .../mailchimp/add_subscriber_to_automation.ts | 113 ++ apps/sim/tools/mailchimp/archive_member.ts | 96 ++ apps/sim/tools/mailchimp/create_audience.ts | 145 ++ .../tools/mailchimp/create_batch_operation.ts | 101 ++ apps/sim/tools/mailchimp/create_campaign.ts | 128 ++ apps/sim/tools/mailchimp/create_interest.ts | 111 ++ .../mailchimp/create_interest_category.ts | 109 ++ .../tools/mailchimp/create_landing_page.ts | 106 ++ .../sim/tools/mailchimp/create_merge_field.ts | 109 ++ apps/sim/tools/mailchimp/create_segment.ts | 120 ++ apps/sim/tools/mailchimp/create_template.ts | 101 ++ apps/sim/tools/mailchimp/delete_audience.ts | 85 + .../tools/mailchimp/delete_batch_operation.ts | 85 + apps/sim/tools/mailchimp/delete_campaign.ts | 85 + apps/sim/tools/mailchimp/delete_interest.ts | 103 ++ .../mailchimp/delete_interest_category.ts | 96 ++ .../tools/mailchimp/delete_landing_page.ts | 85 + apps/sim/tools/mailchimp/delete_member.ts | 93 ++ .../sim/tools/mailchimp/delete_merge_field.ts | 93 ++ apps/sim/tools/mailchimp/delete_segment.ts | 93 ++ apps/sim/tools/mailchimp/delete_template.ts | 85 + apps/sim/tools/mailchimp/get_audience.ts | 90 + apps/sim/tools/mailchimp/get_audiences.ts | 109 ++ apps/sim/tools/mailchimp/get_automation.ts | 90 + apps/sim/tools/mailchimp/get_automations.ts | 109 ++ .../tools/mailchimp/get_batch_operation.ts | 90 + .../tools/mailchimp/get_batch_operations.ts | 109 ++ apps/sim/tools/mailchimp/get_campaign.ts | 90 + .../tools/mailchimp/get_campaign_content.ts | 90 + .../tools/mailchimp/get_campaign_report.ts | 90 + .../tools/mailchimp/get_campaign_reports.ts | 109 ++ apps/sim/tools/mailchimp/get_campaigns.ts | 125 ++ apps/sim/tools/mailchimp/get_interest.ts | 109 ++ .../mailchimp/get_interest_categories.ts | 116 ++ .../tools/mailchimp/get_interest_category.ts | 101 ++ apps/sim/tools/mailchimp/get_interests.ts | 126 ++ apps/sim/tools/mailchimp/get_landing_page.ts | 90 + apps/sim/tools/mailchimp/get_landing_pages.ts | 109 ++ apps/sim/tools/mailchimp/get_member.ts | 98 ++ apps/sim/tools/mailchimp/get_member_tags.ts | 105 ++ apps/sim/tools/mailchimp/get_members.ts | 124 ++ apps/sim/tools/mailchimp/get_merge_field.ts | 98 ++ apps/sim/tools/mailchimp/get_merge_fields.ts | 116 ++ apps/sim/tools/mailchimp/get_segment.ts | 98 ++ .../tools/mailchimp/get_segment_members.ts | 126 ++ apps/sim/tools/mailchimp/get_segments.ts | 116 ++ apps/sim/tools/mailchimp/get_template.ts | 90 + apps/sim/tools/mailchimp/get_templates.ts | 109 ++ apps/sim/tools/mailchimp/index.ts | 88 + apps/sim/tools/mailchimp/pause_automation.ts | 89 + .../tools/mailchimp/publish_landing_page.ts | 86 + .../sim/tools/mailchimp/remove_member_tags.ts | 114 ++ .../tools/mailchimp/remove_segment_member.ts | 103 ++ .../sim/tools/mailchimp/replicate_campaign.ts | 91 + apps/sim/tools/mailchimp/schedule_campaign.ts | 98 ++ apps/sim/tools/mailchimp/send_campaign.ts | 86 + .../tools/mailchimp/set_campaign_content.ts | 120 ++ apps/sim/tools/mailchimp/start_automation.ts | 89 + apps/sim/tools/mailchimp/types.ts | 53 + apps/sim/tools/mailchimp/unarchive_member.ts | 116 ++ .../tools/mailchimp/unpublish_landing_page.ts | 86 + .../tools/mailchimp/unschedule_campaign.ts | 86 + apps/sim/tools/mailchimp/update_audience.ts | 136 ++ apps/sim/tools/mailchimp/update_campaign.ts | 125 ++ apps/sim/tools/mailchimp/update_interest.ts | 122 ++ .../mailchimp/update_interest_category.ts | 115 ++ .../tools/mailchimp/update_landing_page.ts | 104 ++ apps/sim/tools/mailchimp/update_member.ts | 150 ++ .../sim/tools/mailchimp/update_merge_field.ts | 112 ++ apps/sim/tools/mailchimp/update_segment.ts | 128 ++ apps/sim/tools/mailchimp/update_template.ts | 112 ++ apps/sim/tools/pylon/bulk_update_accounts.ts | 140 ++ apps/sim/tools/pylon/create_account.ts | 191 +++ apps/sim/tools/pylon/create_contact.ts | 153 ++ apps/sim/tools/pylon/create_issue.ts | 188 +++ apps/sim/tools/pylon/create_tag.ts | 111 ++ apps/sim/tools/pylon/create_team.ts | 105 ++ apps/sim/tools/pylon/delete_account.ts | 84 + apps/sim/tools/pylon/delete_contact.ts | 84 + apps/sim/tools/pylon/delete_issue.ts | 81 + apps/sim/tools/pylon/delete_tag.ts | 81 + apps/sim/tools/pylon/get_account.ts | 86 + apps/sim/tools/pylon/get_contact.ts | 109 ++ apps/sim/tools/pylon/get_issue.ts | 86 + apps/sim/tools/pylon/get_tag.ts | 86 + apps/sim/tools/pylon/get_team.ts | 86 + apps/sim/tools/pylon/get_user.ts | 86 + apps/sim/tools/pylon/index.ts | 47 + apps/sim/tools/pylon/link_external_issue.ts | 112 ++ apps/sim/tools/pylon/list_accounts.ts | 109 ++ apps/sim/tools/pylon/list_contacts.ts | 109 ++ apps/sim/tools/pylon/list_issue_followers.ts | 91 + apps/sim/tools/pylon/list_issues.ts | 114 ++ apps/sim/tools/pylon/list_tags.ts | 79 + apps/sim/tools/pylon/list_teams.ts | 79 + apps/sim/tools/pylon/list_users.ts | 79 + .../sim/tools/pylon/manage_issue_followers.ts | 128 ++ apps/sim/tools/pylon/redact_message.ts | 94 ++ apps/sim/tools/pylon/search_accounts.ts | 130 ++ apps/sim/tools/pylon/search_contacts.ts | 125 ++ apps/sim/tools/pylon/search_issues.ts | 124 ++ apps/sim/tools/pylon/search_users.ts | 122 ++ apps/sim/tools/pylon/snooze_issue.ts | 99 ++ apps/sim/tools/pylon/types.ts | 27 + apps/sim/tools/pylon/update_account.ts | 198 +++ apps/sim/tools/pylon/update_contact.ts | 159 ++ apps/sim/tools/pylon/update_issue.ts | 168 ++ apps/sim/tools/pylon/update_tag.ts | 109 ++ apps/sim/tools/pylon/update_team.ts | 113 ++ apps/sim/tools/pylon/update_user.ts | 109 ++ apps/sim/tools/registry.ts | 316 ++++ .../zendesk/autocomplete_organizations.ts | 133 ++ apps/sim/tools/zendesk/create_organization.ts | 154 ++ .../zendesk/create_organizations_bulk.ts | 106 ++ apps/sim/tools/zendesk/create_ticket.ts | 185 ++ apps/sim/tools/zendesk/create_tickets_bulk.ts | 107 ++ apps/sim/tools/zendesk/create_user.ts | 166 ++ apps/sim/tools/zendesk/create_users_bulk.ts | 106 ++ apps/sim/tools/zendesk/delete_organization.ts | 96 ++ apps/sim/tools/zendesk/delete_ticket.ts | 95 ++ apps/sim/tools/zendesk/delete_user.ts | 94 ++ apps/sim/tools/zendesk/export_search.ts | 116 ++ apps/sim/tools/zendesk/get_current_user.ts | 88 + apps/sim/tools/zendesk/get_organization.ts | 95 ++ apps/sim/tools/zendesk/get_organizations.ts | 124 ++ apps/sim/tools/zendesk/get_ticket.ts | 92 + apps/sim/tools/zendesk/get_tickets.ts | 178 ++ apps/sim/tools/zendesk/get_user.ts | 92 + apps/sim/tools/zendesk/get_users.ts | 137 ++ apps/sim/tools/zendesk/index.ts | 32 + apps/sim/tools/zendesk/merge_tickets.ts | 124 ++ apps/sim/tools/zendesk/search.ts | 145 ++ apps/sim/tools/zendesk/search_count.ts | 102 ++ apps/sim/tools/zendesk/search_users.ts | 140 ++ apps/sim/tools/zendesk/types.ts | 48 + apps/sim/tools/zendesk/update_organization.ts | 160 ++ apps/sim/tools/zendesk/update_ticket.ts | 183 ++ apps/sim/tools/zendesk/update_tickets_bulk.ts | 144 ++ apps/sim/tools/zendesk/update_user.ts | 173 ++ apps/sim/tools/zendesk/update_users_bulk.ts | 106 ++ 176 files changed, 24599 insertions(+) create mode 100644 apps/docs/content/docs/en/tools/intercom.mdx create mode 100644 apps/docs/content/docs/en/tools/mailchimp.mdx create mode 100644 apps/docs/content/docs/en/tools/pylon.mdx create mode 100644 apps/docs/content/docs/en/tools/zendesk.mdx create mode 100644 apps/sim/blocks/blocks/intercom.ts create mode 100644 apps/sim/blocks/blocks/mailchimp.ts create mode 100644 apps/sim/blocks/blocks/pylon.ts create mode 100644 apps/sim/blocks/blocks/zendesk.ts create mode 100644 apps/sim/tools/intercom/create_company.ts create mode 100644 apps/sim/tools/intercom/create_contact.ts create mode 100644 apps/sim/tools/intercom/create_message.ts create mode 100644 apps/sim/tools/intercom/create_ticket.ts create mode 100644 apps/sim/tools/intercom/delete_contact.ts create mode 100644 apps/sim/tools/intercom/get_company.ts create mode 100644 apps/sim/tools/intercom/get_contact.ts create mode 100644 apps/sim/tools/intercom/get_conversation.ts create mode 100644 apps/sim/tools/intercom/get_ticket.ts create mode 100644 apps/sim/tools/intercom/index.ts create mode 100644 apps/sim/tools/intercom/list_companies.ts create mode 100644 apps/sim/tools/intercom/list_contacts.ts create mode 100644 apps/sim/tools/intercom/list_conversations.ts create mode 100644 apps/sim/tools/intercom/list_tickets.ts create mode 100644 apps/sim/tools/intercom/reply_conversation.ts create mode 100644 apps/sim/tools/intercom/search_contacts.ts create mode 100644 apps/sim/tools/intercom/search_conversations.ts create mode 100644 apps/sim/tools/intercom/types.ts create mode 100644 apps/sim/tools/intercom/update_contact.ts create mode 100644 apps/sim/tools/mailchimp/add_member.ts create mode 100644 apps/sim/tools/mailchimp/add_member_tags.ts create mode 100644 apps/sim/tools/mailchimp/add_or_update_member.ts create mode 100644 apps/sim/tools/mailchimp/add_segment_member.ts create mode 100644 apps/sim/tools/mailchimp/add_subscriber_to_automation.ts create mode 100644 apps/sim/tools/mailchimp/archive_member.ts create mode 100644 apps/sim/tools/mailchimp/create_audience.ts create mode 100644 apps/sim/tools/mailchimp/create_batch_operation.ts create mode 100644 apps/sim/tools/mailchimp/create_campaign.ts create mode 100644 apps/sim/tools/mailchimp/create_interest.ts create mode 100644 apps/sim/tools/mailchimp/create_interest_category.ts create mode 100644 apps/sim/tools/mailchimp/create_landing_page.ts create mode 100644 apps/sim/tools/mailchimp/create_merge_field.ts create mode 100644 apps/sim/tools/mailchimp/create_segment.ts create mode 100644 apps/sim/tools/mailchimp/create_template.ts create mode 100644 apps/sim/tools/mailchimp/delete_audience.ts create mode 100644 apps/sim/tools/mailchimp/delete_batch_operation.ts create mode 100644 apps/sim/tools/mailchimp/delete_campaign.ts create mode 100644 apps/sim/tools/mailchimp/delete_interest.ts create mode 100644 apps/sim/tools/mailchimp/delete_interest_category.ts create mode 100644 apps/sim/tools/mailchimp/delete_landing_page.ts create mode 100644 apps/sim/tools/mailchimp/delete_member.ts create mode 100644 apps/sim/tools/mailchimp/delete_merge_field.ts create mode 100644 apps/sim/tools/mailchimp/delete_segment.ts create mode 100644 apps/sim/tools/mailchimp/delete_template.ts create mode 100644 apps/sim/tools/mailchimp/get_audience.ts create mode 100644 apps/sim/tools/mailchimp/get_audiences.ts create mode 100644 apps/sim/tools/mailchimp/get_automation.ts create mode 100644 apps/sim/tools/mailchimp/get_automations.ts create mode 100644 apps/sim/tools/mailchimp/get_batch_operation.ts create mode 100644 apps/sim/tools/mailchimp/get_batch_operations.ts create mode 100644 apps/sim/tools/mailchimp/get_campaign.ts create mode 100644 apps/sim/tools/mailchimp/get_campaign_content.ts create mode 100644 apps/sim/tools/mailchimp/get_campaign_report.ts create mode 100644 apps/sim/tools/mailchimp/get_campaign_reports.ts create mode 100644 apps/sim/tools/mailchimp/get_campaigns.ts create mode 100644 apps/sim/tools/mailchimp/get_interest.ts create mode 100644 apps/sim/tools/mailchimp/get_interest_categories.ts create mode 100644 apps/sim/tools/mailchimp/get_interest_category.ts create mode 100644 apps/sim/tools/mailchimp/get_interests.ts create mode 100644 apps/sim/tools/mailchimp/get_landing_page.ts create mode 100644 apps/sim/tools/mailchimp/get_landing_pages.ts create mode 100644 apps/sim/tools/mailchimp/get_member.ts create mode 100644 apps/sim/tools/mailchimp/get_member_tags.ts create mode 100644 apps/sim/tools/mailchimp/get_members.ts create mode 100644 apps/sim/tools/mailchimp/get_merge_field.ts create mode 100644 apps/sim/tools/mailchimp/get_merge_fields.ts create mode 100644 apps/sim/tools/mailchimp/get_segment.ts create mode 100644 apps/sim/tools/mailchimp/get_segment_members.ts create mode 100644 apps/sim/tools/mailchimp/get_segments.ts create mode 100644 apps/sim/tools/mailchimp/get_template.ts create mode 100644 apps/sim/tools/mailchimp/get_templates.ts create mode 100644 apps/sim/tools/mailchimp/index.ts create mode 100644 apps/sim/tools/mailchimp/pause_automation.ts create mode 100644 apps/sim/tools/mailchimp/publish_landing_page.ts create mode 100644 apps/sim/tools/mailchimp/remove_member_tags.ts create mode 100644 apps/sim/tools/mailchimp/remove_segment_member.ts create mode 100644 apps/sim/tools/mailchimp/replicate_campaign.ts create mode 100644 apps/sim/tools/mailchimp/schedule_campaign.ts create mode 100644 apps/sim/tools/mailchimp/send_campaign.ts create mode 100644 apps/sim/tools/mailchimp/set_campaign_content.ts create mode 100644 apps/sim/tools/mailchimp/start_automation.ts create mode 100644 apps/sim/tools/mailchimp/types.ts create mode 100644 apps/sim/tools/mailchimp/unarchive_member.ts create mode 100644 apps/sim/tools/mailchimp/unpublish_landing_page.ts create mode 100644 apps/sim/tools/mailchimp/unschedule_campaign.ts create mode 100644 apps/sim/tools/mailchimp/update_audience.ts create mode 100644 apps/sim/tools/mailchimp/update_campaign.ts create mode 100644 apps/sim/tools/mailchimp/update_interest.ts create mode 100644 apps/sim/tools/mailchimp/update_interest_category.ts create mode 100644 apps/sim/tools/mailchimp/update_landing_page.ts create mode 100644 apps/sim/tools/mailchimp/update_member.ts create mode 100644 apps/sim/tools/mailchimp/update_merge_field.ts create mode 100644 apps/sim/tools/mailchimp/update_segment.ts create mode 100644 apps/sim/tools/mailchimp/update_template.ts create mode 100644 apps/sim/tools/pylon/bulk_update_accounts.ts create mode 100644 apps/sim/tools/pylon/create_account.ts create mode 100644 apps/sim/tools/pylon/create_contact.ts create mode 100644 apps/sim/tools/pylon/create_issue.ts create mode 100644 apps/sim/tools/pylon/create_tag.ts create mode 100644 apps/sim/tools/pylon/create_team.ts create mode 100644 apps/sim/tools/pylon/delete_account.ts create mode 100644 apps/sim/tools/pylon/delete_contact.ts create mode 100644 apps/sim/tools/pylon/delete_issue.ts create mode 100644 apps/sim/tools/pylon/delete_tag.ts create mode 100644 apps/sim/tools/pylon/get_account.ts create mode 100644 apps/sim/tools/pylon/get_contact.ts create mode 100644 apps/sim/tools/pylon/get_issue.ts create mode 100644 apps/sim/tools/pylon/get_tag.ts create mode 100644 apps/sim/tools/pylon/get_team.ts create mode 100644 apps/sim/tools/pylon/get_user.ts create mode 100644 apps/sim/tools/pylon/index.ts create mode 100644 apps/sim/tools/pylon/link_external_issue.ts create mode 100644 apps/sim/tools/pylon/list_accounts.ts create mode 100644 apps/sim/tools/pylon/list_contacts.ts create mode 100644 apps/sim/tools/pylon/list_issue_followers.ts create mode 100644 apps/sim/tools/pylon/list_issues.ts create mode 100644 apps/sim/tools/pylon/list_tags.ts create mode 100644 apps/sim/tools/pylon/list_teams.ts create mode 100644 apps/sim/tools/pylon/list_users.ts create mode 100644 apps/sim/tools/pylon/manage_issue_followers.ts create mode 100644 apps/sim/tools/pylon/redact_message.ts create mode 100644 apps/sim/tools/pylon/search_accounts.ts create mode 100644 apps/sim/tools/pylon/search_contacts.ts create mode 100644 apps/sim/tools/pylon/search_issues.ts create mode 100644 apps/sim/tools/pylon/search_users.ts create mode 100644 apps/sim/tools/pylon/snooze_issue.ts create mode 100644 apps/sim/tools/pylon/types.ts create mode 100644 apps/sim/tools/pylon/update_account.ts create mode 100644 apps/sim/tools/pylon/update_contact.ts create mode 100644 apps/sim/tools/pylon/update_issue.ts create mode 100644 apps/sim/tools/pylon/update_tag.ts create mode 100644 apps/sim/tools/pylon/update_team.ts create mode 100644 apps/sim/tools/pylon/update_user.ts create mode 100644 apps/sim/tools/zendesk/autocomplete_organizations.ts create mode 100644 apps/sim/tools/zendesk/create_organization.ts create mode 100644 apps/sim/tools/zendesk/create_organizations_bulk.ts create mode 100644 apps/sim/tools/zendesk/create_ticket.ts create mode 100644 apps/sim/tools/zendesk/create_tickets_bulk.ts create mode 100644 apps/sim/tools/zendesk/create_user.ts create mode 100644 apps/sim/tools/zendesk/create_users_bulk.ts create mode 100644 apps/sim/tools/zendesk/delete_organization.ts create mode 100644 apps/sim/tools/zendesk/delete_ticket.ts create mode 100644 apps/sim/tools/zendesk/delete_user.ts create mode 100644 apps/sim/tools/zendesk/export_search.ts create mode 100644 apps/sim/tools/zendesk/get_current_user.ts create mode 100644 apps/sim/tools/zendesk/get_organization.ts create mode 100644 apps/sim/tools/zendesk/get_organizations.ts create mode 100644 apps/sim/tools/zendesk/get_ticket.ts create mode 100644 apps/sim/tools/zendesk/get_tickets.ts create mode 100644 apps/sim/tools/zendesk/get_user.ts create mode 100644 apps/sim/tools/zendesk/get_users.ts create mode 100644 apps/sim/tools/zendesk/index.ts create mode 100644 apps/sim/tools/zendesk/merge_tickets.ts create mode 100644 apps/sim/tools/zendesk/search.ts create mode 100644 apps/sim/tools/zendesk/search_count.ts create mode 100644 apps/sim/tools/zendesk/search_users.ts create mode 100644 apps/sim/tools/zendesk/types.ts create mode 100644 apps/sim/tools/zendesk/update_organization.ts create mode 100644 apps/sim/tools/zendesk/update_ticket.ts create mode 100644 apps/sim/tools/zendesk/update_tickets_bulk.ts create mode 100644 apps/sim/tools/zendesk/update_user.ts create mode 100644 apps/sim/tools/zendesk/update_users_bulk.ts diff --git a/apps/docs/components/icons.tsx b/apps/docs/components/icons.tsx index a99241ff32..9c9f00984a 100644 --- a/apps/docs/components/icons.tsx +++ b/apps/docs/components/icons.tsx @@ -4243,3 +4243,104 @@ export function IncidentioIcon(props: SVGProps) { ) } + +export function IntercomIcon(props: SVGProps) { + return ( + + + + + + ) +} + +export function MailchimpIcon(props: SVGProps) { + return ( + + + + + + + + + + + + + + + + + + ) +} + +export function ZendeskIcon(props: SVGProps) { + return ( + + + + + + ) +} + +export function PylonIcon(props: SVGProps) { + return ( + + + + + + + + + + + ) +} diff --git a/apps/docs/components/ui/icon-mapping.ts b/apps/docs/components/ui/icon-mapping.ts index 7f40c6b51e..ad748928c5 100644 --- a/apps/docs/components/ui/icon-mapping.ts +++ b/apps/docs/components/ui/icon-mapping.ts @@ -33,10 +33,12 @@ import { HunterIOIcon, ImageIcon, IncidentioIcon, + IntercomIcon, JinaAIIcon, JiraIcon, LinearIcon, LinkupIcon, + MailchimpIcon, Mem0Icon, MicrosoftExcelIcon, MicrosoftOneDriveIcon, @@ -57,6 +59,7 @@ import { PipedriveIcon, PostgresIcon, PosthogIcon, + PylonIcon, QdrantIcon, RedditIcon, ResendIcon, @@ -83,6 +86,7 @@ import { WikipediaIcon, xIcon, YouTubeIcon, + ZendeskIcon, ZepIcon, } from '@/components/icons' @@ -90,6 +94,7 @@ type IconComponent = ComponentType> export const blockTypeToIconMap: Record = { zep: ZepIcon, + zendesk: ZendeskIcon, youtube: YouTubeIcon, x: xIcon, wikipedia: WikipediaIcon, @@ -121,6 +126,7 @@ export const blockTypeToIconMap: Record = { resend: ResendIcon, reddit: RedditIcon, qdrant: QdrantIcon, + pylon: PylonIcon, posthog: PosthogIcon, postgresql: PostgresIcon, pipedrive: PipedriveIcon, @@ -140,11 +146,13 @@ export const blockTypeToIconMap: Record = { microsoft_excel: MicrosoftExcelIcon, memory: BrainIcon, mem0: Mem0Icon, + mailchimp: MailchimpIcon, linkup: LinkupIcon, linear: LinearIcon, knowledge: PackageSearchIcon, jira: JiraIcon, jina: JinaAIIcon, + intercom: IntercomIcon, incidentio: IncidentioIcon, image_generator: ImageIcon, hunter: HunterIOIcon, diff --git a/apps/docs/content/docs/en/tools/intercom.mdx b/apps/docs/content/docs/en/tools/intercom.mdx new file mode 100644 index 0000000000..68c1220d21 --- /dev/null +++ b/apps/docs/content/docs/en/tools/intercom.mdx @@ -0,0 +1,361 @@ +--- +title: Intercom +description: Manage contacts, companies, conversations, tickets, and messages in Intercom +--- + +import { BlockInfoCard } from "@/components/ui/block-info-card" + + + +## Usage Instructions + +Integrate Intercom into the workflow. Can create, get, update, list, search, and delete contacts; create, get, and list companies; get, list, reply, and search conversations; create, get, and list tickets; and create messages. + + + +## Tools + +### `intercom_create_contact` + +Create a new contact in Intercom with email, external_id, or role + +#### Input + +| Parameter | Type | Required | Description | +| --------- | ---- | -------- | ----------- | +| `email` | string | No | The contact's email address | +| `external_id` | string | No | A unique identifier for the contact provided by the client | +| `phone` | string | No | The contact's phone number | +| `name` | string | No | The contact's name | +| `avatar` | string | No | An avatar image URL for the contact | +| `signed_up_at` | number | No | The time the user signed up as a Unix timestamp | +| `last_seen_at` | number | No | The time the user was last seen as a Unix timestamp | +| `owner_id` | string | No | The id of an admin that has been assigned account ownership of the contact | +| `unsubscribed_from_emails` | boolean | No | Whether the contact is unsubscribed from emails | +| `custom_attributes` | string | No | Custom attributes as JSON object \(e.g., \{"attribute_name": "value"\}\) | + +#### Output + +| Parameter | Type | Description | +| --------- | ---- | ----------- | +| `success` | boolean | Operation success status | +| `output` | object | Created contact data | + +### `intercom_get_contact` + +Get a single contact by ID from Intercom + +#### Input + +| Parameter | Type | Required | Description | +| --------- | ---- | -------- | ----------- | +| `contactId` | string | Yes | Contact ID to retrieve | + +#### Output + +| Parameter | Type | Description | +| --------- | ---- | ----------- | +| `success` | boolean | Operation success status | +| `output` | object | Contact data | + +### `intercom_update_contact` + +Update an existing contact in Intercom + +#### Input + +| Parameter | Type | Required | Description | +| --------- | ---- | -------- | ----------- | +| `contactId` | string | Yes | Contact ID to update | +| `email` | string | No | The contact's email address | +| `phone` | string | No | The contact's phone number | +| `name` | string | No | The contact's name | +| `avatar` | string | No | An avatar image URL for the contact | +| `signed_up_at` | number | No | The time the user signed up as a Unix timestamp | +| `last_seen_at` | number | No | The time the user was last seen as a Unix timestamp | +| `owner_id` | string | No | The id of an admin that has been assigned account ownership of the contact | +| `unsubscribed_from_emails` | boolean | No | Whether the contact is unsubscribed from emails | +| `custom_attributes` | string | No | Custom attributes as JSON object \(e.g., \{"attribute_name": "value"\}\) | + +#### Output + +| Parameter | Type | Description | +| --------- | ---- | ----------- | +| `success` | boolean | Operation success status | +| `output` | object | Updated contact data | + +### `intercom_list_contacts` + +List all contacts from Intercom with pagination support + +#### Input + +| Parameter | Type | Required | Description | +| --------- | ---- | -------- | ----------- | +| `per_page` | number | No | Number of results per page \(max: 150\) | +| `starting_after` | string | No | Cursor for pagination - ID to start after | + +#### Output + +| Parameter | Type | Description | +| --------- | ---- | ----------- | +| `success` | boolean | Operation success status | +| `output` | object | List of contacts | + +### `intercom_search_contacts` + +Search for contacts in Intercom using a query + +#### Input + +| Parameter | Type | Required | Description | +| --------- | ---- | -------- | ----------- | +| `query` | string | Yes | Search query \(e.g., \{"field":"email","operator":"=","value":"user@example.com"\}\) | +| `per_page` | number | No | Number of results per page \(max: 150\) | +| `starting_after` | string | No | Cursor for pagination | + +#### Output + +| Parameter | Type | Description | +| --------- | ---- | ----------- | +| `success` | boolean | Operation success status | +| `output` | object | Search results | + +### `intercom_delete_contact` + +Delete a contact from Intercom by ID + +#### Input + +| Parameter | Type | Required | Description | +| --------- | ---- | -------- | ----------- | +| `contactId` | string | Yes | Contact ID to delete | + +#### Output + +| Parameter | Type | Description | +| --------- | ---- | ----------- | +| `success` | boolean | Operation success status | +| `output` | object | Deletion result | + +### `intercom_create_company` + +Create or update a company in Intercom + +#### Input + +| Parameter | Type | Required | Description | +| --------- | ---- | -------- | ----------- | +| `company_id` | string | Yes | Your unique identifier for the company | +| `name` | string | No | The name of the company | +| `website` | string | No | The company website | +| `plan` | string | No | The company plan name | +| `size` | number | No | The number of employees in the company | +| `industry` | string | No | The industry the company operates in | +| `monthly_spend` | number | No | How much revenue the company generates for your business | +| `custom_attributes` | string | No | Custom attributes as JSON object | + +#### Output + +| Parameter | Type | Description | +| --------- | ---- | ----------- | +| `success` | boolean | Operation success status | +| `output` | object | Created or updated company data | + +### `intercom_get_company` + +Retrieve a single company by ID from Intercom + +#### Input + +| Parameter | Type | Required | Description | +| --------- | ---- | -------- | ----------- | +| `companyId` | string | Yes | Company ID to retrieve | + +#### Output + +| Parameter | Type | Description | +| --------- | ---- | ----------- | +| `success` | boolean | Operation success status | +| `output` | object | Company data | + +### `intercom_list_companies` + +List all companies from Intercom with pagination support + +#### Input + +| Parameter | Type | Required | Description | +| --------- | ---- | -------- | ----------- | +| `per_page` | number | No | Number of results per page | +| `page` | number | No | Page number | + +#### Output + +| Parameter | Type | Description | +| --------- | ---- | ----------- | +| `success` | boolean | Operation success status | +| `output` | object | List of companies | + +### `intercom_get_conversation` + +Retrieve a single conversation by ID from Intercom + +#### Input + +| Parameter | Type | Required | Description | +| --------- | ---- | -------- | ----------- | +| `conversationId` | string | Yes | Conversation ID to retrieve | +| `display_as` | string | No | Set to "plaintext" to retrieve messages in plain text | + +#### Output + +| Parameter | Type | Description | +| --------- | ---- | ----------- | +| `success` | boolean | Operation success status | +| `output` | object | Conversation data | + +### `intercom_list_conversations` + +List all conversations from Intercom with pagination support + +#### Input + +| Parameter | Type | Required | Description | +| --------- | ---- | -------- | ----------- | +| `per_page` | number | No | Number of results per page \(max: 150\) | +| `starting_after` | string | No | Cursor for pagination | + +#### Output + +| Parameter | Type | Description | +| --------- | ---- | ----------- | +| `success` | boolean | Operation success status | +| `output` | object | List of conversations | + +### `intercom_reply_conversation` + +Reply to a conversation as an admin in Intercom + +#### Input + +| Parameter | Type | Required | Description | +| --------- | ---- | -------- | ----------- | +| `conversationId` | string | Yes | Conversation ID to reply to | +| `message_type` | string | Yes | Message type: "comment" or "note" | +| `body` | string | Yes | The text body of the reply | +| `admin_id` | string | Yes | The ID of the admin authoring the reply | +| `attachment_urls` | string | No | Comma-separated list of image URLs \(max 10\) | + +#### Output + +| Parameter | Type | Description | +| --------- | ---- | ----------- | +| `success` | boolean | Operation success status | +| `output` | object | Updated conversation with reply | + +### `intercom_search_conversations` + +Search for conversations in Intercom using a query + +#### Input + +| Parameter | Type | Required | Description | +| --------- | ---- | -------- | ----------- | +| `query` | string | Yes | Search query as JSON object | +| `per_page` | number | No | Number of results per page \(max: 150\) | +| `starting_after` | string | No | Cursor for pagination | + +#### Output + +| Parameter | Type | Description | +| --------- | ---- | ----------- | +| `success` | boolean | Operation success status | +| `output` | object | Search results | + +### `intercom_create_ticket` + +Create a new ticket in Intercom + +#### Input + +| Parameter | Type | Required | Description | +| --------- | ---- | -------- | ----------- | +| `ticket_type_id` | string | Yes | The ID of the ticket type | +| `contacts` | string | Yes | JSON array of contact identifiers \(e.g., \[\{"id": "contact_id"\}\]\) | +| `ticket_attributes` | string | Yes | JSON object with ticket attributes including _default_title_ and _default_description_ | + +#### Output + +| Parameter | Type | Description | +| --------- | ---- | ----------- | +| `success` | boolean | Operation success status | +| `output` | object | Created ticket data | + +### `intercom_get_ticket` + +Retrieve a single ticket by ID from Intercom + +#### Input + +| Parameter | Type | Required | Description | +| --------- | ---- | -------- | ----------- | +| `ticketId` | string | Yes | Ticket ID to retrieve | + +#### Output + +| Parameter | Type | Description | +| --------- | ---- | ----------- | +| `success` | boolean | Operation success status | +| `output` | object | Ticket data | + +### `intercom_list_tickets` + +List all tickets from Intercom with pagination support + +#### Input + +| Parameter | Type | Required | Description | +| --------- | ---- | -------- | ----------- | +| `per_page` | number | No | Number of results per page \(max: 150\) | +| `starting_after` | string | No | Cursor for pagination | + +#### Output + +| Parameter | Type | Description | +| --------- | ---- | ----------- | +| `success` | boolean | Operation success status | +| `output` | object | List of tickets | + +### `intercom_create_message` + +Create and send a new admin-initiated message in Intercom + +#### Input + +| Parameter | Type | Required | Description | +| --------- | ---- | -------- | ----------- | +| `message_type` | string | Yes | Message type: "inapp" or "email" | +| `subject` | string | No | The subject of the message \(for email type\) | +| `body` | string | Yes | The body of the message | +| `from_type` | string | Yes | Sender type: "admin" | +| `from_id` | string | Yes | The ID of the admin sending the message | +| `to_type` | string | Yes | Recipient type: "contact" | +| `to_id` | string | Yes | The ID of the contact receiving the message | + +#### Output + +| Parameter | Type | Description | +| --------- | ---- | ----------- | +| `success` | boolean | Operation success status | +| `output` | object | Created message data | + + + +## Notes + +- Category: `tools` +- Type: `intercom` diff --git a/apps/docs/content/docs/en/tools/mailchimp.mdx b/apps/docs/content/docs/en/tools/mailchimp.mdx new file mode 100644 index 0000000000..6876bb1d95 --- /dev/null +++ b/apps/docs/content/docs/en/tools/mailchimp.mdx @@ -0,0 +1,1481 @@ +--- +title: Mailchimp +description: Manage audiences, campaigns, and marketing automation in Mailchimp +--- + +import { BlockInfoCard } from "@/components/ui/block-info-card" + + + +{/* MANUAL-CONTENT-START:intro */} +[Mailchimp](https://mailchimp.com/) is the world's leading email marketing and automation platform that helps businesses connect with their audience through targeted campaigns, automated workflows, and powerful analytics. Its comprehensive API provides complete control over every aspect of email marketing, from audience management to campaign creation and reporting. + +With Mailchimp's extensive integration in Sim, your agents can automate virtually any marketing task programmatically. The Mailchimp integration provides comprehensive access to actions such as: + +- **Audience (List) management**: + - Retrieve audiences and manage list settings (`mailchimp_get_audiences`, `mailchimp_get_audience`) + - Create, update, and delete audiences (`mailchimp_create_audience`, `mailchimp_update_audience`, `mailchimp_delete_audience`) + - Manage audience members with full subscriber lifecycle (`mailchimp_get_members`, `mailchimp_add_member`, `mailchimp_add_or_update_member`, `mailchimp_update_member`, `mailchimp_delete_member`, `mailchimp_archive_member`, `mailchimp_unarchive_member`) +- **Campaign operations**: + - List, create, update, and manage email campaigns (`mailchimp_get_campaigns`, `mailchimp_create_campaign`, `mailchimp_update_campaign`) + - Send, schedule, and unschedule campaigns (`mailchimp_send_campaign`, `mailchimp_schedule_campaign`, `mailchimp_unschedule_campaign`) + - Manage campaign content and replicate successful campaigns (`mailchimp_get_campaign_content`, `mailchimp_set_campaign_content`, `mailchimp_replicate_campaign`) +- **Automation workflows**: + - Manage automated email sequences and triggers (`mailchimp_get_automations`, `mailchimp_get_automation`) + - Start and pause automation workflows (`mailchimp_start_automation`, `mailchimp_pause_automation`) + - Add subscribers to automation workflows (`mailchimp_add_subscriber_to_automation`) +- **Segmentation and targeting**: + - Create and manage audience segments for targeted campaigns (`mailchimp_get_segments`, `mailchimp_create_segment`, `mailchimp_update_segment`) + - Manage segment members (`mailchimp_get_segment_members`, `mailchimp_add_segment_member`, `mailchimp_remove_segment_member`) + - Tag management for flexible subscriber organization (`mailchimp_get_member_tags`, `mailchimp_add_member_tags`, `mailchimp_remove_member_tags`) +- **Template management**: + - Create, update, and manage email templates (`mailchimp_get_templates`, `mailchimp_create_template`, `mailchimp_update_template`) + - Reuse templates across campaigns for consistent branding +- **Advanced features**: + - Merge fields for personalization (`mailchimp_get_merge_fields`, `mailchimp_create_merge_field`) + - Interest categories and interests for subscriber preferences (`mailchimp_get_interest_categories`, `mailchimp_get_interests`, `mailchimp_create_interest_category`) + - Landing pages for lead generation (`mailchimp_get_landing_pages`, `mailchimp_create_landing_page`, `mailchimp_publish_landing_page`) + - Batch operations for bulk updates (`mailchimp_create_batch_operation`) + - Campaign reports and analytics (`mailchimp_get_campaign_reports`, `mailchimp_get_campaign_report`) + +The Mailchimp integration covers all major Marketing API endpoints including audiences (lists), members, campaigns, automation workflows, templates, segments, tags, merge fields, interest categories, landing pages, reports, and batch operations. This enables complete automation of email marketing workflows from subscriber onboarding to campaign execution and performance tracking. + +Whether you need to build automated welcome sequences, sync customer data across platforms, create targeted campaigns, or generate marketing reports, the Mailchimp integration in Sim provides comprehensive control for any email marketing automation need. +{/* MANUAL-CONTENT-END */} + + +## Usage Instructions + +Integrate Mailchimp into the workflow. Can manage audiences (lists), list members, campaigns, automation workflows, templates, reports, segments, tags, merge fields, interest categories, landing pages, signup forms, and batch operations. + + + +## Tools + +### `mailchimp_get_audiences` + +Retrieve a list of audiences (lists) from Mailchimp + +#### Input + +| Parameter | Type | Required | Description | +| --------- | ---- | -------- | ----------- | +| `apiKey` | string | Yes | Mailchimp API key with server prefix | +| `count` | string | No | Number of results \(default: 10, max: 1000\) | +| `offset` | string | No | Number of results to skip | + +#### Output + +| Parameter | Type | Description | +| --------- | ---- | ----------- | +| `success` | boolean | Operation success status | +| `output` | object | Audiences data and metadata | + +### `mailchimp_get_audience` + +Retrieve details of a specific audience (list) from Mailchimp + +#### Input + +| Parameter | Type | Required | Description | +| --------- | ---- | -------- | ----------- | +| `apiKey` | string | Yes | Mailchimp API key with server prefix | +| `listId` | string | Yes | The unique ID for the list | + +#### Output + +| Parameter | Type | Description | +| --------- | ---- | ----------- | +| `success` | boolean | Operation success status | +| `output` | object | Audience data and metadata | + +### `mailchimp_create_audience` + +Create a new audience (list) in Mailchimp + +#### Input + +| Parameter | Type | Required | Description | +| --------- | ---- | -------- | ----------- | +| `apiKey` | string | Yes | Mailchimp API key with server prefix | +| `audienceName` | string | Yes | The name of the list | +| `contact` | string | Yes | Contact information as JSON \(e.g., \{"company": "Acme Inc", "address1": "123 Main St", "city": "Atlanta", "state": "GA", "zip": "30308", "country": "US"\}\) | +| `permissionReminder` | string | Yes | Permission reminder text \(why subscribers are on your list\) | +| `campaignDefaults` | string | Yes | Default campaign settings as JSON \(e.g., \{"from_name": "John", "from_email": "john@example.com", "subject": "Newsletter", "language": "en"\}\) | +| `emailTypeOption` | string | Yes | Whether the list supports multiple formats \(true/false\) | + +#### Output + +| Parameter | Type | Description | +| --------- | ---- | ----------- | +| `success` | boolean | Operation success status | +| `output` | object | Created audience data | + +### `mailchimp_update_audience` + +Update an existing audience (list) in Mailchimp + +#### Input + +| Parameter | Type | Required | Description | +| --------- | ---- | -------- | ----------- | +| `apiKey` | string | Yes | Mailchimp API key with server prefix | +| `listId` | string | Yes | The unique ID for the list | +| `audienceName` | string | No | The name of the list | +| `permissionReminder` | string | No | Permission reminder text | +| `campaignDefaults` | string | No | Default campaign settings as JSON | +| `emailTypeOption` | string | No | Whether the list supports multiple formats \(true/false\) | + +#### Output + +| Parameter | Type | Description | +| --------- | ---- | ----------- | +| `success` | boolean | Operation success status | +| `output` | object | Updated audience data | + +### `mailchimp_delete_audience` + +Delete an audience (list) from Mailchimp + +#### Input + +| Parameter | Type | Required | Description | +| --------- | ---- | -------- | ----------- | +| `apiKey` | string | Yes | Mailchimp API key with server prefix | +| `listId` | string | Yes | The unique ID for the list to delete | + +#### Output + +| Parameter | Type | Description | +| --------- | ---- | ----------- | +| `success` | boolean | Operation success status | +| `output` | object | Deletion confirmation | + +### `mailchimp_get_members` + +Retrieve a list of members from a Mailchimp audience + +#### Input + +| Parameter | Type | Required | Description | +| --------- | ---- | -------- | ----------- | +| `apiKey` | string | Yes | Mailchimp API key with server prefix | +| `listId` | string | Yes | The unique ID for the list | +| `status` | string | No | Filter by status \(subscribed, unsubscribed, cleaned, pending\) | +| `count` | string | No | Number of results \(default: 10, max: 1000\) | +| `offset` | string | No | Number of results to skip | + +#### Output + +| Parameter | Type | Description | +| --------- | ---- | ----------- | +| `success` | boolean | Operation success status | +| `output` | object | Members data and metadata | + +### `mailchimp_get_member` + +Retrieve details of a specific member from a Mailchimp audience + +#### Input + +| Parameter | Type | Required | Description | +| --------- | ---- | -------- | ----------- | +| `apiKey` | string | Yes | Mailchimp API key with server prefix | +| `listId` | string | Yes | The unique ID for the list | +| `subscriberHash` | string | Yes | The MD5 hash of the lowercase version of the list member's email address | + +#### Output + +| Parameter | Type | Description | +| --------- | ---- | ----------- | +| `success` | boolean | Operation success status | +| `output` | object | Member data and metadata | + +### `mailchimp_add_member` + +Add a new member to a Mailchimp audience + +#### Input + +| Parameter | Type | Required | Description | +| --------- | ---- | -------- | ----------- | +| `apiKey` | string | Yes | Mailchimp API key with server prefix | +| `listId` | string | Yes | The unique ID for the list | +| `emailAddress` | string | Yes | Email address for the member | +| `status` | string | Yes | Subscriber status \(subscribed, unsubscribed, cleaned, pending\) | +| `mergeFields` | string | No | Merge fields as JSON object \(e.g., \{"FNAME": "John", "LNAME": "Doe"\}\) | +| `interests` | string | No | Interests as JSON object \(e.g., \{"interest_id": true\}\) | + +#### Output + +| Parameter | Type | Description | +| --------- | ---- | ----------- | +| `success` | boolean | Operation success status | +| `output` | object | Added member data | + +### `mailchimp_add_or_update_member` + +Add a new member or update an existing member in a Mailchimp audience (upsert) + +#### Input + +| Parameter | Type | Required | Description | +| --------- | ---- | -------- | ----------- | +| `apiKey` | string | Yes | Mailchimp API key with server prefix | +| `listId` | string | Yes | The unique ID for the list | +| `subscriberHash` | string | Yes | The MD5 hash of the lowercase version of the list member's email address | +| `emailAddress` | string | Yes | Email address for the member | +| `statusIfNew` | string | Yes | Subscriber status if new member \(subscribed, unsubscribed, cleaned, pending\) | +| `mergeFields` | string | No | Merge fields as JSON object \(e.g., \{"FNAME": "John", "LNAME": "Doe"\}\) | +| `interests` | string | No | Interests as JSON object \(e.g., \{"interest_id": true\}\) | + +#### Output + +| Parameter | Type | Description | +| --------- | ---- | ----------- | +| `success` | boolean | Operation success status | +| `output` | object | Member data | + +### `mailchimp_update_member` + +Update an existing member in a Mailchimp audience + +#### Input + +| Parameter | Type | Required | Description | +| --------- | ---- | -------- | ----------- | +| `apiKey` | string | Yes | Mailchimp API key with server prefix | +| `listId` | string | Yes | The unique ID for the list | +| `subscriberHash` | string | Yes | The MD5 hash of the lowercase version of the list member's email address | +| `emailAddress` | string | No | Email address for the member | +| `status` | string | No | Subscriber status \(subscribed, unsubscribed, cleaned, pending\) | +| `mergeFields` | string | No | Merge fields as JSON object | +| `interests` | string | No | Interests as JSON object | + +#### Output + +| Parameter | Type | Description | +| --------- | ---- | ----------- | +| `success` | boolean | Operation success status | +| `output` | object | Updated member data | + +### `mailchimp_delete_member` + +Delete a member from a Mailchimp audience + +#### Input + +| Parameter | Type | Required | Description | +| --------- | ---- | -------- | ----------- | +| `apiKey` | string | Yes | Mailchimp API key with server prefix | +| `listId` | string | Yes | The unique ID for the list | +| `subscriberHash` | string | Yes | The MD5 hash of the lowercase version of the list member's email address | + +#### Output + +| Parameter | Type | Description | +| --------- | ---- | ----------- | +| `success` | boolean | Operation success status | +| `output` | object | Deletion confirmation | + +### `mailchimp_archive_member` + +Permanently archive (delete) a member from a Mailchimp audience + +#### Input + +| Parameter | Type | Required | Description | +| --------- | ---- | -------- | ----------- | +| `apiKey` | string | Yes | Mailchimp API key with server prefix | +| `listId` | string | Yes | The unique ID for the list | +| `subscriberHash` | string | Yes | The MD5 hash of the lowercase version of the list member's email address | + +#### Output + +| Parameter | Type | Description | +| --------- | ---- | ----------- | +| `success` | boolean | Operation success status | +| `output` | object | Archive confirmation | + +### `mailchimp_unarchive_member` + +Restore an archived member to a Mailchimp audience + +#### Input + +| Parameter | Type | Required | Description | +| --------- | ---- | -------- | ----------- | +| `apiKey` | string | Yes | Mailchimp API key with server prefix | +| `listId` | string | Yes | The unique ID for the list | +| `subscriberHash` | string | Yes | The MD5 hash of the lowercase version of the list member's email address | +| `emailAddress` | string | Yes | Email address for the member | +| `status` | string | Yes | Subscriber status \(subscribed, unsubscribed, cleaned, pending\) | + +#### Output + +| Parameter | Type | Description | +| --------- | ---- | ----------- | +| `success` | boolean | Operation success status | +| `output` | object | Unarchived member data | + +### `mailchimp_get_campaigns` + +Retrieve a list of campaigns from Mailchimp + +#### Input + +| Parameter | Type | Required | Description | +| --------- | ---- | -------- | ----------- | +| `apiKey` | string | Yes | Mailchimp API key with server prefix | +| `campaignType` | string | No | Filter by campaign type \(regular, plaintext, absplit, rss, variate\) | +| `status` | string | No | Filter by status \(save, paused, schedule, sending, sent\) | +| `count` | string | No | Number of results \(default: 10, max: 1000\) | +| `offset` | string | No | Number of results to skip | + +#### Output + +| Parameter | Type | Description | +| --------- | ---- | ----------- | +| `success` | boolean | Operation success status | +| `output` | object | Campaigns data and metadata | + +### `mailchimp_get_campaign` + +Retrieve details of a specific campaign from Mailchimp + +#### Input + +| Parameter | Type | Required | Description | +| --------- | ---- | -------- | ----------- | +| `apiKey` | string | Yes | Mailchimp API key with server prefix | +| `campaignId` | string | Yes | The unique ID for the campaign | + +#### Output + +| Parameter | Type | Description | +| --------- | ---- | ----------- | +| `success` | boolean | Operation success status | +| `output` | object | Campaign data and metadata | + +### `mailchimp_create_campaign` + +Create a new campaign in Mailchimp + +#### Input + +| Parameter | Type | Required | Description | +| --------- | ---- | -------- | ----------- | +| `apiKey` | string | Yes | Mailchimp API key with server prefix | +| `campaignType` | string | Yes | Campaign type \(regular, plaintext, absplit, rss, variate\) | +| `campaignSettings` | string | Yes | Campaign settings as JSON \(e.g., \{"subject_line": "Test", "from_name": "John", "reply_to": "john@example.com"\}\) | +| `recipients` | string | No | Recipients as JSON \(e.g., \{"list_id": "abc123"\}\) | + +#### Output + +| Parameter | Type | Description | +| --------- | ---- | ----------- | +| `success` | boolean | Operation success status | +| `output` | object | Created campaign data | + +### `mailchimp_update_campaign` + +Update an existing campaign in Mailchimp + +#### Input + +| Parameter | Type | Required | Description | +| --------- | ---- | -------- | ----------- | +| `apiKey` | string | Yes | Mailchimp API key with server prefix | +| `campaignId` | string | Yes | The unique ID for the campaign | +| `campaignSettings` | string | No | Campaign settings as JSON | +| `recipients` | string | No | Recipients as JSON | + +#### Output + +| Parameter | Type | Description | +| --------- | ---- | ----------- | +| `success` | boolean | Operation success status | +| `output` | object | Updated campaign data | + +### `mailchimp_delete_campaign` + +Delete a campaign from Mailchimp + +#### Input + +| Parameter | Type | Required | Description | +| --------- | ---- | -------- | ----------- | +| `apiKey` | string | Yes | Mailchimp API key with server prefix | +| `campaignId` | string | Yes | The unique ID for the campaign to delete | + +#### Output + +| Parameter | Type | Description | +| --------- | ---- | ----------- | +| `success` | boolean | Operation success status | +| `output` | object | Deletion confirmation | + +### `mailchimp_send_campaign` + +Send a Mailchimp campaign + +#### Input + +| Parameter | Type | Required | Description | +| --------- | ---- | -------- | ----------- | +| `apiKey` | string | Yes | Mailchimp API key with server prefix | +| `campaignId` | string | Yes | The unique ID for the campaign to send | + +#### Output + +| Parameter | Type | Description | +| --------- | ---- | ----------- | +| `success` | boolean | Operation success status | +| `output` | object | Send confirmation | + +### `mailchimp_schedule_campaign` + +Schedule a Mailchimp campaign to be sent at a specific time + +#### Input + +| Parameter | Type | Required | Description | +| --------- | ---- | -------- | ----------- | +| `apiKey` | string | Yes | Mailchimp API key with server prefix | +| `campaignId` | string | Yes | The unique ID for the campaign to schedule | +| `scheduleTime` | string | Yes | The date and time in ISO 8601 format \(e.g., 2024-01-01T12:00:00+00:00\) | + +#### Output + +| Parameter | Type | Description | +| --------- | ---- | ----------- | +| `success` | boolean | Operation success status | +| `output` | object | Schedule confirmation | + +### `mailchimp_unschedule_campaign` + +Unschedule a previously scheduled Mailchimp campaign + +#### Input + +| Parameter | Type | Required | Description | +| --------- | ---- | -------- | ----------- | +| `apiKey` | string | Yes | Mailchimp API key with server prefix | +| `campaignId` | string | Yes | The unique ID for the campaign to unschedule | + +#### Output + +| Parameter | Type | Description | +| --------- | ---- | ----------- | +| `success` | boolean | Operation success status | +| `output` | object | Unschedule confirmation | + +### `mailchimp_replicate_campaign` + +Create a copy of an existing Mailchimp campaign + +#### Input + +| Parameter | Type | Required | Description | +| --------- | ---- | -------- | ----------- | +| `apiKey` | string | Yes | Mailchimp API key with server prefix | +| `campaignId` | string | Yes | The unique ID for the campaign to replicate | + +#### Output + +| Parameter | Type | Description | +| --------- | ---- | ----------- | +| `success` | boolean | Operation success status | +| `output` | object | Replicated campaign data | + +### `mailchimp_get_campaign_content` + +Retrieve the HTML and plain-text content for a Mailchimp campaign + +#### Input + +| Parameter | Type | Required | Description | +| --------- | ---- | -------- | ----------- | +| `apiKey` | string | Yes | Mailchimp API key with server prefix | +| `campaignId` | string | Yes | The unique ID for the campaign | + +#### Output + +| Parameter | Type | Description | +| --------- | ---- | ----------- | +| `success` | boolean | Operation success status | +| `output` | object | Campaign content data | + +### `mailchimp_set_campaign_content` + +Set the content for a Mailchimp campaign + +#### Input + +| Parameter | Type | Required | Description | +| --------- | ---- | -------- | ----------- | +| `apiKey` | string | Yes | Mailchimp API key with server prefix | +| `campaignId` | string | Yes | The unique ID for the campaign | +| `html` | string | No | The HTML content for the campaign | +| `plainText` | string | No | The plain-text content for the campaign | +| `templateId` | string | No | The ID of the template to use | + +#### Output + +| Parameter | Type | Description | +| --------- | ---- | ----------- | +| `success` | boolean | Operation success status | +| `output` | object | Campaign content data | + +### `mailchimp_get_automations` + +Retrieve a list of automations from Mailchimp + +#### Input + +| Parameter | Type | Required | Description | +| --------- | ---- | -------- | ----------- | +| `apiKey` | string | Yes | Mailchimp API key with server prefix | +| `count` | string | No | Number of results \(default: 10, max: 1000\) | +| `offset` | string | No | Number of results to skip | + +#### Output + +| Parameter | Type | Description | +| --------- | ---- | ----------- | +| `success` | boolean | Operation success status | +| `output` | object | Automations data and metadata | + +### `mailchimp_get_automation` + +Retrieve details of a specific automation from Mailchimp + +#### Input + +| Parameter | Type | Required | Description | +| --------- | ---- | -------- | ----------- | +| `apiKey` | string | Yes | Mailchimp API key with server prefix | +| `workflowId` | string | Yes | The unique ID for the automation workflow | + +#### Output + +| Parameter | Type | Description | +| --------- | ---- | ----------- | +| `success` | boolean | Operation success status | +| `output` | object | Automation data and metadata | + +### `mailchimp_start_automation` + +Start all emails in a Mailchimp automation workflow + +#### Input + +| Parameter | Type | Required | Description | +| --------- | ---- | -------- | ----------- | +| `apiKey` | string | Yes | Mailchimp API key with server prefix | +| `workflowId` | string | Yes | The unique ID for the automation workflow | + +#### Output + +| Parameter | Type | Description | +| --------- | ---- | ----------- | +| `success` | boolean | Operation success status | +| `output` | object | Start confirmation | + +### `mailchimp_pause_automation` + +Pause all emails in a Mailchimp automation workflow + +#### Input + +| Parameter | Type | Required | Description | +| --------- | ---- | -------- | ----------- | +| `apiKey` | string | Yes | Mailchimp API key with server prefix | +| `workflowId` | string | Yes | The unique ID for the automation workflow | + +#### Output + +| Parameter | Type | Description | +| --------- | ---- | ----------- | +| `success` | boolean | Operation success status | +| `output` | object | Pause confirmation | + +### `mailchimp_add_subscriber_to_automation` + +Manually add a subscriber to a workflow email queue + +#### Input + +| Parameter | Type | Required | Description | +| --------- | ---- | -------- | ----------- | +| `apiKey` | string | Yes | Mailchimp API key with server prefix | +| `workflowId` | string | Yes | The unique ID for the automation workflow | +| `workflowEmailId` | string | Yes | The unique ID for the workflow email | +| `emailAddress` | string | Yes | Email address of the subscriber | + +#### Output + +| Parameter | Type | Description | +| --------- | ---- | ----------- | +| `success` | boolean | Operation success status | +| `output` | object | Subscriber queue data | + +### `mailchimp_get_templates` + +Retrieve a list of templates from Mailchimp + +#### Input + +| Parameter | Type | Required | Description | +| --------- | ---- | -------- | ----------- | +| `apiKey` | string | Yes | Mailchimp API key with server prefix | +| `count` | string | No | Number of results \(default: 10, max: 1000\) | +| `offset` | string | No | Number of results to skip | + +#### Output + +| Parameter | Type | Description | +| --------- | ---- | ----------- | +| `success` | boolean | Operation success status | +| `output` | object | Templates data and metadata | + +### `mailchimp_get_template` + +Retrieve details of a specific template from Mailchimp + +#### Input + +| Parameter | Type | Required | Description | +| --------- | ---- | -------- | ----------- | +| `apiKey` | string | Yes | Mailchimp API key with server prefix | +| `templateId` | string | Yes | The unique ID for the template | + +#### Output + +| Parameter | Type | Description | +| --------- | ---- | ----------- | +| `success` | boolean | Operation success status | +| `output` | object | Template data and metadata | + +### `mailchimp_create_template` + +Create a new template in Mailchimp + +#### Input + +| Parameter | Type | Required | Description | +| --------- | ---- | -------- | ----------- | +| `apiKey` | string | Yes | Mailchimp API key with server prefix | +| `templateName` | string | Yes | The name of the template | +| `templateHtml` | string | Yes | The HTML content for the template | + +#### Output + +| Parameter | Type | Description | +| --------- | ---- | ----------- | +| `success` | boolean | Operation success status | +| `output` | object | Created template data | + +### `mailchimp_update_template` + +Update an existing template in Mailchimp + +#### Input + +| Parameter | Type | Required | Description | +| --------- | ---- | -------- | ----------- | +| `apiKey` | string | Yes | Mailchimp API key with server prefix | +| `templateId` | string | Yes | The unique ID for the template | +| `templateName` | string | No | The name of the template | +| `templateHtml` | string | No | The HTML content for the template | + +#### Output + +| Parameter | Type | Description | +| --------- | ---- | ----------- | +| `success` | boolean | Operation success status | +| `output` | object | Updated template data | + +### `mailchimp_delete_template` + +Delete a template from Mailchimp + +#### Input + +| Parameter | Type | Required | Description | +| --------- | ---- | -------- | ----------- | +| `apiKey` | string | Yes | Mailchimp API key with server prefix | +| `templateId` | string | Yes | The unique ID for the template to delete | + +#### Output + +| Parameter | Type | Description | +| --------- | ---- | ----------- | +| `success` | boolean | Operation success status | +| `output` | object | Deletion confirmation | + +### `mailchimp_get_campaign_reports` + +Retrieve a list of campaign reports from Mailchimp + +#### Input + +| Parameter | Type | Required | Description | +| --------- | ---- | -------- | ----------- | +| `apiKey` | string | Yes | Mailchimp API key with server prefix | +| `count` | string | No | Number of results \(default: 10, max: 1000\) | +| `offset` | string | No | Number of results to skip | + +#### Output + +| Parameter | Type | Description | +| --------- | ---- | ----------- | +| `success` | boolean | Operation success status | +| `output` | object | Campaign reports data and metadata | + +### `mailchimp_get_campaign_report` + +Retrieve the report for a specific campaign from Mailchimp + +#### Input + +| Parameter | Type | Required | Description | +| --------- | ---- | -------- | ----------- | +| `apiKey` | string | Yes | Mailchimp API key with server prefix | +| `campaignId` | string | Yes | The unique ID for the campaign | + +#### Output + +| Parameter | Type | Description | +| --------- | ---- | ----------- | +| `success` | boolean | Operation success status | +| `output` | object | Campaign report data and metadata | + +### `mailchimp_get_segments` + +Retrieve a list of segments from a Mailchimp audience + +#### Input + +| Parameter | Type | Required | Description | +| --------- | ---- | -------- | ----------- | +| `apiKey` | string | Yes | Mailchimp API key with server prefix | +| `listId` | string | Yes | The unique ID for the list | +| `count` | string | No | Number of results \(default: 10, max: 1000\) | +| `offset` | string | No | Number of results to skip | + +#### Output + +| Parameter | Type | Description | +| --------- | ---- | ----------- | +| `success` | boolean | Operation success status | +| `output` | object | Segments data and metadata | + +### `mailchimp_get_segment` + +Retrieve details of a specific segment from a Mailchimp audience + +#### Input + +| Parameter | Type | Required | Description | +| --------- | ---- | -------- | ----------- | +| `apiKey` | string | Yes | Mailchimp API key with server prefix | +| `listId` | string | Yes | The unique ID for the list | +| `segmentId` | string | Yes | The unique ID for the segment | + +#### Output + +| Parameter | Type | Description | +| --------- | ---- | ----------- | +| `success` | boolean | Operation success status | +| `output` | object | Segment data and metadata | + +### `mailchimp_create_segment` + +Create a new segment in a Mailchimp audience + +#### Input + +| Parameter | Type | Required | Description | +| --------- | ---- | -------- | ----------- | +| `apiKey` | string | Yes | Mailchimp API key with server prefix | +| `listId` | string | Yes | The unique ID for the list | +| `segmentName` | string | Yes | The name of the segment | +| `segmentOptions` | string | No | Segment options as JSON \(e.g., \{"match": "any", "conditions": \[\]\}\) | + +#### Output + +| Parameter | Type | Description | +| --------- | ---- | ----------- | +| `success` | boolean | Operation success status | +| `output` | object | Created segment data | + +### `mailchimp_update_segment` + +Update an existing segment in a Mailchimp audience + +#### Input + +| Parameter | Type | Required | Description | +| --------- | ---- | -------- | ----------- | +| `apiKey` | string | Yes | Mailchimp API key with server prefix | +| `listId` | string | Yes | The unique ID for the list | +| `segmentId` | string | Yes | The unique ID for the segment | +| `segmentName` | string | No | The name of the segment | +| `segmentOptions` | string | No | Segment options as JSON | + +#### Output + +| Parameter | Type | Description | +| --------- | ---- | ----------- | +| `success` | boolean | Operation success status | +| `output` | object | Updated segment data | + +### `mailchimp_delete_segment` + +Delete a segment from a Mailchimp audience + +#### Input + +| Parameter | Type | Required | Description | +| --------- | ---- | -------- | ----------- | +| `apiKey` | string | Yes | Mailchimp API key with server prefix | +| `listId` | string | Yes | The unique ID for the list | +| `segmentId` | string | Yes | The unique ID for the segment to delete | + +#### Output + +| Parameter | Type | Description | +| --------- | ---- | ----------- | +| `success` | boolean | Operation success status | +| `output` | object | Deletion confirmation | + +### `mailchimp_get_segment_members` + +Retrieve members of a specific segment from a Mailchimp audience + +#### Input + +| Parameter | Type | Required | Description | +| --------- | ---- | -------- | ----------- | +| `apiKey` | string | Yes | Mailchimp API key with server prefix | +| `listId` | string | Yes | The unique ID for the list | +| `segmentId` | string | Yes | The unique ID for the segment | +| `count` | string | No | Number of results \(default: 10, max: 1000\) | +| `offset` | string | No | Number of results to skip | + +#### Output + +| Parameter | Type | Description | +| --------- | ---- | ----------- | +| `success` | boolean | Operation success status | +| `output` | object | Segment members data and metadata | + +### `mailchimp_add_segment_member` + +Add a member to a specific segment in a Mailchimp audience + +#### Input + +| Parameter | Type | Required | Description | +| --------- | ---- | -------- | ----------- | +| `apiKey` | string | Yes | Mailchimp API key with server prefix | +| `listId` | string | Yes | The unique ID for the list | +| `segmentId` | string | Yes | The unique ID for the segment | +| `emailAddress` | string | Yes | Email address of the member | + +#### Output + +| Parameter | Type | Description | +| --------- | ---- | ----------- | +| `success` | boolean | Operation success status | +| `output` | object | Added member data | + +### `mailchimp_remove_segment_member` + +Remove a member from a specific segment in a Mailchimp audience + +#### Input + +| Parameter | Type | Required | Description | +| --------- | ---- | -------- | ----------- | +| `apiKey` | string | Yes | Mailchimp API key with server prefix | +| `listId` | string | Yes | The unique ID for the list | +| `segmentId` | string | Yes | The unique ID for the segment | +| `subscriberHash` | string | Yes | The MD5 hash of the lowercase version of the list member's email address | + +#### Output + +| Parameter | Type | Description | +| --------- | ---- | ----------- | +| `success` | boolean | Operation success status | +| `output` | object | Removal confirmation | + +### `mailchimp_get_member_tags` + +Retrieve tags associated with a member in a Mailchimp audience + +#### Input + +| Parameter | Type | Required | Description | +| --------- | ---- | -------- | ----------- | +| `apiKey` | string | Yes | Mailchimp API key with server prefix | +| `listId` | string | Yes | The unique ID for the list | +| `subscriberHash` | string | Yes | The MD5 hash of the lowercase version of the list member's email address | + +#### Output + +| Parameter | Type | Description | +| --------- | ---- | ----------- | +| `success` | boolean | Operation success status | +| `output` | object | Member tags data and metadata | + +### `mailchimp_add_member_tags` + +Add tags to a member in a Mailchimp audience + +#### Input + +| Parameter | Type | Required | Description | +| --------- | ---- | -------- | ----------- | +| `apiKey` | string | Yes | Mailchimp API key with server prefix | +| `listId` | string | Yes | The unique ID for the list | +| `subscriberHash` | string | Yes | The MD5 hash of the lowercase version of the list member's email address | +| `tags` | string | Yes | Tags as JSON array \(e.g., \[\{"name": "tag1", "status": "active"\}, \{"name": "tag2", "status": "active"\}\]\) | + +#### Output + +| Parameter | Type | Description | +| --------- | ---- | ----------- | +| `success` | boolean | Operation success status | +| `output` | object | Tag addition confirmation | + +### `mailchimp_remove_member_tags` + +Remove tags from a member in a Mailchimp audience + +#### Input + +| Parameter | Type | Required | Description | +| --------- | ---- | -------- | ----------- | +| `apiKey` | string | Yes | Mailchimp API key with server prefix | +| `listId` | string | Yes | The unique ID for the list | +| `subscriberHash` | string | Yes | The MD5 hash of the lowercase version of the list member's email address | +| `tags` | string | Yes | Tags as JSON array with inactive status \(e.g., \[\{"name": "tag1", "status": "inactive"\}, \{"name": "tag2", "status": "inactive"\}\]\) | + +#### Output + +| Parameter | Type | Description | +| --------- | ---- | ----------- | +| `success` | boolean | Operation success status | +| `output` | object | Tag removal confirmation | + +### `mailchimp_get_merge_fields` + +Retrieve a list of merge fields from a Mailchimp audience + +#### Input + +| Parameter | Type | Required | Description | +| --------- | ---- | -------- | ----------- | +| `apiKey` | string | Yes | Mailchimp API key with server prefix | +| `listId` | string | Yes | The unique ID for the list | +| `count` | string | No | Number of results \(default: 10, max: 1000\) | +| `offset` | string | No | Number of results to skip | + +#### Output + +| Parameter | Type | Description | +| --------- | ---- | ----------- | +| `success` | boolean | Operation success status | +| `output` | object | Merge fields data and metadata | + +### `mailchimp_get_merge_field` + +Retrieve details of a specific merge field from a Mailchimp audience + +#### Input + +| Parameter | Type | Required | Description | +| --------- | ---- | -------- | ----------- | +| `apiKey` | string | Yes | Mailchimp API key with server prefix | +| `listId` | string | Yes | The unique ID for the list | +| `mergeId` | string | Yes | The unique ID for the merge field | + +#### Output + +| Parameter | Type | Description | +| --------- | ---- | ----------- | +| `success` | boolean | Operation success status | +| `output` | object | Merge field data and metadata | + +### `mailchimp_create_merge_field` + +Create a new merge field in a Mailchimp audience + +#### Input + +| Parameter | Type | Required | Description | +| --------- | ---- | -------- | ----------- | +| `apiKey` | string | Yes | Mailchimp API key with server prefix | +| `listId` | string | Yes | The unique ID for the list | +| `mergeName` | string | Yes | The name of the merge field | +| `mergeType` | string | Yes | The type of the merge field \(text, number, address, phone, date, url, imageurl, radio, dropdown, birthday, zip\) | + +#### Output + +| Parameter | Type | Description | +| --------- | ---- | ----------- | +| `success` | boolean | Operation success status | +| `output` | object | Created merge field data | + +### `mailchimp_update_merge_field` + +Update an existing merge field in a Mailchimp audience + +#### Input + +| Parameter | Type | Required | Description | +| --------- | ---- | -------- | ----------- | +| `apiKey` | string | Yes | Mailchimp API key with server prefix | +| `listId` | string | Yes | The unique ID for the list | +| `mergeId` | string | Yes | The unique ID for the merge field | +| `mergeName` | string | No | The name of the merge field | + +#### Output + +| Parameter | Type | Description | +| --------- | ---- | ----------- | +| `success` | boolean | Operation success status | +| `output` | object | Updated merge field data | + +### `mailchimp_delete_merge_field` + +Delete a merge field from a Mailchimp audience + +#### Input + +| Parameter | Type | Required | Description | +| --------- | ---- | -------- | ----------- | +| `apiKey` | string | Yes | Mailchimp API key with server prefix | +| `listId` | string | Yes | The unique ID for the list | +| `mergeId` | string | Yes | The unique ID for the merge field to delete | + +#### Output + +| Parameter | Type | Description | +| --------- | ---- | ----------- | +| `success` | boolean | Operation success status | +| `output` | object | Deletion confirmation | + +### `mailchimp_get_interest_categories` + +Retrieve a list of interest categories from a Mailchimp audience + +#### Input + +| Parameter | Type | Required | Description | +| --------- | ---- | -------- | ----------- | +| `apiKey` | string | Yes | Mailchimp API key with server prefix | +| `listId` | string | Yes | The unique ID for the list | +| `count` | string | No | Number of results \(default: 10, max: 1000\) | +| `offset` | string | No | Number of results to skip | + +#### Output + +| Parameter | Type | Description | +| --------- | ---- | ----------- | +| `success` | boolean | Operation success status | +| `output` | object | Interest categories data and metadata | + +### `mailchimp_get_interest_category` + +Retrieve details of a specific interest category from a Mailchimp audience + +#### Input + +| Parameter | Type | Required | Description | +| --------- | ---- | -------- | ----------- | +| `apiKey` | string | Yes | Mailchimp API key with server prefix | +| `listId` | string | Yes | The unique ID for the list | +| `interestCategoryId` | string | Yes | The unique ID for the interest category | + +#### Output + +| Parameter | Type | Description | +| --------- | ---- | ----------- | +| `success` | boolean | Operation success status | +| `output` | object | Interest category data and metadata | + +### `mailchimp_create_interest_category` + +Create a new interest category in a Mailchimp audience + +#### Input + +| Parameter | Type | Required | Description | +| --------- | ---- | -------- | ----------- | +| `apiKey` | string | Yes | Mailchimp API key with server prefix | +| `listId` | string | Yes | The unique ID for the list | +| `interestCategoryTitle` | string | Yes | The title of the interest category | +| `interestCategoryType` | string | Yes | The type of interest category \(checkboxes, dropdown, radio, hidden\) | + +#### Output + +| Parameter | Type | Description | +| --------- | ---- | ----------- | +| `success` | boolean | Operation success status | +| `output` | object | Created interest category data | + +### `mailchimp_update_interest_category` + +Update an existing interest category in a Mailchimp audience + +#### Input + +| Parameter | Type | Required | Description | +| --------- | ---- | -------- | ----------- | +| `apiKey` | string | Yes | Mailchimp API key with server prefix | +| `listId` | string | Yes | The unique ID for the list | +| `interestCategoryId` | string | Yes | The unique ID for the interest category | +| `interestCategoryTitle` | string | No | The title of the interest category | + +#### Output + +| Parameter | Type | Description | +| --------- | ---- | ----------- | +| `success` | boolean | Operation success status | +| `output` | object | Updated interest category data | + +### `mailchimp_delete_interest_category` + +Delete an interest category from a Mailchimp audience + +#### Input + +| Parameter | Type | Required | Description | +| --------- | ---- | -------- | ----------- | +| `apiKey` | string | Yes | Mailchimp API key with server prefix | +| `listId` | string | Yes | The unique ID for the list | +| `interestCategoryId` | string | Yes | The unique ID for the interest category to delete | + +#### Output + +| Parameter | Type | Description | +| --------- | ---- | ----------- | +| `success` | boolean | Operation success status | +| `output` | object | Deletion confirmation | + +### `mailchimp_get_interests` + +Retrieve a list of interests from an interest category in a Mailchimp audience + +#### Input + +| Parameter | Type | Required | Description | +| --------- | ---- | -------- | ----------- | +| `apiKey` | string | Yes | Mailchimp API key with server prefix | +| `listId` | string | Yes | The unique ID for the list | +| `interestCategoryId` | string | Yes | The unique ID for the interest category | +| `count` | string | No | Number of results \(default: 10, max: 1000\) | +| `offset` | string | No | Number of results to skip | + +#### Output + +| Parameter | Type | Description | +| --------- | ---- | ----------- | +| `success` | boolean | Operation success status | +| `output` | object | Interests data and metadata | + +### `mailchimp_get_interest` + +Retrieve details of a specific interest from an interest category in a Mailchimp audience + +#### Input + +| Parameter | Type | Required | Description | +| --------- | ---- | -------- | ----------- | +| `apiKey` | string | Yes | Mailchimp API key with server prefix | +| `listId` | string | Yes | The unique ID for the list | +| `interestCategoryId` | string | Yes | The unique ID for the interest category | +| `interestId` | string | Yes | The unique ID for the interest | + +#### Output + +| Parameter | Type | Description | +| --------- | ---- | ----------- | +| `success` | boolean | Operation success status | +| `output` | object | Interest data and metadata | + +### `mailchimp_create_interest` + +Create a new interest in an interest category in a Mailchimp audience + +#### Input + +| Parameter | Type | Required | Description | +| --------- | ---- | -------- | ----------- | +| `apiKey` | string | Yes | Mailchimp API key with server prefix | +| `listId` | string | Yes | The unique ID for the list | +| `interestCategoryId` | string | Yes | The unique ID for the interest category | +| `interestName` | string | Yes | The name of the interest | + +#### Output + +| Parameter | Type | Description | +| --------- | ---- | ----------- | +| `success` | boolean | Operation success status | +| `output` | object | Created interest data | + +### `mailchimp_update_interest` + +Update an existing interest in an interest category in a Mailchimp audience + +#### Input + +| Parameter | Type | Required | Description | +| --------- | ---- | -------- | ----------- | +| `apiKey` | string | Yes | Mailchimp API key with server prefix | +| `listId` | string | Yes | The unique ID for the list | +| `interestCategoryId` | string | Yes | The unique ID for the interest category | +| `interestId` | string | Yes | The unique ID for the interest | +| `interestName` | string | No | The name of the interest | + +#### Output + +| Parameter | Type | Description | +| --------- | ---- | ----------- | +| `success` | boolean | Operation success status | +| `output` | object | Updated interest data | + +### `mailchimp_delete_interest` + +Delete an interest from an interest category in a Mailchimp audience + +#### Input + +| Parameter | Type | Required | Description | +| --------- | ---- | -------- | ----------- | +| `apiKey` | string | Yes | Mailchimp API key with server prefix | +| `listId` | string | Yes | The unique ID for the list | +| `interestCategoryId` | string | Yes | The unique ID for the interest category | +| `interestId` | string | Yes | The unique ID for the interest to delete | + +#### Output + +| Parameter | Type | Description | +| --------- | ---- | ----------- | +| `success` | boolean | Operation success status | +| `output` | object | Deletion confirmation | + +### `mailchimp_get_landing_pages` + +Retrieve a list of landing pages from Mailchimp + +#### Input + +| Parameter | Type | Required | Description | +| --------- | ---- | -------- | ----------- | +| `apiKey` | string | Yes | Mailchimp API key with server prefix | +| `count` | string | No | Number of results \(default: 10, max: 1000\) | +| `offset` | string | No | Number of results to skip | + +#### Output + +| Parameter | Type | Description | +| --------- | ---- | ----------- | +| `success` | boolean | Operation success status | +| `output` | object | Landing pages data and metadata | + +### `mailchimp_get_landing_page` + +Retrieve details of a specific landing page from Mailchimp + +#### Input + +| Parameter | Type | Required | Description | +| --------- | ---- | -------- | ----------- | +| `apiKey` | string | Yes | Mailchimp API key with server prefix | +| `pageId` | string | Yes | The unique ID for the landing page | + +#### Output + +| Parameter | Type | Description | +| --------- | ---- | ----------- | +| `success` | boolean | Operation success status | +| `output` | object | Landing page data and metadata | + +### `mailchimp_create_landing_page` + +Create a new landing page in Mailchimp + +#### Input + +| Parameter | Type | Required | Description | +| --------- | ---- | -------- | ----------- | +| `apiKey` | string | Yes | Mailchimp API key with server prefix | +| `landingPageType` | string | Yes | The type of landing page \(signup\) | +| `landingPageTitle` | string | No | The title of the landing page | + +#### Output + +| Parameter | Type | Description | +| --------- | ---- | ----------- | +| `success` | boolean | Operation success status | +| `output` | object | Created landing page data | + +### `mailchimp_update_landing_page` + +Update an existing landing page in Mailchimp + +#### Input + +| Parameter | Type | Required | Description | +| --------- | ---- | -------- | ----------- | +| `apiKey` | string | Yes | Mailchimp API key with server prefix | +| `pageId` | string | Yes | The unique ID for the landing page | +| `landingPageTitle` | string | No | The title of the landing page | + +#### Output + +| Parameter | Type | Description | +| --------- | ---- | ----------- | +| `success` | boolean | Operation success status | +| `output` | object | Updated landing page data | + +### `mailchimp_delete_landing_page` + +Delete a landing page from Mailchimp + +#### Input + +| Parameter | Type | Required | Description | +| --------- | ---- | -------- | ----------- | +| `apiKey` | string | Yes | Mailchimp API key with server prefix | +| `pageId` | string | Yes | The unique ID for the landing page to delete | + +#### Output + +| Parameter | Type | Description | +| --------- | ---- | ----------- | +| `success` | boolean | Operation success status | +| `output` | object | Deletion confirmation | + +### `mailchimp_publish_landing_page` + +Publish a landing page in Mailchimp + +#### Input + +| Parameter | Type | Required | Description | +| --------- | ---- | -------- | ----------- | +| `apiKey` | string | Yes | Mailchimp API key with server prefix | +| `pageId` | string | Yes | The unique ID for the landing page | + +#### Output + +| Parameter | Type | Description | +| --------- | ---- | ----------- | +| `success` | boolean | Operation success status | +| `output` | object | Publish confirmation | + +### `mailchimp_unpublish_landing_page` + +Unpublish a landing page in Mailchimp + +#### Input + +| Parameter | Type | Required | Description | +| --------- | ---- | -------- | ----------- | +| `apiKey` | string | Yes | Mailchimp API key with server prefix | +| `pageId` | string | Yes | The unique ID for the landing page | + +#### Output + +| Parameter | Type | Description | +| --------- | ---- | ----------- | +| `success` | boolean | Operation success status | +| `output` | object | Unpublish confirmation | + +### `mailchimp_get_batch_operations` + +Retrieve a list of batch operations from Mailchimp + +#### Input + +| Parameter | Type | Required | Description | +| --------- | ---- | -------- | ----------- | +| `apiKey` | string | Yes | Mailchimp API key with server prefix | +| `count` | string | No | Number of results \(default: 10, max: 1000\) | +| `offset` | string | No | Number of results to skip | + +#### Output + +| Parameter | Type | Description | +| --------- | ---- | ----------- | +| `success` | boolean | Operation success status | +| `output` | object | Batch operations data and metadata | + +### `mailchimp_get_batch_operation` + +Retrieve details of a specific batch operation from Mailchimp + +#### Input + +| Parameter | Type | Required | Description | +| --------- | ---- | -------- | ----------- | +| `apiKey` | string | Yes | Mailchimp API key with server prefix | +| `batchId` | string | Yes | The unique ID for the batch operation | + +#### Output + +| Parameter | Type | Description | +| --------- | ---- | ----------- | +| `success` | boolean | Operation success status | +| `output` | object | Batch operation data and metadata | + +### `mailchimp_create_batch_operation` + +Create a new batch operation in Mailchimp + +#### Input + +| Parameter | Type | Required | Description | +| --------- | ---- | -------- | ----------- | +| `apiKey` | string | Yes | Mailchimp API key with server prefix | +| `operations` | string | Yes | Operations as JSON array \(e.g., \[\{"method": "POST", "path": "/lists", "body": "\{\\"name\\": \\"Test\\"\}"\}\]\) | + +#### Output + +| Parameter | Type | Description | +| --------- | ---- | ----------- | +| `success` | boolean | Operation success status | +| `output` | object | Created batch operation data | + +### `mailchimp_delete_batch_operation` + +Delete a batch operation from Mailchimp + +#### Input + +| Parameter | Type | Required | Description | +| --------- | ---- | -------- | ----------- | +| `apiKey` | string | Yes | Mailchimp API key with server prefix | +| `batchId` | string | Yes | The unique ID for the batch operation to delete | + +#### Output + +| Parameter | Type | Description | +| --------- | ---- | ----------- | +| `success` | boolean | Operation success status | +| `output` | object | Deletion confirmation | + + + +## Notes + +- Category: `tools` +- Type: `mailchimp` diff --git a/apps/docs/content/docs/en/tools/meta.json b/apps/docs/content/docs/en/tools/meta.json index 49259abe7c..6f83cb4500 100644 --- a/apps/docs/content/docs/en/tools/meta.json +++ b/apps/docs/content/docs/en/tools/meta.json @@ -28,11 +28,13 @@ "hunter", "image_generator", "incidentio", + "intercom", "jina", "jira", "knowledge", "linear", "linkup", + "mailchimp", "mem0", "memory", "microsoft_excel", @@ -52,6 +54,7 @@ "pipedrive", "postgresql", "posthog", + "pylon", "qdrant", "reddit", "resend", @@ -83,6 +86,7 @@ "wikipedia", "x", "youtube", + "zendesk", "zep" ] } diff --git a/apps/docs/content/docs/en/tools/pylon.mdx b/apps/docs/content/docs/en/tools/pylon.mdx new file mode 100644 index 0000000000..b513e9d02e --- /dev/null +++ b/apps/docs/content/docs/en/tools/pylon.mdx @@ -0,0 +1,763 @@ +--- +title: Pylon +description: Manage customer support issues, accounts, contacts, users, teams, and tags in Pylon +--- + +import { BlockInfoCard } from "@/components/ui/block-info-card" + + + +## Usage Instructions + +Integrate Pylon into the workflow. Manage issues (list, create, get, update, delete, search, snooze, followers, external issues), accounts (list, create, get, update, delete, bulk update, search), contacts (list, create, get, update, delete, search), users (list, get, update, search), teams (list, get, create, update), tags (list, get, create, update, delete), and messages (redact). + + + +## Tools + +### `pylon_list_issues` + +Retrieve a list of issues within a specified time range + +#### Input + +| Parameter | Type | Required | Description | +| --------- | ---- | -------- | ----------- | +| `apiToken` | string | Yes | Pylon API token | +| `startTime` | string | Yes | Start time in RFC3339 format \(e.g., 2024-01-01T00:00:00Z\) | +| `endTime` | string | Yes | End time in RFC3339 format \(e.g., 2024-01-31T23:59:59Z\) | +| `cursor` | string | No | Pagination cursor for next page of results | + +#### Output + +| Parameter | Type | Description | +| --------- | ---- | ----------- | +| `success` | boolean | Operation success status | +| `output` | object | List of issues | + +### `pylon_create_issue` + +Create a new issue with specified properties + +#### Input + +| Parameter | Type | Required | Description | +| --------- | ---- | -------- | ----------- | +| `apiToken` | string | Yes | Pylon API token | +| `title` | string | Yes | Issue title | +| `bodyHtml` | string | Yes | Issue body in HTML format | +| `accountId` | string | No | Account ID to associate with issue | +| `assigneeId` | string | No | User ID to assign issue to | + +#### Output + +| Parameter | Type | Description | +| --------- | ---- | ----------- | +| `success` | boolean | Operation success status | +| `output` | object | Created issue data | + +### `pylon_get_issue` + +Fetch a specific issue by ID + +#### Input + +| Parameter | Type | Required | Description | +| --------- | ---- | -------- | ----------- | +| `apiToken` | string | Yes | Pylon API token | +| `issueId` | string | Yes | The ID of the issue to retrieve | + +#### Output + +| Parameter | Type | Description | +| --------- | ---- | ----------- | +| `success` | boolean | Operation success status | +| `output` | object | Issue data | + +### `pylon_update_issue` + +Update an existing issue + +#### Input + +| Parameter | Type | Required | Description | +| --------- | ---- | -------- | ----------- | +| `apiToken` | string | Yes | Pylon API token | +| `issueId` | string | Yes | The ID of the issue to update | +| `state` | string | No | Issue state | +| `assigneeId` | string | No | User ID to assign issue to | +| `teamId` | string | No | Team ID to assign issue to | +| `tags` | string | No | Comma-separated tag IDs | +| `customFields` | string | No | Custom fields as JSON object | + +#### Output + +| Parameter | Type | Description | +| --------- | ---- | ----------- | +| `success` | boolean | Operation success status | +| `output` | object | Updated issue data | + +### `pylon_delete_issue` + +Remove an issue by ID + +#### Input + +| Parameter | Type | Required | Description | +| --------- | ---- | -------- | ----------- | +| `apiToken` | string | Yes | Pylon API token | +| `issueId` | string | Yes | The ID of the issue to delete | + +#### Output + +| Parameter | Type | Description | +| --------- | ---- | ----------- | +| `success` | boolean | Operation success status | +| `output` | object | Deletion result | + +### `pylon_search_issues` + +Query issues using filters + +#### Input + +| Parameter | Type | Required | Description | +| --------- | ---- | -------- | ----------- | +| `apiToken` | string | Yes | Pylon API token | +| `filter` | string | Yes | Filter criteria as JSON string | +| `cursor` | string | No | Pagination cursor for next page of results | +| `limit` | number | No | Maximum number of results to return | + +#### Output + +| Parameter | Type | Description | +| --------- | ---- | ----------- | +| `success` | boolean | Operation success status | +| `output` | object | Search results | + +### `pylon_snooze_issue` + +Postpone issue visibility until specified time + +#### Input + +| Parameter | Type | Required | Description | +| --------- | ---- | -------- | ----------- | +| `apiToken` | string | Yes | Pylon API token | +| `issueId` | string | Yes | The ID of the issue to snooze | +| `snoozeUntil` | string | Yes | RFC3339 timestamp when issue should reappear \(e.g., 2024-01-01T00:00:00Z\) | + +#### Output + +| Parameter | Type | Description | +| --------- | ---- | ----------- | +| `success` | boolean | Operation success status | +| `output` | object | Snoozed issue data | + +### `pylon_list_issue_followers` + +Get list of followers for a specific issue + +#### Input + +| Parameter | Type | Required | Description | +| --------- | ---- | -------- | ----------- | +| `apiToken` | string | Yes | Pylon API token | +| `issueId` | string | Yes | The ID of the issue | + +#### Output + +| Parameter | Type | Description | +| --------- | ---- | ----------- | +| `success` | boolean | Operation success status | +| `output` | object | Followers list | + +### `pylon_manage_issue_followers` + +Add or remove followers from an issue + +#### Input + +| Parameter | Type | Required | Description | +| --------- | ---- | -------- | ----------- | +| `apiToken` | string | Yes | Pylon API token | +| `issueId` | string | Yes | The ID of the issue | +| `userIds` | string | No | Comma-separated user IDs to add/remove | +| `contactIds` | string | No | Comma-separated contact IDs to add/remove | +| `operation` | string | No | Operation to perform: "add" or "remove" \(default: "add"\) | + +#### Output + +| Parameter | Type | Description | +| --------- | ---- | ----------- | +| `success` | boolean | Operation success status | +| `output` | object | Updated followers list | + +### `pylon_link_external_issue` + +Link an issue to an external system issue + +#### Input + +| Parameter | Type | Required | Description | +| --------- | ---- | -------- | ----------- | +| `apiToken` | string | Yes | Pylon API token | +| `issueId` | string | Yes | The ID of the Pylon issue | +| `externalIssueId` | string | Yes | The ID of the external issue | +| `source` | string | Yes | The source system \(e.g., "jira", "linear", "github"\) | + +#### Output + +| Parameter | Type | Description | +| --------- | ---- | ----------- | +| `success` | boolean | Operation success status | +| `output` | object | Linked external issue data | + +### `pylon_list_accounts` + +Retrieve a paginated list of accounts + +#### Input + +| Parameter | Type | Required | Description | +| --------- | ---- | -------- | ----------- | +| `apiToken` | string | Yes | Pylon API token | +| `limit` | string | No | Number of accounts to return \(1-1000, default 100\) | +| `cursor` | string | No | Pagination cursor for next page of results | + +#### Output + +| Parameter | Type | Description | +| --------- | ---- | ----------- | +| `success` | boolean | Operation success status | +| `output` | object | List of accounts | + +### `pylon_create_account` + +Create a new account with specified properties + +#### Input + +| Parameter | Type | Required | Description | +| --------- | ---- | -------- | ----------- | +| `apiToken` | string | Yes | Pylon API token | +| `name` | string | Yes | Account name | +| `domains` | string | No | Comma-separated list of domains | +| `primaryDomain` | string | No | Primary domain for the account | +| `customFields` | string | No | Custom fields as JSON object | +| `tags` | string | No | Comma-separated tag IDs | +| `channels` | string | No | Comma-separated channel IDs | +| `externalIds` | string | No | Comma-separated external IDs | +| `ownerId` | string | No | Owner user ID | +| `logoUrl` | string | No | URL to account logo | +| `subaccountIds` | string | No | Comma-separated subaccount IDs | + +#### Output + +| Parameter | Type | Description | +| --------- | ---- | ----------- | +| `success` | boolean | Operation success status | +| `output` | object | Created account data | + +### `pylon_get_account` + +Retrieve a single account by ID + +#### Input + +| Parameter | Type | Required | Description | +| --------- | ---- | -------- | ----------- | +| `apiToken` | string | Yes | Pylon API token | +| `accountId` | string | Yes | Account ID to retrieve | + +#### Output + +| Parameter | Type | Description | +| --------- | ---- | ----------- | +| `success` | boolean | Operation success status | +| `output` | object | Account data | + +### `pylon_update_account` + +Update an existing account with new properties + +#### Input + +| Parameter | Type | Required | Description | +| --------- | ---- | -------- | ----------- | +| `apiToken` | string | Yes | Pylon API token | +| `accountId` | string | Yes | Account ID to update | +| `name` | string | No | Account name | +| `domains` | string | No | Comma-separated list of domains | +| `primaryDomain` | string | No | Primary domain for the account | +| `customFields` | string | No | Custom fields as JSON object | +| `tags` | string | No | Comma-separated tag IDs | +| `channels` | string | No | Comma-separated channel IDs | +| `externalIds` | string | No | Comma-separated external IDs | +| `ownerId` | string | No | Owner user ID | +| `logoUrl` | string | No | URL to account logo | +| `subaccountIds` | string | No | Comma-separated subaccount IDs | + +#### Output + +| Parameter | Type | Description | +| --------- | ---- | ----------- | +| `success` | boolean | Operation success status | +| `output` | object | Updated account data | + +### `pylon_delete_account` + +Remove an account by ID + +#### Input + +| Parameter | Type | Required | Description | +| --------- | ---- | -------- | ----------- | +| `apiToken` | string | Yes | Pylon API token | +| `accountId` | string | Yes | Account ID to delete | + +#### Output + +| Parameter | Type | Description | +| --------- | ---- | ----------- | +| `success` | boolean | Operation success status | +| `output` | object | Deletion confirmation | + +### `pylon_bulk_update_accounts` + +Update multiple accounts at once + +#### Input + +| Parameter | Type | Required | Description | +| --------- | ---- | -------- | ----------- | +| `apiToken` | string | Yes | Pylon API token | +| `accountIds` | string | Yes | Comma-separated account IDs to update | +| `customFields` | string | No | Custom fields as JSON object | +| `tags` | string | No | Comma-separated tag IDs | +| `ownerId` | string | No | Owner user ID | +| `tagsApplyMode` | string | No | Tag application mode: append_only, remove_only, or replace | + +#### Output + +| Parameter | Type | Description | +| --------- | ---- | ----------- | +| `success` | boolean | Operation success status | +| `output` | object | Bulk updated accounts data | + +### `pylon_search_accounts` + +Search accounts with custom filters + +#### Input + +| Parameter | Type | Required | Description | +| --------- | ---- | -------- | ----------- | +| `apiToken` | string | Yes | Pylon API token | +| `filter` | string | Yes | Filter as JSON string with field/operator/value structure | +| `limit` | string | No | Number of accounts to return \(1-1000, default 100\) | +| `cursor` | string | No | Pagination cursor for next page of results | + +#### Output + +| Parameter | Type | Description | +| --------- | ---- | ----------- | +| `success` | boolean | Operation success status | +| `output` | object | Search results | + +### `pylon_list_contacts` + +Retrieve a list of contacts + +#### Input + +| Parameter | Type | Required | Description | +| --------- | ---- | -------- | ----------- | +| `apiToken` | string | Yes | Pylon API token | +| `cursor` | string | No | Pagination cursor for next page of results | +| `limit` | string | No | Maximum number of contacts to return | + +#### Output + +| Parameter | Type | Description | +| --------- | ---- | ----------- | +| `success` | boolean | Operation success status | +| `output` | object | List of contacts | + +### `pylon_create_contact` + +Create a new contact with specified properties + +#### Input + +| Parameter | Type | Required | Description | +| --------- | ---- | -------- | ----------- | +| `apiToken` | string | Yes | Pylon API token | +| `name` | string | Yes | Contact name | +| `email` | string | No | Contact email address | +| `accountId` | string | No | Account ID to associate with contact | +| `accountExternalId` | string | No | External account ID to associate with contact | +| `avatarUrl` | string | No | URL for contact avatar image | +| `customFields` | string | No | Custom fields as JSON object | +| `portalRole` | string | No | Portal role for the contact | + +#### Output + +| Parameter | Type | Description | +| --------- | ---- | ----------- | +| `success` | boolean | Operation success status | +| `output` | object | Created contact data | + +### `pylon_get_contact` + +Retrieve a specific contact by ID + +#### Input + +| Parameter | Type | Required | Description | +| --------- | ---- | -------- | ----------- | +| `apiToken` | string | Yes | Pylon API token | +| `contactId` | string | Yes | Contact ID to retrieve | +| `cursor` | string | No | Pagination cursor for next page of results | +| `limit` | string | No | Maximum number of items to return | + +#### Output + +| Parameter | Type | Description | +| --------- | ---- | ----------- | +| `success` | boolean | Operation success status | +| `output` | object | Contact data | + +### `pylon_update_contact` + +Update an existing contact with specified properties + +#### Input + +| Parameter | Type | Required | Description | +| --------- | ---- | -------- | ----------- | +| `apiToken` | string | Yes | Pylon API token | +| `contactId` | string | Yes | Contact ID to update | +| `name` | string | No | Contact name | +| `email` | string | No | Contact email address | +| `accountId` | string | No | Account ID to associate with contact | +| `accountExternalId` | string | No | External account ID to associate with contact | +| `avatarUrl` | string | No | URL for contact avatar image | +| `customFields` | string | No | Custom fields as JSON object | +| `portalRole` | string | No | Portal role for the contact | + +#### Output + +| Parameter | Type | Description | +| --------- | ---- | ----------- | +| `success` | boolean | Operation success status | +| `output` | object | Updated contact data | + +### `pylon_delete_contact` + +Delete a specific contact by ID + +#### Input + +| Parameter | Type | Required | Description | +| --------- | ---- | -------- | ----------- | +| `apiToken` | string | Yes | Pylon API token | +| `contactId` | string | Yes | Contact ID to delete | + +#### Output + +| Parameter | Type | Description | +| --------- | ---- | ----------- | +| `success` | boolean | Operation success status | +| `output` | object | Delete operation result | + +### `pylon_search_contacts` + +Search for contacts using a filter + +#### Input + +| Parameter | Type | Required | Description | +| --------- | ---- | -------- | ----------- | +| `apiToken` | string | Yes | Pylon API token | +| `filter` | string | Yes | Filter as JSON object | +| `limit` | string | No | Maximum number of contacts to return | +| `cursor` | string | No | Pagination cursor for next page of results | + +#### Output + +| Parameter | Type | Description | +| --------- | ---- | ----------- | +| `success` | boolean | Operation success status | +| `output` | object | Search results | + +### `pylon_list_users` + +Retrieve a list of users + +#### Input + +| Parameter | Type | Required | Description | +| --------- | ---- | -------- | ----------- | +| `apiToken` | string | Yes | Pylon API token | + +#### Output + +| Parameter | Type | Description | +| --------- | ---- | ----------- | +| `success` | boolean | Operation success status | +| `output` | object | List of users | + +### `pylon_get_user` + +Retrieve a specific user by ID + +#### Input + +| Parameter | Type | Required | Description | +| --------- | ---- | -------- | ----------- | +| `apiToken` | string | Yes | Pylon API token | +| `userId` | string | Yes | User ID to retrieve | + +#### Output + +| Parameter | Type | Description | +| --------- | ---- | ----------- | +| `success` | boolean | Operation success status | +| `output` | object | User data | + +### `pylon_update_user` + +Update an existing user with specified properties + +#### Input + +| Parameter | Type | Required | Description | +| --------- | ---- | -------- | ----------- | +| `apiToken` | string | Yes | Pylon API token | +| `userId` | string | Yes | User ID to update | +| `roleId` | string | No | Role ID to assign to user | +| `status` | string | No | User status | + +#### Output + +| Parameter | Type | Description | +| --------- | ---- | ----------- | +| `success` | boolean | Operation success status | +| `output` | object | Updated user data | + +### `pylon_search_users` + +Search for users using a filter with email field + +#### Input + +| Parameter | Type | Required | Description | +| --------- | ---- | -------- | ----------- | +| `apiToken` | string | Yes | Pylon API token | +| `filter` | string | Yes | Filter as JSON object with email field | +| `cursor` | string | No | Pagination cursor for next page of results | +| `limit` | string | No | Maximum number of users to return | + +#### Output + +| Parameter | Type | Description | +| --------- | ---- | ----------- | +| `success` | boolean | Operation success status | +| `output` | object | Search results | + +### `pylon_list_teams` + +Retrieve a list of teams + +#### Input + +| Parameter | Type | Required | Description | +| --------- | ---- | -------- | ----------- | +| `apiToken` | string | Yes | Pylon API token | + +#### Output + +| Parameter | Type | Description | +| --------- | ---- | ----------- | +| `success` | boolean | Operation success status | +| `output` | object | List of teams | + +### `pylon_get_team` + +Retrieve a specific team by ID + +#### Input + +| Parameter | Type | Required | Description | +| --------- | ---- | -------- | ----------- | +| `apiToken` | string | Yes | Pylon API token | +| `teamId` | string | Yes | Team ID to retrieve | + +#### Output + +| Parameter | Type | Description | +| --------- | ---- | ----------- | +| `success` | boolean | Operation success status | +| `output` | object | Team data | + +### `pylon_create_team` + +Create a new team with specified properties + +#### Input + +| Parameter | Type | Required | Description | +| --------- | ---- | -------- | ----------- | +| `apiToken` | string | Yes | Pylon API token | +| `name` | string | No | Team name | +| `userIds` | string | No | Comma-separated user IDs to add as team members | + +#### Output + +| Parameter | Type | Description | +| --------- | ---- | ----------- | +| `success` | boolean | Operation success status | +| `output` | object | Created team data | + +### `pylon_update_team` + +Update an existing team with specified properties (userIds replaces entire membership) + +#### Input + +| Parameter | Type | Required | Description | +| --------- | ---- | -------- | ----------- | +| `apiToken` | string | Yes | Pylon API token | +| `teamId` | string | Yes | Team ID to update | +| `name` | string | No | Team name | +| `userIds` | string | No | Comma-separated user IDs \(replaces entire team membership\) | + +#### Output + +| Parameter | Type | Description | +| --------- | ---- | ----------- | +| `success` | boolean | Operation success status | +| `output` | object | Updated team data | + +### `pylon_list_tags` + +Retrieve a list of tags + +#### Input + +| Parameter | Type | Required | Description | +| --------- | ---- | -------- | ----------- | +| `apiToken` | string | Yes | Pylon API token | + +#### Output + +| Parameter | Type | Description | +| --------- | ---- | ----------- | +| `success` | boolean | Operation success status | +| `output` | object | List of tags | + +### `pylon_get_tag` + +Retrieve a specific tag by ID + +#### Input + +| Parameter | Type | Required | Description | +| --------- | ---- | -------- | ----------- | +| `apiToken` | string | Yes | Pylon API token | +| `tagId` | string | Yes | Tag ID to retrieve | + +#### Output + +| Parameter | Type | Description | +| --------- | ---- | ----------- | +| `success` | boolean | Operation success status | +| `output` | object | Tag data | + +### `pylon_create_tag` + +Create a new tag with specified properties (objectType: account/issue/contact) + +#### Input + +| Parameter | Type | Required | Description | +| --------- | ---- | -------- | ----------- | +| `apiToken` | string | Yes | Pylon API token | +| `objectType` | string | Yes | Object type for tag \(account, issue, or contact\) | +| `value` | string | Yes | Tag value/name | +| `hexColor` | string | No | Hex color code for tag \(e.g., #FF5733\) | + +#### Output + +| Parameter | Type | Description | +| --------- | ---- | ----------- | +| `success` | boolean | Operation success status | +| `output` | object | Created tag data | + +### `pylon_update_tag` + +Update an existing tag with specified properties + +#### Input + +| Parameter | Type | Required | Description | +| --------- | ---- | -------- | ----------- | +| `apiToken` | string | Yes | Pylon API token | +| `tagId` | string | Yes | Tag ID to update | +| `hexColor` | string | No | Hex color code for tag \(e.g., #FF5733\) | +| `value` | string | No | Tag value/name | + +#### Output + +| Parameter | Type | Description | +| --------- | ---- | ----------- | +| `success` | boolean | Operation success status | +| `output` | object | Updated tag data | + +### `pylon_delete_tag` + +Delete a specific tag by ID + +#### Input + +| Parameter | Type | Required | Description | +| --------- | ---- | -------- | ----------- | +| `apiToken` | string | Yes | Pylon API token | +| `tagId` | string | Yes | Tag ID to delete | + +#### Output + +| Parameter | Type | Description | +| --------- | ---- | ----------- | +| `success` | boolean | Operation success status | +| `output` | object | Delete operation result | + +### `pylon_redact_message` + +Redact a specific message within an issue + +#### Input + +| Parameter | Type | Required | Description | +| --------- | ---- | -------- | ----------- | +| `apiToken` | string | Yes | Pylon API token | +| `issueId` | string | Yes | Issue ID containing the message | +| `messageId` | string | Yes | Message ID to redact | + +#### Output + +| Parameter | Type | Description | +| --------- | ---- | ----------- | +| `success` | boolean | Operation success status | +| `output` | object | Redact operation result | + + + +## Notes + +- Category: `tools` +- Type: `pylon` diff --git a/apps/docs/content/docs/en/tools/zendesk.mdx b/apps/docs/content/docs/en/tools/zendesk.mdx new file mode 100644 index 0000000000..a83a771175 --- /dev/null +++ b/apps/docs/content/docs/en/tools/zendesk.mdx @@ -0,0 +1,636 @@ +--- +title: Zendesk +description: Manage support tickets, users, and organizations in Zendesk +--- + +import { BlockInfoCard } from "@/components/ui/block-info-card" + + + +{/* MANUAL-CONTENT-START:intro */} +[Zendesk](https://www.zendesk.com/) is a leading customer service and support platform that enables organizations to efficiently track, prioritize, and solve customer support tickets. Its robust API exposes granular control over all aspects of support, user management, and organizational data, making it a versatile tool for automating business workflows. + +With Zendesk’s rich integration in Sim, your agents can perform nearly any support-related task programmatically. The Zendesk integration provides comprehensive access to actions such as: + +- **Tickets management**: + - Retrieve lists of tickets or a single ticket (`zendesk_get_tickets`, `zendesk_get_ticket`) + - Create a new ticket or multiple tickets in bulk (`zendesk_create_ticket`, `zendesk_create_tickets_bulk`) + - Update a ticket or update multiple tickets at once (`zendesk_update_ticket`, `zendesk_update_tickets_bulk`) + - Delete tickets, merge tickets, and manage ticket lifecycle (`zendesk_delete_ticket`, `zendesk_merge_tickets`) +- **User operations**: + - Fetch all users, get a single user, or get your current Zendesk user (`zendesk_get_users`, `zendesk_get_user`, `zendesk_get_current_user`) + - Search users, create a user, create users in bulk, update users (single or bulk), and delete users (`zendesk_search_users`, `zendesk_create_user`, `zendesk_create_users_bulk`, `zendesk_update_user`, `zendesk_update_users_bulk`, `zendesk_delete_user`) +- **Organization operations**: + - List organizations, get a single organization, or search for organizations (`zendesk_get_organizations`, `zendesk_get_organization`, `zendesk_search_organizations`) + - Create a new organization or multiple at once, update, and delete organizations (`zendesk_create_organization`, `zendesk_create_organizations_bulk`, `zendesk_update_organization`, `zendesk_delete_organization`) +- **Advanced data access and search**: + - Powerful search capabilities across tickets, users, and organizations (`zendesk_search`) + - Count matched results for a search query (`zendesk_search_count`) + - Export search results for reporting or downstream automation (`zendesk_export_search`) + +**Bulk operations** are available for tickets, users, and organizations, allowing you to automate updates or creations at scale. Every major resource (tickets, users, orgs) can be created, listed, updated, deleted, or queried both individually and in batches. + +By leveraging these tools, Sim agents can take complex support scenarios such as onboarding, triage, escalations, ticket merging, and reporting and make them hands-free and fully automated. This enables your workflows to efficiently keep CRM data synchronized, support customers in real-time, and maintain clean, integrated records. + +Whether you need to power support chatbots, automate escalations, sync user databases, or generate cross-system reports, the Zendesk integration in Sim provides granular control for any customer support automation need. +{/* MANUAL-CONTENT-END */} + + +## Usage Instructions + +Integrate Zendesk into the workflow. Can get tickets, get ticket, create ticket, create tickets bulk, update ticket, update tickets bulk, delete ticket, merge tickets, get users, get user, get current user, search users, create user, create users bulk, update user, update users bulk, delete user, get organizations, get organization, autocomplete organizations, create organization, create organizations bulk, update organization, delete organization, search, search count, export search. + + + +## Tools + +### `zendesk_get_tickets` + +Retrieve a list of tickets from Zendesk with optional filtering + +#### Input + +| Parameter | Type | Required | Description | +| --------- | ---- | -------- | ----------- | +| `apiToken` | string | Yes | Zendesk API token | +| `subdomain` | string | Yes | Your Zendesk subdomain \(e.g., "mycompany" for mycompany.zendesk.com\) | +| `status` | string | No | Filter by status \(new, open, pending, hold, solved, closed\) | +| `priority` | string | No | Filter by priority \(low, normal, high, urgent\) | +| `type` | string | No | Filter by type \(problem, incident, question, task\) | +| `assigneeId` | string | No | Filter by assignee user ID | +| `organizationId` | string | No | Filter by organization ID | +| `sortBy` | string | No | Sort field \(created_at, updated_at, priority, status\) | +| `sortOrder` | string | No | Sort order \(asc or desc\) | +| `perPage` | string | No | Results per page \(default: 100, max: 100\) | +| `page` | string | No | Page number | + +#### Output + +| Parameter | Type | Description | +| --------- | ---- | ----------- | +| `success` | boolean | Operation success status | +| `output` | object | Tickets data and metadata | + +### `zendesk_get_ticket` + +Get a single ticket by ID from Zendesk + +#### Input + +| Parameter | Type | Required | Description | +| --------- | ---- | -------- | ----------- | +| `apiToken` | string | Yes | Zendesk API token | +| `subdomain` | string | Yes | Your Zendesk subdomain | +| `ticketId` | string | Yes | Ticket ID to retrieve | + +#### Output + +| Parameter | Type | Description | +| --------- | ---- | ----------- | +| `success` | boolean | Operation success status | +| `output` | object | Ticket data | + +### `zendesk_create_ticket` + +Create a new ticket in Zendesk with support for custom fields + +#### Input + +| Parameter | Type | Required | Description | +| --------- | ---- | -------- | ----------- | +| `apiToken` | string | Yes | Zendesk API token | +| `subdomain` | string | Yes | Your Zendesk subdomain | +| `subject` | string | No | Ticket subject \(optional - will be auto-generated if not provided\) | +| `description` | string | Yes | Ticket description \(first comment\) | +| `priority` | string | No | Priority \(low, normal, high, urgent\) | +| `status` | string | No | Status \(new, open, pending, hold, solved, closed\) | +| `type` | string | No | Type \(problem, incident, question, task\) | +| `tags` | string | No | Comma-separated tags | +| `assigneeId` | string | No | Assignee user ID | + +#### Output + +| Parameter | Type | Description | +| --------- | ---- | ----------- | +| `success` | boolean | Operation success status | +| `output` | object | Created ticket data | + +### `zendesk_create_tickets_bulk` + +Create multiple tickets in Zendesk at once (max 100) + +#### Input + +| Parameter | Type | Required | Description | +| --------- | ---- | -------- | ----------- | +| `apiToken` | string | Yes | Zendesk API token | +| `subdomain` | string | Yes | Your Zendesk subdomain | +| `tickets` | string | Yes | JSON array of ticket objects to create \(max 100\). Each ticket should have subject and comment properties. | + +#### Output + +| Parameter | Type | Description | +| --------- | ---- | ----------- | +| `success` | boolean | Operation success status | +| `output` | object | Bulk create job status | + +### `zendesk_update_ticket` + +Update an existing ticket in Zendesk with support for custom fields + +#### Input + +| Parameter | Type | Required | Description | +| --------- | ---- | -------- | ----------- | +| `apiToken` | string | Yes | Zendesk API token | +| `subdomain` | string | Yes | Your Zendesk subdomain | +| `ticketId` | string | Yes | Ticket ID to update | +| `subject` | string | No | New ticket subject | +| `comment` | string | No | Add a comment to the ticket | +| `priority` | string | No | Priority \(low, normal, high, urgent\) | +| `status` | string | No | Status \(new, open, pending, hold, solved, closed\) | +| `type` | string | No | Type \(problem, incident, question, task\) | +| `tags` | string | No | Comma-separated tags | +| `assigneeId` | string | No | Assignee user ID | +| `groupId` | string | No | Group ID | +| `customFields` | string | No | Custom fields as JSON object | + +#### Output + +| Parameter | Type | Description | +| --------- | ---- | ----------- | +| `success` | boolean | Operation success status | +| `output` | object | Updated ticket data | + +### `zendesk_update_tickets_bulk` + +Update multiple tickets in Zendesk at once (max 100) + +#### Input + +| Parameter | Type | Required | Description | +| --------- | ---- | -------- | ----------- | +| `apiToken` | string | Yes | Zendesk API token | +| `subdomain` | string | Yes | Your Zendesk subdomain | +| `ticketIds` | string | Yes | Comma-separated ticket IDs to update \(max 100\) | +| `status` | string | No | New status for all tickets | +| `priority` | string | No | New priority for all tickets | +| `assigneeId` | string | No | New assignee ID for all tickets | +| `groupId` | string | No | New group ID for all tickets | +| `tags` | string | No | Comma-separated tags to add to all tickets | + +#### Output + +| Parameter | Type | Description | +| --------- | ---- | ----------- | +| `success` | boolean | Operation success status | +| `output` | object | Bulk update job status | + +### `zendesk_delete_ticket` + +Delete a ticket from Zendesk + +#### Input + +| Parameter | Type | Required | Description | +| --------- | ---- | -------- | ----------- | +| `apiToken` | string | Yes | Zendesk API token | +| `subdomain` | string | Yes | Your Zendesk subdomain | +| `ticketId` | string | Yes | Ticket ID to delete | + +#### Output + +| Parameter | Type | Description | +| --------- | ---- | ----------- | +| `success` | boolean | Operation success status | +| `output` | object | Delete confirmation | + +### `zendesk_merge_tickets` + +Merge multiple tickets into a target ticket + +#### Input + +| Parameter | Type | Required | Description | +| --------- | ---- | -------- | ----------- | +| `apiToken` | string | Yes | Zendesk API token | +| `subdomain` | string | Yes | Your Zendesk subdomain | +| `targetTicketId` | string | Yes | Target ticket ID \(tickets will be merged into this one\) | +| `sourceTicketIds` | string | Yes | Comma-separated source ticket IDs to merge | +| `targetComment` | string | No | Comment to add to target ticket after merge | + +#### Output + +| Parameter | Type | Description | +| --------- | ---- | ----------- | +| `success` | boolean | Operation success status | +| `output` | object | Merge job status | + +### `zendesk_get_users` + +Retrieve a list of users from Zendesk with optional filtering + +#### Input + +| Parameter | Type | Required | Description | +| --------- | ---- | -------- | ----------- | +| `apiToken` | string | Yes | Zendesk API token | +| `subdomain` | string | Yes | Your Zendesk subdomain \(e.g., "mycompany" for mycompany.zendesk.com\) | +| `role` | string | No | Filter by role \(end-user, agent, admin\) | +| `permissionSet` | string | No | Filter by permission set ID | +| `perPage` | string | No | Results per page \(default: 100, max: 100\) | +| `page` | string | No | Page number | + +#### Output + +| Parameter | Type | Description | +| --------- | ---- | ----------- | +| `success` | boolean | Operation success status | +| `output` | object | Users data and metadata | + +### `zendesk_get_user` + +Get a single user by ID from Zendesk + +#### Input + +| Parameter | Type | Required | Description | +| --------- | ---- | -------- | ----------- | +| `apiToken` | string | Yes | Zendesk API token | +| `subdomain` | string | Yes | Your Zendesk subdomain | +| `userId` | string | Yes | User ID to retrieve | + +#### Output + +| Parameter | Type | Description | +| --------- | ---- | ----------- | +| `success` | boolean | Operation success status | +| `output` | object | User data | + +### `zendesk_get_current_user` + +Get the currently authenticated user from Zendesk + +#### Input + +| Parameter | Type | Required | Description | +| --------- | ---- | -------- | ----------- | +| `apiToken` | string | Yes | Zendesk API token | +| `subdomain` | string | Yes | Your Zendesk subdomain | + +#### Output + +| Parameter | Type | Description | +| --------- | ---- | ----------- | +| `success` | boolean | Operation success status | +| `output` | object | Current user data | + +### `zendesk_search_users` + +Search for users in Zendesk using a query string + +#### Input + +| Parameter | Type | Required | Description | +| --------- | ---- | -------- | ----------- | +| `apiToken` | string | Yes | Zendesk API token | +| `subdomain` | string | Yes | Your Zendesk subdomain | +| `query` | string | No | Search query string | +| `externalId` | string | No | External ID to search by | +| `perPage` | string | No | Results per page \(default: 100, max: 100\) | +| `page` | string | No | Page number | + +#### Output + +| Parameter | Type | Description | +| --------- | ---- | ----------- | +| `success` | boolean | Operation success status | +| `output` | object | Users search results | + +### `zendesk_create_user` + +Create a new user in Zendesk + +#### Input + +| Parameter | Type | Required | Description | +| --------- | ---- | -------- | ----------- | +| `apiToken` | string | Yes | Zendesk API token | +| `subdomain` | string | Yes | Your Zendesk subdomain | +| `name` | string | No | User name | +| `email` | string | No | User email | +| `role` | string | No | User role \(end-user, agent, admin\) | +| `phone` | string | No | User phone number | +| `organizationId` | string | No | Organization ID | +| `verified` | string | No | Set to "true" to skip email verification | +| `tags` | string | No | Comma-separated tags | +| `customFields` | string | No | Custom fields as JSON object \(e.g., \{"field_id": "value"\}\) | + +#### Output + +| Parameter | Type | Description | +| --------- | ---- | ----------- | +| `success` | boolean | Operation success status | +| `output` | object | Created user data | + +### `zendesk_create_users_bulk` + +Create multiple users in Zendesk using bulk import + +#### Input + +| Parameter | Type | Required | Description | +| --------- | ---- | -------- | ----------- | +| `apiToken` | string | Yes | Zendesk API token | +| `subdomain` | string | Yes | Your Zendesk subdomain | +| `users` | string | Yes | JSON array of user objects to create | + +#### Output + +| Parameter | Type | Description | +| --------- | ---- | ----------- | +| `success` | boolean | Operation success status | +| `output` | object | Bulk creation job status | + +### `zendesk_update_user` + +Update an existing user in Zendesk + +#### Input + +| Parameter | Type | Required | Description | +| --------- | ---- | -------- | ----------- | +| `apiToken` | string | Yes | Zendesk API token | +| `subdomain` | string | Yes | Your Zendesk subdomain | +| `userId` | string | Yes | User ID to update | +| `name` | string | No | New user name | +| `email` | string | No | New user email | +| `role` | string | No | User role \(end-user, agent, admin\) | +| `phone` | string | No | User phone number | +| `organizationId` | string | No | Organization ID | +| `verified` | string | No | Set to "true" to mark user as verified | +| `tags` | string | No | Comma-separated tags | +| `customFields` | string | No | Custom fields as JSON object | + +#### Output + +| Parameter | Type | Description | +| --------- | ---- | ----------- | +| `success` | boolean | Operation success status | +| `output` | object | Updated user data | + +### `zendesk_update_users_bulk` + +Update multiple users in Zendesk using bulk update + +#### Input + +| Parameter | Type | Required | Description | +| --------- | ---- | -------- | ----------- | +| `apiToken` | string | Yes | Zendesk API token | +| `subdomain` | string | Yes | Your Zendesk subdomain | +| `users` | string | Yes | JSON array of user objects to update \(must include id field\) | + +#### Output + +| Parameter | Type | Description | +| --------- | ---- | ----------- | +| `success` | boolean | Operation success status | +| `output` | object | Bulk update job status | + +### `zendesk_delete_user` + +Delete a user from Zendesk + +#### Input + +| Parameter | Type | Required | Description | +| --------- | ---- | -------- | ----------- | +| `apiToken` | string | Yes | Zendesk API token | +| `subdomain` | string | Yes | Your Zendesk subdomain | +| `userId` | string | Yes | User ID to delete | + +#### Output + +| Parameter | Type | Description | +| --------- | ---- | ----------- | +| `success` | boolean | Operation success status | +| `output` | object | Deleted user data | + +### `zendesk_get_organizations` + +Retrieve a list of organizations from Zendesk + +#### Input + +| Parameter | Type | Required | Description | +| --------- | ---- | -------- | ----------- | +| `apiToken` | string | Yes | Zendesk API token | +| `subdomain` | string | Yes | Your Zendesk subdomain \(e.g., "mycompany" for mycompany.zendesk.com\) | +| `perPage` | string | No | Results per page \(default: 100, max: 100\) | +| `page` | string | No | Page number | + +#### Output + +| Parameter | Type | Description | +| --------- | ---- | ----------- | +| `success` | boolean | Operation success status | +| `output` | object | Organizations data and metadata | + +### `zendesk_get_organization` + +Get a single organization by ID from Zendesk + +#### Input + +| Parameter | Type | Required | Description | +| --------- | ---- | -------- | ----------- | +| `apiToken` | string | Yes | Zendesk API token | +| `subdomain` | string | Yes | Your Zendesk subdomain | +| `organizationId` | string | Yes | Organization ID to retrieve | + +#### Output + +| Parameter | Type | Description | +| --------- | ---- | ----------- | +| `success` | boolean | Operation success status | +| `output` | object | Organization data | + +### `zendesk_autocomplete_organizations` + +Autocomplete organizations in Zendesk by name prefix (for name matching/autocomplete) + +#### Input + +| Parameter | Type | Required | Description | +| --------- | ---- | -------- | ----------- | +| `apiToken` | string | Yes | Zendesk API token | +| `subdomain` | string | Yes | Your Zendesk subdomain | +| `name` | string | Yes | Organization name to search for | +| `perPage` | string | No | Results per page \(default: 100, max: 100\) | +| `page` | string | No | Page number | + +#### Output + +| Parameter | Type | Description | +| --------- | ---- | ----------- | +| `success` | boolean | Operation success status | +| `output` | object | Organizations search results | + +### `zendesk_create_organization` + +Create a new organization in Zendesk + +#### Input + +| Parameter | Type | Required | Description | +| --------- | ---- | -------- | ----------- | +| `apiToken` | string | Yes | Zendesk API token | +| `subdomain` | string | Yes | Your Zendesk subdomain | +| `name` | string | Yes | Organization name | +| `domainNames` | string | No | Comma-separated domain names | +| `details` | string | No | Organization details | +| `notes` | string | No | Organization notes | +| `tags` | string | No | Comma-separated tags | +| `customFields` | string | No | Custom fields as JSON object \(e.g., \{"field_id": "value"\}\) | + +#### Output + +| Parameter | Type | Description | +| --------- | ---- | ----------- | +| `success` | boolean | Operation success status | +| `output` | object | Created organization data | + +### `zendesk_create_organizations_bulk` + +Create multiple organizations in Zendesk using bulk import + +#### Input + +| Parameter | Type | Required | Description | +| --------- | ---- | -------- | ----------- | +| `apiToken` | string | Yes | Zendesk API token | +| `subdomain` | string | Yes | Your Zendesk subdomain | +| `organizations` | string | Yes | JSON array of organization objects to create | + +#### Output + +| Parameter | Type | Description | +| --------- | ---- | ----------- | +| `success` | boolean | Operation success status | +| `output` | object | Bulk creation job status | + +### `zendesk_update_organization` + +Update an existing organization in Zendesk + +#### Input + +| Parameter | Type | Required | Description | +| --------- | ---- | -------- | ----------- | +| `apiToken` | string | Yes | Zendesk API token | +| `subdomain` | string | Yes | Your Zendesk subdomain | +| `organizationId` | string | Yes | Organization ID to update | +| `name` | string | No | New organization name | +| `domainNames` | string | No | Comma-separated domain names | +| `details` | string | No | Organization details | +| `notes` | string | No | Organization notes | +| `tags` | string | No | Comma-separated tags | +| `customFields` | string | No | Custom fields as JSON object | + +#### Output + +| Parameter | Type | Description | +| --------- | ---- | ----------- | +| `success` | boolean | Operation success status | +| `output` | object | Updated organization data | + +### `zendesk_delete_organization` + +Delete an organization from Zendesk + +#### Input + +| Parameter | Type | Required | Description | +| --------- | ---- | -------- | ----------- | +| `apiToken` | string | Yes | Zendesk API token | +| `subdomain` | string | Yes | Your Zendesk subdomain | +| `organizationId` | string | Yes | Organization ID to delete | + +#### Output + +| Parameter | Type | Description | +| --------- | ---- | ----------- | +| `success` | boolean | Operation success status | +| `output` | object | Deleted organization data | + +### `zendesk_search` + +Unified search across tickets, users, and organizations in Zendesk + +#### Input + +| Parameter | Type | Required | Description | +| --------- | ---- | -------- | ----------- | +| `apiToken` | string | Yes | Zendesk API token | +| `subdomain` | string | Yes | Your Zendesk subdomain | +| `query` | string | Yes | Search query string | +| `sortBy` | string | No | Sort field \(relevance, created_at, updated_at, priority, status, ticket_type\) | +| `sortOrder` | string | No | Sort order \(asc or desc\) | +| `perPage` | string | No | Results per page \(default: 100, max: 100\) | +| `page` | string | No | Page number | + +#### Output + +| Parameter | Type | Description | +| --------- | ---- | ----------- | +| `success` | boolean | Operation success status | +| `output` | object | Search results | + +### `zendesk_search_count` + +Count the number of search results matching a query in Zendesk + +#### Input + +| Parameter | Type | Required | Description | +| --------- | ---- | -------- | ----------- | +| `apiToken` | string | Yes | Zendesk API token | +| `subdomain` | string | Yes | Your Zendesk subdomain | +| `query` | string | Yes | Search query string | + +#### Output + +| Parameter | Type | Description | +| --------- | ---- | ----------- | +| `success` | boolean | Operation success status | +| `output` | object | Search count result | + +### `zendesk_export_search` + +Export search results from Zendesk (supports larger result sets) + +#### Input + +| Parameter | Type | Required | Description | +| --------- | ---- | -------- | ----------- | +| `apiToken` | string | Yes | Zendesk API token | +| `subdomain` | string | Yes | Your Zendesk subdomain | +| `query` | string | Yes | Search query string | + +#### Output + +| Parameter | Type | Description | +| --------- | ---- | ----------- | +| `success` | boolean | Operation success status | +| `output` | object | Exported search results | + + + +## Notes + +- Category: `tools` +- Type: `zendesk` diff --git a/apps/sim/blocks/blocks/intercom.ts b/apps/sim/blocks/blocks/intercom.ts new file mode 100644 index 0000000000..d4f5efaf29 --- /dev/null +++ b/apps/sim/blocks/blocks/intercom.ts @@ -0,0 +1,582 @@ +import { IntercomIcon } from '@/components/icons' +import type { BlockConfig } from '@/blocks/types' +import { AuthMode } from '@/blocks/types' + +export const IntercomBlock: BlockConfig = { + type: 'intercom', + name: 'Intercom', + description: 'Manage contacts, companies, conversations, tickets, and messages in Intercom', + longDescription: + 'Integrate Intercom into the workflow. Can create, get, update, list, search, and delete contacts; create, get, and list companies; get, list, reply, and search conversations; create, get, and list tickets; and create messages.', + docsLink: 'https://docs.sim.ai/tools/intercom', + authMode: AuthMode.ApiKey, + category: 'tools', + bgColor: '#E0E0E0', + icon: IntercomIcon, + subBlocks: [ + { + id: 'operation', + title: 'Operation', + type: 'dropdown', + options: [ + { label: 'Create Contact', id: 'create_contact' }, + { label: 'Get Contact', id: 'get_contact' }, + { label: 'Update Contact', id: 'update_contact' }, + { label: 'List Contacts', id: 'list_contacts' }, + { label: 'Search Contacts', id: 'search_contacts' }, + { label: 'Delete Contact', id: 'delete_contact' }, + { label: 'Create Company', id: 'create_company' }, + { label: 'Get Company', id: 'get_company' }, + { label: 'List Companies', id: 'list_companies' }, + { label: 'Get Conversation', id: 'get_conversation' }, + { label: 'List Conversations', id: 'list_conversations' }, + { label: 'Reply to Conversation', id: 'reply_conversation' }, + { label: 'Search Conversations', id: 'search_conversations' }, + { label: 'Create Ticket', id: 'create_ticket' }, + { label: 'Get Ticket', id: 'get_ticket' }, + { label: 'List Tickets', id: 'list_tickets' }, + { label: 'Create Message', id: 'create_message' }, + ], + value: () => 'create_contact', + }, + { + id: 'accessToken', + title: 'Access Token', + type: 'short-input', + password: true, + placeholder: 'Enter your Intercom access token', + required: true, + }, + // Contact fields + { + id: 'contactId', + title: 'Contact ID', + type: 'short-input', + placeholder: 'Contact ID', + required: true, + condition: { + field: 'operation', + value: ['get_contact', 'update_contact', 'delete_contact'], + }, + }, + { + id: 'email', + title: 'Email', + type: 'short-input', + placeholder: 'Contact email', + condition: { + field: 'operation', + value: ['create_contact', 'update_contact'], + }, + }, + { + id: 'external_id', + title: 'External ID', + type: 'short-input', + placeholder: 'External identifier for the contact', + condition: { + field: 'operation', + value: ['create_contact'], + }, + }, + { + id: 'phone', + title: 'Phone', + type: 'short-input', + placeholder: 'Contact phone number', + condition: { + field: 'operation', + value: ['create_contact', 'update_contact'], + }, + }, + { + id: 'name', + title: 'Name', + type: 'short-input', + placeholder: 'Contact name', + condition: { + field: 'operation', + value: ['create_contact', 'update_contact'], + }, + }, + { + id: 'avatar', + title: 'Avatar URL', + type: 'short-input', + placeholder: 'Avatar image URL', + condition: { + field: 'operation', + value: ['create_contact', 'update_contact'], + }, + }, + { + id: 'signed_up_at', + title: 'Signed Up At', + type: 'short-input', + placeholder: 'Unix timestamp', + condition: { + field: 'operation', + value: ['create_contact', 'update_contact'], + }, + }, + { + id: 'last_seen_at', + title: 'Last Seen At', + type: 'short-input', + placeholder: 'Unix timestamp', + condition: { + field: 'operation', + value: ['create_contact', 'update_contact'], + }, + }, + { + id: 'owner_id', + title: 'Owner ID', + type: 'short-input', + placeholder: 'Admin ID', + condition: { + field: 'operation', + value: ['create_contact', 'update_contact'], + }, + }, + { + id: 'unsubscribed_from_emails', + title: 'Unsubscribed from Emails', + type: 'dropdown', + options: [ + { label: 'True', id: 'true' }, + { label: 'False', id: 'false' }, + ], + condition: { + field: 'operation', + value: ['create_contact', 'update_contact'], + }, + }, + { + id: 'custom_attributes', + title: 'Custom Attributes', + type: 'long-input', + placeholder: 'JSON object with custom attributes', + condition: { + field: 'operation', + value: ['create_contact', 'update_contact'], + }, + }, + { + id: 'query', + title: 'Search Query', + type: 'long-input', + placeholder: 'JSON search query or text', + required: true, + condition: { + field: 'operation', + value: ['search_contacts', 'search_conversations'], + }, + }, + // Company fields + { + id: 'companyId', + title: 'Company ID', + type: 'short-input', + placeholder: 'Intercom company ID', + required: true, + condition: { + field: 'operation', + value: ['get_company'], + }, + }, + { + id: 'company_id', + title: 'Company ID (External)', + type: 'short-input', + placeholder: 'Your unique identifier for the company', + required: true, + condition: { + field: 'operation', + value: ['create_company'], + }, + }, + { + id: 'company_name', + title: 'Company Name', + type: 'short-input', + placeholder: 'Company name', + condition: { + field: 'operation', + value: ['create_company'], + }, + }, + { + id: 'website', + title: 'Website', + type: 'short-input', + placeholder: 'Company website', + condition: { + field: 'operation', + value: ['create_company'], + }, + }, + { + id: 'plan', + title: 'Plan', + type: 'short-input', + placeholder: 'Subscription plan', + condition: { + field: 'operation', + value: ['create_company'], + }, + }, + { + id: 'size', + title: 'Size', + type: 'short-input', + placeholder: 'Number of employees', + condition: { + field: 'operation', + value: ['create_company'], + }, + }, + { + id: 'industry', + title: 'Industry', + type: 'short-input', + placeholder: 'Company industry', + condition: { + field: 'operation', + value: ['create_company'], + }, + }, + { + id: 'monthly_spend', + title: 'Monthly Spend', + type: 'short-input', + placeholder: 'Revenue amount', + condition: { + field: 'operation', + value: ['create_company'], + }, + }, + // Conversation fields + { + id: 'conversationId', + title: 'Conversation ID', + type: 'short-input', + placeholder: 'Conversation ID', + required: true, + condition: { + field: 'operation', + value: ['get_conversation', 'reply_conversation'], + }, + }, + { + id: 'display_as', + title: 'Display As', + type: 'dropdown', + options: [ + { label: 'HTML', id: 'html' }, + { label: 'Plain Text', id: 'plaintext' }, + ], + condition: { + field: 'operation', + value: ['get_conversation'], + }, + }, + { + id: 'message_type', + title: 'Message Type', + type: 'dropdown', + options: [ + { label: 'Comment', id: 'comment' }, + { label: 'Note', id: 'note' }, + ], + required: true, + condition: { + field: 'operation', + value: ['reply_conversation'], + }, + }, + { + id: 'body', + title: 'Message Body', + type: 'long-input', + placeholder: 'Message text', + required: true, + condition: { + field: 'operation', + value: ['reply_conversation', 'create_message'], + }, + }, + { + id: 'admin_id', + title: 'Admin ID', + type: 'short-input', + placeholder: 'ID of the admin sending the message', + required: true, + condition: { + field: 'operation', + value: ['reply_conversation'], + }, + }, + { + id: 'attachment_urls', + title: 'Attachment URLs', + type: 'short-input', + placeholder: 'Comma-separated image URLs (max 10)', + condition: { + field: 'operation', + value: ['reply_conversation'], + }, + }, + // Ticket fields + { + id: 'ticketId', + title: 'Ticket ID', + type: 'short-input', + placeholder: 'Ticket ID', + required: true, + condition: { + field: 'operation', + value: ['get_ticket'], + }, + }, + { + id: 'ticket_type_id', + title: 'Ticket Type ID', + type: 'short-input', + placeholder: 'ID of the ticket type', + required: true, + condition: { + field: 'operation', + value: ['create_ticket'], + }, + }, + { + id: 'contacts', + title: 'Contacts', + type: 'long-input', + placeholder: 'JSON array of contact identifiers', + required: true, + condition: { + field: 'operation', + value: ['create_ticket'], + }, + }, + { + id: 'ticket_attributes', + title: 'Ticket Attributes', + type: 'long-input', + placeholder: 'JSON object with ticket attributes', + required: true, + condition: { + field: 'operation', + value: ['create_ticket'], + }, + }, + // Message fields + { + id: 'message_type_msg', + title: 'Message Type', + type: 'dropdown', + options: [ + { label: 'In-App', id: 'inapp' }, + { label: 'Email', id: 'email' }, + ], + required: true, + condition: { + field: 'operation', + value: ['create_message'], + }, + }, + { + id: 'subject', + title: 'Subject', + type: 'short-input', + placeholder: 'Email subject (for email type)', + condition: { + field: 'operation', + value: ['create_message'], + }, + }, + { + id: 'from_type', + title: 'From Type', + type: 'dropdown', + options: [{ label: 'Admin', id: 'admin' }], + required: true, + condition: { + field: 'operation', + value: ['create_message'], + }, + }, + { + id: 'from_id', + title: 'From ID', + type: 'short-input', + placeholder: 'Admin ID', + required: true, + condition: { + field: 'operation', + value: ['create_message'], + }, + }, + { + id: 'to_type', + title: 'To Type', + type: 'dropdown', + options: [{ label: 'Contact', id: 'contact' }], + required: true, + condition: { + field: 'operation', + value: ['create_message'], + }, + }, + { + id: 'to_id', + title: 'To ID', + type: 'short-input', + placeholder: 'Contact ID', + required: true, + condition: { + field: 'operation', + value: ['create_message'], + }, + }, + // Pagination fields + { + id: 'per_page', + title: 'Per Page', + type: 'short-input', + placeholder: 'Results per page (max: 150)', + condition: { + field: 'operation', + value: [ + 'list_contacts', + 'search_contacts', + 'list_companies', + 'list_conversations', + 'search_conversations', + 'list_tickets', + ], + }, + }, + { + id: 'starting_after', + title: 'Starting After', + type: 'short-input', + placeholder: 'Cursor for pagination', + condition: { + field: 'operation', + value: [ + 'list_contacts', + 'search_contacts', + 'list_conversations', + 'search_conversations', + 'list_tickets', + ], + }, + }, + { + id: 'page', + title: 'Page', + type: 'short-input', + placeholder: 'Page number', + condition: { + field: 'operation', + value: ['list_companies'], + }, + }, + ], + tools: { + access: [ + 'intercom_create_contact', + 'intercom_get_contact', + 'intercom_update_contact', + 'intercom_list_contacts', + 'intercom_search_contacts', + 'intercom_delete_contact', + 'intercom_create_company', + 'intercom_get_company', + 'intercom_list_companies', + 'intercom_get_conversation', + 'intercom_list_conversations', + 'intercom_reply_conversation', + 'intercom_search_conversations', + 'intercom_create_ticket', + 'intercom_get_ticket', + 'intercom_list_tickets', + 'intercom_create_message', + ], + config: { + tool: (params) => { + switch (params.operation) { + case 'create_contact': + return 'intercom_create_contact' + case 'get_contact': + return 'intercom_get_contact' + case 'update_contact': + return 'intercom_update_contact' + case 'list_contacts': + return 'intercom_list_contacts' + case 'search_contacts': + return 'intercom_search_contacts' + case 'delete_contact': + return 'intercom_delete_contact' + case 'create_company': + return 'intercom_create_company' + case 'get_company': + return 'intercom_get_company' + case 'list_companies': + return 'intercom_list_companies' + case 'get_conversation': + return 'intercom_get_conversation' + case 'list_conversations': + return 'intercom_list_conversations' + case 'reply_conversation': + return 'intercom_reply_conversation' + case 'search_conversations': + return 'intercom_search_conversations' + case 'create_ticket': + return 'intercom_create_ticket' + case 'get_ticket': + return 'intercom_get_ticket' + case 'list_tickets': + return 'intercom_list_tickets' + case 'create_message': + return 'intercom_create_message' + default: + throw new Error(`Unknown operation: ${params.operation}`) + } + }, + params: (params) => { + const { operation, message_type_msg, company_name, ...rest } = params + const cleanParams: Record = {} + + // Special mapping for message_type in create_message + if (operation === 'create_message' && message_type_msg) { + cleanParams.message_type = message_type_msg + } + + // Special mapping for company name + if (operation === 'create_company' && company_name) { + cleanParams.name = company_name + } + + Object.entries(rest).forEach(([key, value]) => { + if (value !== undefined && value !== null && value !== '') { + cleanParams[key] = value + } + }) + + return cleanParams + }, + }, + }, + inputs: { + operation: { type: 'string', description: 'Operation to perform' }, + accessToken: { type: 'string', description: 'Intercom API access token' }, + }, + outputs: { + success: { type: 'boolean', description: 'Operation success status' }, + output: { type: 'json', description: 'Operation result data' }, + }, +} diff --git a/apps/sim/blocks/blocks/mailchimp.ts b/apps/sim/blocks/blocks/mailchimp.ts new file mode 100644 index 0000000000..381f14e3a2 --- /dev/null +++ b/apps/sim/blocks/blocks/mailchimp.ts @@ -0,0 +1,1039 @@ +import { MailchimpIcon } from '@/components/icons' +import type { BlockConfig } from '@/blocks/types' +import { AuthMode } from '@/blocks/types' + +export const MailchimpBlock: BlockConfig = { + type: 'mailchimp', + name: 'Mailchimp', + description: 'Manage audiences, campaigns, and marketing automation in Mailchimp', + longDescription: + 'Integrate Mailchimp into the workflow. Can manage audiences (lists), list members, campaigns, automation workflows, templates, reports, segments, tags, merge fields, interest categories, landing pages, signup forms, and batch operations.', + docsLink: 'https://docs.sim.ai/tools/mailchimp', + authMode: AuthMode.ApiKey, + category: 'tools', + bgColor: '#FFE01B', + icon: MailchimpIcon, + subBlocks: [ + { + id: 'operation', + title: 'Operation', + type: 'dropdown', + options: [ + // Audience/List operations + { label: 'Get Audiences', id: 'get_audiences' }, + { label: 'Get Audience', id: 'get_audience' }, + { label: 'Create Audience', id: 'create_audience' }, + { label: 'Update Audience', id: 'update_audience' }, + { label: 'Delete Audience', id: 'delete_audience' }, + // Member operations + { label: 'Get Members', id: 'get_members' }, + { label: 'Get Member', id: 'get_member' }, + { label: 'Add Member', id: 'add_member' }, + { label: 'Add or Update Member', id: 'add_or_update_member' }, + { label: 'Update Member', id: 'update_member' }, + { label: 'Delete Member', id: 'delete_member' }, + { label: 'Archive Member', id: 'archive_member' }, + { label: 'Unarchive Member', id: 'unarchive_member' }, + // Campaign operations + { label: 'Get Campaigns', id: 'get_campaigns' }, + { label: 'Get Campaign', id: 'get_campaign' }, + { label: 'Create Campaign', id: 'create_campaign' }, + { label: 'Update Campaign', id: 'update_campaign' }, + { label: 'Delete Campaign', id: 'delete_campaign' }, + { label: 'Send Campaign', id: 'send_campaign' }, + { label: 'Schedule Campaign', id: 'schedule_campaign' }, + { label: 'Unschedule Campaign', id: 'unschedule_campaign' }, + { label: 'Replicate Campaign', id: 'replicate_campaign' }, + // Campaign content operations + { label: 'Get Campaign Content', id: 'get_campaign_content' }, + { label: 'Set Campaign Content', id: 'set_campaign_content' }, + // Automation operations + { label: 'Get Automations', id: 'get_automations' }, + { label: 'Get Automation', id: 'get_automation' }, + { label: 'Start Automation', id: 'start_automation' }, + { label: 'Pause Automation', id: 'pause_automation' }, + { label: 'Add Subscriber to Automation', id: 'add_subscriber_to_automation' }, + // Template operations + { label: 'Get Templates', id: 'get_templates' }, + { label: 'Get Template', id: 'get_template' }, + { label: 'Create Template', id: 'create_template' }, + { label: 'Update Template', id: 'update_template' }, + { label: 'Delete Template', id: 'delete_template' }, + // Report operations + { label: 'Get Campaign Reports', id: 'get_campaign_reports' }, + { label: 'Get Campaign Report', id: 'get_campaign_report' }, + // Segment operations + { label: 'Get Segments', id: 'get_segments' }, + { label: 'Get Segment', id: 'get_segment' }, + { label: 'Create Segment', id: 'create_segment' }, + { label: 'Update Segment', id: 'update_segment' }, + { label: 'Delete Segment', id: 'delete_segment' }, + { label: 'Get Segment Members', id: 'get_segment_members' }, + { label: 'Add Segment Member', id: 'add_segment_member' }, + { label: 'Remove Segment Member', id: 'remove_segment_member' }, + // Tag operations + { label: 'Get Member Tags', id: 'get_member_tags' }, + { label: 'Add Member Tags', id: 'add_member_tags' }, + { label: 'Remove Member Tags', id: 'remove_member_tags' }, + // Merge fields operations + { label: 'Get Merge Fields', id: 'get_merge_fields' }, + { label: 'Get Merge Field', id: 'get_merge_field' }, + { label: 'Create Merge Field', id: 'create_merge_field' }, + { label: 'Update Merge Field', id: 'update_merge_field' }, + { label: 'Delete Merge Field', id: 'delete_merge_field' }, + // Interest categories operations + { label: 'Get Interest Categories', id: 'get_interest_categories' }, + { label: 'Get Interest Category', id: 'get_interest_category' }, + { label: 'Create Interest Category', id: 'create_interest_category' }, + { label: 'Update Interest Category', id: 'update_interest_category' }, + { label: 'Delete Interest Category', id: 'delete_interest_category' }, + // Interest operations + { label: 'Get Interests', id: 'get_interests' }, + { label: 'Get Interest', id: 'get_interest' }, + { label: 'Create Interest', id: 'create_interest' }, + { label: 'Update Interest', id: 'update_interest' }, + { label: 'Delete Interest', id: 'delete_interest' }, + // Landing page operations + { label: 'Get Landing Pages', id: 'get_landing_pages' }, + { label: 'Get Landing Page', id: 'get_landing_page' }, + { label: 'Create Landing Page', id: 'create_landing_page' }, + { label: 'Update Landing Page', id: 'update_landing_page' }, + { label: 'Delete Landing Page', id: 'delete_landing_page' }, + { label: 'Publish Landing Page', id: 'publish_landing_page' }, + { label: 'Unpublish Landing Page', id: 'unpublish_landing_page' }, + // Batch operations + { label: 'Get Batch Operations', id: 'get_batch_operations' }, + { label: 'Get Batch Operation', id: 'get_batch_operation' }, + { label: 'Create Batch Operation', id: 'create_batch_operation' }, + { label: 'Delete Batch Operation', id: 'delete_batch_operation' }, + ], + value: () => 'get_audiences', + }, + { + id: 'apiKey', + title: 'API Key', + type: 'short-input', + password: true, + placeholder: 'Enter your Mailchimp API key (includes server prefix)', + required: true, + }, + // Audience/List fields + { + id: 'listId', + title: 'Audience ID', + type: 'short-input', + placeholder: 'Audience/List ID', + required: { + field: 'operation', + value: [ + 'get_audience', + 'update_audience', + 'delete_audience', + 'get_members', + 'get_member', + 'add_member', + 'add_or_update_member', + 'update_member', + 'delete_member', + 'archive_member', + 'unarchive_member', + 'get_segments', + 'get_segment', + 'create_segment', + 'update_segment', + 'delete_segment', + 'get_segment_members', + 'add_segment_member', + 'remove_segment_member', + 'get_member_tags', + 'add_member_tags', + 'remove_member_tags', + 'get_merge_fields', + 'get_merge_field', + 'create_merge_field', + 'update_merge_field', + 'delete_merge_field', + 'get_interest_categories', + 'get_interest_category', + 'create_interest_category', + 'update_interest_category', + 'delete_interest_category', + 'get_interests', + 'get_interest', + 'create_interest', + 'update_interest', + 'delete_interest', + ], + }, + condition: { + field: 'operation', + value: [ + 'get_audience', + 'update_audience', + 'delete_audience', + 'get_members', + 'get_member', + 'add_member', + 'add_or_update_member', + 'update_member', + 'delete_member', + 'archive_member', + 'unarchive_member', + 'get_segments', + 'get_segment', + 'create_segment', + 'update_segment', + 'delete_segment', + 'get_segment_members', + 'add_segment_member', + 'remove_segment_member', + 'get_member_tags', + 'add_member_tags', + 'remove_member_tags', + 'get_merge_fields', + 'get_merge_field', + 'create_merge_field', + 'update_merge_field', + 'delete_merge_field', + 'get_interest_categories', + 'get_interest_category', + 'create_interest_category', + 'update_interest_category', + 'delete_interest_category', + 'get_interests', + 'get_interest', + 'create_interest', + 'update_interest', + 'delete_interest', + ], + }, + }, + { + id: 'audienceName', + title: 'Audience Name', + type: 'short-input', + placeholder: 'Name for the audience', + required: { + field: 'operation', + value: ['create_audience'], + }, + condition: { + field: 'operation', + value: ['create_audience', 'update_audience'], + }, + }, + { + id: 'contact', + title: 'Contact Information', + type: 'long-input', + placeholder: 'JSON object with company, address1, city, state, zip, country', + required: { + field: 'operation', + value: ['create_audience'], + }, + condition: { + field: 'operation', + value: ['create_audience', 'update_audience'], + }, + }, + { + id: 'permissionReminder', + title: 'Permission Reminder', + type: 'short-input', + placeholder: 'Permission reminder text', + required: { + field: 'operation', + value: ['create_audience'], + }, + condition: { + field: 'operation', + value: ['create_audience', 'update_audience'], + }, + }, + { + id: 'campaignDefaults', + title: 'Campaign Defaults', + type: 'long-input', + placeholder: 'JSON object with from_name, from_email, subject, language', + required: { + field: 'operation', + value: ['create_audience'], + }, + condition: { + field: 'operation', + value: ['create_audience', 'update_audience'], + }, + }, + { + id: 'emailTypeOption', + title: 'Email Type Option', + type: 'dropdown', + options: [ + { label: 'True', id: 'true' }, + { label: 'False', id: 'false' }, + ], + required: { + field: 'operation', + value: ['create_audience'], + }, + condition: { + field: 'operation', + value: ['create_audience', 'update_audience'], + }, + value: () => 'true', + }, + // Member fields + { + id: 'subscriberHash', + title: 'Subscriber Hash', + type: 'short-input', + placeholder: 'MD5 hash of lowercase email', + required: { + field: 'operation', + value: [ + 'get_member', + 'update_member', + 'delete_member', + 'archive_member', + 'unarchive_member', + 'get_member_tags', + 'add_member_tags', + 'remove_member_tags', + ], + }, + condition: { + field: 'operation', + value: [ + 'get_member', + 'update_member', + 'delete_member', + 'archive_member', + 'unarchive_member', + 'get_member_tags', + 'add_member_tags', + 'remove_member_tags', + ], + }, + }, + { + id: 'emailAddress', + title: 'Email Address', + type: 'short-input', + placeholder: 'Member email address', + required: { + field: 'operation', + value: ['add_member', 'add_or_update_member'], + }, + condition: { + field: 'operation', + value: ['add_member', 'add_or_update_member', 'update_member'], + }, + }, + { + id: 'status', + title: 'Status', + type: 'dropdown', + options: [ + { label: 'Subscribed', id: 'subscribed' }, + { label: 'Unsubscribed', id: 'unsubscribed' }, + { label: 'Cleaned', id: 'cleaned' }, + { label: 'Pending', id: 'pending' }, + { label: 'Transactional', id: 'transactional' }, + ], + required: { + field: 'operation', + value: ['add_member'], + }, + condition: { + field: 'operation', + value: ['get_members', 'add_member', 'update_member'], + }, + }, + { + id: 'statusIfNew', + title: 'Status If New', + type: 'dropdown', + options: [ + { label: 'Subscribed', id: 'subscribed' }, + { label: 'Unsubscribed', id: 'unsubscribed' }, + { label: 'Cleaned', id: 'cleaned' }, + { label: 'Pending', id: 'pending' }, + { label: 'Transactional', id: 'transactional' }, + ], + required: { + field: 'operation', + value: ['add_or_update_member'], + }, + condition: { + field: 'operation', + value: ['add_or_update_member'], + }, + }, + { + id: 'mergeFields', + title: 'Merge Fields', + type: 'long-input', + placeholder: 'JSON object with merge field values (e.g., {"FNAME": "John", "LNAME": "Doe"})', + condition: { + field: 'operation', + value: ['add_member', 'add_or_update_member', 'update_member'], + }, + }, + { + id: 'interests', + title: 'Interests', + type: 'long-input', + placeholder: 'JSON object with interest IDs and boolean values', + condition: { + field: 'operation', + value: ['add_member', 'add_or_update_member', 'update_member'], + }, + }, + { + id: 'tags', + title: 'Tags', + type: 'long-input', + placeholder: 'JSON array of tag objects with name and status', + required: { + field: 'operation', + value: ['add_member_tags', 'remove_member_tags'], + }, + condition: { + field: 'operation', + value: ['add_member_tags', 'remove_member_tags'], + }, + }, + // Campaign fields + { + id: 'campaignId', + title: 'Campaign ID', + type: 'short-input', + placeholder: 'Campaign ID', + required: { + field: 'operation', + value: [ + 'get_campaign', + 'update_campaign', + 'delete_campaign', + 'send_campaign', + 'schedule_campaign', + 'unschedule_campaign', + 'replicate_campaign', + 'get_campaign_content', + 'set_campaign_content', + 'get_campaign_report', + ], + }, + condition: { + field: 'operation', + value: [ + 'get_campaign', + 'update_campaign', + 'delete_campaign', + 'send_campaign', + 'schedule_campaign', + 'unschedule_campaign', + 'replicate_campaign', + 'get_campaign_content', + 'set_campaign_content', + 'get_campaign_report', + ], + }, + }, + { + id: 'campaignType', + title: 'Campaign Type', + type: 'dropdown', + options: [ + { label: 'Regular', id: 'regular' }, + { label: 'Plain Text', id: 'plaintext' }, + { label: 'A/B Split', id: 'absplit' }, + { label: 'RSS', id: 'rss' }, + { label: 'Variate', id: 'variate' }, + ], + required: { + field: 'operation', + value: ['create_campaign'], + }, + condition: { + field: 'operation', + value: ['get_campaigns', 'create_campaign'], + }, + }, + { + id: 'campaignSettings', + title: 'Campaign Settings', + type: 'long-input', + placeholder: 'JSON object with subject_line, from_name, reply_to, etc. (required for create)', + required: { + field: 'operation', + value: ['create_campaign'], + }, + condition: { + field: 'operation', + value: ['create_campaign', 'update_campaign'], + }, + }, + { + id: 'recipients', + title: 'Recipients', + type: 'long-input', + placeholder: 'JSON object with list_id and optional segment_opts', + condition: { + field: 'operation', + value: ['create_campaign', 'update_campaign'], + }, + }, + { + id: 'scheduleTime', + title: 'Schedule Time', + type: 'short-input', + placeholder: 'ISO 8601 date-time (e.g., 2024-12-31T10:00:00+00:00)', + required: { + field: 'operation', + value: ['schedule_campaign'], + }, + condition: { + field: 'operation', + value: ['schedule_campaign'], + }, + }, + { + id: 'html', + title: 'HTML Content', + type: 'long-input', + placeholder: 'HTML content for the campaign', + condition: { + field: 'operation', + value: ['set_campaign_content'], + }, + }, + { + id: 'plainText', + title: 'Plain Text Content', + type: 'long-input', + placeholder: 'Plain text content for the campaign', + condition: { + field: 'operation', + value: ['set_campaign_content'], + }, + }, + { + id: 'templateId', + title: 'Template ID', + type: 'short-input', + placeholder: 'Template ID', + required: { + field: 'operation', + value: ['get_template', 'update_template', 'delete_template'], + }, + condition: { + field: 'operation', + value: ['get_template', 'update_template', 'delete_template', 'set_campaign_content'], + }, + }, + { + id: 'templateName', + title: 'Template Name', + type: 'short-input', + placeholder: 'Template name', + required: { + field: 'operation', + value: ['create_template'], + }, + condition: { + field: 'operation', + value: ['create_template', 'update_template'], + }, + }, + { + id: 'templateHtml', + title: 'Template HTML', + type: 'long-input', + placeholder: 'HTML content for the template', + required: { + field: 'operation', + value: ['create_template'], + }, + condition: { + field: 'operation', + value: ['create_template', 'update_template'], + }, + }, + // Automation fields + { + id: 'workflowId', + title: 'Workflow ID', + type: 'short-input', + placeholder: 'Automation workflow ID', + required: { + field: 'operation', + value: [ + 'get_automation', + 'start_automation', + 'pause_automation', + 'add_subscriber_to_automation', + ], + }, + condition: { + field: 'operation', + value: [ + 'get_automation', + 'start_automation', + 'pause_automation', + 'add_subscriber_to_automation', + ], + }, + }, + { + id: 'workflowEmailId', + title: 'Workflow Email ID', + type: 'short-input', + placeholder: 'Workflow email ID', + required: { + field: 'operation', + value: ['add_subscriber_to_automation'], + }, + condition: { + field: 'operation', + value: ['add_subscriber_to_automation'], + }, + }, + // Segment fields + { + id: 'segmentId', + title: 'Segment ID', + type: 'short-input', + placeholder: 'Segment ID', + required: { + field: 'operation', + value: [ + 'get_segment', + 'update_segment', + 'delete_segment', + 'get_segment_members', + 'add_segment_member', + 'remove_segment_member', + ], + }, + condition: { + field: 'operation', + value: [ + 'get_segment', + 'update_segment', + 'delete_segment', + 'get_segment_members', + 'add_segment_member', + 'remove_segment_member', + ], + }, + }, + { + id: 'segmentName', + title: 'Segment Name', + type: 'short-input', + placeholder: 'Segment name', + required: { + field: 'operation', + value: ['create_segment'], + }, + condition: { + field: 'operation', + value: ['create_segment', 'update_segment'], + }, + }, + { + id: 'segmentOptions', + title: 'Segment Options', + type: 'long-input', + placeholder: 'JSON object with conditions for segment', + condition: { + field: 'operation', + value: ['create_segment', 'update_segment'], + }, + }, + // Merge field fields + { + id: 'mergeId', + title: 'Merge Field ID', + type: 'short-input', + placeholder: 'Merge field ID', + required: { + field: 'operation', + value: ['get_merge_field', 'update_merge_field', 'delete_merge_field'], + }, + condition: { + field: 'operation', + value: ['get_merge_field', 'update_merge_field', 'delete_merge_field'], + }, + }, + { + id: 'mergeName', + title: 'Merge Field Name', + type: 'short-input', + placeholder: 'Merge field name', + required: { + field: 'operation', + value: ['create_merge_field'], + }, + condition: { + field: 'operation', + value: ['create_merge_field', 'update_merge_field'], + }, + }, + { + id: 'mergeType', + title: 'Merge Field Type', + type: 'dropdown', + options: [ + { label: 'Text', id: 'text' }, + { label: 'Number', id: 'number' }, + { label: 'Address', id: 'address' }, + { label: 'Phone', id: 'phone' }, + { label: 'Date', id: 'date' }, + { label: 'URL', id: 'url' }, + { label: 'Image URL', id: 'imageurl' }, + { label: 'Radio', id: 'radio' }, + { label: 'Dropdown', id: 'dropdown' }, + { label: 'Birthday', id: 'birthday' }, + { label: 'Zip', id: 'zip' }, + ], + required: { + field: 'operation', + value: ['create_merge_field'], + }, + condition: { + field: 'operation', + value: ['create_merge_field'], + }, + }, + // Interest category fields + { + id: 'interestCategoryId', + title: 'Interest Category ID', + type: 'short-input', + placeholder: 'Interest category ID', + required: { + field: 'operation', + value: [ + 'get_interest_category', + 'update_interest_category', + 'delete_interest_category', + 'get_interests', + 'get_interest', + 'create_interest', + 'update_interest', + 'delete_interest', + ], + }, + condition: { + field: 'operation', + value: [ + 'get_interest_category', + 'update_interest_category', + 'delete_interest_category', + 'get_interests', + 'get_interest', + 'create_interest', + 'update_interest', + 'delete_interest', + ], + }, + }, + { + id: 'interestCategoryTitle', + title: 'Interest Category Title', + type: 'short-input', + placeholder: 'Interest category title', + required: { + field: 'operation', + value: ['create_interest_category'], + }, + condition: { + field: 'operation', + value: ['create_interest_category', 'update_interest_category'], + }, + }, + { + id: 'interestCategoryType', + title: 'Interest Category Type', + type: 'dropdown', + options: [ + { label: 'Checkboxes', id: 'checkboxes' }, + { label: 'Dropdown', id: 'dropdown' }, + { label: 'Radio', id: 'radio' }, + { label: 'Hidden', id: 'hidden' }, + ], + required: { + field: 'operation', + value: ['create_interest_category'], + }, + condition: { + field: 'operation', + value: ['create_interest_category'], + }, + }, + // Interest fields + { + id: 'interestId', + title: 'Interest ID', + type: 'short-input', + placeholder: 'Interest ID', + required: { + field: 'operation', + value: ['get_interest', 'update_interest', 'delete_interest'], + }, + condition: { + field: 'operation', + value: ['get_interest', 'update_interest', 'delete_interest'], + }, + }, + { + id: 'interestName', + title: 'Interest Name', + type: 'short-input', + placeholder: 'Interest name', + required: { + field: 'operation', + value: ['create_interest'], + }, + condition: { + field: 'operation', + value: ['create_interest', 'update_interest'], + }, + }, + // Landing page fields + { + id: 'pageId', + title: 'Landing Page ID', + type: 'short-input', + placeholder: 'Landing page ID', + required: { + field: 'operation', + value: [ + 'get_landing_page', + 'update_landing_page', + 'delete_landing_page', + 'publish_landing_page', + 'unpublish_landing_page', + ], + }, + condition: { + field: 'operation', + value: [ + 'get_landing_page', + 'update_landing_page', + 'delete_landing_page', + 'publish_landing_page', + 'unpublish_landing_page', + ], + }, + }, + { + id: 'landingPageTitle', + title: 'Landing Page Title', + type: 'short-input', + placeholder: 'Landing page title', + condition: { + field: 'operation', + value: ['create_landing_page', 'update_landing_page'], + }, + }, + { + id: 'landingPageType', + title: 'Landing Page Type', + type: 'dropdown', + options: [ + { label: 'Signup', id: 'signup' }, + { label: 'Click Through', id: 'click-through' }, + ], + required: { + field: 'operation', + value: ['create_landing_page'], + }, + condition: { + field: 'operation', + value: ['create_landing_page'], + }, + }, + // Batch operation fields + { + id: 'batchId', + title: 'Batch ID', + type: 'short-input', + placeholder: 'Batch operation ID', + required: { + field: 'operation', + value: ['get_batch_operation', 'delete_batch_operation'], + }, + condition: { + field: 'operation', + value: ['get_batch_operation', 'delete_batch_operation'], + }, + }, + { + id: 'operations', + title: 'Operations', + type: 'long-input', + placeholder: 'JSON array of operations with method, path, body, etc.', + required: { + field: 'operation', + value: ['create_batch_operation'], + }, + condition: { + field: 'operation', + value: ['create_batch_operation'], + }, + }, + // Pagination and filtering + { + id: 'count', + title: 'Count', + type: 'short-input', + placeholder: 'Number of results (default: 10, max: 1000)', + condition: { + field: 'operation', + value: [ + 'get_audiences', + 'get_members', + 'get_campaigns', + 'get_automations', + 'get_templates', + 'get_campaign_reports', + 'get_segments', + 'get_segment_members', + 'get_merge_fields', + 'get_interest_categories', + 'get_interests', + 'get_landing_pages', + 'get_batch_operations', + ], + }, + }, + { + id: 'offset', + title: 'Offset', + type: 'short-input', + placeholder: 'Number of results to skip', + condition: { + field: 'operation', + value: [ + 'get_audiences', + 'get_members', + 'get_campaigns', + 'get_automations', + 'get_templates', + 'get_campaign_reports', + 'get_segments', + 'get_segment_members', + 'get_merge_fields', + 'get_interest_categories', + 'get_interests', + 'get_landing_pages', + 'get_batch_operations', + ], + }, + }, + ], + tools: { + access: [ + 'mailchimp_get_audiences', + 'mailchimp_get_audience', + 'mailchimp_create_audience', + 'mailchimp_update_audience', + 'mailchimp_delete_audience', + 'mailchimp_get_members', + 'mailchimp_get_member', + 'mailchimp_add_member', + 'mailchimp_add_or_update_member', + 'mailchimp_update_member', + 'mailchimp_delete_member', + 'mailchimp_archive_member', + 'mailchimp_unarchive_member', + 'mailchimp_get_campaigns', + 'mailchimp_get_campaign', + 'mailchimp_create_campaign', + 'mailchimp_update_campaign', + 'mailchimp_delete_campaign', + 'mailchimp_send_campaign', + 'mailchimp_schedule_campaign', + 'mailchimp_unschedule_campaign', + 'mailchimp_replicate_campaign', + 'mailchimp_get_campaign_content', + 'mailchimp_set_campaign_content', + 'mailchimp_get_automations', + 'mailchimp_get_automation', + 'mailchimp_start_automation', + 'mailchimp_pause_automation', + 'mailchimp_add_subscriber_to_automation', + 'mailchimp_get_templates', + 'mailchimp_get_template', + 'mailchimp_create_template', + 'mailchimp_update_template', + 'mailchimp_delete_template', + 'mailchimp_get_campaign_reports', + 'mailchimp_get_campaign_report', + 'mailchimp_get_segments', + 'mailchimp_get_segment', + 'mailchimp_create_segment', + 'mailchimp_update_segment', + 'mailchimp_delete_segment', + 'mailchimp_get_segment_members', + 'mailchimp_add_segment_member', + 'mailchimp_remove_segment_member', + 'mailchimp_get_member_tags', + 'mailchimp_add_member_tags', + 'mailchimp_remove_member_tags', + 'mailchimp_get_merge_fields', + 'mailchimp_get_merge_field', + 'mailchimp_create_merge_field', + 'mailchimp_update_merge_field', + 'mailchimp_delete_merge_field', + 'mailchimp_get_interest_categories', + 'mailchimp_get_interest_category', + 'mailchimp_create_interest_category', + 'mailchimp_update_interest_category', + 'mailchimp_delete_interest_category', + 'mailchimp_get_interests', + 'mailchimp_get_interest', + 'mailchimp_create_interest', + 'mailchimp_update_interest', + 'mailchimp_delete_interest', + 'mailchimp_get_landing_pages', + 'mailchimp_get_landing_page', + 'mailchimp_create_landing_page', + 'mailchimp_update_landing_page', + 'mailchimp_delete_landing_page', + 'mailchimp_publish_landing_page', + 'mailchimp_unpublish_landing_page', + 'mailchimp_get_batch_operations', + 'mailchimp_get_batch_operation', + 'mailchimp_create_batch_operation', + 'mailchimp_delete_batch_operation', + ], + config: { + tool: (params) => { + return `mailchimp_${params.operation}` + }, + params: (params) => { + const { apiKey, operation, ...rest } = params + const cleanParams: Record = { apiKey } + + Object.entries(rest).forEach(([key, value]) => { + if (value !== undefined && value !== null && value !== '') { + cleanParams[key] = value + } + }) + return cleanParams + }, + }, + }, + inputs: { + operation: { type: 'string', description: 'Operation to perform' }, + apiKey: { type: 'string', description: 'Mailchimp API key with server prefix' }, + }, + outputs: { + success: { type: 'boolean', description: 'Operation success status' }, + output: { type: 'json', description: 'Operation result data' }, + }, +} diff --git a/apps/sim/blocks/blocks/pylon.ts b/apps/sim/blocks/blocks/pylon.ts new file mode 100644 index 0000000000..d6418ff3be --- /dev/null +++ b/apps/sim/blocks/blocks/pylon.ts @@ -0,0 +1,838 @@ +import { PylonIcon } from '@/components/icons' +import type { BlockConfig } from '@/blocks/types' +import { AuthMode } from '@/blocks/types' + +export const PylonBlock: BlockConfig = { + type: 'pylon', + name: 'Pylon', + description: + 'Manage customer support issues, accounts, contacts, users, teams, and tags in Pylon', + longDescription: + 'Integrate Pylon into the workflow. Manage issues (list, create, get, update, delete, search, snooze, followers, external issues), accounts (list, create, get, update, delete, bulk update, search), contacts (list, create, get, update, delete, search), users (list, get, update, search), teams (list, get, create, update), tags (list, get, create, update, delete), and messages (redact).', + docsLink: 'https://docs.usepylon.com/pylon-docs/developer/api', + authMode: AuthMode.ApiKey, + category: 'tools', + bgColor: '#E8F4FA', + icon: PylonIcon, + subBlocks: [ + { + id: 'operation', + title: 'Operation', + type: 'dropdown', + options: [ + // Issue operations + { label: 'List Issues', id: 'list_issues' }, + { label: 'Create Issue', id: 'create_issue' }, + { label: 'Get Issue', id: 'get_issue' }, + { label: 'Update Issue', id: 'update_issue' }, + { label: 'Delete Issue', id: 'delete_issue' }, + { label: 'Search Issues', id: 'search_issues' }, + { label: 'Snooze Issue', id: 'snooze_issue' }, + { label: 'List Issue Followers', id: 'list_issue_followers' }, + { label: 'Manage Issue Followers', id: 'manage_issue_followers' }, + { label: 'Link External Issue', id: 'link_external_issue' }, + // Account operations + { label: 'List Accounts', id: 'list_accounts' }, + { label: 'Create Account', id: 'create_account' }, + { label: 'Get Account', id: 'get_account' }, + { label: 'Update Account', id: 'update_account' }, + { label: 'Delete Account', id: 'delete_account' }, + { label: 'Bulk Update Accounts', id: 'bulk_update_accounts' }, + { label: 'Search Accounts', id: 'search_accounts' }, + // Contact operations + { label: 'List Contacts', id: 'list_contacts' }, + { label: 'Create Contact', id: 'create_contact' }, + { label: 'Get Contact', id: 'get_contact' }, + { label: 'Update Contact', id: 'update_contact' }, + { label: 'Delete Contact', id: 'delete_contact' }, + { label: 'Search Contacts', id: 'search_contacts' }, + // User operations + { label: 'List Users', id: 'list_users' }, + { label: 'Get User', id: 'get_user' }, + { label: 'Update User', id: 'update_user' }, + { label: 'Search Users', id: 'search_users' }, + // Team operations + { label: 'List Teams', id: 'list_teams' }, + { label: 'Get Team', id: 'get_team' }, + { label: 'Create Team', id: 'create_team' }, + { label: 'Update Team', id: 'update_team' }, + // Tag operations + { label: 'List Tags', id: 'list_tags' }, + { label: 'Get Tag', id: 'get_tag' }, + { label: 'Create Tag', id: 'create_tag' }, + { label: 'Update Tag', id: 'update_tag' }, + { label: 'Delete Tag', id: 'delete_tag' }, + // Message operations + { label: 'Redact Message', id: 'redact_message' }, + ], + value: () => 'list_issues', + }, + { + id: 'apiToken', + title: 'API Token', + type: 'short-input', + password: true, + placeholder: 'Enter your Pylon API token', + required: true, + }, + // Issue fields + { + id: 'startTime', + title: 'Start Time', + type: 'short-input', + placeholder: 'RFC3339 format (e.g., 2024-01-01T00:00:00Z)', + required: true, + condition: { + field: 'operation', + value: ['list_issues'], + }, + }, + { + id: 'endTime', + title: 'End Time', + type: 'short-input', + placeholder: 'RFC3339 format (e.g., 2024-01-31T23:59:59Z)', + required: true, + condition: { + field: 'operation', + value: ['list_issues'], + }, + }, + { + id: 'issueId', + title: 'Issue ID', + type: 'short-input', + placeholder: 'Issue ID', + required: true, + condition: { + field: 'operation', + value: [ + 'get_issue', + 'update_issue', + 'delete_issue', + 'snooze_issue', + 'list_issue_followers', + 'manage_issue_followers', + 'link_external_issue', + 'redact_message', + ], + }, + }, + { + id: 'title', + title: 'Title', + type: 'short-input', + placeholder: 'Issue title', + required: { + field: 'operation', + value: ['create_issue'], + }, + condition: { + field: 'operation', + value: ['create_issue'], + }, + }, + { + id: 'bodyHtml', + title: 'Body HTML', + type: 'long-input', + placeholder: 'Issue body in HTML format', + required: true, + condition: { + field: 'operation', + value: ['create_issue'], + }, + }, + { + id: 'accountId', + title: 'Account ID', + type: 'short-input', + placeholder: 'Account ID', + condition: { + field: 'operation', + value: ['create_issue', 'update_issue', 'create_contact', 'update_contact'], + }, + }, + { + id: 'assigneeId', + title: 'Assignee ID', + type: 'short-input', + placeholder: 'User ID to assign to', + condition: { + field: 'operation', + value: ['create_issue', 'update_issue'], + }, + }, + { + id: 'teamId', + title: 'Team ID', + type: 'short-input', + placeholder: 'Team ID', + required: { + field: 'operation', + value: ['get_team', 'update_team'], + }, + condition: { + field: 'operation', + value: ['create_issue', 'update_issue', 'get_team', 'update_team'], + }, + }, + { + id: 'requesterId', + title: 'Requester ID', + type: 'short-input', + placeholder: 'Requester user ID', + condition: { + field: 'operation', + value: ['create_issue', 'update_issue'], + }, + }, + { + id: 'requesterEmail', + title: 'Requester Email', + type: 'short-input', + placeholder: 'Requester email address', + condition: { + field: 'operation', + value: ['create_issue'], + }, + }, + { + id: 'priority', + title: 'Priority', + type: 'short-input', + placeholder: 'Issue priority', + condition: { + field: 'operation', + value: ['create_issue', 'update_issue'], + }, + }, + { + id: 'state', + title: 'State', + type: 'short-input', + placeholder: 'Issue state', + condition: { + field: 'operation', + value: ['update_issue'], + }, + }, + { + id: 'tags', + title: 'Tags', + type: 'short-input', + placeholder: 'Comma-separated tag IDs', + condition: { + field: 'operation', + value: [ + 'create_issue', + 'update_issue', + 'create_account', + 'update_account', + 'bulk_update_accounts', + ], + }, + }, + { + id: 'customFields', + title: 'Custom Fields', + type: 'long-input', + placeholder: 'JSON object with custom fields', + condition: { + field: 'operation', + value: [ + 'create_issue', + 'update_issue', + 'create_account', + 'update_account', + 'bulk_update_accounts', + 'create_contact', + 'update_contact', + ], + }, + }, + { + id: 'attachmentUrls', + title: 'Attachment URLs', + type: 'short-input', + placeholder: 'Comma-separated attachment URLs', + condition: { + field: 'operation', + value: ['create_issue'], + }, + }, + { + id: 'customerPortalVisible', + title: 'Customer Portal Visible', + type: 'short-input', + placeholder: 'true or false', + condition: { + field: 'operation', + value: ['update_issue'], + }, + }, + { + id: 'snoozeUntil', + title: 'Snooze Until', + type: 'short-input', + placeholder: 'RFC3339 timestamp', + required: true, + condition: { + field: 'operation', + value: ['snooze_issue'], + }, + }, + { + id: 'userIds', + title: 'User IDs', + type: 'short-input', + placeholder: 'Comma-separated user IDs', + condition: { + field: 'operation', + value: ['manage_issue_followers', 'create_team', 'update_team'], + }, + }, + { + id: 'contactIds', + title: 'Contact IDs', + type: 'short-input', + placeholder: 'Comma-separated contact IDs', + condition: { + field: 'operation', + value: ['manage_issue_followers'], + }, + }, + { + id: 'followerOperation', + title: 'Follower Operation', + type: 'dropdown', + options: [ + { label: 'Add', id: 'add' }, + { label: 'Remove', id: 'remove' }, + ], + condition: { + field: 'operation', + value: ['manage_issue_followers'], + }, + }, + { + id: 'externalIssueId', + title: 'External Issue ID', + type: 'short-input', + placeholder: 'External issue identifier', + required: true, + condition: { + field: 'operation', + value: ['link_external_issue'], + }, + }, + { + id: 'source', + title: 'Source', + type: 'short-input', + placeholder: 'Source system (e.g., linear, jira)', + required: true, + condition: { + field: 'operation', + value: ['link_external_issue'], + }, + }, + // Account fields + { + id: 'name', + title: 'Name', + type: 'short-input', + placeholder: 'Name', + required: { + field: 'operation', + value: ['create_account', 'create_contact'], + }, + condition: { + field: 'operation', + value: [ + 'create_account', + 'update_account', + 'create_contact', + 'update_contact', + 'create_team', + 'update_team', + ], + }, + }, + { + id: 'accountIdField', + title: 'Account ID', + type: 'short-input', + placeholder: 'Account ID', + required: true, + condition: { + field: 'operation', + value: ['get_account', 'update_account', 'delete_account'], + }, + }, + { + id: 'accountIds', + title: 'Account IDs', + type: 'short-input', + placeholder: 'Comma-separated account IDs', + required: true, + condition: { + field: 'operation', + value: ['bulk_update_accounts'], + }, + }, + { + id: 'domains', + title: 'Domains', + type: 'short-input', + placeholder: 'Comma-separated domain names', + condition: { + field: 'operation', + value: ['create_account', 'update_account'], + }, + }, + { + id: 'primaryDomain', + title: 'Primary Domain', + type: 'short-input', + placeholder: 'Primary domain name', + condition: { + field: 'operation', + value: ['create_account', 'update_account'], + }, + }, + { + id: 'channels', + title: 'Channels', + type: 'short-input', + placeholder: 'Channels', + condition: { + field: 'operation', + value: ['create_account', 'update_account'], + }, + }, + { + id: 'externalIds', + title: 'External IDs', + type: 'short-input', + placeholder: 'External IDs', + condition: { + field: 'operation', + value: ['create_account', 'update_account'], + }, + }, + { + id: 'ownerId', + title: 'Owner ID', + type: 'short-input', + placeholder: 'Owner user ID', + condition: { + field: 'operation', + value: ['create_account', 'update_account', 'bulk_update_accounts'], + }, + }, + { + id: 'logoUrl', + title: 'Logo URL', + type: 'short-input', + placeholder: 'Account logo URL', + condition: { + field: 'operation', + value: ['create_account', 'update_account'], + }, + }, + { + id: 'subaccountIds', + title: 'Subaccount IDs', + type: 'short-input', + placeholder: 'Comma-separated subaccount IDs', + condition: { + field: 'operation', + value: ['create_account', 'update_account'], + }, + }, + { + id: 'tagsApplyMode', + title: 'Tags Apply Mode', + type: 'dropdown', + options: [ + { label: 'Append Only', id: 'append_only' }, + { label: 'Remove Only', id: 'remove_only' }, + { label: 'Replace', id: 'replace' }, + ], + condition: { + field: 'operation', + value: ['bulk_update_accounts'], + }, + }, + // Contact fields + { + id: 'contactId', + title: 'Contact ID', + type: 'short-input', + placeholder: 'Contact ID', + required: true, + condition: { + field: 'operation', + value: ['get_contact', 'update_contact', 'delete_contact'], + }, + }, + { + id: 'email', + title: 'Email', + type: 'short-input', + placeholder: 'Email address', + condition: { + field: 'operation', + value: ['create_contact', 'update_contact'], + }, + }, + { + id: 'accountExternalId', + title: 'Account External ID', + type: 'short-input', + placeholder: 'External account ID', + condition: { + field: 'operation', + value: ['create_contact', 'update_contact'], + }, + }, + { + id: 'avatarUrl', + title: 'Avatar URL', + type: 'short-input', + placeholder: 'Square PNG/JPG image URL', + condition: { + field: 'operation', + value: ['create_contact', 'update_contact'], + }, + }, + { + id: 'portalRole', + title: 'Portal Role', + type: 'dropdown', + options: [ + { label: 'No Access', id: 'no_access' }, + { label: 'Member', id: 'member' }, + { label: 'Admin', id: 'admin' }, + ], + condition: { + field: 'operation', + value: ['create_contact', 'update_contact'], + }, + }, + // User fields + { + id: 'userId', + title: 'User ID', + type: 'short-input', + placeholder: 'User ID', + required: true, + condition: { + field: 'operation', + value: ['get_user', 'update_user'], + }, + }, + { + id: 'roleId', + title: 'Role ID', + type: 'short-input', + placeholder: 'Role ID', + condition: { + field: 'operation', + value: ['update_user'], + }, + }, + { + id: 'status', + title: 'Status', + type: 'dropdown', + options: [ + { label: 'Active', id: 'active' }, + { label: 'Away', id: 'away' }, + { label: 'Out of Office', id: 'out_of_office' }, + ], + condition: { + field: 'operation', + value: ['update_user'], + }, + }, + // Tag fields + { + id: 'tagId', + title: 'Tag ID', + type: 'short-input', + placeholder: 'Tag ID', + required: true, + condition: { + field: 'operation', + value: ['get_tag', 'update_tag', 'delete_tag'], + }, + }, + { + id: 'objectType', + title: 'Object Type', + type: 'dropdown', + options: [ + { label: 'Account', id: 'account' }, + { label: 'Issue', id: 'issue' }, + { label: 'Contact', id: 'contact' }, + ], + required: true, + condition: { + field: 'operation', + value: ['create_tag'], + }, + }, + { + id: 'value', + title: 'Value', + type: 'short-input', + placeholder: 'Tag value/name', + required: { + field: 'operation', + value: ['create_tag'], + }, + condition: { + field: 'operation', + value: ['create_tag', 'update_tag'], + }, + }, + { + id: 'hexColor', + title: 'Hex Color', + type: 'short-input', + placeholder: 'Hex color code (e.g., #3a89ce)', + condition: { + field: 'operation', + value: ['create_tag', 'update_tag'], + }, + }, + // Message fields + { + id: 'messageId', + title: 'Message ID', + type: 'short-input', + placeholder: 'Message ID', + required: true, + condition: { + field: 'operation', + value: ['redact_message'], + }, + }, + // Search and pagination fields + { + id: 'filter', + title: 'Filter', + type: 'long-input', + placeholder: 'JSON filter object', + required: { + field: 'operation', + value: ['search_accounts', 'search_contacts', 'search_users'], + }, + condition: { + field: 'operation', + value: ['search_issues', 'search_accounts', 'search_contacts', 'search_users'], + }, + }, + { + id: 'limit', + title: 'Limit', + type: 'short-input', + placeholder: 'Results per page (1-1000, default: 100)', + condition: { + field: 'operation', + value: [ + 'list_accounts', + 'list_contacts', + 'get_contact', + 'search_issues', + 'search_accounts', + 'search_contacts', + 'search_users', + ], + }, + }, + { + id: 'cursor', + title: 'Cursor', + type: 'short-input', + placeholder: 'Pagination cursor', + condition: { + field: 'operation', + value: [ + 'list_issues', + 'list_accounts', + 'list_contacts', + 'get_contact', + 'search_issues', + 'search_accounts', + 'search_contacts', + 'search_users', + ], + }, + }, + ], + tools: { + access: [ + 'pylon_list_issues', + 'pylon_create_issue', + 'pylon_get_issue', + 'pylon_update_issue', + 'pylon_delete_issue', + 'pylon_search_issues', + 'pylon_snooze_issue', + 'pylon_list_issue_followers', + 'pylon_manage_issue_followers', + 'pylon_link_external_issue', + 'pylon_list_accounts', + 'pylon_create_account', + 'pylon_get_account', + 'pylon_update_account', + 'pylon_delete_account', + 'pylon_bulk_update_accounts', + 'pylon_search_accounts', + 'pylon_list_contacts', + 'pylon_create_contact', + 'pylon_get_contact', + 'pylon_update_contact', + 'pylon_delete_contact', + 'pylon_search_contacts', + 'pylon_list_users', + 'pylon_get_user', + 'pylon_update_user', + 'pylon_search_users', + 'pylon_list_teams', + 'pylon_get_team', + 'pylon_create_team', + 'pylon_update_team', + 'pylon_list_tags', + 'pylon_get_tag', + 'pylon_create_tag', + 'pylon_update_tag', + 'pylon_delete_tag', + 'pylon_redact_message', + ], + config: { + tool: (params) => { + switch (params.operation) { + // Issue operations + case 'list_issues': + return 'pylon_list_issues' + case 'create_issue': + return 'pylon_create_issue' + case 'get_issue': + return 'pylon_get_issue' + case 'update_issue': + return 'pylon_update_issue' + case 'delete_issue': + return 'pylon_delete_issue' + case 'search_issues': + return 'pylon_search_issues' + case 'snooze_issue': + return 'pylon_snooze_issue' + case 'list_issue_followers': + return 'pylon_list_issue_followers' + case 'manage_issue_followers': + return 'pylon_manage_issue_followers' + case 'link_external_issue': + return 'pylon_link_external_issue' + // Account operations + case 'list_accounts': + return 'pylon_list_accounts' + case 'create_account': + return 'pylon_create_account' + case 'get_account': + return 'pylon_get_account' + case 'update_account': + return 'pylon_update_account' + case 'delete_account': + return 'pylon_delete_account' + case 'bulk_update_accounts': + return 'pylon_bulk_update_accounts' + case 'search_accounts': + return 'pylon_search_accounts' + // Contact operations + case 'list_contacts': + return 'pylon_list_contacts' + case 'create_contact': + return 'pylon_create_contact' + case 'get_contact': + return 'pylon_get_contact' + case 'update_contact': + return 'pylon_update_contact' + case 'delete_contact': + return 'pylon_delete_contact' + case 'search_contacts': + return 'pylon_search_contacts' + // User operations + case 'list_users': + return 'pylon_list_users' + case 'get_user': + return 'pylon_get_user' + case 'update_user': + return 'pylon_update_user' + case 'search_users': + return 'pylon_search_users' + // Team operations + case 'list_teams': + return 'pylon_list_teams' + case 'get_team': + return 'pylon_get_team' + case 'create_team': + return 'pylon_create_team' + case 'update_team': + return 'pylon_update_team' + // Tag operations + case 'list_tags': + return 'pylon_list_tags' + case 'get_tag': + return 'pylon_get_tag' + case 'create_tag': + return 'pylon_create_tag' + case 'update_tag': + return 'pylon_update_tag' + case 'delete_tag': + return 'pylon_delete_tag' + // Message operations + case 'redact_message': + return 'pylon_redact_message' + default: + throw new Error(`Unknown operation: ${params.operation}`) + } + }, + params: (params) => { + const { apiToken, operation, ...rest } = params + const cleanParams: Record = { apiToken } + + // Handle parameter mapping + if (params.accountIdField) { + cleanParams.accountId = params.accountIdField + } + if (params.followerOperation) { + cleanParams.operation = params.followerOperation + } + + Object.entries(rest).forEach(([key, value]) => { + if (value !== undefined && value !== null && value !== '') { + // Skip mapped fields + if (key === 'accountIdField' || key === 'followerOperation') { + return + } + cleanParams[key] = value + } + }) + + return cleanParams + }, + }, + }, + inputs: { + operation: { type: 'string', description: 'Operation to perform' }, + apiToken: { type: 'string', description: 'Pylon API token' }, + }, + outputs: { + success: { type: 'boolean', description: 'Operation success status' }, + output: { type: 'json', description: 'Operation result data' }, + }, +} diff --git a/apps/sim/blocks/blocks/zendesk.ts b/apps/sim/blocks/blocks/zendesk.ts new file mode 100644 index 0000000000..ca727422b0 --- /dev/null +++ b/apps/sim/blocks/blocks/zendesk.ts @@ -0,0 +1,497 @@ +import { ZendeskIcon } from '@/components/icons' +import type { BlockConfig } from '@/blocks/types' +import { AuthMode } from '@/blocks/types' + +export const ZendeskBlock: BlockConfig = { + type: 'zendesk', + name: 'Zendesk', + description: 'Manage support tickets, users, and organizations in Zendesk', + longDescription: + 'Integrate Zendesk into the workflow. Can get tickets, get ticket, create ticket, create tickets bulk, update ticket, update tickets bulk, delete ticket, merge tickets, get users, get user, get current user, search users, create user, create users bulk, update user, update users bulk, delete user, get organizations, get organization, autocomplete organizations, create organization, create organizations bulk, update organization, delete organization, search, search count, export search.', + docsLink: 'https://docs.sim.ai/tools/zendesk', + authMode: AuthMode.ApiKey, + category: 'tools', + bgColor: '#E0E0E0', + icon: ZendeskIcon, + subBlocks: [ + { + id: 'operation', + title: 'Operation', + type: 'dropdown', + options: [ + { label: 'Get Tickets', id: 'get_tickets' }, + { label: 'Get Ticket', id: 'get_ticket' }, + { label: 'Create Ticket', id: 'create_ticket' }, + { label: 'Create Tickets Bulk', id: 'create_tickets_bulk' }, + { label: 'Update Ticket', id: 'update_ticket' }, + { label: 'Update Tickets Bulk', id: 'update_tickets_bulk' }, + { label: 'Delete Ticket', id: 'delete_ticket' }, + { label: 'Merge Tickets', id: 'merge_tickets' }, + { label: 'Get Users', id: 'get_users' }, + { label: 'Get User', id: 'get_user' }, + { label: 'Get Current User', id: 'get_current_user' }, + { label: 'Search Users', id: 'search_users' }, + { label: 'Create User', id: 'create_user' }, + { label: 'Create Users Bulk', id: 'create_users_bulk' }, + { label: 'Update User', id: 'update_user' }, + { label: 'Update Users Bulk', id: 'update_users_bulk' }, + { label: 'Delete User', id: 'delete_user' }, + { label: 'Get Organizations', id: 'get_organizations' }, + { label: 'Get Organization', id: 'get_organization' }, + { label: 'Autocomplete Organizations', id: 'autocomplete_organizations' }, + { label: 'Create Organization', id: 'create_organization' }, + { label: 'Create Organizations Bulk', id: 'create_organizations_bulk' }, + { label: 'Update Organization', id: 'update_organization' }, + { label: 'Delete Organization', id: 'delete_organization' }, + { label: 'Search', id: 'search' }, + { label: 'Search Count', id: 'search_count' }, + { label: 'Export Search', id: 'export_search' }, + ], + value: () => 'get_tickets', + }, + { + id: 'apiToken', + title: 'API Token', + type: 'short-input', + password: true, + placeholder: 'Enter your Zendesk API token', + required: true, + }, + { + id: 'subdomain', + title: 'Subdomain', + type: 'short-input', + placeholder: 'Your Zendesk subdomain (e.g., "mycompany")', + required: true, + description: 'The subdomain from your Zendesk URL (mycompany.zendesk.com)', + }, + // Ticket fields + { + id: 'ticketId', + title: 'Ticket ID', + type: 'short-input', + placeholder: 'Ticket ID', + required: true, + condition: { + field: 'operation', + value: ['get_ticket', 'update_ticket', 'delete_ticket'], + }, + }, + { + id: 'subject', + title: 'Subject', + type: 'short-input', + placeholder: 'Ticket subject', + condition: { + field: 'operation', + value: ['create_ticket', 'update_ticket'], + }, + }, + { + id: 'description', + title: 'Description', + type: 'long-input', + placeholder: 'Ticket description', + condition: { + field: 'operation', + value: ['create_ticket', 'update_ticket'], + }, + }, + { + id: 'status', + title: 'Status', + type: 'short-input', + placeholder: 'Status (new, open, pending, hold, solved, closed)', + condition: { + field: 'operation', + value: ['get_tickets', 'create_ticket', 'update_ticket'], + }, + }, + { + id: 'priority', + title: 'Priority', + type: 'short-input', + placeholder: 'Priority (low, normal, high, urgent)', + condition: { + field: 'operation', + value: ['get_tickets', 'create_ticket', 'update_ticket'], + }, + }, + { + id: 'type', + title: 'Type', + type: 'short-input', + placeholder: 'Type (problem, incident, question, task)', + condition: { + field: 'operation', + value: ['get_tickets', 'create_ticket', 'update_ticket'], + }, + }, + { + id: 'tags', + title: 'Tags', + type: 'short-input', + placeholder: 'Comma-separated tags', + condition: { + field: 'operation', + value: ['create_ticket', 'update_ticket'], + }, + }, + { + id: 'assigneeId', + title: 'Assignee ID', + type: 'short-input', + placeholder: 'User ID to assign ticket to', + condition: { + field: 'operation', + value: ['get_tickets', 'create_ticket', 'update_ticket'], + }, + }, + { + id: 'groupId', + title: 'Group ID', + type: 'short-input', + placeholder: 'Group ID', + condition: { + field: 'operation', + value: ['create_ticket', 'update_ticket'], + }, + }, + { + id: 'customFields', + title: 'Custom Fields', + type: 'long-input', + placeholder: 'JSON object with custom fields', + condition: { + field: 'operation', + value: ['create_ticket', 'update_ticket'], + }, + }, + { + id: 'tickets', + title: 'Tickets', + type: 'long-input', + placeholder: 'JSON array of ticket objects', + required: true, + condition: { + field: 'operation', + value: ['create_tickets_bulk', 'update_tickets_bulk'], + }, + }, + { + id: 'targetTicketId', + title: 'Target Ticket ID', + type: 'short-input', + placeholder: 'Ticket ID to merge into', + required: true, + condition: { + field: 'operation', + value: ['merge_tickets'], + }, + }, + { + id: 'sourceTicketIds', + title: 'Source Ticket IDs', + type: 'short-input', + placeholder: 'Comma-separated ticket IDs to merge', + required: true, + condition: { + field: 'operation', + value: ['merge_tickets'], + }, + }, + // User fields + { + id: 'userId', + title: 'User ID', + type: 'short-input', + placeholder: 'User ID', + required: true, + condition: { + field: 'operation', + value: ['get_user', 'update_user', 'delete_user'], + }, + }, + { + id: 'userName', + title: 'Name', + type: 'short-input', + placeholder: 'User name', + condition: { + field: 'operation', + value: ['create_user', 'update_user'], + }, + }, + { + id: 'userEmail', + title: 'Email', + type: 'short-input', + placeholder: 'User email', + condition: { + field: 'operation', + value: ['create_user', 'update_user'], + }, + }, + { + id: 'users', + title: 'Users', + type: 'long-input', + placeholder: 'JSON array of user objects', + required: true, + condition: { + field: 'operation', + value: ['create_users_bulk', 'update_users_bulk'], + }, + }, + // Organization fields + { + id: 'organizationId', + title: 'Organization ID', + type: 'short-input', + placeholder: 'Organization ID', + required: { + field: 'operation', + value: ['get_organization', 'delete_organization'], + }, + condition: { + field: 'operation', + value: [ + 'get_tickets', + 'create_ticket', + 'get_organization', + 'delete_organization', + 'update_organization', + 'create_user', + 'update_user', + ], + }, + }, + { + id: 'organizationName', + title: 'Organization Name', + type: 'short-input', + placeholder: 'Organization name', + required: { + field: 'operation', + value: ['autocomplete_organizations'], + }, + condition: { + field: 'operation', + value: ['autocomplete_organizations', 'create_organization', 'update_organization'], + }, + }, + { + id: 'organizations', + title: 'Organizations', + type: 'long-input', + placeholder: 'JSON array of organization objects', + required: true, + condition: { + field: 'operation', + value: ['create_organizations_bulk'], + }, + }, + // Search fields + { + id: 'query', + title: 'Query', + type: 'short-input', + placeholder: 'Search query', + required: { + field: 'operation', + value: ['search', 'search_count', 'export_search'], + }, + condition: { + field: 'operation', + value: ['search_users', 'search', 'search_count', 'export_search'], + }, + }, + { + id: 'sortBy', + title: 'Sort By', + type: 'dropdown', + options: [ + { label: 'Relevance', id: 'relevance' }, + { label: 'Created At', id: 'created_at' }, + { label: 'Updated At', id: 'updated_at' }, + { label: 'Priority', id: 'priority' }, + { label: 'Status', id: 'status' }, + { label: 'Ticket Type', id: 'ticket_type' }, + ], + condition: { + field: 'operation', + value: ['search'], + }, + }, + { + id: 'sortOrder', + title: 'Sort Order', + type: 'dropdown', + options: [ + { label: 'Ascending', id: 'asc' }, + { label: 'Descending', id: 'desc' }, + ], + condition: { + field: 'operation', + value: ['search'], + }, + }, + // Pagination fields + { + id: 'perPage', + title: 'Per Page', + type: 'short-input', + placeholder: 'Results per page (default: 100, max: 100)', + condition: { + field: 'operation', + value: [ + 'get_tickets', + 'get_users', + 'get_organizations', + 'search_users', + 'autocomplete_organizations', + 'search', + ], + }, + }, + { + id: 'page', + title: 'Page', + type: 'short-input', + placeholder: 'Page number', + condition: { + field: 'operation', + value: [ + 'get_tickets', + 'get_users', + 'get_organizations', + 'search_users', + 'autocomplete_organizations', + 'search', + ], + }, + }, + ], + tools: { + access: [ + 'zendesk_get_tickets', + 'zendesk_get_ticket', + 'zendesk_create_ticket', + 'zendesk_create_tickets_bulk', + 'zendesk_update_ticket', + 'zendesk_update_tickets_bulk', + 'zendesk_delete_ticket', + 'zendesk_merge_tickets', + 'zendesk_get_users', + 'zendesk_get_user', + 'zendesk_get_current_user', + 'zendesk_search_users', + 'zendesk_create_user', + 'zendesk_create_users_bulk', + 'zendesk_update_user', + 'zendesk_update_users_bulk', + 'zendesk_delete_user', + 'zendesk_get_organizations', + 'zendesk_get_organization', + 'zendesk_autocomplete_organizations', + 'zendesk_create_organization', + 'zendesk_create_organizations_bulk', + 'zendesk_update_organization', + 'zendesk_delete_organization', + 'zendesk_search', + 'zendesk_search_count', + 'zendesk_export_search', + ], + config: { + tool: (params) => { + switch (params.operation) { + case 'get_tickets': + return 'zendesk_get_tickets' + case 'get_ticket': + return 'zendesk_get_ticket' + case 'create_ticket': + return 'zendesk_create_ticket' + case 'create_tickets_bulk': + return 'zendesk_create_tickets_bulk' + case 'update_ticket': + return 'zendesk_update_ticket' + case 'update_tickets_bulk': + return 'zendesk_update_tickets_bulk' + case 'delete_ticket': + return 'zendesk_delete_ticket' + case 'merge_tickets': + return 'zendesk_merge_tickets' + case 'get_users': + return 'zendesk_get_users' + case 'get_user': + return 'zendesk_get_user' + case 'get_current_user': + return 'zendesk_get_current_user' + case 'search_users': + return 'zendesk_search_users' + case 'create_user': + return 'zendesk_create_user' + case 'create_users_bulk': + return 'zendesk_create_users_bulk' + case 'update_user': + return 'zendesk_update_user' + case 'update_users_bulk': + return 'zendesk_update_users_bulk' + case 'delete_user': + return 'zendesk_delete_user' + case 'get_organizations': + return 'zendesk_get_organizations' + case 'get_organization': + return 'zendesk_get_organization' + case 'autocomplete_organizations': + return 'zendesk_autocomplete_organizations' + case 'create_organization': + return 'zendesk_create_organization' + case 'create_organizations_bulk': + return 'zendesk_create_organizations_bulk' + case 'update_organization': + return 'zendesk_update_organization' + case 'delete_organization': + return 'zendesk_delete_organization' + case 'search': + return 'zendesk_search' + case 'search_count': + return 'zendesk_search_count' + case 'export_search': + return 'zendesk_export_search' + default: + throw new Error(`Unknown operation: ${params.operation}`) + } + }, + params: (params) => { + const { apiToken, operation, ...rest } = params + const cleanParams: Record = { apiToken } + + // Special mapping for autocomplete_organizations + if (operation === 'autocomplete_organizations' && params.organizationName) { + cleanParams.name = params.organizationName + } + + Object.entries(rest).forEach(([key, value]) => { + if (value !== undefined && value !== null && value !== '') { + // Skip organizationName for autocomplete_organizations as it's mapped to 'name' + if (operation === 'autocomplete_organizations' && key === 'organizationName') { + return + } + cleanParams[key] = value + } + }) + return cleanParams + }, + }, + }, + inputs: { + operation: { type: 'string', description: 'Operation to perform' }, + apiToken: { type: 'string', description: 'Zendesk API token' }, + subdomain: { type: 'string', description: 'Zendesk subdomain' }, + }, + outputs: { + success: { type: 'boolean', description: 'Operation success status' }, + output: { type: 'json', description: 'Operation result data' }, + }, +} diff --git a/apps/sim/blocks/registry.ts b/apps/sim/blocks/registry.ts index 189b09bc85..db663ba3ec 100644 --- a/apps/sim/blocks/registry.ts +++ b/apps/sim/blocks/registry.ts @@ -36,11 +36,13 @@ import { HunterBlock } from '@/blocks/blocks/hunter' import { ImageGeneratorBlock } from '@/blocks/blocks/image_generator' import { IncidentioBlock } from '@/blocks/blocks/incidentio' import { InputTriggerBlock } from '@/blocks/blocks/input_trigger' +import { IntercomBlock } from '@/blocks/blocks/intercom' import { JinaBlock } from '@/blocks/blocks/jina' import { JiraBlock } from '@/blocks/blocks/jira' import { KnowledgeBlock } from '@/blocks/blocks/knowledge' import { LinearBlock } from '@/blocks/blocks/linear' import { LinkupBlock } from '@/blocks/blocks/linkup' +import { MailchimpBlock } from '@/blocks/blocks/mailchimp' import { ManualTriggerBlock } from '@/blocks/blocks/manual_trigger' import { McpBlock } from '@/blocks/blocks/mcp' import { Mem0Block } from '@/blocks/blocks/mem0' @@ -63,6 +65,7 @@ import { PineconeBlock } from '@/blocks/blocks/pinecone' import { PipedriveBlock } from '@/blocks/blocks/pipedrive' import { PostgreSQLBlock } from '@/blocks/blocks/postgresql' import { PostHogBlock } from '@/blocks/blocks/posthog' +import { PylonBlock } from '@/blocks/blocks/pylon' import { QdrantBlock } from '@/blocks/blocks/qdrant' import { RedditBlock } from '@/blocks/blocks/reddit' import { ResendBlock } from '@/blocks/blocks/resend' @@ -104,6 +107,7 @@ import { WorkflowBlock } from '@/blocks/blocks/workflow' import { WorkflowInputBlock } from '@/blocks/blocks/workflow_input' import { XBlock } from '@/blocks/blocks/x' import { YouTubeBlock } from '@/blocks/blocks/youtube' +import { ZendeskBlock } from '@/blocks/blocks/zendesk' import { ZepBlock } from '@/blocks/blocks/zep' import type { BlockConfig } from '@/blocks/types' @@ -149,6 +153,7 @@ export const registry: Record = { knowledge: KnowledgeBlock, linear: LinearBlock, linkup: LinkupBlock, + mailchimp: MailchimpBlock, mcp: McpBlock, mem0: Mem0Block, zep: ZepBlock, @@ -170,6 +175,7 @@ export const registry: Record = { pinecone: PineconeBlock, pipedrive: PipedriveBlock, postgresql: PostgreSQLBlock, + pylon: PylonBlock, qdrant: QdrantBlock, resend: ResendBlock, memory: MemoryBlock, @@ -180,6 +186,8 @@ export const registry: Record = { s3: S3Block, salesforce: SalesforceBlock, sentry: SentryBlock, + intercom: IntercomBlock, + zendesk: ZendeskBlock, serper: SerperBlock, sharepoint: SharepointBlock, stagehand: StagehandBlock, diff --git a/apps/sim/components/icons.tsx b/apps/sim/components/icons.tsx index a99241ff32..9c9f00984a 100644 --- a/apps/sim/components/icons.tsx +++ b/apps/sim/components/icons.tsx @@ -4243,3 +4243,104 @@ export function IncidentioIcon(props: SVGProps) { ) } + +export function IntercomIcon(props: SVGProps) { + return ( + + + + + + ) +} + +export function MailchimpIcon(props: SVGProps) { + return ( + + + + + + + + + + + + + + + + + + ) +} + +export function ZendeskIcon(props: SVGProps) { + return ( + + + + + + ) +} + +export function PylonIcon(props: SVGProps) { + return ( + + + + + + + + + + + ) +} diff --git a/apps/sim/tools/intercom/create_company.ts b/apps/sim/tools/intercom/create_company.ts new file mode 100644 index 0000000000..db8c147292 --- /dev/null +++ b/apps/sim/tools/intercom/create_company.ts @@ -0,0 +1,162 @@ +import { createLogger } from '@/lib/logs/console/logger' +import type { ToolConfig } from '@/tools/types' +import { buildIntercomUrl, handleIntercomError } from './types' + +const logger = createLogger('IntercomCreateCompany') + +export interface IntercomCreateCompanyParams { + accessToken: string + company_id: string + name?: string + website?: string + plan?: string + size?: number + industry?: string + monthly_spend?: number + custom_attributes?: string +} + +export interface IntercomCreateCompanyResponse { + success: boolean + output: { + company: any + metadata: { + operation: 'create_company' + companyId: string + } + success: boolean + } +} + +export const intercomCreateCompanyTool: ToolConfig< + IntercomCreateCompanyParams, + IntercomCreateCompanyResponse +> = { + id: 'intercom_create_company', + name: 'Create Company in Intercom', + description: 'Create or update a company in Intercom', + version: '1.0.0', + + params: { + accessToken: { + type: 'string', + required: true, + visibility: 'hidden', + description: 'Intercom API access token', + }, + company_id: { + type: 'string', + required: true, + visibility: 'user-only', + description: 'Your unique identifier for the company', + }, + name: { + type: 'string', + required: false, + visibility: 'user-only', + description: 'The name of the company', + }, + website: { + type: 'string', + required: false, + visibility: 'user-only', + description: 'The company website', + }, + plan: { + type: 'string', + required: false, + visibility: 'user-only', + description: 'The company plan name', + }, + size: { + type: 'number', + required: false, + visibility: 'user-only', + description: 'The number of employees in the company', + }, + industry: { + type: 'string', + required: false, + visibility: 'user-only', + description: 'The industry the company operates in', + }, + monthly_spend: { + type: 'number', + required: false, + visibility: 'user-only', + description: 'How much revenue the company generates for your business', + }, + custom_attributes: { + type: 'string', + required: false, + visibility: 'user-only', + description: 'Custom attributes as JSON object', + }, + }, + + request: { + url: () => buildIntercomUrl('/companies'), + method: 'POST', + headers: (params) => ({ + Authorization: `Bearer ${params.accessToken}`, + 'Content-Type': 'application/json', + 'Intercom-Version': '2.14', + }), + body: (params) => { + const company: any = { + company_id: params.company_id, + } + + if (params.name) company.name = params.name + if (params.website) company.website = params.website + if (params.plan) company.plan = params.plan + if (params.size) company.size = params.size + if (params.industry) company.industry = params.industry + if (params.monthly_spend) company.monthly_spend = params.monthly_spend + + if (params.custom_attributes) { + try { + company.custom_attributes = JSON.parse(params.custom_attributes) + } catch (error) { + logger.warn('Failed to parse custom attributes', { error }) + } + } + + return company + }, + }, + + transformResponse: async (response: Response) => { + if (!response.ok) { + const data = await response.json() + handleIntercomError(data, response.status, 'create_company') + } + + const data = await response.json() + + return { + success: true, + output: { + company: data, + metadata: { + operation: 'create_company' as const, + companyId: data.id, + }, + success: true, + }, + } + }, + + outputs: { + success: { type: 'boolean', description: 'Operation success status' }, + output: { + type: 'object', + description: 'Created or updated company data', + properties: { + company: { type: 'object', description: 'Company object' }, + metadata: { type: 'object', description: 'Operation metadata' }, + success: { type: 'boolean', description: 'Operation success' }, + }, + }, + }, +} diff --git a/apps/sim/tools/intercom/create_contact.ts b/apps/sim/tools/intercom/create_contact.ts new file mode 100644 index 0000000000..81359fdb04 --- /dev/null +++ b/apps/sim/tools/intercom/create_contact.ts @@ -0,0 +1,178 @@ +import { createLogger } from '@/lib/logs/console/logger' +import type { ToolConfig } from '@/tools/types' +import { buildIntercomUrl, handleIntercomError } from './types' + +const logger = createLogger('IntercomCreateContact') + +export interface IntercomCreateContactParams { + accessToken: string + email?: string + external_id?: string + phone?: string + name?: string + avatar?: string + signed_up_at?: number + last_seen_at?: number + owner_id?: string + unsubscribed_from_emails?: boolean + custom_attributes?: string +} + +export interface IntercomCreateContactResponse { + success: boolean + output: { + contact: any + metadata: { + operation: 'create_contact' + contactId: string + } + success: boolean + } +} + +export const intercomCreateContactTool: ToolConfig< + IntercomCreateContactParams, + IntercomCreateContactResponse +> = { + id: 'intercom_create_contact', + name: 'Create Contact in Intercom', + description: 'Create a new contact in Intercom with email, external_id, or role', + version: '1.0.0', + + params: { + accessToken: { + type: 'string', + required: true, + visibility: 'hidden', + description: 'Intercom API access token', + }, + email: { + type: 'string', + required: false, + visibility: 'user-only', + description: "The contact's email address", + }, + external_id: { + type: 'string', + required: false, + visibility: 'user-only', + description: 'A unique identifier for the contact provided by the client', + }, + phone: { + type: 'string', + required: false, + visibility: 'user-only', + description: "The contact's phone number", + }, + name: { + type: 'string', + required: false, + visibility: 'user-only', + description: "The contact's name", + }, + avatar: { + type: 'string', + required: false, + visibility: 'user-only', + description: 'An avatar image URL for the contact', + }, + signed_up_at: { + type: 'number', + required: false, + visibility: 'user-only', + description: 'The time the user signed up as a Unix timestamp', + }, + last_seen_at: { + type: 'number', + required: false, + visibility: 'user-only', + description: 'The time the user was last seen as a Unix timestamp', + }, + owner_id: { + type: 'string', + required: false, + visibility: 'user-only', + description: 'The id of an admin that has been assigned account ownership of the contact', + }, + unsubscribed_from_emails: { + type: 'boolean', + required: false, + visibility: 'user-only', + description: 'Whether the contact is unsubscribed from emails', + }, + custom_attributes: { + type: 'string', + required: false, + visibility: 'user-only', + description: 'Custom attributes as JSON object (e.g., {"attribute_name": "value"})', + }, + }, + + request: { + url: () => buildIntercomUrl('/contacts'), + method: 'POST', + headers: (params) => ({ + Authorization: `Bearer ${params.accessToken}`, + 'Content-Type': 'application/json', + 'Intercom-Version': '2.14', + }), + body: (params) => { + const contact: any = {} + + if (params.email) contact.email = params.email + if (params.external_id) contact.external_id = params.external_id + if (params.phone) contact.phone = params.phone + if (params.name) contact.name = params.name + if (params.avatar) contact.avatar = params.avatar + if (params.signed_up_at) contact.signed_up_at = params.signed_up_at + if (params.last_seen_at) contact.last_seen_at = params.last_seen_at + if (params.owner_id) contact.owner_id = params.owner_id + if (params.unsubscribed_from_emails !== undefined) + contact.unsubscribed_from_emails = params.unsubscribed_from_emails + + if (params.custom_attributes) { + try { + contact.custom_attributes = JSON.parse(params.custom_attributes) + } catch (error) { + logger.warn('Failed to parse custom attributes', { error }) + } + } + + return contact + }, + }, + + transformResponse: async (response: Response) => { + if (!response.ok) { + const data = await response.json() + handleIntercomError(data, response.status, 'create_contact') + } + + const data = await response.json() + + return { + success: true, + output: { + contact: data, + metadata: { + operation: 'create_contact' as const, + contactId: data.id, + }, + success: true, + }, + } + }, + + outputs: { + success: { type: 'boolean', description: 'Operation success status' }, + output: { + type: 'object', + description: 'Created contact data', + properties: { + contact: { type: 'object', description: 'Created contact object' }, + metadata: { type: 'object', description: 'Operation metadata' }, + success: { type: 'boolean', description: 'Operation success' }, + }, + }, + }, +} diff --git a/apps/sim/tools/intercom/create_message.ts b/apps/sim/tools/intercom/create_message.ts new file mode 100644 index 0000000000..bbbd486ccb --- /dev/null +++ b/apps/sim/tools/intercom/create_message.ts @@ -0,0 +1,153 @@ +import { createLogger } from '@/lib/logs/console/logger' +import type { ToolConfig } from '@/tools/types' +import { buildIntercomUrl, handleIntercomError } from './types' + +const logger = createLogger('IntercomCreateMessage') + +export interface IntercomCreateMessageParams { + accessToken: string + message_type: string + subject?: string + body: string + from_type: string + from_id: string + to_type: string + to_id: string +} + +export interface IntercomCreateMessageResponse { + success: boolean + output: { + message: any + metadata: { + operation: 'create_message' + messageId: string + } + success: boolean + } +} + +export const intercomCreateMessageTool: ToolConfig< + IntercomCreateMessageParams, + IntercomCreateMessageResponse +> = { + id: 'intercom_create_message', + name: 'Create Message in Intercom', + description: 'Create and send a new admin-initiated message in Intercom', + version: '1.0.0', + + params: { + accessToken: { + type: 'string', + required: true, + visibility: 'hidden', + description: 'Intercom API access token', + }, + message_type: { + type: 'string', + required: true, + visibility: 'user-only', + description: 'Message type: "inapp" or "email"', + }, + subject: { + type: 'string', + required: false, + visibility: 'user-only', + description: 'The subject of the message (for email type)', + }, + body: { + type: 'string', + required: true, + visibility: 'user-only', + description: 'The body of the message', + }, + from_type: { + type: 'string', + required: true, + visibility: 'user-only', + description: 'Sender type: "admin"', + }, + from_id: { + type: 'string', + required: true, + visibility: 'user-only', + description: 'The ID of the admin sending the message', + }, + to_type: { + type: 'string', + required: true, + visibility: 'user-only', + description: 'Recipient type: "contact"', + }, + to_id: { + type: 'string', + required: true, + visibility: 'user-only', + description: 'The ID of the contact receiving the message', + }, + }, + + request: { + url: () => buildIntercomUrl('/messages'), + method: 'POST', + headers: (params) => ({ + Authorization: `Bearer ${params.accessToken}`, + 'Content-Type': 'application/json', + 'Intercom-Version': '2.14', + }), + body: (params) => { + const message: any = { + message_type: params.message_type, + body: params.body, + from: { + type: params.from_type, + id: params.from_id, + }, + to: { + type: params.to_type, + id: params.to_id, + }, + } + + if (params.subject && params.message_type === 'email') { + message.subject = params.subject + } + + return message + }, + }, + + transformResponse: async (response: Response) => { + if (!response.ok) { + const data = await response.json() + handleIntercomError(data, response.status, 'create_message') + } + + const data = await response.json() + + return { + success: true, + output: { + message: data, + metadata: { + operation: 'create_message' as const, + messageId: data.id, + }, + success: true, + }, + } + }, + + outputs: { + success: { type: 'boolean', description: 'Operation success status' }, + output: { + type: 'object', + description: 'Created message data', + properties: { + message: { type: 'object', description: 'Created message object' }, + metadata: { type: 'object', description: 'Operation metadata' }, + success: { type: 'boolean', description: 'Operation success' }, + }, + }, + }, +} diff --git a/apps/sim/tools/intercom/create_ticket.ts b/apps/sim/tools/intercom/create_ticket.ts new file mode 100644 index 0000000000..8ec1a665ea --- /dev/null +++ b/apps/sim/tools/intercom/create_ticket.ts @@ -0,0 +1,127 @@ +import { createLogger } from '@/lib/logs/console/logger' +import type { ToolConfig } from '@/tools/types' +import { buildIntercomUrl, handleIntercomError } from './types' + +const logger = createLogger('IntercomCreateTicket') + +export interface IntercomCreateTicketParams { + accessToken: string + ticket_type_id: string + contacts: string + ticket_attributes: string +} + +export interface IntercomCreateTicketResponse { + success: boolean + output: { + ticket: any + metadata: { + operation: 'create_ticket' + ticketId: string + } + success: boolean + } +} + +export const intercomCreateTicketTool: ToolConfig< + IntercomCreateTicketParams, + IntercomCreateTicketResponse +> = { + id: 'intercom_create_ticket', + name: 'Create Ticket in Intercom', + description: 'Create a new ticket in Intercom', + version: '1.0.0', + + params: { + accessToken: { + type: 'string', + required: true, + visibility: 'hidden', + description: 'Intercom API access token', + }, + ticket_type_id: { + type: 'string', + required: true, + visibility: 'user-only', + description: 'The ID of the ticket type', + }, + contacts: { + type: 'string', + required: true, + visibility: 'user-only', + description: 'JSON array of contact identifiers (e.g., [{"id": "contact_id"}])', + }, + ticket_attributes: { + type: 'string', + required: true, + visibility: 'user-only', + description: + 'JSON object with ticket attributes including _default_title_ and _default_description_', + }, + }, + + request: { + url: () => buildIntercomUrl('/tickets'), + method: 'POST', + headers: (params) => ({ + Authorization: `Bearer ${params.accessToken}`, + 'Content-Type': 'application/json', + 'Intercom-Version': '2.14', + }), + body: (params) => { + const ticket: any = { + ticket_type_id: params.ticket_type_id, + } + + try { + ticket.contacts = JSON.parse(params.contacts) + } catch (error) { + logger.warn('Failed to parse contacts, using as single contact ID', { error }) + ticket.contacts = [{ id: params.contacts }] + } + + try { + ticket.ticket_attributes = JSON.parse(params.ticket_attributes) + } catch (error) { + logger.error('Failed to parse ticket attributes', { error }) + throw new Error('ticket_attributes must be a valid JSON object') + } + + return ticket + }, + }, + + transformResponse: async (response: Response) => { + if (!response.ok) { + const data = await response.json() + handleIntercomError(data, response.status, 'create_ticket') + } + + const data = await response.json() + + return { + success: true, + output: { + ticket: data, + metadata: { + operation: 'create_ticket' as const, + ticketId: data.id, + }, + success: true, + }, + } + }, + + outputs: { + success: { type: 'boolean', description: 'Operation success status' }, + output: { + type: 'object', + description: 'Created ticket data', + properties: { + ticket: { type: 'object', description: 'Created ticket object' }, + metadata: { type: 'object', description: 'Operation metadata' }, + success: { type: 'boolean', description: 'Operation success' }, + }, + }, + }, +} diff --git a/apps/sim/tools/intercom/delete_contact.ts b/apps/sim/tools/intercom/delete_contact.ts new file mode 100644 index 0000000000..bb74789257 --- /dev/null +++ b/apps/sim/tools/intercom/delete_contact.ts @@ -0,0 +1,92 @@ +import { createLogger } from '@/lib/logs/console/logger' +import type { ToolConfig } from '@/tools/types' +import { buildIntercomUrl, handleIntercomError } from './types' + +const logger = createLogger('IntercomDeleteContact') + +export interface IntercomDeleteContactParams { + accessToken: string + contactId: string +} + +export interface IntercomDeleteContactResponse { + success: boolean + output: { + id: string + deleted: boolean + metadata: { + operation: 'delete_contact' + } + success: boolean + } +} + +export const intercomDeleteContactTool: ToolConfig< + IntercomDeleteContactParams, + IntercomDeleteContactResponse +> = { + id: 'intercom_delete_contact', + name: 'Delete Contact from Intercom', + description: 'Delete a contact from Intercom by ID', + version: '1.0.0', + + params: { + accessToken: { + type: 'string', + required: true, + visibility: 'hidden', + description: 'Intercom API access token', + }, + contactId: { + type: 'string', + required: true, + visibility: 'user-only', + description: 'Contact ID to delete', + }, + }, + + request: { + url: (params) => buildIntercomUrl(`/contacts/${params.contactId}`), + method: 'DELETE', + headers: (params) => ({ + Authorization: `Bearer ${params.accessToken}`, + 'Content-Type': 'application/json', + 'Intercom-Version': '2.14', + }), + }, + + transformResponse: async (response: Response) => { + if (!response.ok) { + const data = await response.json() + handleIntercomError(data, response.status, 'delete_contact') + } + + const data = await response.json() + + return { + success: true, + output: { + id: data.id, + deleted: true, + metadata: { + operation: 'delete_contact' as const, + }, + success: true, + }, + } + }, + + outputs: { + success: { type: 'boolean', description: 'Operation success status' }, + output: { + type: 'object', + description: 'Deletion result', + properties: { + id: { type: 'string', description: 'ID of deleted contact' }, + deleted: { type: 'boolean', description: 'Deletion status' }, + metadata: { type: 'object', description: 'Operation metadata' }, + success: { type: 'boolean', description: 'Operation success' }, + }, + }, + }, +} diff --git a/apps/sim/tools/intercom/get_company.ts b/apps/sim/tools/intercom/get_company.ts new file mode 100644 index 0000000000..5803cc46aa --- /dev/null +++ b/apps/sim/tools/intercom/get_company.ts @@ -0,0 +1,89 @@ +import { createLogger } from '@/lib/logs/console/logger' +import type { ToolConfig } from '@/tools/types' +import { buildIntercomUrl, handleIntercomError } from './types' + +const logger = createLogger('IntercomGetCompany') + +export interface IntercomGetCompanyParams { + accessToken: string + companyId: string +} + +export interface IntercomGetCompanyResponse { + success: boolean + output: { + company: any + metadata: { + operation: 'get_company' + } + success: boolean + } +} + +export const intercomGetCompanyTool: ToolConfig< + IntercomGetCompanyParams, + IntercomGetCompanyResponse +> = { + id: 'intercom_get_company', + name: 'Get Company from Intercom', + description: 'Retrieve a single company by ID from Intercom', + version: '1.0.0', + + params: { + accessToken: { + type: 'string', + required: true, + visibility: 'hidden', + description: 'Intercom API access token', + }, + companyId: { + type: 'string', + required: true, + visibility: 'user-only', + description: 'Company ID to retrieve', + }, + }, + + request: { + url: (params) => buildIntercomUrl(`/companies/${params.companyId}`), + method: 'GET', + headers: (params) => ({ + Authorization: `Bearer ${params.accessToken}`, + 'Content-Type': 'application/json', + 'Intercom-Version': '2.14', + }), + }, + + transformResponse: async (response: Response) => { + if (!response.ok) { + const data = await response.json() + handleIntercomError(data, response.status, 'get_company') + } + + const data = await response.json() + + return { + success: true, + output: { + company: data, + metadata: { + operation: 'get_company' as const, + }, + success: true, + }, + } + }, + + outputs: { + success: { type: 'boolean', description: 'Operation success status' }, + output: { + type: 'object', + description: 'Company data', + properties: { + company: { type: 'object', description: 'Company object' }, + metadata: { type: 'object', description: 'Operation metadata' }, + success: { type: 'boolean', description: 'Operation success' }, + }, + }, + }, +} diff --git a/apps/sim/tools/intercom/get_contact.ts b/apps/sim/tools/intercom/get_contact.ts new file mode 100644 index 0000000000..8b1c85f1da --- /dev/null +++ b/apps/sim/tools/intercom/get_contact.ts @@ -0,0 +1,89 @@ +import { createLogger } from '@/lib/logs/console/logger' +import type { ToolConfig } from '@/tools/types' +import { buildIntercomUrl, handleIntercomError } from './types' + +const logger = createLogger('IntercomGetContact') + +export interface IntercomGetContactParams { + accessToken: string + contactId: string +} + +export interface IntercomGetContactResponse { + success: boolean + output: { + contact: any + metadata: { + operation: 'get_contact' + } + success: boolean + } +} + +export const intercomGetContactTool: ToolConfig< + IntercomGetContactParams, + IntercomGetContactResponse +> = { + id: 'intercom_get_contact', + name: 'Get Single Contact from Intercom', + description: 'Get a single contact by ID from Intercom', + version: '1.0.0', + + params: { + accessToken: { + type: 'string', + required: true, + visibility: 'hidden', + description: 'Intercom API access token', + }, + contactId: { + type: 'string', + required: true, + visibility: 'user-only', + description: 'Contact ID to retrieve', + }, + }, + + request: { + url: (params) => buildIntercomUrl(`/contacts/${params.contactId}`), + method: 'GET', + headers: (params) => ({ + Authorization: `Bearer ${params.accessToken}`, + 'Content-Type': 'application/json', + 'Intercom-Version': '2.14', + }), + }, + + transformResponse: async (response: Response) => { + if (!response.ok) { + const data = await response.json() + handleIntercomError(data, response.status, 'get_contact') + } + + const data = await response.json() + + return { + success: true, + output: { + contact: data, + metadata: { + operation: 'get_contact' as const, + }, + success: true, + }, + } + }, + + outputs: { + success: { type: 'boolean', description: 'Operation success status' }, + output: { + type: 'object', + description: 'Contact data', + properties: { + contact: { type: 'object', description: 'Contact object' }, + metadata: { type: 'object', description: 'Operation metadata' }, + success: { type: 'boolean', description: 'Operation success' }, + }, + }, + }, +} diff --git a/apps/sim/tools/intercom/get_conversation.ts b/apps/sim/tools/intercom/get_conversation.ts new file mode 100644 index 0000000000..ce81663f56 --- /dev/null +++ b/apps/sim/tools/intercom/get_conversation.ts @@ -0,0 +1,102 @@ +import { createLogger } from '@/lib/logs/console/logger' +import type { ToolConfig } from '@/tools/types' +import { buildIntercomUrl, handleIntercomError } from './types' + +const logger = createLogger('IntercomGetConversation') + +export interface IntercomGetConversationParams { + accessToken: string + conversationId: string + display_as?: string +} + +export interface IntercomGetConversationResponse { + success: boolean + output: { + conversation: any + metadata: { + operation: 'get_conversation' + } + success: boolean + } +} + +export const intercomGetConversationTool: ToolConfig< + IntercomGetConversationParams, + IntercomGetConversationResponse +> = { + id: 'intercom_get_conversation', + name: 'Get Conversation from Intercom', + description: 'Retrieve a single conversation by ID from Intercom', + version: '1.0.0', + + params: { + accessToken: { + type: 'string', + required: true, + visibility: 'hidden', + description: 'Intercom API access token', + }, + conversationId: { + type: 'string', + required: true, + visibility: 'user-only', + description: 'Conversation ID to retrieve', + }, + display_as: { + type: 'string', + required: false, + visibility: 'user-only', + description: 'Set to "plaintext" to retrieve messages in plain text', + }, + }, + + request: { + url: (params) => { + const url = buildIntercomUrl(`/conversations/${params.conversationId}`) + if (params.display_as) { + return `${url}?display_as=${params.display_as}` + } + return url + }, + method: 'GET', + headers: (params) => ({ + Authorization: `Bearer ${params.accessToken}`, + 'Content-Type': 'application/json', + 'Intercom-Version': '2.14', + }), + }, + + transformResponse: async (response: Response) => { + if (!response.ok) { + const data = await response.json() + handleIntercomError(data, response.status, 'get_conversation') + } + + const data = await response.json() + + return { + success: true, + output: { + conversation: data, + metadata: { + operation: 'get_conversation' as const, + }, + success: true, + }, + } + }, + + outputs: { + success: { type: 'boolean', description: 'Operation success status' }, + output: { + type: 'object', + description: 'Conversation data', + properties: { + conversation: { type: 'object', description: 'Conversation object' }, + metadata: { type: 'object', description: 'Operation metadata' }, + success: { type: 'boolean', description: 'Operation success' }, + }, + }, + }, +} diff --git a/apps/sim/tools/intercom/get_ticket.ts b/apps/sim/tools/intercom/get_ticket.ts new file mode 100644 index 0000000000..7a04bf5dcc --- /dev/null +++ b/apps/sim/tools/intercom/get_ticket.ts @@ -0,0 +1,87 @@ +import { createLogger } from '@/lib/logs/console/logger' +import type { ToolConfig } from '@/tools/types' +import { buildIntercomUrl, handleIntercomError } from './types' + +const logger = createLogger('IntercomGetTicket') + +export interface IntercomGetTicketParams { + accessToken: string + ticketId: string +} + +export interface IntercomGetTicketResponse { + success: boolean + output: { + ticket: any + metadata: { + operation: 'get_ticket' + } + success: boolean + } +} + +export const intercomGetTicketTool: ToolConfig = + { + id: 'intercom_get_ticket', + name: 'Get Ticket from Intercom', + description: 'Retrieve a single ticket by ID from Intercom', + version: '1.0.0', + + params: { + accessToken: { + type: 'string', + required: true, + visibility: 'hidden', + description: 'Intercom API access token', + }, + ticketId: { + type: 'string', + required: true, + visibility: 'user-only', + description: 'Ticket ID to retrieve', + }, + }, + + request: { + url: (params) => buildIntercomUrl(`/tickets/${params.ticketId}`), + method: 'GET', + headers: (params) => ({ + Authorization: `Bearer ${params.accessToken}`, + 'Content-Type': 'application/json', + 'Intercom-Version': '2.14', + }), + }, + + transformResponse: async (response: Response) => { + if (!response.ok) { + const data = await response.json() + handleIntercomError(data, response.status, 'get_ticket') + } + + const data = await response.json() + + return { + success: true, + output: { + ticket: data, + metadata: { + operation: 'get_ticket' as const, + }, + success: true, + }, + } + }, + + outputs: { + success: { type: 'boolean', description: 'Operation success status' }, + output: { + type: 'object', + description: 'Ticket data', + properties: { + ticket: { type: 'object', description: 'Ticket object' }, + metadata: { type: 'object', description: 'Operation metadata' }, + success: { type: 'boolean', description: 'Operation success' }, + }, + }, + }, + } diff --git a/apps/sim/tools/intercom/index.ts b/apps/sim/tools/intercom/index.ts new file mode 100644 index 0000000000..feda2beedb --- /dev/null +++ b/apps/sim/tools/intercom/index.ts @@ -0,0 +1,23 @@ +// Contact tools + +// Company tools +export { intercomCreateCompanyTool } from './create_company' +export { intercomCreateContactTool } from './create_contact' +// Message tools +export { intercomCreateMessageTool } from './create_message' +// Ticket tools +export { intercomCreateTicketTool } from './create_ticket' +export { intercomDeleteContactTool } from './delete_contact' +export { intercomGetCompanyTool } from './get_company' +export { intercomGetContactTool } from './get_contact' +// Conversation tools +export { intercomGetConversationTool } from './get_conversation' +export { intercomGetTicketTool } from './get_ticket' +export { intercomListCompaniesTool } from './list_companies' +export { intercomListContactsTool } from './list_contacts' +export { intercomListConversationsTool } from './list_conversations' +export { intercomListTicketsTool } from './list_tickets' +export { intercomReplyConversationTool } from './reply_conversation' +export { intercomSearchContactsTool } from './search_contacts' +export { intercomSearchConversationsTool } from './search_conversations' +export { intercomUpdateContactTool } from './update_contact' diff --git a/apps/sim/tools/intercom/list_companies.ts b/apps/sim/tools/intercom/list_companies.ts new file mode 100644 index 0000000000..0fc29e622f --- /dev/null +++ b/apps/sim/tools/intercom/list_companies.ts @@ -0,0 +1,110 @@ +import { createLogger } from '@/lib/logs/console/logger' +import type { ToolConfig } from '@/tools/types' +import { buildIntercomUrl, handleIntercomError } from './types' + +const logger = createLogger('IntercomListCompanies') + +export interface IntercomListCompaniesParams { + accessToken: string + per_page?: number + page?: number +} + +export interface IntercomListCompaniesResponse { + success: boolean + output: { + companies: any[] + pages?: any + metadata: { + operation: 'list_companies' + total_count?: number + } + success: boolean + } +} + +export const intercomListCompaniesTool: ToolConfig< + IntercomListCompaniesParams, + IntercomListCompaniesResponse +> = { + id: 'intercom_list_companies', + name: 'List Companies from Intercom', + description: 'List all companies from Intercom with pagination support', + version: '1.0.0', + + params: { + accessToken: { + type: 'string', + required: true, + visibility: 'hidden', + description: 'Intercom API access token', + }, + per_page: { + type: 'number', + required: false, + visibility: 'user-only', + description: 'Number of results per page', + }, + page: { + type: 'number', + required: false, + visibility: 'user-only', + description: 'Page number', + }, + }, + + request: { + url: (params) => { + const url = buildIntercomUrl('/companies/list') + const queryParams = new URLSearchParams() + + if (params.per_page) queryParams.append('per_page', params.per_page.toString()) + if (params.page) queryParams.append('page', params.page.toString()) + + const queryString = queryParams.toString() + return queryString ? `${url}?${queryString}` : url + }, + method: 'GET', + headers: (params) => ({ + Authorization: `Bearer ${params.accessToken}`, + 'Content-Type': 'application/json', + 'Intercom-Version': '2.14', + }), + }, + + transformResponse: async (response: Response) => { + if (!response.ok) { + const data = await response.json() + handleIntercomError(data, response.status, 'list_companies') + } + + const data = await response.json() + + return { + success: true, + output: { + companies: data.data || data.companies || [], + pages: data.pages, + metadata: { + operation: 'list_companies' as const, + total_count: data.total_count, + }, + success: true, + }, + } + }, + + outputs: { + success: { type: 'boolean', description: 'Operation success status' }, + output: { + type: 'object', + description: 'List of companies', + properties: { + companies: { type: 'array', description: 'Array of company objects' }, + pages: { type: 'object', description: 'Pagination information' }, + metadata: { type: 'object', description: 'Operation metadata' }, + success: { type: 'boolean', description: 'Operation success' }, + }, + }, + }, +} diff --git a/apps/sim/tools/intercom/list_contacts.ts b/apps/sim/tools/intercom/list_contacts.ts new file mode 100644 index 0000000000..6b3123a512 --- /dev/null +++ b/apps/sim/tools/intercom/list_contacts.ts @@ -0,0 +1,110 @@ +import { createLogger } from '@/lib/logs/console/logger' +import type { ToolConfig } from '@/tools/types' +import { buildIntercomUrl, handleIntercomError } from './types' + +const logger = createLogger('IntercomListContacts') + +export interface IntercomListContactsParams { + accessToken: string + per_page?: number + starting_after?: string +} + +export interface IntercomListContactsResponse { + success: boolean + output: { + contacts: any[] + pages?: any + metadata: { + operation: 'list_contacts' + total_count?: number + } + success: boolean + } +} + +export const intercomListContactsTool: ToolConfig< + IntercomListContactsParams, + IntercomListContactsResponse +> = { + id: 'intercom_list_contacts', + name: 'List Contacts from Intercom', + description: 'List all contacts from Intercom with pagination support', + version: '1.0.0', + + params: { + accessToken: { + type: 'string', + required: true, + visibility: 'hidden', + description: 'Intercom API access token', + }, + per_page: { + type: 'number', + required: false, + visibility: 'user-only', + description: 'Number of results per page (max: 150)', + }, + starting_after: { + type: 'string', + required: false, + visibility: 'user-only', + description: 'Cursor for pagination - ID to start after', + }, + }, + + request: { + url: (params) => { + const url = buildIntercomUrl('/contacts') + const queryParams = new URLSearchParams() + + if (params.per_page) queryParams.append('per_page', params.per_page.toString()) + if (params.starting_after) queryParams.append('starting_after', params.starting_after) + + const queryString = queryParams.toString() + return queryString ? `${url}?${queryString}` : url + }, + method: 'GET', + headers: (params) => ({ + Authorization: `Bearer ${params.accessToken}`, + 'Content-Type': 'application/json', + 'Intercom-Version': '2.14', + }), + }, + + transformResponse: async (response: Response) => { + if (!response.ok) { + const data = await response.json() + handleIntercomError(data, response.status, 'list_contacts') + } + + const data = await response.json() + + return { + success: true, + output: { + contacts: data.data || [], + pages: data.pages, + metadata: { + operation: 'list_contacts' as const, + total_count: data.total_count, + }, + success: true, + }, + } + }, + + outputs: { + success: { type: 'boolean', description: 'Operation success status' }, + output: { + type: 'object', + description: 'List of contacts', + properties: { + contacts: { type: 'array', description: 'Array of contact objects' }, + pages: { type: 'object', description: 'Pagination information' }, + metadata: { type: 'object', description: 'Operation metadata' }, + success: { type: 'boolean', description: 'Operation success' }, + }, + }, + }, +} diff --git a/apps/sim/tools/intercom/list_conversations.ts b/apps/sim/tools/intercom/list_conversations.ts new file mode 100644 index 0000000000..c3668b4b89 --- /dev/null +++ b/apps/sim/tools/intercom/list_conversations.ts @@ -0,0 +1,110 @@ +import { createLogger } from '@/lib/logs/console/logger' +import type { ToolConfig } from '@/tools/types' +import { buildIntercomUrl, handleIntercomError } from './types' + +const logger = createLogger('IntercomListConversations') + +export interface IntercomListConversationsParams { + accessToken: string + per_page?: number + starting_after?: string +} + +export interface IntercomListConversationsResponse { + success: boolean + output: { + conversations: any[] + pages?: any + metadata: { + operation: 'list_conversations' + total_count?: number + } + success: boolean + } +} + +export const intercomListConversationsTool: ToolConfig< + IntercomListConversationsParams, + IntercomListConversationsResponse +> = { + id: 'intercom_list_conversations', + name: 'List Conversations from Intercom', + description: 'List all conversations from Intercom with pagination support', + version: '1.0.0', + + params: { + accessToken: { + type: 'string', + required: true, + visibility: 'hidden', + description: 'Intercom API access token', + }, + per_page: { + type: 'number', + required: false, + visibility: 'user-only', + description: 'Number of results per page (max: 150)', + }, + starting_after: { + type: 'string', + required: false, + visibility: 'user-only', + description: 'Cursor for pagination', + }, + }, + + request: { + url: (params) => { + const url = buildIntercomUrl('/conversations') + const queryParams = new URLSearchParams() + + if (params.per_page) queryParams.append('per_page', params.per_page.toString()) + if (params.starting_after) queryParams.append('starting_after', params.starting_after) + + const queryString = queryParams.toString() + return queryString ? `${url}?${queryString}` : url + }, + method: 'GET', + headers: (params) => ({ + Authorization: `Bearer ${params.accessToken}`, + 'Content-Type': 'application/json', + 'Intercom-Version': '2.14', + }), + }, + + transformResponse: async (response: Response) => { + if (!response.ok) { + const data = await response.json() + handleIntercomError(data, response.status, 'list_conversations') + } + + const data = await response.json() + + return { + success: true, + output: { + conversations: data.conversations || [], + pages: data.pages, + metadata: { + operation: 'list_conversations' as const, + total_count: data.total_count, + }, + success: true, + }, + } + }, + + outputs: { + success: { type: 'boolean', description: 'Operation success status' }, + output: { + type: 'object', + description: 'List of conversations', + properties: { + conversations: { type: 'array', description: 'Array of conversation objects' }, + pages: { type: 'object', description: 'Pagination information' }, + metadata: { type: 'object', description: 'Operation metadata' }, + success: { type: 'boolean', description: 'Operation success' }, + }, + }, + }, +} diff --git a/apps/sim/tools/intercom/list_tickets.ts b/apps/sim/tools/intercom/list_tickets.ts new file mode 100644 index 0000000000..034cea80fb --- /dev/null +++ b/apps/sim/tools/intercom/list_tickets.ts @@ -0,0 +1,110 @@ +import { createLogger } from '@/lib/logs/console/logger' +import type { ToolConfig } from '@/tools/types' +import { buildIntercomUrl, handleIntercomError } from './types' + +const logger = createLogger('IntercomListTickets') + +export interface IntercomListTicketsParams { + accessToken: string + per_page?: number + starting_after?: string +} + +export interface IntercomListTicketsResponse { + success: boolean + output: { + tickets: any[] + pages?: any + metadata: { + operation: 'list_tickets' + total_count?: number + } + success: boolean + } +} + +export const intercomListTicketsTool: ToolConfig< + IntercomListTicketsParams, + IntercomListTicketsResponse +> = { + id: 'intercom_list_tickets', + name: 'List Tickets from Intercom', + description: 'List all tickets from Intercom with pagination support', + version: '1.0.0', + + params: { + accessToken: { + type: 'string', + required: true, + visibility: 'hidden', + description: 'Intercom API access token', + }, + per_page: { + type: 'number', + required: false, + visibility: 'user-only', + description: 'Number of results per page (max: 150)', + }, + starting_after: { + type: 'string', + required: false, + visibility: 'user-only', + description: 'Cursor for pagination', + }, + }, + + request: { + url: (params) => { + const url = buildIntercomUrl('/tickets') + const queryParams = new URLSearchParams() + + if (params.per_page) queryParams.append('per_page', params.per_page.toString()) + if (params.starting_after) queryParams.append('starting_after', params.starting_after) + + const queryString = queryParams.toString() + return queryString ? `${url}?${queryString}` : url + }, + method: 'GET', + headers: (params) => ({ + Authorization: `Bearer ${params.accessToken}`, + 'Content-Type': 'application/json', + 'Intercom-Version': '2.14', + }), + }, + + transformResponse: async (response: Response) => { + if (!response.ok) { + const data = await response.json() + handleIntercomError(data, response.status, 'list_tickets') + } + + const data = await response.json() + + return { + success: true, + output: { + tickets: data.tickets || [], + pages: data.pages, + metadata: { + operation: 'list_tickets' as const, + total_count: data.total_count, + }, + success: true, + }, + } + }, + + outputs: { + success: { type: 'boolean', description: 'Operation success status' }, + output: { + type: 'object', + description: 'List of tickets', + properties: { + tickets: { type: 'array', description: 'Array of ticket objects' }, + pages: { type: 'object', description: 'Pagination information' }, + metadata: { type: 'object', description: 'Operation metadata' }, + success: { type: 'boolean', description: 'Operation success' }, + }, + }, + }, +} diff --git a/apps/sim/tools/intercom/reply_conversation.ts b/apps/sim/tools/intercom/reply_conversation.ts new file mode 100644 index 0000000000..1a894b0eac --- /dev/null +++ b/apps/sim/tools/intercom/reply_conversation.ts @@ -0,0 +1,137 @@ +import { createLogger } from '@/lib/logs/console/logger' +import type { ToolConfig } from '@/tools/types' +import { buildIntercomUrl, handleIntercomError } from './types' + +const logger = createLogger('IntercomReplyConversation') + +export interface IntercomReplyConversationParams { + accessToken: string + conversationId: string + message_type: string + body: string + admin_id?: string + attachment_urls?: string +} + +export interface IntercomReplyConversationResponse { + success: boolean + output: { + conversation: any + metadata: { + operation: 'reply_conversation' + conversationId: string + } + success: boolean + } +} + +export const intercomReplyConversationTool: ToolConfig< + IntercomReplyConversationParams, + IntercomReplyConversationResponse +> = { + id: 'intercom_reply_conversation', + name: 'Reply to Conversation in Intercom', + description: 'Reply to a conversation as an admin in Intercom', + version: '1.0.0', + + params: { + accessToken: { + type: 'string', + required: true, + visibility: 'hidden', + description: 'Intercom API access token', + }, + conversationId: { + type: 'string', + required: true, + visibility: 'user-only', + description: 'Conversation ID to reply to', + }, + message_type: { + type: 'string', + required: true, + visibility: 'user-only', + description: 'Message type: "comment" or "note"', + }, + body: { + type: 'string', + required: true, + visibility: 'user-only', + description: 'The text body of the reply', + }, + admin_id: { + type: 'string', + required: true, + visibility: 'user-only', + description: 'The ID of the admin authoring the reply', + }, + attachment_urls: { + type: 'string', + required: false, + visibility: 'user-only', + description: 'Comma-separated list of image URLs (max 10)', + }, + }, + + request: { + url: (params) => buildIntercomUrl(`/conversations/${params.conversationId}/reply`), + method: 'POST', + headers: (params) => ({ + Authorization: `Bearer ${params.accessToken}`, + 'Content-Type': 'application/json', + 'Intercom-Version': '2.14', + }), + body: (params) => { + const reply: any = { + message_type: params.message_type, + type: 'admin', + body: params.body, + } + + if (params.admin_id) reply.admin_id = params.admin_id + + if (params.attachment_urls) { + reply.attachment_urls = params.attachment_urls + .split(',') + .map((url) => url.trim()) + .slice(0, 10) + } + + return reply + }, + }, + + transformResponse: async (response: Response) => { + if (!response.ok) { + const data = await response.json() + handleIntercomError(data, response.status, 'reply_conversation') + } + + const data = await response.json() + + return { + success: true, + output: { + conversation: data, + metadata: { + operation: 'reply_conversation' as const, + conversationId: data.id, + }, + success: true, + }, + } + }, + + outputs: { + success: { type: 'boolean', description: 'Operation success status' }, + output: { + type: 'object', + description: 'Updated conversation with reply', + properties: { + conversation: { type: 'object', description: 'Updated conversation object' }, + metadata: { type: 'object', description: 'Operation metadata' }, + success: { type: 'boolean', description: 'Operation success' }, + }, + }, + }, +} diff --git a/apps/sim/tools/intercom/search_contacts.ts b/apps/sim/tools/intercom/search_contacts.ts new file mode 100644 index 0000000000..f6e0be8a0a --- /dev/null +++ b/apps/sim/tools/intercom/search_contacts.ts @@ -0,0 +1,130 @@ +import { createLogger } from '@/lib/logs/console/logger' +import type { ToolConfig } from '@/tools/types' +import { buildIntercomUrl, handleIntercomError } from './types' + +const logger = createLogger('IntercomSearchContacts') + +export interface IntercomSearchContactsParams { + accessToken: string + query: string + per_page?: number + starting_after?: string +} + +export interface IntercomSearchContactsResponse { + success: boolean + output: { + contacts: any[] + pages?: any + metadata: { + operation: 'search_contacts' + total_count?: number + } + success: boolean + } +} + +export const intercomSearchContactsTool: ToolConfig< + IntercomSearchContactsParams, + IntercomSearchContactsResponse +> = { + id: 'intercom_search_contacts', + name: 'Search Contacts in Intercom', + description: 'Search for contacts in Intercom using a query', + version: '1.0.0', + + params: { + accessToken: { + type: 'string', + required: true, + visibility: 'hidden', + description: 'Intercom API access token', + }, + query: { + type: 'string', + required: true, + visibility: 'user-only', + description: + 'Search query (e.g., {"field":"email","operator":"=","value":"user@example.com"})', + }, + per_page: { + type: 'number', + required: false, + visibility: 'user-only', + description: 'Number of results per page (max: 150)', + }, + starting_after: { + type: 'string', + required: false, + visibility: 'user-only', + description: 'Cursor for pagination', + }, + }, + + request: { + url: () => buildIntercomUrl('/contacts/search'), + method: 'POST', + headers: (params) => ({ + Authorization: `Bearer ${params.accessToken}`, + 'Content-Type': 'application/json', + 'Intercom-Version': '2.14', + }), + body: (params) => { + let query + try { + query = JSON.parse(params.query) + } catch (error) { + // If not JSON, treat as simple text search + query = { + field: 'name', + operator: '~', + value: params.query, + } + } + + const body: any = { query } + + if (params.per_page) body.pagination = { per_page: params.per_page } + if (params.starting_after) + body.pagination = { ...body.pagination, starting_after: params.starting_after } + + return body + }, + }, + + transformResponse: async (response: Response) => { + if (!response.ok) { + const data = await response.json() + handleIntercomError(data, response.status, 'search_contacts') + } + + const data = await response.json() + + return { + success: true, + output: { + contacts: data.data || [], + pages: data.pages, + metadata: { + operation: 'search_contacts' as const, + total_count: data.total_count, + }, + success: true, + }, + } + }, + + outputs: { + success: { type: 'boolean', description: 'Operation success status' }, + output: { + type: 'object', + description: 'Search results', + properties: { + contacts: { type: 'array', description: 'Array of matching contact objects' }, + pages: { type: 'object', description: 'Pagination information' }, + metadata: { type: 'object', description: 'Operation metadata' }, + success: { type: 'boolean', description: 'Operation success' }, + }, + }, + }, +} diff --git a/apps/sim/tools/intercom/search_conversations.ts b/apps/sim/tools/intercom/search_conversations.ts new file mode 100644 index 0000000000..864f42ef97 --- /dev/null +++ b/apps/sim/tools/intercom/search_conversations.ts @@ -0,0 +1,129 @@ +import { createLogger } from '@/lib/logs/console/logger' +import type { ToolConfig } from '@/tools/types' +import { buildIntercomUrl, handleIntercomError } from './types' + +const logger = createLogger('IntercomSearchConversations') + +export interface IntercomSearchConversationsParams { + accessToken: string + query: string + per_page?: number + starting_after?: string +} + +export interface IntercomSearchConversationsResponse { + success: boolean + output: { + conversations: any[] + pages?: any + metadata: { + operation: 'search_conversations' + total_count?: number + } + success: boolean + } +} + +export const intercomSearchConversationsTool: ToolConfig< + IntercomSearchConversationsParams, + IntercomSearchConversationsResponse +> = { + id: 'intercom_search_conversations', + name: 'Search Conversations in Intercom', + description: 'Search for conversations in Intercom using a query', + version: '1.0.0', + + params: { + accessToken: { + type: 'string', + required: true, + visibility: 'hidden', + description: 'Intercom API access token', + }, + query: { + type: 'string', + required: true, + visibility: 'user-only', + description: 'Search query as JSON object', + }, + per_page: { + type: 'number', + required: false, + visibility: 'user-only', + description: 'Number of results per page (max: 150)', + }, + starting_after: { + type: 'string', + required: false, + visibility: 'user-only', + description: 'Cursor for pagination', + }, + }, + + request: { + url: () => buildIntercomUrl('/conversations/search'), + method: 'POST', + headers: (params) => ({ + Authorization: `Bearer ${params.accessToken}`, + 'Content-Type': 'application/json', + 'Intercom-Version': '2.14', + }), + body: (params) => { + let query + try { + query = JSON.parse(params.query) + } catch (error) { + logger.warn('Failed to parse search query, using default', { error }) + query = { + field: 'updated_at', + operator: '>', + value: Math.floor(Date.now() / 1000) - 86400, // Last 24 hours + } + } + + const body: any = { query } + + if (params.per_page) body.pagination = { per_page: params.per_page } + if (params.starting_after) + body.pagination = { ...body.pagination, starting_after: params.starting_after } + + return body + }, + }, + + transformResponse: async (response: Response) => { + if (!response.ok) { + const data = await response.json() + handleIntercomError(data, response.status, 'search_conversations') + } + + const data = await response.json() + + return { + success: true, + output: { + conversations: data.conversations || [], + pages: data.pages, + metadata: { + operation: 'search_conversations' as const, + total_count: data.total_count, + }, + success: true, + }, + } + }, + + outputs: { + success: { type: 'boolean', description: 'Operation success status' }, + output: { + type: 'object', + description: 'Search results', + properties: { + conversations: { type: 'array', description: 'Array of matching conversation objects' }, + pages: { type: 'object', description: 'Pagination information' }, + metadata: { type: 'object', description: 'Operation metadata' }, + success: { type: 'boolean', description: 'Operation success' }, + }, + }, + }, +} diff --git a/apps/sim/tools/intercom/types.ts b/apps/sim/tools/intercom/types.ts new file mode 100644 index 0000000000..0059700c8c --- /dev/null +++ b/apps/sim/tools/intercom/types.ts @@ -0,0 +1,47 @@ +import { createLogger } from '@/lib/logs/console/logger' + +const logger = createLogger('Intercom') + +// Base params for Intercom API +export interface IntercomBaseParams { + accessToken: string // OAuth token or API token (hidden) +} + +export interface IntercomPaginationParams { + per_page?: number + starting_after?: string // Cursor for pagination +} + +export interface IntercomPagingInfo { + next?: { + page: number + starting_after: string + } | null + total_count?: number +} + +export interface IntercomResponse { + success: boolean + output: { + data?: T + pages?: IntercomPagingInfo + metadata: { + operation: string + [key: string]: any + } + success: boolean + } +} + +// Helper function to build Intercom API URLs +export function buildIntercomUrl(path: string): string { + return `https://api.intercom.io${path}` +} + +// Helper function for consistent error handling +export function handleIntercomError(data: any, status: number, operation: string): never { + logger.error(`Intercom API request failed for ${operation}`, { data, status }) + + const errorMessage = data.errors?.[0]?.message || data.error || data.message || 'Unknown error' + throw new Error(`Intercom ${operation} failed: ${errorMessage}`) +} diff --git a/apps/sim/tools/intercom/update_contact.ts b/apps/sim/tools/intercom/update_contact.ts new file mode 100644 index 0000000000..1fb3c7b042 --- /dev/null +++ b/apps/sim/tools/intercom/update_contact.ts @@ -0,0 +1,177 @@ +import { createLogger } from '@/lib/logs/console/logger' +import type { ToolConfig } from '@/tools/types' +import { buildIntercomUrl, handleIntercomError } from './types' + +const logger = createLogger('IntercomUpdateContact') + +export interface IntercomUpdateContactParams { + accessToken: string + contactId: string + email?: string + phone?: string + name?: string + avatar?: string + signed_up_at?: number + last_seen_at?: number + owner_id?: string + unsubscribed_from_emails?: boolean + custom_attributes?: string +} + +export interface IntercomUpdateContactResponse { + success: boolean + output: { + contact: any + metadata: { + operation: 'update_contact' + contactId: string + } + success: boolean + } +} + +export const intercomUpdateContactTool: ToolConfig< + IntercomUpdateContactParams, + IntercomUpdateContactResponse +> = { + id: 'intercom_update_contact', + name: 'Update Contact in Intercom', + description: 'Update an existing contact in Intercom', + version: '1.0.0', + + params: { + accessToken: { + type: 'string', + required: true, + visibility: 'hidden', + description: 'Intercom API access token', + }, + contactId: { + type: 'string', + required: true, + visibility: 'user-only', + description: 'Contact ID to update', + }, + email: { + type: 'string', + required: false, + visibility: 'user-only', + description: "The contact's email address", + }, + phone: { + type: 'string', + required: false, + visibility: 'user-only', + description: "The contact's phone number", + }, + name: { + type: 'string', + required: false, + visibility: 'user-only', + description: "The contact's name", + }, + avatar: { + type: 'string', + required: false, + visibility: 'user-only', + description: 'An avatar image URL for the contact', + }, + signed_up_at: { + type: 'number', + required: false, + visibility: 'user-only', + description: 'The time the user signed up as a Unix timestamp', + }, + last_seen_at: { + type: 'number', + required: false, + visibility: 'user-only', + description: 'The time the user was last seen as a Unix timestamp', + }, + owner_id: { + type: 'string', + required: false, + visibility: 'user-only', + description: 'The id of an admin that has been assigned account ownership of the contact', + }, + unsubscribed_from_emails: { + type: 'boolean', + required: false, + visibility: 'user-only', + description: 'Whether the contact is unsubscribed from emails', + }, + custom_attributes: { + type: 'string', + required: false, + visibility: 'user-only', + description: 'Custom attributes as JSON object (e.g., {"attribute_name": "value"})', + }, + }, + + request: { + url: (params) => buildIntercomUrl(`/contacts/${params.contactId}`), + method: 'PUT', + headers: (params) => ({ + Authorization: `Bearer ${params.accessToken}`, + 'Content-Type': 'application/json', + 'Intercom-Version': '2.14', + }), + body: (params) => { + const contact: any = {} + + if (params.email) contact.email = params.email + if (params.phone) contact.phone = params.phone + if (params.name) contact.name = params.name + if (params.avatar) contact.avatar = params.avatar + if (params.signed_up_at) contact.signed_up_at = params.signed_up_at + if (params.last_seen_at) contact.last_seen_at = params.last_seen_at + if (params.owner_id) contact.owner_id = params.owner_id + if (params.unsubscribed_from_emails !== undefined) + contact.unsubscribed_from_emails = params.unsubscribed_from_emails + + if (params.custom_attributes) { + try { + contact.custom_attributes = JSON.parse(params.custom_attributes) + } catch (error) { + logger.warn('Failed to parse custom attributes', { error }) + } + } + + return contact + }, + }, + + transformResponse: async (response: Response) => { + if (!response.ok) { + const data = await response.json() + handleIntercomError(data, response.status, 'update_contact') + } + + const data = await response.json() + + return { + success: true, + output: { + contact: data, + metadata: { + operation: 'update_contact' as const, + contactId: data.id, + }, + success: true, + }, + } + }, + + outputs: { + success: { type: 'boolean', description: 'Operation success status' }, + output: { + type: 'object', + description: 'Updated contact data', + properties: { + contact: { type: 'object', description: 'Updated contact object' }, + metadata: { type: 'object', description: 'Operation metadata' }, + success: { type: 'boolean', description: 'Operation success' }, + }, + }, + }, +} diff --git a/apps/sim/tools/mailchimp/add_member.ts b/apps/sim/tools/mailchimp/add_member.ts new file mode 100644 index 0000000000..3d5f124af5 --- /dev/null +++ b/apps/sim/tools/mailchimp/add_member.ts @@ -0,0 +1,142 @@ +import { createLogger } from '@/lib/logs/console/logger' +import type { ToolConfig } from '@/tools/types' +import { buildMailchimpUrl, handleMailchimpError } from './types' + +const logger = createLogger('MailchimpAddMember') + +export interface MailchimpAddMemberParams { + apiKey: string + listId: string + emailAddress: string + status: string + mergeFields?: string + interests?: string +} + +export interface MailchimpAddMemberResponse { + success: boolean + output: { + member: any + metadata: { + operation: 'add_member' + subscriberHash: string + } + success: boolean + } +} + +export const mailchimpAddMemberTool: ToolConfig< + MailchimpAddMemberParams, + MailchimpAddMemberResponse +> = { + id: 'mailchimp_add_member', + name: 'Add Member to Mailchimp Audience', + description: 'Add a new member to a Mailchimp audience', + version: '1.0.0', + + params: { + apiKey: { + type: 'string', + required: true, + visibility: 'hidden', + description: 'Mailchimp API key with server prefix', + }, + listId: { + type: 'string', + required: true, + visibility: 'user-only', + description: 'The unique ID for the list', + }, + emailAddress: { + type: 'string', + required: true, + visibility: 'user-only', + description: 'Email address for the member', + }, + status: { + type: 'string', + required: true, + visibility: 'user-only', + description: 'Subscriber status (subscribed, unsubscribed, cleaned, pending)', + }, + mergeFields: { + type: 'string', + required: false, + visibility: 'user-only', + description: 'Merge fields as JSON object (e.g., {"FNAME": "John", "LNAME": "Doe"})', + }, + interests: { + type: 'string', + required: false, + visibility: 'user-only', + description: 'Interests as JSON object (e.g., {"interest_id": true})', + }, + }, + + request: { + url: (params) => buildMailchimpUrl(params.apiKey, `/lists/${params.listId}/members`), + method: 'POST', + headers: (params) => ({ + Authorization: `Bearer ${params.apiKey}`, + 'Content-Type': 'application/json', + }), + body: (params) => { + const body: any = { + email_address: params.emailAddress, + status: params.status, + } + + if (params.mergeFields) { + try { + body.merge_fields = JSON.parse(params.mergeFields) + } catch (error) { + logger.warn('Failed to parse merge fields', { error }) + } + } + + if (params.interests) { + try { + body.interests = JSON.parse(params.interests) + } catch (error) { + logger.warn('Failed to parse interests', { error }) + } + } + + return body + }, + }, + + transformResponse: async (response: Response) => { + if (!response.ok) { + const data = await response.json() + handleMailchimpError(data, response.status, 'add_member') + } + + const data = await response.json() + + return { + success: true, + output: { + member: data, + metadata: { + operation: 'add_member' as const, + subscriberHash: data.id, + }, + success: true, + }, + } + }, + + outputs: { + success: { type: 'boolean', description: 'Operation success status' }, + output: { + type: 'object', + description: 'Added member data', + properties: { + member: { type: 'object', description: 'Added member object' }, + metadata: { type: 'object', description: 'Operation metadata' }, + success: { type: 'boolean', description: 'Operation success' }, + }, + }, + }, +} diff --git a/apps/sim/tools/mailchimp/add_member_tags.ts b/apps/sim/tools/mailchimp/add_member_tags.ts new file mode 100644 index 0000000000..18901d5f9f --- /dev/null +++ b/apps/sim/tools/mailchimp/add_member_tags.ts @@ -0,0 +1,114 @@ +import { createLogger } from '@/lib/logs/console/logger' +import type { ToolConfig } from '@/tools/types' +import { buildMailchimpUrl, handleMailchimpError } from './types' + +const logger = createLogger('MailchimpAddMemberTags') + +export interface MailchimpAddMemberTagsParams { + apiKey: string + listId: string + subscriberHash: string + tags: string +} + +export interface MailchimpAddMemberTagsResponse { + success: boolean + output: { + metadata: { + operation: 'add_member_tags' + subscriberHash: string + } + success: boolean + } +} + +export const mailchimpAddMemberTagsTool: ToolConfig< + MailchimpAddMemberTagsParams, + MailchimpAddMemberTagsResponse +> = { + id: 'mailchimp_add_member_tags', + name: 'Add Tags to Member in Mailchimp', + description: 'Add tags to a member in a Mailchimp audience', + version: '1.0.0', + + params: { + apiKey: { + type: 'string', + required: true, + visibility: 'hidden', + description: 'Mailchimp API key with server prefix', + }, + listId: { + type: 'string', + required: true, + visibility: 'user-only', + description: 'The unique ID for the list', + }, + subscriberHash: { + type: 'string', + required: true, + visibility: 'user-only', + description: "The MD5 hash of the lowercase version of the list member's email address", + }, + tags: { + type: 'string', + required: true, + visibility: 'user-only', + description: + 'Tags as JSON array (e.g., [{"name": "tag1", "status": "active"}, {"name": "tag2", "status": "active"}])', + }, + }, + + request: { + url: (params) => + buildMailchimpUrl( + params.apiKey, + `/lists/${params.listId}/members/${params.subscriberHash}/tags` + ), + method: 'POST', + headers: (params) => ({ + Authorization: `Bearer ${params.apiKey}`, + 'Content-Type': 'application/json', + }), + body: (params) => { + let tags = [] + try { + tags = JSON.parse(params.tags) + } catch (error) { + logger.warn('Failed to parse tags', { error }) + } + + return { tags } + }, + }, + + transformResponse: async (response: Response) => { + if (!response.ok) { + const data = await response.json() + handleMailchimpError(data, response.status, 'add_member_tags') + } + + return { + success: true, + output: { + metadata: { + operation: 'add_member_tags' as const, + subscriberHash: '', + }, + success: true, + }, + } + }, + + outputs: { + success: { type: 'boolean', description: 'Operation success status' }, + output: { + type: 'object', + description: 'Tag addition confirmation', + properties: { + metadata: { type: 'object', description: 'Operation metadata' }, + success: { type: 'boolean', description: 'Operation success' }, + }, + }, + }, +} diff --git a/apps/sim/tools/mailchimp/add_or_update_member.ts b/apps/sim/tools/mailchimp/add_or_update_member.ts new file mode 100644 index 0000000000..94b12d8113 --- /dev/null +++ b/apps/sim/tools/mailchimp/add_or_update_member.ts @@ -0,0 +1,150 @@ +import { createLogger } from '@/lib/logs/console/logger' +import type { ToolConfig } from '@/tools/types' +import { buildMailchimpUrl, handleMailchimpError } from './types' + +const logger = createLogger('MailchimpAddOrUpdateMember') + +export interface MailchimpAddOrUpdateMemberParams { + apiKey: string + listId: string + subscriberHash: string + emailAddress: string + statusIfNew: string + mergeFields?: string + interests?: string +} + +export interface MailchimpAddOrUpdateMemberResponse { + success: boolean + output: { + member: any + metadata: { + operation: 'add_or_update_member' + subscriberHash: string + } + success: boolean + } +} + +export const mailchimpAddOrUpdateMemberTool: ToolConfig< + MailchimpAddOrUpdateMemberParams, + MailchimpAddOrUpdateMemberResponse +> = { + id: 'mailchimp_add_or_update_member', + name: 'Add or Update Member in Mailchimp Audience', + description: 'Add a new member or update an existing member in a Mailchimp audience (upsert)', + version: '1.0.0', + + params: { + apiKey: { + type: 'string', + required: true, + visibility: 'hidden', + description: 'Mailchimp API key with server prefix', + }, + listId: { + type: 'string', + required: true, + visibility: 'user-only', + description: 'The unique ID for the list', + }, + subscriberHash: { + type: 'string', + required: true, + visibility: 'user-only', + description: "The MD5 hash of the lowercase version of the list member's email address", + }, + emailAddress: { + type: 'string', + required: true, + visibility: 'user-only', + description: 'Email address for the member', + }, + statusIfNew: { + type: 'string', + required: true, + visibility: 'user-only', + description: 'Subscriber status if new member (subscribed, unsubscribed, cleaned, pending)', + }, + mergeFields: { + type: 'string', + required: false, + visibility: 'user-only', + description: 'Merge fields as JSON object (e.g., {"FNAME": "John", "LNAME": "Doe"})', + }, + interests: { + type: 'string', + required: false, + visibility: 'user-only', + description: 'Interests as JSON object (e.g., {"interest_id": true})', + }, + }, + + request: { + url: (params) => + buildMailchimpUrl(params.apiKey, `/lists/${params.listId}/members/${params.subscriberHash}`), + method: 'PUT', + headers: (params) => ({ + Authorization: `Bearer ${params.apiKey}`, + 'Content-Type': 'application/json', + }), + body: (params) => { + const body: any = { + email_address: params.emailAddress, + status_if_new: params.statusIfNew, + } + + if (params.mergeFields) { + try { + body.merge_fields = JSON.parse(params.mergeFields) + } catch (error) { + logger.warn('Failed to parse merge fields', { error }) + } + } + + if (params.interests) { + try { + body.interests = JSON.parse(params.interests) + } catch (error) { + logger.warn('Failed to parse interests', { error }) + } + } + + return body + }, + }, + + transformResponse: async (response: Response) => { + if (!response.ok) { + const data = await response.json() + handleMailchimpError(data, response.status, 'add_or_update_member') + } + + const data = await response.json() + + return { + success: true, + output: { + member: data, + metadata: { + operation: 'add_or_update_member' as const, + subscriberHash: data.id, + }, + success: true, + }, + } + }, + + outputs: { + success: { type: 'boolean', description: 'Operation success status' }, + output: { + type: 'object', + description: 'Member data', + properties: { + member: { type: 'object', description: 'Member object' }, + metadata: { type: 'object', description: 'Operation metadata' }, + success: { type: 'boolean', description: 'Operation success' }, + }, + }, + }, +} diff --git a/apps/sim/tools/mailchimp/add_segment_member.ts b/apps/sim/tools/mailchimp/add_segment_member.ts new file mode 100644 index 0000000000..c5ea3d686a --- /dev/null +++ b/apps/sim/tools/mailchimp/add_segment_member.ts @@ -0,0 +1,111 @@ +import { createLogger } from '@/lib/logs/console/logger' +import type { ToolConfig } from '@/tools/types' +import { buildMailchimpUrl, handleMailchimpError } from './types' + +const logger = createLogger('MailchimpAddSegmentMember') + +export interface MailchimpAddSegmentMemberParams { + apiKey: string + listId: string + segmentId: string + emailAddress: string +} + +export interface MailchimpAddSegmentMemberResponse { + success: boolean + output: { + member: any + metadata: { + operation: 'add_segment_member' + segmentId: string + } + success: boolean + } +} + +export const mailchimpAddSegmentMemberTool: ToolConfig< + MailchimpAddSegmentMemberParams, + MailchimpAddSegmentMemberResponse +> = { + id: 'mailchimp_add_segment_member', + name: 'Add Member to Segment in Mailchimp', + description: 'Add a member to a specific segment in a Mailchimp audience', + version: '1.0.0', + + params: { + apiKey: { + type: 'string', + required: true, + visibility: 'hidden', + description: 'Mailchimp API key with server prefix', + }, + listId: { + type: 'string', + required: true, + visibility: 'user-only', + description: 'The unique ID for the list', + }, + segmentId: { + type: 'string', + required: true, + visibility: 'user-only', + description: 'The unique ID for the segment', + }, + emailAddress: { + type: 'string', + required: true, + visibility: 'user-only', + description: 'Email address of the member', + }, + }, + + request: { + url: (params) => + buildMailchimpUrl( + params.apiKey, + `/lists/${params.listId}/segments/${params.segmentId}/members` + ), + method: 'POST', + headers: (params) => ({ + Authorization: `Bearer ${params.apiKey}`, + 'Content-Type': 'application/json', + }), + body: (params) => ({ + email_address: params.emailAddress, + }), + }, + + transformResponse: async (response: Response) => { + if (!response.ok) { + const data = await response.json() + handleMailchimpError(data, response.status, 'add_segment_member') + } + + const data = await response.json() + + return { + success: true, + output: { + member: data, + metadata: { + operation: 'add_segment_member' as const, + segmentId: '', + }, + success: true, + }, + } + }, + + outputs: { + success: { type: 'boolean', description: 'Operation success status' }, + output: { + type: 'object', + description: 'Added member data', + properties: { + member: { type: 'object', description: 'Added member object' }, + metadata: { type: 'object', description: 'Operation metadata' }, + success: { type: 'boolean', description: 'Operation success' }, + }, + }, + }, +} diff --git a/apps/sim/tools/mailchimp/add_subscriber_to_automation.ts b/apps/sim/tools/mailchimp/add_subscriber_to_automation.ts new file mode 100644 index 0000000000..81152a8985 --- /dev/null +++ b/apps/sim/tools/mailchimp/add_subscriber_to_automation.ts @@ -0,0 +1,113 @@ +import { createLogger } from '@/lib/logs/console/logger' +import type { ToolConfig } from '@/tools/types' +import { buildMailchimpUrl, handleMailchimpError } from './types' + +const logger = createLogger('MailchimpAddSubscriberToAutomation') + +export interface MailchimpAddSubscriberToAutomationParams { + apiKey: string + workflowId: string + workflowEmailId: string + emailAddress: string +} + +export interface MailchimpAddSubscriberToAutomationResponse { + success: boolean + output: { + subscriber: any + metadata: { + operation: 'add_subscriber_to_automation' + workflowId: string + workflowEmailId: string + } + success: boolean + } +} + +export const mailchimpAddSubscriberToAutomationTool: ToolConfig< + MailchimpAddSubscriberToAutomationParams, + MailchimpAddSubscriberToAutomationResponse +> = { + id: 'mailchimp_add_subscriber_to_automation', + name: 'Add Subscriber to Automation in Mailchimp', + description: 'Manually add a subscriber to a workflow email queue', + version: '1.0.0', + + params: { + apiKey: { + type: 'string', + required: true, + visibility: 'hidden', + description: 'Mailchimp API key with server prefix', + }, + workflowId: { + type: 'string', + required: true, + visibility: 'user-only', + description: 'The unique ID for the automation workflow', + }, + workflowEmailId: { + type: 'string', + required: true, + visibility: 'user-only', + description: 'The unique ID for the workflow email', + }, + emailAddress: { + type: 'string', + required: true, + visibility: 'user-only', + description: 'Email address of the subscriber', + }, + }, + + request: { + url: (params) => + buildMailchimpUrl( + params.apiKey, + `/automations/${params.workflowId}/emails/${params.workflowEmailId}/queue` + ), + method: 'POST', + headers: (params) => ({ + Authorization: `Bearer ${params.apiKey}`, + 'Content-Type': 'application/json', + }), + body: (params) => ({ + email_address: params.emailAddress, + }), + }, + + transformResponse: async (response: Response) => { + if (!response.ok) { + const data = await response.json() + handleMailchimpError(data, response.status, 'add_subscriber_to_automation') + } + + const data = await response.json() + + return { + success: true, + output: { + subscriber: data, + metadata: { + operation: 'add_subscriber_to_automation' as const, + workflowId: '', + workflowEmailId: '', + }, + success: true, + }, + } + }, + + outputs: { + success: { type: 'boolean', description: 'Operation success status' }, + output: { + type: 'object', + description: 'Subscriber queue data', + properties: { + subscriber: { type: 'object', description: 'Subscriber object' }, + metadata: { type: 'object', description: 'Operation metadata' }, + success: { type: 'boolean', description: 'Operation success' }, + }, + }, + }, +} diff --git a/apps/sim/tools/mailchimp/archive_member.ts b/apps/sim/tools/mailchimp/archive_member.ts new file mode 100644 index 0000000000..01378444ab --- /dev/null +++ b/apps/sim/tools/mailchimp/archive_member.ts @@ -0,0 +1,96 @@ +import { createLogger } from '@/lib/logs/console/logger' +import type { ToolConfig } from '@/tools/types' +import { buildMailchimpUrl, handleMailchimpError } from './types' + +const logger = createLogger('MailchimpArchiveMember') + +export interface MailchimpArchiveMemberParams { + apiKey: string + listId: string + subscriberHash: string +} + +export interface MailchimpArchiveMemberResponse { + success: boolean + output: { + metadata: { + operation: 'archive_member' + subscriberHash: string + } + success: boolean + } +} + +export const mailchimpArchiveMemberTool: ToolConfig< + MailchimpArchiveMemberParams, + MailchimpArchiveMemberResponse +> = { + id: 'mailchimp_archive_member', + name: 'Archive Member from Mailchimp Audience', + description: 'Permanently archive (delete) a member from a Mailchimp audience', + version: '1.0.0', + + params: { + apiKey: { + type: 'string', + required: true, + visibility: 'hidden', + description: 'Mailchimp API key with server prefix', + }, + listId: { + type: 'string', + required: true, + visibility: 'user-only', + description: 'The unique ID for the list', + }, + subscriberHash: { + type: 'string', + required: true, + visibility: 'user-only', + description: "The MD5 hash of the lowercase version of the list member's email address", + }, + }, + + request: { + url: (params) => + buildMailchimpUrl( + params.apiKey, + `/lists/${params.listId}/members/${params.subscriberHash}/actions/delete-permanent` + ), + method: 'DELETE', + headers: (params) => ({ + Authorization: `Bearer ${params.apiKey}`, + 'Content-Type': 'application/json', + }), + }, + + transformResponse: async (response: Response) => { + if (!response.ok) { + const data = await response.json() + handleMailchimpError(data, response.status, 'archive_member') + } + + return { + success: true, + output: { + metadata: { + operation: 'archive_member' as const, + subscriberHash: '', + }, + success: true, + }, + } + }, + + outputs: { + success: { type: 'boolean', description: 'Operation success status' }, + output: { + type: 'object', + description: 'Archive confirmation', + properties: { + metadata: { type: 'object', description: 'Operation metadata' }, + success: { type: 'boolean', description: 'Operation success' }, + }, + }, + }, +} diff --git a/apps/sim/tools/mailchimp/create_audience.ts b/apps/sim/tools/mailchimp/create_audience.ts new file mode 100644 index 0000000000..1cf79a83b3 --- /dev/null +++ b/apps/sim/tools/mailchimp/create_audience.ts @@ -0,0 +1,145 @@ +import { createLogger } from '@/lib/logs/console/logger' +import type { ToolConfig } from '@/tools/types' +import { buildMailchimpUrl, handleMailchimpError } from './types' + +const logger = createLogger('MailchimpCreateAudience') + +export interface MailchimpCreateAudienceParams { + apiKey: string + audienceName: string + contact: string + permissionReminder: string + campaignDefaults: string + emailTypeOption: string +} + +export interface MailchimpCreateAudienceResponse { + success: boolean + output: { + list: any + metadata: { + operation: 'create_audience' + listId: string + } + success: boolean + } +} + +export const mailchimpCreateAudienceTool: ToolConfig< + MailchimpCreateAudienceParams, + MailchimpCreateAudienceResponse +> = { + id: 'mailchimp_create_audience', + name: 'Create Audience in Mailchimp', + description: 'Create a new audience (list) in Mailchimp', + version: '1.0.0', + + params: { + apiKey: { + type: 'string', + required: true, + visibility: 'hidden', + description: 'Mailchimp API key with server prefix', + }, + audienceName: { + type: 'string', + required: true, + visibility: 'user-only', + description: 'The name of the list', + }, + contact: { + type: 'string', + required: true, + visibility: 'user-only', + description: + 'Contact information as JSON (e.g., {"company": "Acme Inc", "address1": "123 Main St", "city": "Atlanta", "state": "GA", "zip": "30308", "country": "US"})', + }, + permissionReminder: { + type: 'string', + required: true, + visibility: 'user-only', + description: 'Permission reminder text (why subscribers are on your list)', + }, + campaignDefaults: { + type: 'string', + required: true, + visibility: 'user-only', + description: + 'Default campaign settings as JSON (e.g., {"from_name": "John", "from_email": "john@example.com", "subject": "Newsletter", "language": "en"})', + }, + emailTypeOption: { + type: 'string', + required: true, + visibility: 'user-only', + description: 'Whether the list supports multiple formats (true/false)', + }, + }, + + request: { + url: (params) => buildMailchimpUrl(params.apiKey, '/lists'), + method: 'POST', + headers: (params) => ({ + Authorization: `Bearer ${params.apiKey}`, + 'Content-Type': 'application/json', + }), + body: (params) => { + const body: any = { + name: params.audienceName, + permission_reminder: params.permissionReminder, + email_type_option: params.emailTypeOption === 'true', + } + + if (params.contact) { + try { + body.contact = JSON.parse(params.contact) + } catch (error) { + logger.warn('Failed to parse contact', { error }) + } + } + + if (params.campaignDefaults) { + try { + body.campaign_defaults = JSON.parse(params.campaignDefaults) + } catch (error) { + logger.warn('Failed to parse campaign defaults', { error }) + } + } + + return body + }, + }, + + transformResponse: async (response: Response) => { + if (!response.ok) { + const data = await response.json() + handleMailchimpError(data, response.status, 'create_audience') + } + + const data = await response.json() + + return { + success: true, + output: { + list: data, + metadata: { + operation: 'create_audience' as const, + listId: data.id, + }, + success: true, + }, + } + }, + + outputs: { + success: { type: 'boolean', description: 'Operation success status' }, + output: { + type: 'object', + description: 'Created audience data', + properties: { + list: { type: 'object', description: 'Created audience/list object' }, + metadata: { type: 'object', description: 'Operation metadata' }, + success: { type: 'boolean', description: 'Operation success' }, + }, + }, + }, +} diff --git a/apps/sim/tools/mailchimp/create_batch_operation.ts b/apps/sim/tools/mailchimp/create_batch_operation.ts new file mode 100644 index 0000000000..df792ee6df --- /dev/null +++ b/apps/sim/tools/mailchimp/create_batch_operation.ts @@ -0,0 +1,101 @@ +import { createLogger } from '@/lib/logs/console/logger' +import type { ToolConfig } from '@/tools/types' +import { buildMailchimpUrl, handleMailchimpError } from './types' + +const logger = createLogger('MailchimpCreateBatchOperation') + +export interface MailchimpCreateBatchOperationParams { + apiKey: string + operations: string +} + +export interface MailchimpCreateBatchOperationResponse { + success: boolean + output: { + batch: any + metadata: { + operation: 'create_batch_operation' + batchId: string + } + success: boolean + } +} + +export const mailchimpCreateBatchOperationTool: ToolConfig< + MailchimpCreateBatchOperationParams, + MailchimpCreateBatchOperationResponse +> = { + id: 'mailchimp_create_batch_operation', + name: 'Create Batch Operation in Mailchimp', + description: 'Create a new batch operation in Mailchimp', + version: '1.0.0', + + params: { + apiKey: { + type: 'string', + required: true, + visibility: 'hidden', + description: 'Mailchimp API key with server prefix', + }, + operations: { + type: 'string', + required: true, + visibility: 'user-only', + description: + 'Operations as JSON array (e.g., [{"method": "POST", "path": "/lists", "body": "{\\"name\\": \\"Test\\"}"}])', + }, + }, + + request: { + url: (params) => buildMailchimpUrl(params.apiKey, '/batches'), + method: 'POST', + headers: (params) => ({ + Authorization: `Bearer ${params.apiKey}`, + 'Content-Type': 'application/json', + }), + body: (params) => { + let operations = [] + try { + operations = JSON.parse(params.operations) + } catch (error) { + logger.warn('Failed to parse operations', { error }) + } + + return { operations } + }, + }, + + transformResponse: async (response: Response) => { + if (!response.ok) { + const data = await response.json() + handleMailchimpError(data, response.status, 'create_batch_operation') + } + + const data = await response.json() + + return { + success: true, + output: { + batch: data, + metadata: { + operation: 'create_batch_operation' as const, + batchId: data.id, + }, + success: true, + }, + } + }, + + outputs: { + success: { type: 'boolean', description: 'Operation success status' }, + output: { + type: 'object', + description: 'Created batch operation data', + properties: { + batch: { type: 'object', description: 'Created batch operation object' }, + metadata: { type: 'object', description: 'Operation metadata' }, + success: { type: 'boolean', description: 'Operation success' }, + }, + }, + }, +} diff --git a/apps/sim/tools/mailchimp/create_campaign.ts b/apps/sim/tools/mailchimp/create_campaign.ts new file mode 100644 index 0000000000..0e46c6aeae --- /dev/null +++ b/apps/sim/tools/mailchimp/create_campaign.ts @@ -0,0 +1,128 @@ +import { createLogger } from '@/lib/logs/console/logger' +import type { ToolConfig } from '@/tools/types' +import { buildMailchimpUrl, handleMailchimpError } from './types' + +const logger = createLogger('MailchimpCreateCampaign') + +export interface MailchimpCreateCampaignParams { + apiKey: string + campaignType: string + campaignSettings: string + recipients?: string +} + +export interface MailchimpCreateCampaignResponse { + success: boolean + output: { + campaign: any + metadata: { + operation: 'create_campaign' + campaignId: string + } + success: boolean + } +} + +export const mailchimpCreateCampaignTool: ToolConfig< + MailchimpCreateCampaignParams, + MailchimpCreateCampaignResponse +> = { + id: 'mailchimp_create_campaign', + name: 'Create Campaign in Mailchimp', + description: 'Create a new campaign in Mailchimp', + version: '1.0.0', + + params: { + apiKey: { + type: 'string', + required: true, + visibility: 'hidden', + description: 'Mailchimp API key with server prefix', + }, + campaignType: { + type: 'string', + required: true, + visibility: 'user-only', + description: 'Campaign type (regular, plaintext, absplit, rss, variate)', + }, + campaignSettings: { + type: 'string', + required: true, + visibility: 'user-only', + description: + 'Campaign settings as JSON (e.g., {"subject_line": "Test", "from_name": "John", "reply_to": "john@example.com"})', + }, + recipients: { + type: 'string', + required: false, + visibility: 'user-only', + description: 'Recipients as JSON (e.g., {"list_id": "abc123"})', + }, + }, + + request: { + url: (params) => buildMailchimpUrl(params.apiKey, '/campaigns'), + method: 'POST', + headers: (params) => ({ + Authorization: `Bearer ${params.apiKey}`, + 'Content-Type': 'application/json', + }), + body: (params) => { + const body: any = { + type: params.campaignType, + } + + if (params.campaignSettings) { + try { + body.settings = JSON.parse(params.campaignSettings) + } catch (error) { + logger.warn('Failed to parse campaign settings', { error }) + } + } + + if (params.recipients) { + try { + body.recipients = JSON.parse(params.recipients) + } catch (error) { + logger.warn('Failed to parse recipients', { error }) + } + } + + return body + }, + }, + + transformResponse: async (response: Response) => { + if (!response.ok) { + const data = await response.json() + handleMailchimpError(data, response.status, 'create_campaign') + } + + const data = await response.json() + + return { + success: true, + output: { + campaign: data, + metadata: { + operation: 'create_campaign' as const, + campaignId: data.id, + }, + success: true, + }, + } + }, + + outputs: { + success: { type: 'boolean', description: 'Operation success status' }, + output: { + type: 'object', + description: 'Created campaign data', + properties: { + campaign: { type: 'object', description: 'Created campaign object' }, + metadata: { type: 'object', description: 'Operation metadata' }, + success: { type: 'boolean', description: 'Operation success' }, + }, + }, + }, +} diff --git a/apps/sim/tools/mailchimp/create_interest.ts b/apps/sim/tools/mailchimp/create_interest.ts new file mode 100644 index 0000000000..2845a347c4 --- /dev/null +++ b/apps/sim/tools/mailchimp/create_interest.ts @@ -0,0 +1,111 @@ +import { createLogger } from '@/lib/logs/console/logger' +import type { ToolConfig } from '@/tools/types' +import { buildMailchimpUrl, handleMailchimpError } from './types' + +const logger = createLogger('MailchimpCreateInterest') + +export interface MailchimpCreateInterestParams { + apiKey: string + listId: string + interestCategoryId: string + interestName: string +} + +export interface MailchimpCreateInterestResponse { + success: boolean + output: { + interest: any + metadata: { + operation: 'create_interest' + interestId: string + } + success: boolean + } +} + +export const mailchimpCreateInterestTool: ToolConfig< + MailchimpCreateInterestParams, + MailchimpCreateInterestResponse +> = { + id: 'mailchimp_create_interest', + name: 'Create Interest in Mailchimp Interest Category', + description: 'Create a new interest in an interest category in a Mailchimp audience', + version: '1.0.0', + + params: { + apiKey: { + type: 'string', + required: true, + visibility: 'hidden', + description: 'Mailchimp API key with server prefix', + }, + listId: { + type: 'string', + required: true, + visibility: 'user-only', + description: 'The unique ID for the list', + }, + interestCategoryId: { + type: 'string', + required: true, + visibility: 'user-only', + description: 'The unique ID for the interest category', + }, + interestName: { + type: 'string', + required: true, + visibility: 'user-only', + description: 'The name of the interest', + }, + }, + + request: { + url: (params) => + buildMailchimpUrl( + params.apiKey, + `/lists/${params.listId}/interest-categories/${params.interestCategoryId}/interests` + ), + method: 'POST', + headers: (params) => ({ + Authorization: `Bearer ${params.apiKey}`, + 'Content-Type': 'application/json', + }), + body: (params) => ({ + name: params.interestName, + }), + }, + + transformResponse: async (response: Response) => { + if (!response.ok) { + const data = await response.json() + handleMailchimpError(data, response.status, 'create_interest') + } + + const data = await response.json() + + return { + success: true, + output: { + interest: data, + metadata: { + operation: 'create_interest' as const, + interestId: data.id, + }, + success: true, + }, + } + }, + + outputs: { + success: { type: 'boolean', description: 'Operation success status' }, + output: { + type: 'object', + description: 'Created interest data', + properties: { + interest: { type: 'object', description: 'Created interest object' }, + metadata: { type: 'object', description: 'Operation metadata' }, + success: { type: 'boolean', description: 'Operation success' }, + }, + }, + }, +} diff --git a/apps/sim/tools/mailchimp/create_interest_category.ts b/apps/sim/tools/mailchimp/create_interest_category.ts new file mode 100644 index 0000000000..2fb3b147b4 --- /dev/null +++ b/apps/sim/tools/mailchimp/create_interest_category.ts @@ -0,0 +1,109 @@ +import { createLogger } from '@/lib/logs/console/logger' +import type { ToolConfig } from '@/tools/types' +import { buildMailchimpUrl, handleMailchimpError } from './types' + +const logger = createLogger('MailchimpCreateInterestCategory') + +export interface MailchimpCreateInterestCategoryParams { + apiKey: string + listId: string + interestCategoryTitle: string + interestCategoryType: string +} + +export interface MailchimpCreateInterestCategoryResponse { + success: boolean + output: { + category: any + metadata: { + operation: 'create_interest_category' + interestCategoryId: string + } + success: boolean + } +} + +export const mailchimpCreateInterestCategoryTool: ToolConfig< + MailchimpCreateInterestCategoryParams, + MailchimpCreateInterestCategoryResponse +> = { + id: 'mailchimp_create_interest_category', + name: 'Create Interest Category in Mailchimp Audience', + description: 'Create a new interest category in a Mailchimp audience', + version: '1.0.0', + + params: { + apiKey: { + type: 'string', + required: true, + visibility: 'hidden', + description: 'Mailchimp API key with server prefix', + }, + listId: { + type: 'string', + required: true, + visibility: 'user-only', + description: 'The unique ID for the list', + }, + interestCategoryTitle: { + type: 'string', + required: true, + visibility: 'user-only', + description: 'The title of the interest category', + }, + interestCategoryType: { + type: 'string', + required: true, + visibility: 'user-only', + description: 'The type of interest category (checkboxes, dropdown, radio, hidden)', + }, + }, + + request: { + url: (params) => + buildMailchimpUrl(params.apiKey, `/lists/${params.listId}/interest-categories`), + method: 'POST', + headers: (params) => ({ + Authorization: `Bearer ${params.apiKey}`, + 'Content-Type': 'application/json', + }), + body: (params) => ({ + title: params.interestCategoryTitle, + type: params.interestCategoryType, + }), + }, + + transformResponse: async (response: Response) => { + if (!response.ok) { + const data = await response.json() + handleMailchimpError(data, response.status, 'create_interest_category') + } + + const data = await response.json() + + return { + success: true, + output: { + category: data, + metadata: { + operation: 'create_interest_category' as const, + interestCategoryId: data.id, + }, + success: true, + }, + } + }, + + outputs: { + success: { type: 'boolean', description: 'Operation success status' }, + output: { + type: 'object', + description: 'Created interest category data', + properties: { + category: { type: 'object', description: 'Created interest category object' }, + metadata: { type: 'object', description: 'Operation metadata' }, + success: { type: 'boolean', description: 'Operation success' }, + }, + }, + }, +} diff --git a/apps/sim/tools/mailchimp/create_landing_page.ts b/apps/sim/tools/mailchimp/create_landing_page.ts new file mode 100644 index 0000000000..5ed9ca3f21 --- /dev/null +++ b/apps/sim/tools/mailchimp/create_landing_page.ts @@ -0,0 +1,106 @@ +import { createLogger } from '@/lib/logs/console/logger' +import type { ToolConfig } from '@/tools/types' +import { buildMailchimpUrl, handleMailchimpError } from './types' + +const logger = createLogger('MailchimpCreateLandingPage') + +export interface MailchimpCreateLandingPageParams { + apiKey: string + landingPageType: string + landingPageTitle?: string +} + +export interface MailchimpCreateLandingPageResponse { + success: boolean + output: { + landingPage: any + metadata: { + operation: 'create_landing_page' + pageId: string + } + success: boolean + } +} + +export const mailchimpCreateLandingPageTool: ToolConfig< + MailchimpCreateLandingPageParams, + MailchimpCreateLandingPageResponse +> = { + id: 'mailchimp_create_landing_page', + name: 'Create Landing Page in Mailchimp', + description: 'Create a new landing page in Mailchimp', + version: '1.0.0', + + params: { + apiKey: { + type: 'string', + required: true, + visibility: 'hidden', + description: 'Mailchimp API key with server prefix', + }, + landingPageType: { + type: 'string', + required: true, + visibility: 'user-only', + description: 'The type of landing page (signup)', + }, + landingPageTitle: { + type: 'string', + required: false, + visibility: 'user-only', + description: 'The title of the landing page', + }, + }, + + request: { + url: (params) => buildMailchimpUrl(params.apiKey, '/landing-pages'), + method: 'POST', + headers: (params) => ({ + Authorization: `Bearer ${params.apiKey}`, + 'Content-Type': 'application/json', + }), + body: (params) => { + const body: any = { + type: params.landingPageType, + } + + if (params.landingPageTitle) body.title = params.landingPageTitle + + return body + }, + }, + + transformResponse: async (response: Response) => { + if (!response.ok) { + const data = await response.json() + handleMailchimpError(data, response.status, 'create_landing_page') + } + + const data = await response.json() + + return { + success: true, + output: { + landingPage: data, + metadata: { + operation: 'create_landing_page' as const, + pageId: data.id, + }, + success: true, + }, + } + }, + + outputs: { + success: { type: 'boolean', description: 'Operation success status' }, + output: { + type: 'object', + description: 'Created landing page data', + properties: { + landingPage: { type: 'object', description: 'Created landing page object' }, + metadata: { type: 'object', description: 'Operation metadata' }, + success: { type: 'boolean', description: 'Operation success' }, + }, + }, + }, +} diff --git a/apps/sim/tools/mailchimp/create_merge_field.ts b/apps/sim/tools/mailchimp/create_merge_field.ts new file mode 100644 index 0000000000..d069404ab2 --- /dev/null +++ b/apps/sim/tools/mailchimp/create_merge_field.ts @@ -0,0 +1,109 @@ +import { createLogger } from '@/lib/logs/console/logger' +import type { ToolConfig } from '@/tools/types' +import { buildMailchimpUrl, handleMailchimpError } from './types' + +const logger = createLogger('MailchimpCreateMergeField') + +export interface MailchimpCreateMergeFieldParams { + apiKey: string + listId: string + mergeName: string + mergeType: string +} + +export interface MailchimpCreateMergeFieldResponse { + success: boolean + output: { + mergeField: any + metadata: { + operation: 'create_merge_field' + mergeId: string + } + success: boolean + } +} + +export const mailchimpCreateMergeFieldTool: ToolConfig< + MailchimpCreateMergeFieldParams, + MailchimpCreateMergeFieldResponse +> = { + id: 'mailchimp_create_merge_field', + name: 'Create Merge Field in Mailchimp Audience', + description: 'Create a new merge field in a Mailchimp audience', + version: '1.0.0', + + params: { + apiKey: { + type: 'string', + required: true, + visibility: 'hidden', + description: 'Mailchimp API key with server prefix', + }, + listId: { + type: 'string', + required: true, + visibility: 'user-only', + description: 'The unique ID for the list', + }, + mergeName: { + type: 'string', + required: true, + visibility: 'user-only', + description: 'The name of the merge field', + }, + mergeType: { + type: 'string', + required: true, + visibility: 'user-only', + description: + 'The type of the merge field (text, number, address, phone, date, url, imageurl, radio, dropdown, birthday, zip)', + }, + }, + + request: { + url: (params) => buildMailchimpUrl(params.apiKey, `/lists/${params.listId}/merge-fields`), + method: 'POST', + headers: (params) => ({ + Authorization: `Bearer ${params.apiKey}`, + 'Content-Type': 'application/json', + }), + body: (params) => ({ + name: params.mergeName, + type: params.mergeType, + }), + }, + + transformResponse: async (response: Response) => { + if (!response.ok) { + const data = await response.json() + handleMailchimpError(data, response.status, 'create_merge_field') + } + + const data = await response.json() + + return { + success: true, + output: { + mergeField: data, + metadata: { + operation: 'create_merge_field' as const, + mergeId: data.merge_id, + }, + success: true, + }, + } + }, + + outputs: { + success: { type: 'boolean', description: 'Operation success status' }, + output: { + type: 'object', + description: 'Created merge field data', + properties: { + mergeField: { type: 'object', description: 'Created merge field object' }, + metadata: { type: 'object', description: 'Operation metadata' }, + success: { type: 'boolean', description: 'Operation success' }, + }, + }, + }, +} diff --git a/apps/sim/tools/mailchimp/create_segment.ts b/apps/sim/tools/mailchimp/create_segment.ts new file mode 100644 index 0000000000..2937f03be4 --- /dev/null +++ b/apps/sim/tools/mailchimp/create_segment.ts @@ -0,0 +1,120 @@ +import { createLogger } from '@/lib/logs/console/logger' +import type { ToolConfig } from '@/tools/types' +import { buildMailchimpUrl, handleMailchimpError } from './types' + +const logger = createLogger('MailchimpCreateSegment') + +export interface MailchimpCreateSegmentParams { + apiKey: string + listId: string + segmentName: string + segmentOptions?: string +} + +export interface MailchimpCreateSegmentResponse { + success: boolean + output: { + segment: any + metadata: { + operation: 'create_segment' + segmentId: string + } + success: boolean + } +} + +export const mailchimpCreateSegmentTool: ToolConfig< + MailchimpCreateSegmentParams, + MailchimpCreateSegmentResponse +> = { + id: 'mailchimp_create_segment', + name: 'Create Segment in Mailchimp Audience', + description: 'Create a new segment in a Mailchimp audience', + version: '1.0.0', + + params: { + apiKey: { + type: 'string', + required: true, + visibility: 'hidden', + description: 'Mailchimp API key with server prefix', + }, + listId: { + type: 'string', + required: true, + visibility: 'user-only', + description: 'The unique ID for the list', + }, + segmentName: { + type: 'string', + required: true, + visibility: 'user-only', + description: 'The name of the segment', + }, + segmentOptions: { + type: 'string', + required: false, + visibility: 'user-only', + description: 'Segment options as JSON (e.g., {"match": "any", "conditions": []})', + }, + }, + + request: { + url: (params) => buildMailchimpUrl(params.apiKey, `/lists/${params.listId}/segments`), + method: 'POST', + headers: (params) => ({ + Authorization: `Bearer ${params.apiKey}`, + 'Content-Type': 'application/json', + }), + body: (params) => { + const body: any = { + name: params.segmentName, + } + + if (params.segmentOptions) { + try { + const options = JSON.parse(params.segmentOptions) + body.options = options + } catch (error) { + logger.warn('Failed to parse segment options', { error }) + } + } + + return body + }, + }, + + transformResponse: async (response: Response) => { + if (!response.ok) { + const data = await response.json() + handleMailchimpError(data, response.status, 'create_segment') + } + + const data = await response.json() + + return { + success: true, + output: { + segment: data, + metadata: { + operation: 'create_segment' as const, + segmentId: data.id, + }, + success: true, + }, + } + }, + + outputs: { + success: { type: 'boolean', description: 'Operation success status' }, + output: { + type: 'object', + description: 'Created segment data', + properties: { + segment: { type: 'object', description: 'Created segment object' }, + metadata: { type: 'object', description: 'Operation metadata' }, + success: { type: 'boolean', description: 'Operation success' }, + }, + }, + }, +} diff --git a/apps/sim/tools/mailchimp/create_template.ts b/apps/sim/tools/mailchimp/create_template.ts new file mode 100644 index 0000000000..51de9edf9c --- /dev/null +++ b/apps/sim/tools/mailchimp/create_template.ts @@ -0,0 +1,101 @@ +import { createLogger } from '@/lib/logs/console/logger' +import type { ToolConfig } from '@/tools/types' +import { buildMailchimpUrl, handleMailchimpError } from './types' + +const logger = createLogger('MailchimpCreateTemplate') + +export interface MailchimpCreateTemplateParams { + apiKey: string + templateName: string + templateHtml: string +} + +export interface MailchimpCreateTemplateResponse { + success: boolean + output: { + template: any + metadata: { + operation: 'create_template' + templateId: string + } + success: boolean + } +} + +export const mailchimpCreateTemplateTool: ToolConfig< + MailchimpCreateTemplateParams, + MailchimpCreateTemplateResponse +> = { + id: 'mailchimp_create_template', + name: 'Create Template in Mailchimp', + description: 'Create a new template in Mailchimp', + version: '1.0.0', + + params: { + apiKey: { + type: 'string', + required: true, + visibility: 'hidden', + description: 'Mailchimp API key with server prefix', + }, + templateName: { + type: 'string', + required: true, + visibility: 'user-only', + description: 'The name of the template', + }, + templateHtml: { + type: 'string', + required: true, + visibility: 'user-only', + description: 'The HTML content for the template', + }, + }, + + request: { + url: (params) => buildMailchimpUrl(params.apiKey, '/templates'), + method: 'POST', + headers: (params) => ({ + Authorization: `Bearer ${params.apiKey}`, + 'Content-Type': 'application/json', + }), + body: (params) => ({ + name: params.templateName, + html: params.templateHtml, + }), + }, + + transformResponse: async (response: Response) => { + if (!response.ok) { + const data = await response.json() + handleMailchimpError(data, response.status, 'create_template') + } + + const data = await response.json() + + return { + success: true, + output: { + template: data, + metadata: { + operation: 'create_template' as const, + templateId: data.id, + }, + success: true, + }, + } + }, + + outputs: { + success: { type: 'boolean', description: 'Operation success status' }, + output: { + type: 'object', + description: 'Created template data', + properties: { + template: { type: 'object', description: 'Created template object' }, + metadata: { type: 'object', description: 'Operation metadata' }, + success: { type: 'boolean', description: 'Operation success' }, + }, + }, + }, +} diff --git a/apps/sim/tools/mailchimp/delete_audience.ts b/apps/sim/tools/mailchimp/delete_audience.ts new file mode 100644 index 0000000000..29519a1f0e --- /dev/null +++ b/apps/sim/tools/mailchimp/delete_audience.ts @@ -0,0 +1,85 @@ +import { createLogger } from '@/lib/logs/console/logger' +import type { ToolConfig } from '@/tools/types' +import { buildMailchimpUrl, handleMailchimpError } from './types' + +const logger = createLogger('MailchimpDeleteAudience') + +export interface MailchimpDeleteAudienceParams { + apiKey: string + listId: string +} + +export interface MailchimpDeleteAudienceResponse { + success: boolean + output: { + metadata: { + operation: 'delete_audience' + listId: string + } + success: boolean + } +} + +export const mailchimpDeleteAudienceTool: ToolConfig< + MailchimpDeleteAudienceParams, + MailchimpDeleteAudienceResponse +> = { + id: 'mailchimp_delete_audience', + name: 'Delete Audience from Mailchimp', + description: 'Delete an audience (list) from Mailchimp', + version: '1.0.0', + + params: { + apiKey: { + type: 'string', + required: true, + visibility: 'hidden', + description: 'Mailchimp API key with server prefix', + }, + listId: { + type: 'string', + required: true, + visibility: 'user-only', + description: 'The unique ID for the list to delete', + }, + }, + + request: { + url: (params) => buildMailchimpUrl(params.apiKey, `/lists/${params.listId}`), + method: 'DELETE', + headers: (params) => ({ + Authorization: `Bearer ${params.apiKey}`, + 'Content-Type': 'application/json', + }), + }, + + transformResponse: async (response: Response) => { + if (!response.ok) { + const data = await response.json() + handleMailchimpError(data, response.status, 'delete_audience') + } + + return { + success: true, + output: { + metadata: { + operation: 'delete_audience' as const, + listId: '', + }, + success: true, + }, + } + }, + + outputs: { + success: { type: 'boolean', description: 'Operation success status' }, + output: { + type: 'object', + description: 'Deletion confirmation', + properties: { + metadata: { type: 'object', description: 'Operation metadata' }, + success: { type: 'boolean', description: 'Operation success' }, + }, + }, + }, +} diff --git a/apps/sim/tools/mailchimp/delete_batch_operation.ts b/apps/sim/tools/mailchimp/delete_batch_operation.ts new file mode 100644 index 0000000000..a808bd2970 --- /dev/null +++ b/apps/sim/tools/mailchimp/delete_batch_operation.ts @@ -0,0 +1,85 @@ +import { createLogger } from '@/lib/logs/console/logger' +import type { ToolConfig } from '@/tools/types' +import { buildMailchimpUrl, handleMailchimpError } from './types' + +const logger = createLogger('MailchimpDeleteBatchOperation') + +export interface MailchimpDeleteBatchOperationParams { + apiKey: string + batchId: string +} + +export interface MailchimpDeleteBatchOperationResponse { + success: boolean + output: { + metadata: { + operation: 'delete_batch_operation' + batchId: string + } + success: boolean + } +} + +export const mailchimpDeleteBatchOperationTool: ToolConfig< + MailchimpDeleteBatchOperationParams, + MailchimpDeleteBatchOperationResponse +> = { + id: 'mailchimp_delete_batch_operation', + name: 'Delete Batch Operation from Mailchimp', + description: 'Delete a batch operation from Mailchimp', + version: '1.0.0', + + params: { + apiKey: { + type: 'string', + required: true, + visibility: 'hidden', + description: 'Mailchimp API key with server prefix', + }, + batchId: { + type: 'string', + required: true, + visibility: 'user-only', + description: 'The unique ID for the batch operation to delete', + }, + }, + + request: { + url: (params) => buildMailchimpUrl(params.apiKey, `/batches/${params.batchId}`), + method: 'DELETE', + headers: (params) => ({ + Authorization: `Bearer ${params.apiKey}`, + 'Content-Type': 'application/json', + }), + }, + + transformResponse: async (response: Response) => { + if (!response.ok) { + const data = await response.json() + handleMailchimpError(data, response.status, 'delete_batch_operation') + } + + return { + success: true, + output: { + metadata: { + operation: 'delete_batch_operation' as const, + batchId: '', + }, + success: true, + }, + } + }, + + outputs: { + success: { type: 'boolean', description: 'Operation success status' }, + output: { + type: 'object', + description: 'Deletion confirmation', + properties: { + metadata: { type: 'object', description: 'Operation metadata' }, + success: { type: 'boolean', description: 'Operation success' }, + }, + }, + }, +} diff --git a/apps/sim/tools/mailchimp/delete_campaign.ts b/apps/sim/tools/mailchimp/delete_campaign.ts new file mode 100644 index 0000000000..bde51c42ec --- /dev/null +++ b/apps/sim/tools/mailchimp/delete_campaign.ts @@ -0,0 +1,85 @@ +import { createLogger } from '@/lib/logs/console/logger' +import type { ToolConfig } from '@/tools/types' +import { buildMailchimpUrl, handleMailchimpError } from './types' + +const logger = createLogger('MailchimpDeleteCampaign') + +export interface MailchimpDeleteCampaignParams { + apiKey: string + campaignId: string +} + +export interface MailchimpDeleteCampaignResponse { + success: boolean + output: { + metadata: { + operation: 'delete_campaign' + campaignId: string + } + success: boolean + } +} + +export const mailchimpDeleteCampaignTool: ToolConfig< + MailchimpDeleteCampaignParams, + MailchimpDeleteCampaignResponse +> = { + id: 'mailchimp_delete_campaign', + name: 'Delete Campaign from Mailchimp', + description: 'Delete a campaign from Mailchimp', + version: '1.0.0', + + params: { + apiKey: { + type: 'string', + required: true, + visibility: 'hidden', + description: 'Mailchimp API key with server prefix', + }, + campaignId: { + type: 'string', + required: true, + visibility: 'user-only', + description: 'The unique ID for the campaign to delete', + }, + }, + + request: { + url: (params) => buildMailchimpUrl(params.apiKey, `/campaigns/${params.campaignId}`), + method: 'DELETE', + headers: (params) => ({ + Authorization: `Bearer ${params.apiKey}`, + 'Content-Type': 'application/json', + }), + }, + + transformResponse: async (response: Response) => { + if (!response.ok) { + const data = await response.json() + handleMailchimpError(data, response.status, 'delete_campaign') + } + + return { + success: true, + output: { + metadata: { + operation: 'delete_campaign' as const, + campaignId: '', + }, + success: true, + }, + } + }, + + outputs: { + success: { type: 'boolean', description: 'Operation success status' }, + output: { + type: 'object', + description: 'Deletion confirmation', + properties: { + metadata: { type: 'object', description: 'Operation metadata' }, + success: { type: 'boolean', description: 'Operation success' }, + }, + }, + }, +} diff --git a/apps/sim/tools/mailchimp/delete_interest.ts b/apps/sim/tools/mailchimp/delete_interest.ts new file mode 100644 index 0000000000..4eac735552 --- /dev/null +++ b/apps/sim/tools/mailchimp/delete_interest.ts @@ -0,0 +1,103 @@ +import { createLogger } from '@/lib/logs/console/logger' +import type { ToolConfig } from '@/tools/types' +import { buildMailchimpUrl, handleMailchimpError } from './types' + +const logger = createLogger('MailchimpDeleteInterest') + +export interface MailchimpDeleteInterestParams { + apiKey: string + listId: string + interestCategoryId: string + interestId: string +} + +export interface MailchimpDeleteInterestResponse { + success: boolean + output: { + metadata: { + operation: 'delete_interest' + interestId: string + } + success: boolean + } +} + +export const mailchimpDeleteInterestTool: ToolConfig< + MailchimpDeleteInterestParams, + MailchimpDeleteInterestResponse +> = { + id: 'mailchimp_delete_interest', + name: 'Delete Interest from Mailchimp Interest Category', + description: 'Delete an interest from an interest category in a Mailchimp audience', + version: '1.0.0', + + params: { + apiKey: { + type: 'string', + required: true, + visibility: 'hidden', + description: 'Mailchimp API key with server prefix', + }, + listId: { + type: 'string', + required: true, + visibility: 'user-only', + description: 'The unique ID for the list', + }, + interestCategoryId: { + type: 'string', + required: true, + visibility: 'user-only', + description: 'The unique ID for the interest category', + }, + interestId: { + type: 'string', + required: true, + visibility: 'user-only', + description: 'The unique ID for the interest to delete', + }, + }, + + request: { + url: (params) => + buildMailchimpUrl( + params.apiKey, + `/lists/${params.listId}/interest-categories/${params.interestCategoryId}/interests/${params.interestId}` + ), + method: 'DELETE', + headers: (params) => ({ + Authorization: `Bearer ${params.apiKey}`, + 'Content-Type': 'application/json', + }), + }, + + transformResponse: async (response: Response) => { + if (!response.ok) { + const data = await response.json() + handleMailchimpError(data, response.status, 'delete_interest') + } + + return { + success: true, + output: { + metadata: { + operation: 'delete_interest' as const, + interestId: '', + }, + success: true, + }, + } + }, + + outputs: { + success: { type: 'boolean', description: 'Operation success status' }, + output: { + type: 'object', + description: 'Deletion confirmation', + properties: { + metadata: { type: 'object', description: 'Operation metadata' }, + success: { type: 'boolean', description: 'Operation success' }, + }, + }, + }, +} diff --git a/apps/sim/tools/mailchimp/delete_interest_category.ts b/apps/sim/tools/mailchimp/delete_interest_category.ts new file mode 100644 index 0000000000..db4031b430 --- /dev/null +++ b/apps/sim/tools/mailchimp/delete_interest_category.ts @@ -0,0 +1,96 @@ +import { createLogger } from '@/lib/logs/console/logger' +import type { ToolConfig } from '@/tools/types' +import { buildMailchimpUrl, handleMailchimpError } from './types' + +const logger = createLogger('MailchimpDeleteInterestCategory') + +export interface MailchimpDeleteInterestCategoryParams { + apiKey: string + listId: string + interestCategoryId: string +} + +export interface MailchimpDeleteInterestCategoryResponse { + success: boolean + output: { + metadata: { + operation: 'delete_interest_category' + interestCategoryId: string + } + success: boolean + } +} + +export const mailchimpDeleteInterestCategoryTool: ToolConfig< + MailchimpDeleteInterestCategoryParams, + MailchimpDeleteInterestCategoryResponse +> = { + id: 'mailchimp_delete_interest_category', + name: 'Delete Interest Category from Mailchimp Audience', + description: 'Delete an interest category from a Mailchimp audience', + version: '1.0.0', + + params: { + apiKey: { + type: 'string', + required: true, + visibility: 'hidden', + description: 'Mailchimp API key with server prefix', + }, + listId: { + type: 'string', + required: true, + visibility: 'user-only', + description: 'The unique ID for the list', + }, + interestCategoryId: { + type: 'string', + required: true, + visibility: 'user-only', + description: 'The unique ID for the interest category to delete', + }, + }, + + request: { + url: (params) => + buildMailchimpUrl( + params.apiKey, + `/lists/${params.listId}/interest-categories/${params.interestCategoryId}` + ), + method: 'DELETE', + headers: (params) => ({ + Authorization: `Bearer ${params.apiKey}`, + 'Content-Type': 'application/json', + }), + }, + + transformResponse: async (response: Response) => { + if (!response.ok) { + const data = await response.json() + handleMailchimpError(data, response.status, 'delete_interest_category') + } + + return { + success: true, + output: { + metadata: { + operation: 'delete_interest_category' as const, + interestCategoryId: '', + }, + success: true, + }, + } + }, + + outputs: { + success: { type: 'boolean', description: 'Operation success status' }, + output: { + type: 'object', + description: 'Deletion confirmation', + properties: { + metadata: { type: 'object', description: 'Operation metadata' }, + success: { type: 'boolean', description: 'Operation success' }, + }, + }, + }, +} diff --git a/apps/sim/tools/mailchimp/delete_landing_page.ts b/apps/sim/tools/mailchimp/delete_landing_page.ts new file mode 100644 index 0000000000..a590f5ee43 --- /dev/null +++ b/apps/sim/tools/mailchimp/delete_landing_page.ts @@ -0,0 +1,85 @@ +import { createLogger } from '@/lib/logs/console/logger' +import type { ToolConfig } from '@/tools/types' +import { buildMailchimpUrl, handleMailchimpError } from './types' + +const logger = createLogger('MailchimpDeleteLandingPage') + +export interface MailchimpDeleteLandingPageParams { + apiKey: string + pageId: string +} + +export interface MailchimpDeleteLandingPageResponse { + success: boolean + output: { + metadata: { + operation: 'delete_landing_page' + pageId: string + } + success: boolean + } +} + +export const mailchimpDeleteLandingPageTool: ToolConfig< + MailchimpDeleteLandingPageParams, + MailchimpDeleteLandingPageResponse +> = { + id: 'mailchimp_delete_landing_page', + name: 'Delete Landing Page from Mailchimp', + description: 'Delete a landing page from Mailchimp', + version: '1.0.0', + + params: { + apiKey: { + type: 'string', + required: true, + visibility: 'hidden', + description: 'Mailchimp API key with server prefix', + }, + pageId: { + type: 'string', + required: true, + visibility: 'user-only', + description: 'The unique ID for the landing page to delete', + }, + }, + + request: { + url: (params) => buildMailchimpUrl(params.apiKey, `/landing-pages/${params.pageId}`), + method: 'DELETE', + headers: (params) => ({ + Authorization: `Bearer ${params.apiKey}`, + 'Content-Type': 'application/json', + }), + }, + + transformResponse: async (response: Response) => { + if (!response.ok) { + const data = await response.json() + handleMailchimpError(data, response.status, 'delete_landing_page') + } + + return { + success: true, + output: { + metadata: { + operation: 'delete_landing_page' as const, + pageId: '', + }, + success: true, + }, + } + }, + + outputs: { + success: { type: 'boolean', description: 'Operation success status' }, + output: { + type: 'object', + description: 'Deletion confirmation', + properties: { + metadata: { type: 'object', description: 'Operation metadata' }, + success: { type: 'boolean', description: 'Operation success' }, + }, + }, + }, +} diff --git a/apps/sim/tools/mailchimp/delete_member.ts b/apps/sim/tools/mailchimp/delete_member.ts new file mode 100644 index 0000000000..f28b7da709 --- /dev/null +++ b/apps/sim/tools/mailchimp/delete_member.ts @@ -0,0 +1,93 @@ +import { createLogger } from '@/lib/logs/console/logger' +import type { ToolConfig } from '@/tools/types' +import { buildMailchimpUrl, handleMailchimpError } from './types' + +const logger = createLogger('MailchimpDeleteMember') + +export interface MailchimpDeleteMemberParams { + apiKey: string + listId: string + subscriberHash: string +} + +export interface MailchimpDeleteMemberResponse { + success: boolean + output: { + metadata: { + operation: 'delete_member' + subscriberHash: string + } + success: boolean + } +} + +export const mailchimpDeleteMemberTool: ToolConfig< + MailchimpDeleteMemberParams, + MailchimpDeleteMemberResponse +> = { + id: 'mailchimp_delete_member', + name: 'Delete Member from Mailchimp Audience', + description: 'Delete a member from a Mailchimp audience', + version: '1.0.0', + + params: { + apiKey: { + type: 'string', + required: true, + visibility: 'hidden', + description: 'Mailchimp API key with server prefix', + }, + listId: { + type: 'string', + required: true, + visibility: 'user-only', + description: 'The unique ID for the list', + }, + subscriberHash: { + type: 'string', + required: true, + visibility: 'user-only', + description: "The MD5 hash of the lowercase version of the list member's email address", + }, + }, + + request: { + url: (params) => + buildMailchimpUrl(params.apiKey, `/lists/${params.listId}/members/${params.subscriberHash}`), + method: 'DELETE', + headers: (params) => ({ + Authorization: `Bearer ${params.apiKey}`, + 'Content-Type': 'application/json', + }), + }, + + transformResponse: async (response: Response) => { + if (!response.ok) { + const data = await response.json() + handleMailchimpError(data, response.status, 'delete_member') + } + + return { + success: true, + output: { + metadata: { + operation: 'delete_member' as const, + subscriberHash: '', + }, + success: true, + }, + } + }, + + outputs: { + success: { type: 'boolean', description: 'Operation success status' }, + output: { + type: 'object', + description: 'Deletion confirmation', + properties: { + metadata: { type: 'object', description: 'Operation metadata' }, + success: { type: 'boolean', description: 'Operation success' }, + }, + }, + }, +} diff --git a/apps/sim/tools/mailchimp/delete_merge_field.ts b/apps/sim/tools/mailchimp/delete_merge_field.ts new file mode 100644 index 0000000000..bb9f4a1c40 --- /dev/null +++ b/apps/sim/tools/mailchimp/delete_merge_field.ts @@ -0,0 +1,93 @@ +import { createLogger } from '@/lib/logs/console/logger' +import type { ToolConfig } from '@/tools/types' +import { buildMailchimpUrl, handleMailchimpError } from './types' + +const logger = createLogger('MailchimpDeleteMergeField') + +export interface MailchimpDeleteMergeFieldParams { + apiKey: string + listId: string + mergeId: string +} + +export interface MailchimpDeleteMergeFieldResponse { + success: boolean + output: { + metadata: { + operation: 'delete_merge_field' + mergeId: string + } + success: boolean + } +} + +export const mailchimpDeleteMergeFieldTool: ToolConfig< + MailchimpDeleteMergeFieldParams, + MailchimpDeleteMergeFieldResponse +> = { + id: 'mailchimp_delete_merge_field', + name: 'Delete Merge Field from Mailchimp Audience', + description: 'Delete a merge field from a Mailchimp audience', + version: '1.0.0', + + params: { + apiKey: { + type: 'string', + required: true, + visibility: 'hidden', + description: 'Mailchimp API key with server prefix', + }, + listId: { + type: 'string', + required: true, + visibility: 'user-only', + description: 'The unique ID for the list', + }, + mergeId: { + type: 'string', + required: true, + visibility: 'user-only', + description: 'The unique ID for the merge field to delete', + }, + }, + + request: { + url: (params) => + buildMailchimpUrl(params.apiKey, `/lists/${params.listId}/merge-fields/${params.mergeId}`), + method: 'DELETE', + headers: (params) => ({ + Authorization: `Bearer ${params.apiKey}`, + 'Content-Type': 'application/json', + }), + }, + + transformResponse: async (response: Response) => { + if (!response.ok) { + const data = await response.json() + handleMailchimpError(data, response.status, 'delete_merge_field') + } + + return { + success: true, + output: { + metadata: { + operation: 'delete_merge_field' as const, + mergeId: '', + }, + success: true, + }, + } + }, + + outputs: { + success: { type: 'boolean', description: 'Operation success status' }, + output: { + type: 'object', + description: 'Deletion confirmation', + properties: { + metadata: { type: 'object', description: 'Operation metadata' }, + success: { type: 'boolean', description: 'Operation success' }, + }, + }, + }, +} diff --git a/apps/sim/tools/mailchimp/delete_segment.ts b/apps/sim/tools/mailchimp/delete_segment.ts new file mode 100644 index 0000000000..5c5ee2640b --- /dev/null +++ b/apps/sim/tools/mailchimp/delete_segment.ts @@ -0,0 +1,93 @@ +import { createLogger } from '@/lib/logs/console/logger' +import type { ToolConfig } from '@/tools/types' +import { buildMailchimpUrl, handleMailchimpError } from './types' + +const logger = createLogger('MailchimpDeleteSegment') + +export interface MailchimpDeleteSegmentParams { + apiKey: string + listId: string + segmentId: string +} + +export interface MailchimpDeleteSegmentResponse { + success: boolean + output: { + metadata: { + operation: 'delete_segment' + segmentId: string + } + success: boolean + } +} + +export const mailchimpDeleteSegmentTool: ToolConfig< + MailchimpDeleteSegmentParams, + MailchimpDeleteSegmentResponse +> = { + id: 'mailchimp_delete_segment', + name: 'Delete Segment from Mailchimp Audience', + description: 'Delete a segment from a Mailchimp audience', + version: '1.0.0', + + params: { + apiKey: { + type: 'string', + required: true, + visibility: 'hidden', + description: 'Mailchimp API key with server prefix', + }, + listId: { + type: 'string', + required: true, + visibility: 'user-only', + description: 'The unique ID for the list', + }, + segmentId: { + type: 'string', + required: true, + visibility: 'user-only', + description: 'The unique ID for the segment to delete', + }, + }, + + request: { + url: (params) => + buildMailchimpUrl(params.apiKey, `/lists/${params.listId}/segments/${params.segmentId}`), + method: 'DELETE', + headers: (params) => ({ + Authorization: `Bearer ${params.apiKey}`, + 'Content-Type': 'application/json', + }), + }, + + transformResponse: async (response: Response) => { + if (!response.ok) { + const data = await response.json() + handleMailchimpError(data, response.status, 'delete_segment') + } + + return { + success: true, + output: { + metadata: { + operation: 'delete_segment' as const, + segmentId: '', + }, + success: true, + }, + } + }, + + outputs: { + success: { type: 'boolean', description: 'Operation success status' }, + output: { + type: 'object', + description: 'Deletion confirmation', + properties: { + metadata: { type: 'object', description: 'Operation metadata' }, + success: { type: 'boolean', description: 'Operation success' }, + }, + }, + }, +} diff --git a/apps/sim/tools/mailchimp/delete_template.ts b/apps/sim/tools/mailchimp/delete_template.ts new file mode 100644 index 0000000000..2756b9eef4 --- /dev/null +++ b/apps/sim/tools/mailchimp/delete_template.ts @@ -0,0 +1,85 @@ +import { createLogger } from '@/lib/logs/console/logger' +import type { ToolConfig } from '@/tools/types' +import { buildMailchimpUrl, handleMailchimpError } from './types' + +const logger = createLogger('MailchimpDeleteTemplate') + +export interface MailchimpDeleteTemplateParams { + apiKey: string + templateId: string +} + +export interface MailchimpDeleteTemplateResponse { + success: boolean + output: { + metadata: { + operation: 'delete_template' + templateId: string + } + success: boolean + } +} + +export const mailchimpDeleteTemplateTool: ToolConfig< + MailchimpDeleteTemplateParams, + MailchimpDeleteTemplateResponse +> = { + id: 'mailchimp_delete_template', + name: 'Delete Template from Mailchimp', + description: 'Delete a template from Mailchimp', + version: '1.0.0', + + params: { + apiKey: { + type: 'string', + required: true, + visibility: 'hidden', + description: 'Mailchimp API key with server prefix', + }, + templateId: { + type: 'string', + required: true, + visibility: 'user-only', + description: 'The unique ID for the template to delete', + }, + }, + + request: { + url: (params) => buildMailchimpUrl(params.apiKey, `/templates/${params.templateId}`), + method: 'DELETE', + headers: (params) => ({ + Authorization: `Bearer ${params.apiKey}`, + 'Content-Type': 'application/json', + }), + }, + + transformResponse: async (response: Response) => { + if (!response.ok) { + const data = await response.json() + handleMailchimpError(data, response.status, 'delete_template') + } + + return { + success: true, + output: { + metadata: { + operation: 'delete_template' as const, + templateId: '', + }, + success: true, + }, + } + }, + + outputs: { + success: { type: 'boolean', description: 'Operation success status' }, + output: { + type: 'object', + description: 'Deletion confirmation', + properties: { + metadata: { type: 'object', description: 'Operation metadata' }, + success: { type: 'boolean', description: 'Operation success' }, + }, + }, + }, +} diff --git a/apps/sim/tools/mailchimp/get_audience.ts b/apps/sim/tools/mailchimp/get_audience.ts new file mode 100644 index 0000000000..daf71dd4b2 --- /dev/null +++ b/apps/sim/tools/mailchimp/get_audience.ts @@ -0,0 +1,90 @@ +import { createLogger } from '@/lib/logs/console/logger' +import type { ToolConfig } from '@/tools/types' +import { buildMailchimpUrl, handleMailchimpError } from './types' + +const logger = createLogger('MailchimpGetAudience') + +export interface MailchimpGetAudienceParams { + apiKey: string + listId: string +} + +export interface MailchimpGetAudienceResponse { + success: boolean + output: { + list: any + metadata: { + operation: 'get_audience' + listId: string + } + success: boolean + } +} + +export const mailchimpGetAudienceTool: ToolConfig< + MailchimpGetAudienceParams, + MailchimpGetAudienceResponse +> = { + id: 'mailchimp_get_audience', + name: 'Get Audience from Mailchimp', + description: 'Retrieve details of a specific audience (list) from Mailchimp', + version: '1.0.0', + + params: { + apiKey: { + type: 'string', + required: true, + visibility: 'hidden', + description: 'Mailchimp API key with server prefix', + }, + listId: { + type: 'string', + required: true, + visibility: 'user-only', + description: 'The unique ID for the list', + }, + }, + + request: { + url: (params) => buildMailchimpUrl(params.apiKey, `/lists/${params.listId}`), + method: 'GET', + headers: (params) => ({ + Authorization: `Bearer ${params.apiKey}`, + 'Content-Type': 'application/json', + }), + }, + + transformResponse: async (response: Response) => { + if (!response.ok) { + const data = await response.json() + handleMailchimpError(data, response.status, 'get_audience') + } + + const data = await response.json() + + return { + success: true, + output: { + list: data, + metadata: { + operation: 'get_audience' as const, + listId: data.id, + }, + success: true, + }, + } + }, + + outputs: { + success: { type: 'boolean', description: 'Operation success status' }, + output: { + type: 'object', + description: 'Audience data and metadata', + properties: { + list: { type: 'object', description: 'Audience/list object' }, + metadata: { type: 'object', description: 'Operation metadata' }, + success: { type: 'boolean', description: 'Operation success' }, + }, + }, + }, +} diff --git a/apps/sim/tools/mailchimp/get_audiences.ts b/apps/sim/tools/mailchimp/get_audiences.ts new file mode 100644 index 0000000000..971d7a528d --- /dev/null +++ b/apps/sim/tools/mailchimp/get_audiences.ts @@ -0,0 +1,109 @@ +import { createLogger } from '@/lib/logs/console/logger' +import type { ToolConfig } from '@/tools/types' +import { buildMailchimpUrl, handleMailchimpError } from './types' + +const logger = createLogger('MailchimpGetAudiences') + +export interface MailchimpGetAudiencesParams { + apiKey: string + count?: string + offset?: string +} + +export interface MailchimpGetAudiencesResponse { + success: boolean + output: { + lists: any[] + totalItems: number + metadata: { + operation: 'get_audiences' + totalReturned: number + } + success: boolean + } +} + +export const mailchimpGetAudiencesTool: ToolConfig< + MailchimpGetAudiencesParams, + MailchimpGetAudiencesResponse +> = { + id: 'mailchimp_get_audiences', + name: 'Get Audiences from Mailchimp', + description: 'Retrieve a list of audiences (lists) from Mailchimp', + version: '1.0.0', + + params: { + apiKey: { + type: 'string', + required: true, + visibility: 'hidden', + description: 'Mailchimp API key with server prefix', + }, + count: { + type: 'string', + required: false, + visibility: 'user-only', + description: 'Number of results (default: 10, max: 1000)', + }, + offset: { + type: 'string', + required: false, + visibility: 'user-only', + description: 'Number of results to skip', + }, + }, + + request: { + url: (params) => { + const queryParams = new URLSearchParams() + if (params.count) queryParams.append('count', params.count) + if (params.offset) queryParams.append('offset', params.offset) + + const query = queryParams.toString() + const url = buildMailchimpUrl(params.apiKey, '/lists') + return query ? `${url}?${query}` : url + }, + method: 'GET', + headers: (params) => ({ + Authorization: `Bearer ${params.apiKey}`, + 'Content-Type': 'application/json', + }), + }, + + transformResponse: async (response: Response) => { + if (!response.ok) { + const data = await response.json() + handleMailchimpError(data, response.status, 'get_audiences') + } + + const data = await response.json() + const lists = data.lists || [] + + return { + success: true, + output: { + lists, + totalItems: data.total_items || lists.length, + metadata: { + operation: 'get_audiences' as const, + totalReturned: lists.length, + }, + success: true, + }, + } + }, + + outputs: { + success: { type: 'boolean', description: 'Operation success status' }, + output: { + type: 'object', + description: 'Audiences data and metadata', + properties: { + lists: { type: 'array', description: 'Array of audience/list objects' }, + totalItems: { type: 'number', description: 'Total number of lists' }, + metadata: { type: 'object', description: 'Operation metadata' }, + success: { type: 'boolean', description: 'Operation success' }, + }, + }, + }, +} diff --git a/apps/sim/tools/mailchimp/get_automation.ts b/apps/sim/tools/mailchimp/get_automation.ts new file mode 100644 index 0000000000..9b05f9f5ea --- /dev/null +++ b/apps/sim/tools/mailchimp/get_automation.ts @@ -0,0 +1,90 @@ +import { createLogger } from '@/lib/logs/console/logger' +import type { ToolConfig } from '@/tools/types' +import { buildMailchimpUrl, handleMailchimpError } from './types' + +const logger = createLogger('MailchimpGetAutomation') + +export interface MailchimpGetAutomationParams { + apiKey: string + workflowId: string +} + +export interface MailchimpGetAutomationResponse { + success: boolean + output: { + automation: any + metadata: { + operation: 'get_automation' + workflowId: string + } + success: boolean + } +} + +export const mailchimpGetAutomationTool: ToolConfig< + MailchimpGetAutomationParams, + MailchimpGetAutomationResponse +> = { + id: 'mailchimp_get_automation', + name: 'Get Automation from Mailchimp', + description: 'Retrieve details of a specific automation from Mailchimp', + version: '1.0.0', + + params: { + apiKey: { + type: 'string', + required: true, + visibility: 'hidden', + description: 'Mailchimp API key with server prefix', + }, + workflowId: { + type: 'string', + required: true, + visibility: 'user-only', + description: 'The unique ID for the automation workflow', + }, + }, + + request: { + url: (params) => buildMailchimpUrl(params.apiKey, `/automations/${params.workflowId}`), + method: 'GET', + headers: (params) => ({ + Authorization: `Bearer ${params.apiKey}`, + 'Content-Type': 'application/json', + }), + }, + + transformResponse: async (response: Response) => { + if (!response.ok) { + const data = await response.json() + handleMailchimpError(data, response.status, 'get_automation') + } + + const data = await response.json() + + return { + success: true, + output: { + automation: data, + metadata: { + operation: 'get_automation' as const, + workflowId: data.id, + }, + success: true, + }, + } + }, + + outputs: { + success: { type: 'boolean', description: 'Operation success status' }, + output: { + type: 'object', + description: 'Automation data and metadata', + properties: { + automation: { type: 'object', description: 'Automation object' }, + metadata: { type: 'object', description: 'Operation metadata' }, + success: { type: 'boolean', description: 'Operation success' }, + }, + }, + }, +} diff --git a/apps/sim/tools/mailchimp/get_automations.ts b/apps/sim/tools/mailchimp/get_automations.ts new file mode 100644 index 0000000000..ea47a87133 --- /dev/null +++ b/apps/sim/tools/mailchimp/get_automations.ts @@ -0,0 +1,109 @@ +import { createLogger } from '@/lib/logs/console/logger' +import type { ToolConfig } from '@/tools/types' +import { buildMailchimpUrl, handleMailchimpError } from './types' + +const logger = createLogger('MailchimpGetAutomations') + +export interface MailchimpGetAutomationsParams { + apiKey: string + count?: string + offset?: string +} + +export interface MailchimpGetAutomationsResponse { + success: boolean + output: { + automations: any[] + totalItems: number + metadata: { + operation: 'get_automations' + totalReturned: number + } + success: boolean + } +} + +export const mailchimpGetAutomationsTool: ToolConfig< + MailchimpGetAutomationsParams, + MailchimpGetAutomationsResponse +> = { + id: 'mailchimp_get_automations', + name: 'Get Automations from Mailchimp', + description: 'Retrieve a list of automations from Mailchimp', + version: '1.0.0', + + params: { + apiKey: { + type: 'string', + required: true, + visibility: 'hidden', + description: 'Mailchimp API key with server prefix', + }, + count: { + type: 'string', + required: false, + visibility: 'user-only', + description: 'Number of results (default: 10, max: 1000)', + }, + offset: { + type: 'string', + required: false, + visibility: 'user-only', + description: 'Number of results to skip', + }, + }, + + request: { + url: (params) => { + const queryParams = new URLSearchParams() + if (params.count) queryParams.append('count', params.count) + if (params.offset) queryParams.append('offset', params.offset) + + const query = queryParams.toString() + const url = buildMailchimpUrl(params.apiKey, '/automations') + return query ? `${url}?${query}` : url + }, + method: 'GET', + headers: (params) => ({ + Authorization: `Bearer ${params.apiKey}`, + 'Content-Type': 'application/json', + }), + }, + + transformResponse: async (response: Response) => { + if (!response.ok) { + const data = await response.json() + handleMailchimpError(data, response.status, 'get_automations') + } + + const data = await response.json() + const automations = data.automations || [] + + return { + success: true, + output: { + automations, + totalItems: data.total_items || automations.length, + metadata: { + operation: 'get_automations' as const, + totalReturned: automations.length, + }, + success: true, + }, + } + }, + + outputs: { + success: { type: 'boolean', description: 'Operation success status' }, + output: { + type: 'object', + description: 'Automations data and metadata', + properties: { + automations: { type: 'array', description: 'Array of automation objects' }, + totalItems: { type: 'number', description: 'Total number of automations' }, + metadata: { type: 'object', description: 'Operation metadata' }, + success: { type: 'boolean', description: 'Operation success' }, + }, + }, + }, +} diff --git a/apps/sim/tools/mailchimp/get_batch_operation.ts b/apps/sim/tools/mailchimp/get_batch_operation.ts new file mode 100644 index 0000000000..4e1ccdd089 --- /dev/null +++ b/apps/sim/tools/mailchimp/get_batch_operation.ts @@ -0,0 +1,90 @@ +import { createLogger } from '@/lib/logs/console/logger' +import type { ToolConfig } from '@/tools/types' +import { buildMailchimpUrl, handleMailchimpError } from './types' + +const logger = createLogger('MailchimpGetBatchOperation') + +export interface MailchimpGetBatchOperationParams { + apiKey: string + batchId: string +} + +export interface MailchimpGetBatchOperationResponse { + success: boolean + output: { + batch: any + metadata: { + operation: 'get_batch_operation' + batchId: string + } + success: boolean + } +} + +export const mailchimpGetBatchOperationTool: ToolConfig< + MailchimpGetBatchOperationParams, + MailchimpGetBatchOperationResponse +> = { + id: 'mailchimp_get_batch_operation', + name: 'Get Batch Operation from Mailchimp', + description: 'Retrieve details of a specific batch operation from Mailchimp', + version: '1.0.0', + + params: { + apiKey: { + type: 'string', + required: true, + visibility: 'hidden', + description: 'Mailchimp API key with server prefix', + }, + batchId: { + type: 'string', + required: true, + visibility: 'user-only', + description: 'The unique ID for the batch operation', + }, + }, + + request: { + url: (params) => buildMailchimpUrl(params.apiKey, `/batches/${params.batchId}`), + method: 'GET', + headers: (params) => ({ + Authorization: `Bearer ${params.apiKey}`, + 'Content-Type': 'application/json', + }), + }, + + transformResponse: async (response: Response) => { + if (!response.ok) { + const data = await response.json() + handleMailchimpError(data, response.status, 'get_batch_operation') + } + + const data = await response.json() + + return { + success: true, + output: { + batch: data, + metadata: { + operation: 'get_batch_operation' as const, + batchId: data.id, + }, + success: true, + }, + } + }, + + outputs: { + success: { type: 'boolean', description: 'Operation success status' }, + output: { + type: 'object', + description: 'Batch operation data and metadata', + properties: { + batch: { type: 'object', description: 'Batch operation object' }, + metadata: { type: 'object', description: 'Operation metadata' }, + success: { type: 'boolean', description: 'Operation success' }, + }, + }, + }, +} diff --git a/apps/sim/tools/mailchimp/get_batch_operations.ts b/apps/sim/tools/mailchimp/get_batch_operations.ts new file mode 100644 index 0000000000..0e98715d86 --- /dev/null +++ b/apps/sim/tools/mailchimp/get_batch_operations.ts @@ -0,0 +1,109 @@ +import { createLogger } from '@/lib/logs/console/logger' +import type { ToolConfig } from '@/tools/types' +import { buildMailchimpUrl, handleMailchimpError } from './types' + +const logger = createLogger('MailchimpGetBatchOperations') + +export interface MailchimpGetBatchOperationsParams { + apiKey: string + count?: string + offset?: string +} + +export interface MailchimpGetBatchOperationsResponse { + success: boolean + output: { + batches: any[] + totalItems: number + metadata: { + operation: 'get_batch_operations' + totalReturned: number + } + success: boolean + } +} + +export const mailchimpGetBatchOperationsTool: ToolConfig< + MailchimpGetBatchOperationsParams, + MailchimpGetBatchOperationsResponse +> = { + id: 'mailchimp_get_batch_operations', + name: 'Get Batch Operations from Mailchimp', + description: 'Retrieve a list of batch operations from Mailchimp', + version: '1.0.0', + + params: { + apiKey: { + type: 'string', + required: true, + visibility: 'hidden', + description: 'Mailchimp API key with server prefix', + }, + count: { + type: 'string', + required: false, + visibility: 'user-only', + description: 'Number of results (default: 10, max: 1000)', + }, + offset: { + type: 'string', + required: false, + visibility: 'user-only', + description: 'Number of results to skip', + }, + }, + + request: { + url: (params) => { + const queryParams = new URLSearchParams() + if (params.count) queryParams.append('count', params.count) + if (params.offset) queryParams.append('offset', params.offset) + + const query = queryParams.toString() + const url = buildMailchimpUrl(params.apiKey, '/batches') + return query ? `${url}?${query}` : url + }, + method: 'GET', + headers: (params) => ({ + Authorization: `Bearer ${params.apiKey}`, + 'Content-Type': 'application/json', + }), + }, + + transformResponse: async (response: Response) => { + if (!response.ok) { + const data = await response.json() + handleMailchimpError(data, response.status, 'get_batch_operations') + } + + const data = await response.json() + const batches = data.batches || [] + + return { + success: true, + output: { + batches, + totalItems: data.total_items || batches.length, + metadata: { + operation: 'get_batch_operations' as const, + totalReturned: batches.length, + }, + success: true, + }, + } + }, + + outputs: { + success: { type: 'boolean', description: 'Operation success status' }, + output: { + type: 'object', + description: 'Batch operations data and metadata', + properties: { + batches: { type: 'array', description: 'Array of batch operation objects' }, + totalItems: { type: 'number', description: 'Total number of batch operations' }, + metadata: { type: 'object', description: 'Operation metadata' }, + success: { type: 'boolean', description: 'Operation success' }, + }, + }, + }, +} diff --git a/apps/sim/tools/mailchimp/get_campaign.ts b/apps/sim/tools/mailchimp/get_campaign.ts new file mode 100644 index 0000000000..ec40e0272f --- /dev/null +++ b/apps/sim/tools/mailchimp/get_campaign.ts @@ -0,0 +1,90 @@ +import { createLogger } from '@/lib/logs/console/logger' +import type { ToolConfig } from '@/tools/types' +import { buildMailchimpUrl, handleMailchimpError } from './types' + +const logger = createLogger('MailchimpGetCampaign') + +export interface MailchimpGetCampaignParams { + apiKey: string + campaignId: string +} + +export interface MailchimpGetCampaignResponse { + success: boolean + output: { + campaign: any + metadata: { + operation: 'get_campaign' + campaignId: string + } + success: boolean + } +} + +export const mailchimpGetCampaignTool: ToolConfig< + MailchimpGetCampaignParams, + MailchimpGetCampaignResponse +> = { + id: 'mailchimp_get_campaign', + name: 'Get Campaign from Mailchimp', + description: 'Retrieve details of a specific campaign from Mailchimp', + version: '1.0.0', + + params: { + apiKey: { + type: 'string', + required: true, + visibility: 'hidden', + description: 'Mailchimp API key with server prefix', + }, + campaignId: { + type: 'string', + required: true, + visibility: 'user-only', + description: 'The unique ID for the campaign', + }, + }, + + request: { + url: (params) => buildMailchimpUrl(params.apiKey, `/campaigns/${params.campaignId}`), + method: 'GET', + headers: (params) => ({ + Authorization: `Bearer ${params.apiKey}`, + 'Content-Type': 'application/json', + }), + }, + + transformResponse: async (response: Response) => { + if (!response.ok) { + const data = await response.json() + handleMailchimpError(data, response.status, 'get_campaign') + } + + const data = await response.json() + + return { + success: true, + output: { + campaign: data, + metadata: { + operation: 'get_campaign' as const, + campaignId: data.id, + }, + success: true, + }, + } + }, + + outputs: { + success: { type: 'boolean', description: 'Operation success status' }, + output: { + type: 'object', + description: 'Campaign data and metadata', + properties: { + campaign: { type: 'object', description: 'Campaign object' }, + metadata: { type: 'object', description: 'Operation metadata' }, + success: { type: 'boolean', description: 'Operation success' }, + }, + }, + }, +} diff --git a/apps/sim/tools/mailchimp/get_campaign_content.ts b/apps/sim/tools/mailchimp/get_campaign_content.ts new file mode 100644 index 0000000000..706b8b5ae7 --- /dev/null +++ b/apps/sim/tools/mailchimp/get_campaign_content.ts @@ -0,0 +1,90 @@ +import { createLogger } from '@/lib/logs/console/logger' +import type { ToolConfig } from '@/tools/types' +import { buildMailchimpUrl, handleMailchimpError } from './types' + +const logger = createLogger('MailchimpGetCampaignContent') + +export interface MailchimpGetCampaignContentParams { + apiKey: string + campaignId: string +} + +export interface MailchimpGetCampaignContentResponse { + success: boolean + output: { + content: any + metadata: { + operation: 'get_campaign_content' + campaignId: string + } + success: boolean + } +} + +export const mailchimpGetCampaignContentTool: ToolConfig< + MailchimpGetCampaignContentParams, + MailchimpGetCampaignContentResponse +> = { + id: 'mailchimp_get_campaign_content', + name: 'Get Campaign Content from Mailchimp', + description: 'Retrieve the HTML and plain-text content for a Mailchimp campaign', + version: '1.0.0', + + params: { + apiKey: { + type: 'string', + required: true, + visibility: 'hidden', + description: 'Mailchimp API key with server prefix', + }, + campaignId: { + type: 'string', + required: true, + visibility: 'user-only', + description: 'The unique ID for the campaign', + }, + }, + + request: { + url: (params) => buildMailchimpUrl(params.apiKey, `/campaigns/${params.campaignId}/content`), + method: 'GET', + headers: (params) => ({ + Authorization: `Bearer ${params.apiKey}`, + 'Content-Type': 'application/json', + }), + }, + + transformResponse: async (response: Response) => { + if (!response.ok) { + const data = await response.json() + handleMailchimpError(data, response.status, 'get_campaign_content') + } + + const data = await response.json() + + return { + success: true, + output: { + content: data, + metadata: { + operation: 'get_campaign_content' as const, + campaignId: '', + }, + success: true, + }, + } + }, + + outputs: { + success: { type: 'boolean', description: 'Operation success status' }, + output: { + type: 'object', + description: 'Campaign content data', + properties: { + content: { type: 'object', description: 'Campaign content object' }, + metadata: { type: 'object', description: 'Operation metadata' }, + success: { type: 'boolean', description: 'Operation success' }, + }, + }, + }, +} diff --git a/apps/sim/tools/mailchimp/get_campaign_report.ts b/apps/sim/tools/mailchimp/get_campaign_report.ts new file mode 100644 index 0000000000..852a9c912f --- /dev/null +++ b/apps/sim/tools/mailchimp/get_campaign_report.ts @@ -0,0 +1,90 @@ +import { createLogger } from '@/lib/logs/console/logger' +import type { ToolConfig } from '@/tools/types' +import { buildMailchimpUrl, handleMailchimpError } from './types' + +const logger = createLogger('MailchimpGetCampaignReport') + +export interface MailchimpGetCampaignReportParams { + apiKey: string + campaignId: string +} + +export interface MailchimpGetCampaignReportResponse { + success: boolean + output: { + report: any + metadata: { + operation: 'get_campaign_report' + campaignId: string + } + success: boolean + } +} + +export const mailchimpGetCampaignReportTool: ToolConfig< + MailchimpGetCampaignReportParams, + MailchimpGetCampaignReportResponse +> = { + id: 'mailchimp_get_campaign_report', + name: 'Get Campaign Report from Mailchimp', + description: 'Retrieve the report for a specific campaign from Mailchimp', + version: '1.0.0', + + params: { + apiKey: { + type: 'string', + required: true, + visibility: 'hidden', + description: 'Mailchimp API key with server prefix', + }, + campaignId: { + type: 'string', + required: true, + visibility: 'user-only', + description: 'The unique ID for the campaign', + }, + }, + + request: { + url: (params) => buildMailchimpUrl(params.apiKey, `/reports/${params.campaignId}`), + method: 'GET', + headers: (params) => ({ + Authorization: `Bearer ${params.apiKey}`, + 'Content-Type': 'application/json', + }), + }, + + transformResponse: async (response: Response) => { + if (!response.ok) { + const data = await response.json() + handleMailchimpError(data, response.status, 'get_campaign_report') + } + + const data = await response.json() + + return { + success: true, + output: { + report: data, + metadata: { + operation: 'get_campaign_report' as const, + campaignId: data.campaign_id, + }, + success: true, + }, + } + }, + + outputs: { + success: { type: 'boolean', description: 'Operation success status' }, + output: { + type: 'object', + description: 'Campaign report data and metadata', + properties: { + report: { type: 'object', description: 'Campaign report object' }, + metadata: { type: 'object', description: 'Operation metadata' }, + success: { type: 'boolean', description: 'Operation success' }, + }, + }, + }, +} diff --git a/apps/sim/tools/mailchimp/get_campaign_reports.ts b/apps/sim/tools/mailchimp/get_campaign_reports.ts new file mode 100644 index 0000000000..d83a2acd2c --- /dev/null +++ b/apps/sim/tools/mailchimp/get_campaign_reports.ts @@ -0,0 +1,109 @@ +import { createLogger } from '@/lib/logs/console/logger' +import type { ToolConfig } from '@/tools/types' +import { buildMailchimpUrl, handleMailchimpError } from './types' + +const logger = createLogger('MailchimpGetCampaignReports') + +export interface MailchimpGetCampaignReportsParams { + apiKey: string + count?: string + offset?: string +} + +export interface MailchimpGetCampaignReportsResponse { + success: boolean + output: { + reports: any[] + totalItems: number + metadata: { + operation: 'get_campaign_reports' + totalReturned: number + } + success: boolean + } +} + +export const mailchimpGetCampaignReportsTool: ToolConfig< + MailchimpGetCampaignReportsParams, + MailchimpGetCampaignReportsResponse +> = { + id: 'mailchimp_get_campaign_reports', + name: 'Get Campaign Reports from Mailchimp', + description: 'Retrieve a list of campaign reports from Mailchimp', + version: '1.0.0', + + params: { + apiKey: { + type: 'string', + required: true, + visibility: 'hidden', + description: 'Mailchimp API key with server prefix', + }, + count: { + type: 'string', + required: false, + visibility: 'user-only', + description: 'Number of results (default: 10, max: 1000)', + }, + offset: { + type: 'string', + required: false, + visibility: 'user-only', + description: 'Number of results to skip', + }, + }, + + request: { + url: (params) => { + const queryParams = new URLSearchParams() + if (params.count) queryParams.append('count', params.count) + if (params.offset) queryParams.append('offset', params.offset) + + const query = queryParams.toString() + const url = buildMailchimpUrl(params.apiKey, '/reports') + return query ? `${url}?${query}` : url + }, + method: 'GET', + headers: (params) => ({ + Authorization: `Bearer ${params.apiKey}`, + 'Content-Type': 'application/json', + }), + }, + + transformResponse: async (response: Response) => { + if (!response.ok) { + const data = await response.json() + handleMailchimpError(data, response.status, 'get_campaign_reports') + } + + const data = await response.json() + const reports = data.reports || [] + + return { + success: true, + output: { + reports, + totalItems: data.total_items || reports.length, + metadata: { + operation: 'get_campaign_reports' as const, + totalReturned: reports.length, + }, + success: true, + }, + } + }, + + outputs: { + success: { type: 'boolean', description: 'Operation success status' }, + output: { + type: 'object', + description: 'Campaign reports data and metadata', + properties: { + reports: { type: 'array', description: 'Array of campaign report objects' }, + totalItems: { type: 'number', description: 'Total number of reports' }, + metadata: { type: 'object', description: 'Operation metadata' }, + success: { type: 'boolean', description: 'Operation success' }, + }, + }, + }, +} diff --git a/apps/sim/tools/mailchimp/get_campaigns.ts b/apps/sim/tools/mailchimp/get_campaigns.ts new file mode 100644 index 0000000000..bc725ab7bc --- /dev/null +++ b/apps/sim/tools/mailchimp/get_campaigns.ts @@ -0,0 +1,125 @@ +import { createLogger } from '@/lib/logs/console/logger' +import type { ToolConfig } from '@/tools/types' +import { buildMailchimpUrl, handleMailchimpError } from './types' + +const logger = createLogger('MailchimpGetCampaigns') + +export interface MailchimpGetCampaignsParams { + apiKey: string + campaignType?: string + status?: string + count?: string + offset?: string +} + +export interface MailchimpGetCampaignsResponse { + success: boolean + output: { + campaigns: any[] + totalItems: number + metadata: { + operation: 'get_campaigns' + totalReturned: number + } + success: boolean + } +} + +export const mailchimpGetCampaignsTool: ToolConfig< + MailchimpGetCampaignsParams, + MailchimpGetCampaignsResponse +> = { + id: 'mailchimp_get_campaigns', + name: 'Get Campaigns from Mailchimp', + description: 'Retrieve a list of campaigns from Mailchimp', + version: '1.0.0', + + params: { + apiKey: { + type: 'string', + required: true, + visibility: 'hidden', + description: 'Mailchimp API key with server prefix', + }, + campaignType: { + type: 'string', + required: false, + visibility: 'user-only', + description: 'Filter by campaign type (regular, plaintext, absplit, rss, variate)', + }, + status: { + type: 'string', + required: false, + visibility: 'user-only', + description: 'Filter by status (save, paused, schedule, sending, sent)', + }, + count: { + type: 'string', + required: false, + visibility: 'user-only', + description: 'Number of results (default: 10, max: 1000)', + }, + offset: { + type: 'string', + required: false, + visibility: 'user-only', + description: 'Number of results to skip', + }, + }, + + request: { + url: (params) => { + const queryParams = new URLSearchParams() + if (params.campaignType) queryParams.append('type', params.campaignType) + if (params.status) queryParams.append('status', params.status) + if (params.count) queryParams.append('count', params.count) + if (params.offset) queryParams.append('offset', params.offset) + + const query = queryParams.toString() + const url = buildMailchimpUrl(params.apiKey, '/campaigns') + return query ? `${url}?${query}` : url + }, + method: 'GET', + headers: (params) => ({ + Authorization: `Bearer ${params.apiKey}`, + 'Content-Type': 'application/json', + }), + }, + + transformResponse: async (response: Response) => { + if (!response.ok) { + const data = await response.json() + handleMailchimpError(data, response.status, 'get_campaigns') + } + + const data = await response.json() + const campaigns = data.campaigns || [] + + return { + success: true, + output: { + campaigns, + totalItems: data.total_items || campaigns.length, + metadata: { + operation: 'get_campaigns' as const, + totalReturned: campaigns.length, + }, + success: true, + }, + } + }, + + outputs: { + success: { type: 'boolean', description: 'Operation success status' }, + output: { + type: 'object', + description: 'Campaigns data and metadata', + properties: { + campaigns: { type: 'array', description: 'Array of campaign objects' }, + totalItems: { type: 'number', description: 'Total number of campaigns' }, + metadata: { type: 'object', description: 'Operation metadata' }, + success: { type: 'boolean', description: 'Operation success' }, + }, + }, + }, +} diff --git a/apps/sim/tools/mailchimp/get_interest.ts b/apps/sim/tools/mailchimp/get_interest.ts new file mode 100644 index 0000000000..bdde022c76 --- /dev/null +++ b/apps/sim/tools/mailchimp/get_interest.ts @@ -0,0 +1,109 @@ +import { createLogger } from '@/lib/logs/console/logger' +import type { ToolConfig } from '@/tools/types' +import { buildMailchimpUrl, handleMailchimpError } from './types' + +const logger = createLogger('MailchimpGetInterest') + +export interface MailchimpGetInterestParams { + apiKey: string + listId: string + interestCategoryId: string + interestId: string +} + +export interface MailchimpGetInterestResponse { + success: boolean + output: { + interest: any + metadata: { + operation: 'get_interest' + interestId: string + } + success: boolean + } +} + +export const mailchimpGetInterestTool: ToolConfig< + MailchimpGetInterestParams, + MailchimpGetInterestResponse +> = { + id: 'mailchimp_get_interest', + name: 'Get Interest from Mailchimp Interest Category', + description: + 'Retrieve details of a specific interest from an interest category in a Mailchimp audience', + version: '1.0.0', + + params: { + apiKey: { + type: 'string', + required: true, + visibility: 'hidden', + description: 'Mailchimp API key with server prefix', + }, + listId: { + type: 'string', + required: true, + visibility: 'user-only', + description: 'The unique ID for the list', + }, + interestCategoryId: { + type: 'string', + required: true, + visibility: 'user-only', + description: 'The unique ID for the interest category', + }, + interestId: { + type: 'string', + required: true, + visibility: 'user-only', + description: 'The unique ID for the interest', + }, + }, + + request: { + url: (params) => + buildMailchimpUrl( + params.apiKey, + `/lists/${params.listId}/interest-categories/${params.interestCategoryId}/interests/${params.interestId}` + ), + method: 'GET', + headers: (params) => ({ + Authorization: `Bearer ${params.apiKey}`, + 'Content-Type': 'application/json', + }), + }, + + transformResponse: async (response: Response) => { + if (!response.ok) { + const data = await response.json() + handleMailchimpError(data, response.status, 'get_interest') + } + + const data = await response.json() + + return { + success: true, + output: { + interest: data, + metadata: { + operation: 'get_interest' as const, + interestId: data.id, + }, + success: true, + }, + } + }, + + outputs: { + success: { type: 'boolean', description: 'Operation success status' }, + output: { + type: 'object', + description: 'Interest data and metadata', + properties: { + interest: { type: 'object', description: 'Interest object' }, + metadata: { type: 'object', description: 'Operation metadata' }, + success: { type: 'boolean', description: 'Operation success' }, + }, + }, + }, +} diff --git a/apps/sim/tools/mailchimp/get_interest_categories.ts b/apps/sim/tools/mailchimp/get_interest_categories.ts new file mode 100644 index 0000000000..80305e7d45 --- /dev/null +++ b/apps/sim/tools/mailchimp/get_interest_categories.ts @@ -0,0 +1,116 @@ +import { createLogger } from '@/lib/logs/console/logger' +import type { ToolConfig } from '@/tools/types' +import { buildMailchimpUrl, handleMailchimpError } from './types' + +const logger = createLogger('MailchimpGetInterestCategories') + +export interface MailchimpGetInterestCategoriesParams { + apiKey: string + listId: string + count?: string + offset?: string +} + +export interface MailchimpGetInterestCategoriesResponse { + success: boolean + output: { + categories: any[] + totalItems: number + metadata: { + operation: 'get_interest_categories' + totalReturned: number + } + success: boolean + } +} + +export const mailchimpGetInterestCategoriesTool: ToolConfig< + MailchimpGetInterestCategoriesParams, + MailchimpGetInterestCategoriesResponse +> = { + id: 'mailchimp_get_interest_categories', + name: 'Get Interest Categories from Mailchimp Audience', + description: 'Retrieve a list of interest categories from a Mailchimp audience', + version: '1.0.0', + + params: { + apiKey: { + type: 'string', + required: true, + visibility: 'hidden', + description: 'Mailchimp API key with server prefix', + }, + listId: { + type: 'string', + required: true, + visibility: 'user-only', + description: 'The unique ID for the list', + }, + count: { + type: 'string', + required: false, + visibility: 'user-only', + description: 'Number of results (default: 10, max: 1000)', + }, + offset: { + type: 'string', + required: false, + visibility: 'user-only', + description: 'Number of results to skip', + }, + }, + + request: { + url: (params) => { + const queryParams = new URLSearchParams() + if (params.count) queryParams.append('count', params.count) + if (params.offset) queryParams.append('offset', params.offset) + + const query = queryParams.toString() + const url = buildMailchimpUrl(params.apiKey, `/lists/${params.listId}/interest-categories`) + return query ? `${url}?${query}` : url + }, + method: 'GET', + headers: (params) => ({ + Authorization: `Bearer ${params.apiKey}`, + 'Content-Type': 'application/json', + }), + }, + + transformResponse: async (response: Response) => { + if (!response.ok) { + const data = await response.json() + handleMailchimpError(data, response.status, 'get_interest_categories') + } + + const data = await response.json() + const categories = data.categories || [] + + return { + success: true, + output: { + categories, + totalItems: data.total_items || categories.length, + metadata: { + operation: 'get_interest_categories' as const, + totalReturned: categories.length, + }, + success: true, + }, + } + }, + + outputs: { + success: { type: 'boolean', description: 'Operation success status' }, + output: { + type: 'object', + description: 'Interest categories data and metadata', + properties: { + categories: { type: 'array', description: 'Array of interest category objects' }, + totalItems: { type: 'number', description: 'Total number of categories' }, + metadata: { type: 'object', description: 'Operation metadata' }, + success: { type: 'boolean', description: 'Operation success' }, + }, + }, + }, +} diff --git a/apps/sim/tools/mailchimp/get_interest_category.ts b/apps/sim/tools/mailchimp/get_interest_category.ts new file mode 100644 index 0000000000..6d51d0457f --- /dev/null +++ b/apps/sim/tools/mailchimp/get_interest_category.ts @@ -0,0 +1,101 @@ +import { createLogger } from '@/lib/logs/console/logger' +import type { ToolConfig } from '@/tools/types' +import { buildMailchimpUrl, handleMailchimpError } from './types' + +const logger = createLogger('MailchimpGetInterestCategory') + +export interface MailchimpGetInterestCategoryParams { + apiKey: string + listId: string + interestCategoryId: string +} + +export interface MailchimpGetInterestCategoryResponse { + success: boolean + output: { + category: any + metadata: { + operation: 'get_interest_category' + interestCategoryId: string + } + success: boolean + } +} + +export const mailchimpGetInterestCategoryTool: ToolConfig< + MailchimpGetInterestCategoryParams, + MailchimpGetInterestCategoryResponse +> = { + id: 'mailchimp_get_interest_category', + name: 'Get Interest Category from Mailchimp Audience', + description: 'Retrieve details of a specific interest category from a Mailchimp audience', + version: '1.0.0', + + params: { + apiKey: { + type: 'string', + required: true, + visibility: 'hidden', + description: 'Mailchimp API key with server prefix', + }, + listId: { + type: 'string', + required: true, + visibility: 'user-only', + description: 'The unique ID for the list', + }, + interestCategoryId: { + type: 'string', + required: true, + visibility: 'user-only', + description: 'The unique ID for the interest category', + }, + }, + + request: { + url: (params) => + buildMailchimpUrl( + params.apiKey, + `/lists/${params.listId}/interest-categories/${params.interestCategoryId}` + ), + method: 'GET', + headers: (params) => ({ + Authorization: `Bearer ${params.apiKey}`, + 'Content-Type': 'application/json', + }), + }, + + transformResponse: async (response: Response) => { + if (!response.ok) { + const data = await response.json() + handleMailchimpError(data, response.status, 'get_interest_category') + } + + const data = await response.json() + + return { + success: true, + output: { + category: data, + metadata: { + operation: 'get_interest_category' as const, + interestCategoryId: data.id, + }, + success: true, + }, + } + }, + + outputs: { + success: { type: 'boolean', description: 'Operation success status' }, + output: { + type: 'object', + description: 'Interest category data and metadata', + properties: { + category: { type: 'object', description: 'Interest category object' }, + metadata: { type: 'object', description: 'Operation metadata' }, + success: { type: 'boolean', description: 'Operation success' }, + }, + }, + }, +} diff --git a/apps/sim/tools/mailchimp/get_interests.ts b/apps/sim/tools/mailchimp/get_interests.ts new file mode 100644 index 0000000000..93ca63e1f5 --- /dev/null +++ b/apps/sim/tools/mailchimp/get_interests.ts @@ -0,0 +1,126 @@ +import { createLogger } from '@/lib/logs/console/logger' +import type { ToolConfig } from '@/tools/types' +import { buildMailchimpUrl, handleMailchimpError } from './types' + +const logger = createLogger('MailchimpGetInterests') + +export interface MailchimpGetInterestsParams { + apiKey: string + listId: string + interestCategoryId: string + count?: string + offset?: string +} + +export interface MailchimpGetInterestsResponse { + success: boolean + output: { + interests: any[] + totalItems: number + metadata: { + operation: 'get_interests' + totalReturned: number + } + success: boolean + } +} + +export const mailchimpGetInterestsTool: ToolConfig< + MailchimpGetInterestsParams, + MailchimpGetInterestsResponse +> = { + id: 'mailchimp_get_interests', + name: 'Get Interests from Mailchimp Interest Category', + description: 'Retrieve a list of interests from an interest category in a Mailchimp audience', + version: '1.0.0', + + params: { + apiKey: { + type: 'string', + required: true, + visibility: 'hidden', + description: 'Mailchimp API key with server prefix', + }, + listId: { + type: 'string', + required: true, + visibility: 'user-only', + description: 'The unique ID for the list', + }, + interestCategoryId: { + type: 'string', + required: true, + visibility: 'user-only', + description: 'The unique ID for the interest category', + }, + count: { + type: 'string', + required: false, + visibility: 'user-only', + description: 'Number of results (default: 10, max: 1000)', + }, + offset: { + type: 'string', + required: false, + visibility: 'user-only', + description: 'Number of results to skip', + }, + }, + + request: { + url: (params) => { + const queryParams = new URLSearchParams() + if (params.count) queryParams.append('count', params.count) + if (params.offset) queryParams.append('offset', params.offset) + + const query = queryParams.toString() + const url = buildMailchimpUrl( + params.apiKey, + `/lists/${params.listId}/interest-categories/${params.interestCategoryId}/interests` + ) + return query ? `${url}?${query}` : url + }, + method: 'GET', + headers: (params) => ({ + Authorization: `Bearer ${params.apiKey}`, + 'Content-Type': 'application/json', + }), + }, + + transformResponse: async (response: Response) => { + if (!response.ok) { + const data = await response.json() + handleMailchimpError(data, response.status, 'get_interests') + } + + const data = await response.json() + const interests = data.interests || [] + + return { + success: true, + output: { + interests, + totalItems: data.total_items || interests.length, + metadata: { + operation: 'get_interests' as const, + totalReturned: interests.length, + }, + success: true, + }, + } + }, + + outputs: { + success: { type: 'boolean', description: 'Operation success status' }, + output: { + type: 'object', + description: 'Interests data and metadata', + properties: { + interests: { type: 'array', description: 'Array of interest objects' }, + totalItems: { type: 'number', description: 'Total number of interests' }, + metadata: { type: 'object', description: 'Operation metadata' }, + success: { type: 'boolean', description: 'Operation success' }, + }, + }, + }, +} diff --git a/apps/sim/tools/mailchimp/get_landing_page.ts b/apps/sim/tools/mailchimp/get_landing_page.ts new file mode 100644 index 0000000000..f3ec0cf37b --- /dev/null +++ b/apps/sim/tools/mailchimp/get_landing_page.ts @@ -0,0 +1,90 @@ +import { createLogger } from '@/lib/logs/console/logger' +import type { ToolConfig } from '@/tools/types' +import { buildMailchimpUrl, handleMailchimpError } from './types' + +const logger = createLogger('MailchimpGetLandingPage') + +export interface MailchimpGetLandingPageParams { + apiKey: string + pageId: string +} + +export interface MailchimpGetLandingPageResponse { + success: boolean + output: { + landingPage: any + metadata: { + operation: 'get_landing_page' + pageId: string + } + success: boolean + } +} + +export const mailchimpGetLandingPageTool: ToolConfig< + MailchimpGetLandingPageParams, + MailchimpGetLandingPageResponse +> = { + id: 'mailchimp_get_landing_page', + name: 'Get Landing Page from Mailchimp', + description: 'Retrieve details of a specific landing page from Mailchimp', + version: '1.0.0', + + params: { + apiKey: { + type: 'string', + required: true, + visibility: 'hidden', + description: 'Mailchimp API key with server prefix', + }, + pageId: { + type: 'string', + required: true, + visibility: 'user-only', + description: 'The unique ID for the landing page', + }, + }, + + request: { + url: (params) => buildMailchimpUrl(params.apiKey, `/landing-pages/${params.pageId}`), + method: 'GET', + headers: (params) => ({ + Authorization: `Bearer ${params.apiKey}`, + 'Content-Type': 'application/json', + }), + }, + + transformResponse: async (response: Response) => { + if (!response.ok) { + const data = await response.json() + handleMailchimpError(data, response.status, 'get_landing_page') + } + + const data = await response.json() + + return { + success: true, + output: { + landingPage: data, + metadata: { + operation: 'get_landing_page' as const, + pageId: data.id, + }, + success: true, + }, + } + }, + + outputs: { + success: { type: 'boolean', description: 'Operation success status' }, + output: { + type: 'object', + description: 'Landing page data and metadata', + properties: { + landingPage: { type: 'object', description: 'Landing page object' }, + metadata: { type: 'object', description: 'Operation metadata' }, + success: { type: 'boolean', description: 'Operation success' }, + }, + }, + }, +} diff --git a/apps/sim/tools/mailchimp/get_landing_pages.ts b/apps/sim/tools/mailchimp/get_landing_pages.ts new file mode 100644 index 0000000000..b8095cdd9c --- /dev/null +++ b/apps/sim/tools/mailchimp/get_landing_pages.ts @@ -0,0 +1,109 @@ +import { createLogger } from '@/lib/logs/console/logger' +import type { ToolConfig } from '@/tools/types' +import { buildMailchimpUrl, handleMailchimpError } from './types' + +const logger = createLogger('MailchimpGetLandingPages') + +export interface MailchimpGetLandingPagesParams { + apiKey: string + count?: string + offset?: string +} + +export interface MailchimpGetLandingPagesResponse { + success: boolean + output: { + landingPages: any[] + totalItems: number + metadata: { + operation: 'get_landing_pages' + totalReturned: number + } + success: boolean + } +} + +export const mailchimpGetLandingPagesTool: ToolConfig< + MailchimpGetLandingPagesParams, + MailchimpGetLandingPagesResponse +> = { + id: 'mailchimp_get_landing_pages', + name: 'Get Landing Pages from Mailchimp', + description: 'Retrieve a list of landing pages from Mailchimp', + version: '1.0.0', + + params: { + apiKey: { + type: 'string', + required: true, + visibility: 'hidden', + description: 'Mailchimp API key with server prefix', + }, + count: { + type: 'string', + required: false, + visibility: 'user-only', + description: 'Number of results (default: 10, max: 1000)', + }, + offset: { + type: 'string', + required: false, + visibility: 'user-only', + description: 'Number of results to skip', + }, + }, + + request: { + url: (params) => { + const queryParams = new URLSearchParams() + if (params.count) queryParams.append('count', params.count) + if (params.offset) queryParams.append('offset', params.offset) + + const query = queryParams.toString() + const url = buildMailchimpUrl(params.apiKey, '/landing-pages') + return query ? `${url}?${query}` : url + }, + method: 'GET', + headers: (params) => ({ + Authorization: `Bearer ${params.apiKey}`, + 'Content-Type': 'application/json', + }), + }, + + transformResponse: async (response: Response) => { + if (!response.ok) { + const data = await response.json() + handleMailchimpError(data, response.status, 'get_landing_pages') + } + + const data = await response.json() + const landingPages = data.landing_pages || [] + + return { + success: true, + output: { + landingPages, + totalItems: data.total_items || landingPages.length, + metadata: { + operation: 'get_landing_pages' as const, + totalReturned: landingPages.length, + }, + success: true, + }, + } + }, + + outputs: { + success: { type: 'boolean', description: 'Operation success status' }, + output: { + type: 'object', + description: 'Landing pages data and metadata', + properties: { + landingPages: { type: 'array', description: 'Array of landing page objects' }, + totalItems: { type: 'number', description: 'Total number of landing pages' }, + metadata: { type: 'object', description: 'Operation metadata' }, + success: { type: 'boolean', description: 'Operation success' }, + }, + }, + }, +} diff --git a/apps/sim/tools/mailchimp/get_member.ts b/apps/sim/tools/mailchimp/get_member.ts new file mode 100644 index 0000000000..538645e424 --- /dev/null +++ b/apps/sim/tools/mailchimp/get_member.ts @@ -0,0 +1,98 @@ +import { createLogger } from '@/lib/logs/console/logger' +import type { ToolConfig } from '@/tools/types' +import { buildMailchimpUrl, handleMailchimpError } from './types' + +const logger = createLogger('MailchimpGetMember') + +export interface MailchimpGetMemberParams { + apiKey: string + listId: string + subscriberHash: string +} + +export interface MailchimpGetMemberResponse { + success: boolean + output: { + member: any + metadata: { + operation: 'get_member' + subscriberHash: string + } + success: boolean + } +} + +export const mailchimpGetMemberTool: ToolConfig< + MailchimpGetMemberParams, + MailchimpGetMemberResponse +> = { + id: 'mailchimp_get_member', + name: 'Get Member from Mailchimp Audience', + description: 'Retrieve details of a specific member from a Mailchimp audience', + version: '1.0.0', + + params: { + apiKey: { + type: 'string', + required: true, + visibility: 'hidden', + description: 'Mailchimp API key with server prefix', + }, + listId: { + type: 'string', + required: true, + visibility: 'user-only', + description: 'The unique ID for the list', + }, + subscriberHash: { + type: 'string', + required: true, + visibility: 'user-only', + description: "The MD5 hash of the lowercase version of the list member's email address", + }, + }, + + request: { + url: (params) => + buildMailchimpUrl(params.apiKey, `/lists/${params.listId}/members/${params.subscriberHash}`), + method: 'GET', + headers: (params) => ({ + Authorization: `Bearer ${params.apiKey}`, + 'Content-Type': 'application/json', + }), + }, + + transformResponse: async (response: Response) => { + if (!response.ok) { + const data = await response.json() + handleMailchimpError(data, response.status, 'get_member') + } + + const data = await response.json() + + return { + success: true, + output: { + member: data, + metadata: { + operation: 'get_member' as const, + subscriberHash: data.id, + }, + success: true, + }, + } + }, + + outputs: { + success: { type: 'boolean', description: 'Operation success status' }, + output: { + type: 'object', + description: 'Member data and metadata', + properties: { + member: { type: 'object', description: 'Member object' }, + metadata: { type: 'object', description: 'Operation metadata' }, + success: { type: 'boolean', description: 'Operation success' }, + }, + }, + }, +} diff --git a/apps/sim/tools/mailchimp/get_member_tags.ts b/apps/sim/tools/mailchimp/get_member_tags.ts new file mode 100644 index 0000000000..a616f9d19d --- /dev/null +++ b/apps/sim/tools/mailchimp/get_member_tags.ts @@ -0,0 +1,105 @@ +import { createLogger } from '@/lib/logs/console/logger' +import type { ToolConfig } from '@/tools/types' +import { buildMailchimpUrl, handleMailchimpError } from './types' + +const logger = createLogger('MailchimpGetMemberTags') + +export interface MailchimpGetMemberTagsParams { + apiKey: string + listId: string + subscriberHash: string +} + +export interface MailchimpGetMemberTagsResponse { + success: boolean + output: { + tags: any[] + totalItems: number + metadata: { + operation: 'get_member_tags' + totalReturned: number + } + success: boolean + } +} + +export const mailchimpGetMemberTagsTool: ToolConfig< + MailchimpGetMemberTagsParams, + MailchimpGetMemberTagsResponse +> = { + id: 'mailchimp_get_member_tags', + name: 'Get Member Tags from Mailchimp', + description: 'Retrieve tags associated with a member in a Mailchimp audience', + version: '1.0.0', + + params: { + apiKey: { + type: 'string', + required: true, + visibility: 'hidden', + description: 'Mailchimp API key with server prefix', + }, + listId: { + type: 'string', + required: true, + visibility: 'user-only', + description: 'The unique ID for the list', + }, + subscriberHash: { + type: 'string', + required: true, + visibility: 'user-only', + description: "The MD5 hash of the lowercase version of the list member's email address", + }, + }, + + request: { + url: (params) => + buildMailchimpUrl( + params.apiKey, + `/lists/${params.listId}/members/${params.subscriberHash}/tags` + ), + method: 'GET', + headers: (params) => ({ + Authorization: `Bearer ${params.apiKey}`, + 'Content-Type': 'application/json', + }), + }, + + transformResponse: async (response: Response) => { + if (!response.ok) { + const data = await response.json() + handleMailchimpError(data, response.status, 'get_member_tags') + } + + const data = await response.json() + const tags = data.tags || [] + + return { + success: true, + output: { + tags, + totalItems: data.total_items || tags.length, + metadata: { + operation: 'get_member_tags' as const, + totalReturned: tags.length, + }, + success: true, + }, + } + }, + + outputs: { + success: { type: 'boolean', description: 'Operation success status' }, + output: { + type: 'object', + description: 'Member tags data and metadata', + properties: { + tags: { type: 'array', description: 'Array of tag objects' }, + totalItems: { type: 'number', description: 'Total number of tags' }, + metadata: { type: 'object', description: 'Operation metadata' }, + success: { type: 'boolean', description: 'Operation success' }, + }, + }, + }, +} diff --git a/apps/sim/tools/mailchimp/get_members.ts b/apps/sim/tools/mailchimp/get_members.ts new file mode 100644 index 0000000000..64fbaa7b3a --- /dev/null +++ b/apps/sim/tools/mailchimp/get_members.ts @@ -0,0 +1,124 @@ +import { createLogger } from '@/lib/logs/console/logger' +import type { ToolConfig } from '@/tools/types' +import { buildMailchimpUrl, handleMailchimpError } from './types' + +const logger = createLogger('MailchimpGetMembers') + +export interface MailchimpGetMembersParams { + apiKey: string + listId: string + status?: string + count?: string + offset?: string +} + +export interface MailchimpGetMembersResponse { + success: boolean + output: { + members: any[] + totalItems: number + metadata: { + operation: 'get_members' + totalReturned: number + } + success: boolean + } +} + +export const mailchimpGetMembersTool: ToolConfig< + MailchimpGetMembersParams, + MailchimpGetMembersResponse +> = { + id: 'mailchimp_get_members', + name: 'Get Members from Mailchimp Audience', + description: 'Retrieve a list of members from a Mailchimp audience', + version: '1.0.0', + + params: { + apiKey: { + type: 'string', + required: true, + visibility: 'hidden', + description: 'Mailchimp API key with server prefix', + }, + listId: { + type: 'string', + required: true, + visibility: 'user-only', + description: 'The unique ID for the list', + }, + status: { + type: 'string', + required: false, + visibility: 'user-only', + description: 'Filter by status (subscribed, unsubscribed, cleaned, pending)', + }, + count: { + type: 'string', + required: false, + visibility: 'user-only', + description: 'Number of results (default: 10, max: 1000)', + }, + offset: { + type: 'string', + required: false, + visibility: 'user-only', + description: 'Number of results to skip', + }, + }, + + request: { + url: (params) => { + const queryParams = new URLSearchParams() + if (params.status) queryParams.append('status', params.status) + if (params.count) queryParams.append('count', params.count) + if (params.offset) queryParams.append('offset', params.offset) + + const query = queryParams.toString() + const url = buildMailchimpUrl(params.apiKey, `/lists/${params.listId}/members`) + return query ? `${url}?${query}` : url + }, + method: 'GET', + headers: (params) => ({ + Authorization: `Bearer ${params.apiKey}`, + 'Content-Type': 'application/json', + }), + }, + + transformResponse: async (response: Response) => { + if (!response.ok) { + const data = await response.json() + handleMailchimpError(data, response.status, 'get_members') + } + + const data = await response.json() + const members = data.members || [] + + return { + success: true, + output: { + members, + totalItems: data.total_items || members.length, + metadata: { + operation: 'get_members' as const, + totalReturned: members.length, + }, + success: true, + }, + } + }, + + outputs: { + success: { type: 'boolean', description: 'Operation success status' }, + output: { + type: 'object', + description: 'Members data and metadata', + properties: { + members: { type: 'array', description: 'Array of member objects' }, + totalItems: { type: 'number', description: 'Total number of members' }, + metadata: { type: 'object', description: 'Operation metadata' }, + success: { type: 'boolean', description: 'Operation success' }, + }, + }, + }, +} diff --git a/apps/sim/tools/mailchimp/get_merge_field.ts b/apps/sim/tools/mailchimp/get_merge_field.ts new file mode 100644 index 0000000000..912be2a5fc --- /dev/null +++ b/apps/sim/tools/mailchimp/get_merge_field.ts @@ -0,0 +1,98 @@ +import { createLogger } from '@/lib/logs/console/logger' +import type { ToolConfig } from '@/tools/types' +import { buildMailchimpUrl, handleMailchimpError } from './types' + +const logger = createLogger('MailchimpGetMergeField') + +export interface MailchimpGetMergeFieldParams { + apiKey: string + listId: string + mergeId: string +} + +export interface MailchimpGetMergeFieldResponse { + success: boolean + output: { + mergeField: any + metadata: { + operation: 'get_merge_field' + mergeId: string + } + success: boolean + } +} + +export const mailchimpGetMergeFieldTool: ToolConfig< + MailchimpGetMergeFieldParams, + MailchimpGetMergeFieldResponse +> = { + id: 'mailchimp_get_merge_field', + name: 'Get Merge Field from Mailchimp Audience', + description: 'Retrieve details of a specific merge field from a Mailchimp audience', + version: '1.0.0', + + params: { + apiKey: { + type: 'string', + required: true, + visibility: 'hidden', + description: 'Mailchimp API key with server prefix', + }, + listId: { + type: 'string', + required: true, + visibility: 'user-only', + description: 'The unique ID for the list', + }, + mergeId: { + type: 'string', + required: true, + visibility: 'user-only', + description: 'The unique ID for the merge field', + }, + }, + + request: { + url: (params) => + buildMailchimpUrl(params.apiKey, `/lists/${params.listId}/merge-fields/${params.mergeId}`), + method: 'GET', + headers: (params) => ({ + Authorization: `Bearer ${params.apiKey}`, + 'Content-Type': 'application/json', + }), + }, + + transformResponse: async (response: Response) => { + if (!response.ok) { + const data = await response.json() + handleMailchimpError(data, response.status, 'get_merge_field') + } + + const data = await response.json() + + return { + success: true, + output: { + mergeField: data, + metadata: { + operation: 'get_merge_field' as const, + mergeId: data.merge_id, + }, + success: true, + }, + } + }, + + outputs: { + success: { type: 'boolean', description: 'Operation success status' }, + output: { + type: 'object', + description: 'Merge field data and metadata', + properties: { + mergeField: { type: 'object', description: 'Merge field object' }, + metadata: { type: 'object', description: 'Operation metadata' }, + success: { type: 'boolean', description: 'Operation success' }, + }, + }, + }, +} diff --git a/apps/sim/tools/mailchimp/get_merge_fields.ts b/apps/sim/tools/mailchimp/get_merge_fields.ts new file mode 100644 index 0000000000..8e1dbca19a --- /dev/null +++ b/apps/sim/tools/mailchimp/get_merge_fields.ts @@ -0,0 +1,116 @@ +import { createLogger } from '@/lib/logs/console/logger' +import type { ToolConfig } from '@/tools/types' +import { buildMailchimpUrl, handleMailchimpError } from './types' + +const logger = createLogger('MailchimpGetMergeFields') + +export interface MailchimpGetMergeFieldsParams { + apiKey: string + listId: string + count?: string + offset?: string +} + +export interface MailchimpGetMergeFieldsResponse { + success: boolean + output: { + mergeFields: any[] + totalItems: number + metadata: { + operation: 'get_merge_fields' + totalReturned: number + } + success: boolean + } +} + +export const mailchimpGetMergeFieldsTool: ToolConfig< + MailchimpGetMergeFieldsParams, + MailchimpGetMergeFieldsResponse +> = { + id: 'mailchimp_get_merge_fields', + name: 'Get Merge Fields from Mailchimp Audience', + description: 'Retrieve a list of merge fields from a Mailchimp audience', + version: '1.0.0', + + params: { + apiKey: { + type: 'string', + required: true, + visibility: 'hidden', + description: 'Mailchimp API key with server prefix', + }, + listId: { + type: 'string', + required: true, + visibility: 'user-only', + description: 'The unique ID for the list', + }, + count: { + type: 'string', + required: false, + visibility: 'user-only', + description: 'Number of results (default: 10, max: 1000)', + }, + offset: { + type: 'string', + required: false, + visibility: 'user-only', + description: 'Number of results to skip', + }, + }, + + request: { + url: (params) => { + const queryParams = new URLSearchParams() + if (params.count) queryParams.append('count', params.count) + if (params.offset) queryParams.append('offset', params.offset) + + const query = queryParams.toString() + const url = buildMailchimpUrl(params.apiKey, `/lists/${params.listId}/merge-fields`) + return query ? `${url}?${query}` : url + }, + method: 'GET', + headers: (params) => ({ + Authorization: `Bearer ${params.apiKey}`, + 'Content-Type': 'application/json', + }), + }, + + transformResponse: async (response: Response) => { + if (!response.ok) { + const data = await response.json() + handleMailchimpError(data, response.status, 'get_merge_fields') + } + + const data = await response.json() + const mergeFields = data.merge_fields || [] + + return { + success: true, + output: { + mergeFields, + totalItems: data.total_items || mergeFields.length, + metadata: { + operation: 'get_merge_fields' as const, + totalReturned: mergeFields.length, + }, + success: true, + }, + } + }, + + outputs: { + success: { type: 'boolean', description: 'Operation success status' }, + output: { + type: 'object', + description: 'Merge fields data and metadata', + properties: { + mergeFields: { type: 'array', description: 'Array of merge field objects' }, + totalItems: { type: 'number', description: 'Total number of merge fields' }, + metadata: { type: 'object', description: 'Operation metadata' }, + success: { type: 'boolean', description: 'Operation success' }, + }, + }, + }, +} diff --git a/apps/sim/tools/mailchimp/get_segment.ts b/apps/sim/tools/mailchimp/get_segment.ts new file mode 100644 index 0000000000..ed2ba417ad --- /dev/null +++ b/apps/sim/tools/mailchimp/get_segment.ts @@ -0,0 +1,98 @@ +import { createLogger } from '@/lib/logs/console/logger' +import type { ToolConfig } from '@/tools/types' +import { buildMailchimpUrl, handleMailchimpError } from './types' + +const logger = createLogger('MailchimpGetSegment') + +export interface MailchimpGetSegmentParams { + apiKey: string + listId: string + segmentId: string +} + +export interface MailchimpGetSegmentResponse { + success: boolean + output: { + segment: any + metadata: { + operation: 'get_segment' + segmentId: string + } + success: boolean + } +} + +export const mailchimpGetSegmentTool: ToolConfig< + MailchimpGetSegmentParams, + MailchimpGetSegmentResponse +> = { + id: 'mailchimp_get_segment', + name: 'Get Segment from Mailchimp Audience', + description: 'Retrieve details of a specific segment from a Mailchimp audience', + version: '1.0.0', + + params: { + apiKey: { + type: 'string', + required: true, + visibility: 'hidden', + description: 'Mailchimp API key with server prefix', + }, + listId: { + type: 'string', + required: true, + visibility: 'user-only', + description: 'The unique ID for the list', + }, + segmentId: { + type: 'string', + required: true, + visibility: 'user-only', + description: 'The unique ID for the segment', + }, + }, + + request: { + url: (params) => + buildMailchimpUrl(params.apiKey, `/lists/${params.listId}/segments/${params.segmentId}`), + method: 'GET', + headers: (params) => ({ + Authorization: `Bearer ${params.apiKey}`, + 'Content-Type': 'application/json', + }), + }, + + transformResponse: async (response: Response) => { + if (!response.ok) { + const data = await response.json() + handleMailchimpError(data, response.status, 'get_segment') + } + + const data = await response.json() + + return { + success: true, + output: { + segment: data, + metadata: { + operation: 'get_segment' as const, + segmentId: data.id, + }, + success: true, + }, + } + }, + + outputs: { + success: { type: 'boolean', description: 'Operation success status' }, + output: { + type: 'object', + description: 'Segment data and metadata', + properties: { + segment: { type: 'object', description: 'Segment object' }, + metadata: { type: 'object', description: 'Operation metadata' }, + success: { type: 'boolean', description: 'Operation success' }, + }, + }, + }, +} diff --git a/apps/sim/tools/mailchimp/get_segment_members.ts b/apps/sim/tools/mailchimp/get_segment_members.ts new file mode 100644 index 0000000000..8a594c8fb2 --- /dev/null +++ b/apps/sim/tools/mailchimp/get_segment_members.ts @@ -0,0 +1,126 @@ +import { createLogger } from '@/lib/logs/console/logger' +import type { ToolConfig } from '@/tools/types' +import { buildMailchimpUrl, handleMailchimpError } from './types' + +const logger = createLogger('MailchimpGetSegmentMembers') + +export interface MailchimpGetSegmentMembersParams { + apiKey: string + listId: string + segmentId: string + count?: string + offset?: string +} + +export interface MailchimpGetSegmentMembersResponse { + success: boolean + output: { + members: any[] + totalItems: number + metadata: { + operation: 'get_segment_members' + totalReturned: number + } + success: boolean + } +} + +export const mailchimpGetSegmentMembersTool: ToolConfig< + MailchimpGetSegmentMembersParams, + MailchimpGetSegmentMembersResponse +> = { + id: 'mailchimp_get_segment_members', + name: 'Get Segment Members from Mailchimp', + description: 'Retrieve members of a specific segment from a Mailchimp audience', + version: '1.0.0', + + params: { + apiKey: { + type: 'string', + required: true, + visibility: 'hidden', + description: 'Mailchimp API key with server prefix', + }, + listId: { + type: 'string', + required: true, + visibility: 'user-only', + description: 'The unique ID for the list', + }, + segmentId: { + type: 'string', + required: true, + visibility: 'user-only', + description: 'The unique ID for the segment', + }, + count: { + type: 'string', + required: false, + visibility: 'user-only', + description: 'Number of results (default: 10, max: 1000)', + }, + offset: { + type: 'string', + required: false, + visibility: 'user-only', + description: 'Number of results to skip', + }, + }, + + request: { + url: (params) => { + const queryParams = new URLSearchParams() + if (params.count) queryParams.append('count', params.count) + if (params.offset) queryParams.append('offset', params.offset) + + const query = queryParams.toString() + const url = buildMailchimpUrl( + params.apiKey, + `/lists/${params.listId}/segments/${params.segmentId}/members` + ) + return query ? `${url}?${query}` : url + }, + method: 'GET', + headers: (params) => ({ + Authorization: `Bearer ${params.apiKey}`, + 'Content-Type': 'application/json', + }), + }, + + transformResponse: async (response: Response) => { + if (!response.ok) { + const data = await response.json() + handleMailchimpError(data, response.status, 'get_segment_members') + } + + const data = await response.json() + const members = data.members || [] + + return { + success: true, + output: { + members, + totalItems: data.total_items || members.length, + metadata: { + operation: 'get_segment_members' as const, + totalReturned: members.length, + }, + success: true, + }, + } + }, + + outputs: { + success: { type: 'boolean', description: 'Operation success status' }, + output: { + type: 'object', + description: 'Segment members data and metadata', + properties: { + members: { type: 'array', description: 'Array of member objects' }, + totalItems: { type: 'number', description: 'Total number of members' }, + metadata: { type: 'object', description: 'Operation metadata' }, + success: { type: 'boolean', description: 'Operation success' }, + }, + }, + }, +} diff --git a/apps/sim/tools/mailchimp/get_segments.ts b/apps/sim/tools/mailchimp/get_segments.ts new file mode 100644 index 0000000000..480eb0cf73 --- /dev/null +++ b/apps/sim/tools/mailchimp/get_segments.ts @@ -0,0 +1,116 @@ +import { createLogger } from '@/lib/logs/console/logger' +import type { ToolConfig } from '@/tools/types' +import { buildMailchimpUrl, handleMailchimpError } from './types' + +const logger = createLogger('MailchimpGetSegments') + +export interface MailchimpGetSegmentsParams { + apiKey: string + listId: string + count?: string + offset?: string +} + +export interface MailchimpGetSegmentsResponse { + success: boolean + output: { + segments: any[] + totalItems: number + metadata: { + operation: 'get_segments' + totalReturned: number + } + success: boolean + } +} + +export const mailchimpGetSegmentsTool: ToolConfig< + MailchimpGetSegmentsParams, + MailchimpGetSegmentsResponse +> = { + id: 'mailchimp_get_segments', + name: 'Get Segments from Mailchimp Audience', + description: 'Retrieve a list of segments from a Mailchimp audience', + version: '1.0.0', + + params: { + apiKey: { + type: 'string', + required: true, + visibility: 'hidden', + description: 'Mailchimp API key with server prefix', + }, + listId: { + type: 'string', + required: true, + visibility: 'user-only', + description: 'The unique ID for the list', + }, + count: { + type: 'string', + required: false, + visibility: 'user-only', + description: 'Number of results (default: 10, max: 1000)', + }, + offset: { + type: 'string', + required: false, + visibility: 'user-only', + description: 'Number of results to skip', + }, + }, + + request: { + url: (params) => { + const queryParams = new URLSearchParams() + if (params.count) queryParams.append('count', params.count) + if (params.offset) queryParams.append('offset', params.offset) + + const query = queryParams.toString() + const url = buildMailchimpUrl(params.apiKey, `/lists/${params.listId}/segments`) + return query ? `${url}?${query}` : url + }, + method: 'GET', + headers: (params) => ({ + Authorization: `Bearer ${params.apiKey}`, + 'Content-Type': 'application/json', + }), + }, + + transformResponse: async (response: Response) => { + if (!response.ok) { + const data = await response.json() + handleMailchimpError(data, response.status, 'get_segments') + } + + const data = await response.json() + const segments = data.segments || [] + + return { + success: true, + output: { + segments, + totalItems: data.total_items || segments.length, + metadata: { + operation: 'get_segments' as const, + totalReturned: segments.length, + }, + success: true, + }, + } + }, + + outputs: { + success: { type: 'boolean', description: 'Operation success status' }, + output: { + type: 'object', + description: 'Segments data and metadata', + properties: { + segments: { type: 'array', description: 'Array of segment objects' }, + totalItems: { type: 'number', description: 'Total number of segments' }, + metadata: { type: 'object', description: 'Operation metadata' }, + success: { type: 'boolean', description: 'Operation success' }, + }, + }, + }, +} diff --git a/apps/sim/tools/mailchimp/get_template.ts b/apps/sim/tools/mailchimp/get_template.ts new file mode 100644 index 0000000000..31a4f79389 --- /dev/null +++ b/apps/sim/tools/mailchimp/get_template.ts @@ -0,0 +1,90 @@ +import { createLogger } from '@/lib/logs/console/logger' +import type { ToolConfig } from '@/tools/types' +import { buildMailchimpUrl, handleMailchimpError } from './types' + +const logger = createLogger('MailchimpGetTemplate') + +export interface MailchimpGetTemplateParams { + apiKey: string + templateId: string +} + +export interface MailchimpGetTemplateResponse { + success: boolean + output: { + template: any + metadata: { + operation: 'get_template' + templateId: string + } + success: boolean + } +} + +export const mailchimpGetTemplateTool: ToolConfig< + MailchimpGetTemplateParams, + MailchimpGetTemplateResponse +> = { + id: 'mailchimp_get_template', + name: 'Get Template from Mailchimp', + description: 'Retrieve details of a specific template from Mailchimp', + version: '1.0.0', + + params: { + apiKey: { + type: 'string', + required: true, + visibility: 'hidden', + description: 'Mailchimp API key with server prefix', + }, + templateId: { + type: 'string', + required: true, + visibility: 'user-only', + description: 'The unique ID for the template', + }, + }, + + request: { + url: (params) => buildMailchimpUrl(params.apiKey, `/templates/${params.templateId}`), + method: 'GET', + headers: (params) => ({ + Authorization: `Bearer ${params.apiKey}`, + 'Content-Type': 'application/json', + }), + }, + + transformResponse: async (response: Response) => { + if (!response.ok) { + const data = await response.json() + handleMailchimpError(data, response.status, 'get_template') + } + + const data = await response.json() + + return { + success: true, + output: { + template: data, + metadata: { + operation: 'get_template' as const, + templateId: data.id, + }, + success: true, + }, + } + }, + + outputs: { + success: { type: 'boolean', description: 'Operation success status' }, + output: { + type: 'object', + description: 'Template data and metadata', + properties: { + template: { type: 'object', description: 'Template object' }, + metadata: { type: 'object', description: 'Operation metadata' }, + success: { type: 'boolean', description: 'Operation success' }, + }, + }, + }, +} diff --git a/apps/sim/tools/mailchimp/get_templates.ts b/apps/sim/tools/mailchimp/get_templates.ts new file mode 100644 index 0000000000..db181474c6 --- /dev/null +++ b/apps/sim/tools/mailchimp/get_templates.ts @@ -0,0 +1,109 @@ +import { createLogger } from '@/lib/logs/console/logger' +import type { ToolConfig } from '@/tools/types' +import { buildMailchimpUrl, handleMailchimpError } from './types' + +const logger = createLogger('MailchimpGetTemplates') + +export interface MailchimpGetTemplatesParams { + apiKey: string + count?: string + offset?: string +} + +export interface MailchimpGetTemplatesResponse { + success: boolean + output: { + templates: any[] + totalItems: number + metadata: { + operation: 'get_templates' + totalReturned: number + } + success: boolean + } +} + +export const mailchimpGetTemplatesTool: ToolConfig< + MailchimpGetTemplatesParams, + MailchimpGetTemplatesResponse +> = { + id: 'mailchimp_get_templates', + name: 'Get Templates from Mailchimp', + description: 'Retrieve a list of templates from Mailchimp', + version: '1.0.0', + + params: { + apiKey: { + type: 'string', + required: true, + visibility: 'hidden', + description: 'Mailchimp API key with server prefix', + }, + count: { + type: 'string', + required: false, + visibility: 'user-only', + description: 'Number of results (default: 10, max: 1000)', + }, + offset: { + type: 'string', + required: false, + visibility: 'user-only', + description: 'Number of results to skip', + }, + }, + + request: { + url: (params) => { + const queryParams = new URLSearchParams() + if (params.count) queryParams.append('count', params.count) + if (params.offset) queryParams.append('offset', params.offset) + + const query = queryParams.toString() + const url = buildMailchimpUrl(params.apiKey, '/templates') + return query ? `${url}?${query}` : url + }, + method: 'GET', + headers: (params) => ({ + Authorization: `Bearer ${params.apiKey}`, + 'Content-Type': 'application/json', + }), + }, + + transformResponse: async (response: Response) => { + if (!response.ok) { + const data = await response.json() + handleMailchimpError(data, response.status, 'get_templates') + } + + const data = await response.json() + const templates = data.templates || [] + + return { + success: true, + output: { + templates, + totalItems: data.total_items || templates.length, + metadata: { + operation: 'get_templates' as const, + totalReturned: templates.length, + }, + success: true, + }, + } + }, + + outputs: { + success: { type: 'boolean', description: 'Operation success status' }, + output: { + type: 'object', + description: 'Templates data and metadata', + properties: { + templates: { type: 'array', description: 'Array of template objects' }, + totalItems: { type: 'number', description: 'Total number of templates' }, + metadata: { type: 'object', description: 'Operation metadata' }, + success: { type: 'boolean', description: 'Operation success' }, + }, + }, + }, +} diff --git a/apps/sim/tools/mailchimp/index.ts b/apps/sim/tools/mailchimp/index.ts new file mode 100644 index 0000000000..8b1f23a692 --- /dev/null +++ b/apps/sim/tools/mailchimp/index.ts @@ -0,0 +1,88 @@ +// Audience/List tools + +export { mailchimpAddMemberTool } from './add_member' +export { mailchimpAddMemberTagsTool } from './add_member_tags' +export { mailchimpAddOrUpdateMemberTool } from './add_or_update_member' +export { mailchimpAddSegmentMemberTool } from './add_segment_member' +export { mailchimpAddSubscriberToAutomationTool } from './add_subscriber_to_automation' +export { mailchimpArchiveMemberTool } from './archive_member' +export { mailchimpCreateAudienceTool } from './create_audience' +export { mailchimpCreateBatchOperationTool } from './create_batch_operation' +export { mailchimpCreateCampaignTool } from './create_campaign' +export { mailchimpCreateInterestTool } from './create_interest' +export { mailchimpCreateInterestCategoryTool } from './create_interest_category' +export { mailchimpCreateLandingPageTool } from './create_landing_page' +export { mailchimpCreateMergeFieldTool } from './create_merge_field' +export { mailchimpCreateSegmentTool } from './create_segment' +export { mailchimpCreateTemplateTool } from './create_template' +export { mailchimpDeleteAudienceTool } from './delete_audience' +export { mailchimpDeleteBatchOperationTool } from './delete_batch_operation' +export { mailchimpDeleteCampaignTool } from './delete_campaign' +export { mailchimpDeleteInterestTool } from './delete_interest' +export { mailchimpDeleteInterestCategoryTool } from './delete_interest_category' +export { mailchimpDeleteLandingPageTool } from './delete_landing_page' +export { mailchimpDeleteMemberTool } from './delete_member' +export { mailchimpDeleteMergeFieldTool } from './delete_merge_field' +export { mailchimpDeleteSegmentTool } from './delete_segment' +export { mailchimpDeleteTemplateTool } from './delete_template' +export { mailchimpGetAudienceTool } from './get_audience' +export { mailchimpGetAudiencesTool } from './get_audiences' +export { mailchimpGetAutomationTool } from './get_automation' +// Automation tools +export { mailchimpGetAutomationsTool } from './get_automations' +export { mailchimpGetBatchOperationTool } from './get_batch_operation' +// Batch operation tools +export { mailchimpGetBatchOperationsTool } from './get_batch_operations' +export { mailchimpGetCampaignTool } from './get_campaign' +// Campaign content tools +export { mailchimpGetCampaignContentTool } from './get_campaign_content' +export { mailchimpGetCampaignReportTool } from './get_campaign_report' +// Report tools +export { mailchimpGetCampaignReportsTool } from './get_campaign_reports' +// Campaign tools +export { mailchimpGetCampaignsTool } from './get_campaigns' +export { mailchimpGetInterestTool } from './get_interest' +// Interest category tools +export { mailchimpGetInterestCategoriesTool } from './get_interest_categories' +export { mailchimpGetInterestCategoryTool } from './get_interest_category' +// Interest tools +export { mailchimpGetInterestsTool } from './get_interests' +export { mailchimpGetLandingPageTool } from './get_landing_page' +// Landing page tools +export { mailchimpGetLandingPagesTool } from './get_landing_pages' +export { mailchimpGetMemberTool } from './get_member' +// Tag tools +export { mailchimpGetMemberTagsTool } from './get_member_tags' +// Member tools +export { mailchimpGetMembersTool } from './get_members' +export { mailchimpGetMergeFieldTool } from './get_merge_field' +// Merge field tools +export { mailchimpGetMergeFieldsTool } from './get_merge_fields' +export { mailchimpGetSegmentTool } from './get_segment' +export { mailchimpGetSegmentMembersTool } from './get_segment_members' +// Segment tools +export { mailchimpGetSegmentsTool } from './get_segments' +export { mailchimpGetTemplateTool } from './get_template' +// Template tools +export { mailchimpGetTemplatesTool } from './get_templates' +export { mailchimpPauseAutomationTool } from './pause_automation' +export { mailchimpPublishLandingPageTool } from './publish_landing_page' +export { mailchimpRemoveMemberTagsTool } from './remove_member_tags' +export { mailchimpRemoveSegmentMemberTool } from './remove_segment_member' +export { mailchimpReplicateCampaignTool } from './replicate_campaign' +export { mailchimpScheduleCampaignTool } from './schedule_campaign' +export { mailchimpSendCampaignTool } from './send_campaign' +export { mailchimpSetCampaignContentTool } from './set_campaign_content' +export { mailchimpStartAutomationTool } from './start_automation' +export { mailchimpUnarchiveMemberTool } from './unarchive_member' +export { mailchimpUnpublishLandingPageTool } from './unpublish_landing_page' +export { mailchimpUnscheduleCampaignTool } from './unschedule_campaign' +export { mailchimpUpdateAudienceTool } from './update_audience' +export { mailchimpUpdateCampaignTool } from './update_campaign' +export { mailchimpUpdateInterestTool } from './update_interest' +export { mailchimpUpdateInterestCategoryTool } from './update_interest_category' +export { mailchimpUpdateLandingPageTool } from './update_landing_page' +export { mailchimpUpdateMemberTool } from './update_member' +export { mailchimpUpdateMergeFieldTool } from './update_merge_field' +export { mailchimpUpdateSegmentTool } from './update_segment' +export { mailchimpUpdateTemplateTool } from './update_template' diff --git a/apps/sim/tools/mailchimp/pause_automation.ts b/apps/sim/tools/mailchimp/pause_automation.ts new file mode 100644 index 0000000000..0f26072019 --- /dev/null +++ b/apps/sim/tools/mailchimp/pause_automation.ts @@ -0,0 +1,89 @@ +import { createLogger } from '@/lib/logs/console/logger' +import type { ToolConfig } from '@/tools/types' +import { buildMailchimpUrl, handleMailchimpError } from './types' + +const logger = createLogger('MailchimpPauseAutomation') + +export interface MailchimpPauseAutomationParams { + apiKey: string + workflowId: string +} + +export interface MailchimpPauseAutomationResponse { + success: boolean + output: { + metadata: { + operation: 'pause_automation' + workflowId: string + } + success: boolean + } +} + +export const mailchimpPauseAutomationTool: ToolConfig< + MailchimpPauseAutomationParams, + MailchimpPauseAutomationResponse +> = { + id: 'mailchimp_pause_automation', + name: 'Pause Automation in Mailchimp', + description: 'Pause all emails in a Mailchimp automation workflow', + version: '1.0.0', + + params: { + apiKey: { + type: 'string', + required: true, + visibility: 'hidden', + description: 'Mailchimp API key with server prefix', + }, + workflowId: { + type: 'string', + required: true, + visibility: 'user-only', + description: 'The unique ID for the automation workflow', + }, + }, + + request: { + url: (params) => + buildMailchimpUrl( + params.apiKey, + `/automations/${params.workflowId}/actions/pause-all-emails` + ), + method: 'POST', + headers: (params) => ({ + Authorization: `Bearer ${params.apiKey}`, + 'Content-Type': 'application/json', + }), + }, + + transformResponse: async (response: Response) => { + if (!response.ok) { + const data = await response.json() + handleMailchimpError(data, response.status, 'pause_automation') + } + + return { + success: true, + output: { + metadata: { + operation: 'pause_automation' as const, + workflowId: '', + }, + success: true, + }, + } + }, + + outputs: { + success: { type: 'boolean', description: 'Operation success status' }, + output: { + type: 'object', + description: 'Pause confirmation', + properties: { + metadata: { type: 'object', description: 'Operation metadata' }, + success: { type: 'boolean', description: 'Operation success' }, + }, + }, + }, +} diff --git a/apps/sim/tools/mailchimp/publish_landing_page.ts b/apps/sim/tools/mailchimp/publish_landing_page.ts new file mode 100644 index 0000000000..bfcfa700d8 --- /dev/null +++ b/apps/sim/tools/mailchimp/publish_landing_page.ts @@ -0,0 +1,86 @@ +import { createLogger } from '@/lib/logs/console/logger' +import type { ToolConfig } from '@/tools/types' +import { buildMailchimpUrl, handleMailchimpError } from './types' + +const logger = createLogger('MailchimpPublishLandingPage') + +export interface MailchimpPublishLandingPageParams { + apiKey: string + pageId: string +} + +export interface MailchimpPublishLandingPageResponse { + success: boolean + output: { + metadata: { + operation: 'publish_landing_page' + pageId: string + } + success: boolean + } +} + +export const mailchimpPublishLandingPageTool: ToolConfig< + MailchimpPublishLandingPageParams, + MailchimpPublishLandingPageResponse +> = { + id: 'mailchimp_publish_landing_page', + name: 'Publish Landing Page in Mailchimp', + description: 'Publish a landing page in Mailchimp', + version: '1.0.0', + + params: { + apiKey: { + type: 'string', + required: true, + visibility: 'hidden', + description: 'Mailchimp API key with server prefix', + }, + pageId: { + type: 'string', + required: true, + visibility: 'user-only', + description: 'The unique ID for the landing page', + }, + }, + + request: { + url: (params) => + buildMailchimpUrl(params.apiKey, `/landing-pages/${params.pageId}/actions/publish`), + method: 'POST', + headers: (params) => ({ + Authorization: `Bearer ${params.apiKey}`, + 'Content-Type': 'application/json', + }), + }, + + transformResponse: async (response: Response) => { + if (!response.ok) { + const data = await response.json() + handleMailchimpError(data, response.status, 'publish_landing_page') + } + + return { + success: true, + output: { + metadata: { + operation: 'publish_landing_page' as const, + pageId: '', + }, + success: true, + }, + } + }, + + outputs: { + success: { type: 'boolean', description: 'Operation success status' }, + output: { + type: 'object', + description: 'Publish confirmation', + properties: { + metadata: { type: 'object', description: 'Operation metadata' }, + success: { type: 'boolean', description: 'Operation success' }, + }, + }, + }, +} diff --git a/apps/sim/tools/mailchimp/remove_member_tags.ts b/apps/sim/tools/mailchimp/remove_member_tags.ts new file mode 100644 index 0000000000..7d0b99c74d --- /dev/null +++ b/apps/sim/tools/mailchimp/remove_member_tags.ts @@ -0,0 +1,114 @@ +import { createLogger } from '@/lib/logs/console/logger' +import type { ToolConfig } from '@/tools/types' +import { buildMailchimpUrl, handleMailchimpError } from './types' + +const logger = createLogger('MailchimpRemoveMemberTags') + +export interface MailchimpRemoveMemberTagsParams { + apiKey: string + listId: string + subscriberHash: string + tags: string +} + +export interface MailchimpRemoveMemberTagsResponse { + success: boolean + output: { + metadata: { + operation: 'remove_member_tags' + subscriberHash: string + } + success: boolean + } +} + +export const mailchimpRemoveMemberTagsTool: ToolConfig< + MailchimpRemoveMemberTagsParams, + MailchimpRemoveMemberTagsResponse +> = { + id: 'mailchimp_remove_member_tags', + name: 'Remove Tags from Member in Mailchimp', + description: 'Remove tags from a member in a Mailchimp audience', + version: '1.0.0', + + params: { + apiKey: { + type: 'string', + required: true, + visibility: 'hidden', + description: 'Mailchimp API key with server prefix', + }, + listId: { + type: 'string', + required: true, + visibility: 'user-only', + description: 'The unique ID for the list', + }, + subscriberHash: { + type: 'string', + required: true, + visibility: 'user-only', + description: "The MD5 hash of the lowercase version of the list member's email address", + }, + tags: { + type: 'string', + required: true, + visibility: 'user-only', + description: + 'Tags as JSON array with inactive status (e.g., [{"name": "tag1", "status": "inactive"}, {"name": "tag2", "status": "inactive"}])', + }, + }, + + request: { + url: (params) => + buildMailchimpUrl( + params.apiKey, + `/lists/${params.listId}/members/${params.subscriberHash}/tags` + ), + method: 'POST', + headers: (params) => ({ + Authorization: `Bearer ${params.apiKey}`, + 'Content-Type': 'application/json', + }), + body: (params) => { + let tags = [] + try { + tags = JSON.parse(params.tags) + } catch (error) { + logger.warn('Failed to parse tags', { error }) + } + + return { tags } + }, + }, + + transformResponse: async (response: Response) => { + if (!response.ok) { + const data = await response.json() + handleMailchimpError(data, response.status, 'remove_member_tags') + } + + return { + success: true, + output: { + metadata: { + operation: 'remove_member_tags' as const, + subscriberHash: '', + }, + success: true, + }, + } + }, + + outputs: { + success: { type: 'boolean', description: 'Operation success status' }, + output: { + type: 'object', + description: 'Tag removal confirmation', + properties: { + metadata: { type: 'object', description: 'Operation metadata' }, + success: { type: 'boolean', description: 'Operation success' }, + }, + }, + }, +} diff --git a/apps/sim/tools/mailchimp/remove_segment_member.ts b/apps/sim/tools/mailchimp/remove_segment_member.ts new file mode 100644 index 0000000000..d5bdf8e59a --- /dev/null +++ b/apps/sim/tools/mailchimp/remove_segment_member.ts @@ -0,0 +1,103 @@ +import { createLogger } from '@/lib/logs/console/logger' +import type { ToolConfig } from '@/tools/types' +import { buildMailchimpUrl, handleMailchimpError } from './types' + +const logger = createLogger('MailchimpRemoveSegmentMember') + +export interface MailchimpRemoveSegmentMemberParams { + apiKey: string + listId: string + segmentId: string + subscriberHash: string +} + +export interface MailchimpRemoveSegmentMemberResponse { + success: boolean + output: { + metadata: { + operation: 'remove_segment_member' + subscriberHash: string + } + success: boolean + } +} + +export const mailchimpRemoveSegmentMemberTool: ToolConfig< + MailchimpRemoveSegmentMemberParams, + MailchimpRemoveSegmentMemberResponse +> = { + id: 'mailchimp_remove_segment_member', + name: 'Remove Member from Segment in Mailchimp', + description: 'Remove a member from a specific segment in a Mailchimp audience', + version: '1.0.0', + + params: { + apiKey: { + type: 'string', + required: true, + visibility: 'hidden', + description: 'Mailchimp API key with server prefix', + }, + listId: { + type: 'string', + required: true, + visibility: 'user-only', + description: 'The unique ID for the list', + }, + segmentId: { + type: 'string', + required: true, + visibility: 'user-only', + description: 'The unique ID for the segment', + }, + subscriberHash: { + type: 'string', + required: true, + visibility: 'user-only', + description: "The MD5 hash of the lowercase version of the list member's email address", + }, + }, + + request: { + url: (params) => + buildMailchimpUrl( + params.apiKey, + `/lists/${params.listId}/segments/${params.segmentId}/members/${params.subscriberHash}` + ), + method: 'DELETE', + headers: (params) => ({ + Authorization: `Bearer ${params.apiKey}`, + 'Content-Type': 'application/json', + }), + }, + + transformResponse: async (response: Response) => { + if (!response.ok) { + const data = await response.json() + handleMailchimpError(data, response.status, 'remove_segment_member') + } + + return { + success: true, + output: { + metadata: { + operation: 'remove_segment_member' as const, + subscriberHash: '', + }, + success: true, + }, + } + }, + + outputs: { + success: { type: 'boolean', description: 'Operation success status' }, + output: { + type: 'object', + description: 'Removal confirmation', + properties: { + metadata: { type: 'object', description: 'Operation metadata' }, + success: { type: 'boolean', description: 'Operation success' }, + }, + }, + }, +} diff --git a/apps/sim/tools/mailchimp/replicate_campaign.ts b/apps/sim/tools/mailchimp/replicate_campaign.ts new file mode 100644 index 0000000000..36f856045c --- /dev/null +++ b/apps/sim/tools/mailchimp/replicate_campaign.ts @@ -0,0 +1,91 @@ +import { createLogger } from '@/lib/logs/console/logger' +import type { ToolConfig } from '@/tools/types' +import { buildMailchimpUrl, handleMailchimpError } from './types' + +const logger = createLogger('MailchimpReplicateCampaign') + +export interface MailchimpReplicateCampaignParams { + apiKey: string + campaignId: string +} + +export interface MailchimpReplicateCampaignResponse { + success: boolean + output: { + campaign: any + metadata: { + operation: 'replicate_campaign' + campaignId: string + } + success: boolean + } +} + +export const mailchimpReplicateCampaignTool: ToolConfig< + MailchimpReplicateCampaignParams, + MailchimpReplicateCampaignResponse +> = { + id: 'mailchimp_replicate_campaign', + name: 'Replicate Campaign in Mailchimp', + description: 'Create a copy of an existing Mailchimp campaign', + version: '1.0.0', + + params: { + apiKey: { + type: 'string', + required: true, + visibility: 'hidden', + description: 'Mailchimp API key with server prefix', + }, + campaignId: { + type: 'string', + required: true, + visibility: 'user-only', + description: 'The unique ID for the campaign to replicate', + }, + }, + + request: { + url: (params) => + buildMailchimpUrl(params.apiKey, `/campaigns/${params.campaignId}/actions/replicate`), + method: 'POST', + headers: (params) => ({ + Authorization: `Bearer ${params.apiKey}`, + 'Content-Type': 'application/json', + }), + }, + + transformResponse: async (response: Response) => { + if (!response.ok) { + const data = await response.json() + handleMailchimpError(data, response.status, 'replicate_campaign') + } + + const data = await response.json() + + return { + success: true, + output: { + campaign: data, + metadata: { + operation: 'replicate_campaign' as const, + campaignId: data.id, + }, + success: true, + }, + } + }, + + outputs: { + success: { type: 'boolean', description: 'Operation success status' }, + output: { + type: 'object', + description: 'Replicated campaign data', + properties: { + campaign: { type: 'object', description: 'Replicated campaign object' }, + metadata: { type: 'object', description: 'Operation metadata' }, + success: { type: 'boolean', description: 'Operation success' }, + }, + }, + }, +} diff --git a/apps/sim/tools/mailchimp/schedule_campaign.ts b/apps/sim/tools/mailchimp/schedule_campaign.ts new file mode 100644 index 0000000000..971d7a863b --- /dev/null +++ b/apps/sim/tools/mailchimp/schedule_campaign.ts @@ -0,0 +1,98 @@ +import { createLogger } from '@/lib/logs/console/logger' +import type { ToolConfig } from '@/tools/types' +import { buildMailchimpUrl, handleMailchimpError } from './types' + +const logger = createLogger('MailchimpScheduleCampaign') + +export interface MailchimpScheduleCampaignParams { + apiKey: string + campaignId: string + scheduleTime: string +} + +export interface MailchimpScheduleCampaignResponse { + success: boolean + output: { + metadata: { + operation: 'schedule_campaign' + campaignId: string + scheduleTime: string + } + success: boolean + } +} + +export const mailchimpScheduleCampaignTool: ToolConfig< + MailchimpScheduleCampaignParams, + MailchimpScheduleCampaignResponse +> = { + id: 'mailchimp_schedule_campaign', + name: 'Schedule Campaign in Mailchimp', + description: 'Schedule a Mailchimp campaign to be sent at a specific time', + version: '1.0.0', + + params: { + apiKey: { + type: 'string', + required: true, + visibility: 'hidden', + description: 'Mailchimp API key with server prefix', + }, + campaignId: { + type: 'string', + required: true, + visibility: 'user-only', + description: 'The unique ID for the campaign to schedule', + }, + scheduleTime: { + type: 'string', + required: true, + visibility: 'user-only', + description: 'The date and time in ISO 8601 format (e.g., 2024-01-01T12:00:00+00:00)', + }, + }, + + request: { + url: (params) => + buildMailchimpUrl(params.apiKey, `/campaigns/${params.campaignId}/actions/schedule`), + method: 'POST', + headers: (params) => ({ + Authorization: `Bearer ${params.apiKey}`, + 'Content-Type': 'application/json', + }), + body: (params) => ({ + schedule_time: params.scheduleTime, + }), + }, + + transformResponse: async (response: Response) => { + if (!response.ok) { + const data = await response.json() + handleMailchimpError(data, response.status, 'schedule_campaign') + } + + return { + success: true, + output: { + metadata: { + operation: 'schedule_campaign' as const, + campaignId: '', + scheduleTime: '', + }, + success: true, + }, + } + }, + + outputs: { + success: { type: 'boolean', description: 'Operation success status' }, + output: { + type: 'object', + description: 'Schedule confirmation', + properties: { + metadata: { type: 'object', description: 'Operation metadata' }, + success: { type: 'boolean', description: 'Operation success' }, + }, + }, + }, +} diff --git a/apps/sim/tools/mailchimp/send_campaign.ts b/apps/sim/tools/mailchimp/send_campaign.ts new file mode 100644 index 0000000000..f30269e80f --- /dev/null +++ b/apps/sim/tools/mailchimp/send_campaign.ts @@ -0,0 +1,86 @@ +import { createLogger } from '@/lib/logs/console/logger' +import type { ToolConfig } from '@/tools/types' +import { buildMailchimpUrl, handleMailchimpError } from './types' + +const logger = createLogger('MailchimpSendCampaign') + +export interface MailchimpSendCampaignParams { + apiKey: string + campaignId: string +} + +export interface MailchimpSendCampaignResponse { + success: boolean + output: { + metadata: { + operation: 'send_campaign' + campaignId: string + } + success: boolean + } +} + +export const mailchimpSendCampaignTool: ToolConfig< + MailchimpSendCampaignParams, + MailchimpSendCampaignResponse +> = { + id: 'mailchimp_send_campaign', + name: 'Send Campaign in Mailchimp', + description: 'Send a Mailchimp campaign', + version: '1.0.0', + + params: { + apiKey: { + type: 'string', + required: true, + visibility: 'hidden', + description: 'Mailchimp API key with server prefix', + }, + campaignId: { + type: 'string', + required: true, + visibility: 'user-only', + description: 'The unique ID for the campaign to send', + }, + }, + + request: { + url: (params) => + buildMailchimpUrl(params.apiKey, `/campaigns/${params.campaignId}/actions/send`), + method: 'POST', + headers: (params) => ({ + Authorization: `Bearer ${params.apiKey}`, + 'Content-Type': 'application/json', + }), + }, + + transformResponse: async (response: Response) => { + if (!response.ok) { + const data = await response.json() + handleMailchimpError(data, response.status, 'send_campaign') + } + + return { + success: true, + output: { + metadata: { + operation: 'send_campaign' as const, + campaignId: '', + }, + success: true, + }, + } + }, + + outputs: { + success: { type: 'boolean', description: 'Operation success status' }, + output: { + type: 'object', + description: 'Send confirmation', + properties: { + metadata: { type: 'object', description: 'Operation metadata' }, + success: { type: 'boolean', description: 'Operation success' }, + }, + }, + }, +} diff --git a/apps/sim/tools/mailchimp/set_campaign_content.ts b/apps/sim/tools/mailchimp/set_campaign_content.ts new file mode 100644 index 0000000000..737756c548 --- /dev/null +++ b/apps/sim/tools/mailchimp/set_campaign_content.ts @@ -0,0 +1,120 @@ +import { createLogger } from '@/lib/logs/console/logger' +import type { ToolConfig } from '@/tools/types' +import { buildMailchimpUrl, handleMailchimpError } from './types' + +const logger = createLogger('MailchimpSetCampaignContent') + +export interface MailchimpSetCampaignContentParams { + apiKey: string + campaignId: string + html?: string + plainText?: string + templateId?: string +} + +export interface MailchimpSetCampaignContentResponse { + success: boolean + output: { + content: any + metadata: { + operation: 'set_campaign_content' + campaignId: string + } + success: boolean + } +} + +export const mailchimpSetCampaignContentTool: ToolConfig< + MailchimpSetCampaignContentParams, + MailchimpSetCampaignContentResponse +> = { + id: 'mailchimp_set_campaign_content', + name: 'Set Campaign Content in Mailchimp', + description: 'Set the content for a Mailchimp campaign', + version: '1.0.0', + + params: { + apiKey: { + type: 'string', + required: true, + visibility: 'hidden', + description: 'Mailchimp API key with server prefix', + }, + campaignId: { + type: 'string', + required: true, + visibility: 'user-only', + description: 'The unique ID for the campaign', + }, + html: { + type: 'string', + required: false, + visibility: 'user-only', + description: 'The HTML content for the campaign', + }, + plainText: { + type: 'string', + required: false, + visibility: 'user-only', + description: 'The plain-text content for the campaign', + }, + templateId: { + type: 'string', + required: false, + visibility: 'user-only', + description: 'The ID of the template to use', + }, + }, + + request: { + url: (params) => buildMailchimpUrl(params.apiKey, `/campaigns/${params.campaignId}/content`), + method: 'PUT', + headers: (params) => ({ + Authorization: `Bearer ${params.apiKey}`, + 'Content-Type': 'application/json', + }), + body: (params) => { + const body: any = {} + + if (params.html) body.html = params.html + if (params.plainText) body.plain_text = params.plainText + if (params.templateId) body.template = { id: params.templateId } + + return body + }, + }, + + transformResponse: async (response: Response) => { + if (!response.ok) { + const data = await response.json() + handleMailchimpError(data, response.status, 'set_campaign_content') + } + + const data = await response.json() + + return { + success: true, + output: { + content: data, + metadata: { + operation: 'set_campaign_content' as const, + campaignId: '', + }, + success: true, + }, + } + }, + + outputs: { + success: { type: 'boolean', description: 'Operation success status' }, + output: { + type: 'object', + description: 'Campaign content data', + properties: { + content: { type: 'object', description: 'Campaign content object' }, + metadata: { type: 'object', description: 'Operation metadata' }, + success: { type: 'boolean', description: 'Operation success' }, + }, + }, + }, +} diff --git a/apps/sim/tools/mailchimp/start_automation.ts b/apps/sim/tools/mailchimp/start_automation.ts new file mode 100644 index 0000000000..4f7fa3133c --- /dev/null +++ b/apps/sim/tools/mailchimp/start_automation.ts @@ -0,0 +1,89 @@ +import { createLogger } from '@/lib/logs/console/logger' +import type { ToolConfig } from '@/tools/types' +import { buildMailchimpUrl, handleMailchimpError } from './types' + +const logger = createLogger('MailchimpStartAutomation') + +export interface MailchimpStartAutomationParams { + apiKey: string + workflowId: string +} + +export interface MailchimpStartAutomationResponse { + success: boolean + output: { + metadata: { + operation: 'start_automation' + workflowId: string + } + success: boolean + } +} + +export const mailchimpStartAutomationTool: ToolConfig< + MailchimpStartAutomationParams, + MailchimpStartAutomationResponse +> = { + id: 'mailchimp_start_automation', + name: 'Start Automation in Mailchimp', + description: 'Start all emails in a Mailchimp automation workflow', + version: '1.0.0', + + params: { + apiKey: { + type: 'string', + required: true, + visibility: 'hidden', + description: 'Mailchimp API key with server prefix', + }, + workflowId: { + type: 'string', + required: true, + visibility: 'user-only', + description: 'The unique ID for the automation workflow', + }, + }, + + request: { + url: (params) => + buildMailchimpUrl( + params.apiKey, + `/automations/${params.workflowId}/actions/start-all-emails` + ), + method: 'POST', + headers: (params) => ({ + Authorization: `Bearer ${params.apiKey}`, + 'Content-Type': 'application/json', + }), + }, + + transformResponse: async (response: Response) => { + if (!response.ok) { + const data = await response.json() + handleMailchimpError(data, response.status, 'start_automation') + } + + return { + success: true, + output: { + metadata: { + operation: 'start_automation' as const, + workflowId: '', + }, + success: true, + }, + } + }, + + outputs: { + success: { type: 'boolean', description: 'Operation success status' }, + output: { + type: 'object', + description: 'Start confirmation', + properties: { + metadata: { type: 'object', description: 'Operation metadata' }, + success: { type: 'boolean', description: 'Operation success' }, + }, + }, + }, +} diff --git a/apps/sim/tools/mailchimp/types.ts b/apps/sim/tools/mailchimp/types.ts new file mode 100644 index 0000000000..2348e68639 --- /dev/null +++ b/apps/sim/tools/mailchimp/types.ts @@ -0,0 +1,53 @@ +import { createLogger } from '@/lib/logs/console/logger' + +const logger = createLogger('Mailchimp') + +// Base params +export interface MailchimpBaseParams { + apiKey: string // API key with server prefix (e.g., "key-us19") +} + +export interface MailchimpPaginationParams { + count?: string + offset?: string +} + +export interface MailchimpPagingInfo { + totalItems: number +} + +export interface MailchimpResponse { + success: boolean + output: { + data?: T + paging?: MailchimpPagingInfo + metadata: { + operation: string + [key: string]: any + } + success: boolean + } +} + +// Helper function to extract server prefix from API key +export function extractServerPrefix(apiKey: string): string { + const parts = apiKey.split('-') + if (parts.length < 2) { + throw new Error('Invalid Mailchimp API key format. Expected format: key-dc (e.g., abc123-us19)') + } + return parts[parts.length - 1] +} + +// Helper function to build Mailchimp API URLs +export function buildMailchimpUrl(apiKey: string, path: string): string { + const serverPrefix = extractServerPrefix(apiKey) + return `https://${serverPrefix}.api.mailchimp.com/3.0${path}` +} + +// Helper function for consistent error handling +export function handleMailchimpError(data: any, status: number, operation: string): never { + logger.error(`Mailchimp API request failed for ${operation}`, { data, status }) + + const errorMessage = data.detail || data.title || data.error || data.message || 'Unknown error' + throw new Error(`Mailchimp ${operation} failed: ${errorMessage}`) +} diff --git a/apps/sim/tools/mailchimp/unarchive_member.ts b/apps/sim/tools/mailchimp/unarchive_member.ts new file mode 100644 index 0000000000..873007bd84 --- /dev/null +++ b/apps/sim/tools/mailchimp/unarchive_member.ts @@ -0,0 +1,116 @@ +import { createLogger } from '@/lib/logs/console/logger' +import type { ToolConfig } from '@/tools/types' +import { buildMailchimpUrl, handleMailchimpError } from './types' + +const logger = createLogger('MailchimpUnarchiveMember') + +export interface MailchimpUnarchiveMemberParams { + apiKey: string + listId: string + subscriberHash: string + emailAddress: string + status: string +} + +export interface MailchimpUnarchiveMemberResponse { + success: boolean + output: { + member: any + metadata: { + operation: 'unarchive_member' + subscriberHash: string + } + success: boolean + } +} + +export const mailchimpUnarchiveMemberTool: ToolConfig< + MailchimpUnarchiveMemberParams, + MailchimpUnarchiveMemberResponse +> = { + id: 'mailchimp_unarchive_member', + name: 'Unarchive Member in Mailchimp Audience', + description: 'Restore an archived member to a Mailchimp audience', + version: '1.0.0', + + params: { + apiKey: { + type: 'string', + required: true, + visibility: 'hidden', + description: 'Mailchimp API key with server prefix', + }, + listId: { + type: 'string', + required: true, + visibility: 'user-only', + description: 'The unique ID for the list', + }, + subscriberHash: { + type: 'string', + required: true, + visibility: 'user-only', + description: "The MD5 hash of the lowercase version of the list member's email address", + }, + emailAddress: { + type: 'string', + required: true, + visibility: 'user-only', + description: 'Email address for the member', + }, + status: { + type: 'string', + required: true, + visibility: 'user-only', + description: 'Subscriber status (subscribed, unsubscribed, cleaned, pending)', + }, + }, + + request: { + url: (params) => + buildMailchimpUrl(params.apiKey, `/lists/${params.listId}/members/${params.subscriberHash}`), + method: 'PUT', + headers: (params) => ({ + Authorization: `Bearer ${params.apiKey}`, + 'Content-Type': 'application/json', + }), + body: (params) => ({ + email_address: params.emailAddress, + status: params.status, + }), + }, + + transformResponse: async (response: Response) => { + if (!response.ok) { + const data = await response.json() + handleMailchimpError(data, response.status, 'unarchive_member') + } + + const data = await response.json() + + return { + success: true, + output: { + member: data, + metadata: { + operation: 'unarchive_member' as const, + subscriberHash: data.id, + }, + success: true, + }, + } + }, + + outputs: { + success: { type: 'boolean', description: 'Operation success status' }, + output: { + type: 'object', + description: 'Unarchived member data', + properties: { + member: { type: 'object', description: 'Unarchived member object' }, + metadata: { type: 'object', description: 'Operation metadata' }, + success: { type: 'boolean', description: 'Operation success' }, + }, + }, + }, +} diff --git a/apps/sim/tools/mailchimp/unpublish_landing_page.ts b/apps/sim/tools/mailchimp/unpublish_landing_page.ts new file mode 100644 index 0000000000..defa2bdb3f --- /dev/null +++ b/apps/sim/tools/mailchimp/unpublish_landing_page.ts @@ -0,0 +1,86 @@ +import { createLogger } from '@/lib/logs/console/logger' +import type { ToolConfig } from '@/tools/types' +import { buildMailchimpUrl, handleMailchimpError } from './types' + +const logger = createLogger('MailchimpUnpublishLandingPage') + +export interface MailchimpUnpublishLandingPageParams { + apiKey: string + pageId: string +} + +export interface MailchimpUnpublishLandingPageResponse { + success: boolean + output: { + metadata: { + operation: 'unpublish_landing_page' + pageId: string + } + success: boolean + } +} + +export const mailchimpUnpublishLandingPageTool: ToolConfig< + MailchimpUnpublishLandingPageParams, + MailchimpUnpublishLandingPageResponse +> = { + id: 'mailchimp_unpublish_landing_page', + name: 'Unpublish Landing Page in Mailchimp', + description: 'Unpublish a landing page in Mailchimp', + version: '1.0.0', + + params: { + apiKey: { + type: 'string', + required: true, + visibility: 'hidden', + description: 'Mailchimp API key with server prefix', + }, + pageId: { + type: 'string', + required: true, + visibility: 'user-only', + description: 'The unique ID for the landing page', + }, + }, + + request: { + url: (params) => + buildMailchimpUrl(params.apiKey, `/landing-pages/${params.pageId}/actions/unpublish`), + method: 'POST', + headers: (params) => ({ + Authorization: `Bearer ${params.apiKey}`, + 'Content-Type': 'application/json', + }), + }, + + transformResponse: async (response: Response) => { + if (!response.ok) { + const data = await response.json() + handleMailchimpError(data, response.status, 'unpublish_landing_page') + } + + return { + success: true, + output: { + metadata: { + operation: 'unpublish_landing_page' as const, + pageId: '', + }, + success: true, + }, + } + }, + + outputs: { + success: { type: 'boolean', description: 'Operation success status' }, + output: { + type: 'object', + description: 'Unpublish confirmation', + properties: { + metadata: { type: 'object', description: 'Operation metadata' }, + success: { type: 'boolean', description: 'Operation success' }, + }, + }, + }, +} diff --git a/apps/sim/tools/mailchimp/unschedule_campaign.ts b/apps/sim/tools/mailchimp/unschedule_campaign.ts new file mode 100644 index 0000000000..20f383a8c5 --- /dev/null +++ b/apps/sim/tools/mailchimp/unschedule_campaign.ts @@ -0,0 +1,86 @@ +import { createLogger } from '@/lib/logs/console/logger' +import type { ToolConfig } from '@/tools/types' +import { buildMailchimpUrl, handleMailchimpError } from './types' + +const logger = createLogger('MailchimpUnscheduleCampaign') + +export interface MailchimpUnscheduleCampaignParams { + apiKey: string + campaignId: string +} + +export interface MailchimpUnscheduleCampaignResponse { + success: boolean + output: { + metadata: { + operation: 'unschedule_campaign' + campaignId: string + } + success: boolean + } +} + +export const mailchimpUnscheduleCampaignTool: ToolConfig< + MailchimpUnscheduleCampaignParams, + MailchimpUnscheduleCampaignResponse +> = { + id: 'mailchimp_unschedule_campaign', + name: 'Unschedule Campaign in Mailchimp', + description: 'Unschedule a previously scheduled Mailchimp campaign', + version: '1.0.0', + + params: { + apiKey: { + type: 'string', + required: true, + visibility: 'hidden', + description: 'Mailchimp API key with server prefix', + }, + campaignId: { + type: 'string', + required: true, + visibility: 'user-only', + description: 'The unique ID for the campaign to unschedule', + }, + }, + + request: { + url: (params) => + buildMailchimpUrl(params.apiKey, `/campaigns/${params.campaignId}/actions/unschedule`), + method: 'POST', + headers: (params) => ({ + Authorization: `Bearer ${params.apiKey}`, + 'Content-Type': 'application/json', + }), + }, + + transformResponse: async (response: Response) => { + if (!response.ok) { + const data = await response.json() + handleMailchimpError(data, response.status, 'unschedule_campaign') + } + + return { + success: true, + output: { + metadata: { + operation: 'unschedule_campaign' as const, + campaignId: '', + }, + success: true, + }, + } + }, + + outputs: { + success: { type: 'boolean', description: 'Operation success status' }, + output: { + type: 'object', + description: 'Unschedule confirmation', + properties: { + metadata: { type: 'object', description: 'Operation metadata' }, + success: { type: 'boolean', description: 'Operation success' }, + }, + }, + }, +} diff --git a/apps/sim/tools/mailchimp/update_audience.ts b/apps/sim/tools/mailchimp/update_audience.ts new file mode 100644 index 0000000000..07f96ab5a1 --- /dev/null +++ b/apps/sim/tools/mailchimp/update_audience.ts @@ -0,0 +1,136 @@ +import { createLogger } from '@/lib/logs/console/logger' +import type { ToolConfig } from '@/tools/types' +import { buildMailchimpUrl, handleMailchimpError } from './types' + +const logger = createLogger('MailchimpUpdateAudience') + +export interface MailchimpUpdateAudienceParams { + apiKey: string + listId: string + audienceName?: string + permissionReminder?: string + campaignDefaults?: string + emailTypeOption?: string +} + +export interface MailchimpUpdateAudienceResponse { + success: boolean + output: { + list: any + metadata: { + operation: 'update_audience' + listId: string + } + success: boolean + } +} + +export const mailchimpUpdateAudienceTool: ToolConfig< + MailchimpUpdateAudienceParams, + MailchimpUpdateAudienceResponse +> = { + id: 'mailchimp_update_audience', + name: 'Update Audience in Mailchimp', + description: 'Update an existing audience (list) in Mailchimp', + version: '1.0.0', + + params: { + apiKey: { + type: 'string', + required: true, + visibility: 'hidden', + description: 'Mailchimp API key with server prefix', + }, + listId: { + type: 'string', + required: true, + visibility: 'user-only', + description: 'The unique ID for the list', + }, + audienceName: { + type: 'string', + required: false, + visibility: 'user-only', + description: 'The name of the list', + }, + permissionReminder: { + type: 'string', + required: false, + visibility: 'user-only', + description: 'Permission reminder text', + }, + campaignDefaults: { + type: 'string', + required: false, + visibility: 'user-only', + description: 'Default campaign settings as JSON', + }, + emailTypeOption: { + type: 'string', + required: false, + visibility: 'user-only', + description: 'Whether the list supports multiple formats (true/false)', + }, + }, + + request: { + url: (params) => buildMailchimpUrl(params.apiKey, `/lists/${params.listId}`), + method: 'PATCH', + headers: (params) => ({ + Authorization: `Bearer ${params.apiKey}`, + 'Content-Type': 'application/json', + }), + body: (params) => { + const body: any = {} + + if (params.audienceName) body.name = params.audienceName + if (params.permissionReminder) body.permission_reminder = params.permissionReminder + if (params.emailTypeOption !== undefined) + body.email_type_option = params.emailTypeOption === 'true' + + if (params.campaignDefaults) { + try { + body.campaign_defaults = JSON.parse(params.campaignDefaults) + } catch (error) { + logger.warn('Failed to parse campaign defaults', { error }) + } + } + + return body + }, + }, + + transformResponse: async (response: Response) => { + if (!response.ok) { + const data = await response.json() + handleMailchimpError(data, response.status, 'update_audience') + } + + const data = await response.json() + + return { + success: true, + output: { + list: data, + metadata: { + operation: 'update_audience' as const, + listId: data.id, + }, + success: true, + }, + } + }, + + outputs: { + success: { type: 'boolean', description: 'Operation success status' }, + output: { + type: 'object', + description: 'Updated audience data', + properties: { + list: { type: 'object', description: 'Updated audience/list object' }, + metadata: { type: 'object', description: 'Operation metadata' }, + success: { type: 'boolean', description: 'Operation success' }, + }, + }, + }, +} diff --git a/apps/sim/tools/mailchimp/update_campaign.ts b/apps/sim/tools/mailchimp/update_campaign.ts new file mode 100644 index 0000000000..0824f006c1 --- /dev/null +++ b/apps/sim/tools/mailchimp/update_campaign.ts @@ -0,0 +1,125 @@ +import { createLogger } from '@/lib/logs/console/logger' +import type { ToolConfig } from '@/tools/types' +import { buildMailchimpUrl, handleMailchimpError } from './types' + +const logger = createLogger('MailchimpUpdateCampaign') + +export interface MailchimpUpdateCampaignParams { + apiKey: string + campaignId: string + campaignSettings?: string + recipients?: string +} + +export interface MailchimpUpdateCampaignResponse { + success: boolean + output: { + campaign: any + metadata: { + operation: 'update_campaign' + campaignId: string + } + success: boolean + } +} + +export const mailchimpUpdateCampaignTool: ToolConfig< + MailchimpUpdateCampaignParams, + MailchimpUpdateCampaignResponse +> = { + id: 'mailchimp_update_campaign', + name: 'Update Campaign in Mailchimp', + description: 'Update an existing campaign in Mailchimp', + version: '1.0.0', + + params: { + apiKey: { + type: 'string', + required: true, + visibility: 'hidden', + description: 'Mailchimp API key with server prefix', + }, + campaignId: { + type: 'string', + required: true, + visibility: 'user-only', + description: 'The unique ID for the campaign', + }, + campaignSettings: { + type: 'string', + required: false, + visibility: 'user-only', + description: 'Campaign settings as JSON', + }, + recipients: { + type: 'string', + required: false, + visibility: 'user-only', + description: 'Recipients as JSON', + }, + }, + + request: { + url: (params) => buildMailchimpUrl(params.apiKey, `/campaigns/${params.campaignId}`), + method: 'PATCH', + headers: (params) => ({ + Authorization: `Bearer ${params.apiKey}`, + 'Content-Type': 'application/json', + }), + body: (params) => { + const body: any = {} + + if (params.campaignSettings) { + try { + body.settings = JSON.parse(params.campaignSettings) + } catch (error) { + logger.warn('Failed to parse campaign settings', { error }) + } + } + + if (params.recipients) { + try { + body.recipients = JSON.parse(params.recipients) + } catch (error) { + logger.warn('Failed to parse recipients', { error }) + } + } + + return body + }, + }, + + transformResponse: async (response: Response) => { + if (!response.ok) { + const data = await response.json() + handleMailchimpError(data, response.status, 'update_campaign') + } + + const data = await response.json() + + return { + success: true, + output: { + campaign: data, + metadata: { + operation: 'update_campaign' as const, + campaignId: data.id, + }, + success: true, + }, + } + }, + + outputs: { + success: { type: 'boolean', description: 'Operation success status' }, + output: { + type: 'object', + description: 'Updated campaign data', + properties: { + campaign: { type: 'object', description: 'Updated campaign object' }, + metadata: { type: 'object', description: 'Operation metadata' }, + success: { type: 'boolean', description: 'Operation success' }, + }, + }, + }, +} diff --git a/apps/sim/tools/mailchimp/update_interest.ts b/apps/sim/tools/mailchimp/update_interest.ts new file mode 100644 index 0000000000..ba9d03016c --- /dev/null +++ b/apps/sim/tools/mailchimp/update_interest.ts @@ -0,0 +1,122 @@ +import { createLogger } from '@/lib/logs/console/logger' +import type { ToolConfig } from '@/tools/types' +import { buildMailchimpUrl, handleMailchimpError } from './types' + +const logger = createLogger('MailchimpUpdateInterest') + +export interface MailchimpUpdateInterestParams { + apiKey: string + listId: string + interestCategoryId: string + interestId: string + interestName?: string +} + +export interface MailchimpUpdateInterestResponse { + success: boolean + output: { + interest: any + metadata: { + operation: 'update_interest' + interestId: string + } + success: boolean + } +} + +export const mailchimpUpdateInterestTool: ToolConfig< + MailchimpUpdateInterestParams, + MailchimpUpdateInterestResponse +> = { + id: 'mailchimp_update_interest', + name: 'Update Interest in Mailchimp Interest Category', + description: 'Update an existing interest in an interest category in a Mailchimp audience', + version: '1.0.0', + + params: { + apiKey: { + type: 'string', + required: true, + visibility: 'hidden', + description: 'Mailchimp API key with server prefix', + }, + listId: { + type: 'string', + required: true, + visibility: 'user-only', + description: 'The unique ID for the list', + }, + interestCategoryId: { + type: 'string', + required: true, + visibility: 'user-only', + description: 'The unique ID for the interest category', + }, + interestId: { + type: 'string', + required: true, + visibility: 'user-only', + description: 'The unique ID for the interest', + }, + interestName: { + type: 'string', + required: false, + visibility: 'user-only', + description: 'The name of the interest', + }, + }, + + request: { + url: (params) => + buildMailchimpUrl( + params.apiKey, + `/lists/${params.listId}/interest-categories/${params.interestCategoryId}/interests/${params.interestId}` + ), + method: 'PATCH', + headers: (params) => ({ + Authorization: `Bearer ${params.apiKey}`, + 'Content-Type': 'application/json', + }), + body: (params) => { + const body: any = {} + + if (params.interestName) body.name = params.interestName + + return body + }, + }, + + transformResponse: async (response: Response) => { + if (!response.ok) { + const data = await response.json() + handleMailchimpError(data, response.status, 'update_interest') + } + + const data = await response.json() + + return { + success: true, + output: { + interest: data, + metadata: { + operation: 'update_interest' as const, + interestId: data.id, + }, + success: true, + }, + } + }, + + outputs: { + success: { type: 'boolean', description: 'Operation success status' }, + output: { + type: 'object', + description: 'Updated interest data', + properties: { + interest: { type: 'object', description: 'Updated interest object' }, + metadata: { type: 'object', description: 'Operation metadata' }, + success: { type: 'boolean', description: 'Operation success' }, + }, + }, + }, +} diff --git a/apps/sim/tools/mailchimp/update_interest_category.ts b/apps/sim/tools/mailchimp/update_interest_category.ts new file mode 100644 index 0000000000..b21fa61226 --- /dev/null +++ b/apps/sim/tools/mailchimp/update_interest_category.ts @@ -0,0 +1,115 @@ +import { createLogger } from '@/lib/logs/console/logger' +import type { ToolConfig } from '@/tools/types' +import { buildMailchimpUrl, handleMailchimpError } from './types' + +const logger = createLogger('MailchimpUpdateInterestCategory') + +export interface MailchimpUpdateInterestCategoryParams { + apiKey: string + listId: string + interestCategoryId: string + interestCategoryTitle?: string +} + +export interface MailchimpUpdateInterestCategoryResponse { + success: boolean + output: { + category: any + metadata: { + operation: 'update_interest_category' + interestCategoryId: string + } + success: boolean + } +} + +export const mailchimpUpdateInterestCategoryTool: ToolConfig< + MailchimpUpdateInterestCategoryParams, + MailchimpUpdateInterestCategoryResponse +> = { + id: 'mailchimp_update_interest_category', + name: 'Update Interest Category in Mailchimp Audience', + description: 'Update an existing interest category in a Mailchimp audience', + version: '1.0.0', + + params: { + apiKey: { + type: 'string', + required: true, + visibility: 'hidden', + description: 'Mailchimp API key with server prefix', + }, + listId: { + type: 'string', + required: true, + visibility: 'user-only', + description: 'The unique ID for the list', + }, + interestCategoryId: { + type: 'string', + required: true, + visibility: 'user-only', + description: 'The unique ID for the interest category', + }, + interestCategoryTitle: { + type: 'string', + required: false, + visibility: 'user-only', + description: 'The title of the interest category', + }, + }, + + request: { + url: (params) => + buildMailchimpUrl( + params.apiKey, + `/lists/${params.listId}/interest-categories/${params.interestCategoryId}` + ), + method: 'PATCH', + headers: (params) => ({ + Authorization: `Bearer ${params.apiKey}`, + 'Content-Type': 'application/json', + }), + body: (params) => { + const body: any = {} + + if (params.interestCategoryTitle) body.title = params.interestCategoryTitle + + return body + }, + }, + + transformResponse: async (response: Response) => { + if (!response.ok) { + const data = await response.json() + handleMailchimpError(data, response.status, 'update_interest_category') + } + + const data = await response.json() + + return { + success: true, + output: { + category: data, + metadata: { + operation: 'update_interest_category' as const, + interestCategoryId: data.id, + }, + success: true, + }, + } + }, + + outputs: { + success: { type: 'boolean', description: 'Operation success status' }, + output: { + type: 'object', + description: 'Updated interest category data', + properties: { + category: { type: 'object', description: 'Updated interest category object' }, + metadata: { type: 'object', description: 'Operation metadata' }, + success: { type: 'boolean', description: 'Operation success' }, + }, + }, + }, +} diff --git a/apps/sim/tools/mailchimp/update_landing_page.ts b/apps/sim/tools/mailchimp/update_landing_page.ts new file mode 100644 index 0000000000..8d002653e7 --- /dev/null +++ b/apps/sim/tools/mailchimp/update_landing_page.ts @@ -0,0 +1,104 @@ +import { createLogger } from '@/lib/logs/console/logger' +import type { ToolConfig } from '@/tools/types' +import { buildMailchimpUrl, handleMailchimpError } from './types' + +const logger = createLogger('MailchimpUpdateLandingPage') + +export interface MailchimpUpdateLandingPageParams { + apiKey: string + pageId: string + landingPageTitle?: string +} + +export interface MailchimpUpdateLandingPageResponse { + success: boolean + output: { + landingPage: any + metadata: { + operation: 'update_landing_page' + pageId: string + } + success: boolean + } +} + +export const mailchimpUpdateLandingPageTool: ToolConfig< + MailchimpUpdateLandingPageParams, + MailchimpUpdateLandingPageResponse +> = { + id: 'mailchimp_update_landing_page', + name: 'Update Landing Page in Mailchimp', + description: 'Update an existing landing page in Mailchimp', + version: '1.0.0', + + params: { + apiKey: { + type: 'string', + required: true, + visibility: 'hidden', + description: 'Mailchimp API key with server prefix', + }, + pageId: { + type: 'string', + required: true, + visibility: 'user-only', + description: 'The unique ID for the landing page', + }, + landingPageTitle: { + type: 'string', + required: false, + visibility: 'user-only', + description: 'The title of the landing page', + }, + }, + + request: { + url: (params) => buildMailchimpUrl(params.apiKey, `/landing-pages/${params.pageId}`), + method: 'PATCH', + headers: (params) => ({ + Authorization: `Bearer ${params.apiKey}`, + 'Content-Type': 'application/json', + }), + body: (params) => { + const body: any = {} + + if (params.landingPageTitle) body.title = params.landingPageTitle + + return body + }, + }, + + transformResponse: async (response: Response) => { + if (!response.ok) { + const data = await response.json() + handleMailchimpError(data, response.status, 'update_landing_page') + } + + const data = await response.json() + + return { + success: true, + output: { + landingPage: data, + metadata: { + operation: 'update_landing_page' as const, + pageId: data.id, + }, + success: true, + }, + } + }, + + outputs: { + success: { type: 'boolean', description: 'Operation success status' }, + output: { + type: 'object', + description: 'Updated landing page data', + properties: { + landingPage: { type: 'object', description: 'Updated landing page object' }, + metadata: { type: 'object', description: 'Operation metadata' }, + success: { type: 'boolean', description: 'Operation success' }, + }, + }, + }, +} diff --git a/apps/sim/tools/mailchimp/update_member.ts b/apps/sim/tools/mailchimp/update_member.ts new file mode 100644 index 0000000000..c7f5e7ae5c --- /dev/null +++ b/apps/sim/tools/mailchimp/update_member.ts @@ -0,0 +1,150 @@ +import { createLogger } from '@/lib/logs/console/logger' +import type { ToolConfig } from '@/tools/types' +import { buildMailchimpUrl, handleMailchimpError } from './types' + +const logger = createLogger('MailchimpUpdateMember') + +export interface MailchimpUpdateMemberParams { + apiKey: string + listId: string + subscriberHash: string + emailAddress?: string + status?: string + mergeFields?: string + interests?: string +} + +export interface MailchimpUpdateMemberResponse { + success: boolean + output: { + member: any + metadata: { + operation: 'update_member' + subscriberHash: string + } + success: boolean + } +} + +export const mailchimpUpdateMemberTool: ToolConfig< + MailchimpUpdateMemberParams, + MailchimpUpdateMemberResponse +> = { + id: 'mailchimp_update_member', + name: 'Update Member in Mailchimp Audience', + description: 'Update an existing member in a Mailchimp audience', + version: '1.0.0', + + params: { + apiKey: { + type: 'string', + required: true, + visibility: 'hidden', + description: 'Mailchimp API key with server prefix', + }, + listId: { + type: 'string', + required: true, + visibility: 'user-only', + description: 'The unique ID for the list', + }, + subscriberHash: { + type: 'string', + required: true, + visibility: 'user-only', + description: "The MD5 hash of the lowercase version of the list member's email address", + }, + emailAddress: { + type: 'string', + required: false, + visibility: 'user-only', + description: 'Email address for the member', + }, + status: { + type: 'string', + required: false, + visibility: 'user-only', + description: 'Subscriber status (subscribed, unsubscribed, cleaned, pending)', + }, + mergeFields: { + type: 'string', + required: false, + visibility: 'user-only', + description: 'Merge fields as JSON object', + }, + interests: { + type: 'string', + required: false, + visibility: 'user-only', + description: 'Interests as JSON object', + }, + }, + + request: { + url: (params) => + buildMailchimpUrl(params.apiKey, `/lists/${params.listId}/members/${params.subscriberHash}`), + method: 'PATCH', + headers: (params) => ({ + Authorization: `Bearer ${params.apiKey}`, + 'Content-Type': 'application/json', + }), + body: (params) => { + const body: any = {} + + if (params.emailAddress) body.email_address = params.emailAddress + if (params.status) body.status = params.status + + if (params.mergeFields) { + try { + body.merge_fields = JSON.parse(params.mergeFields) + } catch (error) { + logger.warn('Failed to parse merge fields', { error }) + } + } + + if (params.interests) { + try { + body.interests = JSON.parse(params.interests) + } catch (error) { + logger.warn('Failed to parse interests', { error }) + } + } + + return body + }, + }, + + transformResponse: async (response: Response) => { + if (!response.ok) { + const data = await response.json() + handleMailchimpError(data, response.status, 'update_member') + } + + const data = await response.json() + + return { + success: true, + output: { + member: data, + metadata: { + operation: 'update_member' as const, + subscriberHash: data.id, + }, + success: true, + }, + } + }, + + outputs: { + success: { type: 'boolean', description: 'Operation success status' }, + output: { + type: 'object', + description: 'Updated member data', + properties: { + member: { type: 'object', description: 'Updated member object' }, + metadata: { type: 'object', description: 'Operation metadata' }, + success: { type: 'boolean', description: 'Operation success' }, + }, + }, + }, +} diff --git a/apps/sim/tools/mailchimp/update_merge_field.ts b/apps/sim/tools/mailchimp/update_merge_field.ts new file mode 100644 index 0000000000..1b25460769 --- /dev/null +++ b/apps/sim/tools/mailchimp/update_merge_field.ts @@ -0,0 +1,112 @@ +import { createLogger } from '@/lib/logs/console/logger' +import type { ToolConfig } from '@/tools/types' +import { buildMailchimpUrl, handleMailchimpError } from './types' + +const logger = createLogger('MailchimpUpdateMergeField') + +export interface MailchimpUpdateMergeFieldParams { + apiKey: string + listId: string + mergeId: string + mergeName?: string +} + +export interface MailchimpUpdateMergeFieldResponse { + success: boolean + output: { + mergeField: any + metadata: { + operation: 'update_merge_field' + mergeId: string + } + success: boolean + } +} + +export const mailchimpUpdateMergeFieldTool: ToolConfig< + MailchimpUpdateMergeFieldParams, + MailchimpUpdateMergeFieldResponse +> = { + id: 'mailchimp_update_merge_field', + name: 'Update Merge Field in Mailchimp Audience', + description: 'Update an existing merge field in a Mailchimp audience', + version: '1.0.0', + + params: { + apiKey: { + type: 'string', + required: true, + visibility: 'hidden', + description: 'Mailchimp API key with server prefix', + }, + listId: { + type: 'string', + required: true, + visibility: 'user-only', + description: 'The unique ID for the list', + }, + mergeId: { + type: 'string', + required: true, + visibility: 'user-only', + description: 'The unique ID for the merge field', + }, + mergeName: { + type: 'string', + required: false, + visibility: 'user-only', + description: 'The name of the merge field', + }, + }, + + request: { + url: (params) => + buildMailchimpUrl(params.apiKey, `/lists/${params.listId}/merge-fields/${params.mergeId}`), + method: 'PATCH', + headers: (params) => ({ + Authorization: `Bearer ${params.apiKey}`, + 'Content-Type': 'application/json', + }), + body: (params) => { + const body: any = {} + + if (params.mergeName) body.name = params.mergeName + + return body + }, + }, + + transformResponse: async (response: Response) => { + if (!response.ok) { + const data = await response.json() + handleMailchimpError(data, response.status, 'update_merge_field') + } + + const data = await response.json() + + return { + success: true, + output: { + mergeField: data, + metadata: { + operation: 'update_merge_field' as const, + mergeId: data.merge_id, + }, + success: true, + }, + } + }, + + outputs: { + success: { type: 'boolean', description: 'Operation success status' }, + output: { + type: 'object', + description: 'Updated merge field data', + properties: { + mergeField: { type: 'object', description: 'Updated merge field object' }, + metadata: { type: 'object', description: 'Operation metadata' }, + success: { type: 'boolean', description: 'Operation success' }, + }, + }, + }, +} diff --git a/apps/sim/tools/mailchimp/update_segment.ts b/apps/sim/tools/mailchimp/update_segment.ts new file mode 100644 index 0000000000..a3d2722971 --- /dev/null +++ b/apps/sim/tools/mailchimp/update_segment.ts @@ -0,0 +1,128 @@ +import { createLogger } from '@/lib/logs/console/logger' +import type { ToolConfig } from '@/tools/types' +import { buildMailchimpUrl, handleMailchimpError } from './types' + +const logger = createLogger('MailchimpUpdateSegment') + +export interface MailchimpUpdateSegmentParams { + apiKey: string + listId: string + segmentId: string + segmentName?: string + segmentOptions?: string +} + +export interface MailchimpUpdateSegmentResponse { + success: boolean + output: { + segment: any + metadata: { + operation: 'update_segment' + segmentId: string + } + success: boolean + } +} + +export const mailchimpUpdateSegmentTool: ToolConfig< + MailchimpUpdateSegmentParams, + MailchimpUpdateSegmentResponse +> = { + id: 'mailchimp_update_segment', + name: 'Update Segment in Mailchimp Audience', + description: 'Update an existing segment in a Mailchimp audience', + version: '1.0.0', + + params: { + apiKey: { + type: 'string', + required: true, + visibility: 'hidden', + description: 'Mailchimp API key with server prefix', + }, + listId: { + type: 'string', + required: true, + visibility: 'user-only', + description: 'The unique ID for the list', + }, + segmentId: { + type: 'string', + required: true, + visibility: 'user-only', + description: 'The unique ID for the segment', + }, + segmentName: { + type: 'string', + required: false, + visibility: 'user-only', + description: 'The name of the segment', + }, + segmentOptions: { + type: 'string', + required: false, + visibility: 'user-only', + description: 'Segment options as JSON', + }, + }, + + request: { + url: (params) => + buildMailchimpUrl(params.apiKey, `/lists/${params.listId}/segments/${params.segmentId}`), + method: 'PATCH', + headers: (params) => ({ + Authorization: `Bearer ${params.apiKey}`, + 'Content-Type': 'application/json', + }), + body: (params) => { + const body: any = {} + + if (params.segmentName) body.name = params.segmentName + + if (params.segmentOptions) { + try { + const options = JSON.parse(params.segmentOptions) + body.options = options + } catch (error) { + logger.warn('Failed to parse segment options', { error }) + } + } + + return body + }, + }, + + transformResponse: async (response: Response) => { + if (!response.ok) { + const data = await response.json() + handleMailchimpError(data, response.status, 'update_segment') + } + + const data = await response.json() + + return { + success: true, + output: { + segment: data, + metadata: { + operation: 'update_segment' as const, + segmentId: data.id, + }, + success: true, + }, + } + }, + + outputs: { + success: { type: 'boolean', description: 'Operation success status' }, + output: { + type: 'object', + description: 'Updated segment data', + properties: { + segment: { type: 'object', description: 'Updated segment object' }, + metadata: { type: 'object', description: 'Operation metadata' }, + success: { type: 'boolean', description: 'Operation success' }, + }, + }, + }, +} diff --git a/apps/sim/tools/mailchimp/update_template.ts b/apps/sim/tools/mailchimp/update_template.ts new file mode 100644 index 0000000000..3e7ea3fbba --- /dev/null +++ b/apps/sim/tools/mailchimp/update_template.ts @@ -0,0 +1,112 @@ +import { createLogger } from '@/lib/logs/console/logger' +import type { ToolConfig } from '@/tools/types' +import { buildMailchimpUrl, handleMailchimpError } from './types' + +const logger = createLogger('MailchimpUpdateTemplate') + +export interface MailchimpUpdateTemplateParams { + apiKey: string + templateId: string + templateName?: string + templateHtml?: string +} + +export interface MailchimpUpdateTemplateResponse { + success: boolean + output: { + template: any + metadata: { + operation: 'update_template' + templateId: string + } + success: boolean + } +} + +export const mailchimpUpdateTemplateTool: ToolConfig< + MailchimpUpdateTemplateParams, + MailchimpUpdateTemplateResponse +> = { + id: 'mailchimp_update_template', + name: 'Update Template in Mailchimp', + description: 'Update an existing template in Mailchimp', + version: '1.0.0', + + params: { + apiKey: { + type: 'string', + required: true, + visibility: 'hidden', + description: 'Mailchimp API key with server prefix', + }, + templateId: { + type: 'string', + required: true, + visibility: 'user-only', + description: 'The unique ID for the template', + }, + templateName: { + type: 'string', + required: false, + visibility: 'user-only', + description: 'The name of the template', + }, + templateHtml: { + type: 'string', + required: false, + visibility: 'user-only', + description: 'The HTML content for the template', + }, + }, + + request: { + url: (params) => buildMailchimpUrl(params.apiKey, `/templates/${params.templateId}`), + method: 'PATCH', + headers: (params) => ({ + Authorization: `Bearer ${params.apiKey}`, + 'Content-Type': 'application/json', + }), + body: (params) => { + const body: any = {} + + if (params.templateName) body.name = params.templateName + if (params.templateHtml) body.html = params.templateHtml + + return body + }, + }, + + transformResponse: async (response: Response) => { + if (!response.ok) { + const data = await response.json() + handleMailchimpError(data, response.status, 'update_template') + } + + const data = await response.json() + + return { + success: true, + output: { + template: data, + metadata: { + operation: 'update_template' as const, + templateId: data.id, + }, + success: true, + }, + } + }, + + outputs: { + success: { type: 'boolean', description: 'Operation success status' }, + output: { + type: 'object', + description: 'Updated template data', + properties: { + template: { type: 'object', description: 'Updated template object' }, + metadata: { type: 'object', description: 'Operation metadata' }, + success: { type: 'boolean', description: 'Operation success' }, + }, + }, + }, +} diff --git a/apps/sim/tools/pylon/bulk_update_accounts.ts b/apps/sim/tools/pylon/bulk_update_accounts.ts new file mode 100644 index 0000000000..817b1658f4 --- /dev/null +++ b/apps/sim/tools/pylon/bulk_update_accounts.ts @@ -0,0 +1,140 @@ +import { createLogger } from '@/lib/logs/console/logger' +import type { ToolConfig } from '@/tools/types' +import { buildPylonUrl, handlePylonError } from './types' + +const logger = createLogger('PylonBulkUpdateAccounts') + +export interface PylonBulkUpdateAccountsParams { + apiToken: string + accountIds: string + customFields?: string + tags?: string + ownerId?: string + tagsApplyMode?: string +} + +export interface PylonBulkUpdateAccountsResponse { + success: boolean + output: { + accounts: any[] + metadata: { + operation: 'bulk_update_accounts' + totalUpdated: number + } + success: boolean + } +} + +export const pylonBulkUpdateAccountsTool: ToolConfig< + PylonBulkUpdateAccountsParams, + PylonBulkUpdateAccountsResponse +> = { + id: 'pylon_bulk_update_accounts', + name: 'Bulk Update Accounts in Pylon', + description: 'Update multiple accounts at once', + version: '1.0.0', + + params: { + apiToken: { + type: 'string', + required: true, + visibility: 'hidden', + description: 'Pylon API token', + }, + accountIds: { + type: 'string', + required: true, + visibility: 'user-only', + description: 'Comma-separated account IDs to update', + }, + customFields: { + type: 'string', + required: false, + visibility: 'user-only', + description: 'Custom fields as JSON object', + }, + tags: { + type: 'string', + required: false, + visibility: 'user-only', + description: 'Comma-separated tag IDs', + }, + ownerId: { + type: 'string', + required: false, + visibility: 'user-only', + description: 'Owner user ID', + }, + tagsApplyMode: { + type: 'string', + required: false, + visibility: 'user-only', + description: 'Tag application mode: append_only, remove_only, or replace', + }, + }, + + request: { + url: () => buildPylonUrl('/accounts'), + method: 'PATCH', + headers: (params) => ({ + Authorization: `Bearer ${params.apiToken}`, + 'Content-Type': 'application/json', + }), + body: (params) => { + const body: any = { + account_ids: params.accountIds.split(',').map((id) => id.trim()), + } + + if (params.ownerId) body.owner_id = params.ownerId + if (params.tagsApplyMode) body.tags_apply_mode = params.tagsApplyMode + + if (params.customFields) { + try { + body.custom_fields = JSON.parse(params.customFields) + } catch (error) { + logger.warn('Failed to parse custom fields', { error }) + } + } + + if (params.tags) { + body.tags = params.tags.split(',').map((t) => t.trim()) + } + + return body + }, + }, + + transformResponse: async (response: Response) => { + if (!response.ok) { + const data = await response.json() + handlePylonError(data, response.status, 'bulk_update_accounts') + } + + const data = await response.json() + + return { + success: true, + output: { + accounts: data.data || [], + metadata: { + operation: 'bulk_update_accounts' as const, + totalUpdated: data.data?.length || 0, + }, + success: true, + }, + } + }, + + outputs: { + success: { type: 'boolean', description: 'Operation success status' }, + output: { + type: 'object', + description: 'Bulk updated accounts data', + properties: { + accounts: { type: 'array', description: 'Array of updated account objects' }, + metadata: { type: 'object', description: 'Operation metadata' }, + success: { type: 'boolean', description: 'Operation success' }, + }, + }, + }, +} diff --git a/apps/sim/tools/pylon/create_account.ts b/apps/sim/tools/pylon/create_account.ts new file mode 100644 index 0000000000..a87c9fa419 --- /dev/null +++ b/apps/sim/tools/pylon/create_account.ts @@ -0,0 +1,191 @@ +import { createLogger } from '@/lib/logs/console/logger' +import type { ToolConfig } from '@/tools/types' +import { buildPylonUrl, handlePylonError } from './types' + +const logger = createLogger('PylonCreateAccount') + +export interface PylonCreateAccountParams { + apiToken: string + name: string + domains?: string + primaryDomain?: string + customFields?: string + tags?: string + channels?: string + externalIds?: string + ownerId?: string + logoUrl?: string + subaccountIds?: string +} + +export interface PylonCreateAccountResponse { + success: boolean + output: { + account: any + metadata: { + operation: 'create_account' + accountId: string + } + success: boolean + } +} + +export const pylonCreateAccountTool: ToolConfig< + PylonCreateAccountParams, + PylonCreateAccountResponse +> = { + id: 'pylon_create_account', + name: 'Create Account in Pylon', + description: 'Create a new account with specified properties', + version: '1.0.0', + + params: { + apiToken: { + type: 'string', + required: true, + visibility: 'hidden', + description: 'Pylon API token', + }, + name: { + type: 'string', + required: true, + visibility: 'user-only', + description: 'Account name', + }, + domains: { + type: 'string', + required: false, + visibility: 'user-only', + description: 'Comma-separated list of domains', + }, + primaryDomain: { + type: 'string', + required: false, + visibility: 'user-only', + description: 'Primary domain for the account', + }, + customFields: { + type: 'string', + required: false, + visibility: 'user-only', + description: 'Custom fields as JSON object', + }, + tags: { + type: 'string', + required: false, + visibility: 'user-only', + description: 'Comma-separated tag IDs', + }, + channels: { + type: 'string', + required: false, + visibility: 'user-only', + description: 'Comma-separated channel IDs', + }, + externalIds: { + type: 'string', + required: false, + visibility: 'user-only', + description: 'Comma-separated external IDs', + }, + ownerId: { + type: 'string', + required: false, + visibility: 'user-only', + description: 'Owner user ID', + }, + logoUrl: { + type: 'string', + required: false, + visibility: 'user-only', + description: 'URL to account logo', + }, + subaccountIds: { + type: 'string', + required: false, + visibility: 'user-only', + description: 'Comma-separated subaccount IDs', + }, + }, + + request: { + url: () => buildPylonUrl('/accounts'), + method: 'POST', + headers: (params) => ({ + Authorization: `Bearer ${params.apiToken}`, + 'Content-Type': 'application/json', + }), + body: (params) => { + const body: any = { + name: params.name, + } + + if (params.domains) { + body.domains = params.domains.split(',').map((d) => d.trim()) + } + if (params.primaryDomain) body.primary_domain = params.primaryDomain + if (params.ownerId) body.owner_id = params.ownerId + if (params.logoUrl) body.logo_url = params.logoUrl + + if (params.customFields) { + try { + body.custom_fields = JSON.parse(params.customFields) + } catch (error) { + logger.warn('Failed to parse custom fields', { error }) + } + } + + if (params.tags) { + body.tags = params.tags.split(',').map((t) => t.trim()) + } + + if (params.channels) { + body.channels = params.channels.split(',').map((c) => c.trim()) + } + + if (params.externalIds) { + body.external_ids = params.externalIds.split(',').map((e) => e.trim()) + } + + if (params.subaccountIds) { + body.subaccount_ids = params.subaccountIds.split(',').map((s) => s.trim()) + } + + return body + }, + }, + + transformResponse: async (response: Response) => { + if (!response.ok) { + const data = await response.json() + handlePylonError(data, response.status, 'create_account') + } + + const data = await response.json() + + return { + success: true, + output: { + account: data.data, + metadata: { + operation: 'create_account' as const, + accountId: data.data?.id || '', + }, + success: true, + }, + } + }, + + outputs: { + success: { type: 'boolean', description: 'Operation success status' }, + output: { + type: 'object', + description: 'Created account data', + properties: { + account: { type: 'object', description: 'Created account object' }, + metadata: { type: 'object', description: 'Operation metadata' }, + success: { type: 'boolean', description: 'Operation success' }, + }, + }, + }, +} diff --git a/apps/sim/tools/pylon/create_contact.ts b/apps/sim/tools/pylon/create_contact.ts new file mode 100644 index 0000000000..ebe0bff34a --- /dev/null +++ b/apps/sim/tools/pylon/create_contact.ts @@ -0,0 +1,153 @@ +import { createLogger } from '@/lib/logs/console/logger' +import type { ToolConfig } from '@/tools/types' +import { buildPylonUrl, handlePylonError } from './types' + +const logger = createLogger('PylonCreateContact') + +export interface PylonCreateContactParams { + apiToken: string + name: string + email?: string + accountId?: string + accountExternalId?: string + avatarUrl?: string + customFields?: string + portalRole?: string +} + +export interface PylonCreateContactResponse { + success: boolean + output: { + contact: any + metadata: { + operation: 'create_contact' + contactId: string + } + success: boolean + } +} + +export const pylonCreateContactTool: ToolConfig< + PylonCreateContactParams, + PylonCreateContactResponse +> = { + id: 'pylon_create_contact', + name: 'Create Contact in Pylon', + description: 'Create a new contact with specified properties', + version: '1.0.0', + + params: { + apiToken: { + type: 'string', + required: true, + visibility: 'hidden', + description: 'Pylon API token', + }, + name: { + type: 'string', + required: true, + visibility: 'user-only', + description: 'Contact name', + }, + email: { + type: 'string', + required: false, + visibility: 'user-only', + description: 'Contact email address', + }, + accountId: { + type: 'string', + required: false, + visibility: 'user-only', + description: 'Account ID to associate with contact', + }, + accountExternalId: { + type: 'string', + required: false, + visibility: 'user-only', + description: 'External account ID to associate with contact', + }, + avatarUrl: { + type: 'string', + required: false, + visibility: 'user-only', + description: 'URL for contact avatar image', + }, + customFields: { + type: 'string', + required: false, + visibility: 'user-only', + description: 'Custom fields as JSON object', + }, + portalRole: { + type: 'string', + required: false, + visibility: 'user-only', + description: 'Portal role for the contact', + }, + }, + + request: { + url: () => buildPylonUrl('/contacts'), + method: 'POST', + headers: (params) => ({ + Authorization: `Bearer ${params.apiToken}`, + 'Content-Type': 'application/json', + }), + body: (params) => { + const body: any = { + name: params.name, + } + + if (params.email) body.email = params.email + if (params.accountId) body.account_id = params.accountId + if (params.accountExternalId) body.account_external_id = params.accountExternalId + if (params.avatarUrl) body.avatar_url = params.avatarUrl + if (params.portalRole) body.portal_role = params.portalRole + + if (params.customFields) { + try { + body.custom_fields = JSON.parse(params.customFields) + } catch (error) { + logger.warn('Failed to parse custom fields', { error }) + } + } + + return body + }, + }, + + transformResponse: async (response: Response) => { + if (!response.ok) { + const data = await response.json() + handlePylonError(data, response.status, 'create_contact') + } + + const data = await response.json() + + return { + success: true, + output: { + contact: data.data, + metadata: { + operation: 'create_contact' as const, + contactId: data.data?.id || '', + }, + success: true, + }, + } + }, + + outputs: { + success: { type: 'boolean', description: 'Operation success status' }, + output: { + type: 'object', + description: 'Created contact data', + properties: { + contact: { type: 'object', description: 'Created contact object' }, + metadata: { type: 'object', description: 'Operation metadata' }, + success: { type: 'boolean', description: 'Operation success' }, + }, + }, + }, +} diff --git a/apps/sim/tools/pylon/create_issue.ts b/apps/sim/tools/pylon/create_issue.ts new file mode 100644 index 0000000000..b1da5ef815 --- /dev/null +++ b/apps/sim/tools/pylon/create_issue.ts @@ -0,0 +1,188 @@ +import { createLogger } from '@/lib/logs/console/logger' +import type { ToolConfig } from '@/tools/types' +import { buildPylonUrl, handlePylonError } from './types' + +const logger = createLogger('PylonCreateIssue') + +export interface PylonCreateIssueParams { + apiToken: string + title: string + bodyHtml: string + accountId?: string + assigneeId?: string + teamId?: string + requesterId?: string + requesterEmail?: string + priority?: string + tags?: string + customFields?: string + attachmentUrls?: string +} + +export interface PylonCreateIssueResponse { + success: boolean + output: { + issue: any + metadata: { + operation: 'create_issue' + issueId: string + } + success: boolean + } +} + +export const pylonCreateIssueTool: ToolConfig = { + id: 'pylon_create_issue', + name: 'Create Issue in Pylon', + description: 'Create a new issue with specified properties', + version: '1.0.0', + + params: { + apiToken: { + type: 'string', + required: true, + visibility: 'hidden', + description: 'Pylon API token', + }, + title: { + type: 'string', + required: true, + visibility: 'user-only', + description: 'Issue title', + }, + bodyHtml: { + type: 'string', + required: true, + visibility: 'user-only', + description: 'Issue body in HTML format', + }, + accountId: { + type: 'string', + required: false, + visibility: 'user-only', + description: 'Account ID to associate with issue', + }, + assigneeId: { + type: 'string', + required: false, + visibility: 'user-only', + description: 'User ID to assign issue to', + }, + teamId: { + type: 'string', + required: false, + visibility: 'user-only', + description: 'Team ID to assign issue to', + }, + requesterId: { + type: 'string', + required: false, + visibility: 'user-only', + description: 'Requester user ID (alternative to requester_email)', + }, + requesterEmail: { + type: 'string', + required: false, + visibility: 'user-only', + description: 'Requester email address (alternative to requester_id)', + }, + priority: { + type: 'string', + required: false, + visibility: 'user-only', + description: 'Issue priority', + }, + tags: { + type: 'string', + required: false, + visibility: 'user-only', + description: 'Comma-separated tag IDs', + }, + customFields: { + type: 'string', + required: false, + visibility: 'user-only', + description: 'Custom fields as JSON object', + }, + attachmentUrls: { + type: 'string', + required: false, + visibility: 'user-only', + description: 'Comma-separated attachment URLs', + }, + }, + + request: { + url: () => buildPylonUrl('/issues'), + method: 'POST', + headers: (params) => ({ + Authorization: `Bearer ${params.apiToken}`, + 'Content-Type': 'application/json', + }), + body: (params) => { + const body: any = { + title: params.title, + body_html: params.bodyHtml, + } + + if (params.accountId) body.account_id = params.accountId + if (params.assigneeId) body.assignee_id = params.assigneeId + if (params.teamId) body.team_id = params.teamId + if (params.requesterId) body.requester_id = params.requesterId + if (params.requesterEmail) body.requester_email = params.requesterEmail + if (params.priority) body.priority = params.priority + + if (params.tags) { + body.tags = params.tags.split(',').map((t) => t.trim()) + } + + if (params.customFields) { + try { + body.custom_fields = JSON.parse(params.customFields) + } catch (error) { + logger.warn('Failed to parse custom fields', { error }) + } + } + + if (params.attachmentUrls) { + body.attachment_urls = params.attachmentUrls.split(',').map((url) => url.trim()) + } + + return body + }, + }, + + transformResponse: async (response: Response) => { + if (!response.ok) { + const data = await response.json() + handlePylonError(data, response.status, 'create_issue') + } + + const data = await response.json() + + return { + success: true, + output: { + issue: data.data, + metadata: { + operation: 'create_issue' as const, + issueId: data.data?.id || '', + }, + success: true, + }, + } + }, + + outputs: { + success: { type: 'boolean', description: 'Operation success status' }, + output: { + type: 'object', + description: 'Created issue data', + properties: { + issue: { type: 'object', description: 'Created issue object' }, + metadata: { type: 'object', description: 'Operation metadata' }, + success: { type: 'boolean', description: 'Operation success' }, + }, + }, + }, +} diff --git a/apps/sim/tools/pylon/create_tag.ts b/apps/sim/tools/pylon/create_tag.ts new file mode 100644 index 0000000000..059e4c5d9c --- /dev/null +++ b/apps/sim/tools/pylon/create_tag.ts @@ -0,0 +1,111 @@ +import { createLogger } from '@/lib/logs/console/logger' +import type { ToolConfig } from '@/tools/types' +import { buildPylonUrl, handlePylonError } from './types' + +const logger = createLogger('PylonCreateTag') + +export interface PylonCreateTagParams { + apiToken: string + objectType: string + value: string + hexColor?: string +} + +export interface PylonCreateTagResponse { + success: boolean + output: { + tag: any + metadata: { + operation: 'create_tag' + tagId: string + } + success: boolean + } +} + +export const pylonCreateTagTool: ToolConfig = { + id: 'pylon_create_tag', + name: 'Create Tag in Pylon', + description: 'Create a new tag with specified properties (objectType: account/issue/contact)', + version: '1.0.0', + + params: { + apiToken: { + type: 'string', + required: true, + visibility: 'hidden', + description: 'Pylon API token', + }, + objectType: { + type: 'string', + required: true, + visibility: 'user-only', + description: 'Object type for tag (account, issue, or contact)', + }, + value: { + type: 'string', + required: true, + visibility: 'user-only', + description: 'Tag value/name', + }, + hexColor: { + type: 'string', + required: false, + visibility: 'user-only', + description: 'Hex color code for tag (e.g., #FF5733)', + }, + }, + + request: { + url: () => buildPylonUrl('/tags'), + method: 'POST', + headers: (params) => ({ + Authorization: `Bearer ${params.apiToken}`, + 'Content-Type': 'application/json', + }), + body: (params) => { + const body: any = { + object_type: params.objectType, + value: params.value, + } + + if (params.hexColor) body.hex_color = params.hexColor + + return body + }, + }, + + transformResponse: async (response: Response) => { + if (!response.ok) { + const data = await response.json() + handlePylonError(data, response.status, 'create_tag') + } + + const data = await response.json() + + return { + success: true, + output: { + tag: data.data, + metadata: { + operation: 'create_tag' as const, + tagId: data.data?.id || '', + }, + success: true, + }, + } + }, + + outputs: { + success: { type: 'boolean', description: 'Operation success status' }, + output: { + type: 'object', + description: 'Created tag data', + properties: { + tag: { type: 'object', description: 'Created tag object' }, + metadata: { type: 'object', description: 'Operation metadata' }, + success: { type: 'boolean', description: 'Operation success' }, + }, + }, + }, +} diff --git a/apps/sim/tools/pylon/create_team.ts b/apps/sim/tools/pylon/create_team.ts new file mode 100644 index 0000000000..258386d304 --- /dev/null +++ b/apps/sim/tools/pylon/create_team.ts @@ -0,0 +1,105 @@ +import { createLogger } from '@/lib/logs/console/logger' +import type { ToolConfig } from '@/tools/types' +import { buildPylonUrl, handlePylonError } from './types' + +const logger = createLogger('PylonCreateTeam') + +export interface PylonCreateTeamParams { + apiToken: string + name?: string + userIds?: string +} + +export interface PylonCreateTeamResponse { + success: boolean + output: { + team: any + metadata: { + operation: 'create_team' + teamId: string + } + success: boolean + } +} + +export const pylonCreateTeamTool: ToolConfig = { + id: 'pylon_create_team', + name: 'Create Team in Pylon', + description: 'Create a new team with specified properties', + version: '1.0.0', + + params: { + apiToken: { + type: 'string', + required: true, + visibility: 'hidden', + description: 'Pylon API token', + }, + name: { + type: 'string', + required: false, + visibility: 'user-only', + description: 'Team name', + }, + userIds: { + type: 'string', + required: false, + visibility: 'user-only', + description: 'Comma-separated user IDs to add as team members', + }, + }, + + request: { + url: () => buildPylonUrl('/teams'), + method: 'POST', + headers: (params) => ({ + Authorization: `Bearer ${params.apiToken}`, + 'Content-Type': 'application/json', + }), + body: (params) => { + const body: any = {} + + if (params.name) body.name = params.name + + if (params.userIds) { + body.user_ids = params.userIds.split(',').map((id) => id.trim()) + } + + return body + }, + }, + + transformResponse: async (response: Response) => { + if (!response.ok) { + const data = await response.json() + handlePylonError(data, response.status, 'create_team') + } + + const data = await response.json() + + return { + success: true, + output: { + team: data.data, + metadata: { + operation: 'create_team' as const, + teamId: data.data?.id || '', + }, + success: true, + }, + } + }, + + outputs: { + success: { type: 'boolean', description: 'Operation success status' }, + output: { + type: 'object', + description: 'Created team data', + properties: { + team: { type: 'object', description: 'Created team object' }, + metadata: { type: 'object', description: 'Operation metadata' }, + success: { type: 'boolean', description: 'Operation success' }, + }, + }, + }, +} diff --git a/apps/sim/tools/pylon/delete_account.ts b/apps/sim/tools/pylon/delete_account.ts new file mode 100644 index 0000000000..62fd0f890d --- /dev/null +++ b/apps/sim/tools/pylon/delete_account.ts @@ -0,0 +1,84 @@ +import { createLogger } from '@/lib/logs/console/logger' +import type { ToolConfig } from '@/tools/types' +import { buildPylonUrl, handlePylonError } from './types' + +const logger = createLogger('PylonDeleteAccount') + +export interface PylonDeleteAccountParams { + apiToken: string + accountId: string +} + +export interface PylonDeleteAccountResponse { + success: boolean + output: { + metadata: { + operation: 'delete_account' + accountId: string + } + success: boolean + } +} + +export const pylonDeleteAccountTool: ToolConfig< + PylonDeleteAccountParams, + PylonDeleteAccountResponse +> = { + id: 'pylon_delete_account', + name: 'Delete Account from Pylon', + description: 'Remove an account by ID', + version: '1.0.0', + + params: { + apiToken: { + type: 'string', + required: true, + visibility: 'hidden', + description: 'Pylon API token', + }, + accountId: { + type: 'string', + required: true, + visibility: 'user-only', + description: 'Account ID to delete', + }, + }, + + request: { + url: (params) => buildPylonUrl(`/accounts/${params.accountId}`), + method: 'DELETE', + headers: (params) => ({ + Authorization: `Bearer ${params.apiToken}`, + }), + }, + + transformResponse: async (response: Response) => { + if (!response.ok) { + const data = await response.json() + handlePylonError(data, response.status, 'delete_account') + } + + return { + success: true, + output: { + metadata: { + operation: 'delete_account' as const, + accountId: '', + }, + success: true, + }, + } + }, + + outputs: { + success: { type: 'boolean', description: 'Operation success status' }, + output: { + type: 'object', + description: 'Deletion confirmation', + properties: { + metadata: { type: 'object', description: 'Operation metadata' }, + success: { type: 'boolean', description: 'Operation success' }, + }, + }, + }, +} diff --git a/apps/sim/tools/pylon/delete_contact.ts b/apps/sim/tools/pylon/delete_contact.ts new file mode 100644 index 0000000000..7b97021808 --- /dev/null +++ b/apps/sim/tools/pylon/delete_contact.ts @@ -0,0 +1,84 @@ +import { createLogger } from '@/lib/logs/console/logger' +import type { ToolConfig } from '@/tools/types' +import { buildPylonUrl, handlePylonError } from './types' + +const logger = createLogger('PylonDeleteContact') + +export interface PylonDeleteContactParams { + apiToken: string + contactId: string +} + +export interface PylonDeleteContactResponse { + success: boolean + output: { + metadata: { + operation: 'delete_contact' + contactId: string + } + success: boolean + } +} + +export const pylonDeleteContactTool: ToolConfig< + PylonDeleteContactParams, + PylonDeleteContactResponse +> = { + id: 'pylon_delete_contact', + name: 'Delete Contact in Pylon', + description: 'Delete a specific contact by ID', + version: '1.0.0', + + params: { + apiToken: { + type: 'string', + required: true, + visibility: 'hidden', + description: 'Pylon API token', + }, + contactId: { + type: 'string', + required: true, + visibility: 'user-only', + description: 'Contact ID to delete', + }, + }, + + request: { + url: (params) => buildPylonUrl(`/contacts/${params.contactId}`), + method: 'DELETE', + headers: (params) => ({ + Authorization: `Bearer ${params.apiToken}`, + }), + }, + + transformResponse: async (response: Response) => { + if (!response.ok) { + const data = await response.json() + handlePylonError(data, response.status, 'delete_contact') + } + + return { + success: true, + output: { + metadata: { + operation: 'delete_contact' as const, + contactId: '', + }, + success: true, + }, + } + }, + + outputs: { + success: { type: 'boolean', description: 'Operation success status' }, + output: { + type: 'object', + description: 'Delete operation result', + properties: { + metadata: { type: 'object', description: 'Operation metadata' }, + success: { type: 'boolean', description: 'Operation success' }, + }, + }, + }, +} diff --git a/apps/sim/tools/pylon/delete_issue.ts b/apps/sim/tools/pylon/delete_issue.ts new file mode 100644 index 0000000000..caff3f6b0c --- /dev/null +++ b/apps/sim/tools/pylon/delete_issue.ts @@ -0,0 +1,81 @@ +import { createLogger } from '@/lib/logs/console/logger' +import type { ToolConfig } from '@/tools/types' +import { buildPylonUrl, handlePylonError } from './types' + +const logger = createLogger('PylonDeleteIssue') + +export interface PylonDeleteIssueParams { + apiToken: string + issueId: string +} + +export interface PylonDeleteIssueResponse { + success: boolean + output: { + metadata: { + operation: 'delete_issue' + issueId: string + } + success: boolean + } +} + +export const pylonDeleteIssueTool: ToolConfig = { + id: 'pylon_delete_issue', + name: 'Delete Issue from Pylon', + description: 'Remove an issue by ID', + version: '1.0.0', + + params: { + apiToken: { + type: 'string', + required: true, + visibility: 'hidden', + description: 'Pylon API token', + }, + issueId: { + type: 'string', + required: true, + visibility: 'user-only', + description: 'The ID of the issue to delete', + }, + }, + + request: { + url: (params) => buildPylonUrl(`/issues/${params.issueId}`), + method: 'DELETE', + headers: (params) => ({ + Authorization: `Bearer ${params.apiToken}`, + }), + }, + + transformResponse: async (response: Response, params?: PylonDeleteIssueParams) => { + if (!response.ok) { + const data = await response.json() + handlePylonError(data, response.status, 'delete_issue') + } + + return { + success: true, + output: { + metadata: { + operation: 'delete_issue' as const, + issueId: params?.issueId || '', + }, + success: true, + }, + } + }, + + outputs: { + success: { type: 'boolean', description: 'Operation success status' }, + output: { + type: 'object', + description: 'Deletion result', + properties: { + metadata: { type: 'object', description: 'Operation metadata' }, + success: { type: 'boolean', description: 'Operation success' }, + }, + }, + }, +} diff --git a/apps/sim/tools/pylon/delete_tag.ts b/apps/sim/tools/pylon/delete_tag.ts new file mode 100644 index 0000000000..4ee8eac25b --- /dev/null +++ b/apps/sim/tools/pylon/delete_tag.ts @@ -0,0 +1,81 @@ +import { createLogger } from '@/lib/logs/console/logger' +import type { ToolConfig } from '@/tools/types' +import { buildPylonUrl, handlePylonError } from './types' + +const logger = createLogger('PylonDeleteTag') + +export interface PylonDeleteTagParams { + apiToken: string + tagId: string +} + +export interface PylonDeleteTagResponse { + success: boolean + output: { + metadata: { + operation: 'delete_tag' + tagId: string + } + success: boolean + } +} + +export const pylonDeleteTagTool: ToolConfig = { + id: 'pylon_delete_tag', + name: 'Delete Tag in Pylon', + description: 'Delete a specific tag by ID', + version: '1.0.0', + + params: { + apiToken: { + type: 'string', + required: true, + visibility: 'hidden', + description: 'Pylon API token', + }, + tagId: { + type: 'string', + required: true, + visibility: 'user-only', + description: 'Tag ID to delete', + }, + }, + + request: { + url: (params) => buildPylonUrl(`/tags/${params.tagId}`), + method: 'DELETE', + headers: (params) => ({ + Authorization: `Bearer ${params.apiToken}`, + }), + }, + + transformResponse: async (response: Response) => { + if (!response.ok) { + const data = await response.json() + handlePylonError(data, response.status, 'delete_tag') + } + + return { + success: true, + output: { + metadata: { + operation: 'delete_tag' as const, + tagId: '', + }, + success: true, + }, + } + }, + + outputs: { + success: { type: 'boolean', description: 'Operation success status' }, + output: { + type: 'object', + description: 'Delete operation result', + properties: { + metadata: { type: 'object', description: 'Operation metadata' }, + success: { type: 'boolean', description: 'Operation success' }, + }, + }, + }, +} diff --git a/apps/sim/tools/pylon/get_account.ts b/apps/sim/tools/pylon/get_account.ts new file mode 100644 index 0000000000..34cfcf1666 --- /dev/null +++ b/apps/sim/tools/pylon/get_account.ts @@ -0,0 +1,86 @@ +import { createLogger } from '@/lib/logs/console/logger' +import type { ToolConfig } from '@/tools/types' +import { buildPylonUrl, handlePylonError } from './types' + +const logger = createLogger('PylonGetAccount') + +export interface PylonGetAccountParams { + apiToken: string + accountId: string +} + +export interface PylonGetAccountResponse { + success: boolean + output: { + account: any + metadata: { + operation: 'get_account' + accountId: string + } + success: boolean + } +} + +export const pylonGetAccountTool: ToolConfig = { + id: 'pylon_get_account', + name: 'Get Account from Pylon', + description: 'Retrieve a single account by ID', + version: '1.0.0', + + params: { + apiToken: { + type: 'string', + required: true, + visibility: 'hidden', + description: 'Pylon API token', + }, + accountId: { + type: 'string', + required: true, + visibility: 'user-only', + description: 'Account ID to retrieve', + }, + }, + + request: { + url: (params) => buildPylonUrl(`/accounts/${params.accountId}`), + method: 'GET', + headers: (params) => ({ + Authorization: `Bearer ${params.apiToken}`, + }), + }, + + transformResponse: async (response: Response) => { + if (!response.ok) { + const data = await response.json() + handlePylonError(data, response.status, 'get_account') + } + + const data = await response.json() + + return { + success: true, + output: { + account: data.data, + metadata: { + operation: 'get_account' as const, + accountId: data.data?.id || '', + }, + success: true, + }, + } + }, + + outputs: { + success: { type: 'boolean', description: 'Operation success status' }, + output: { + type: 'object', + description: 'Account data', + properties: { + account: { type: 'object', description: 'Account object' }, + metadata: { type: 'object', description: 'Operation metadata' }, + success: { type: 'boolean', description: 'Operation success' }, + }, + }, + }, +} diff --git a/apps/sim/tools/pylon/get_contact.ts b/apps/sim/tools/pylon/get_contact.ts new file mode 100644 index 0000000000..a3119ac2d3 --- /dev/null +++ b/apps/sim/tools/pylon/get_contact.ts @@ -0,0 +1,109 @@ +import { createLogger } from '@/lib/logs/console/logger' +import type { ToolConfig } from '@/tools/types' +import { buildPylonUrl, handlePylonError } from './types' + +const logger = createLogger('PylonGetContact') + +export interface PylonGetContactParams { + apiToken: string + contactId: string + cursor?: string + limit?: string +} + +export interface PylonGetContactResponse { + success: boolean + output: { + contact: any + metadata: { + operation: 'get_contact' + contactId: string + } + success: boolean + } +} + +export const pylonGetContactTool: ToolConfig = { + id: 'pylon_get_contact', + name: 'Get Contact in Pylon', + description: 'Retrieve a specific contact by ID', + version: '1.0.0', + + params: { + apiToken: { + type: 'string', + required: true, + visibility: 'hidden', + description: 'Pylon API token', + }, + contactId: { + type: 'string', + required: true, + visibility: 'user-only', + description: 'Contact ID to retrieve', + }, + cursor: { + type: 'string', + required: false, + visibility: 'user-only', + description: 'Pagination cursor for next page of results', + }, + limit: { + type: 'string', + required: false, + visibility: 'user-only', + description: 'Maximum number of items to return', + }, + }, + + request: { + url: (params) => { + const url = new URL(buildPylonUrl(`/contacts/${params.contactId}`)) + if (params.cursor) { + url.searchParams.append('cursor', params.cursor) + } + if (params.limit) { + url.searchParams.append('limit', params.limit) + } + return url.toString() + }, + method: 'GET', + headers: (params) => ({ + Authorization: `Bearer ${params.apiToken}`, + }), + }, + + transformResponse: async (response: Response) => { + if (!response.ok) { + const data = await response.json() + handlePylonError(data, response.status, 'get_contact') + } + + const data = await response.json() + + return { + success: true, + output: { + contact: data.data, + metadata: { + operation: 'get_contact' as const, + contactId: data.data?.id || '', + }, + success: true, + }, + } + }, + + outputs: { + success: { type: 'boolean', description: 'Operation success status' }, + output: { + type: 'object', + description: 'Contact data', + properties: { + contact: { type: 'object', description: 'Contact object' }, + metadata: { type: 'object', description: 'Operation metadata' }, + success: { type: 'boolean', description: 'Operation success' }, + }, + }, + }, +} diff --git a/apps/sim/tools/pylon/get_issue.ts b/apps/sim/tools/pylon/get_issue.ts new file mode 100644 index 0000000000..9316f15fcd --- /dev/null +++ b/apps/sim/tools/pylon/get_issue.ts @@ -0,0 +1,86 @@ +import { createLogger } from '@/lib/logs/console/logger' +import type { ToolConfig } from '@/tools/types' +import { buildPylonUrl, handlePylonError } from './types' + +const logger = createLogger('PylonGetIssue') + +export interface PylonGetIssueParams { + apiToken: string + issueId: string +} + +export interface PylonGetIssueResponse { + success: boolean + output: { + issue: any + metadata: { + operation: 'get_issue' + issueId: string + } + success: boolean + } +} + +export const pylonGetIssueTool: ToolConfig = { + id: 'pylon_get_issue', + name: 'Get Issue from Pylon', + description: 'Fetch a specific issue by ID', + version: '1.0.0', + + params: { + apiToken: { + type: 'string', + required: true, + visibility: 'hidden', + description: 'Pylon API token', + }, + issueId: { + type: 'string', + required: true, + visibility: 'user-only', + description: 'The ID of the issue to retrieve', + }, + }, + + request: { + url: (params) => buildPylonUrl(`/issues/${params.issueId}`), + method: 'GET', + headers: (params) => ({ + Authorization: `Bearer ${params.apiToken}`, + }), + }, + + transformResponse: async (response: Response) => { + if (!response.ok) { + const data = await response.json() + handlePylonError(data, response.status, 'get_issue') + } + + const data = await response.json() + + return { + success: true, + output: { + issue: data.data, + metadata: { + operation: 'get_issue' as const, + issueId: data.data?.id || '', + }, + success: true, + }, + } + }, + + outputs: { + success: { type: 'boolean', description: 'Operation success status' }, + output: { + type: 'object', + description: 'Issue data', + properties: { + issue: { type: 'object', description: 'Issue object' }, + metadata: { type: 'object', description: 'Operation metadata' }, + success: { type: 'boolean', description: 'Operation success' }, + }, + }, + }, +} diff --git a/apps/sim/tools/pylon/get_tag.ts b/apps/sim/tools/pylon/get_tag.ts new file mode 100644 index 0000000000..093b8e5c2b --- /dev/null +++ b/apps/sim/tools/pylon/get_tag.ts @@ -0,0 +1,86 @@ +import { createLogger } from '@/lib/logs/console/logger' +import type { ToolConfig } from '@/tools/types' +import { buildPylonUrl, handlePylonError } from './types' + +const logger = createLogger('PylonGetTag') + +export interface PylonGetTagParams { + apiToken: string + tagId: string +} + +export interface PylonGetTagResponse { + success: boolean + output: { + tag: any + metadata: { + operation: 'get_tag' + tagId: string + } + success: boolean + } +} + +export const pylonGetTagTool: ToolConfig = { + id: 'pylon_get_tag', + name: 'Get Tag in Pylon', + description: 'Retrieve a specific tag by ID', + version: '1.0.0', + + params: { + apiToken: { + type: 'string', + required: true, + visibility: 'hidden', + description: 'Pylon API token', + }, + tagId: { + type: 'string', + required: true, + visibility: 'user-only', + description: 'Tag ID to retrieve', + }, + }, + + request: { + url: (params) => buildPylonUrl(`/tags/${params.tagId}`), + method: 'GET', + headers: (params) => ({ + Authorization: `Bearer ${params.apiToken}`, + }), + }, + + transformResponse: async (response: Response) => { + if (!response.ok) { + const data = await response.json() + handlePylonError(data, response.status, 'get_tag') + } + + const data = await response.json() + + return { + success: true, + output: { + tag: data.data, + metadata: { + operation: 'get_tag' as const, + tagId: data.data?.id || '', + }, + success: true, + }, + } + }, + + outputs: { + success: { type: 'boolean', description: 'Operation success status' }, + output: { + type: 'object', + description: 'Tag data', + properties: { + tag: { type: 'object', description: 'Tag object' }, + metadata: { type: 'object', description: 'Operation metadata' }, + success: { type: 'boolean', description: 'Operation success' }, + }, + }, + }, +} diff --git a/apps/sim/tools/pylon/get_team.ts b/apps/sim/tools/pylon/get_team.ts new file mode 100644 index 0000000000..24bc1af392 --- /dev/null +++ b/apps/sim/tools/pylon/get_team.ts @@ -0,0 +1,86 @@ +import { createLogger } from '@/lib/logs/console/logger' +import type { ToolConfig } from '@/tools/types' +import { buildPylonUrl, handlePylonError } from './types' + +const logger = createLogger('PylonGetTeam') + +export interface PylonGetTeamParams { + apiToken: string + teamId: string +} + +export interface PylonGetTeamResponse { + success: boolean + output: { + team: any + metadata: { + operation: 'get_team' + teamId: string + } + success: boolean + } +} + +export const pylonGetTeamTool: ToolConfig = { + id: 'pylon_get_team', + name: 'Get Team in Pylon', + description: 'Retrieve a specific team by ID', + version: '1.0.0', + + params: { + apiToken: { + type: 'string', + required: true, + visibility: 'hidden', + description: 'Pylon API token', + }, + teamId: { + type: 'string', + required: true, + visibility: 'user-only', + description: 'Team ID to retrieve', + }, + }, + + request: { + url: (params) => buildPylonUrl(`/teams/${params.teamId}`), + method: 'GET', + headers: (params) => ({ + Authorization: `Bearer ${params.apiToken}`, + }), + }, + + transformResponse: async (response: Response) => { + if (!response.ok) { + const data = await response.json() + handlePylonError(data, response.status, 'get_team') + } + + const data = await response.json() + + return { + success: true, + output: { + team: data.data, + metadata: { + operation: 'get_team' as const, + teamId: data.data?.id || '', + }, + success: true, + }, + } + }, + + outputs: { + success: { type: 'boolean', description: 'Operation success status' }, + output: { + type: 'object', + description: 'Team data', + properties: { + team: { type: 'object', description: 'Team object' }, + metadata: { type: 'object', description: 'Operation metadata' }, + success: { type: 'boolean', description: 'Operation success' }, + }, + }, + }, +} diff --git a/apps/sim/tools/pylon/get_user.ts b/apps/sim/tools/pylon/get_user.ts new file mode 100644 index 0000000000..579b953a67 --- /dev/null +++ b/apps/sim/tools/pylon/get_user.ts @@ -0,0 +1,86 @@ +import { createLogger } from '@/lib/logs/console/logger' +import type { ToolConfig } from '@/tools/types' +import { buildPylonUrl, handlePylonError } from './types' + +const logger = createLogger('PylonGetUser') + +export interface PylonGetUserParams { + apiToken: string + userId: string +} + +export interface PylonGetUserResponse { + success: boolean + output: { + user: any + metadata: { + operation: 'get_user' + userId: string + } + success: boolean + } +} + +export const pylonGetUserTool: ToolConfig = { + id: 'pylon_get_user', + name: 'Get User in Pylon', + description: 'Retrieve a specific user by ID', + version: '1.0.0', + + params: { + apiToken: { + type: 'string', + required: true, + visibility: 'hidden', + description: 'Pylon API token', + }, + userId: { + type: 'string', + required: true, + visibility: 'user-only', + description: 'User ID to retrieve', + }, + }, + + request: { + url: (params) => buildPylonUrl(`/users/${params.userId}`), + method: 'GET', + headers: (params) => ({ + Authorization: `Bearer ${params.apiToken}`, + }), + }, + + transformResponse: async (response: Response) => { + if (!response.ok) { + const data = await response.json() + handlePylonError(data, response.status, 'get_user') + } + + const data = await response.json() + + return { + success: true, + output: { + user: data.data, + metadata: { + operation: 'get_user' as const, + userId: data.data?.id || '', + }, + success: true, + }, + } + }, + + outputs: { + success: { type: 'boolean', description: 'Operation success status' }, + output: { + type: 'object', + description: 'User data', + properties: { + user: { type: 'object', description: 'User object' }, + metadata: { type: 'object', description: 'Operation metadata' }, + success: { type: 'boolean', description: 'Operation success' }, + }, + }, + }, +} diff --git a/apps/sim/tools/pylon/index.ts b/apps/sim/tools/pylon/index.ts new file mode 100644 index 0000000000..e58ca95e95 --- /dev/null +++ b/apps/sim/tools/pylon/index.ts @@ -0,0 +1,47 @@ +// Pylon API integration tools +// Export all tools for registration + +export { pylonBulkUpdateAccountsTool } from './bulk_update_accounts' +export { pylonCreateAccountTool } from './create_account' +export { pylonCreateContactTool } from './create_contact' +export { pylonCreateIssueTool } from './create_issue' +export { pylonCreateTagTool } from './create_tag' +export { pylonCreateTeamTool } from './create_team' +export { pylonDeleteAccountTool } from './delete_account' +export { pylonDeleteContactTool } from './delete_contact' +export { pylonDeleteIssueTool } from './delete_issue' +export { pylonDeleteTagTool } from './delete_tag' +export { pylonGetAccountTool } from './get_account' +export { pylonGetContactTool } from './get_contact' +export { pylonGetIssueTool } from './get_issue' +export { pylonGetTagTool } from './get_tag' +export { pylonGetTeamTool } from './get_team' +export { pylonGetUserTool } from './get_user' +export { pylonLinkExternalIssueTool } from './link_external_issue' +// Account tools +export { pylonListAccountsTool } from './list_accounts' +// Contact tools +export { pylonListContactsTool } from './list_contacts' +export { pylonListIssueFollowersTool } from './list_issue_followers' +// Issue tools +export { pylonListIssuesTool } from './list_issues' +// Tag tools +export { pylonListTagsTool } from './list_tags' +// Team tools +export { pylonListTeamsTool } from './list_teams' +// User tools +export { pylonListUsersTool } from './list_users' +export { pylonManageIssueFollowersTool } from './manage_issue_followers' +// Message tools +export { pylonRedactMessageTool } from './redact_message' +export { pylonSearchAccountsTool } from './search_accounts' +export { pylonSearchContactsTool } from './search_contacts' +export { pylonSearchIssuesTool } from './search_issues' +export { pylonSearchUsersTool } from './search_users' +export { pylonSnoozeIssueTool } from './snooze_issue' +export { pylonUpdateAccountTool } from './update_account' +export { pylonUpdateContactTool } from './update_contact' +export { pylonUpdateIssueTool } from './update_issue' +export { pylonUpdateTagTool } from './update_tag' +export { pylonUpdateTeamTool } from './update_team' +export { pylonUpdateUserTool } from './update_user' diff --git a/apps/sim/tools/pylon/link_external_issue.ts b/apps/sim/tools/pylon/link_external_issue.ts new file mode 100644 index 0000000000..b69f1ed4ca --- /dev/null +++ b/apps/sim/tools/pylon/link_external_issue.ts @@ -0,0 +1,112 @@ +import { createLogger } from '@/lib/logs/console/logger' +import type { ToolConfig } from '@/tools/types' +import { buildPylonUrl, handlePylonError } from './types' + +const logger = createLogger('PylonLinkExternalIssue') + +export interface PylonLinkExternalIssueParams { + apiToken: string + issueId: string + externalIssueId: string + source: string +} + +export interface PylonLinkExternalIssueResponse { + success: boolean + output: { + externalIssue: any + metadata: { + operation: 'link_external_issue' + issueId: string + externalIssueId: string + source: string + } + success: boolean + } +} + +export const pylonLinkExternalIssueTool: ToolConfig< + PylonLinkExternalIssueParams, + PylonLinkExternalIssueResponse +> = { + id: 'pylon_link_external_issue', + name: 'Link External Issue in Pylon', + description: 'Link an issue to an external system issue', + version: '1.0.0', + + params: { + apiToken: { + type: 'string', + required: true, + visibility: 'hidden', + description: 'Pylon API token', + }, + issueId: { + type: 'string', + required: true, + visibility: 'user-only', + description: 'The ID of the Pylon issue', + }, + externalIssueId: { + type: 'string', + required: true, + visibility: 'user-only', + description: 'The ID of the external issue', + }, + source: { + type: 'string', + required: true, + visibility: 'user-only', + description: 'The source system (e.g., "jira", "linear", "github")', + }, + }, + + request: { + url: (params) => buildPylonUrl(`/issues/${params?.issueId || ''}/external-issues`), + method: 'POST', + headers: (params) => ({ + Authorization: `Bearer ${params.apiToken}`, + 'Content-Type': 'application/json', + }), + body: (params) => ({ + external_issue_id: params?.externalIssueId || '', + source: params?.source || '', + }), + }, + + transformResponse: async (response: Response, params?: PylonLinkExternalIssueParams) => { + if (!response.ok) { + const data = await response.json() + handlePylonError(data, response.status, 'link_external_issue') + } + + const data = await response.json() + + return { + success: true, + output: { + externalIssue: data.data, + metadata: { + operation: 'link_external_issue' as const, + issueId: params?.issueId || '', + externalIssueId: params?.externalIssueId || '', + source: params?.source || '', + }, + success: true, + }, + } + }, + + outputs: { + success: { type: 'boolean', description: 'Operation success status' }, + output: { + type: 'object', + description: 'Linked external issue data', + properties: { + externalIssue: { type: 'object', description: 'External issue link object' }, + metadata: { type: 'object', description: 'Operation metadata' }, + success: { type: 'boolean', description: 'Operation success' }, + }, + }, + }, +} diff --git a/apps/sim/tools/pylon/list_accounts.ts b/apps/sim/tools/pylon/list_accounts.ts new file mode 100644 index 0000000000..06af15feb4 --- /dev/null +++ b/apps/sim/tools/pylon/list_accounts.ts @@ -0,0 +1,109 @@ +import { createLogger } from '@/lib/logs/console/logger' +import type { ToolConfig } from '@/tools/types' +import { buildPylonUrl, handlePylonError } from './types' + +const logger = createLogger('PylonListAccounts') + +export interface PylonListAccountsParams { + apiToken: string + limit?: string + cursor?: string +} + +export interface PylonListAccountsResponse { + success: boolean + output: { + accounts: any[] + pagination?: { + cursor?: string + has_next_page?: boolean + } + metadata: { + operation: 'list_accounts' + totalReturned: number + } + success: boolean + } +} + +export const pylonListAccountsTool: ToolConfig = + { + id: 'pylon_list_accounts', + name: 'List Accounts in Pylon', + description: 'Retrieve a paginated list of accounts', + version: '1.0.0', + + params: { + apiToken: { + type: 'string', + required: true, + visibility: 'hidden', + description: 'Pylon API token', + }, + limit: { + type: 'string', + required: false, + visibility: 'user-only', + description: 'Number of accounts to return (1-1000, default 100)', + }, + cursor: { + type: 'string', + required: false, + visibility: 'user-only', + description: 'Pagination cursor for next page of results', + }, + }, + + request: { + url: (params) => { + const url = new URL(buildPylonUrl('/accounts')) + if (params.limit) { + url.searchParams.append('limit', params.limit) + } + if (params.cursor) { + url.searchParams.append('cursor', params.cursor) + } + return url.toString() + }, + method: 'GET', + headers: (params) => ({ + Authorization: `Bearer ${params.apiToken}`, + }), + }, + + transformResponse: async (response: Response) => { + if (!response.ok) { + const data = await response.json() + handlePylonError(data, response.status, 'list_accounts') + } + + const data = await response.json() + + return { + success: true, + output: { + accounts: data.data || [], + pagination: data.pagination, + metadata: { + operation: 'list_accounts' as const, + totalReturned: data.data?.length || 0, + }, + success: true, + }, + } + }, + + outputs: { + success: { type: 'boolean', description: 'Operation success status' }, + output: { + type: 'object', + description: 'List of accounts', + properties: { + accounts: { type: 'array', description: 'Array of account objects' }, + pagination: { type: 'object', description: 'Pagination metadata' }, + metadata: { type: 'object', description: 'Operation metadata' }, + success: { type: 'boolean', description: 'Operation success' }, + }, + }, + }, + } diff --git a/apps/sim/tools/pylon/list_contacts.ts b/apps/sim/tools/pylon/list_contacts.ts new file mode 100644 index 0000000000..f09a2152ac --- /dev/null +++ b/apps/sim/tools/pylon/list_contacts.ts @@ -0,0 +1,109 @@ +import { createLogger } from '@/lib/logs/console/logger' +import type { ToolConfig } from '@/tools/types' +import { buildPylonUrl, handlePylonError } from './types' + +const logger = createLogger('PylonListContacts') + +export interface PylonListContactsParams { + apiToken: string + cursor?: string + limit?: string +} + +export interface PylonListContactsResponse { + success: boolean + output: { + contacts: any[] + pagination?: { + cursor?: string + has_next_page?: boolean + } + metadata: { + operation: 'list_contacts' + totalReturned: number + } + success: boolean + } +} + +export const pylonListContactsTool: ToolConfig = + { + id: 'pylon_list_contacts', + name: 'List Contacts in Pylon', + description: 'Retrieve a list of contacts', + version: '1.0.0', + + params: { + apiToken: { + type: 'string', + required: true, + visibility: 'hidden', + description: 'Pylon API token', + }, + cursor: { + type: 'string', + required: false, + visibility: 'user-only', + description: 'Pagination cursor for next page of results', + }, + limit: { + type: 'string', + required: false, + visibility: 'user-only', + description: 'Maximum number of contacts to return', + }, + }, + + request: { + url: (params) => { + const url = new URL(buildPylonUrl('/contacts')) + if (params.cursor) { + url.searchParams.append('cursor', params.cursor) + } + if (params.limit) { + url.searchParams.append('limit', params.limit) + } + return url.toString() + }, + method: 'GET', + headers: (params) => ({ + Authorization: `Bearer ${params.apiToken}`, + }), + }, + + transformResponse: async (response: Response) => { + if (!response.ok) { + const data = await response.json() + handlePylonError(data, response.status, 'list_contacts') + } + + const data = await response.json() + + return { + success: true, + output: { + contacts: data.data || [], + pagination: data.pagination, + metadata: { + operation: 'list_contacts' as const, + totalReturned: data.data?.length || 0, + }, + success: true, + }, + } + }, + + outputs: { + success: { type: 'boolean', description: 'Operation success status' }, + output: { + type: 'object', + description: 'List of contacts', + properties: { + contacts: { type: 'array', description: 'Array of contact objects' }, + pagination: { type: 'object', description: 'Pagination metadata' }, + metadata: { type: 'object', description: 'Operation metadata' }, + success: { type: 'boolean', description: 'Operation success' }, + }, + }, + }, + } diff --git a/apps/sim/tools/pylon/list_issue_followers.ts b/apps/sim/tools/pylon/list_issue_followers.ts new file mode 100644 index 0000000000..5fbf42d6b3 --- /dev/null +++ b/apps/sim/tools/pylon/list_issue_followers.ts @@ -0,0 +1,91 @@ +import { createLogger } from '@/lib/logs/console/logger' +import type { ToolConfig } from '@/tools/types' +import { buildPylonUrl, handlePylonError } from './types' + +const logger = createLogger('PylonListIssueFollowers') + +export interface PylonListIssueFollowersParams { + apiToken: string + issueId: string +} + +export interface PylonListIssueFollowersResponse { + success: boolean + output: { + followers: any[] + metadata: { + operation: 'list_issue_followers' + issueId: string + totalFollowers: number + } + success: boolean + } +} + +export const pylonListIssueFollowersTool: ToolConfig< + PylonListIssueFollowersParams, + PylonListIssueFollowersResponse +> = { + id: 'pylon_list_issue_followers', + name: 'List Issue Followers in Pylon', + description: 'Get list of followers for a specific issue', + version: '1.0.0', + + params: { + apiToken: { + type: 'string', + required: true, + visibility: 'hidden', + description: 'Pylon API token', + }, + issueId: { + type: 'string', + required: true, + visibility: 'user-only', + description: 'The ID of the issue', + }, + }, + + request: { + url: (params) => buildPylonUrl(`/issues/${params?.issueId || ''}/followers`), + method: 'GET', + headers: (params) => ({ + Authorization: `Bearer ${params.apiToken}`, + }), + }, + + transformResponse: async (response: Response, params?: PylonListIssueFollowersParams) => { + if (!response.ok) { + const data = await response.json() + handlePylonError(data, response.status, 'list_issue_followers') + } + + const data = await response.json() + + return { + success: true, + output: { + followers: data.data || [], + metadata: { + operation: 'list_issue_followers' as const, + issueId: params?.issueId || '', + totalFollowers: data.data?.length || 0, + }, + success: true, + }, + } + }, + + outputs: { + success: { type: 'boolean', description: 'Operation success status' }, + output: { + type: 'object', + description: 'Followers list', + properties: { + followers: { type: 'array', description: 'Array of follower objects' }, + metadata: { type: 'object', description: 'Operation metadata' }, + success: { type: 'boolean', description: 'Operation success' }, + }, + }, + }, +} diff --git a/apps/sim/tools/pylon/list_issues.ts b/apps/sim/tools/pylon/list_issues.ts new file mode 100644 index 0000000000..53593360b5 --- /dev/null +++ b/apps/sim/tools/pylon/list_issues.ts @@ -0,0 +1,114 @@ +import { createLogger } from '@/lib/logs/console/logger' +import type { ToolConfig } from '@/tools/types' +import { buildPylonUrl, handlePylonError } from './types' + +const logger = createLogger('PylonListIssues') + +export interface PylonListIssuesParams { + apiToken: string + startTime: string + endTime: string + cursor?: string +} + +export interface PylonListIssuesResponse { + success: boolean + output: { + issues: any[] + pagination?: { + cursor?: string + has_next_page?: boolean + } + metadata: { + operation: 'list_issues' + totalReturned: number + } + success: boolean + } +} + +export const pylonListIssuesTool: ToolConfig = { + id: 'pylon_list_issues', + name: 'List Issues in Pylon', + description: 'Retrieve a list of issues within a specified time range', + version: '1.0.0', + + params: { + apiToken: { + type: 'string', + required: true, + visibility: 'hidden', + description: 'Pylon API token', + }, + startTime: { + type: 'string', + required: true, + visibility: 'user-only', + description: 'Start time in RFC3339 format (e.g., 2024-01-01T00:00:00Z)', + }, + endTime: { + type: 'string', + required: true, + visibility: 'user-only', + description: 'End time in RFC3339 format (e.g., 2024-01-31T23:59:59Z)', + }, + cursor: { + type: 'string', + required: false, + visibility: 'user-only', + description: 'Pagination cursor for next page of results', + }, + }, + + request: { + url: (params) => { + const url = new URL(buildPylonUrl('/issues')) + url.searchParams.append('start_time', params.startTime) + url.searchParams.append('end_time', params.endTime) + if (params.cursor) { + url.searchParams.append('cursor', params.cursor) + } + return url.toString() + }, + method: 'GET', + headers: (params) => ({ + Authorization: `Bearer ${params.apiToken}`, + }), + }, + + transformResponse: async (response: Response) => { + if (!response.ok) { + const data = await response.json() + handlePylonError(data, response.status, 'list_issues') + } + + const data = await response.json() + + return { + success: true, + output: { + issues: data.data || [], + pagination: data.pagination, + metadata: { + operation: 'list_issues' as const, + totalReturned: data.data?.length || 0, + }, + success: true, + }, + } + }, + + outputs: { + success: { type: 'boolean', description: 'Operation success status' }, + output: { + type: 'object', + description: 'List of issues', + properties: { + issues: { type: 'array', description: 'Array of issue objects' }, + pagination: { type: 'object', description: 'Pagination metadata' }, + metadata: { type: 'object', description: 'Operation metadata' }, + success: { type: 'boolean', description: 'Operation success' }, + }, + }, + }, +} diff --git a/apps/sim/tools/pylon/list_tags.ts b/apps/sim/tools/pylon/list_tags.ts new file mode 100644 index 0000000000..ce89b2ac67 --- /dev/null +++ b/apps/sim/tools/pylon/list_tags.ts @@ -0,0 +1,79 @@ +import { createLogger } from '@/lib/logs/console/logger' +import type { ToolConfig } from '@/tools/types' +import { buildPylonUrl, handlePylonError } from './types' + +const logger = createLogger('PylonListTags') + +export interface PylonListTagsParams { + apiToken: string +} + +export interface PylonListTagsResponse { + success: boolean + output: { + tags: any[] + metadata: { + operation: 'list_tags' + totalReturned: number + } + success: boolean + } +} + +export const pylonListTagsTool: ToolConfig = { + id: 'pylon_list_tags', + name: 'List Tags in Pylon', + description: 'Retrieve a list of tags', + version: '1.0.0', + + params: { + apiToken: { + type: 'string', + required: true, + visibility: 'hidden', + description: 'Pylon API token', + }, + }, + + request: { + url: () => buildPylonUrl('/tags'), + method: 'GET', + headers: (params) => ({ + Authorization: `Bearer ${params.apiToken}`, + }), + }, + + transformResponse: async (response: Response) => { + if (!response.ok) { + const data = await response.json() + handlePylonError(data, response.status, 'list_tags') + } + + const data = await response.json() + + return { + success: true, + output: { + tags: data.data || [], + metadata: { + operation: 'list_tags' as const, + totalReturned: data.data?.length || 0, + }, + success: true, + }, + } + }, + + outputs: { + success: { type: 'boolean', description: 'Operation success status' }, + output: { + type: 'object', + description: 'List of tags', + properties: { + tags: { type: 'array', description: 'Array of tag objects' }, + metadata: { type: 'object', description: 'Operation metadata' }, + success: { type: 'boolean', description: 'Operation success' }, + }, + }, + }, +} diff --git a/apps/sim/tools/pylon/list_teams.ts b/apps/sim/tools/pylon/list_teams.ts new file mode 100644 index 0000000000..e1194ce54c --- /dev/null +++ b/apps/sim/tools/pylon/list_teams.ts @@ -0,0 +1,79 @@ +import { createLogger } from '@/lib/logs/console/logger' +import type { ToolConfig } from '@/tools/types' +import { buildPylonUrl, handlePylonError } from './types' + +const logger = createLogger('PylonListTeams') + +export interface PylonListTeamsParams { + apiToken: string +} + +export interface PylonListTeamsResponse { + success: boolean + output: { + teams: any[] + metadata: { + operation: 'list_teams' + totalReturned: number + } + success: boolean + } +} + +export const pylonListTeamsTool: ToolConfig = { + id: 'pylon_list_teams', + name: 'List Teams in Pylon', + description: 'Retrieve a list of teams', + version: '1.0.0', + + params: { + apiToken: { + type: 'string', + required: true, + visibility: 'hidden', + description: 'Pylon API token', + }, + }, + + request: { + url: () => buildPylonUrl('/teams'), + method: 'GET', + headers: (params) => ({ + Authorization: `Bearer ${params.apiToken}`, + }), + }, + + transformResponse: async (response: Response) => { + if (!response.ok) { + const data = await response.json() + handlePylonError(data, response.status, 'list_teams') + } + + const data = await response.json() + + return { + success: true, + output: { + teams: data.data || [], + metadata: { + operation: 'list_teams' as const, + totalReturned: data.data?.length || 0, + }, + success: true, + }, + } + }, + + outputs: { + success: { type: 'boolean', description: 'Operation success status' }, + output: { + type: 'object', + description: 'List of teams', + properties: { + teams: { type: 'array', description: 'Array of team objects' }, + metadata: { type: 'object', description: 'Operation metadata' }, + success: { type: 'boolean', description: 'Operation success' }, + }, + }, + }, +} diff --git a/apps/sim/tools/pylon/list_users.ts b/apps/sim/tools/pylon/list_users.ts new file mode 100644 index 0000000000..825be35bd5 --- /dev/null +++ b/apps/sim/tools/pylon/list_users.ts @@ -0,0 +1,79 @@ +import { createLogger } from '@/lib/logs/console/logger' +import type { ToolConfig } from '@/tools/types' +import { buildPylonUrl, handlePylonError } from './types' + +const logger = createLogger('PylonListUsers') + +export interface PylonListUsersParams { + apiToken: string +} + +export interface PylonListUsersResponse { + success: boolean + output: { + users: any[] + metadata: { + operation: 'list_users' + totalReturned: number + } + success: boolean + } +} + +export const pylonListUsersTool: ToolConfig = { + id: 'pylon_list_users', + name: 'List Users in Pylon', + description: 'Retrieve a list of users', + version: '1.0.0', + + params: { + apiToken: { + type: 'string', + required: true, + visibility: 'hidden', + description: 'Pylon API token', + }, + }, + + request: { + url: () => buildPylonUrl('/users'), + method: 'GET', + headers: (params) => ({ + Authorization: `Bearer ${params.apiToken}`, + }), + }, + + transformResponse: async (response: Response) => { + if (!response.ok) { + const data = await response.json() + handlePylonError(data, response.status, 'list_users') + } + + const data = await response.json() + + return { + success: true, + output: { + users: data.data || [], + metadata: { + operation: 'list_users' as const, + totalReturned: data.data?.length || 0, + }, + success: true, + }, + } + }, + + outputs: { + success: { type: 'boolean', description: 'Operation success status' }, + output: { + type: 'object', + description: 'List of users', + properties: { + users: { type: 'array', description: 'Array of user objects' }, + metadata: { type: 'object', description: 'Operation metadata' }, + success: { type: 'boolean', description: 'Operation success' }, + }, + }, + }, +} diff --git a/apps/sim/tools/pylon/manage_issue_followers.ts b/apps/sim/tools/pylon/manage_issue_followers.ts new file mode 100644 index 0000000000..f102e1cacc --- /dev/null +++ b/apps/sim/tools/pylon/manage_issue_followers.ts @@ -0,0 +1,128 @@ +import { createLogger } from '@/lib/logs/console/logger' +import type { ToolConfig } from '@/tools/types' +import { buildPylonUrl, handlePylonError } from './types' + +const logger = createLogger('PylonManageIssueFollowers') + +export interface PylonManageIssueFollowersParams { + apiToken: string + issueId: string + userIds?: string + contactIds?: string + operation?: string +} + +export interface PylonManageIssueFollowersResponse { + success: boolean + output: { + followers: any[] + metadata: { + operation: 'manage_issue_followers' + issueId: string + action: string + } + success: boolean + } +} + +export const pylonManageIssueFollowersTool: ToolConfig< + PylonManageIssueFollowersParams, + PylonManageIssueFollowersResponse +> = { + id: 'pylon_manage_issue_followers', + name: 'Manage Issue Followers in Pylon', + description: 'Add or remove followers from an issue', + version: '1.0.0', + + params: { + apiToken: { + type: 'string', + required: true, + visibility: 'hidden', + description: 'Pylon API token', + }, + issueId: { + type: 'string', + required: true, + visibility: 'user-only', + description: 'The ID of the issue', + }, + userIds: { + type: 'string', + required: false, + visibility: 'user-only', + description: 'Comma-separated user IDs to add/remove', + }, + contactIds: { + type: 'string', + required: false, + visibility: 'user-only', + description: 'Comma-separated contact IDs to add/remove', + }, + operation: { + type: 'string', + required: false, + visibility: 'user-only', + description: 'Operation to perform: "add" or "remove" (default: "add")', + }, + }, + + request: { + url: (params) => buildPylonUrl(`/issues/${params?.issueId || ''}/followers`), + method: 'POST', + headers: (params) => ({ + Authorization: `Bearer ${params.apiToken}`, + 'Content-Type': 'application/json', + }), + body: (params) => { + const body: any = {} + + if (params.userIds) { + body.user_ids = params.userIds.split(',').map((id) => id.trim()) + } + + if (params.contactIds) { + body.contact_ids = params.contactIds.split(',').map((id) => id.trim()) + } + + body.operation = params?.operation || 'add' + + return body + }, + }, + + transformResponse: async (response: Response, params?: PylonManageIssueFollowersParams) => { + if (!response.ok) { + const data = await response.json() + handlePylonError(data, response.status, 'manage_issue_followers') + } + + const data = await response.json() + + return { + success: true, + output: { + followers: data.data || [], + metadata: { + operation: 'manage_issue_followers' as const, + issueId: params?.issueId || '', + action: params?.operation || 'add' || 'add', + }, + success: true, + }, + } + }, + + outputs: { + success: { type: 'boolean', description: 'Operation success status' }, + output: { + type: 'object', + description: 'Updated followers list', + properties: { + followers: { type: 'array', description: 'Array of follower objects' }, + metadata: { type: 'object', description: 'Operation metadata' }, + success: { type: 'boolean', description: 'Operation success' }, + }, + }, + }, +} diff --git a/apps/sim/tools/pylon/redact_message.ts b/apps/sim/tools/pylon/redact_message.ts new file mode 100644 index 0000000000..39b9fedf1d --- /dev/null +++ b/apps/sim/tools/pylon/redact_message.ts @@ -0,0 +1,94 @@ +import { createLogger } from '@/lib/logs/console/logger' +import type { ToolConfig } from '@/tools/types' +import { buildPylonUrl, handlePylonError } from './types' + +const logger = createLogger('PylonRedactMessage') + +export interface PylonRedactMessageParams { + apiToken: string + issueId: string + messageId: string +} + +export interface PylonRedactMessageResponse { + success: boolean + output: { + metadata: { + operation: 'redact_message' + issueId: string + messageId: string + } + success: boolean + } +} + +export const pylonRedactMessageTool: ToolConfig< + PylonRedactMessageParams, + PylonRedactMessageResponse +> = { + id: 'pylon_redact_message', + name: 'Redact Message in Pylon', + description: 'Redact a specific message within an issue', + version: '1.0.0', + + params: { + apiToken: { + type: 'string', + required: true, + visibility: 'hidden', + description: 'Pylon API token', + }, + issueId: { + type: 'string', + required: true, + visibility: 'user-only', + description: 'Issue ID containing the message', + }, + messageId: { + type: 'string', + required: true, + visibility: 'user-only', + description: 'Message ID to redact', + }, + }, + + request: { + url: (params) => buildPylonUrl(`/issues/${params.issueId}/messages/${params.messageId}/redact`), + method: 'POST', + headers: (params) => ({ + Authorization: `Bearer ${params.apiToken}`, + 'Content-Type': 'application/json', + }), + }, + + transformResponse: async (response: Response) => { + if (!response.ok) { + const data = await response.json() + handlePylonError(data, response.status, 'redact_message') + } + + return { + success: true, + output: { + metadata: { + operation: 'redact_message' as const, + issueId: '', + messageId: '', + }, + success: true, + }, + } + }, + + outputs: { + success: { type: 'boolean', description: 'Operation success status' }, + output: { + type: 'object', + description: 'Redact operation result', + properties: { + metadata: { type: 'object', description: 'Operation metadata' }, + success: { type: 'boolean', description: 'Operation success' }, + }, + }, + }, +} diff --git a/apps/sim/tools/pylon/search_accounts.ts b/apps/sim/tools/pylon/search_accounts.ts new file mode 100644 index 0000000000..78b403eac3 --- /dev/null +++ b/apps/sim/tools/pylon/search_accounts.ts @@ -0,0 +1,130 @@ +import { createLogger } from '@/lib/logs/console/logger' +import type { ToolConfig } from '@/tools/types' +import { buildPylonUrl, handlePylonError } from './types' + +const logger = createLogger('PylonSearchAccounts') + +export interface PylonSearchAccountsParams { + apiToken: string + filter: string + limit?: string + cursor?: string +} + +export interface PylonSearchAccountsResponse { + success: boolean + output: { + accounts: any[] + pagination?: { + cursor?: string + has_next_page?: boolean + } + metadata: { + operation: 'search_accounts' + totalReturned: number + } + success: boolean + } +} + +export const pylonSearchAccountsTool: ToolConfig< + PylonSearchAccountsParams, + PylonSearchAccountsResponse +> = { + id: 'pylon_search_accounts', + name: 'Search Accounts in Pylon', + description: 'Search accounts with custom filters', + version: '1.0.0', + + params: { + apiToken: { + type: 'string', + required: true, + visibility: 'hidden', + description: 'Pylon API token', + }, + filter: { + type: 'string', + required: true, + visibility: 'user-only', + description: 'Filter as JSON string with field/operator/value structure', + }, + limit: { + type: 'string', + required: false, + visibility: 'user-only', + description: 'Number of accounts to return (1-1000, default 100)', + }, + cursor: { + type: 'string', + required: false, + visibility: 'user-only', + description: 'Pagination cursor for next page of results', + }, + }, + + request: { + url: () => buildPylonUrl('/accounts/search'), + method: 'POST', + headers: (params) => ({ + Authorization: `Bearer ${params.apiToken}`, + 'Content-Type': 'application/json', + }), + body: (params) => { + const body: any = {} + + try { + body.filter = JSON.parse(params.filter) + } catch (error) { + logger.warn('Failed to parse filter', { error }) + throw new Error('Invalid filter JSON format') + } + + if (params.limit) { + body.limit = Number.parseInt(params.limit, 10) + } + + if (params.cursor) { + body.cursor = params.cursor + } + + return body + }, + }, + + transformResponse: async (response: Response) => { + if (!response.ok) { + const data = await response.json() + handlePylonError(data, response.status, 'search_accounts') + } + + const data = await response.json() + + return { + success: true, + output: { + accounts: data.data || [], + pagination: data.pagination, + metadata: { + operation: 'search_accounts' as const, + totalReturned: data.data?.length || 0, + }, + success: true, + }, + } + }, + + outputs: { + success: { type: 'boolean', description: 'Operation success status' }, + output: { + type: 'object', + description: 'Search results', + properties: { + accounts: { type: 'array', description: 'Array of matching account objects' }, + pagination: { type: 'object', description: 'Pagination metadata' }, + metadata: { type: 'object', description: 'Operation metadata' }, + success: { type: 'boolean', description: 'Operation success' }, + }, + }, + }, +} diff --git a/apps/sim/tools/pylon/search_contacts.ts b/apps/sim/tools/pylon/search_contacts.ts new file mode 100644 index 0000000000..baaaea6c87 --- /dev/null +++ b/apps/sim/tools/pylon/search_contacts.ts @@ -0,0 +1,125 @@ +import { createLogger } from '@/lib/logs/console/logger' +import type { ToolConfig } from '@/tools/types' +import { buildPylonUrl, handlePylonError } from './types' + +const logger = createLogger('PylonSearchContacts') + +export interface PylonSearchContactsParams { + apiToken: string + filter: string + limit?: string + cursor?: string +} + +export interface PylonSearchContactsResponse { + success: boolean + output: { + contacts: any[] + pagination?: { + cursor?: string + has_next_page?: boolean + } + metadata: { + operation: 'search_contacts' + totalReturned: number + } + success: boolean + } +} + +export const pylonSearchContactsTool: ToolConfig< + PylonSearchContactsParams, + PylonSearchContactsResponse +> = { + id: 'pylon_search_contacts', + name: 'Search Contacts in Pylon', + description: 'Search for contacts using a filter', + version: '1.0.0', + + params: { + apiToken: { + type: 'string', + required: true, + visibility: 'hidden', + description: 'Pylon API token', + }, + filter: { + type: 'string', + required: true, + visibility: 'user-only', + description: 'Filter as JSON object', + }, + limit: { + type: 'string', + required: false, + visibility: 'user-only', + description: 'Maximum number of contacts to return', + }, + cursor: { + type: 'string', + required: false, + visibility: 'user-only', + description: 'Pagination cursor for next page of results', + }, + }, + + request: { + url: () => buildPylonUrl('/contacts/search'), + method: 'POST', + headers: (params) => ({ + Authorization: `Bearer ${params.apiToken}`, + 'Content-Type': 'application/json', + }), + body: (params) => { + const body: any = {} + + try { + body.filter = JSON.parse(params.filter) + } catch (error) { + logger.warn('Failed to parse filter', { error }) + body.filter = {} + } + + if (params.limit) body.limit = Number.parseInt(params.limit, 10) + if (params.cursor) body.cursor = params.cursor + + return body + }, + }, + + transformResponse: async (response: Response) => { + if (!response.ok) { + const data = await response.json() + handlePylonError(data, response.status, 'search_contacts') + } + + const data = await response.json() + + return { + success: true, + output: { + contacts: data.data || [], + pagination: data.pagination, + metadata: { + operation: 'search_contacts' as const, + totalReturned: data.data?.length || 0, + }, + success: true, + }, + } + }, + + outputs: { + success: { type: 'boolean', description: 'Operation success status' }, + output: { + type: 'object', + description: 'Search results', + properties: { + contacts: { type: 'array', description: 'Array of contact objects' }, + pagination: { type: 'object', description: 'Pagination metadata' }, + metadata: { type: 'object', description: 'Operation metadata' }, + success: { type: 'boolean', description: 'Operation success' }, + }, + }, + }, +} diff --git a/apps/sim/tools/pylon/search_issues.ts b/apps/sim/tools/pylon/search_issues.ts new file mode 100644 index 0000000000..b11f2242fb --- /dev/null +++ b/apps/sim/tools/pylon/search_issues.ts @@ -0,0 +1,124 @@ +import { createLogger } from '@/lib/logs/console/logger' +import type { ToolConfig } from '@/tools/types' +import { buildPylonUrl, handlePylonError } from './types' + +const logger = createLogger('PylonSearchIssues') + +export interface PylonSearchIssuesParams { + apiToken: string + filter: string + cursor?: string + limit?: number +} + +export interface PylonSearchIssuesResponse { + success: boolean + output: { + issues: any[] + pagination?: { + cursor?: string + has_next_page?: boolean + } + metadata: { + operation: 'search_issues' + totalReturned: number + } + success: boolean + } +} + +export const pylonSearchIssuesTool: ToolConfig = + { + id: 'pylon_search_issues', + name: 'Search Issues in Pylon', + description: 'Query issues using filters', + version: '1.0.0', + + params: { + apiToken: { + type: 'string', + required: true, + visibility: 'hidden', + description: 'Pylon API token', + }, + filter: { + type: 'string', + required: true, + visibility: 'user-only', + description: 'Filter criteria as JSON string', + }, + cursor: { + type: 'string', + required: false, + visibility: 'user-only', + description: 'Pagination cursor for next page of results', + }, + limit: { + type: 'number', + required: false, + visibility: 'user-only', + description: 'Maximum number of results to return', + }, + }, + + request: { + url: () => buildPylonUrl('/issues/search'), + method: 'POST', + headers: (params) => ({ + Authorization: `Bearer ${params.apiToken}`, + 'Content-Type': 'application/json', + }), + body: (params) => { + const body: any = {} + + if (params.filter) { + try { + body.filter = JSON.parse(params.filter) + } catch (error) { + logger.warn('Failed to parse filter', { error }) + } + } + + if (params.cursor) body.cursor = params.cursor + if (params.limit !== undefined) body.limit = params.limit + + return body + }, + }, + + transformResponse: async (response: Response) => { + if (!response.ok) { + const data = await response.json() + handlePylonError(data, response.status, 'search_issues') + } + + const data = await response.json() + + return { + success: true, + output: { + issues: data.data || [], + pagination: data.pagination, + metadata: { + operation: 'search_issues' as const, + totalReturned: data.data?.length || 0, + }, + success: true, + }, + } + }, + + outputs: { + success: { type: 'boolean', description: 'Operation success status' }, + output: { + type: 'object', + description: 'Search results', + properties: { + issues: { type: 'array', description: 'Array of issue objects' }, + pagination: { type: 'object', description: 'Pagination metadata' }, + metadata: { type: 'object', description: 'Operation metadata' }, + success: { type: 'boolean', description: 'Operation success' }, + }, + }, + }, + } diff --git a/apps/sim/tools/pylon/search_users.ts b/apps/sim/tools/pylon/search_users.ts new file mode 100644 index 0000000000..a68fec6cda --- /dev/null +++ b/apps/sim/tools/pylon/search_users.ts @@ -0,0 +1,122 @@ +import { createLogger } from '@/lib/logs/console/logger' +import type { ToolConfig } from '@/tools/types' +import { buildPylonUrl, handlePylonError } from './types' + +const logger = createLogger('PylonSearchUsers') + +export interface PylonSearchUsersParams { + apiToken: string + filter: string + cursor?: string + limit?: string +} + +export interface PylonSearchUsersResponse { + success: boolean + output: { + users: any[] + pagination?: { + cursor?: string + has_next_page?: boolean + } + metadata: { + operation: 'search_users' + totalReturned: number + } + success: boolean + } +} + +export const pylonSearchUsersTool: ToolConfig = { + id: 'pylon_search_users', + name: 'Search Users in Pylon', + description: 'Search for users using a filter with email field', + version: '1.0.0', + + params: { + apiToken: { + type: 'string', + required: true, + visibility: 'hidden', + description: 'Pylon API token', + }, + filter: { + type: 'string', + required: true, + visibility: 'user-only', + description: 'Filter as JSON object with email field', + }, + cursor: { + type: 'string', + required: false, + visibility: 'user-only', + description: 'Pagination cursor for next page of results', + }, + limit: { + type: 'string', + required: false, + visibility: 'user-only', + description: 'Maximum number of users to return', + }, + }, + + request: { + url: () => buildPylonUrl('/users/search'), + method: 'POST', + headers: (params) => ({ + Authorization: `Bearer ${params.apiToken}`, + 'Content-Type': 'application/json', + }), + body: (params) => { + const body: any = {} + + try { + body.filter = JSON.parse(params.filter) + } catch (error) { + logger.warn('Failed to parse filter', { error }) + body.filter = {} + } + + if (params.cursor) body.cursor = params.cursor + if (params.limit) body.limit = Number.parseInt(params.limit, 10) + + return body + }, + }, + + transformResponse: async (response: Response) => { + if (!response.ok) { + const data = await response.json() + handlePylonError(data, response.status, 'search_users') + } + + const data = await response.json() + + return { + success: true, + output: { + users: data.data || [], + pagination: data.pagination, + metadata: { + operation: 'search_users' as const, + totalReturned: data.data?.length || 0, + }, + success: true, + }, + } + }, + + outputs: { + success: { type: 'boolean', description: 'Operation success status' }, + output: { + type: 'object', + description: 'Search results', + properties: { + users: { type: 'array', description: 'Array of user objects' }, + pagination: { type: 'object', description: 'Pagination metadata' }, + metadata: { type: 'object', description: 'Operation metadata' }, + success: { type: 'boolean', description: 'Operation success' }, + }, + }, + }, +} diff --git a/apps/sim/tools/pylon/snooze_issue.ts b/apps/sim/tools/pylon/snooze_issue.ts new file mode 100644 index 0000000000..112b5f4bf7 --- /dev/null +++ b/apps/sim/tools/pylon/snooze_issue.ts @@ -0,0 +1,99 @@ +import { createLogger } from '@/lib/logs/console/logger' +import type { ToolConfig } from '@/tools/types' +import { buildPylonUrl, handlePylonError } from './types' + +const logger = createLogger('PylonSnoozeIssue') + +export interface PylonSnoozeIssueParams { + apiToken: string + issueId: string + snoozeUntil: string +} + +export interface PylonSnoozeIssueResponse { + success: boolean + output: { + issue: any + metadata: { + operation: 'snooze_issue' + issueId: string + snoozeUntil: string + } + success: boolean + } +} + +export const pylonSnoozeIssueTool: ToolConfig = { + id: 'pylon_snooze_issue', + name: 'Snooze Issue in Pylon', + description: 'Postpone issue visibility until specified time', + version: '1.0.0', + + params: { + apiToken: { + type: 'string', + required: true, + visibility: 'hidden', + description: 'Pylon API token', + }, + issueId: { + type: 'string', + required: true, + visibility: 'user-only', + description: 'The ID of the issue to snooze', + }, + snoozeUntil: { + type: 'string', + required: true, + visibility: 'user-only', + description: 'RFC3339 timestamp when issue should reappear (e.g., 2024-01-01T00:00:00Z)', + }, + }, + + request: { + url: (params) => buildPylonUrl(`/issues/${params?.issueId || ''}/snooze`), + method: 'POST', + headers: (params) => ({ + Authorization: `Bearer ${params.apiToken}`, + 'Content-Type': 'application/json', + }), + body: (params) => ({ + snooze_until: params?.snoozeUntil || '', + }), + }, + + transformResponse: async (response: Response, params?: PylonSnoozeIssueParams) => { + if (!response.ok) { + const data = await response.json() + handlePylonError(data, response.status, 'snooze_issue') + } + + const data = await response.json() + + return { + success: true, + output: { + issue: data.data, + metadata: { + operation: 'snooze_issue' as const, + issueId: params?.issueId || '', + snoozeUntil: params?.snoozeUntil || '', + }, + success: true, + }, + } + }, + + outputs: { + success: { type: 'boolean', description: 'Operation success status' }, + output: { + type: 'object', + description: 'Snoozed issue data', + properties: { + issue: { type: 'object', description: 'Snoozed issue object' }, + metadata: { type: 'object', description: 'Operation metadata' }, + success: { type: 'boolean', description: 'Operation success' }, + }, + }, + }, +} diff --git a/apps/sim/tools/pylon/types.ts b/apps/sim/tools/pylon/types.ts new file mode 100644 index 0000000000..059766b3d7 --- /dev/null +++ b/apps/sim/tools/pylon/types.ts @@ -0,0 +1,27 @@ +// Shared types and utilities for Pylon tools + +export const PYLON_API_BASE_URL = 'https://api.usepylon.com' + +export function buildPylonUrl(path: string): string { + return `${PYLON_API_BASE_URL}${path}` +} + +export interface PylonErrorResponse { + error?: { + code?: string + message?: string + details?: any + } + request_id?: string +} + +export function handlePylonError( + data: PylonErrorResponse, + status: number, + operation: string +): never { + const errorMessage = data.error?.message || `Pylon API error during ${operation}` + const errorCode = data.error?.code || `HTTP_${status}` + + throw new Error(`${errorCode}: ${errorMessage}`) +} diff --git a/apps/sim/tools/pylon/update_account.ts b/apps/sim/tools/pylon/update_account.ts new file mode 100644 index 0000000000..30151347b0 --- /dev/null +++ b/apps/sim/tools/pylon/update_account.ts @@ -0,0 +1,198 @@ +import { createLogger } from '@/lib/logs/console/logger' +import type { ToolConfig } from '@/tools/types' +import { buildPylonUrl, handlePylonError } from './types' + +const logger = createLogger('PylonUpdateAccount') + +export interface PylonUpdateAccountParams { + apiToken: string + accountId: string + name?: string + domains?: string + primaryDomain?: string + customFields?: string + tags?: string + channels?: string + externalIds?: string + ownerId?: string + logoUrl?: string + subaccountIds?: string +} + +export interface PylonUpdateAccountResponse { + success: boolean + output: { + account: any + metadata: { + operation: 'update_account' + accountId: string + } + success: boolean + } +} + +export const pylonUpdateAccountTool: ToolConfig< + PylonUpdateAccountParams, + PylonUpdateAccountResponse +> = { + id: 'pylon_update_account', + name: 'Update Account in Pylon', + description: 'Update an existing account with new properties', + version: '1.0.0', + + params: { + apiToken: { + type: 'string', + required: true, + visibility: 'hidden', + description: 'Pylon API token', + }, + accountId: { + type: 'string', + required: true, + visibility: 'user-only', + description: 'Account ID to update', + }, + name: { + type: 'string', + required: false, + visibility: 'user-only', + description: 'Account name', + }, + domains: { + type: 'string', + required: false, + visibility: 'user-only', + description: 'Comma-separated list of domains', + }, + primaryDomain: { + type: 'string', + required: false, + visibility: 'user-only', + description: 'Primary domain for the account', + }, + customFields: { + type: 'string', + required: false, + visibility: 'user-only', + description: 'Custom fields as JSON object', + }, + tags: { + type: 'string', + required: false, + visibility: 'user-only', + description: 'Comma-separated tag IDs', + }, + channels: { + type: 'string', + required: false, + visibility: 'user-only', + description: 'Comma-separated channel IDs', + }, + externalIds: { + type: 'string', + required: false, + visibility: 'user-only', + description: 'Comma-separated external IDs', + }, + ownerId: { + type: 'string', + required: false, + visibility: 'user-only', + description: 'Owner user ID', + }, + logoUrl: { + type: 'string', + required: false, + visibility: 'user-only', + description: 'URL to account logo', + }, + subaccountIds: { + type: 'string', + required: false, + visibility: 'user-only', + description: 'Comma-separated subaccount IDs', + }, + }, + + request: { + url: (params) => buildPylonUrl(`/accounts/${params.accountId}`), + method: 'PATCH', + headers: (params) => ({ + Authorization: `Bearer ${params.apiToken}`, + 'Content-Type': 'application/json', + }), + body: (params) => { + const body: any = {} + + if (params.name) body.name = params.name + if (params.primaryDomain) body.primary_domain = params.primaryDomain + if (params.ownerId) body.owner_id = params.ownerId + if (params.logoUrl) body.logo_url = params.logoUrl + + if (params.domains) { + body.domains = params.domains.split(',').map((d) => d.trim()) + } + + if (params.customFields) { + try { + body.custom_fields = JSON.parse(params.customFields) + } catch (error) { + logger.warn('Failed to parse custom fields', { error }) + } + } + + if (params.tags) { + body.tags = params.tags.split(',').map((t) => t.trim()) + } + + if (params.channels) { + body.channels = params.channels.split(',').map((c) => c.trim()) + } + + if (params.externalIds) { + body.external_ids = params.externalIds.split(',').map((e) => e.trim()) + } + + if (params.subaccountIds) { + body.subaccount_ids = params.subaccountIds.split(',').map((s) => s.trim()) + } + + return body + }, + }, + + transformResponse: async (response: Response) => { + if (!response.ok) { + const data = await response.json() + handlePylonError(data, response.status, 'update_account') + } + + const data = await response.json() + + return { + success: true, + output: { + account: data.data, + metadata: { + operation: 'update_account' as const, + accountId: data.data?.id || '', + }, + success: true, + }, + } + }, + + outputs: { + success: { type: 'boolean', description: 'Operation success status' }, + output: { + type: 'object', + description: 'Updated account data', + properties: { + account: { type: 'object', description: 'Updated account object' }, + metadata: { type: 'object', description: 'Operation metadata' }, + success: { type: 'boolean', description: 'Operation success' }, + }, + }, + }, +} diff --git a/apps/sim/tools/pylon/update_contact.ts b/apps/sim/tools/pylon/update_contact.ts new file mode 100644 index 0000000000..8480364ef7 --- /dev/null +++ b/apps/sim/tools/pylon/update_contact.ts @@ -0,0 +1,159 @@ +import { createLogger } from '@/lib/logs/console/logger' +import type { ToolConfig } from '@/tools/types' +import { buildPylonUrl, handlePylonError } from './types' + +const logger = createLogger('PylonUpdateContact') + +export interface PylonUpdateContactParams { + apiToken: string + contactId: string + name?: string + email?: string + accountId?: string + accountExternalId?: string + avatarUrl?: string + customFields?: string + portalRole?: string +} + +export interface PylonUpdateContactResponse { + success: boolean + output: { + contact: any + metadata: { + operation: 'update_contact' + contactId: string + } + success: boolean + } +} + +export const pylonUpdateContactTool: ToolConfig< + PylonUpdateContactParams, + PylonUpdateContactResponse +> = { + id: 'pylon_update_contact', + name: 'Update Contact in Pylon', + description: 'Update an existing contact with specified properties', + version: '1.0.0', + + params: { + apiToken: { + type: 'string', + required: true, + visibility: 'hidden', + description: 'Pylon API token', + }, + contactId: { + type: 'string', + required: true, + visibility: 'user-only', + description: 'Contact ID to update', + }, + name: { + type: 'string', + required: false, + visibility: 'user-only', + description: 'Contact name', + }, + email: { + type: 'string', + required: false, + visibility: 'user-only', + description: 'Contact email address', + }, + accountId: { + type: 'string', + required: false, + visibility: 'user-only', + description: 'Account ID to associate with contact', + }, + accountExternalId: { + type: 'string', + required: false, + visibility: 'user-only', + description: 'External account ID to associate with contact', + }, + avatarUrl: { + type: 'string', + required: false, + visibility: 'user-only', + description: 'URL for contact avatar image', + }, + customFields: { + type: 'string', + required: false, + visibility: 'user-only', + description: 'Custom fields as JSON object', + }, + portalRole: { + type: 'string', + required: false, + visibility: 'user-only', + description: 'Portal role for the contact', + }, + }, + + request: { + url: (params) => buildPylonUrl(`/contacts/${params.contactId}`), + method: 'PATCH', + headers: (params) => ({ + Authorization: `Bearer ${params.apiToken}`, + 'Content-Type': 'application/json', + }), + body: (params) => { + const body: any = {} + + if (params.name) body.name = params.name + if (params.email) body.email = params.email + if (params.accountId) body.account_id = params.accountId + if (params.accountExternalId) body.account_external_id = params.accountExternalId + if (params.avatarUrl) body.avatar_url = params.avatarUrl + if (params.portalRole) body.portal_role = params.portalRole + + if (params.customFields) { + try { + body.custom_fields = JSON.parse(params.customFields) + } catch (error) { + logger.warn('Failed to parse custom fields', { error }) + } + } + + return body + }, + }, + + transformResponse: async (response: Response) => { + if (!response.ok) { + const data = await response.json() + handlePylonError(data, response.status, 'update_contact') + } + + const data = await response.json() + + return { + success: true, + output: { + contact: data.data, + metadata: { + operation: 'update_contact' as const, + contactId: data.data?.id || '', + }, + success: true, + }, + } + }, + + outputs: { + success: { type: 'boolean', description: 'Operation success status' }, + output: { + type: 'object', + description: 'Updated contact data', + properties: { + contact: { type: 'object', description: 'Updated contact object' }, + metadata: { type: 'object', description: 'Operation metadata' }, + success: { type: 'boolean', description: 'Operation success' }, + }, + }, + }, +} diff --git a/apps/sim/tools/pylon/update_issue.ts b/apps/sim/tools/pylon/update_issue.ts new file mode 100644 index 0000000000..1b5e47525d --- /dev/null +++ b/apps/sim/tools/pylon/update_issue.ts @@ -0,0 +1,168 @@ +import { createLogger } from '@/lib/logs/console/logger' +import type { ToolConfig } from '@/tools/types' +import { buildPylonUrl, handlePylonError } from './types' + +const logger = createLogger('PylonUpdateIssue') + +export interface PylonUpdateIssueParams { + apiToken: string + issueId: string + state?: string + assigneeId?: string + teamId?: string + tags?: string + customFields?: string + customerPortalVisible?: boolean + requesterId?: string + accountId?: string +} + +export interface PylonUpdateIssueResponse { + success: boolean + output: { + issue: any + metadata: { + operation: 'update_issue' + issueId: string + } + success: boolean + } +} + +export const pylonUpdateIssueTool: ToolConfig = { + id: 'pylon_update_issue', + name: 'Update Issue in Pylon', + description: 'Update an existing issue', + version: '1.0.0', + + params: { + apiToken: { + type: 'string', + required: true, + visibility: 'hidden', + description: 'Pylon API token', + }, + issueId: { + type: 'string', + required: true, + visibility: 'user-only', + description: 'The ID of the issue to update', + }, + state: { + type: 'string', + required: false, + visibility: 'user-only', + description: 'Issue state', + }, + assigneeId: { + type: 'string', + required: false, + visibility: 'user-only', + description: 'User ID to assign issue to', + }, + teamId: { + type: 'string', + required: false, + visibility: 'user-only', + description: 'Team ID to assign issue to', + }, + tags: { + type: 'string', + required: false, + visibility: 'user-only', + description: 'Comma-separated tag IDs', + }, + customFields: { + type: 'string', + required: false, + visibility: 'user-only', + description: 'Custom fields as JSON object', + }, + customerPortalVisible: { + type: 'boolean', + required: false, + visibility: 'user-only', + description: 'Whether issue is visible in customer portal', + }, + requesterId: { + type: 'string', + required: false, + visibility: 'user-only', + description: 'Requester user ID', + }, + accountId: { + type: 'string', + required: false, + visibility: 'user-only', + description: 'Account ID to associate with issue', + }, + }, + + request: { + url: (params) => buildPylonUrl(`/issues/${params.issueId}`), + method: 'PATCH', + headers: (params) => ({ + Authorization: `Bearer ${params.apiToken}`, + 'Content-Type': 'application/json', + }), + body: (params) => { + const body: any = {} + + if (params.state !== undefined) body.state = params.state + if (params.assigneeId !== undefined) body.assignee_id = params.assigneeId + if (params.teamId !== undefined) body.team_id = params.teamId + if (params.requesterId !== undefined) body.requester_id = params.requesterId + if (params.accountId !== undefined) body.account_id = params.accountId + if (params.customerPortalVisible !== undefined) + body.customer_portal_visible = params.customerPortalVisible + + if (params.tags) { + body.tags = params.tags.split(',').map((t) => t.trim()) + } + + if (params.customFields) { + try { + body.custom_fields = JSON.parse(params.customFields) + } catch (error) { + logger.warn('Failed to parse custom fields', { error }) + } + } + + return body + }, + }, + + transformResponse: async (response: Response) => { + if (!response.ok) { + const data = await response.json() + handlePylonError(data, response.status, 'update_issue') + } + + const data = await response.json() + + return { + success: true, + output: { + issue: data.data, + metadata: { + operation: 'update_issue' as const, + issueId: data.data?.id || '', + }, + success: true, + }, + } + }, + + outputs: { + success: { type: 'boolean', description: 'Operation success status' }, + output: { + type: 'object', + description: 'Updated issue data', + properties: { + issue: { type: 'object', description: 'Updated issue object' }, + metadata: { type: 'object', description: 'Operation metadata' }, + success: { type: 'boolean', description: 'Operation success' }, + }, + }, + }, +} diff --git a/apps/sim/tools/pylon/update_tag.ts b/apps/sim/tools/pylon/update_tag.ts new file mode 100644 index 0000000000..19a7bfe112 --- /dev/null +++ b/apps/sim/tools/pylon/update_tag.ts @@ -0,0 +1,109 @@ +import { createLogger } from '@/lib/logs/console/logger' +import type { ToolConfig } from '@/tools/types' +import { buildPylonUrl, handlePylonError } from './types' + +const logger = createLogger('PylonUpdateTag') + +export interface PylonUpdateTagParams { + apiToken: string + tagId: string + hexColor?: string + value?: string +} + +export interface PylonUpdateTagResponse { + success: boolean + output: { + tag: any + metadata: { + operation: 'update_tag' + tagId: string + } + success: boolean + } +} + +export const pylonUpdateTagTool: ToolConfig = { + id: 'pylon_update_tag', + name: 'Update Tag in Pylon', + description: 'Update an existing tag with specified properties', + version: '1.0.0', + + params: { + apiToken: { + type: 'string', + required: true, + visibility: 'hidden', + description: 'Pylon API token', + }, + tagId: { + type: 'string', + required: true, + visibility: 'user-only', + description: 'Tag ID to update', + }, + hexColor: { + type: 'string', + required: false, + visibility: 'user-only', + description: 'Hex color code for tag (e.g., #FF5733)', + }, + value: { + type: 'string', + required: false, + visibility: 'user-only', + description: 'Tag value/name', + }, + }, + + request: { + url: (params) => buildPylonUrl(`/tags/${params.tagId}`), + method: 'PATCH', + headers: (params) => ({ + Authorization: `Bearer ${params.apiToken}`, + 'Content-Type': 'application/json', + }), + body: (params) => { + const body: any = {} + + if (params.hexColor) body.hex_color = params.hexColor + if (params.value) body.value = params.value + + return body + }, + }, + + transformResponse: async (response: Response) => { + if (!response.ok) { + const data = await response.json() + handlePylonError(data, response.status, 'update_tag') + } + + const data = await response.json() + + return { + success: true, + output: { + tag: data.data, + metadata: { + operation: 'update_tag' as const, + tagId: data.data?.id || '', + }, + success: true, + }, + } + }, + + outputs: { + success: { type: 'boolean', description: 'Operation success status' }, + output: { + type: 'object', + description: 'Updated tag data', + properties: { + tag: { type: 'object', description: 'Updated tag object' }, + metadata: { type: 'object', description: 'Operation metadata' }, + success: { type: 'boolean', description: 'Operation success' }, + }, + }, + }, +} diff --git a/apps/sim/tools/pylon/update_team.ts b/apps/sim/tools/pylon/update_team.ts new file mode 100644 index 0000000000..1e758f6076 --- /dev/null +++ b/apps/sim/tools/pylon/update_team.ts @@ -0,0 +1,113 @@ +import { createLogger } from '@/lib/logs/console/logger' +import type { ToolConfig } from '@/tools/types' +import { buildPylonUrl, handlePylonError } from './types' + +const logger = createLogger('PylonUpdateTeam') + +export interface PylonUpdateTeamParams { + apiToken: string + teamId: string + name?: string + userIds?: string +} + +export interface PylonUpdateTeamResponse { + success: boolean + output: { + team: any + metadata: { + operation: 'update_team' + teamId: string + } + success: boolean + } +} + +export const pylonUpdateTeamTool: ToolConfig = { + id: 'pylon_update_team', + name: 'Update Team in Pylon', + description: + 'Update an existing team with specified properties (userIds replaces entire membership)', + version: '1.0.0', + + params: { + apiToken: { + type: 'string', + required: true, + visibility: 'hidden', + description: 'Pylon API token', + }, + teamId: { + type: 'string', + required: true, + visibility: 'user-only', + description: 'Team ID to update', + }, + name: { + type: 'string', + required: false, + visibility: 'user-only', + description: 'Team name', + }, + userIds: { + type: 'string', + required: false, + visibility: 'user-only', + description: 'Comma-separated user IDs (replaces entire team membership)', + }, + }, + + request: { + url: (params) => buildPylonUrl(`/teams/${params.teamId}`), + method: 'PATCH', + headers: (params) => ({ + Authorization: `Bearer ${params.apiToken}`, + 'Content-Type': 'application/json', + }), + body: (params) => { + const body: any = {} + + if (params.name) body.name = params.name + + if (params.userIds) { + body.user_ids = params.userIds.split(',').map((id) => id.trim()) + } + + return body + }, + }, + + transformResponse: async (response: Response) => { + if (!response.ok) { + const data = await response.json() + handlePylonError(data, response.status, 'update_team') + } + + const data = await response.json() + + return { + success: true, + output: { + team: data.data, + metadata: { + operation: 'update_team' as const, + teamId: data.data?.id || '', + }, + success: true, + }, + } + }, + + outputs: { + success: { type: 'boolean', description: 'Operation success status' }, + output: { + type: 'object', + description: 'Updated team data', + properties: { + team: { type: 'object', description: 'Updated team object' }, + metadata: { type: 'object', description: 'Operation metadata' }, + success: { type: 'boolean', description: 'Operation success' }, + }, + }, + }, +} diff --git a/apps/sim/tools/pylon/update_user.ts b/apps/sim/tools/pylon/update_user.ts new file mode 100644 index 0000000000..b90e30993b --- /dev/null +++ b/apps/sim/tools/pylon/update_user.ts @@ -0,0 +1,109 @@ +import { createLogger } from '@/lib/logs/console/logger' +import type { ToolConfig } from '@/tools/types' +import { buildPylonUrl, handlePylonError } from './types' + +const logger = createLogger('PylonUpdateUser') + +export interface PylonUpdateUserParams { + apiToken: string + userId: string + roleId?: string + status?: string +} + +export interface PylonUpdateUserResponse { + success: boolean + output: { + user: any + metadata: { + operation: 'update_user' + userId: string + } + success: boolean + } +} + +export const pylonUpdateUserTool: ToolConfig = { + id: 'pylon_update_user', + name: 'Update User in Pylon', + description: 'Update an existing user with specified properties', + version: '1.0.0', + + params: { + apiToken: { + type: 'string', + required: true, + visibility: 'hidden', + description: 'Pylon API token', + }, + userId: { + type: 'string', + required: true, + visibility: 'user-only', + description: 'User ID to update', + }, + roleId: { + type: 'string', + required: false, + visibility: 'user-only', + description: 'Role ID to assign to user', + }, + status: { + type: 'string', + required: false, + visibility: 'user-only', + description: 'User status', + }, + }, + + request: { + url: (params) => buildPylonUrl(`/users/${params.userId}`), + method: 'PATCH', + headers: (params) => ({ + Authorization: `Bearer ${params.apiToken}`, + 'Content-Type': 'application/json', + }), + body: (params) => { + const body: any = {} + + if (params.roleId) body.role_id = params.roleId + if (params.status) body.status = params.status + + return body + }, + }, + + transformResponse: async (response: Response) => { + if (!response.ok) { + const data = await response.json() + handlePylonError(data, response.status, 'update_user') + } + + const data = await response.json() + + return { + success: true, + output: { + user: data.data, + metadata: { + operation: 'update_user' as const, + userId: data.data?.id || '', + }, + success: true, + }, + } + }, + + outputs: { + success: { type: 'boolean', description: 'Operation success status' }, + output: { + type: 'object', + description: 'Updated user data', + properties: { + user: { type: 'object', description: 'Updated user object' }, + metadata: { type: 'object', description: 'Operation metadata' }, + success: { type: 'boolean', description: 'Operation success' }, + }, + }, + }, +} diff --git a/apps/sim/tools/registry.ts b/apps/sim/tools/registry.ts index 5a73522963..579e1e7404 100644 --- a/apps/sim/tools/registry.ts +++ b/apps/sim/tools/registry.ts @@ -290,6 +290,25 @@ import { incidentioWorkflowsShowTool, incidentioWorkflowsUpdateTool, } from '@/tools/incidentio' +import { + intercomCreateCompanyTool, + intercomCreateContactTool, + intercomCreateMessageTool, + intercomCreateTicketTool, + intercomDeleteContactTool, + intercomGetCompanyTool, + intercomGetContactTool, + intercomGetConversationTool, + intercomGetTicketTool, + intercomListCompaniesTool, + intercomListContactsTool, + intercomListConversationsTool, + intercomListTicketsTool, + intercomReplyConversationTool, + intercomSearchContactsTool, + intercomSearchConversationsTool, + intercomUpdateContactTool, +} from '@/tools/intercom' import { searchTool as jinaSearchTool, readUrlTool } from '@/tools/jina' import { jiraAddCommentTool, @@ -402,6 +421,81 @@ import { linearUpdateWorkflowStateTool, } from '@/tools/linear' import { linkupSearchTool } from '@/tools/linkup' +import { + mailchimpAddMemberTagsTool, + mailchimpAddMemberTool, + mailchimpAddOrUpdateMemberTool, + mailchimpAddSegmentMemberTool, + mailchimpAddSubscriberToAutomationTool, + mailchimpArchiveMemberTool, + mailchimpCreateAudienceTool, + mailchimpCreateBatchOperationTool, + mailchimpCreateCampaignTool, + mailchimpCreateInterestCategoryTool, + mailchimpCreateInterestTool, + mailchimpCreateLandingPageTool, + mailchimpCreateMergeFieldTool, + mailchimpCreateSegmentTool, + mailchimpCreateTemplateTool, + mailchimpDeleteAudienceTool, + mailchimpDeleteBatchOperationTool, + mailchimpDeleteCampaignTool, + mailchimpDeleteInterestCategoryTool, + mailchimpDeleteInterestTool, + mailchimpDeleteLandingPageTool, + mailchimpDeleteMemberTool, + mailchimpDeleteMergeFieldTool, + mailchimpDeleteSegmentTool, + mailchimpDeleteTemplateTool, + mailchimpGetAudiencesTool, + mailchimpGetAudienceTool, + mailchimpGetAutomationsTool, + mailchimpGetAutomationTool, + mailchimpGetBatchOperationsTool, + mailchimpGetBatchOperationTool, + mailchimpGetCampaignContentTool, + mailchimpGetCampaignReportsTool, + mailchimpGetCampaignReportTool, + mailchimpGetCampaignsTool, + mailchimpGetCampaignTool, + mailchimpGetInterestCategoriesTool, + mailchimpGetInterestCategoryTool, + mailchimpGetInterestsTool, + mailchimpGetInterestTool, + mailchimpGetLandingPagesTool, + mailchimpGetLandingPageTool, + mailchimpGetMembersTool, + mailchimpGetMemberTagsTool, + mailchimpGetMemberTool, + mailchimpGetMergeFieldsTool, + mailchimpGetMergeFieldTool, + mailchimpGetSegmentMembersTool, + mailchimpGetSegmentsTool, + mailchimpGetSegmentTool, + mailchimpGetTemplatesTool, + mailchimpGetTemplateTool, + mailchimpPauseAutomationTool, + mailchimpPublishLandingPageTool, + mailchimpRemoveMemberTagsTool, + mailchimpRemoveSegmentMemberTool, + mailchimpReplicateCampaignTool, + mailchimpScheduleCampaignTool, + mailchimpSendCampaignTool, + mailchimpSetCampaignContentTool, + mailchimpStartAutomationTool, + mailchimpUnarchiveMemberTool, + mailchimpUnpublishLandingPageTool, + mailchimpUnscheduleCampaignTool, + mailchimpUpdateAudienceTool, + mailchimpUpdateCampaignTool, + mailchimpUpdateInterestCategoryTool, + mailchimpUpdateInterestTool, + mailchimpUpdateLandingPageTool, + mailchimpUpdateMemberTool, + mailchimpUpdateMergeFieldTool, + mailchimpUpdateSegmentTool, + mailchimpUpdateTemplateTool, +} from '@/tools/mailchimp' import { mem0AddMemoriesTool, mem0GetMemoriesTool, mem0SearchMemoriesTool } from '@/tools/mem0' import { memoryAddTool, memoryDeleteTool, memoryGetAllTool, memoryGetTool } from '@/tools/memory' import { @@ -574,6 +668,45 @@ import { posthogUpdatePropertyDefinitionTool, posthogUpdateSurveyTool, } from '@/tools/posthog' +import { + pylonBulkUpdateAccountsTool, + pylonCreateAccountTool, + pylonCreateContactTool, + pylonCreateIssueTool, + pylonCreateTagTool, + pylonCreateTeamTool, + pylonDeleteAccountTool, + pylonDeleteContactTool, + pylonDeleteIssueTool, + pylonDeleteTagTool, + pylonGetAccountTool, + pylonGetContactTool, + pylonGetIssueTool, + pylonGetTagTool, + pylonGetTeamTool, + pylonGetUserTool, + pylonLinkExternalIssueTool, + pylonListAccountsTool, + pylonListContactsTool, + pylonListIssueFollowersTool, + pylonListIssuesTool, + pylonListTagsTool, + pylonListTeamsTool, + pylonListUsersTool, + pylonManageIssueFollowersTool, + pylonRedactMessageTool, + pylonSearchAccountsTool, + pylonSearchContactsTool, + pylonSearchIssuesTool, + pylonSearchUsersTool, + pylonSnoozeIssueTool, + pylonUpdateAccountTool, + pylonUpdateContactTool, + pylonUpdateIssueTool, + pylonUpdateTagTool, + pylonUpdateTeamTool, + pylonUpdateUserTool, +} from '@/tools/pylon' import { qdrantFetchTool, qdrantSearchTool, qdrantUpsertTool } from '@/tools/qdrant' import { redditDeleteTool, @@ -825,6 +958,35 @@ import { youtubeSearchTool, youtubeVideoDetailsTool, } from '@/tools/youtube' +import { + zendeskAutocompleteOrganizationsTool, + zendeskCreateOrganizationsBulkTool, + zendeskCreateOrganizationTool, + zendeskCreateTicketsBulkTool, + zendeskCreateTicketTool, + zendeskCreateUsersBulkTool, + zendeskCreateUserTool, + zendeskDeleteOrganizationTool, + zendeskDeleteTicketTool, + zendeskDeleteUserTool, + zendeskExportSearchTool, + zendeskGetCurrentUserTool, + zendeskGetOrganizationsTool, + zendeskGetOrganizationTool, + zendeskGetTicketsTool, + zendeskGetTicketTool, + zendeskGetUsersTool, + zendeskGetUserTool, + zendeskMergeTicketsTool, + zendeskSearchCountTool, + zendeskSearchTool, + zendeskSearchUsersTool, + zendeskUpdateOrganizationTool, + zendeskUpdateTicketsBulkTool, + zendeskUpdateTicketTool, + zendeskUpdateUsersBulkTool, + zendeskUpdateUserTool, +} from '@/tools/zendesk' import { zepAddMessagesTool, zepAddUserTool, @@ -1591,6 +1753,160 @@ export const tools: Record = { salesforce_create_task: salesforceCreateTaskTool, salesforce_update_task: salesforceUpdateTaskTool, salesforce_delete_task: salesforceDeleteTaskTool, + pylon_list_issues: pylonListIssuesTool, + pylon_create_issue: pylonCreateIssueTool, + pylon_get_issue: pylonGetIssueTool, + pylon_update_issue: pylonUpdateIssueTool, + pylon_delete_issue: pylonDeleteIssueTool, + pylon_search_issues: pylonSearchIssuesTool, + pylon_snooze_issue: pylonSnoozeIssueTool, + pylon_list_issue_followers: pylonListIssueFollowersTool, + pylon_manage_issue_followers: pylonManageIssueFollowersTool, + pylon_link_external_issue: pylonLinkExternalIssueTool, + pylon_list_accounts: pylonListAccountsTool, + pylon_create_account: pylonCreateAccountTool, + pylon_get_account: pylonGetAccountTool, + pylon_update_account: pylonUpdateAccountTool, + pylon_delete_account: pylonDeleteAccountTool, + pylon_bulk_update_accounts: pylonBulkUpdateAccountsTool, + pylon_search_accounts: pylonSearchAccountsTool, + pylon_list_contacts: pylonListContactsTool, + pylon_create_contact: pylonCreateContactTool, + pylon_get_contact: pylonGetContactTool, + pylon_update_contact: pylonUpdateContactTool, + pylon_delete_contact: pylonDeleteContactTool, + pylon_search_contacts: pylonSearchContactsTool, + pylon_list_users: pylonListUsersTool, + pylon_get_user: pylonGetUserTool, + pylon_update_user: pylonUpdateUserTool, + pylon_search_users: pylonSearchUsersTool, + pylon_list_teams: pylonListTeamsTool, + pylon_get_team: pylonGetTeamTool, + pylon_create_team: pylonCreateTeamTool, + pylon_update_team: pylonUpdateTeamTool, + pylon_list_tags: pylonListTagsTool, + pylon_get_tag: pylonGetTagTool, + pylon_create_tag: pylonCreateTagTool, + pylon_update_tag: pylonUpdateTagTool, + pylon_delete_tag: pylonDeleteTagTool, + pylon_redact_message: pylonRedactMessageTool, + mailchimp_get_audiences: mailchimpGetAudiencesTool, + mailchimp_get_audience: mailchimpGetAudienceTool, + mailchimp_create_audience: mailchimpCreateAudienceTool, + mailchimp_update_audience: mailchimpUpdateAudienceTool, + mailchimp_delete_audience: mailchimpDeleteAudienceTool, + mailchimp_get_members: mailchimpGetMembersTool, + mailchimp_get_member: mailchimpGetMemberTool, + mailchimp_add_member: mailchimpAddMemberTool, + mailchimp_add_or_update_member: mailchimpAddOrUpdateMemberTool, + mailchimp_update_member: mailchimpUpdateMemberTool, + mailchimp_delete_member: mailchimpDeleteMemberTool, + mailchimp_archive_member: mailchimpArchiveMemberTool, + mailchimp_unarchive_member: mailchimpUnarchiveMemberTool, + mailchimp_get_campaigns: mailchimpGetCampaignsTool, + mailchimp_get_campaign: mailchimpGetCampaignTool, + mailchimp_create_campaign: mailchimpCreateCampaignTool, + mailchimp_update_campaign: mailchimpUpdateCampaignTool, + mailchimp_delete_campaign: mailchimpDeleteCampaignTool, + mailchimp_send_campaign: mailchimpSendCampaignTool, + mailchimp_schedule_campaign: mailchimpScheduleCampaignTool, + mailchimp_unschedule_campaign: mailchimpUnscheduleCampaignTool, + mailchimp_replicate_campaign: mailchimpReplicateCampaignTool, + mailchimp_get_campaign_content: mailchimpGetCampaignContentTool, + mailchimp_set_campaign_content: mailchimpSetCampaignContentTool, + mailchimp_get_automations: mailchimpGetAutomationsTool, + mailchimp_get_automation: mailchimpGetAutomationTool, + mailchimp_start_automation: mailchimpStartAutomationTool, + mailchimp_pause_automation: mailchimpPauseAutomationTool, + mailchimp_add_subscriber_to_automation: mailchimpAddSubscriberToAutomationTool, + mailchimp_get_templates: mailchimpGetTemplatesTool, + mailchimp_get_template: mailchimpGetTemplateTool, + mailchimp_create_template: mailchimpCreateTemplateTool, + mailchimp_update_template: mailchimpUpdateTemplateTool, + mailchimp_delete_template: mailchimpDeleteTemplateTool, + mailchimp_get_campaign_reports: mailchimpGetCampaignReportsTool, + mailchimp_get_campaign_report: mailchimpGetCampaignReportTool, + mailchimp_get_segments: mailchimpGetSegmentsTool, + mailchimp_get_segment: mailchimpGetSegmentTool, + mailchimp_create_segment: mailchimpCreateSegmentTool, + mailchimp_update_segment: mailchimpUpdateSegmentTool, + mailchimp_delete_segment: mailchimpDeleteSegmentTool, + mailchimp_get_segment_members: mailchimpGetSegmentMembersTool, + mailchimp_add_segment_member: mailchimpAddSegmentMemberTool, + mailchimp_remove_segment_member: mailchimpRemoveSegmentMemberTool, + mailchimp_get_member_tags: mailchimpGetMemberTagsTool, + mailchimp_add_member_tags: mailchimpAddMemberTagsTool, + mailchimp_remove_member_tags: mailchimpRemoveMemberTagsTool, + mailchimp_get_merge_fields: mailchimpGetMergeFieldsTool, + mailchimp_get_merge_field: mailchimpGetMergeFieldTool, + mailchimp_create_merge_field: mailchimpCreateMergeFieldTool, + mailchimp_update_merge_field: mailchimpUpdateMergeFieldTool, + mailchimp_delete_merge_field: mailchimpDeleteMergeFieldTool, + mailchimp_get_interest_categories: mailchimpGetInterestCategoriesTool, + mailchimp_get_interest_category: mailchimpGetInterestCategoryTool, + mailchimp_create_interest_category: mailchimpCreateInterestCategoryTool, + mailchimp_update_interest_category: mailchimpUpdateInterestCategoryTool, + mailchimp_delete_interest_category: mailchimpDeleteInterestCategoryTool, + mailchimp_get_interests: mailchimpGetInterestsTool, + mailchimp_get_interest: mailchimpGetInterestTool, + mailchimp_create_interest: mailchimpCreateInterestTool, + mailchimp_update_interest: mailchimpUpdateInterestTool, + mailchimp_delete_interest: mailchimpDeleteInterestTool, + mailchimp_get_landing_pages: mailchimpGetLandingPagesTool, + mailchimp_get_landing_page: mailchimpGetLandingPageTool, + mailchimp_create_landing_page: mailchimpCreateLandingPageTool, + mailchimp_update_landing_page: mailchimpUpdateLandingPageTool, + mailchimp_delete_landing_page: mailchimpDeleteLandingPageTool, + mailchimp_publish_landing_page: mailchimpPublishLandingPageTool, + mailchimp_unpublish_landing_page: mailchimpUnpublishLandingPageTool, + mailchimp_get_batch_operations: mailchimpGetBatchOperationsTool, + mailchimp_get_batch_operation: mailchimpGetBatchOperationTool, + mailchimp_create_batch_operation: mailchimpCreateBatchOperationTool, + mailchimp_delete_batch_operation: mailchimpDeleteBatchOperationTool, + zendesk_get_tickets: zendeskGetTicketsTool, + zendesk_get_ticket: zendeskGetTicketTool, + zendesk_create_ticket: zendeskCreateTicketTool, + zendesk_create_tickets_bulk: zendeskCreateTicketsBulkTool, + zendesk_update_ticket: zendeskUpdateTicketTool, + zendesk_update_tickets_bulk: zendeskUpdateTicketsBulkTool, + zendesk_delete_ticket: zendeskDeleteTicketTool, + zendesk_merge_tickets: zendeskMergeTicketsTool, + zendesk_get_users: zendeskGetUsersTool, + zendesk_get_user: zendeskGetUserTool, + zendesk_search_users: zendeskSearchUsersTool, + zendesk_create_user: zendeskCreateUserTool, + zendesk_create_users_bulk: zendeskCreateUsersBulkTool, + zendesk_update_user: zendeskUpdateUserTool, + zendesk_update_users_bulk: zendeskUpdateUsersBulkTool, + zendesk_delete_user: zendeskDeleteUserTool, + zendesk_get_current_user: zendeskGetCurrentUserTool, + zendesk_get_organizations: zendeskGetOrganizationsTool, + zendesk_get_organization: zendeskGetOrganizationTool, + zendesk_autocomplete_organizations: zendeskAutocompleteOrganizationsTool, + zendesk_create_organization: zendeskCreateOrganizationTool, + zendesk_create_organizations_bulk: zendeskCreateOrganizationsBulkTool, + zendesk_update_organization: zendeskUpdateOrganizationTool, + zendesk_delete_organization: zendeskDeleteOrganizationTool, + zendesk_search: zendeskSearchTool, + zendesk_search_count: zendeskSearchCountTool, + zendesk_export_search: zendeskExportSearchTool, + intercom_create_contact: intercomCreateContactTool, + intercom_get_contact: intercomGetContactTool, + intercom_update_contact: intercomUpdateContactTool, + intercom_list_contacts: intercomListContactsTool, + intercom_search_contacts: intercomSearchContactsTool, + intercom_delete_contact: intercomDeleteContactTool, + intercom_create_company: intercomCreateCompanyTool, + intercom_get_company: intercomGetCompanyTool, + intercom_list_companies: intercomListCompaniesTool, + intercom_get_conversation: intercomGetConversationTool, + intercom_list_conversations: intercomListConversationsTool, + intercom_reply_conversation: intercomReplyConversationTool, + intercom_search_conversations: intercomSearchConversationsTool, + intercom_create_ticket: intercomCreateTicketTool, + intercom_get_ticket: intercomGetTicketTool, + intercom_list_tickets: intercomListTicketsTool, + intercom_create_message: intercomCreateMessageTool, sentry_issues_list: listIssuesTool, sentry_issues_get: getIssueTool, sentry_issues_update: updateIssueTool, diff --git a/apps/sim/tools/zendesk/autocomplete_organizations.ts b/apps/sim/tools/zendesk/autocomplete_organizations.ts new file mode 100644 index 0000000000..9ada7f23a9 --- /dev/null +++ b/apps/sim/tools/zendesk/autocomplete_organizations.ts @@ -0,0 +1,133 @@ +import { createLogger } from '@/lib/logs/console/logger' +import type { ToolConfig } from '@/tools/types' +import { buildZendeskUrl, handleZendeskError } from './types' + +const logger = createLogger('ZendeskAutocompleteOrganizations') + +export interface ZendeskAutocompleteOrganizationsParams { + apiToken: string + subdomain: string + name: string + perPage?: string + page?: string +} + +export interface ZendeskAutocompleteOrganizationsResponse { + success: boolean + output: { + organizations: any[] + paging?: { + nextPage?: string | null + previousPage?: string | null + count: number + } + metadata: { + operation: 'autocomplete_organizations' + totalReturned: number + } + success: boolean + } +} + +export const zendeskAutocompleteOrganizationsTool: ToolConfig< + ZendeskAutocompleteOrganizationsParams, + ZendeskAutocompleteOrganizationsResponse +> = { + id: 'zendesk_autocomplete_organizations', + name: 'Autocomplete Organizations in Zendesk', + description: + 'Autocomplete organizations in Zendesk by name prefix (for name matching/autocomplete)', + version: '1.0.0', + + params: { + apiToken: { + type: 'string', + required: true, + visibility: 'hidden', + description: 'Zendesk API token', + }, + subdomain: { + type: 'string', + required: true, + visibility: 'user-only', + description: 'Your Zendesk subdomain', + }, + name: { + type: 'string', + required: true, + visibility: 'user-only', + description: 'Organization name to search for', + }, + perPage: { + type: 'string', + required: false, + visibility: 'user-only', + description: 'Results per page (default: 100, max: 100)', + }, + page: { + type: 'string', + required: false, + visibility: 'user-only', + description: 'Page number', + }, + }, + + request: { + url: (params) => { + const queryParams = new URLSearchParams() + queryParams.append('name', params.name) + if (params.page) queryParams.append('page', params.page) + if (params.perPage) queryParams.append('per_page', params.perPage) + + const query = queryParams.toString() + const url = buildZendeskUrl(params.subdomain, '/organizations/autocomplete') + return `${url}?${query}` + }, + method: 'GET', + headers: (params) => ({ + Authorization: `Bearer ${params.apiToken}`, + 'Content-Type': 'application/json', + }), + }, + + transformResponse: async (response: Response) => { + if (!response.ok) { + const data = await response.json() + handleZendeskError(data, response.status, 'autocomplete_organizations') + } + + const data = await response.json() + const organizations = data.organizations || [] + + return { + success: true, + output: { + organizations, + paging: { + nextPage: data.next_page, + previousPage: data.previous_page, + count: data.count || organizations.length, + }, + metadata: { + operation: 'autocomplete_organizations' as const, + totalReturned: organizations.length, + }, + success: true, + }, + } + }, + + outputs: { + success: { type: 'boolean', description: 'Operation success status' }, + output: { + type: 'object', + description: 'Organizations search results', + properties: { + organizations: { type: 'array', description: 'Array of organization objects' }, + paging: { type: 'object', description: 'Pagination information' }, + metadata: { type: 'object', description: 'Operation metadata' }, + success: { type: 'boolean', description: 'Operation success' }, + }, + }, + }, +} diff --git a/apps/sim/tools/zendesk/create_organization.ts b/apps/sim/tools/zendesk/create_organization.ts new file mode 100644 index 0000000000..588a2e2fd9 --- /dev/null +++ b/apps/sim/tools/zendesk/create_organization.ts @@ -0,0 +1,154 @@ +import { createLogger } from '@/lib/logs/console/logger' +import type { ToolConfig } from '@/tools/types' +import { buildZendeskUrl, handleZendeskError } from './types' + +const logger = createLogger('ZendeskCreateOrganization') + +export interface ZendeskCreateOrganizationParams { + apiToken: string + subdomain: string + name: string + domainNames?: string + details?: string + notes?: string + tags?: string + customFields?: string +} + +export interface ZendeskCreateOrganizationResponse { + success: boolean + output: { + organization: any + metadata: { + operation: 'create_organization' + organizationId: string + } + success: boolean + } +} + +export const zendeskCreateOrganizationTool: ToolConfig< + ZendeskCreateOrganizationParams, + ZendeskCreateOrganizationResponse +> = { + id: 'zendesk_create_organization', + name: 'Create Organization in Zendesk', + description: 'Create a new organization in Zendesk', + version: '1.0.0', + + params: { + apiToken: { + type: 'string', + required: true, + visibility: 'hidden', + description: 'Zendesk API token', + }, + subdomain: { + type: 'string', + required: true, + visibility: 'user-only', + description: 'Your Zendesk subdomain', + }, + name: { + type: 'string', + required: true, + visibility: 'user-only', + description: 'Organization name', + }, + domainNames: { + type: 'string', + required: false, + visibility: 'user-only', + description: 'Comma-separated domain names', + }, + details: { + type: 'string', + required: false, + visibility: 'user-only', + description: 'Organization details', + }, + notes: { + type: 'string', + required: false, + visibility: 'user-only', + description: 'Organization notes', + }, + tags: { + type: 'string', + required: false, + visibility: 'user-only', + description: 'Comma-separated tags', + }, + customFields: { + type: 'string', + required: false, + visibility: 'user-only', + description: 'Custom fields as JSON object (e.g., {"field_id": "value"})', + }, + }, + + request: { + url: (params) => buildZendeskUrl(params.subdomain, '/organizations'), + method: 'POST', + headers: (params) => ({ + Authorization: `Bearer ${params.apiToken}`, + 'Content-Type': 'application/json', + }), + body: (params) => { + const organization: any = { + name: params.name, + } + + if (params.domainNames) + organization.domain_names = params.domainNames.split(',').map((d) => d.trim()) + if (params.details) organization.details = params.details + if (params.notes) organization.notes = params.notes + if (params.tags) organization.tags = params.tags.split(',').map((t) => t.trim()) + + if (params.customFields) { + try { + const customFields = JSON.parse(params.customFields) + organization.organization_fields = customFields + } catch (error) { + logger.warn('Failed to parse custom fields', { error }) + } + } + + return { organization } + }, + }, + + transformResponse: async (response: Response) => { + if (!response.ok) { + const data = await response.json() + handleZendeskError(data, response.status, 'create_organization') + } + + const data = await response.json() + + return { + success: true, + output: { + organization: data.organization, + metadata: { + operation: 'create_organization' as const, + organizationId: data.organization?.id, + }, + success: true, + }, + } + }, + + outputs: { + success: { type: 'boolean', description: 'Operation success status' }, + output: { + type: 'object', + description: 'Created organization data', + properties: { + organization: { type: 'object', description: 'Created organization object' }, + metadata: { type: 'object', description: 'Operation metadata' }, + success: { type: 'boolean', description: 'Operation success' }, + }, + }, + }, +} diff --git a/apps/sim/tools/zendesk/create_organizations_bulk.ts b/apps/sim/tools/zendesk/create_organizations_bulk.ts new file mode 100644 index 0000000000..5c2150d438 --- /dev/null +++ b/apps/sim/tools/zendesk/create_organizations_bulk.ts @@ -0,0 +1,106 @@ +import { createLogger } from '@/lib/logs/console/logger' +import type { ToolConfig } from '@/tools/types' +import { buildZendeskUrl, handleZendeskError } from './types' + +const logger = createLogger('ZendeskCreateOrganizationsBulk') + +export interface ZendeskCreateOrganizationsBulkParams { + apiToken: string + subdomain: string + organizations: string +} + +export interface ZendeskCreateOrganizationsBulkResponse { + success: boolean + output: { + jobStatus: any + metadata: { + operation: 'create_organizations_bulk' + jobId: string + } + success: boolean + } +} + +export const zendeskCreateOrganizationsBulkTool: ToolConfig< + ZendeskCreateOrganizationsBulkParams, + ZendeskCreateOrganizationsBulkResponse +> = { + id: 'zendesk_create_organizations_bulk', + name: 'Bulk Create Organizations in Zendesk', + description: 'Create multiple organizations in Zendesk using bulk import', + version: '1.0.0', + + params: { + apiToken: { + type: 'string', + required: true, + visibility: 'hidden', + description: 'Zendesk API token', + }, + subdomain: { + type: 'string', + required: true, + visibility: 'user-only', + description: 'Your Zendesk subdomain', + }, + organizations: { + type: 'string', + required: true, + visibility: 'user-only', + description: 'JSON array of organization objects to create', + }, + }, + + request: { + url: (params) => buildZendeskUrl(params.subdomain, '/organizations/create_many'), + method: 'POST', + headers: (params) => ({ + Authorization: `Bearer ${params.apiToken}`, + 'Content-Type': 'application/json', + }), + body: (params) => { + try { + const organizations = JSON.parse(params.organizations) + return { organizations } + } catch (error) { + logger.error('Failed to parse organizations array', { error }) + throw new Error('Invalid organizations JSON format') + } + }, + }, + + transformResponse: async (response: Response) => { + if (!response.ok) { + const data = await response.json() + handleZendeskError(data, response.status, 'create_organizations_bulk') + } + + const data = await response.json() + + return { + success: true, + output: { + jobStatus: data.job_status, + metadata: { + operation: 'create_organizations_bulk' as const, + jobId: data.job_status?.id, + }, + success: true, + }, + } + }, + + outputs: { + success: { type: 'boolean', description: 'Operation success status' }, + output: { + type: 'object', + description: 'Bulk creation job status', + properties: { + jobStatus: { type: 'object', description: 'Job status object' }, + metadata: { type: 'object', description: 'Operation metadata' }, + success: { type: 'boolean', description: 'Operation success' }, + }, + }, + }, +} diff --git a/apps/sim/tools/zendesk/create_ticket.ts b/apps/sim/tools/zendesk/create_ticket.ts new file mode 100644 index 0000000000..9c32b77640 --- /dev/null +++ b/apps/sim/tools/zendesk/create_ticket.ts @@ -0,0 +1,185 @@ +import { createLogger } from '@/lib/logs/console/logger' +import type { ToolConfig } from '@/tools/types' +import { buildZendeskUrl, handleZendeskError } from './types' + +const logger = createLogger('ZendeskCreateTicket') + +export interface ZendeskCreateTicketParams { + apiToken: string + subdomain: string + subject: string + description: string + priority?: string + status?: string + type?: string + tags?: string + assigneeId?: string + groupId?: string + requesterId?: string + customFields?: string +} + +export interface ZendeskCreateTicketResponse { + success: boolean + output: { + ticket: any + metadata: { + operation: 'create_ticket' + ticketId: string + } + success: boolean + } +} + +export const zendeskCreateTicketTool: ToolConfig< + ZendeskCreateTicketParams, + ZendeskCreateTicketResponse +> = { + id: 'zendesk_create_ticket', + name: 'Create Ticket in Zendesk', + description: 'Create a new ticket in Zendesk with support for custom fields', + version: '1.0.0', + + params: { + apiToken: { + type: 'string', + required: true, + visibility: 'hidden', + description: 'Zendesk API token', + }, + subdomain: { + type: 'string', + required: true, + visibility: 'user-only', + description: 'Your Zendesk subdomain', + }, + subject: { + type: 'string', + required: false, + visibility: 'user-only', + description: 'Ticket subject (optional - will be auto-generated if not provided)', + }, + description: { + type: 'string', + required: true, + visibility: 'user-only', + description: 'Ticket description (first comment)', + }, + priority: { + type: 'string', + required: false, + visibility: 'user-only', + description: 'Priority (low, normal, high, urgent)', + }, + status: { + type: 'string', + required: false, + visibility: 'user-only', + description: 'Status (new, open, pending, hold, solved, closed)', + }, + type: { + type: 'string', + required: false, + visibility: 'user-only', + description: 'Type (problem, incident, question, task)', + }, + tags: { + type: 'string', + required: false, + visibility: 'user-only', + description: 'Comma-separated tags', + }, + assigneeId: { + type: 'string', + required: false, + visibility: 'user-only', + description: 'Assignee user ID', + }, + groupId: { + type: 'string', + required: false, + visibility: 'user-only', + description: 'Group ID', + }, + requesterId: { + type: 'string', + required: false, + visibility: 'user-only', + description: 'Requester user ID', + }, + customFields: { + type: 'string', + required: false, + visibility: 'user-only', + description: 'Custom fields as JSON object (e.g., {"field_id": "value"})', + }, + }, + + request: { + url: (params) => buildZendeskUrl(params.subdomain, '/tickets'), + method: 'POST', + headers: (params) => ({ + Authorization: `Bearer ${params.apiToken}`, + 'Content-Type': 'application/json', + }), + body: (params) => { + const ticket: any = { + subject: params.subject, + comment: { body: params.description }, + } + + if (params.priority) ticket.priority = params.priority + if (params.status) ticket.status = params.status + if (params.type) ticket.type = params.type + if (params.assigneeId) ticket.assignee_id = params.assigneeId + if (params.groupId) ticket.group_id = params.groupId + if (params.requesterId) ticket.requester_id = params.requesterId + if (params.tags) ticket.tags = params.tags.split(',').map((t) => t.trim()) + + if (params.customFields) { + try { + const customFields = JSON.parse(params.customFields) + ticket.custom_fields = Object.entries(customFields).map(([id, value]) => ({ id, value })) + } catch (error) { + logger.warn('Failed to parse custom fields', { error }) + } + } + + return { ticket } + }, + }, + + transformResponse: async (response: Response) => { + if (!response.ok) { + const data = await response.json() + handleZendeskError(data, response.status, 'create_ticket') + } + + const data = await response.json() + + return { + success: true, + output: { + ticket: data.ticket, + metadata: { + operation: 'create_ticket' as const, + ticketId: data.ticket?.id, + }, + success: true, + }, + } + }, + + outputs: { + success: { type: 'boolean', description: 'Operation success status' }, + output: { + type: 'object', + description: 'Created ticket data', + properties: { + ticket: { type: 'object', description: 'Created ticket object' }, + metadata: { type: 'object', description: 'Operation metadata' }, + success: { type: 'boolean', description: 'Operation success' }, + }, + }, + }, +} diff --git a/apps/sim/tools/zendesk/create_tickets_bulk.ts b/apps/sim/tools/zendesk/create_tickets_bulk.ts new file mode 100644 index 0000000000..7f521be5cc --- /dev/null +++ b/apps/sim/tools/zendesk/create_tickets_bulk.ts @@ -0,0 +1,107 @@ +import { createLogger } from '@/lib/logs/console/logger' +import type { ToolConfig } from '@/tools/types' +import { buildZendeskUrl, handleZendeskError } from './types' + +const logger = createLogger('ZendeskCreateTicketsBulk') + +export interface ZendeskCreateTicketsBulkParams { + apiToken: string + subdomain: string + tickets: string +} + +export interface ZendeskCreateTicketsBulkResponse { + success: boolean + output: { + jobStatus: any + metadata: { + operation: 'create_tickets_bulk' + jobId?: string + } + success: boolean + } +} + +export const zendeskCreateTicketsBulkTool: ToolConfig< + ZendeskCreateTicketsBulkParams, + ZendeskCreateTicketsBulkResponse +> = { + id: 'zendesk_create_tickets_bulk', + name: 'Bulk Create Tickets in Zendesk', + description: 'Create multiple tickets in Zendesk at once (max 100)', + version: '1.0.0', + + params: { + apiToken: { + type: 'string', + required: true, + visibility: 'hidden', + description: 'Zendesk API token', + }, + subdomain: { + type: 'string', + required: true, + visibility: 'user-only', + description: 'Your Zendesk subdomain', + }, + tickets: { + type: 'string', + required: true, + visibility: 'user-only', + description: + 'JSON array of ticket objects to create (max 100). Each ticket should have subject and comment properties.', + }, + }, + + request: { + url: (params) => buildZendeskUrl(params.subdomain, '/tickets/create_many'), + method: 'POST', + headers: (params) => ({ + Authorization: `Bearer ${params.apiToken}`, + 'Content-Type': 'application/json', + }), + body: (params) => { + try { + const tickets = JSON.parse(params.tickets) + return { tickets } + } catch (error) { + logger.error('Failed to parse tickets JSON', { error }) + throw new Error('Invalid tickets JSON format') + } + }, + }, + + transformResponse: async (response: Response) => { + if (!response.ok) { + const data = await response.json() + handleZendeskError(data, response.status, 'create_tickets_bulk') + } + + const data = await response.json() + + return { + success: true, + output: { + jobStatus: data.job_status, + metadata: { + operation: 'create_tickets_bulk' as const, + jobId: data.job_status?.id, + }, + success: true, + }, + } + }, + + outputs: { + success: { type: 'boolean', description: 'Operation success status' }, + output: { + type: 'object', + description: 'Bulk create job status', + properties: { + jobStatus: { type: 'object', description: 'Job status object' }, + metadata: { type: 'object', description: 'Operation metadata' }, + success: { type: 'boolean', description: 'Operation success' }, + }, + }, + }, +} diff --git a/apps/sim/tools/zendesk/create_user.ts b/apps/sim/tools/zendesk/create_user.ts new file mode 100644 index 0000000000..c69b11d513 --- /dev/null +++ b/apps/sim/tools/zendesk/create_user.ts @@ -0,0 +1,166 @@ +import { createLogger } from '@/lib/logs/console/logger' +import type { ToolConfig } from '@/tools/types' +import { buildZendeskUrl, handleZendeskError } from './types' + +const logger = createLogger('ZendeskCreateUser') + +export interface ZendeskCreateUserParams { + apiToken: string + subdomain: string + name?: string + email?: string + role?: string + phone?: string + organizationId?: string + verified?: string + tags?: string + customFields?: string +} + +export interface ZendeskCreateUserResponse { + success: boolean + output: { + user: any + metadata: { + operation: 'create_user' + userId: string + } + success: boolean + } +} + +export const zendeskCreateUserTool: ToolConfig = + { + id: 'zendesk_create_user', + name: 'Create User in Zendesk', + description: 'Create a new user in Zendesk', + version: '1.0.0', + + params: { + apiToken: { + type: 'string', + required: true, + visibility: 'hidden', + description: 'Zendesk API token', + }, + subdomain: { + type: 'string', + required: true, + visibility: 'user-only', + description: 'Your Zendesk subdomain', + }, + name: { + type: 'string', + required: false, + visibility: 'user-only', + description: 'User name', + }, + email: { + type: 'string', + required: false, + visibility: 'user-only', + description: 'User email', + }, + role: { + type: 'string', + required: false, + visibility: 'user-only', + description: 'User role (end-user, agent, admin)', + }, + phone: { + type: 'string', + required: false, + visibility: 'user-only', + description: 'User phone number', + }, + organizationId: { + type: 'string', + required: false, + visibility: 'user-only', + description: 'Organization ID', + }, + verified: { + type: 'string', + required: false, + visibility: 'user-only', + description: 'Set to "true" to skip email verification', + }, + tags: { + type: 'string', + required: false, + visibility: 'user-only', + description: 'Comma-separated tags', + }, + customFields: { + type: 'string', + required: false, + visibility: 'user-only', + description: 'Custom fields as JSON object (e.g., {"field_id": "value"})', + }, + }, + + request: { + url: (params) => buildZendeskUrl(params.subdomain, '/users'), + method: 'POST', + headers: (params) => ({ + Authorization: `Bearer ${params.apiToken}`, + 'Content-Type': 'application/json', + }), + body: (params) => { + const user: any = {} + + if (params.name) user.name = params.name + if (params.email) user.email = params.email + if (params.role) user.role = params.role + if (params.phone) user.phone = params.phone + if (params.organizationId) user.organization_id = params.organizationId + if (params.verified) user.verified = params.verified === 'true' + if (params.tags) user.tags = params.tags.split(',').map((t) => t.trim()) + + if (params.customFields) { + try { + const customFields = JSON.parse(params.customFields) + user.user_fields = customFields + } catch (error) { + logger.warn('Failed to parse custom fields', { error }) + } + } + + return { user } + }, + }, + + transformResponse: async (response: Response) => { + if (!response.ok) { + const data = await response.json() + handleZendeskError(data, response.status, 'create_user') + } + + const data = await response.json() + + return { + success: true, + output: { + user: data.user, + metadata: { + operation: 'create_user' as const, + userId: data.user?.id, + }, + success: true, + }, + } + }, + + outputs: { + success: { type: 'boolean', description: 'Operation success status' }, + output: { + type: 'object', + description: 'Created user data', + properties: { + user: { type: 'object', description: 'Created user object' }, + metadata: { type: 'object', description: 'Operation metadata' }, + success: { type: 'boolean', description: 'Operation success' }, + }, + }, + }, + } diff --git a/apps/sim/tools/zendesk/create_users_bulk.ts b/apps/sim/tools/zendesk/create_users_bulk.ts new file mode 100644 index 0000000000..2185660ed9 --- /dev/null +++ b/apps/sim/tools/zendesk/create_users_bulk.ts @@ -0,0 +1,106 @@ +import { createLogger } from '@/lib/logs/console/logger' +import type { ToolConfig } from '@/tools/types' +import { buildZendeskUrl, handleZendeskError } from './types' + +const logger = createLogger('ZendeskCreateUsersBulk') + +export interface ZendeskCreateUsersBulkParams { + apiToken: string + subdomain: string + users: string +} + +export interface ZendeskCreateUsersBulkResponse { + success: boolean + output: { + jobStatus: any + metadata: { + operation: 'create_users_bulk' + jobId: string + } + success: boolean + } +} + +export const zendeskCreateUsersBulkTool: ToolConfig< + ZendeskCreateUsersBulkParams, + ZendeskCreateUsersBulkResponse +> = { + id: 'zendesk_create_users_bulk', + name: 'Bulk Create Users in Zendesk', + description: 'Create multiple users in Zendesk using bulk import', + version: '1.0.0', + + params: { + apiToken: { + type: 'string', + required: true, + visibility: 'hidden', + description: 'Zendesk API token', + }, + subdomain: { + type: 'string', + required: true, + visibility: 'user-only', + description: 'Your Zendesk subdomain', + }, + users: { + type: 'string', + required: true, + visibility: 'user-only', + description: 'JSON array of user objects to create', + }, + }, + + request: { + url: (params) => buildZendeskUrl(params.subdomain, '/users/create_many'), + method: 'POST', + headers: (params) => ({ + Authorization: `Bearer ${params.apiToken}`, + 'Content-Type': 'application/json', + }), + body: (params) => { + try { + const users = JSON.parse(params.users) + return { users } + } catch (error) { + logger.error('Failed to parse users array', { error }) + throw new Error('Invalid users JSON format') + } + }, + }, + + transformResponse: async (response: Response) => { + if (!response.ok) { + const data = await response.json() + handleZendeskError(data, response.status, 'create_users_bulk') + } + + const data = await response.json() + + return { + success: true, + output: { + jobStatus: data.job_status, + metadata: { + operation: 'create_users_bulk' as const, + jobId: data.job_status?.id, + }, + success: true, + }, + } + }, + + outputs: { + success: { type: 'boolean', description: 'Operation success status' }, + output: { + type: 'object', + description: 'Bulk creation job status', + properties: { + jobStatus: { type: 'object', description: 'Job status object' }, + metadata: { type: 'object', description: 'Operation metadata' }, + success: { type: 'boolean', description: 'Operation success' }, + }, + }, + }, +} diff --git a/apps/sim/tools/zendesk/delete_organization.ts b/apps/sim/tools/zendesk/delete_organization.ts new file mode 100644 index 0000000000..16dc0f68aa --- /dev/null +++ b/apps/sim/tools/zendesk/delete_organization.ts @@ -0,0 +1,96 @@ +import { createLogger } from '@/lib/logs/console/logger' +import type { ToolConfig } from '@/tools/types' +import { buildZendeskUrl, handleZendeskError } from './types' + +const logger = createLogger('ZendeskDeleteOrganization') + +export interface ZendeskDeleteOrganizationParams { + apiToken: string + subdomain: string + organizationId: string +} + +export interface ZendeskDeleteOrganizationResponse { + success: boolean + output: { + organization: any + metadata: { + operation: 'delete_organization' + organizationId: string + } + success: boolean + } +} + +export const zendeskDeleteOrganizationTool: ToolConfig< + ZendeskDeleteOrganizationParams, + ZendeskDeleteOrganizationResponse +> = { + id: 'zendesk_delete_organization', + name: 'Delete Organization from Zendesk', + description: 'Delete an organization from Zendesk', + version: '1.0.0', + + params: { + apiToken: { + type: 'string', + required: true, + visibility: 'hidden', + description: 'Zendesk API token', + }, + subdomain: { + type: 'string', + required: true, + visibility: 'user-only', + description: 'Your Zendesk subdomain', + }, + organizationId: { + type: 'string', + required: true, + visibility: 'user-only', + description: 'Organization ID to delete', + }, + }, + + request: { + url: (params) => buildZendeskUrl(params.subdomain, `/organizations/${params.organizationId}`), + method: 'DELETE', + headers: (params) => ({ + Authorization: `Bearer ${params.apiToken}`, + 'Content-Type': 'application/json', + }), + }, + + transformResponse: async (response: Response, params) => { + if (!response.ok) { + const data = await response.json() + handleZendeskError(data, response.status, 'delete_organization') + } + + // DELETE returns 204 No Content with empty body + return { + success: true, + output: { + organization: null, + metadata: { + operation: 'delete_organization' as const, + organizationId: params?.organizationId || '', + }, + success: true, + }, + } + }, + + outputs: { + success: { type: 'boolean', description: 'Operation success status' }, + output: { + type: 'object', + description: 'Deleted organization data', + properties: { + organization: { type: 'object', description: 'Deleted organization object' }, + metadata: { type: 'object', description: 'Operation metadata' }, + success: { type: 'boolean', description: 'Operation success' }, + }, + }, + }, +} diff --git a/apps/sim/tools/zendesk/delete_ticket.ts b/apps/sim/tools/zendesk/delete_ticket.ts new file mode 100644 index 0000000000..2bdeb06c63 --- /dev/null +++ b/apps/sim/tools/zendesk/delete_ticket.ts @@ -0,0 +1,95 @@ +import { createLogger } from '@/lib/logs/console/logger' +import type { ToolConfig } from '@/tools/types' +import { buildZendeskUrl, handleZendeskError } from './types' + +const logger = createLogger('ZendeskDeleteTicket') + +export interface ZendeskDeleteTicketParams { + apiToken: string + subdomain: string + ticketId: string +} + +export interface ZendeskDeleteTicketResponse { + success: boolean + output: { + deleted: boolean + metadata: { + operation: 'delete_ticket' + ticketId: string + } + success: boolean + } +} + +export const zendeskDeleteTicketTool: ToolConfig< + ZendeskDeleteTicketParams, + ZendeskDeleteTicketResponse +> = { + id: 'zendesk_delete_ticket', + name: 'Delete Ticket from Zendesk', + description: 'Delete a ticket from Zendesk', + version: '1.0.0', + + params: { + apiToken: { + type: 'string', + required: true, + visibility: 'hidden', + description: 'Zendesk API token', + }, + subdomain: { + type: 'string', + required: true, + visibility: 'user-only', + description: 'Your Zendesk subdomain', + }, + ticketId: { + type: 'string', + required: true, + visibility: 'user-only', + description: 'Ticket ID to delete', + }, + }, + + request: { + url: (params) => buildZendeskUrl(params.subdomain, `/tickets/${params.ticketId}`), + method: 'DELETE', + headers: (params) => ({ + Authorization: `Bearer ${params.apiToken}`, + 'Content-Type': 'application/json', + }), + }, + + transformResponse: async (response: Response, params) => { + if (!response.ok) { + const data = await response.json() + handleZendeskError(data, response.status, 'delete_ticket') + } + + return { + success: true, + output: { + deleted: true, + metadata: { + operation: 'delete_ticket' as const, + ticketId: params?.ticketId || '', + }, + success: true, + }, + } + }, + + outputs: { + success: { type: 'boolean', description: 'Operation success status' }, + output: { + type: 'object', + description: 'Delete confirmation', + properties: { + deleted: { type: 'boolean', description: 'Deletion success' }, + metadata: { type: 'object', description: 'Operation metadata' }, + success: { type: 'boolean', description: 'Operation success' }, + }, + }, + }, +} diff --git a/apps/sim/tools/zendesk/delete_user.ts b/apps/sim/tools/zendesk/delete_user.ts new file mode 100644 index 0000000000..458bd70284 --- /dev/null +++ b/apps/sim/tools/zendesk/delete_user.ts @@ -0,0 +1,94 @@ +import { createLogger } from '@/lib/logs/console/logger' +import type { ToolConfig } from '@/tools/types' +import { buildZendeskUrl, handleZendeskError } from './types' + +const logger = createLogger('ZendeskDeleteUser') + +export interface ZendeskDeleteUserParams { + apiToken: string + subdomain: string + userId: string +} + +export interface ZendeskDeleteUserResponse { + success: boolean + output: { + user: any + metadata: { + operation: 'delete_user' + userId: string + } + success: boolean + } +} + +export const zendeskDeleteUserTool: ToolConfig = + { + id: 'zendesk_delete_user', + name: 'Delete User from Zendesk', + description: 'Delete a user from Zendesk', + version: '1.0.0', + + params: { + apiToken: { + type: 'string', + required: true, + visibility: 'hidden', + description: 'Zendesk API token', + }, + subdomain: { + type: 'string', + required: true, + visibility: 'user-only', + description: 'Your Zendesk subdomain', + }, + userId: { + type: 'string', + required: true, + visibility: 'user-only', + description: 'User ID to delete', + }, + }, + + request: { + url: (params) => buildZendeskUrl(params.subdomain, `/users/${params.userId}`), + method: 'DELETE', + headers: (params) => ({ + Authorization: `Bearer ${params.apiToken}`, + 'Content-Type': 'application/json', + }), + }, + + transformResponse: async (response: Response, params) => { + if (!response.ok) { + const data = await response.json() + handleZendeskError(data, response.status, 'delete_user') + } + + // DELETE returns 204 No Content with empty body + return { + success: true, + output: { + user: null, + metadata: { + operation: 'delete_user' as const, + userId: params?.userId || '', + }, + success: true, + }, + } + }, + + outputs: { + success: { type: 'boolean', description: 'Operation success status' }, + output: { + type: 'object', + description: 'Deleted user data', + properties: { + user: { type: 'object', description: 'Deleted user object' }, + metadata: { type: 'object', description: 'Operation metadata' }, + success: { type: 'boolean', description: 'Operation success' }, + }, + }, + }, + } diff --git a/apps/sim/tools/zendesk/export_search.ts b/apps/sim/tools/zendesk/export_search.ts new file mode 100644 index 0000000000..7a88f27437 --- /dev/null +++ b/apps/sim/tools/zendesk/export_search.ts @@ -0,0 +1,116 @@ +import { createLogger } from '@/lib/logs/console/logger' +import type { ToolConfig } from '@/tools/types' +import { buildZendeskUrl, handleZendeskError } from './types' + +const logger = createLogger('ZendeskExportSearch') + +export interface ZendeskExportSearchParams { + apiToken: string + subdomain: string + query: string +} + +export interface ZendeskExportSearchResponse { + success: boolean + output: { + results: any[] + paging?: { + nextPage?: string | null + previousPage?: string | null + count: number + } + metadata: { + operation: 'export_search' + totalReturned: number + } + success: boolean + } +} + +export const zendeskExportSearchTool: ToolConfig< + ZendeskExportSearchParams, + ZendeskExportSearchResponse +> = { + id: 'zendesk_export_search', + name: 'Export Search Results from Zendesk', + description: 'Export search results from Zendesk (supports larger result sets)', + version: '1.0.0', + + params: { + apiToken: { + type: 'string', + required: true, + visibility: 'hidden', + description: 'Zendesk API token', + }, + subdomain: { + type: 'string', + required: true, + visibility: 'user-only', + description: 'Your Zendesk subdomain', + }, + query: { + type: 'string', + required: true, + visibility: 'user-only', + description: 'Search query string', + }, + }, + + request: { + url: (params) => { + const queryParams = new URLSearchParams() + queryParams.append('query', params.query) + + const query = queryParams.toString() + const url = buildZendeskUrl(params.subdomain, '/search/export') + return `${url}?${query}` + }, + method: 'GET', + headers: (params) => ({ + Authorization: `Bearer ${params.apiToken}`, + 'Content-Type': 'application/json', + }), + }, + + transformResponse: async (response: Response) => { + if (!response.ok) { + const data = await response.json() + handleZendeskError(data, response.status, 'export_search') + } + + const data = await response.json() + const results = data.results || [] + + return { + success: true, + output: { + results, + paging: { + nextPage: data.next_page, + previousPage: data.previous_page, + count: data.count || results.length, + }, + metadata: { + operation: 'export_search' as const, + totalReturned: results.length, + }, + success: true, + }, + } + }, + + outputs: { + success: { type: 'boolean', description: 'Operation success status' }, + output: { + type: 'object', + description: 'Exported search results', + properties: { + results: { type: 'array', description: 'Array of result objects' }, + paging: { type: 'object', description: 'Pagination information' }, + metadata: { type: 'object', description: 'Operation metadata' }, + success: { type: 'boolean', description: 'Operation success' }, + }, + }, + }, +} diff --git a/apps/sim/tools/zendesk/get_current_user.ts b/apps/sim/tools/zendesk/get_current_user.ts new file mode 100644 index 0000000000..3b0a831244 --- /dev/null +++ b/apps/sim/tools/zendesk/get_current_user.ts @@ -0,0 +1,88 @@ +import { createLogger } from '@/lib/logs/console/logger' +import type { ToolConfig } from '@/tools/types' +import { buildZendeskUrl, handleZendeskError } from './types' + +const logger = createLogger('ZendeskGetCurrentUser') + +export interface ZendeskGetCurrentUserParams { + apiToken: string + subdomain: string +} + +export interface ZendeskGetCurrentUserResponse { + success: boolean + output: { + user: any + metadata: { + operation: 'get_current_user' + } + success: boolean + } +} + +export const zendeskGetCurrentUserTool: ToolConfig< + ZendeskGetCurrentUserParams, + ZendeskGetCurrentUserResponse +> = { + id: 'zendesk_get_current_user', + name: 'Get Current User from Zendesk', + description: 'Get the currently authenticated user from Zendesk', + version: '1.0.0', + + params: { + apiToken: { + type: 'string', + required: true, + visibility: 'hidden', + description: 'Zendesk API token', + }, + subdomain: { + type: 'string', + required: true, + visibility: 'user-only', + description: 'Your Zendesk subdomain', + }, + }, + + request: { + url: (params) => buildZendeskUrl(params.subdomain, '/users/me'), + method: 'GET', + headers: (params) => ({ + Authorization: `Bearer ${params.apiToken}`, + 'Content-Type': 'application/json', + }), + }, + + transformResponse: async (response: Response) => { + if (!response.ok) { + const data = await response.json() + handleZendeskError(data, response.status, 'get_current_user') + } + + const data = await response.json() + + return { + success: true, + output: { + user: data.user, + metadata: { + operation: 'get_current_user' as const, + }, + success: true, + }, + } + }, + + outputs: { + success: { type: 'boolean', description: 'Operation success status' }, + output: { + type: 'object', + description: 'Current user data', + properties: { + user: { type: 'object', description: 'Current user object' }, + metadata: { type: 'object', description: 'Operation metadata' }, + success: { type: 'boolean', description: 'Operation success' }, + }, + }, + }, +} diff --git a/apps/sim/tools/zendesk/get_organization.ts b/apps/sim/tools/zendesk/get_organization.ts new file mode 100644 index 0000000000..eb81df4dd9 --- /dev/null +++ b/apps/sim/tools/zendesk/get_organization.ts @@ -0,0 +1,95 @@ +import { createLogger } from '@/lib/logs/console/logger' +import type { ToolConfig } from '@/tools/types' +import { buildZendeskUrl, handleZendeskError } from './types' + +const logger = createLogger('ZendeskGetOrganization') + +export interface ZendeskGetOrganizationParams { + apiToken: string + subdomain: string + organizationId: string +} + +export interface ZendeskGetOrganizationResponse { + success: boolean + output: { + organization: any + metadata: { + operation: 'get_organization' + } + success: boolean + } +} + +export const zendeskGetOrganizationTool: ToolConfig< + ZendeskGetOrganizationParams, + ZendeskGetOrganizationResponse +> = { + id: 'zendesk_get_organization', + name: 'Get Single Organization from Zendesk', + description: 'Get a single organization by ID from Zendesk', + version: '1.0.0', + + params: { + apiToken: { + type: 'string', + required: true, + visibility: 'hidden', + description: 'Zendesk API token', + }, + subdomain: { + type: 'string', + required: true, + visibility: 'user-only', + description: 'Your Zendesk subdomain', + }, + organizationId: { + type: 'string', + required: true, + visibility: 'user-only', + description: 'Organization ID to retrieve', + }, + }, + + request: { + url: (params) => buildZendeskUrl(params.subdomain, `/organizations/${params.organizationId}`), + method: 'GET', + headers: (params) => ({ + Authorization: `Bearer ${params.apiToken}`, + 'Content-Type': 'application/json', + }), + }, + + transformResponse: async (response: Response) => { + if (!response.ok) { + const data = await response.json() + handleZendeskError(data, response.status, 'get_organization') + } + + const data = await response.json() + + return { + success: true, + output: { + organization: data.organization, + metadata: { + operation: 'get_organization' as const, + }, + success: true, + }, + } + }, + + outputs: { + success: { type: 'boolean', description: 'Operation success status' }, + output: { + type: 'object', + description: 'Organization data', + properties: { + organization: { type: 'object', description: 'Organization object' }, + metadata: { type: 'object', description: 'Operation metadata' }, + success: { type: 'boolean', description: 'Operation success' }, + }, + }, + }, +} diff --git a/apps/sim/tools/zendesk/get_organizations.ts b/apps/sim/tools/zendesk/get_organizations.ts new file mode 100644 index 0000000000..1af3524ca3 --- /dev/null +++ b/apps/sim/tools/zendesk/get_organizations.ts @@ -0,0 +1,124 @@ +import { createLogger } from '@/lib/logs/console/logger' +import type { ToolConfig } from '@/tools/types' +import { buildZendeskUrl, handleZendeskError } from './types' + +const logger = createLogger('ZendeskGetOrganizations') + +export interface ZendeskGetOrganizationsParams { + apiToken: string + subdomain: string + perPage?: string + page?: string +} + +export interface ZendeskGetOrganizationsResponse { + success: boolean + output: { + organizations: any[] + paging?: { + nextPage?: string | null + previousPage?: string | null + count: number + } + metadata: { + operation: 'get_organizations' + totalReturned: number + } + success: boolean + } +} + +export const zendeskGetOrganizationsTool: ToolConfig< + ZendeskGetOrganizationsParams, + ZendeskGetOrganizationsResponse +> = { + id: 'zendesk_get_organizations', + name: 'Get Organizations from Zendesk', + description: 'Retrieve a list of organizations from Zendesk', + version: '1.0.0', + + params: { + apiToken: { + type: 'string', + required: true, + visibility: 'hidden', + description: 'Zendesk API token', + }, + subdomain: { + type: 'string', + required: true, + visibility: 'user-only', + description: 'Your Zendesk subdomain (e.g., "mycompany" for mycompany.zendesk.com)', + }, + perPage: { + type: 'string', + required: false, + visibility: 'user-only', + description: 'Results per page (default: 100, max: 100)', + }, + page: { + type: 'string', + required: false, + visibility: 'user-only', + description: 'Page number', + }, + }, + + request: { + url: (params) => { + const queryParams = new URLSearchParams() + if (params.page) queryParams.append('page', params.page) + if (params.perPage) queryParams.append('per_page', params.perPage) + + const query = queryParams.toString() + const url = buildZendeskUrl(params.subdomain, '/organizations') + return query ? `${url}?${query}` : url + }, + method: 'GET', + headers: (params) => ({ + Authorization: `Bearer ${params.apiToken}`, + 'Content-Type': 'application/json', + }), + }, + + transformResponse: async (response: Response) => { + if (!response.ok) { + const data = await response.json() + handleZendeskError(data, response.status, 'get_organizations') + } + + const data = await response.json() + const organizations = data.organizations || [] + + return { + success: true, + output: { + organizations, + paging: { + nextPage: data.next_page, + previousPage: data.previous_page, + count: data.count || organizations.length, + }, + metadata: { + operation: 'get_organizations' as const, + totalReturned: organizations.length, + }, + success: true, + }, + } + }, + + outputs: { + success: { type: 'boolean', description: 'Operation success status' }, + output: { + type: 'object', + description: 'Organizations data and metadata', + properties: { + organizations: { type: 'array', description: 'Array of organization objects' }, + paging: { type: 'object', description: 'Pagination information' }, + metadata: { type: 'object', description: 'Operation metadata' }, + success: { type: 'boolean', description: 'Operation success' }, + }, + }, + }, +} diff --git a/apps/sim/tools/zendesk/get_ticket.ts b/apps/sim/tools/zendesk/get_ticket.ts new file mode 100644 index 0000000000..242cfc8835 --- /dev/null +++ b/apps/sim/tools/zendesk/get_ticket.ts @@ -0,0 +1,92 @@ +import { createLogger } from '@/lib/logs/console/logger' +import type { ToolConfig } from '@/tools/types' +import { buildZendeskUrl, handleZendeskError } from './types' + +const logger = createLogger('ZendeskGetTicket') + +export interface ZendeskGetTicketParams { + apiToken: string + subdomain: string + ticketId: string +} + +export interface ZendeskGetTicketResponse { + success: boolean + output: { + ticket: any + metadata: { + operation: 'get_ticket' + } + success: boolean + } +} + +export const zendeskGetTicketTool: ToolConfig = { + id: 'zendesk_get_ticket', + name: 'Get Single Ticket from Zendesk', + description: 'Get a single ticket by ID from Zendesk', + version: '1.0.0', + + params: { + apiToken: { + type: 'string', + required: true, + visibility: 'hidden', + description: 'Zendesk API token', + }, + subdomain: { + type: 'string', + required: true, + visibility: 'user-only', + description: 'Your Zendesk subdomain', + }, + ticketId: { + type: 'string', + required: true, + visibility: 'user-only', + description: 'Ticket ID to retrieve', + }, + }, + + request: { + url: (params) => buildZendeskUrl(params.subdomain, `/tickets/${params.ticketId}`), + method: 'GET', + headers: (params) => ({ + Authorization: `Bearer ${params.apiToken}`, + 'Content-Type': 'application/json', + }), + }, + + transformResponse: async (response: Response) => { + if (!response.ok) { + const data = await response.json() + handleZendeskError(data, response.status, 'get_ticket') + } + + const data = await response.json() + + return { + success: true, + output: { + ticket: data.ticket, + metadata: { + operation: 'get_ticket' as const, + }, + success: true, + }, + } + }, + + outputs: { + success: { type: 'boolean', description: 'Operation success status' }, + output: { + type: 'object', + description: 'Ticket data', + properties: { + ticket: { type: 'object', description: 'Ticket object' }, + metadata: { type: 'object', description: 'Operation metadata' }, + success: { type: 'boolean', description: 'Operation success' }, + }, + }, + }, +} diff --git a/apps/sim/tools/zendesk/get_tickets.ts b/apps/sim/tools/zendesk/get_tickets.ts new file mode 100644 index 0000000000..5460171d4e --- /dev/null +++ b/apps/sim/tools/zendesk/get_tickets.ts @@ -0,0 +1,178 @@ +import { createLogger } from '@/lib/logs/console/logger' +import type { ToolConfig } from '@/tools/types' +import { buildZendeskUrl, handleZendeskError } from './types' + +const logger = createLogger('ZendeskGetTickets') + +export interface ZendeskGetTicketsParams { + apiToken: string + subdomain: string + status?: string + priority?: string + type?: string + assigneeId?: string + organizationId?: string + sortBy?: string + sortOrder?: string + perPage?: string + page?: string +} + +export interface ZendeskGetTicketsResponse { + success: boolean + output: { + tickets: any[] + paging?: { + nextPage?: string | null + previousPage?: string | null + count: number + } + metadata: { + operation: 'get_tickets' + totalReturned: number + } + success: boolean + } +} + +export const zendeskGetTicketsTool: ToolConfig = + { + id: 'zendesk_get_tickets', + name: 'Get Tickets from Zendesk', + description: 'Retrieve a list of tickets from Zendesk with optional filtering', + version: '1.0.0', + + params: { + apiToken: { + type: 'string', + required: true, + visibility: 'hidden', + description: 'Zendesk API token', + }, + subdomain: { + type: 'string', + required: true, + visibility: 'user-only', + description: 'Your Zendesk subdomain (e.g., "mycompany" for mycompany.zendesk.com)', + }, + status: { + type: 'string', + required: false, + visibility: 'user-only', + description: 'Filter by status (new, open, pending, hold, solved, closed)', + }, + priority: { + type: 'string', + required: false, + visibility: 'user-only', + description: 'Filter by priority (low, normal, high, urgent)', + }, + type: { + type: 'string', + required: false, + visibility: 'user-only', + description: 'Filter by type (problem, incident, question, task)', + }, + assigneeId: { + type: 'string', + required: false, + visibility: 'user-only', + description: 'Filter by assignee user ID', + }, + organizationId: { + type: 'string', + required: false, + visibility: 'user-only', + description: 'Filter by organization ID', + }, + sortBy: { + type: 'string', + required: false, + visibility: 'user-only', + description: 'Sort field (created_at, updated_at, priority, status)', + }, + sortOrder: { + type: 'string', + required: false, + visibility: 'user-only', + description: 'Sort order (asc or desc)', + }, + perPage: { + type: 'string', + required: false, + visibility: 'user-only', + description: 'Results per page (default: 100, max: 100)', + }, + page: { + type: 'string', + required: false, + visibility: 'user-only', + description: 'Page number', + }, + }, + + request: { + url: (params) => { + const queryParams = new URLSearchParams() + if (params.status) queryParams.append('status', params.status) + if (params.priority) queryParams.append('priority', params.priority) + if (params.type) queryParams.append('type', params.type) + if (params.assigneeId) queryParams.append('assignee_id', params.assigneeId) + if (params.organizationId) queryParams.append('organization_id', params.organizationId) + if (params.sortBy) queryParams.append('sort_by', params.sortBy) + if (params.sortOrder) queryParams.append('sort_order', params.sortOrder) + if (params.page) queryParams.append('page', params.page) + if (params.perPage) queryParams.append('per_page', params.perPage) + + const query = queryParams.toString() + const url = buildZendeskUrl(params.subdomain, '/tickets') + return query ? `${url}?${query}` : url + }, + method: 'GET', + headers: (params) => ({ + Authorization: `Bearer ${params.apiToken}`, + 'Content-Type': 'application/json', + }), + }, + + transformResponse: async (response: Response) => { + if (!response.ok) { + const data = await response.json() + handleZendeskError(data, response.status, 'get_tickets') + } + + const data = await response.json() + const tickets = data.tickets || [] + + return { + success: true, + output: { + tickets, + paging: { + nextPage: data.next_page, + previousPage: data.previous_page, + count: data.count || tickets.length, + }, + metadata: { + operation: 'get_tickets' as const, + totalReturned: tickets.length, + }, + success: true, + }, + } + }, + + outputs: { + success: { type: 'boolean', description: 'Operation success status' }, + output: { + type: 'object', + description: 'Tickets data and metadata', + properties: { + tickets: { type: 'array', description: 'Array of ticket objects' }, + paging: { type: 'object', description: 'Pagination information' }, + metadata: { type: 'object', description: 'Operation metadata' }, + success: { type: 'boolean', description: 'Operation success' }, + }, + }, + }, + } diff --git a/apps/sim/tools/zendesk/get_user.ts b/apps/sim/tools/zendesk/get_user.ts new file mode 100644 index 0000000000..427668018a --- /dev/null +++ b/apps/sim/tools/zendesk/get_user.ts @@ -0,0 +1,92 @@ +import { createLogger } from '@/lib/logs/console/logger' +import type { ToolConfig } from '@/tools/types' +import { buildZendeskUrl, handleZendeskError } from './types' + +const logger = createLogger('ZendeskGetUser') + +export interface ZendeskGetUserParams { + apiToken: string + subdomain: string + userId: string +} + +export interface ZendeskGetUserResponse { + success: boolean + output: { + user: any + metadata: { + operation: 'get_user' + } + success: boolean + } +} + +export const zendeskGetUserTool: ToolConfig = { + id: 'zendesk_get_user', + name: 'Get Single User from Zendesk', + description: 'Get a single user by ID from Zendesk', + version: '1.0.0', + + params: { + apiToken: { + type: 'string', + required: true, + visibility: 'hidden', + description: 'Zendesk API token', + }, + subdomain: { + type: 'string', + required: true, + visibility: 'user-only', + description: 'Your Zendesk subdomain', + }, + userId: { + type: 'string', + required: true, + visibility: 'user-only', + description: 'User ID to retrieve', + }, + }, + + request: { + url: (params) => buildZendeskUrl(params.subdomain, `/users/${params.userId}`), + method: 'GET', + headers: (params) => ({ + Authorization: `Bearer ${params.apiToken}`, + 'Content-Type': 'application/json', + }), + }, + + transformResponse: async (response: Response) => { + if (!response.ok) { + const data = await response.json() + handleZendeskError(data, response.status, 'get_user') + } + + const data = await response.json() + + return { + success: true, + output: { + user: data.user, + metadata: { + operation: 'get_user' as const, + }, + success: true, + }, + } + }, + + outputs: { + success: { type: 'boolean', description: 'Operation success status' }, + output: { + type: 'object', + description: 'User data', + properties: { + user: { type: 'object', description: 'User object' }, + metadata: { type: 'object', description: 'Operation metadata' }, + success: { type: 'boolean', description: 'Operation success' }, + }, + }, + }, +} diff --git a/apps/sim/tools/zendesk/get_users.ts b/apps/sim/tools/zendesk/get_users.ts new file mode 100644 index 0000000000..146e48e6f9 --- /dev/null +++ b/apps/sim/tools/zendesk/get_users.ts @@ -0,0 +1,137 @@ +import { createLogger } from '@/lib/logs/console/logger' +import type { ToolConfig } from '@/tools/types' +import { buildZendeskUrl, handleZendeskError } from './types' + +const logger = createLogger('ZendeskGetUsers') + +export interface ZendeskGetUsersParams { + apiToken: string + subdomain: string + role?: string + permissionSet?: string + perPage?: string + page?: string +} + +export interface ZendeskGetUsersResponse { + success: boolean + output: { + users: any[] + paging?: { + nextPage?: string | null + previousPage?: string | null + count: number + } + metadata: { + operation: 'get_users' + totalReturned: number + } + success: boolean + } +} + +export const zendeskGetUsersTool: ToolConfig = { + id: 'zendesk_get_users', + name: 'Get Users from Zendesk', + description: 'Retrieve a list of users from Zendesk with optional filtering', + version: '1.0.0', + + params: { + apiToken: { + type: 'string', + required: true, + visibility: 'hidden', + description: 'Zendesk API token', + }, + subdomain: { + type: 'string', + required: true, + visibility: 'user-only', + description: 'Your Zendesk subdomain (e.g., "mycompany" for mycompany.zendesk.com)', + }, + role: { + type: 'string', + required: false, + visibility: 'user-only', + description: 'Filter by role (end-user, agent, admin)', + }, + permissionSet: { + type: 'string', + required: false, + visibility: 'user-only', + description: 'Filter by permission set ID', + }, + perPage: { + type: 'string', + required: false, + visibility: 'user-only', + description: 'Results per page (default: 100, max: 100)', + }, + page: { + type: 'string', + required: false, + visibility: 'user-only', + description: 'Page number', + }, + }, + + request: { + url: (params) => { + const queryParams = new URLSearchParams() + if (params.role) queryParams.append('role', params.role) + if (params.permissionSet) queryParams.append('permission_set', params.permissionSet) + if (params.page) queryParams.append('page', params.page) + if (params.perPage) queryParams.append('per_page', params.perPage) + + const query = queryParams.toString() + const url = buildZendeskUrl(params.subdomain, '/users') + return query ? `${url}?${query}` : url + }, + method: 'GET', + headers: (params) => ({ + Authorization: `Bearer ${params.apiToken}`, + 'Content-Type': 'application/json', + }), + }, + + transformResponse: async (response: Response) => { + if (!response.ok) { + const data = await response.json() + handleZendeskError(data, response.status, 'get_users') + } + + const data = await response.json() + const users = data.users || [] + + return { + success: true, + output: { + users, + paging: { + nextPage: data.next_page, + previousPage: data.previous_page, + count: data.count || users.length, + }, + metadata: { + operation: 'get_users' as const, + totalReturned: users.length, + }, + success: true, + }, + } + }, + + outputs: { + success: { type: 'boolean', description: 'Operation success status' }, + output: { + type: 'object', + description: 'Users data and metadata', + properties: { + users: { type: 'array', description: 'Array of user objects' }, + paging: { type: 'object', description: 'Pagination information' }, + metadata: { type: 'object', description: 'Operation metadata' }, + success: { type: 'boolean', description: 'Operation success' }, + }, + }, + }, +} diff --git a/apps/sim/tools/zendesk/index.ts b/apps/sim/tools/zendesk/index.ts new file mode 100644 index 0000000000..f5b2f4c936 --- /dev/null +++ b/apps/sim/tools/zendesk/index.ts @@ -0,0 +1,32 @@ +// Ticket tools + +export { zendeskAutocompleteOrganizationsTool } from './autocomplete_organizations' +export { zendeskCreateOrganizationTool } from './create_organization' +export { zendeskCreateOrganizationsBulkTool } from './create_organizations_bulk' +export { zendeskCreateTicketTool } from './create_ticket' +export { zendeskCreateTicketsBulkTool } from './create_tickets_bulk' +export { zendeskCreateUserTool } from './create_user' +export { zendeskCreateUsersBulkTool } from './create_users_bulk' +export { zendeskDeleteOrganizationTool } from './delete_organization' +export { zendeskDeleteTicketTool } from './delete_ticket' +export { zendeskDeleteUserTool } from './delete_user' +export { zendeskExportSearchTool } from './export_search' +export { zendeskGetCurrentUserTool } from './get_current_user' +export { zendeskGetOrganizationTool } from './get_organization' +// Organization tools +export { zendeskGetOrganizationsTool } from './get_organizations' +export { zendeskGetTicketTool } from './get_ticket' +export { zendeskGetTicketsTool } from './get_tickets' +export { zendeskGetUserTool } from './get_user' +// User tools +export { zendeskGetUsersTool } from './get_users' +export { zendeskMergeTicketsTool } from './merge_tickets' +// Search tools +export { zendeskSearchTool } from './search' +export { zendeskSearchCountTool } from './search_count' +export { zendeskSearchUsersTool } from './search_users' +export { zendeskUpdateOrganizationTool } from './update_organization' +export { zendeskUpdateTicketTool } from './update_ticket' +export { zendeskUpdateTicketsBulkTool } from './update_tickets_bulk' +export { zendeskUpdateUserTool } from './update_user' +export { zendeskUpdateUsersBulkTool } from './update_users_bulk' diff --git a/apps/sim/tools/zendesk/merge_tickets.ts b/apps/sim/tools/zendesk/merge_tickets.ts new file mode 100644 index 0000000000..d8a2facaab --- /dev/null +++ b/apps/sim/tools/zendesk/merge_tickets.ts @@ -0,0 +1,124 @@ +import { createLogger } from '@/lib/logs/console/logger' +import type { ToolConfig } from '@/tools/types' +import { buildZendeskUrl, handleZendeskError } from './types' + +const logger = createLogger('ZendeskMergeTickets') + +export interface ZendeskMergeTicketsParams { + apiToken: string + subdomain: string + targetTicketId: string + sourceTicketIds: string + targetComment?: string +} + +export interface ZendeskMergeTicketsResponse { + success: boolean + output: { + jobStatus: any + metadata: { + operation: 'merge_tickets' + jobId?: string + targetTicketId: string + } + success: boolean + } +} + +export const zendeskMergeTicketsTool: ToolConfig< + ZendeskMergeTicketsParams, + ZendeskMergeTicketsResponse +> = { + id: 'zendesk_merge_tickets', + name: 'Merge Tickets in Zendesk', + description: 'Merge multiple tickets into a target ticket', + version: '1.0.0', + + params: { + apiToken: { + type: 'string', + required: true, + visibility: 'hidden', + description: 'Zendesk API token', + }, + subdomain: { + type: 'string', + required: true, + visibility: 'user-only', + description: 'Your Zendesk subdomain', + }, + targetTicketId: { + type: 'string', + required: true, + visibility: 'user-only', + description: 'Target ticket ID (tickets will be merged into this one)', + }, + sourceTicketIds: { + type: 'string', + required: true, + visibility: 'user-only', + description: 'Comma-separated source ticket IDs to merge', + }, + targetComment: { + type: 'string', + required: false, + visibility: 'user-only', + description: 'Comment to add to target ticket after merge', + }, + }, + + request: { + url: (params) => buildZendeskUrl(params.subdomain, `/tickets/${params.targetTicketId}/merge`), + method: 'POST', + headers: (params) => ({ + Authorization: `Bearer ${params.apiToken}`, + 'Content-Type': 'application/json', + }), + body: (params) => { + const ids = params.sourceTicketIds.split(',').map((id) => id.trim()) + const body: any = { ids } + if (params.targetComment) { + body.target_comment = { + body: params.targetComment, + public: true, + } + } + return body + }, + }, + + transformResponse: async (response: Response, params) => { + if (!response.ok) { + const data = await response.json() + handleZendeskError(data, response.status, 'merge_tickets') + } + + const data = await response.json() + + return { + success: true, + output: { + jobStatus: data.job_status, + metadata: { + operation: 'merge_tickets' as const, + jobId: data.job_status?.id, + targetTicketId: params?.targetTicketId || '', + }, + success: true, + }, + } + }, + + outputs: { + success: { type: 'boolean', description: 'Operation success status' }, + output: { + type: 'object', + description: 'Merge job status', + properties: { + jobStatus: { type: 'object', description: 'Job status object' }, + metadata: { type: 'object', description: 'Operation metadata' }, + success: { type: 'boolean', description: 'Operation success' }, + }, + }, + }, +} diff --git a/apps/sim/tools/zendesk/search.ts b/apps/sim/tools/zendesk/search.ts new file mode 100644 index 0000000000..abe0e84fc9 --- /dev/null +++ b/apps/sim/tools/zendesk/search.ts @@ -0,0 +1,145 @@ +import { createLogger } from '@/lib/logs/console/logger' +import type { ToolConfig } from '@/tools/types' +import { buildZendeskUrl, handleZendeskError } from './types' + +const logger = createLogger('ZendeskSearch') + +export interface ZendeskSearchParams { + apiToken: string + subdomain: string + query: string + sortBy?: string + sortOrder?: string + perPage?: string + page?: string +} + +export interface ZendeskSearchResponse { + success: boolean + output: { + results: any[] + paging?: { + nextPage?: string | null + previousPage?: string | null + count: number + } + metadata: { + operation: 'search' + totalReturned: number + } + success: boolean + } +} + +export const zendeskSearchTool: ToolConfig = { + id: 'zendesk_search', + name: 'Search Zendesk', + description: 'Unified search across tickets, users, and organizations in Zendesk', + version: '1.0.0', + + params: { + apiToken: { + type: 'string', + required: true, + visibility: 'hidden', + description: 'Zendesk API token', + }, + subdomain: { + type: 'string', + required: true, + visibility: 'user-only', + description: 'Your Zendesk subdomain', + }, + query: { + type: 'string', + required: true, + visibility: 'user-only', + description: 'Search query string', + }, + sortBy: { + type: 'string', + required: false, + visibility: 'user-only', + description: 'Sort field (relevance, created_at, updated_at, priority, status, ticket_type)', + }, + sortOrder: { + type: 'string', + required: false, + visibility: 'user-only', + description: 'Sort order (asc or desc)', + }, + perPage: { + type: 'string', + required: false, + visibility: 'user-only', + description: 'Results per page (default: 100, max: 100)', + }, + page: { + type: 'string', + required: false, + visibility: 'user-only', + description: 'Page number', + }, + }, + + request: { + url: (params) => { + const queryParams = new URLSearchParams() + queryParams.append('query', params.query) + if (params.sortBy) queryParams.append('sort_by', params.sortBy) + if (params.sortOrder) queryParams.append('sort_order', params.sortOrder) + if (params.page) queryParams.append('page', params.page) + if (params.perPage) queryParams.append('per_page', params.perPage) + + const query = queryParams.toString() + const url = buildZendeskUrl(params.subdomain, '/search') + return `${url}?${query}` + }, + method: 'GET', + headers: (params) => ({ + Authorization: `Bearer ${params.apiToken}`, + 'Content-Type': 'application/json', + }), + }, + + transformResponse: async (response: Response) => { + if (!response.ok) { + const data = await response.json() + handleZendeskError(data, response.status, 'search') + } + + const data = await response.json() + const results = data.results || [] + + return { + success: true, + output: { + results, + paging: { + nextPage: data.next_page, + previousPage: data.previous_page, + count: data.count || results.length, + }, + metadata: { + operation: 'search' as const, + totalReturned: results.length, + }, + success: true, + }, + } + }, + + outputs: { + success: { type: 'boolean', description: 'Operation success status' }, + output: { + type: 'object', + description: 'Search results', + properties: { + results: { type: 'array', description: 'Array of result objects' }, + paging: { type: 'object', description: 'Pagination information' }, + metadata: { type: 'object', description: 'Operation metadata' }, + success: { type: 'boolean', description: 'Operation success' }, + }, + }, + }, +} diff --git a/apps/sim/tools/zendesk/search_count.ts b/apps/sim/tools/zendesk/search_count.ts new file mode 100644 index 0000000000..f28e9351ec --- /dev/null +++ b/apps/sim/tools/zendesk/search_count.ts @@ -0,0 +1,102 @@ +import { createLogger } from '@/lib/logs/console/logger' +import type { ToolConfig } from '@/tools/types' +import { buildZendeskUrl, handleZendeskError } from './types' + +const logger = createLogger('ZendeskSearchCount') + +export interface ZendeskSearchCountParams { + apiToken: string + subdomain: string + query: string +} + +export interface ZendeskSearchCountResponse { + success: boolean + output: { + count: number + metadata: { + operation: 'search_count' + } + success: boolean + } +} + +export const zendeskSearchCountTool: ToolConfig< + ZendeskSearchCountParams, + ZendeskSearchCountResponse +> = { + id: 'zendesk_search_count', + name: 'Count Search Results in Zendesk', + description: 'Count the number of search results matching a query in Zendesk', + version: '1.0.0', + + params: { + apiToken: { + type: 'string', + required: true, + visibility: 'hidden', + description: 'Zendesk API token', + }, + subdomain: { + type: 'string', + required: true, + visibility: 'user-only', + description: 'Your Zendesk subdomain', + }, + query: { + type: 'string', + required: true, + visibility: 'user-only', + description: 'Search query string', + }, + }, + + request: { + url: (params) => { + const queryParams = new URLSearchParams() + queryParams.append('query', params.query) + + const query = queryParams.toString() + const url = buildZendeskUrl(params.subdomain, '/search/count') + return `${url}?${query}` + }, + method: 'GET', + headers: (params) => ({ + Authorization: `Bearer ${params.apiToken}`, + 'Content-Type': 'application/json', + }), + }, + + transformResponse: async (response: Response) => { + if (!response.ok) { + const data = await response.json() + handleZendeskError(data, response.status, 'search_count') + } + + const data = await response.json() + + return { + success: true, + output: { + count: data.count || 0, + metadata: { + operation: 'search_count' as const, + }, + success: true, + }, + } + }, + + outputs: { + success: { type: 'boolean', description: 'Operation success status' }, + output: { + type: 'object', + description: 'Search count result', + properties: { + count: { type: 'number', description: 'Number of matching results' }, + metadata: { type: 'object', description: 'Operation metadata' }, + success: { type: 'boolean', description: 'Operation success' }, + }, + }, + }, +} diff --git a/apps/sim/tools/zendesk/search_users.ts b/apps/sim/tools/zendesk/search_users.ts new file mode 100644 index 0000000000..58dfe268b0 --- /dev/null +++ b/apps/sim/tools/zendesk/search_users.ts @@ -0,0 +1,140 @@ +import { createLogger } from '@/lib/logs/console/logger' +import type { ToolConfig } from '@/tools/types' +import { buildZendeskUrl, handleZendeskError } from './types' + +const logger = createLogger('ZendeskSearchUsers') + +export interface ZendeskSearchUsersParams { + apiToken: string + subdomain: string + query?: string + externalId?: string + perPage?: string + page?: string +} + +export interface ZendeskSearchUsersResponse { + success: boolean + output: { + users: any[] + paging?: { + nextPage?: string | null + previousPage?: string | null + count: number + } + metadata: { + operation: 'search_users' + totalReturned: number + } + success: boolean + } +} + +export const zendeskSearchUsersTool: ToolConfig< + ZendeskSearchUsersParams, + ZendeskSearchUsersResponse +> = { + id: 'zendesk_search_users', + name: 'Search Users in Zendesk', + description: 'Search for users in Zendesk using a query string', + version: '1.0.0', + + params: { + apiToken: { + type: 'string', + required: true, + visibility: 'hidden', + description: 'Zendesk API token', + }, + subdomain: { + type: 'string', + required: true, + visibility: 'user-only', + description: 'Your Zendesk subdomain', + }, + query: { + type: 'string', + required: false, + visibility: 'user-only', + description: 'Search query string', + }, + externalId: { + type: 'string', + required: false, + visibility: 'user-only', + description: 'External ID to search by', + }, + perPage: { + type: 'string', + required: false, + visibility: 'user-only', + description: 'Results per page (default: 100, max: 100)', + }, + page: { + type: 'string', + required: false, + visibility: 'user-only', + description: 'Page number', + }, + }, + + request: { + url: (params) => { + const queryParams = new URLSearchParams() + if (params.query) queryParams.append('query', params.query) + if (params.externalId) queryParams.append('external_id', params.externalId) + if (params.page) queryParams.append('page', params.page) + if (params.perPage) queryParams.append('per_page', params.perPage) + + const query = queryParams.toString() + const url = buildZendeskUrl(params.subdomain, '/users/search') + return `${url}?${query}` + }, + method: 'GET', + headers: (params) => ({ + Authorization: `Bearer ${params.apiToken}`, + 'Content-Type': 'application/json', + }), + }, + + transformResponse: async (response: Response) => { + if (!response.ok) { + const data = await response.json() + handleZendeskError(data, response.status, 'search_users') + } + + const data = await response.json() + const users = data.users || [] + + return { + success: true, + output: { + users, + paging: { + nextPage: data.next_page, + previousPage: data.previous_page, + count: data.count || users.length, + }, + metadata: { + operation: 'search_users' as const, + totalReturned: users.length, + }, + success: true, + }, + } + }, + + outputs: { + success: { type: 'boolean', description: 'Operation success status' }, + output: { + type: 'object', + description: 'Users search results', + properties: { + users: { type: 'array', description: 'Array of user objects' }, + paging: { type: 'object', description: 'Pagination information' }, + metadata: { type: 'object', description: 'Operation metadata' }, + success: { type: 'boolean', description: 'Operation success' }, + }, + }, + }, +} diff --git a/apps/sim/tools/zendesk/types.ts b/apps/sim/tools/zendesk/types.ts new file mode 100644 index 0000000000..e2db2c2701 --- /dev/null +++ b/apps/sim/tools/zendesk/types.ts @@ -0,0 +1,48 @@ +import { createLogger } from '@/lib/logs/console/logger' + +const logger = createLogger('Zendesk') + +// Base params - following Sentry pattern where subdomain is user-provided +export interface ZendeskBaseParams { + accessToken: string // OAuth token (hidden) + idToken?: string // Optional ID token (hidden) + subdomain: string // Zendesk subdomain (user-visible, required - e.g., "mycompany" for mycompany.zendesk.com) +} + +export interface ZendeskPaginationParams { + page?: string + perPage?: string +} + +export interface ZendeskPagingInfo { + nextPage?: string | null + previousPage?: string | null + count: number +} + +export interface ZendeskResponse { + success: boolean + output: { + data?: T + paging?: ZendeskPagingInfo + metadata: { + operation: string + [key: string]: any + } + success: boolean + } +} + +// Helper function to build Zendesk API URLs +// Subdomain is always provided by user as a parameter +export function buildZendeskUrl(subdomain: string, path: string): string { + return `https://${subdomain}.zendesk.com/api/v2${path}` +} + +// Helper function for consistent error handling +export function handleZendeskError(data: any, status: number, operation: string): never { + logger.error(`Zendesk API request failed for ${operation}`, { data, status }) + + const errorMessage = data.error || data.description || data.message || 'Unknown error' + throw new Error(`Zendesk ${operation} failed: ${errorMessage}`) +} diff --git a/apps/sim/tools/zendesk/update_organization.ts b/apps/sim/tools/zendesk/update_organization.ts new file mode 100644 index 0000000000..055b18019d --- /dev/null +++ b/apps/sim/tools/zendesk/update_organization.ts @@ -0,0 +1,160 @@ +import { createLogger } from '@/lib/logs/console/logger' +import type { ToolConfig } from '@/tools/types' +import { buildZendeskUrl, handleZendeskError } from './types' + +const logger = createLogger('ZendeskUpdateOrganization') + +export interface ZendeskUpdateOrganizationParams { + apiToken: string + subdomain: string + organizationId: string + name?: string + domainNames?: string + details?: string + notes?: string + tags?: string + customFields?: string +} + +export interface ZendeskUpdateOrganizationResponse { + success: boolean + output: { + organization: any + metadata: { + operation: 'update_organization' + organizationId: string + } + success: boolean + } +} + +export const zendeskUpdateOrganizationTool: ToolConfig< + ZendeskUpdateOrganizationParams, + ZendeskUpdateOrganizationResponse +> = { + id: 'zendesk_update_organization', + name: 'Update Organization in Zendesk', + description: 'Update an existing organization in Zendesk', + version: '1.0.0', + + params: { + apiToken: { + type: 'string', + required: true, + visibility: 'hidden', + description: 'Zendesk API token', + }, + subdomain: { + type: 'string', + required: true, + visibility: 'user-only', + description: 'Your Zendesk subdomain', + }, + organizationId: { + type: 'string', + required: true, + visibility: 'user-only', + description: 'Organization ID to update', + }, + name: { + type: 'string', + required: false, + visibility: 'user-only', + description: 'New organization name', + }, + domainNames: { + type: 'string', + required: false, + visibility: 'user-only', + description: 'Comma-separated domain names', + }, + details: { + type: 'string', + required: false, + visibility: 'user-only', + description: 'Organization details', + }, + notes: { + type: 'string', + required: false, + visibility: 'user-only', + description: 'Organization notes', + }, + tags: { + type: 'string', + required: false, + visibility: 'user-only', + description: 'Comma-separated tags', + }, + customFields: { + type: 'string', + required: false, + visibility: 'user-only', + description: 'Custom fields as JSON object', + }, + }, + + request: { + url: (params) => buildZendeskUrl(params.subdomain, `/organizations/${params.organizationId}`), + method: 'PUT', + headers: (params) => ({ + Authorization: `Bearer ${params.apiToken}`, + 'Content-Type': 'application/json', + }), + body: (params) => { + const organization: any = {} + + if (params.name) organization.name = params.name + if (params.domainNames) + organization.domain_names = params.domainNames.split(',').map((d) => d.trim()) + if (params.details) organization.details = params.details + if (params.notes) organization.notes = params.notes + if (params.tags) organization.tags = params.tags.split(',').map((t) => t.trim()) + + if (params.customFields) { + try { + const customFields = JSON.parse(params.customFields) + organization.organization_fields = customFields + } catch (error) { + logger.warn('Failed to parse custom fields', { error }) + } + } + + return { organization } + }, + }, + + transformResponse: async (response: Response) => { + if (!response.ok) { + const data = await response.json() + handleZendeskError(data, response.status, 'update_organization') + } + + const data = await response.json() + + return { + success: true, + output: { + organization: data.organization, + metadata: { + operation: 'update_organization' as const, + organizationId: data.organization?.id, + }, + success: true, + }, + } + }, + + outputs: { + success: { type: 'boolean', description: 'Operation success status' }, + output: { + type: 'object', + description: 'Updated organization data', + properties: { + organization: { type: 'object', description: 'Updated organization object' }, + metadata: { type: 'object', description: 'Operation metadata' }, + success: { type: 'boolean', description: 'Operation success' }, + }, + }, + }, +} diff --git a/apps/sim/tools/zendesk/update_ticket.ts b/apps/sim/tools/zendesk/update_ticket.ts new file mode 100644 index 0000000000..4e3368a3ad --- /dev/null +++ b/apps/sim/tools/zendesk/update_ticket.ts @@ -0,0 +1,183 @@ +import { createLogger } from '@/lib/logs/console/logger' +import type { ToolConfig } from '@/tools/types' +import { buildZendeskUrl, handleZendeskError } from './types' + +const logger = createLogger('ZendeskUpdateTicket') + +export interface ZendeskUpdateTicketParams { + apiToken: string + subdomain: string + ticketId: string + subject?: string + comment?: string + priority?: string + status?: string + type?: string + tags?: string + assigneeId?: string + groupId?: string + customFields?: string +} + +export interface ZendeskUpdateTicketResponse { + success: boolean + output: { + ticket: any + metadata: { + operation: 'update_ticket' + ticketId: string + } + success: boolean + } +} + +export const zendeskUpdateTicketTool: ToolConfig< + ZendeskUpdateTicketParams, + ZendeskUpdateTicketResponse +> = { + id: 'zendesk_update_ticket', + name: 'Update Ticket in Zendesk', + description: 'Update an existing ticket in Zendesk with support for custom fields', + version: '1.0.0', + + params: { + apiToken: { + type: 'string', + required: true, + visibility: 'hidden', + description: 'Zendesk API token', + }, + subdomain: { + type: 'string', + required: true, + visibility: 'user-only', + description: 'Your Zendesk subdomain', + }, + ticketId: { + type: 'string', + required: true, + visibility: 'user-only', + description: 'Ticket ID to update', + }, + subject: { + type: 'string', + required: false, + visibility: 'user-only', + description: 'New ticket subject', + }, + comment: { + type: 'string', + required: false, + visibility: 'user-only', + description: 'Add a comment to the ticket', + }, + priority: { + type: 'string', + required: false, + visibility: 'user-only', + description: 'Priority (low, normal, high, urgent)', + }, + status: { + type: 'string', + required: false, + visibility: 'user-only', + description: 'Status (new, open, pending, hold, solved, closed)', + }, + type: { + type: 'string', + required: false, + visibility: 'user-only', + description: 'Type (problem, incident, question, task)', + }, + tags: { + type: 'string', + required: false, + visibility: 'user-only', + description: 'Comma-separated tags', + }, + assigneeId: { + type: 'string', + required: false, + visibility: 'user-only', + description: 'Assignee user ID', + }, + groupId: { + type: 'string', + required: false, + visibility: 'user-only', + description: 'Group ID', + }, + customFields: { + type: 'string', + required: false, + visibility: 'user-only', + description: 'Custom fields as JSON object', + }, + }, + + request: { + url: (params) => buildZendeskUrl(params.subdomain, `/tickets/${params.ticketId}`), + method: 'PUT', + headers: (params) => ({ + Authorization: `Bearer ${params.apiToken}`, + 'Content-Type': 'application/json', + }), + body: (params) => { + const ticket: any = {} + + if (params.subject) ticket.subject = params.subject + if (params.priority) ticket.priority = params.priority + if (params.status) ticket.status = params.status + if (params.type) ticket.type = params.type + if (params.assigneeId) ticket.assignee_id = params.assigneeId + if (params.groupId) ticket.group_id = params.groupId + if (params.tags) ticket.tags = params.tags.split(',').map((t) => t.trim()) + if (params.comment) ticket.comment = { body: params.comment } + + if (params.customFields) { + try { + const customFields = JSON.parse(params.customFields) + ticket.custom_fields = Object.entries(customFields).map(([id, value]) => ({ id, value })) + } catch (error) { + logger.warn('Failed to parse custom fields', { error }) + } + } + + return { ticket } + }, + }, + + transformResponse: async (response: Response) => { + if (!response.ok) { + const data = await response.json() + handleZendeskError(data, response.status, 'update_ticket') + } + + const data = await response.json() + + return { + success: true, + output: { + ticket: data.ticket, + metadata: { + operation: 'update_ticket' as const, + ticketId: data.ticket?.id, + }, + success: true, + }, + } + }, + + outputs: { + success: { type: 'boolean', description: 'Operation success status' }, + output: { + type: 'object', + description: 'Updated ticket data', + properties: { + ticket: { type: 'object', description: 'Updated ticket object' }, + metadata: { type: 'object', description: 'Operation metadata' }, + success: { type: 'boolean', description: 'Operation success' }, + }, + }, + }, +} diff --git a/apps/sim/tools/zendesk/update_tickets_bulk.ts b/apps/sim/tools/zendesk/update_tickets_bulk.ts new file mode 100644 index 0000000000..efd2c25b54 --- /dev/null +++ b/apps/sim/tools/zendesk/update_tickets_bulk.ts @@ -0,0 +1,144 @@ +import { createLogger } from '@/lib/logs/console/logger' +import type { ToolConfig } from '@/tools/types' +import { buildZendeskUrl, handleZendeskError } from './types' + +const logger = createLogger('ZendeskUpdateTicketsBulk') + +export interface ZendeskUpdateTicketsBulkParams { + apiToken: string + subdomain: string + ticketIds: string + status?: string + priority?: string + assigneeId?: string + groupId?: string + tags?: string +} + +export interface ZendeskUpdateTicketsBulkResponse { + success: boolean + output: { + jobStatus: any + metadata: { + operation: 'update_tickets_bulk' + jobId?: string + } + success: boolean + } +} + +export const zendeskUpdateTicketsBulkTool: ToolConfig< + ZendeskUpdateTicketsBulkParams, + ZendeskUpdateTicketsBulkResponse +> = { + id: 'zendesk_update_tickets_bulk', + name: 'Bulk Update Tickets in Zendesk', + description: 'Update multiple tickets in Zendesk at once (max 100)', + version: '1.0.0', + + params: { + apiToken: { + type: 'string', + required: true, + visibility: 'hidden', + description: 'Zendesk API token', + }, + subdomain: { + type: 'string', + required: true, + visibility: 'user-only', + description: 'Your Zendesk subdomain', + }, + ticketIds: { + type: 'string', + required: true, + visibility: 'user-only', + description: 'Comma-separated ticket IDs to update (max 100)', + }, + status: { + type: 'string', + required: false, + visibility: 'user-only', + description: 'New status for all tickets', + }, + priority: { + type: 'string', + required: false, + visibility: 'user-only', + description: 'New priority for all tickets', + }, + assigneeId: { + type: 'string', + required: false, + visibility: 'user-only', + description: 'New assignee ID for all tickets', + }, + groupId: { + type: 'string', + required: false, + visibility: 'user-only', + description: 'New group ID for all tickets', + }, + tags: { + type: 'string', + required: false, + visibility: 'user-only', + description: 'Comma-separated tags to add to all tickets', + }, + }, + + request: { + url: (params) => { + const ids = params.ticketIds.split(',').map((id) => id.trim()) + return buildZendeskUrl(params.subdomain, `/tickets/update_many?ids=${ids.join(',')}`) + }, + method: 'PUT', + headers: (params) => ({ + Authorization: `Bearer ${params.apiToken}`, + 'Content-Type': 'application/json', + }), + body: (params) => { + const ticket: any = {} + if (params.status) ticket.status = params.status + if (params.priority) ticket.priority = params.priority + if (params.assigneeId) ticket.assignee_id = params.assigneeId + if (params.groupId) ticket.group_id = params.groupId + if (params.tags) ticket.tags = params.tags.split(',').map((t) => t.trim()) + return { ticket } + }, + }, + + transformResponse: async (response: Response) => { + if (!response.ok) { + const data = await response.json() + handleZendeskError(data, response.status, 'update_tickets_bulk') + } + + const data = await response.json() + + return { + success: true, + output: { + jobStatus: data.job_status, + metadata: { + operation: 'update_tickets_bulk' as const, + jobId: data.job_status?.id, + }, + success: true, + }, + } + }, + + outputs: { + success: { type: 'boolean', description: 'Operation success status' }, + output: { + type: 'object', + description: 'Bulk update job status', + properties: { + jobStatus: { type: 'object', description: 'Job status object' }, + metadata: { type: 'object', description: 'Operation metadata' }, + success: { type: 'boolean', description: 'Operation success' }, + }, + }, + }, +} diff --git a/apps/sim/tools/zendesk/update_user.ts b/apps/sim/tools/zendesk/update_user.ts new file mode 100644 index 0000000000..12acd62b2c --- /dev/null +++ b/apps/sim/tools/zendesk/update_user.ts @@ -0,0 +1,173 @@ +import { createLogger } from '@/lib/logs/console/logger' +import type { ToolConfig } from '@/tools/types' +import { buildZendeskUrl, handleZendeskError } from './types' + +const logger = createLogger('ZendeskUpdateUser') + +export interface ZendeskUpdateUserParams { + apiToken: string + subdomain: string + userId: string + name?: string + email?: string + role?: string + phone?: string + organizationId?: string + verified?: string + tags?: string + customFields?: string +} + +export interface ZendeskUpdateUserResponse { + success: boolean + output: { + user: any + metadata: { + operation: 'update_user' + userId: string + } + success: boolean + } +} + +export const zendeskUpdateUserTool: ToolConfig = + { + id: 'zendesk_update_user', + name: 'Update User in Zendesk', + description: 'Update an existing user in Zendesk', + version: '1.0.0', + + params: { + apiToken: { + type: 'string', + required: true, + visibility: 'hidden', + description: 'Zendesk API token', + }, + subdomain: { + type: 'string', + required: true, + visibility: 'user-only', + description: 'Your Zendesk subdomain', + }, + userId: { + type: 'string', + required: true, + visibility: 'user-only', + description: 'User ID to update', + }, + name: { + type: 'string', + required: false, + visibility: 'user-only', + description: 'New user name', + }, + email: { + type: 'string', + required: false, + visibility: 'user-only', + description: 'New user email', + }, + role: { + type: 'string', + required: false, + visibility: 'user-only', + description: 'User role (end-user, agent, admin)', + }, + phone: { + type: 'string', + required: false, + visibility: 'user-only', + description: 'User phone number', + }, + organizationId: { + type: 'string', + required: false, + visibility: 'user-only', + description: 'Organization ID', + }, + verified: { + type: 'string', + required: false, + visibility: 'user-only', + description: 'Set to "true" to mark user as verified', + }, + tags: { + type: 'string', + required: false, + visibility: 'user-only', + description: 'Comma-separated tags', + }, + customFields: { + type: 'string', + required: false, + visibility: 'user-only', + description: 'Custom fields as JSON object', + }, + }, + + request: { + url: (params) => buildZendeskUrl(params.subdomain, `/users/${params.userId}`), + method: 'PUT', + headers: (params) => ({ + Authorization: `Bearer ${params.apiToken}`, + 'Content-Type': 'application/json', + }), + body: (params) => { + const user: any = {} + + if (params.name) user.name = params.name + if (params.email) user.email = params.email + if (params.role) user.role = params.role + if (params.phone) user.phone = params.phone + if (params.organizationId) user.organization_id = params.organizationId + if (params.verified) user.verified = params.verified === 'true' + if (params.tags) user.tags = params.tags.split(',').map((t) => t.trim()) + + if (params.customFields) { + try { + const customFields = JSON.parse(params.customFields) + user.user_fields = customFields + } catch (error) { + logger.warn('Failed to parse custom fields', { error }) + } + } + + return { user } + }, + }, + + transformResponse: async (response: Response) => { + if (!response.ok) { + const data = await response.json() + handleZendeskError(data, response.status, 'update_user') + } + + const data = await response.json() + + return { + success: true, + output: { + user: data.user, + metadata: { + operation: 'update_user' as const, + userId: data.user?.id, + }, + success: true, + }, + } + }, + + outputs: { + success: { type: 'boolean', description: 'Operation success status' }, + output: { + type: 'object', + description: 'Updated user data', + properties: { + user: { type: 'object', description: 'Updated user object' }, + metadata: { type: 'object', description: 'Operation metadata' }, + success: { type: 'boolean', description: 'Operation success' }, + }, + }, + }, + } diff --git a/apps/sim/tools/zendesk/update_users_bulk.ts b/apps/sim/tools/zendesk/update_users_bulk.ts new file mode 100644 index 0000000000..092ae162ed --- /dev/null +++ b/apps/sim/tools/zendesk/update_users_bulk.ts @@ -0,0 +1,106 @@ +import { createLogger } from '@/lib/logs/console/logger' +import type { ToolConfig } from '@/tools/types' +import { buildZendeskUrl, handleZendeskError } from './types' + +const logger = createLogger('ZendeskUpdateUsersBulk') + +export interface ZendeskUpdateUsersBulkParams { + apiToken: string + subdomain: string + users: string +} + +export interface ZendeskUpdateUsersBulkResponse { + success: boolean + output: { + jobStatus: any + metadata: { + operation: 'update_users_bulk' + jobId: string + } + success: boolean + } +} + +export const zendeskUpdateUsersBulkTool: ToolConfig< + ZendeskUpdateUsersBulkParams, + ZendeskUpdateUsersBulkResponse +> = { + id: 'zendesk_update_users_bulk', + name: 'Bulk Update Users in Zendesk', + description: 'Update multiple users in Zendesk using bulk update', + version: '1.0.0', + + params: { + apiToken: { + type: 'string', + required: true, + visibility: 'hidden', + description: 'Zendesk API token', + }, + subdomain: { + type: 'string', + required: true, + visibility: 'user-only', + description: 'Your Zendesk subdomain', + }, + users: { + type: 'string', + required: true, + visibility: 'user-only', + description: 'JSON array of user objects to update (must include id field)', + }, + }, + + request: { + url: (params) => buildZendeskUrl(params.subdomain, '/users/update_many'), + method: 'PUT', + headers: (params) => ({ + Authorization: `Bearer ${params.apiToken}`, + 'Content-Type': 'application/json', + }), + body: (params) => { + try { + const users = JSON.parse(params.users) + return { users } + } catch (error) { + logger.error('Failed to parse users array', { error }) + throw new Error('Invalid users JSON format') + } + }, + }, + + transformResponse: async (response: Response) => { + if (!response.ok) { + const data = await response.json() + handleZendeskError(data, response.status, 'update_users_bulk') + } + + const data = await response.json() + + return { + success: true, + output: { + jobStatus: data.job_status, + metadata: { + operation: 'update_users_bulk' as const, + jobId: data.job_status?.id, + }, + success: true, + }, + } + }, + + outputs: { + success: { type: 'boolean', description: 'Operation success status' }, + output: { + type: 'object', + description: 'Bulk update job status', + properties: { + jobStatus: { type: 'object', description: 'Job status object' }, + metadata: { type: 'object', description: 'Operation metadata' }, + success: { type: 'boolean', description: 'Operation success' }, + }, + }, + }, +} From e0af28e6b3b5ba08f68aede9b936dac6afa36bae Mon Sep 17 00:00:00 2001 From: waleed Date: Thu, 27 Nov 2025 16:23:24 -0800 Subject: [PATCH 2/3] finish zendesk and pylon --- apps/docs/content/docs/en/tools/intercom.mdx | 20 +-- apps/docs/content/docs/en/tools/mailchimp.mdx | 82 ++++++------- apps/docs/content/docs/en/tools/zendesk.mdx | 53 ++++---- .../panel/components/editor/editor.tsx | 2 +- apps/sim/blocks/blocks/intercom.ts | 15 +-- apps/sim/blocks/blocks/mailchimp.ts | 31 +++-- apps/sim/blocks/blocks/zendesk.ts | 29 +++-- apps/sim/tools/intercom/create_company.ts | 1 + apps/sim/tools/intercom/get_company.ts | 1 + apps/sim/tools/intercom/get_contact.ts | 1 + apps/sim/tools/intercom/get_conversation.ts | 1 + apps/sim/tools/intercom/get_ticket.ts | 1 + apps/sim/tools/intercom/index.ts | 1 - apps/sim/tools/intercom/list_companies.ts | 3 +- apps/sim/tools/intercom/list_contacts.ts | 1 + apps/sim/tools/intercom/list_conversations.ts | 1 + apps/sim/tools/intercom/list_tickets.ts | 110 ----------------- apps/sim/tools/intercom/search_contacts.ts | 1 + .../tools/intercom/search_conversations.ts | 1 + apps/sim/tools/mailchimp/add_member.ts | 8 +- apps/sim/tools/mailchimp/add_member_tags.ts | 11 +- .../tools/mailchimp/add_or_update_member.ts | 16 +-- apps/sim/tools/mailchimp/archive_member.ts | 8 +- apps/sim/tools/mailchimp/create_audience.ts | 10 +- .../tools/mailchimp/create_batch_operation.ts | 3 +- apps/sim/tools/mailchimp/create_campaign.ts | 7 +- apps/sim/tools/mailchimp/create_segment.ts | 2 +- apps/sim/tools/mailchimp/delete_member.ts | 8 +- apps/sim/tools/mailchimp/get_member.ts | 8 +- apps/sim/tools/mailchimp/get_member_tags.ts | 8 +- .../sim/tools/mailchimp/remove_member_tags.ts | 11 +- .../tools/mailchimp/remove_segment_member.ts | 8 +- apps/sim/tools/mailchimp/schedule_campaign.ts | 2 +- apps/sim/tools/mailchimp/unarchive_member.ts | 12 +- apps/sim/tools/mailchimp/update_audience.ts | 4 +- apps/sim/tools/mailchimp/update_campaign.ts | 4 +- apps/sim/tools/mailchimp/update_member.ts | 16 +-- apps/sim/tools/mailchimp/update_segment.ts | 2 +- apps/sim/tools/registry.ts | 4 - .../zendesk/autocomplete_organizations.ts | 19 ++- apps/sim/tools/zendesk/create_organization.ts | 19 ++- .../zendesk/create_organizations_bulk.ts | 19 ++- apps/sim/tools/zendesk/create_ticket.ts | 20 ++- apps/sim/tools/zendesk/create_tickets_bulk.ts | 19 ++- apps/sim/tools/zendesk/create_user.ts | 29 +++-- apps/sim/tools/zendesk/create_users_bulk.ts | 19 ++- apps/sim/tools/zendesk/delete_organization.ts | 19 ++- apps/sim/tools/zendesk/delete_ticket.ts | 20 ++- apps/sim/tools/zendesk/delete_user.ts | 19 ++- apps/sim/tools/zendesk/export_search.ts | 116 ------------------ apps/sim/tools/zendesk/get_current_user.ts | 19 ++- apps/sim/tools/zendesk/get_organization.ts | 19 ++- apps/sim/tools/zendesk/get_organizations.ts | 19 ++- apps/sim/tools/zendesk/get_ticket.ts | 20 ++- apps/sim/tools/zendesk/get_tickets.ts | 20 ++- apps/sim/tools/zendesk/get_user.ts | 19 ++- apps/sim/tools/zendesk/get_users.ts | 19 ++- apps/sim/tools/zendesk/index.ts | 6 - apps/sim/tools/zendesk/merge_tickets.ts | 19 ++- apps/sim/tools/zendesk/search.ts | 19 ++- apps/sim/tools/zendesk/search_count.ts | 19 ++- apps/sim/tools/zendesk/search_users.ts | 19 ++- apps/sim/tools/zendesk/types.ts | 4 +- apps/sim/tools/zendesk/update_organization.ts | 19 ++- apps/sim/tools/zendesk/update_ticket.ts | 20 ++- apps/sim/tools/zendesk/update_tickets_bulk.ts | 19 ++- apps/sim/tools/zendesk/update_user.ts | 25 ++-- apps/sim/tools/zendesk/update_users_bulk.ts | 19 ++- 68 files changed, 607 insertions(+), 541 deletions(-) delete mode 100644 apps/sim/tools/intercom/list_tickets.ts delete mode 100644 apps/sim/tools/zendesk/export_search.ts diff --git a/apps/docs/content/docs/en/tools/intercom.mdx b/apps/docs/content/docs/en/tools/intercom.mdx index 68c1220d21..75b42745dd 100644 --- a/apps/docs/content/docs/en/tools/intercom.mdx +++ b/apps/docs/content/docs/en/tools/intercom.mdx @@ -12,7 +12,7 @@ import { BlockInfoCard } from "@/components/ui/block-info-card" ## Usage Instructions -Integrate Intercom into the workflow. Can create, get, update, list, search, and delete contacts; create, get, and list companies; get, list, reply, and search conversations; create, get, and list tickets; and create messages. +Integrate Intercom into the workflow. Can create, get, update, list, search, and delete contacts; create, get, and list companies; get, list, reply, and search conversations; create and get tickets; and create messages. @@ -312,24 +312,6 @@ Retrieve a single ticket by ID from Intercom | `success` | boolean | Operation success status | | `output` | object | Ticket data | -### `intercom_list_tickets` - -List all tickets from Intercom with pagination support - -#### Input - -| Parameter | Type | Required | Description | -| --------- | ---- | -------- | ----------- | -| `per_page` | number | No | Number of results per page \(max: 150\) | -| `starting_after` | string | No | Cursor for pagination | - -#### Output - -| Parameter | Type | Description | -| --------- | ---- | ----------- | -| `success` | boolean | Operation success status | -| `output` | object | List of tickets | - ### `intercom_create_message` Create and send a new admin-initiated message in Intercom diff --git a/apps/docs/content/docs/en/tools/mailchimp.mdx b/apps/docs/content/docs/en/tools/mailchimp.mdx index 6876bb1d95..b999e49703 100644 --- a/apps/docs/content/docs/en/tools/mailchimp.mdx +++ b/apps/docs/content/docs/en/tools/mailchimp.mdx @@ -102,10 +102,10 @@ Create a new audience (list) in Mailchimp | --------- | ---- | -------- | ----------- | | `apiKey` | string | Yes | Mailchimp API key with server prefix | | `audienceName` | string | Yes | The name of the list | -| `contact` | string | Yes | Contact information as JSON \(e.g., \{"company": "Acme Inc", "address1": "123 Main St", "city": "Atlanta", "state": "GA", "zip": "30308", "country": "US"\}\) | -| `permissionReminder` | string | Yes | Permission reminder text \(why subscribers are on your list\) | -| `campaignDefaults` | string | Yes | Default campaign settings as JSON \(e.g., \{"from_name": "John", "from_email": "john@example.com", "subject": "Newsletter", "language": "en"\}\) | -| `emailTypeOption` | string | Yes | Whether the list supports multiple formats \(true/false\) | +| `contact` | string | Yes | JSON object of contact information | +| `permissionReminder` | string | Yes | Permission reminder text | +| `campaignDefaults` | string | Yes | JSON object of default campaign settings | +| `emailTypeOption` | string | Yes | Support multiple email formats | #### Output @@ -126,8 +126,8 @@ Update an existing audience (list) in Mailchimp | `listId` | string | Yes | The unique ID for the list | | `audienceName` | string | No | The name of the list | | `permissionReminder` | string | No | Permission reminder text | -| `campaignDefaults` | string | No | Default campaign settings as JSON | -| `emailTypeOption` | string | No | Whether the list supports multiple formats \(true/false\) | +| `campaignDefaults` | string | No | JSON object of default campaign settings | +| `emailTypeOption` | string | No | Support multiple email formats | #### Output @@ -185,7 +185,7 @@ Retrieve details of a specific member from a Mailchimp audience | --------- | ---- | -------- | ----------- | | `apiKey` | string | Yes | Mailchimp API key with server prefix | | `listId` | string | Yes | The unique ID for the list | -| `subscriberHash` | string | Yes | The MD5 hash of the lowercase version of the list member's email address | +| `subscriberEmail` | string | Yes | Member email address or MD5 hash | #### Output @@ -204,10 +204,10 @@ Add a new member to a Mailchimp audience | --------- | ---- | -------- | ----------- | | `apiKey` | string | Yes | Mailchimp API key with server prefix | | `listId` | string | Yes | The unique ID for the list | -| `emailAddress` | string | Yes | Email address for the member | -| `status` | string | Yes | Subscriber status \(subscribed, unsubscribed, cleaned, pending\) | -| `mergeFields` | string | No | Merge fields as JSON object \(e.g., \{"FNAME": "John", "LNAME": "Doe"\}\) | -| `interests` | string | No | Interests as JSON object \(e.g., \{"interest_id": true\}\) | +| `emailAddress` | string | Yes | Member email address | +| `status` | string | Yes | Subscriber status | +| `mergeFields` | string | No | JSON object of merge fields | +| `interests` | string | No | JSON object of interests | #### Output @@ -226,11 +226,11 @@ Add a new member or update an existing member in a Mailchimp audience (upsert) | --------- | ---- | -------- | ----------- | | `apiKey` | string | Yes | Mailchimp API key with server prefix | | `listId` | string | Yes | The unique ID for the list | -| `subscriberHash` | string | Yes | The MD5 hash of the lowercase version of the list member's email address | -| `emailAddress` | string | Yes | Email address for the member | -| `statusIfNew` | string | Yes | Subscriber status if new member \(subscribed, unsubscribed, cleaned, pending\) | -| `mergeFields` | string | No | Merge fields as JSON object \(e.g., \{"FNAME": "John", "LNAME": "Doe"\}\) | -| `interests` | string | No | Interests as JSON object \(e.g., \{"interest_id": true\}\) | +| `subscriberEmail` | string | Yes | Member email address or MD5 hash | +| `emailAddress` | string | Yes | Member email address | +| `statusIfNew` | string | Yes | Subscriber status if new member | +| `mergeFields` | string | No | JSON object of merge fields | +| `interests` | string | No | JSON object of interests | #### Output @@ -249,11 +249,11 @@ Update an existing member in a Mailchimp audience | --------- | ---- | -------- | ----------- | | `apiKey` | string | Yes | Mailchimp API key with server prefix | | `listId` | string | Yes | The unique ID for the list | -| `subscriberHash` | string | Yes | The MD5 hash of the lowercase version of the list member's email address | -| `emailAddress` | string | No | Email address for the member | -| `status` | string | No | Subscriber status \(subscribed, unsubscribed, cleaned, pending\) | -| `mergeFields` | string | No | Merge fields as JSON object | -| `interests` | string | No | Interests as JSON object | +| `subscriberEmail` | string | Yes | Member email address or MD5 hash | +| `emailAddress` | string | No | Member email address | +| `status` | string | No | Subscriber status | +| `mergeFields` | string | No | JSON object of merge fields | +| `interests` | string | No | JSON object of interests | #### Output @@ -272,7 +272,7 @@ Delete a member from a Mailchimp audience | --------- | ---- | -------- | ----------- | | `apiKey` | string | Yes | Mailchimp API key with server prefix | | `listId` | string | Yes | The unique ID for the list | -| `subscriberHash` | string | Yes | The MD5 hash of the lowercase version of the list member's email address | +| `subscriberEmail` | string | Yes | Member email address or MD5 hash | #### Output @@ -291,7 +291,7 @@ Permanently archive (delete) a member from a Mailchimp audience | --------- | ---- | -------- | ----------- | | `apiKey` | string | Yes | Mailchimp API key with server prefix | | `listId` | string | Yes | The unique ID for the list | -| `subscriberHash` | string | Yes | The MD5 hash of the lowercase version of the list member's email address | +| `subscriberEmail` | string | Yes | Member email address or MD5 hash | #### Output @@ -310,9 +310,9 @@ Restore an archived member to a Mailchimp audience | --------- | ---- | -------- | ----------- | | `apiKey` | string | Yes | Mailchimp API key with server prefix | | `listId` | string | Yes | The unique ID for the list | -| `subscriberHash` | string | Yes | The MD5 hash of the lowercase version of the list member's email address | -| `emailAddress` | string | Yes | Email address for the member | -| `status` | string | Yes | Subscriber status \(subscribed, unsubscribed, cleaned, pending\) | +| `subscriberEmail` | string | Yes | Member email address or MD5 hash | +| `emailAddress` | string | Yes | Member email address | +| `status` | string | Yes | Subscriber status | #### Output @@ -369,9 +369,9 @@ Create a new campaign in Mailchimp | Parameter | Type | Required | Description | | --------- | ---- | -------- | ----------- | | `apiKey` | string | Yes | Mailchimp API key with server prefix | -| `campaignType` | string | Yes | Campaign type \(regular, plaintext, absplit, rss, variate\) | -| `campaignSettings` | string | Yes | Campaign settings as JSON \(e.g., \{"subject_line": "Test", "from_name": "John", "reply_to": "john@example.com"\}\) | -| `recipients` | string | No | Recipients as JSON \(e.g., \{"list_id": "abc123"\}\) | +| `campaignType` | string | Yes | Campaign type | +| `campaignSettings` | string | Yes | JSON object of campaign settings | +| `recipients` | string | No | JSON object of recipients | #### Output @@ -390,8 +390,8 @@ Update an existing campaign in Mailchimp | --------- | ---- | -------- | ----------- | | `apiKey` | string | Yes | Mailchimp API key with server prefix | | `campaignId` | string | Yes | The unique ID for the campaign | -| `campaignSettings` | string | No | Campaign settings as JSON | -| `recipients` | string | No | Recipients as JSON | +| `campaignSettings` | string | No | JSON object of campaign settings | +| `recipients` | string | No | JSON object of recipients | #### Output @@ -446,7 +446,7 @@ Schedule a Mailchimp campaign to be sent at a specific time | --------- | ---- | -------- | ----------- | | `apiKey` | string | Yes | Mailchimp API key with server prefix | | `campaignId` | string | Yes | The unique ID for the campaign to schedule | -| `scheduleTime` | string | Yes | The date and time in ISO 8601 format \(e.g., 2024-01-01T12:00:00+00:00\) | +| `scheduleTime` | string | Yes | ISO 8601 format date and time | #### Output @@ -804,7 +804,7 @@ Create a new segment in a Mailchimp audience | `apiKey` | string | Yes | Mailchimp API key with server prefix | | `listId` | string | Yes | The unique ID for the list | | `segmentName` | string | Yes | The name of the segment | -| `segmentOptions` | string | No | Segment options as JSON \(e.g., \{"match": "any", "conditions": \[\]\}\) | +| `segmentOptions` | string | No | JSON object of segment options | #### Output @@ -825,7 +825,7 @@ Update an existing segment in a Mailchimp audience | `listId` | string | Yes | The unique ID for the list | | `segmentId` | string | Yes | The unique ID for the segment | | `segmentName` | string | No | The name of the segment | -| `segmentOptions` | string | No | Segment options as JSON | +| `segmentOptions` | string | No | JSON object of segment options | #### Output @@ -905,7 +905,7 @@ Remove a member from a specific segment in a Mailchimp audience | `apiKey` | string | Yes | Mailchimp API key with server prefix | | `listId` | string | Yes | The unique ID for the list | | `segmentId` | string | Yes | The unique ID for the segment | -| `subscriberHash` | string | Yes | The MD5 hash of the lowercase version of the list member's email address | +| `subscriberEmail` | string | Yes | Member email address or MD5 hash | #### Output @@ -924,7 +924,7 @@ Retrieve tags associated with a member in a Mailchimp audience | --------- | ---- | -------- | ----------- | | `apiKey` | string | Yes | Mailchimp API key with server prefix | | `listId` | string | Yes | The unique ID for the list | -| `subscriberHash` | string | Yes | The MD5 hash of the lowercase version of the list member's email address | +| `subscriberEmail` | string | Yes | Member email address or MD5 hash | #### Output @@ -943,8 +943,8 @@ Add tags to a member in a Mailchimp audience | --------- | ---- | -------- | ----------- | | `apiKey` | string | Yes | Mailchimp API key with server prefix | | `listId` | string | Yes | The unique ID for the list | -| `subscriberHash` | string | Yes | The MD5 hash of the lowercase version of the list member's email address | -| `tags` | string | Yes | Tags as JSON array \(e.g., \[\{"name": "tag1", "status": "active"\}, \{"name": "tag2", "status": "active"\}\]\) | +| `subscriberEmail` | string | Yes | Member email address or MD5 hash | +| `tags` | string | Yes | JSON array of tags | #### Output @@ -963,8 +963,8 @@ Remove tags from a member in a Mailchimp audience | --------- | ---- | -------- | ----------- | | `apiKey` | string | Yes | Mailchimp API key with server prefix | | `listId` | string | Yes | The unique ID for the list | -| `subscriberHash` | string | Yes | The MD5 hash of the lowercase version of the list member's email address | -| `tags` | string | Yes | Tags as JSON array with inactive status \(e.g., \[\{"name": "tag1", "status": "inactive"\}, \{"name": "tag2", "status": "inactive"\}\]\) | +| `subscriberEmail` | string | Yes | Member email address or MD5 hash | +| `tags` | string | Yes | JSON array of tags with inactive status | #### Output @@ -1446,7 +1446,7 @@ Create a new batch operation in Mailchimp | Parameter | Type | Required | Description | | --------- | ---- | -------- | ----------- | | `apiKey` | string | Yes | Mailchimp API key with server prefix | -| `operations` | string | Yes | Operations as JSON array \(e.g., \[\{"method": "POST", "path": "/lists", "body": "\{\\"name\\": \\"Test\\"\}"\}\]\) | +| `operations` | string | Yes | JSON array of operations | #### Output diff --git a/apps/docs/content/docs/en/tools/zendesk.mdx b/apps/docs/content/docs/en/tools/zendesk.mdx index a83a771175..e458539b7e 100644 --- a/apps/docs/content/docs/en/tools/zendesk.mdx +++ b/apps/docs/content/docs/en/tools/zendesk.mdx @@ -41,7 +41,7 @@ Whether you need to power support chatbots, automate escalations, sync user data ## Usage Instructions -Integrate Zendesk into the workflow. Can get tickets, get ticket, create ticket, create tickets bulk, update ticket, update tickets bulk, delete ticket, merge tickets, get users, get user, get current user, search users, create user, create users bulk, update user, update users bulk, delete user, get organizations, get organization, autocomplete organizations, create organization, create organizations bulk, update organization, delete organization, search, search count, export search. +Integrate Zendesk into the workflow. Can get tickets, get ticket, create ticket, create tickets bulk, update ticket, update tickets bulk, delete ticket, merge tickets, get users, get user, get current user, search users, create user, create users bulk, update user, update users bulk, delete user, get organizations, get organization, autocomplete organizations, create organization, create organizations bulk, update organization, delete organization, search, search count. @@ -55,6 +55,7 @@ Retrieve a list of tickets from Zendesk with optional filtering | Parameter | Type | Required | Description | | --------- | ---- | -------- | ----------- | +| `email` | string | Yes | Your Zendesk email address | | `apiToken` | string | Yes | Zendesk API token | | `subdomain` | string | Yes | Your Zendesk subdomain \(e.g., "mycompany" for mycompany.zendesk.com\) | | `status` | string | No | Filter by status \(new, open, pending, hold, solved, closed\) | @@ -82,6 +83,7 @@ Get a single ticket by ID from Zendesk | Parameter | Type | Required | Description | | --------- | ---- | -------- | ----------- | +| `email` | string | Yes | Your Zendesk email address | | `apiToken` | string | Yes | Zendesk API token | | `subdomain` | string | Yes | Your Zendesk subdomain | | `ticketId` | string | Yes | Ticket ID to retrieve | @@ -101,6 +103,7 @@ Create a new ticket in Zendesk with support for custom fields | Parameter | Type | Required | Description | | --------- | ---- | -------- | ----------- | +| `email` | string | Yes | Your Zendesk email address | | `apiToken` | string | Yes | Zendesk API token | | `subdomain` | string | Yes | Your Zendesk subdomain | | `subject` | string | No | Ticket subject \(optional - will be auto-generated if not provided\) | @@ -126,6 +129,7 @@ Create multiple tickets in Zendesk at once (max 100) | Parameter | Type | Required | Description | | --------- | ---- | -------- | ----------- | +| `email` | string | Yes | Your Zendesk email address | | `apiToken` | string | Yes | Zendesk API token | | `subdomain` | string | Yes | Your Zendesk subdomain | | `tickets` | string | Yes | JSON array of ticket objects to create \(max 100\). Each ticket should have subject and comment properties. | @@ -145,6 +149,7 @@ Update an existing ticket in Zendesk with support for custom fields | Parameter | Type | Required | Description | | --------- | ---- | -------- | ----------- | +| `email` | string | Yes | Your Zendesk email address | | `apiToken` | string | Yes | Zendesk API token | | `subdomain` | string | Yes | Your Zendesk subdomain | | `ticketId` | string | Yes | Ticket ID to update | @@ -173,6 +178,7 @@ Update multiple tickets in Zendesk at once (max 100) | Parameter | Type | Required | Description | | --------- | ---- | -------- | ----------- | +| `email` | string | Yes | Your Zendesk email address | | `apiToken` | string | Yes | Zendesk API token | | `subdomain` | string | Yes | Your Zendesk subdomain | | `ticketIds` | string | Yes | Comma-separated ticket IDs to update \(max 100\) | @@ -197,6 +203,7 @@ Delete a ticket from Zendesk | Parameter | Type | Required | Description | | --------- | ---- | -------- | ----------- | +| `email` | string | Yes | Your Zendesk email address | | `apiToken` | string | Yes | Zendesk API token | | `subdomain` | string | Yes | Your Zendesk subdomain | | `ticketId` | string | Yes | Ticket ID to delete | @@ -216,6 +223,7 @@ Merge multiple tickets into a target ticket | Parameter | Type | Required | Description | | --------- | ---- | -------- | ----------- | +| `email` | string | Yes | Your Zendesk email address | | `apiToken` | string | Yes | Zendesk API token | | `subdomain` | string | Yes | Your Zendesk subdomain | | `targetTicketId` | string | Yes | Target ticket ID \(tickets will be merged into this one\) | @@ -237,6 +245,7 @@ Retrieve a list of users from Zendesk with optional filtering | Parameter | Type | Required | Description | | --------- | ---- | -------- | ----------- | +| `email` | string | Yes | Your Zendesk email address | | `apiToken` | string | Yes | Zendesk API token | | `subdomain` | string | Yes | Your Zendesk subdomain \(e.g., "mycompany" for mycompany.zendesk.com\) | | `role` | string | No | Filter by role \(end-user, agent, admin\) | @@ -259,6 +268,7 @@ Get a single user by ID from Zendesk | Parameter | Type | Required | Description | | --------- | ---- | -------- | ----------- | +| `email` | string | Yes | Your Zendesk email address | | `apiToken` | string | Yes | Zendesk API token | | `subdomain` | string | Yes | Your Zendesk subdomain | | `userId` | string | Yes | User ID to retrieve | @@ -278,6 +288,7 @@ Get the currently authenticated user from Zendesk | Parameter | Type | Required | Description | | --------- | ---- | -------- | ----------- | +| `email` | string | Yes | Your Zendesk email address | | `apiToken` | string | Yes | Zendesk API token | | `subdomain` | string | Yes | Your Zendesk subdomain | @@ -296,6 +307,7 @@ Search for users in Zendesk using a query string | Parameter | Type | Required | Description | | --------- | ---- | -------- | ----------- | +| `email` | string | Yes | Your Zendesk email address | | `apiToken` | string | Yes | Zendesk API token | | `subdomain` | string | Yes | Your Zendesk subdomain | | `query` | string | No | Search query string | @@ -318,10 +330,11 @@ Create a new user in Zendesk | Parameter | Type | Required | Description | | --------- | ---- | -------- | ----------- | +| `email` | string | Yes | Your Zendesk email address | | `apiToken` | string | Yes | Zendesk API token | | `subdomain` | string | Yes | Your Zendesk subdomain | -| `name` | string | No | User name | -| `email` | string | No | User email | +| `name` | string | Yes | User name | +| `userEmail` | string | No | User email | | `role` | string | No | User role \(end-user, agent, admin\) | | `phone` | string | No | User phone number | | `organizationId` | string | No | Organization ID | @@ -344,6 +357,7 @@ Create multiple users in Zendesk using bulk import | Parameter | Type | Required | Description | | --------- | ---- | -------- | ----------- | +| `email` | string | Yes | Your Zendesk email address | | `apiToken` | string | Yes | Zendesk API token | | `subdomain` | string | Yes | Your Zendesk subdomain | | `users` | string | Yes | JSON array of user objects to create | @@ -363,11 +377,12 @@ Update an existing user in Zendesk | Parameter | Type | Required | Description | | --------- | ---- | -------- | ----------- | +| `email` | string | Yes | Your Zendesk email address | | `apiToken` | string | Yes | Zendesk API token | | `subdomain` | string | Yes | Your Zendesk subdomain | | `userId` | string | Yes | User ID to update | | `name` | string | No | New user name | -| `email` | string | No | New user email | +| `userEmail` | string | No | New user email | | `role` | string | No | User role \(end-user, agent, admin\) | | `phone` | string | No | User phone number | | `organizationId` | string | No | Organization ID | @@ -390,6 +405,7 @@ Update multiple users in Zendesk using bulk update | Parameter | Type | Required | Description | | --------- | ---- | -------- | ----------- | +| `email` | string | Yes | Your Zendesk email address | | `apiToken` | string | Yes | Zendesk API token | | `subdomain` | string | Yes | Your Zendesk subdomain | | `users` | string | Yes | JSON array of user objects to update \(must include id field\) | @@ -409,6 +425,7 @@ Delete a user from Zendesk | Parameter | Type | Required | Description | | --------- | ---- | -------- | ----------- | +| `email` | string | Yes | Your Zendesk email address | | `apiToken` | string | Yes | Zendesk API token | | `subdomain` | string | Yes | Your Zendesk subdomain | | `userId` | string | Yes | User ID to delete | @@ -428,6 +445,7 @@ Retrieve a list of organizations from Zendesk | Parameter | Type | Required | Description | | --------- | ---- | -------- | ----------- | +| `email` | string | Yes | Your Zendesk email address | | `apiToken` | string | Yes | Zendesk API token | | `subdomain` | string | Yes | Your Zendesk subdomain \(e.g., "mycompany" for mycompany.zendesk.com\) | | `perPage` | string | No | Results per page \(default: 100, max: 100\) | @@ -448,6 +466,7 @@ Get a single organization by ID from Zendesk | Parameter | Type | Required | Description | | --------- | ---- | -------- | ----------- | +| `email` | string | Yes | Your Zendesk email address | | `apiToken` | string | Yes | Zendesk API token | | `subdomain` | string | Yes | Your Zendesk subdomain | | `organizationId` | string | Yes | Organization ID to retrieve | @@ -467,6 +486,7 @@ Autocomplete organizations in Zendesk by name prefix (for name matching/autocomp | Parameter | Type | Required | Description | | --------- | ---- | -------- | ----------- | +| `email` | string | Yes | Your Zendesk email address | | `apiToken` | string | Yes | Zendesk API token | | `subdomain` | string | Yes | Your Zendesk subdomain | | `name` | string | Yes | Organization name to search for | @@ -488,6 +508,7 @@ Create a new organization in Zendesk | Parameter | Type | Required | Description | | --------- | ---- | -------- | ----------- | +| `email` | string | Yes | Your Zendesk email address | | `apiToken` | string | Yes | Zendesk API token | | `subdomain` | string | Yes | Your Zendesk subdomain | | `name` | string | Yes | Organization name | @@ -512,6 +533,7 @@ Create multiple organizations in Zendesk using bulk import | Parameter | Type | Required | Description | | --------- | ---- | -------- | ----------- | +| `email` | string | Yes | Your Zendesk email address | | `apiToken` | string | Yes | Zendesk API token | | `subdomain` | string | Yes | Your Zendesk subdomain | | `organizations` | string | Yes | JSON array of organization objects to create | @@ -531,6 +553,7 @@ Update an existing organization in Zendesk | Parameter | Type | Required | Description | | --------- | ---- | -------- | ----------- | +| `email` | string | Yes | Your Zendesk email address | | `apiToken` | string | Yes | Zendesk API token | | `subdomain` | string | Yes | Your Zendesk subdomain | | `organizationId` | string | Yes | Organization ID to update | @@ -556,6 +579,7 @@ Delete an organization from Zendesk | Parameter | Type | Required | Description | | --------- | ---- | -------- | ----------- | +| `email` | string | Yes | Your Zendesk email address | | `apiToken` | string | Yes | Zendesk API token | | `subdomain` | string | Yes | Your Zendesk subdomain | | `organizationId` | string | Yes | Organization ID to delete | @@ -575,6 +599,7 @@ Unified search across tickets, users, and organizations in Zendesk | Parameter | Type | Required | Description | | --------- | ---- | -------- | ----------- | +| `email` | string | Yes | Your Zendesk email address | | `apiToken` | string | Yes | Zendesk API token | | `subdomain` | string | Yes | Your Zendesk subdomain | | `query` | string | Yes | Search query string | @@ -598,6 +623,7 @@ Count the number of search results matching a query in Zendesk | Parameter | Type | Required | Description | | --------- | ---- | -------- | ----------- | +| `email` | string | Yes | Your Zendesk email address | | `apiToken` | string | Yes | Zendesk API token | | `subdomain` | string | Yes | Your Zendesk subdomain | | `query` | string | Yes | Search query string | @@ -609,25 +635,6 @@ Count the number of search results matching a query in Zendesk | `success` | boolean | Operation success status | | `output` | object | Search count result | -### `zendesk_export_search` - -Export search results from Zendesk (supports larger result sets) - -#### Input - -| Parameter | Type | Required | Description | -| --------- | ---- | -------- | ----------- | -| `apiToken` | string | Yes | Zendesk API token | -| `subdomain` | string | Yes | Your Zendesk subdomain | -| `query` | string | Yes | Search query string | - -#### Output - -| Parameter | Type | Description | -| --------- | ---- | ----------- | -| `success` | boolean | Operation success status | -| `output` | object | Exported search results | - ## Notes diff --git a/apps/sim/app/workspace/[workspaceId]/w/[workflowId]/components/panel/components/editor/editor.tsx b/apps/sim/app/workspace/[workspaceId]/w/[workflowId]/components/panel/components/editor/editor.tsx index 9b474d8022..bac04d13c1 100644 --- a/apps/sim/app/workspace/[workspaceId]/w/[workflowId]/components/panel/components/editor/editor.tsx +++ b/apps/sim/app/workspace/[workspaceId]/w/[workflowId]/components/panel/components/editor/editor.tsx @@ -353,7 +353,7 @@ export function Editor() { blockId={currentBlockId} config={subBlock} isPreview={false} - subBlockValues={undefined} + subBlockValues={subBlockState} disabled={!userPermissions.canEdit} fieldDiffStatus={undefined} allowExpandInPreview={false} diff --git a/apps/sim/blocks/blocks/intercom.ts b/apps/sim/blocks/blocks/intercom.ts index d4f5efaf29..5960d1b7c7 100644 --- a/apps/sim/blocks/blocks/intercom.ts +++ b/apps/sim/blocks/blocks/intercom.ts @@ -7,7 +7,7 @@ export const IntercomBlock: BlockConfig = { name: 'Intercom', description: 'Manage contacts, companies, conversations, tickets, and messages in Intercom', longDescription: - 'Integrate Intercom into the workflow. Can create, get, update, list, search, and delete contacts; create, get, and list companies; get, list, reply, and search conversations; create, get, and list tickets; and create messages.', + 'Integrate Intercom into the workflow. Can create, get, update, list, search, and delete contacts; create, get, and list companies; get, list, reply, and search conversations; create and get tickets; and create messages.', docsLink: 'https://docs.sim.ai/tools/intercom', authMode: AuthMode.ApiKey, category: 'tools', @@ -34,7 +34,6 @@ export const IntercomBlock: BlockConfig = { { label: 'Search Conversations', id: 'search_conversations' }, { label: 'Create Ticket', id: 'create_ticket' }, { label: 'Get Ticket', id: 'get_ticket' }, - { label: 'List Tickets', id: 'list_tickets' }, { label: 'Create Message', id: 'create_message' }, ], value: () => 'create_contact', @@ -455,7 +454,6 @@ export const IntercomBlock: BlockConfig = { 'list_companies', 'list_conversations', 'search_conversations', - 'list_tickets', ], }, }, @@ -466,13 +464,7 @@ export const IntercomBlock: BlockConfig = { placeholder: 'Cursor for pagination', condition: { field: 'operation', - value: [ - 'list_contacts', - 'search_contacts', - 'list_conversations', - 'search_conversations', - 'list_tickets', - ], + value: ['list_contacts', 'search_contacts', 'list_conversations', 'search_conversations'], }, }, { @@ -503,7 +495,6 @@ export const IntercomBlock: BlockConfig = { 'intercom_search_conversations', 'intercom_create_ticket', 'intercom_get_ticket', - 'intercom_list_tickets', 'intercom_create_message', ], config: { @@ -539,8 +530,6 @@ export const IntercomBlock: BlockConfig = { return 'intercom_create_ticket' case 'get_ticket': return 'intercom_get_ticket' - case 'list_tickets': - return 'intercom_list_tickets' case 'create_message': return 'intercom_create_message' default: diff --git a/apps/sim/blocks/blocks/mailchimp.ts b/apps/sim/blocks/blocks/mailchimp.ts index 381f14e3a2..dec15a6531 100644 --- a/apps/sim/blocks/blocks/mailchimp.ts +++ b/apps/sim/blocks/blocks/mailchimp.ts @@ -284,10 +284,10 @@ export const MailchimpBlock: BlockConfig = { }, // Member fields { - id: 'subscriberHash', - title: 'Subscriber Hash', + id: 'subscriberEmail', + title: 'Subscriber Email', type: 'short-input', - placeholder: 'MD5 hash of lowercase email', + placeholder: 'Email address or MD5 hash', required: { field: 'operation', value: [ @@ -299,6 +299,8 @@ export const MailchimpBlock: BlockConfig = { 'get_member_tags', 'add_member_tags', 'remove_member_tags', + 'add_or_update_member', + 'remove_segment_member', ], }, condition: { @@ -312,6 +314,8 @@ export const MailchimpBlock: BlockConfig = { 'get_member_tags', 'add_member_tags', 'remove_member_tags', + 'add_or_update_member', + 'remove_segment_member', ], }, }, @@ -322,11 +326,24 @@ export const MailchimpBlock: BlockConfig = { placeholder: 'Member email address', required: { field: 'operation', - value: ['add_member', 'add_or_update_member'], + value: [ + 'add_member', + 'add_or_update_member', + 'unarchive_member', + 'add_segment_member', + 'add_subscriber_to_automation', + ], }, condition: { field: 'operation', - value: ['add_member', 'add_or_update_member', 'update_member'], + value: [ + 'add_member', + 'add_or_update_member', + 'update_member', + 'unarchive_member', + 'add_segment_member', + 'add_subscriber_to_automation', + ], }, }, { @@ -342,11 +359,11 @@ export const MailchimpBlock: BlockConfig = { ], required: { field: 'operation', - value: ['add_member'], + value: ['add_member', 'unarchive_member'], }, condition: { field: 'operation', - value: ['get_members', 'add_member', 'update_member'], + value: ['get_members', 'add_member', 'update_member', 'unarchive_member'], }, }, { diff --git a/apps/sim/blocks/blocks/zendesk.ts b/apps/sim/blocks/blocks/zendesk.ts index ca727422b0..d0f956cc75 100644 --- a/apps/sim/blocks/blocks/zendesk.ts +++ b/apps/sim/blocks/blocks/zendesk.ts @@ -7,7 +7,7 @@ export const ZendeskBlock: BlockConfig = { name: 'Zendesk', description: 'Manage support tickets, users, and organizations in Zendesk', longDescription: - 'Integrate Zendesk into the workflow. Can get tickets, get ticket, create ticket, create tickets bulk, update ticket, update tickets bulk, delete ticket, merge tickets, get users, get user, get current user, search users, create user, create users bulk, update user, update users bulk, delete user, get organizations, get organization, autocomplete organizations, create organization, create organizations bulk, update organization, delete organization, search, search count, export search.', + 'Integrate Zendesk into the workflow. Can get tickets, get ticket, create ticket, create tickets bulk, update ticket, update tickets bulk, delete ticket, merge tickets, get users, get user, get current user, search users, create user, create users bulk, update user, update users bulk, delete user, get organizations, get organization, autocomplete organizations, create organization, create organizations bulk, update organization, delete organization, search, search count.', docsLink: 'https://docs.sim.ai/tools/zendesk', authMode: AuthMode.ApiKey, category: 'tools', @@ -45,10 +45,17 @@ export const ZendeskBlock: BlockConfig = { { label: 'Delete Organization', id: 'delete_organization' }, { label: 'Search', id: 'search' }, { label: 'Search Count', id: 'search_count' }, - { label: 'Export Search', id: 'export_search' }, ], value: () => 'get_tickets', }, + { + id: 'email', + title: 'Email', + type: 'short-input', + placeholder: 'Your Zendesk email address', + required: true, + description: 'The email address associated with your Zendesk account', + }, { id: 'apiToken', title: 'API Token', @@ -92,6 +99,10 @@ export const ZendeskBlock: BlockConfig = { title: 'Description', type: 'long-input', placeholder: 'Ticket description', + required: { + field: 'operation', + value: ['create_ticket'], + }, condition: { field: 'operation', value: ['create_ticket', 'update_ticket'], @@ -213,10 +224,14 @@ export const ZendeskBlock: BlockConfig = { }, }, { - id: 'userName', + id: 'name', title: 'Name', type: 'short-input', placeholder: 'User name', + required: { + field: 'operation', + value: ['create_user'], + }, condition: { field: 'operation', value: ['create_user', 'update_user'], @@ -299,11 +314,11 @@ export const ZendeskBlock: BlockConfig = { placeholder: 'Search query', required: { field: 'operation', - value: ['search', 'search_count', 'export_search'], + value: ['search', 'search_count'], }, condition: { field: 'operation', - value: ['search_users', 'search', 'search_count', 'export_search'], + value: ['search_users', 'search', 'search_count'], }, }, { @@ -400,7 +415,6 @@ export const ZendeskBlock: BlockConfig = { 'zendesk_delete_organization', 'zendesk_search', 'zendesk_search_count', - 'zendesk_export_search', ], config: { tool: (params) => { @@ -457,8 +471,6 @@ export const ZendeskBlock: BlockConfig = { return 'zendesk_search' case 'search_count': return 'zendesk_search_count' - case 'export_search': - return 'zendesk_export_search' default: throw new Error(`Unknown operation: ${params.operation}`) } @@ -487,6 +499,7 @@ export const ZendeskBlock: BlockConfig = { }, inputs: { operation: { type: 'string', description: 'Operation to perform' }, + email: { type: 'string', description: 'Zendesk email address' }, apiToken: { type: 'string', description: 'Zendesk API token' }, subdomain: { type: 'string', description: 'Zendesk subdomain' }, }, diff --git a/apps/sim/tools/intercom/create_company.ts b/apps/sim/tools/intercom/create_company.ts index db8c147292..0da0df49fa 100644 --- a/apps/sim/tools/intercom/create_company.ts +++ b/apps/sim/tools/intercom/create_company.ts @@ -99,6 +99,7 @@ export const intercomCreateCompanyTool: ToolConfig< method: 'POST', headers: (params) => ({ Authorization: `Bearer ${params.accessToken}`, + Accept: 'application/json', 'Content-Type': 'application/json', 'Intercom-Version': '2.14', }), diff --git a/apps/sim/tools/intercom/get_company.ts b/apps/sim/tools/intercom/get_company.ts index 5803cc46aa..1cce9c4354 100644 --- a/apps/sim/tools/intercom/get_company.ts +++ b/apps/sim/tools/intercom/get_company.ts @@ -49,6 +49,7 @@ export const intercomGetCompanyTool: ToolConfig< method: 'GET', headers: (params) => ({ Authorization: `Bearer ${params.accessToken}`, + Accept: 'application/json', 'Content-Type': 'application/json', 'Intercom-Version': '2.14', }), diff --git a/apps/sim/tools/intercom/get_contact.ts b/apps/sim/tools/intercom/get_contact.ts index 8b1c85f1da..19fd3f336d 100644 --- a/apps/sim/tools/intercom/get_contact.ts +++ b/apps/sim/tools/intercom/get_contact.ts @@ -49,6 +49,7 @@ export const intercomGetContactTool: ToolConfig< method: 'GET', headers: (params) => ({ Authorization: `Bearer ${params.accessToken}`, + Accept: 'application/json', 'Content-Type': 'application/json', 'Intercom-Version': '2.14', }), diff --git a/apps/sim/tools/intercom/get_conversation.ts b/apps/sim/tools/intercom/get_conversation.ts index ce81663f56..97289bdca8 100644 --- a/apps/sim/tools/intercom/get_conversation.ts +++ b/apps/sim/tools/intercom/get_conversation.ts @@ -62,6 +62,7 @@ export const intercomGetConversationTool: ToolConfig< method: 'GET', headers: (params) => ({ Authorization: `Bearer ${params.accessToken}`, + Accept: 'application/json', 'Content-Type': 'application/json', 'Intercom-Version': '2.14', }), diff --git a/apps/sim/tools/intercom/get_ticket.ts b/apps/sim/tools/intercom/get_ticket.ts index 7a04bf5dcc..0c5c66d925 100644 --- a/apps/sim/tools/intercom/get_ticket.ts +++ b/apps/sim/tools/intercom/get_ticket.ts @@ -47,6 +47,7 @@ export const intercomGetTicketTool: ToolConfig ({ Authorization: `Bearer ${params.accessToken}`, + Accept: 'application/json', 'Content-Type': 'application/json', 'Intercom-Version': '2.14', }), diff --git a/apps/sim/tools/intercom/index.ts b/apps/sim/tools/intercom/index.ts index feda2beedb..dab0671ba9 100644 --- a/apps/sim/tools/intercom/index.ts +++ b/apps/sim/tools/intercom/index.ts @@ -16,7 +16,6 @@ export { intercomGetTicketTool } from './get_ticket' export { intercomListCompaniesTool } from './list_companies' export { intercomListContactsTool } from './list_contacts' export { intercomListConversationsTool } from './list_conversations' -export { intercomListTicketsTool } from './list_tickets' export { intercomReplyConversationTool } from './reply_conversation' export { intercomSearchContactsTool } from './search_contacts' export { intercomSearchConversationsTool } from './search_conversations' diff --git a/apps/sim/tools/intercom/list_companies.ts b/apps/sim/tools/intercom/list_companies.ts index 0fc29e622f..8d5a3f32cc 100644 --- a/apps/sim/tools/intercom/list_companies.ts +++ b/apps/sim/tools/intercom/list_companies.ts @@ -64,9 +64,10 @@ export const intercomListCompaniesTool: ToolConfig< const queryString = queryParams.toString() return queryString ? `${url}?${queryString}` : url }, - method: 'GET', + method: 'POST', headers: (params) => ({ Authorization: `Bearer ${params.accessToken}`, + Accept: 'application/json', 'Content-Type': 'application/json', 'Intercom-Version': '2.14', }), diff --git a/apps/sim/tools/intercom/list_contacts.ts b/apps/sim/tools/intercom/list_contacts.ts index 6b3123a512..7f5dd01820 100644 --- a/apps/sim/tools/intercom/list_contacts.ts +++ b/apps/sim/tools/intercom/list_contacts.ts @@ -67,6 +67,7 @@ export const intercomListContactsTool: ToolConfig< method: 'GET', headers: (params) => ({ Authorization: `Bearer ${params.accessToken}`, + Accept: 'application/json', 'Content-Type': 'application/json', 'Intercom-Version': '2.14', }), diff --git a/apps/sim/tools/intercom/list_conversations.ts b/apps/sim/tools/intercom/list_conversations.ts index c3668b4b89..ebb4f6b7f7 100644 --- a/apps/sim/tools/intercom/list_conversations.ts +++ b/apps/sim/tools/intercom/list_conversations.ts @@ -67,6 +67,7 @@ export const intercomListConversationsTool: ToolConfig< method: 'GET', headers: (params) => ({ Authorization: `Bearer ${params.accessToken}`, + Accept: 'application/json', 'Content-Type': 'application/json', 'Intercom-Version': '2.14', }), diff --git a/apps/sim/tools/intercom/list_tickets.ts b/apps/sim/tools/intercom/list_tickets.ts deleted file mode 100644 index 034cea80fb..0000000000 --- a/apps/sim/tools/intercom/list_tickets.ts +++ /dev/null @@ -1,110 +0,0 @@ -import { createLogger } from '@/lib/logs/console/logger' -import type { ToolConfig } from '@/tools/types' -import { buildIntercomUrl, handleIntercomError } from './types' - -const logger = createLogger('IntercomListTickets') - -export interface IntercomListTicketsParams { - accessToken: string - per_page?: number - starting_after?: string -} - -export interface IntercomListTicketsResponse { - success: boolean - output: { - tickets: any[] - pages?: any - metadata: { - operation: 'list_tickets' - total_count?: number - } - success: boolean - } -} - -export const intercomListTicketsTool: ToolConfig< - IntercomListTicketsParams, - IntercomListTicketsResponse -> = { - id: 'intercom_list_tickets', - name: 'List Tickets from Intercom', - description: 'List all tickets from Intercom with pagination support', - version: '1.0.0', - - params: { - accessToken: { - type: 'string', - required: true, - visibility: 'hidden', - description: 'Intercom API access token', - }, - per_page: { - type: 'number', - required: false, - visibility: 'user-only', - description: 'Number of results per page (max: 150)', - }, - starting_after: { - type: 'string', - required: false, - visibility: 'user-only', - description: 'Cursor for pagination', - }, - }, - - request: { - url: (params) => { - const url = buildIntercomUrl('/tickets') - const queryParams = new URLSearchParams() - - if (params.per_page) queryParams.append('per_page', params.per_page.toString()) - if (params.starting_after) queryParams.append('starting_after', params.starting_after) - - const queryString = queryParams.toString() - return queryString ? `${url}?${queryString}` : url - }, - method: 'GET', - headers: (params) => ({ - Authorization: `Bearer ${params.accessToken}`, - 'Content-Type': 'application/json', - 'Intercom-Version': '2.14', - }), - }, - - transformResponse: async (response: Response) => { - if (!response.ok) { - const data = await response.json() - handleIntercomError(data, response.status, 'list_tickets') - } - - const data = await response.json() - - return { - success: true, - output: { - tickets: data.tickets || [], - pages: data.pages, - metadata: { - operation: 'list_tickets' as const, - total_count: data.total_count, - }, - success: true, - }, - } - }, - - outputs: { - success: { type: 'boolean', description: 'Operation success status' }, - output: { - type: 'object', - description: 'List of tickets', - properties: { - tickets: { type: 'array', description: 'Array of ticket objects' }, - pages: { type: 'object', description: 'Pagination information' }, - metadata: { type: 'object', description: 'Operation metadata' }, - success: { type: 'boolean', description: 'Operation success' }, - }, - }, - }, -} diff --git a/apps/sim/tools/intercom/search_contacts.ts b/apps/sim/tools/intercom/search_contacts.ts index f6e0be8a0a..4dab34158b 100644 --- a/apps/sim/tools/intercom/search_contacts.ts +++ b/apps/sim/tools/intercom/search_contacts.ts @@ -66,6 +66,7 @@ export const intercomSearchContactsTool: ToolConfig< method: 'POST', headers: (params) => ({ Authorization: `Bearer ${params.accessToken}`, + Accept: 'application/json', 'Content-Type': 'application/json', 'Intercom-Version': '2.14', }), diff --git a/apps/sim/tools/intercom/search_conversations.ts b/apps/sim/tools/intercom/search_conversations.ts index 864f42ef97..976ac43120 100644 --- a/apps/sim/tools/intercom/search_conversations.ts +++ b/apps/sim/tools/intercom/search_conversations.ts @@ -65,6 +65,7 @@ export const intercomSearchConversationsTool: ToolConfig< method: 'POST', headers: (params) => ({ Authorization: `Bearer ${params.accessToken}`, + Accept: 'application/json', 'Content-Type': 'application/json', 'Intercom-Version': '2.14', }), diff --git a/apps/sim/tools/mailchimp/add_member.ts b/apps/sim/tools/mailchimp/add_member.ts index 3d5f124af5..226ab6dceb 100644 --- a/apps/sim/tools/mailchimp/add_member.ts +++ b/apps/sim/tools/mailchimp/add_member.ts @@ -51,25 +51,25 @@ export const mailchimpAddMemberTool: ToolConfig< type: 'string', required: true, visibility: 'user-only', - description: 'Email address for the member', + description: 'Member email address', }, status: { type: 'string', required: true, visibility: 'user-only', - description: 'Subscriber status (subscribed, unsubscribed, cleaned, pending)', + description: 'Subscriber status', }, mergeFields: { type: 'string', required: false, visibility: 'user-only', - description: 'Merge fields as JSON object (e.g., {"FNAME": "John", "LNAME": "Doe"})', + description: 'JSON object of merge fields', }, interests: { type: 'string', required: false, visibility: 'user-only', - description: 'Interests as JSON object (e.g., {"interest_id": true})', + description: 'JSON object of interests', }, }, diff --git a/apps/sim/tools/mailchimp/add_member_tags.ts b/apps/sim/tools/mailchimp/add_member_tags.ts index 18901d5f9f..6d3a140f8e 100644 --- a/apps/sim/tools/mailchimp/add_member_tags.ts +++ b/apps/sim/tools/mailchimp/add_member_tags.ts @@ -7,7 +7,7 @@ const logger = createLogger('MailchimpAddMemberTags') export interface MailchimpAddMemberTagsParams { apiKey: string listId: string - subscriberHash: string + subscriberEmail: string tags: string } @@ -44,18 +44,17 @@ export const mailchimpAddMemberTagsTool: ToolConfig< visibility: 'user-only', description: 'The unique ID for the list', }, - subscriberHash: { + subscriberEmail: { type: 'string', required: true, visibility: 'user-only', - description: "The MD5 hash of the lowercase version of the list member's email address", + description: 'Member email address or MD5 hash', }, tags: { type: 'string', required: true, visibility: 'user-only', - description: - 'Tags as JSON array (e.g., [{"name": "tag1", "status": "active"}, {"name": "tag2", "status": "active"}])', + description: 'JSON array of tags', }, }, @@ -63,7 +62,7 @@ export const mailchimpAddMemberTagsTool: ToolConfig< url: (params) => buildMailchimpUrl( params.apiKey, - `/lists/${params.listId}/members/${params.subscriberHash}/tags` + `/lists/${params.listId}/members/${params.subscriberEmail}/tags` ), method: 'POST', headers: (params) => ({ diff --git a/apps/sim/tools/mailchimp/add_or_update_member.ts b/apps/sim/tools/mailchimp/add_or_update_member.ts index 94b12d8113..ae5a786544 100644 --- a/apps/sim/tools/mailchimp/add_or_update_member.ts +++ b/apps/sim/tools/mailchimp/add_or_update_member.ts @@ -7,7 +7,7 @@ const logger = createLogger('MailchimpAddOrUpdateMember') export interface MailchimpAddOrUpdateMemberParams { apiKey: string listId: string - subscriberHash: string + subscriberEmail: string emailAddress: string statusIfNew: string mergeFields?: string @@ -48,41 +48,41 @@ export const mailchimpAddOrUpdateMemberTool: ToolConfig< visibility: 'user-only', description: 'The unique ID for the list', }, - subscriberHash: { + subscriberEmail: { type: 'string', required: true, visibility: 'user-only', - description: "The MD5 hash of the lowercase version of the list member's email address", + description: 'Member email address or MD5 hash', }, emailAddress: { type: 'string', required: true, visibility: 'user-only', - description: 'Email address for the member', + description: 'Member email address', }, statusIfNew: { type: 'string', required: true, visibility: 'user-only', - description: 'Subscriber status if new member (subscribed, unsubscribed, cleaned, pending)', + description: 'Subscriber status if new member', }, mergeFields: { type: 'string', required: false, visibility: 'user-only', - description: 'Merge fields as JSON object (e.g., {"FNAME": "John", "LNAME": "Doe"})', + description: 'JSON object of merge fields', }, interests: { type: 'string', required: false, visibility: 'user-only', - description: 'Interests as JSON object (e.g., {"interest_id": true})', + description: 'JSON object of interests', }, }, request: { url: (params) => - buildMailchimpUrl(params.apiKey, `/lists/${params.listId}/members/${params.subscriberHash}`), + buildMailchimpUrl(params.apiKey, `/lists/${params.listId}/members/${params.subscriberEmail}`), method: 'PUT', headers: (params) => ({ Authorization: `Bearer ${params.apiKey}`, diff --git a/apps/sim/tools/mailchimp/archive_member.ts b/apps/sim/tools/mailchimp/archive_member.ts index 01378444ab..dbe79651e4 100644 --- a/apps/sim/tools/mailchimp/archive_member.ts +++ b/apps/sim/tools/mailchimp/archive_member.ts @@ -7,7 +7,7 @@ const logger = createLogger('MailchimpArchiveMember') export interface MailchimpArchiveMemberParams { apiKey: string listId: string - subscriberHash: string + subscriberEmail: string } export interface MailchimpArchiveMemberResponse { @@ -43,11 +43,11 @@ export const mailchimpArchiveMemberTool: ToolConfig< visibility: 'user-only', description: 'The unique ID for the list', }, - subscriberHash: { + subscriberEmail: { type: 'string', required: true, visibility: 'user-only', - description: "The MD5 hash of the lowercase version of the list member's email address", + description: 'Member email address or MD5 hash', }, }, @@ -55,7 +55,7 @@ export const mailchimpArchiveMemberTool: ToolConfig< url: (params) => buildMailchimpUrl( params.apiKey, - `/lists/${params.listId}/members/${params.subscriberHash}/actions/delete-permanent` + `/lists/${params.listId}/members/${params.subscriberEmail}/actions/delete-permanent` ), method: 'DELETE', headers: (params) => ({ diff --git a/apps/sim/tools/mailchimp/create_audience.ts b/apps/sim/tools/mailchimp/create_audience.ts index 1cf79a83b3..17310ec932 100644 --- a/apps/sim/tools/mailchimp/create_audience.ts +++ b/apps/sim/tools/mailchimp/create_audience.ts @@ -51,27 +51,25 @@ export const mailchimpCreateAudienceTool: ToolConfig< type: 'string', required: true, visibility: 'user-only', - description: - 'Contact information as JSON (e.g., {"company": "Acme Inc", "address1": "123 Main St", "city": "Atlanta", "state": "GA", "zip": "30308", "country": "US"})', + description: 'JSON object of contact information', }, permissionReminder: { type: 'string', required: true, visibility: 'user-only', - description: 'Permission reminder text (why subscribers are on your list)', + description: 'Permission reminder text', }, campaignDefaults: { type: 'string', required: true, visibility: 'user-only', - description: - 'Default campaign settings as JSON (e.g., {"from_name": "John", "from_email": "john@example.com", "subject": "Newsletter", "language": "en"})', + description: 'JSON object of default campaign settings', }, emailTypeOption: { type: 'string', required: true, visibility: 'user-only', - description: 'Whether the list supports multiple formats (true/false)', + description: 'Support multiple email formats', }, }, diff --git a/apps/sim/tools/mailchimp/create_batch_operation.ts b/apps/sim/tools/mailchimp/create_batch_operation.ts index df792ee6df..5e49f871b1 100644 --- a/apps/sim/tools/mailchimp/create_batch_operation.ts +++ b/apps/sim/tools/mailchimp/create_batch_operation.ts @@ -41,8 +41,7 @@ export const mailchimpCreateBatchOperationTool: ToolConfig< type: 'string', required: true, visibility: 'user-only', - description: - 'Operations as JSON array (e.g., [{"method": "POST", "path": "/lists", "body": "{\\"name\\": \\"Test\\"}"}])', + description: 'JSON array of operations', }, }, diff --git a/apps/sim/tools/mailchimp/create_campaign.ts b/apps/sim/tools/mailchimp/create_campaign.ts index 0e46c6aeae..add7e5dce8 100644 --- a/apps/sim/tools/mailchimp/create_campaign.ts +++ b/apps/sim/tools/mailchimp/create_campaign.ts @@ -43,20 +43,19 @@ export const mailchimpCreateCampaignTool: ToolConfig< type: 'string', required: true, visibility: 'user-only', - description: 'Campaign type (regular, plaintext, absplit, rss, variate)', + description: 'Campaign type', }, campaignSettings: { type: 'string', required: true, visibility: 'user-only', - description: - 'Campaign settings as JSON (e.g., {"subject_line": "Test", "from_name": "John", "reply_to": "john@example.com"})', + description: 'JSON object of campaign settings', }, recipients: { type: 'string', required: false, visibility: 'user-only', - description: 'Recipients as JSON (e.g., {"list_id": "abc123"})', + description: 'JSON object of recipients', }, }, diff --git a/apps/sim/tools/mailchimp/create_segment.ts b/apps/sim/tools/mailchimp/create_segment.ts index 2937f03be4..4c3afb767a 100644 --- a/apps/sim/tools/mailchimp/create_segment.ts +++ b/apps/sim/tools/mailchimp/create_segment.ts @@ -55,7 +55,7 @@ export const mailchimpCreateSegmentTool: ToolConfig< type: 'string', required: false, visibility: 'user-only', - description: 'Segment options as JSON (e.g., {"match": "any", "conditions": []})', + description: 'JSON object of segment options', }, }, diff --git a/apps/sim/tools/mailchimp/delete_member.ts b/apps/sim/tools/mailchimp/delete_member.ts index f28b7da709..1b0e02b535 100644 --- a/apps/sim/tools/mailchimp/delete_member.ts +++ b/apps/sim/tools/mailchimp/delete_member.ts @@ -7,7 +7,7 @@ const logger = createLogger('MailchimpDeleteMember') export interface MailchimpDeleteMemberParams { apiKey: string listId: string - subscriberHash: string + subscriberEmail: string } export interface MailchimpDeleteMemberResponse { @@ -43,17 +43,17 @@ export const mailchimpDeleteMemberTool: ToolConfig< visibility: 'user-only', description: 'The unique ID for the list', }, - subscriberHash: { + subscriberEmail: { type: 'string', required: true, visibility: 'user-only', - description: "The MD5 hash of the lowercase version of the list member's email address", + description: 'Member email address or MD5 hash', }, }, request: { url: (params) => - buildMailchimpUrl(params.apiKey, `/lists/${params.listId}/members/${params.subscriberHash}`), + buildMailchimpUrl(params.apiKey, `/lists/${params.listId}/members/${params.subscriberEmail}`), method: 'DELETE', headers: (params) => ({ Authorization: `Bearer ${params.apiKey}`, diff --git a/apps/sim/tools/mailchimp/get_member.ts b/apps/sim/tools/mailchimp/get_member.ts index 538645e424..42a24a1eaa 100644 --- a/apps/sim/tools/mailchimp/get_member.ts +++ b/apps/sim/tools/mailchimp/get_member.ts @@ -7,7 +7,7 @@ const logger = createLogger('MailchimpGetMember') export interface MailchimpGetMemberParams { apiKey: string listId: string - subscriberHash: string + subscriberEmail: string } export interface MailchimpGetMemberResponse { @@ -44,17 +44,17 @@ export const mailchimpGetMemberTool: ToolConfig< visibility: 'user-only', description: 'The unique ID for the list', }, - subscriberHash: { + subscriberEmail: { type: 'string', required: true, visibility: 'user-only', - description: "The MD5 hash of the lowercase version of the list member's email address", + description: 'Member email address or MD5 hash', }, }, request: { url: (params) => - buildMailchimpUrl(params.apiKey, `/lists/${params.listId}/members/${params.subscriberHash}`), + buildMailchimpUrl(params.apiKey, `/lists/${params.listId}/members/${params.subscriberEmail}`), method: 'GET', headers: (params) => ({ Authorization: `Bearer ${params.apiKey}`, diff --git a/apps/sim/tools/mailchimp/get_member_tags.ts b/apps/sim/tools/mailchimp/get_member_tags.ts index a616f9d19d..850f7e23b9 100644 --- a/apps/sim/tools/mailchimp/get_member_tags.ts +++ b/apps/sim/tools/mailchimp/get_member_tags.ts @@ -7,7 +7,7 @@ const logger = createLogger('MailchimpGetMemberTags') export interface MailchimpGetMemberTagsParams { apiKey: string listId: string - subscriberHash: string + subscriberEmail: string } export interface MailchimpGetMemberTagsResponse { @@ -45,11 +45,11 @@ export const mailchimpGetMemberTagsTool: ToolConfig< visibility: 'user-only', description: 'The unique ID for the list', }, - subscriberHash: { + subscriberEmail: { type: 'string', required: true, visibility: 'user-only', - description: "The MD5 hash of the lowercase version of the list member's email address", + description: 'Member email address or MD5 hash', }, }, @@ -57,7 +57,7 @@ export const mailchimpGetMemberTagsTool: ToolConfig< url: (params) => buildMailchimpUrl( params.apiKey, - `/lists/${params.listId}/members/${params.subscriberHash}/tags` + `/lists/${params.listId}/members/${params.subscriberEmail}/tags` ), method: 'GET', headers: (params) => ({ diff --git a/apps/sim/tools/mailchimp/remove_member_tags.ts b/apps/sim/tools/mailchimp/remove_member_tags.ts index 7d0b99c74d..578f84d057 100644 --- a/apps/sim/tools/mailchimp/remove_member_tags.ts +++ b/apps/sim/tools/mailchimp/remove_member_tags.ts @@ -7,7 +7,7 @@ const logger = createLogger('MailchimpRemoveMemberTags') export interface MailchimpRemoveMemberTagsParams { apiKey: string listId: string - subscriberHash: string + subscriberEmail: string tags: string } @@ -44,18 +44,17 @@ export const mailchimpRemoveMemberTagsTool: ToolConfig< visibility: 'user-only', description: 'The unique ID for the list', }, - subscriberHash: { + subscriberEmail: { type: 'string', required: true, visibility: 'user-only', - description: "The MD5 hash of the lowercase version of the list member's email address", + description: 'Member email address or MD5 hash', }, tags: { type: 'string', required: true, visibility: 'user-only', - description: - 'Tags as JSON array with inactive status (e.g., [{"name": "tag1", "status": "inactive"}, {"name": "tag2", "status": "inactive"}])', + description: 'JSON array of tags with inactive status', }, }, @@ -63,7 +62,7 @@ export const mailchimpRemoveMemberTagsTool: ToolConfig< url: (params) => buildMailchimpUrl( params.apiKey, - `/lists/${params.listId}/members/${params.subscriberHash}/tags` + `/lists/${params.listId}/members/${params.subscriberEmail}/tags` ), method: 'POST', headers: (params) => ({ diff --git a/apps/sim/tools/mailchimp/remove_segment_member.ts b/apps/sim/tools/mailchimp/remove_segment_member.ts index d5bdf8e59a..7166f86881 100644 --- a/apps/sim/tools/mailchimp/remove_segment_member.ts +++ b/apps/sim/tools/mailchimp/remove_segment_member.ts @@ -8,7 +8,7 @@ export interface MailchimpRemoveSegmentMemberParams { apiKey: string listId: string segmentId: string - subscriberHash: string + subscriberEmail: string } export interface MailchimpRemoveSegmentMemberResponse { @@ -50,11 +50,11 @@ export const mailchimpRemoveSegmentMemberTool: ToolConfig< visibility: 'user-only', description: 'The unique ID for the segment', }, - subscriberHash: { + subscriberEmail: { type: 'string', required: true, visibility: 'user-only', - description: "The MD5 hash of the lowercase version of the list member's email address", + description: 'Member email address or MD5 hash', }, }, @@ -62,7 +62,7 @@ export const mailchimpRemoveSegmentMemberTool: ToolConfig< url: (params) => buildMailchimpUrl( params.apiKey, - `/lists/${params.listId}/segments/${params.segmentId}/members/${params.subscriberHash}` + `/lists/${params.listId}/segments/${params.segmentId}/members/${params.subscriberEmail}` ), method: 'DELETE', headers: (params) => ({ diff --git a/apps/sim/tools/mailchimp/schedule_campaign.ts b/apps/sim/tools/mailchimp/schedule_campaign.ts index 971d7a863b..377ac05a39 100644 --- a/apps/sim/tools/mailchimp/schedule_campaign.ts +++ b/apps/sim/tools/mailchimp/schedule_campaign.ts @@ -48,7 +48,7 @@ export const mailchimpScheduleCampaignTool: ToolConfig< type: 'string', required: true, visibility: 'user-only', - description: 'The date and time in ISO 8601 format (e.g., 2024-01-01T12:00:00+00:00)', + description: 'ISO 8601 format date and time', }, }, diff --git a/apps/sim/tools/mailchimp/unarchive_member.ts b/apps/sim/tools/mailchimp/unarchive_member.ts index 873007bd84..da92094208 100644 --- a/apps/sim/tools/mailchimp/unarchive_member.ts +++ b/apps/sim/tools/mailchimp/unarchive_member.ts @@ -7,7 +7,7 @@ const logger = createLogger('MailchimpUnarchiveMember') export interface MailchimpUnarchiveMemberParams { apiKey: string listId: string - subscriberHash: string + subscriberEmail: string emailAddress: string status: string } @@ -46,29 +46,29 @@ export const mailchimpUnarchiveMemberTool: ToolConfig< visibility: 'user-only', description: 'The unique ID for the list', }, - subscriberHash: { + subscriberEmail: { type: 'string', required: true, visibility: 'user-only', - description: "The MD5 hash of the lowercase version of the list member's email address", + description: 'Member email address or MD5 hash', }, emailAddress: { type: 'string', required: true, visibility: 'user-only', - description: 'Email address for the member', + description: 'Member email address', }, status: { type: 'string', required: true, visibility: 'user-only', - description: 'Subscriber status (subscribed, unsubscribed, cleaned, pending)', + description: 'Subscriber status', }, }, request: { url: (params) => - buildMailchimpUrl(params.apiKey, `/lists/${params.listId}/members/${params.subscriberHash}`), + buildMailchimpUrl(params.apiKey, `/lists/${params.listId}/members/${params.subscriberEmail}`), method: 'PUT', headers: (params) => ({ Authorization: `Bearer ${params.apiKey}`, diff --git a/apps/sim/tools/mailchimp/update_audience.ts b/apps/sim/tools/mailchimp/update_audience.ts index 07f96ab5a1..fe7b7a3828 100644 --- a/apps/sim/tools/mailchimp/update_audience.ts +++ b/apps/sim/tools/mailchimp/update_audience.ts @@ -63,13 +63,13 @@ export const mailchimpUpdateAudienceTool: ToolConfig< type: 'string', required: false, visibility: 'user-only', - description: 'Default campaign settings as JSON', + description: 'JSON object of default campaign settings', }, emailTypeOption: { type: 'string', required: false, visibility: 'user-only', - description: 'Whether the list supports multiple formats (true/false)', + description: 'Support multiple email formats', }, }, diff --git a/apps/sim/tools/mailchimp/update_campaign.ts b/apps/sim/tools/mailchimp/update_campaign.ts index 0824f006c1..246c9d91fe 100644 --- a/apps/sim/tools/mailchimp/update_campaign.ts +++ b/apps/sim/tools/mailchimp/update_campaign.ts @@ -49,13 +49,13 @@ export const mailchimpUpdateCampaignTool: ToolConfig< type: 'string', required: false, visibility: 'user-only', - description: 'Campaign settings as JSON', + description: 'JSON object of campaign settings', }, recipients: { type: 'string', required: false, visibility: 'user-only', - description: 'Recipients as JSON', + description: 'JSON object of recipients', }, }, diff --git a/apps/sim/tools/mailchimp/update_member.ts b/apps/sim/tools/mailchimp/update_member.ts index c7f5e7ae5c..0483f8bf92 100644 --- a/apps/sim/tools/mailchimp/update_member.ts +++ b/apps/sim/tools/mailchimp/update_member.ts @@ -7,7 +7,7 @@ const logger = createLogger('MailchimpUpdateMember') export interface MailchimpUpdateMemberParams { apiKey: string listId: string - subscriberHash: string + subscriberEmail: string emailAddress?: string status?: string mergeFields?: string @@ -48,41 +48,41 @@ export const mailchimpUpdateMemberTool: ToolConfig< visibility: 'user-only', description: 'The unique ID for the list', }, - subscriberHash: { + subscriberEmail: { type: 'string', required: true, visibility: 'user-only', - description: "The MD5 hash of the lowercase version of the list member's email address", + description: 'Member email address or MD5 hash', }, emailAddress: { type: 'string', required: false, visibility: 'user-only', - description: 'Email address for the member', + description: 'Member email address', }, status: { type: 'string', required: false, visibility: 'user-only', - description: 'Subscriber status (subscribed, unsubscribed, cleaned, pending)', + description: 'Subscriber status', }, mergeFields: { type: 'string', required: false, visibility: 'user-only', - description: 'Merge fields as JSON object', + description: 'JSON object of merge fields', }, interests: { type: 'string', required: false, visibility: 'user-only', - description: 'Interests as JSON object', + description: 'JSON object of interests', }, }, request: { url: (params) => - buildMailchimpUrl(params.apiKey, `/lists/${params.listId}/members/${params.subscriberHash}`), + buildMailchimpUrl(params.apiKey, `/lists/${params.listId}/members/${params.subscriberEmail}`), method: 'PATCH', headers: (params) => ({ Authorization: `Bearer ${params.apiKey}`, diff --git a/apps/sim/tools/mailchimp/update_segment.ts b/apps/sim/tools/mailchimp/update_segment.ts index a3d2722971..90d237514c 100644 --- a/apps/sim/tools/mailchimp/update_segment.ts +++ b/apps/sim/tools/mailchimp/update_segment.ts @@ -62,7 +62,7 @@ export const mailchimpUpdateSegmentTool: ToolConfig< type: 'string', required: false, visibility: 'user-only', - description: 'Segment options as JSON', + description: 'JSON object of segment options', }, }, diff --git a/apps/sim/tools/registry.ts b/apps/sim/tools/registry.ts index 579e1e7404..f22d04cd20 100644 --- a/apps/sim/tools/registry.ts +++ b/apps/sim/tools/registry.ts @@ -303,7 +303,6 @@ import { intercomListCompaniesTool, intercomListContactsTool, intercomListConversationsTool, - intercomListTicketsTool, intercomReplyConversationTool, intercomSearchContactsTool, intercomSearchConversationsTool, @@ -969,7 +968,6 @@ import { zendeskDeleteOrganizationTool, zendeskDeleteTicketTool, zendeskDeleteUserTool, - zendeskExportSearchTool, zendeskGetCurrentUserTool, zendeskGetOrganizationsTool, zendeskGetOrganizationTool, @@ -1889,7 +1887,6 @@ export const tools: Record = { zendesk_delete_organization: zendeskDeleteOrganizationTool, zendesk_search: zendeskSearchTool, zendesk_search_count: zendeskSearchCountTool, - zendesk_export_search: zendeskExportSearchTool, intercom_create_contact: intercomCreateContactTool, intercom_get_contact: intercomGetContactTool, intercom_update_contact: intercomUpdateContactTool, @@ -1905,7 +1902,6 @@ export const tools: Record = { intercom_search_conversations: intercomSearchConversationsTool, intercom_create_ticket: intercomCreateTicketTool, intercom_get_ticket: intercomGetTicketTool, - intercom_list_tickets: intercomListTicketsTool, intercom_create_message: intercomCreateMessageTool, sentry_issues_list: listIssuesTool, sentry_issues_get: getIssueTool, diff --git a/apps/sim/tools/zendesk/autocomplete_organizations.ts b/apps/sim/tools/zendesk/autocomplete_organizations.ts index 9ada7f23a9..7b0ef8ccbb 100644 --- a/apps/sim/tools/zendesk/autocomplete_organizations.ts +++ b/apps/sim/tools/zendesk/autocomplete_organizations.ts @@ -5,6 +5,7 @@ import { buildZendeskUrl, handleZendeskError } from './types' const logger = createLogger('ZendeskAutocompleteOrganizations') export interface ZendeskAutocompleteOrganizationsParams { + email: string apiToken: string subdomain: string name: string @@ -40,6 +41,12 @@ export const zendeskAutocompleteOrganizationsTool: ToolConfig< version: '1.0.0', params: { + email: { + type: 'string', + required: true, + visibility: 'user-only', + description: 'Your Zendesk email address', + }, apiToken: { type: 'string', required: true, @@ -84,10 +91,14 @@ export const zendeskAutocompleteOrganizationsTool: ToolConfig< return `${url}?${query}` }, method: 'GET', - headers: (params) => ({ - Authorization: `Bearer ${params.apiToken}`, - 'Content-Type': 'application/json', - }), + headers: (params) => { + const credentials = `${params.email}/token:${params.apiToken}` + const base64Credentials = Buffer.from(credentials).toString('base64') + return { + Authorization: `Basic ${base64Credentials}`, + 'Content-Type': 'application/json', + } + }, }, transformResponse: async (response: Response) => { diff --git a/apps/sim/tools/zendesk/create_organization.ts b/apps/sim/tools/zendesk/create_organization.ts index 588a2e2fd9..c77162ba85 100644 --- a/apps/sim/tools/zendesk/create_organization.ts +++ b/apps/sim/tools/zendesk/create_organization.ts @@ -5,6 +5,7 @@ import { buildZendeskUrl, handleZendeskError } from './types' const logger = createLogger('ZendeskCreateOrganization') export interface ZendeskCreateOrganizationParams { + email: string apiToken: string subdomain: string name: string @@ -37,6 +38,12 @@ export const zendeskCreateOrganizationTool: ToolConfig< version: '1.0.0', params: { + email: { + type: 'string', + required: true, + visibility: 'user-only', + description: 'Your Zendesk email address', + }, apiToken: { type: 'string', required: true, @@ -90,10 +97,14 @@ export const zendeskCreateOrganizationTool: ToolConfig< request: { url: (params) => buildZendeskUrl(params.subdomain, '/organizations'), method: 'POST', - headers: (params) => ({ - Authorization: `Bearer ${params.apiToken}`, - 'Content-Type': 'application/json', - }), + headers: (params) => { + const credentials = `${params.email}/token:${params.apiToken}` + const base64Credentials = Buffer.from(credentials).toString('base64') + return { + Authorization: `Basic ${base64Credentials}`, + 'Content-Type': 'application/json', + } + }, body: (params) => { const organization: any = { name: params.name, diff --git a/apps/sim/tools/zendesk/create_organizations_bulk.ts b/apps/sim/tools/zendesk/create_organizations_bulk.ts index 5c2150d438..e46f9d9a8f 100644 --- a/apps/sim/tools/zendesk/create_organizations_bulk.ts +++ b/apps/sim/tools/zendesk/create_organizations_bulk.ts @@ -5,6 +5,7 @@ import { buildZendeskUrl, handleZendeskError } from './types' const logger = createLogger('ZendeskCreateOrganizationsBulk') export interface ZendeskCreateOrganizationsBulkParams { + email: string apiToken: string subdomain: string organizations: string @@ -32,6 +33,12 @@ export const zendeskCreateOrganizationsBulkTool: ToolConfig< version: '1.0.0', params: { + email: { + type: 'string', + required: true, + visibility: 'user-only', + description: 'Your Zendesk email address', + }, apiToken: { type: 'string', required: true, @@ -55,10 +62,14 @@ export const zendeskCreateOrganizationsBulkTool: ToolConfig< request: { url: (params) => buildZendeskUrl(params.subdomain, '/organizations/create_many'), method: 'POST', - headers: (params) => ({ - Authorization: `Bearer ${params.apiToken}`, - 'Content-Type': 'application/json', - }), + headers: (params) => { + const credentials = `${params.email}/token:${params.apiToken}` + const base64Credentials = Buffer.from(credentials).toString('base64') + return { + Authorization: `Basic ${base64Credentials}`, + 'Content-Type': 'application/json', + } + }, body: (params) => { try { const organizations = JSON.parse(params.organizations) diff --git a/apps/sim/tools/zendesk/create_ticket.ts b/apps/sim/tools/zendesk/create_ticket.ts index 9c32b77640..d0fd81a994 100644 --- a/apps/sim/tools/zendesk/create_ticket.ts +++ b/apps/sim/tools/zendesk/create_ticket.ts @@ -5,6 +5,7 @@ import { buildZendeskUrl, handleZendeskError } from './types' const logger = createLogger('ZendeskCreateTicket') export interface ZendeskCreateTicketParams { + email: string apiToken: string subdomain: string subject: string @@ -41,6 +42,12 @@ export const zendeskCreateTicketTool: ToolConfig< version: '1.0.0', params: { + email: { + type: 'string', + required: true, + visibility: 'user-only', + description: 'Your Zendesk email address', + }, apiToken: { type: 'string', required: true, @@ -118,10 +125,15 @@ export const zendeskCreateTicketTool: ToolConfig< request: { url: (params) => buildZendeskUrl(params.subdomain, '/tickets'), method: 'POST', - headers: (params) => ({ - Authorization: `Bearer ${params.apiToken}`, - 'Content-Type': 'application/json', - }), + headers: (params) => { + // Use Basic Authentication with email/token format for Zendesk API tokens + const credentials = `${params.email}/token:${params.apiToken}` + const base64Credentials = Buffer.from(credentials).toString('base64') + return { + Authorization: `Basic ${base64Credentials}`, + 'Content-Type': 'application/json', + } + }, body: (params) => { const ticket: any = { subject: params.subject, diff --git a/apps/sim/tools/zendesk/create_tickets_bulk.ts b/apps/sim/tools/zendesk/create_tickets_bulk.ts index 7f521be5cc..bf7084f7db 100644 --- a/apps/sim/tools/zendesk/create_tickets_bulk.ts +++ b/apps/sim/tools/zendesk/create_tickets_bulk.ts @@ -5,6 +5,7 @@ import { buildZendeskUrl, handleZendeskError } from './types' const logger = createLogger('ZendeskCreateTicketsBulk') export interface ZendeskCreateTicketsBulkParams { + email: string apiToken: string subdomain: string tickets: string @@ -32,6 +33,12 @@ export const zendeskCreateTicketsBulkTool: ToolConfig< version: '1.0.0', params: { + email: { + type: 'string', + required: true, + visibility: 'user-only', + description: 'Your Zendesk email address', + }, apiToken: { type: 'string', required: true, @@ -56,10 +63,14 @@ export const zendeskCreateTicketsBulkTool: ToolConfig< request: { url: (params) => buildZendeskUrl(params.subdomain, '/tickets/create_many'), method: 'POST', - headers: (params) => ({ - Authorization: `Bearer ${params.apiToken}`, - 'Content-Type': 'application/json', - }), + headers: (params) => { + const credentials = `${params.email}/token:${params.apiToken}` + const base64Credentials = Buffer.from(credentials).toString('base64') + return { + Authorization: `Basic ${base64Credentials}`, + 'Content-Type': 'application/json', + } + }, body: (params) => { try { const tickets = JSON.parse(params.tickets) diff --git a/apps/sim/tools/zendesk/create_user.ts b/apps/sim/tools/zendesk/create_user.ts index c69b11d513..c8f138e377 100644 --- a/apps/sim/tools/zendesk/create_user.ts +++ b/apps/sim/tools/zendesk/create_user.ts @@ -5,10 +5,11 @@ import { buildZendeskUrl, handleZendeskError } from './types' const logger = createLogger('ZendeskCreateUser') export interface ZendeskCreateUserParams { + email: string apiToken: string subdomain: string - name?: string - email?: string + name: string + userEmail?: string role?: string phone?: string organizationId?: string @@ -37,6 +38,12 @@ export const zendeskCreateUserTool: ToolConfig buildZendeskUrl(params.subdomain, '/users'), method: 'POST', - headers: (params) => ({ - Authorization: `Bearer ${params.apiToken}`, - 'Content-Type': 'application/json', - }), + headers: (params) => { + const credentials = `${params.email}/token:${params.apiToken}` + const base64Credentials = Buffer.from(credentials).toString('base64') + return { + Authorization: `Basic ${base64Credentials}`, + 'Content-Type': 'application/json', + } + }, body: (params) => { const user: any = {} if (params.name) user.name = params.name - if (params.email) user.email = params.email + if (params.userEmail) user.email = params.userEmail if (params.role) user.role = params.role if (params.phone) user.phone = params.phone if (params.organizationId) user.organization_id = params.organizationId diff --git a/apps/sim/tools/zendesk/create_users_bulk.ts b/apps/sim/tools/zendesk/create_users_bulk.ts index 2185660ed9..5549d2d609 100644 --- a/apps/sim/tools/zendesk/create_users_bulk.ts +++ b/apps/sim/tools/zendesk/create_users_bulk.ts @@ -5,6 +5,7 @@ import { buildZendeskUrl, handleZendeskError } from './types' const logger = createLogger('ZendeskCreateUsersBulk') export interface ZendeskCreateUsersBulkParams { + email: string apiToken: string subdomain: string users: string @@ -32,6 +33,12 @@ export const zendeskCreateUsersBulkTool: ToolConfig< version: '1.0.0', params: { + email: { + type: 'string', + required: true, + visibility: 'user-only', + description: 'Your Zendesk email address', + }, apiToken: { type: 'string', required: true, @@ -55,10 +62,14 @@ export const zendeskCreateUsersBulkTool: ToolConfig< request: { url: (params) => buildZendeskUrl(params.subdomain, '/users/create_many'), method: 'POST', - headers: (params) => ({ - Authorization: `Bearer ${params.apiToken}`, - 'Content-Type': 'application/json', - }), + headers: (params) => { + const credentials = `${params.email}/token:${params.apiToken}` + const base64Credentials = Buffer.from(credentials).toString('base64') + return { + Authorization: `Basic ${base64Credentials}`, + 'Content-Type': 'application/json', + } + }, body: (params) => { try { const users = JSON.parse(params.users) diff --git a/apps/sim/tools/zendesk/delete_organization.ts b/apps/sim/tools/zendesk/delete_organization.ts index 16dc0f68aa..e733e4f75d 100644 --- a/apps/sim/tools/zendesk/delete_organization.ts +++ b/apps/sim/tools/zendesk/delete_organization.ts @@ -5,6 +5,7 @@ import { buildZendeskUrl, handleZendeskError } from './types' const logger = createLogger('ZendeskDeleteOrganization') export interface ZendeskDeleteOrganizationParams { + email: string apiToken: string subdomain: string organizationId: string @@ -32,6 +33,12 @@ export const zendeskDeleteOrganizationTool: ToolConfig< version: '1.0.0', params: { + email: { + type: 'string', + required: true, + visibility: 'user-only', + description: 'Your Zendesk email address', + }, apiToken: { type: 'string', required: true, @@ -55,10 +62,14 @@ export const zendeskDeleteOrganizationTool: ToolConfig< request: { url: (params) => buildZendeskUrl(params.subdomain, `/organizations/${params.organizationId}`), method: 'DELETE', - headers: (params) => ({ - Authorization: `Bearer ${params.apiToken}`, - 'Content-Type': 'application/json', - }), + headers: (params) => { + const credentials = `${params.email}/token:${params.apiToken}` + const base64Credentials = Buffer.from(credentials).toString('base64') + return { + Authorization: `Basic ${base64Credentials}`, + 'Content-Type': 'application/json', + } + }, }, transformResponse: async (response: Response, params) => { diff --git a/apps/sim/tools/zendesk/delete_ticket.ts b/apps/sim/tools/zendesk/delete_ticket.ts index 2bdeb06c63..20768572b8 100644 --- a/apps/sim/tools/zendesk/delete_ticket.ts +++ b/apps/sim/tools/zendesk/delete_ticket.ts @@ -5,6 +5,7 @@ import { buildZendeskUrl, handleZendeskError } from './types' const logger = createLogger('ZendeskDeleteTicket') export interface ZendeskDeleteTicketParams { + email: string apiToken: string subdomain: string ticketId: string @@ -32,6 +33,12 @@ export const zendeskDeleteTicketTool: ToolConfig< version: '1.0.0', params: { + email: { + type: 'string', + required: true, + visibility: 'user-only', + description: 'Your Zendesk email address', + }, apiToken: { type: 'string', required: true, @@ -55,10 +62,15 @@ export const zendeskDeleteTicketTool: ToolConfig< request: { url: (params) => buildZendeskUrl(params.subdomain, `/tickets/${params.ticketId}`), method: 'DELETE', - headers: (params) => ({ - Authorization: `Bearer ${params.apiToken}`, - 'Content-Type': 'application/json', - }), + headers: (params) => { + // Use Basic Authentication with email/token format for Zendesk API tokens + const credentials = `${params.email}/token:${params.apiToken}` + const base64Credentials = Buffer.from(credentials).toString('base64') + return { + Authorization: `Basic ${base64Credentials}`, + 'Content-Type': 'application/json', + } + }, }, transformResponse: async (response: Response, params) => { diff --git a/apps/sim/tools/zendesk/delete_user.ts b/apps/sim/tools/zendesk/delete_user.ts index 458bd70284..9d4f69e98c 100644 --- a/apps/sim/tools/zendesk/delete_user.ts +++ b/apps/sim/tools/zendesk/delete_user.ts @@ -5,6 +5,7 @@ import { buildZendeskUrl, handleZendeskError } from './types' const logger = createLogger('ZendeskDeleteUser') export interface ZendeskDeleteUserParams { + email: string apiToken: string subdomain: string userId: string @@ -30,6 +31,12 @@ export const zendeskDeleteUserTool: ToolConfig buildZendeskUrl(params.subdomain, `/users/${params.userId}`), method: 'DELETE', - headers: (params) => ({ - Authorization: `Bearer ${params.apiToken}`, - 'Content-Type': 'application/json', - }), + headers: (params) => { + const credentials = `${params.email}/token:${params.apiToken}` + const base64Credentials = Buffer.from(credentials).toString('base64') + return { + Authorization: `Basic ${base64Credentials}`, + 'Content-Type': 'application/json', + } + }, }, transformResponse: async (response: Response, params) => { diff --git a/apps/sim/tools/zendesk/export_search.ts b/apps/sim/tools/zendesk/export_search.ts deleted file mode 100644 index 7a88f27437..0000000000 --- a/apps/sim/tools/zendesk/export_search.ts +++ /dev/null @@ -1,116 +0,0 @@ -import { createLogger } from '@/lib/logs/console/logger' -import type { ToolConfig } from '@/tools/types' -import { buildZendeskUrl, handleZendeskError } from './types' - -const logger = createLogger('ZendeskExportSearch') - -export interface ZendeskExportSearchParams { - apiToken: string - subdomain: string - query: string -} - -export interface ZendeskExportSearchResponse { - success: boolean - output: { - results: any[] - paging?: { - nextPage?: string | null - previousPage?: string | null - count: number - } - metadata: { - operation: 'export_search' - totalReturned: number - } - success: boolean - } -} - -export const zendeskExportSearchTool: ToolConfig< - ZendeskExportSearchParams, - ZendeskExportSearchResponse -> = { - id: 'zendesk_export_search', - name: 'Export Search Results from Zendesk', - description: 'Export search results from Zendesk (supports larger result sets)', - version: '1.0.0', - - params: { - apiToken: { - type: 'string', - required: true, - visibility: 'hidden', - description: 'Zendesk API token', - }, - subdomain: { - type: 'string', - required: true, - visibility: 'user-only', - description: 'Your Zendesk subdomain', - }, - query: { - type: 'string', - required: true, - visibility: 'user-only', - description: 'Search query string', - }, - }, - - request: { - url: (params) => { - const queryParams = new URLSearchParams() - queryParams.append('query', params.query) - - const query = queryParams.toString() - const url = buildZendeskUrl(params.subdomain, '/search/export') - return `${url}?${query}` - }, - method: 'GET', - headers: (params) => ({ - Authorization: `Bearer ${params.apiToken}`, - 'Content-Type': 'application/json', - }), - }, - - transformResponse: async (response: Response) => { - if (!response.ok) { - const data = await response.json() - handleZendeskError(data, response.status, 'export_search') - } - - const data = await response.json() - const results = data.results || [] - - return { - success: true, - output: { - results, - paging: { - nextPage: data.next_page, - previousPage: data.previous_page, - count: data.count || results.length, - }, - metadata: { - operation: 'export_search' as const, - totalReturned: results.length, - }, - success: true, - }, - } - }, - - outputs: { - success: { type: 'boolean', description: 'Operation success status' }, - output: { - type: 'object', - description: 'Exported search results', - properties: { - results: { type: 'array', description: 'Array of result objects' }, - paging: { type: 'object', description: 'Pagination information' }, - metadata: { type: 'object', description: 'Operation metadata' }, - success: { type: 'boolean', description: 'Operation success' }, - }, - }, - }, -} diff --git a/apps/sim/tools/zendesk/get_current_user.ts b/apps/sim/tools/zendesk/get_current_user.ts index 3b0a831244..6605afa737 100644 --- a/apps/sim/tools/zendesk/get_current_user.ts +++ b/apps/sim/tools/zendesk/get_current_user.ts @@ -5,6 +5,7 @@ import { buildZendeskUrl, handleZendeskError } from './types' const logger = createLogger('ZendeskGetCurrentUser') export interface ZendeskGetCurrentUserParams { + email: string apiToken: string subdomain: string } @@ -30,6 +31,12 @@ export const zendeskGetCurrentUserTool: ToolConfig< version: '1.0.0', params: { + email: { + type: 'string', + required: true, + visibility: 'user-only', + description: 'Your Zendesk email address', + }, apiToken: { type: 'string', required: true, @@ -47,10 +54,14 @@ export const zendeskGetCurrentUserTool: ToolConfig< request: { url: (params) => buildZendeskUrl(params.subdomain, '/users/me'), method: 'GET', - headers: (params) => ({ - Authorization: `Bearer ${params.apiToken}`, - 'Content-Type': 'application/json', - }), + headers: (params) => { + const credentials = `${params.email}/token:${params.apiToken}` + const base64Credentials = Buffer.from(credentials).toString('base64') + return { + Authorization: `Basic ${base64Credentials}`, + 'Content-Type': 'application/json', + } + }, }, transformResponse: async (response: Response) => { diff --git a/apps/sim/tools/zendesk/get_organization.ts b/apps/sim/tools/zendesk/get_organization.ts index eb81df4dd9..a62a2cce5b 100644 --- a/apps/sim/tools/zendesk/get_organization.ts +++ b/apps/sim/tools/zendesk/get_organization.ts @@ -5,6 +5,7 @@ import { buildZendeskUrl, handleZendeskError } from './types' const logger = createLogger('ZendeskGetOrganization') export interface ZendeskGetOrganizationParams { + email: string apiToken: string subdomain: string organizationId: string @@ -31,6 +32,12 @@ export const zendeskGetOrganizationTool: ToolConfig< version: '1.0.0', params: { + email: { + type: 'string', + required: true, + visibility: 'user-only', + description: 'Your Zendesk email address', + }, apiToken: { type: 'string', required: true, @@ -54,10 +61,14 @@ export const zendeskGetOrganizationTool: ToolConfig< request: { url: (params) => buildZendeskUrl(params.subdomain, `/organizations/${params.organizationId}`), method: 'GET', - headers: (params) => ({ - Authorization: `Bearer ${params.apiToken}`, - 'Content-Type': 'application/json', - }), + headers: (params) => { + const credentials = `${params.email}/token:${params.apiToken}` + const base64Credentials = Buffer.from(credentials).toString('base64') + return { + Authorization: `Basic ${base64Credentials}`, + 'Content-Type': 'application/json', + } + }, }, transformResponse: async (response: Response) => { diff --git a/apps/sim/tools/zendesk/get_organizations.ts b/apps/sim/tools/zendesk/get_organizations.ts index 1af3524ca3..fad3c2e0af 100644 --- a/apps/sim/tools/zendesk/get_organizations.ts +++ b/apps/sim/tools/zendesk/get_organizations.ts @@ -5,6 +5,7 @@ import { buildZendeskUrl, handleZendeskError } from './types' const logger = createLogger('ZendeskGetOrganizations') export interface ZendeskGetOrganizationsParams { + email: string apiToken: string subdomain: string perPage?: string @@ -38,6 +39,12 @@ export const zendeskGetOrganizationsTool: ToolConfig< version: '1.0.0', params: { + email: { + type: 'string', + required: true, + visibility: 'user-only', + description: 'Your Zendesk email address', + }, apiToken: { type: 'string', required: true, @@ -75,10 +82,14 @@ export const zendeskGetOrganizationsTool: ToolConfig< return query ? `${url}?${query}` : url }, method: 'GET', - headers: (params) => ({ - Authorization: `Bearer ${params.apiToken}`, - 'Content-Type': 'application/json', - }), + headers: (params) => { + const credentials = `${params.email}/token:${params.apiToken}` + const base64Credentials = Buffer.from(credentials).toString('base64') + return { + Authorization: `Basic ${base64Credentials}`, + 'Content-Type': 'application/json', + } + }, }, transformResponse: async (response: Response) => { diff --git a/apps/sim/tools/zendesk/get_ticket.ts b/apps/sim/tools/zendesk/get_ticket.ts index 242cfc8835..e4af1dd5ab 100644 --- a/apps/sim/tools/zendesk/get_ticket.ts +++ b/apps/sim/tools/zendesk/get_ticket.ts @@ -5,6 +5,7 @@ import { buildZendeskUrl, handleZendeskError } from './types' const logger = createLogger('ZendeskGetTicket') export interface ZendeskGetTicketParams { + email: string apiToken: string subdomain: string ticketId: string @@ -28,6 +29,12 @@ export const zendeskGetTicketTool: ToolConfig buildZendeskUrl(params.subdomain, `/tickets/${params.ticketId}`), method: 'GET', - headers: (params) => ({ - Authorization: `Bearer ${params.apiToken}`, - 'Content-Type': 'application/json', - }), + headers: (params) => { + // Use Basic Authentication with email/token format for Zendesk API tokens + const credentials = `${params.email}/token:${params.apiToken}` + const base64Credentials = Buffer.from(credentials).toString('base64') + return { + Authorization: `Basic ${base64Credentials}`, + 'Content-Type': 'application/json', + } + }, }, transformResponse: async (response: Response) => { diff --git a/apps/sim/tools/zendesk/get_tickets.ts b/apps/sim/tools/zendesk/get_tickets.ts index 5460171d4e..97846c68b8 100644 --- a/apps/sim/tools/zendesk/get_tickets.ts +++ b/apps/sim/tools/zendesk/get_tickets.ts @@ -5,6 +5,7 @@ import { buildZendeskUrl, handleZendeskError } from './types' const logger = createLogger('ZendeskGetTickets') export interface ZendeskGetTicketsParams { + email: string apiToken: string subdomain: string status?: string @@ -43,6 +44,12 @@ export const zendeskGetTicketsTool: ToolConfig ({ - Authorization: `Bearer ${params.apiToken}`, - 'Content-Type': 'application/json', - }), + headers: (params) => { + // Use Basic Authentication with email/token format for Zendesk API tokens + const credentials = `${params.email}/token:${params.apiToken}` + const base64Credentials = Buffer.from(credentials).toString('base64') + return { + Authorization: `Basic ${base64Credentials}`, + 'Content-Type': 'application/json', + } + }, }, transformResponse: async (response: Response) => { diff --git a/apps/sim/tools/zendesk/get_user.ts b/apps/sim/tools/zendesk/get_user.ts index 427668018a..7b1527c984 100644 --- a/apps/sim/tools/zendesk/get_user.ts +++ b/apps/sim/tools/zendesk/get_user.ts @@ -5,6 +5,7 @@ import { buildZendeskUrl, handleZendeskError } from './types' const logger = createLogger('ZendeskGetUser') export interface ZendeskGetUserParams { + email: string apiToken: string subdomain: string userId: string @@ -28,6 +29,12 @@ export const zendeskGetUserTool: ToolConfig buildZendeskUrl(params.subdomain, `/users/${params.userId}`), method: 'GET', - headers: (params) => ({ - Authorization: `Bearer ${params.apiToken}`, - 'Content-Type': 'application/json', - }), + headers: (params) => { + const credentials = `${params.email}/token:${params.apiToken}` + const base64Credentials = Buffer.from(credentials).toString('base64') + return { + Authorization: `Basic ${base64Credentials}`, + 'Content-Type': 'application/json', + } + }, }, transformResponse: async (response: Response) => { diff --git a/apps/sim/tools/zendesk/get_users.ts b/apps/sim/tools/zendesk/get_users.ts index 146e48e6f9..6492a1e77f 100644 --- a/apps/sim/tools/zendesk/get_users.ts +++ b/apps/sim/tools/zendesk/get_users.ts @@ -5,6 +5,7 @@ import { buildZendeskUrl, handleZendeskError } from './types' const logger = createLogger('ZendeskGetUsers') export interface ZendeskGetUsersParams { + email: string apiToken: string subdomain: string role?: string @@ -37,6 +38,12 @@ export const zendeskGetUsersTool: ToolConfig ({ - Authorization: `Bearer ${params.apiToken}`, - 'Content-Type': 'application/json', - }), + headers: (params) => { + const credentials = `${params.email}/token:${params.apiToken}` + const base64Credentials = Buffer.from(credentials).toString('base64') + return { + Authorization: `Basic ${base64Credentials}`, + 'Content-Type': 'application/json', + } + }, }, transformResponse: async (response: Response) => { diff --git a/apps/sim/tools/zendesk/index.ts b/apps/sim/tools/zendesk/index.ts index f5b2f4c936..20e60c0e03 100644 --- a/apps/sim/tools/zendesk/index.ts +++ b/apps/sim/tools/zendesk/index.ts @@ -1,5 +1,3 @@ -// Ticket tools - export { zendeskAutocompleteOrganizationsTool } from './autocomplete_organizations' export { zendeskCreateOrganizationTool } from './create_organization' export { zendeskCreateOrganizationsBulkTool } from './create_organizations_bulk' @@ -10,18 +8,14 @@ export { zendeskCreateUsersBulkTool } from './create_users_bulk' export { zendeskDeleteOrganizationTool } from './delete_organization' export { zendeskDeleteTicketTool } from './delete_ticket' export { zendeskDeleteUserTool } from './delete_user' -export { zendeskExportSearchTool } from './export_search' export { zendeskGetCurrentUserTool } from './get_current_user' export { zendeskGetOrganizationTool } from './get_organization' -// Organization tools export { zendeskGetOrganizationsTool } from './get_organizations' export { zendeskGetTicketTool } from './get_ticket' export { zendeskGetTicketsTool } from './get_tickets' export { zendeskGetUserTool } from './get_user' -// User tools export { zendeskGetUsersTool } from './get_users' export { zendeskMergeTicketsTool } from './merge_tickets' -// Search tools export { zendeskSearchTool } from './search' export { zendeskSearchCountTool } from './search_count' export { zendeskSearchUsersTool } from './search_users' diff --git a/apps/sim/tools/zendesk/merge_tickets.ts b/apps/sim/tools/zendesk/merge_tickets.ts index d8a2facaab..256ecc2ac6 100644 --- a/apps/sim/tools/zendesk/merge_tickets.ts +++ b/apps/sim/tools/zendesk/merge_tickets.ts @@ -5,6 +5,7 @@ import { buildZendeskUrl, handleZendeskError } from './types' const logger = createLogger('ZendeskMergeTickets') export interface ZendeskMergeTicketsParams { + email: string apiToken: string subdomain: string targetTicketId: string @@ -35,6 +36,12 @@ export const zendeskMergeTicketsTool: ToolConfig< version: '1.0.0', params: { + email: { + type: 'string', + required: true, + visibility: 'user-only', + description: 'Your Zendesk email address', + }, apiToken: { type: 'string', required: true, @@ -70,10 +77,14 @@ export const zendeskMergeTicketsTool: ToolConfig< request: { url: (params) => buildZendeskUrl(params.subdomain, `/tickets/${params.targetTicketId}/merge`), method: 'POST', - headers: (params) => ({ - Authorization: `Bearer ${params.apiToken}`, - 'Content-Type': 'application/json', - }), + headers: (params) => { + const credentials = `${params.email}/token:${params.apiToken}` + const base64Credentials = Buffer.from(credentials).toString('base64') + return { + Authorization: `Basic ${base64Credentials}`, + 'Content-Type': 'application/json', + } + }, body: (params) => { const ids = params.sourceTicketIds.split(',').map((id) => id.trim()) const body: any = { ids } diff --git a/apps/sim/tools/zendesk/search.ts b/apps/sim/tools/zendesk/search.ts index abe0e84fc9..1f76442975 100644 --- a/apps/sim/tools/zendesk/search.ts +++ b/apps/sim/tools/zendesk/search.ts @@ -5,6 +5,7 @@ import { buildZendeskUrl, handleZendeskError } from './types' const logger = createLogger('ZendeskSearch') export interface ZendeskSearchParams { + email: string apiToken: string subdomain: string query: string @@ -38,6 +39,12 @@ export const zendeskSearchTool: ToolConfig ({ - Authorization: `Bearer ${params.apiToken}`, - 'Content-Type': 'application/json', - }), + headers: (params) => { + const credentials = `${params.email}/token:${params.apiToken}` + const base64Credentials = Buffer.from(credentials).toString('base64') + return { + Authorization: `Basic ${base64Credentials}`, + 'Content-Type': 'application/json', + } + }, }, transformResponse: async (response: Response) => { diff --git a/apps/sim/tools/zendesk/search_count.ts b/apps/sim/tools/zendesk/search_count.ts index f28e9351ec..636cc321b7 100644 --- a/apps/sim/tools/zendesk/search_count.ts +++ b/apps/sim/tools/zendesk/search_count.ts @@ -5,6 +5,7 @@ import { buildZendeskUrl, handleZendeskError } from './types' const logger = createLogger('ZendeskSearchCount') export interface ZendeskSearchCountParams { + email: string apiToken: string subdomain: string query: string @@ -31,6 +32,12 @@ export const zendeskSearchCountTool: ToolConfig< version: '1.0.0', params: { + email: { + type: 'string', + required: true, + visibility: 'user-only', + description: 'Your Zendesk email address', + }, apiToken: { type: 'string', required: true, @@ -61,10 +68,14 @@ export const zendeskSearchCountTool: ToolConfig< return `${url}?${query}` }, method: 'GET', - headers: (params) => ({ - Authorization: `Bearer ${params.apiToken}`, - 'Content-Type': 'application/json', - }), + headers: (params) => { + const credentials = `${params.email}/token:${params.apiToken}` + const base64Credentials = Buffer.from(credentials).toString('base64') + return { + Authorization: `Basic ${base64Credentials}`, + 'Content-Type': 'application/json', + } + }, }, transformResponse: async (response: Response) => { diff --git a/apps/sim/tools/zendesk/search_users.ts b/apps/sim/tools/zendesk/search_users.ts index 58dfe268b0..5ad4c9a90a 100644 --- a/apps/sim/tools/zendesk/search_users.ts +++ b/apps/sim/tools/zendesk/search_users.ts @@ -5,6 +5,7 @@ import { buildZendeskUrl, handleZendeskError } from './types' const logger = createLogger('ZendeskSearchUsers') export interface ZendeskSearchUsersParams { + email: string apiToken: string subdomain: string query?: string @@ -40,6 +41,12 @@ export const zendeskSearchUsersTool: ToolConfig< version: '1.0.0', params: { + email: { + type: 'string', + required: true, + visibility: 'user-only', + description: 'Your Zendesk email address', + }, apiToken: { type: 'string', required: true, @@ -91,10 +98,14 @@ export const zendeskSearchUsersTool: ToolConfig< return `${url}?${query}` }, method: 'GET', - headers: (params) => ({ - Authorization: `Bearer ${params.apiToken}`, - 'Content-Type': 'application/json', - }), + headers: (params) => { + const credentials = `${params.email}/token:${params.apiToken}` + const base64Credentials = Buffer.from(credentials).toString('base64') + return { + Authorization: `Basic ${base64Credentials}`, + 'Content-Type': 'application/json', + } + }, }, transformResponse: async (response: Response) => { diff --git a/apps/sim/tools/zendesk/types.ts b/apps/sim/tools/zendesk/types.ts index e2db2c2701..aa7103b28e 100644 --- a/apps/sim/tools/zendesk/types.ts +++ b/apps/sim/tools/zendesk/types.ts @@ -4,8 +4,8 @@ const logger = createLogger('Zendesk') // Base params - following Sentry pattern where subdomain is user-provided export interface ZendeskBaseParams { - accessToken: string // OAuth token (hidden) - idToken?: string // Optional ID token (hidden) + email: string // Zendesk user email (required for API token authentication) + apiToken: string // API token (hidden) subdomain: string // Zendesk subdomain (user-visible, required - e.g., "mycompany" for mycompany.zendesk.com) } diff --git a/apps/sim/tools/zendesk/update_organization.ts b/apps/sim/tools/zendesk/update_organization.ts index 055b18019d..f8cb7609a4 100644 --- a/apps/sim/tools/zendesk/update_organization.ts +++ b/apps/sim/tools/zendesk/update_organization.ts @@ -5,6 +5,7 @@ import { buildZendeskUrl, handleZendeskError } from './types' const logger = createLogger('ZendeskUpdateOrganization') export interface ZendeskUpdateOrganizationParams { + email: string apiToken: string subdomain: string organizationId: string @@ -38,6 +39,12 @@ export const zendeskUpdateOrganizationTool: ToolConfig< version: '1.0.0', params: { + email: { + type: 'string', + required: true, + visibility: 'user-only', + description: 'Your Zendesk email address', + }, apiToken: { type: 'string', required: true, @@ -97,10 +104,14 @@ export const zendeskUpdateOrganizationTool: ToolConfig< request: { url: (params) => buildZendeskUrl(params.subdomain, `/organizations/${params.organizationId}`), method: 'PUT', - headers: (params) => ({ - Authorization: `Bearer ${params.apiToken}`, - 'Content-Type': 'application/json', - }), + headers: (params) => { + const credentials = `${params.email}/token:${params.apiToken}` + const base64Credentials = Buffer.from(credentials).toString('base64') + return { + Authorization: `Basic ${base64Credentials}`, + 'Content-Type': 'application/json', + } + }, body: (params) => { const organization: any = {} diff --git a/apps/sim/tools/zendesk/update_ticket.ts b/apps/sim/tools/zendesk/update_ticket.ts index 4e3368a3ad..08196340c3 100644 --- a/apps/sim/tools/zendesk/update_ticket.ts +++ b/apps/sim/tools/zendesk/update_ticket.ts @@ -5,6 +5,7 @@ import { buildZendeskUrl, handleZendeskError } from './types' const logger = createLogger('ZendeskUpdateTicket') export interface ZendeskUpdateTicketParams { + email: string apiToken: string subdomain: string ticketId: string @@ -41,6 +42,12 @@ export const zendeskUpdateTicketTool: ToolConfig< version: '1.0.0', params: { + email: { + type: 'string', + required: true, + visibility: 'user-only', + description: 'Your Zendesk email address', + }, apiToken: { type: 'string', required: true, @@ -118,10 +125,15 @@ export const zendeskUpdateTicketTool: ToolConfig< request: { url: (params) => buildZendeskUrl(params.subdomain, `/tickets/${params.ticketId}`), method: 'PUT', - headers: (params) => ({ - Authorization: `Bearer ${params.apiToken}`, - 'Content-Type': 'application/json', - }), + headers: (params) => { + // Use Basic Authentication with email/token format for Zendesk API tokens + const credentials = `${params.email}/token:${params.apiToken}` + const base64Credentials = Buffer.from(credentials).toString('base64') + return { + Authorization: `Basic ${base64Credentials}`, + 'Content-Type': 'application/json', + } + }, body: (params) => { const ticket: any = {} diff --git a/apps/sim/tools/zendesk/update_tickets_bulk.ts b/apps/sim/tools/zendesk/update_tickets_bulk.ts index efd2c25b54..19c602855b 100644 --- a/apps/sim/tools/zendesk/update_tickets_bulk.ts +++ b/apps/sim/tools/zendesk/update_tickets_bulk.ts @@ -5,6 +5,7 @@ import { buildZendeskUrl, handleZendeskError } from './types' const logger = createLogger('ZendeskUpdateTicketsBulk') export interface ZendeskUpdateTicketsBulkParams { + email: string apiToken: string subdomain: string ticketIds: string @@ -37,6 +38,12 @@ export const zendeskUpdateTicketsBulkTool: ToolConfig< version: '1.0.0', params: { + email: { + type: 'string', + required: true, + visibility: 'user-only', + description: 'Your Zendesk email address', + }, apiToken: { type: 'string', required: true, @@ -93,10 +100,14 @@ export const zendeskUpdateTicketsBulkTool: ToolConfig< return buildZendeskUrl(params.subdomain, `/tickets/update_many?ids=${ids.join(',')}`) }, method: 'PUT', - headers: (params) => ({ - Authorization: `Bearer ${params.apiToken}`, - 'Content-Type': 'application/json', - }), + headers: (params) => { + const credentials = `${params.email}/token:${params.apiToken}` + const base64Credentials = Buffer.from(credentials).toString('base64') + return { + Authorization: `Basic ${base64Credentials}`, + 'Content-Type': 'application/json', + } + }, body: (params) => { const ticket: any = {} if (params.status) ticket.status = params.status diff --git a/apps/sim/tools/zendesk/update_user.ts b/apps/sim/tools/zendesk/update_user.ts index 12acd62b2c..2e529e0274 100644 --- a/apps/sim/tools/zendesk/update_user.ts +++ b/apps/sim/tools/zendesk/update_user.ts @@ -5,11 +5,12 @@ import { buildZendeskUrl, handleZendeskError } from './types' const logger = createLogger('ZendeskUpdateUser') export interface ZendeskUpdateUserParams { + email: string apiToken: string subdomain: string userId: string name?: string - email?: string + userEmail?: string role?: string phone?: string organizationId?: string @@ -38,6 +39,12 @@ export const zendeskUpdateUserTool: ToolConfig buildZendeskUrl(params.subdomain, `/users/${params.userId}`), method: 'PUT', - headers: (params) => ({ - Authorization: `Bearer ${params.apiToken}`, - 'Content-Type': 'application/json', - }), + headers: (params) => { + const credentials = `${params.email}/token:${params.apiToken}` + const base64Credentials = Buffer.from(credentials).toString('base64') + return { + Authorization: `Basic ${base64Credentials}`, + 'Content-Type': 'application/json', + } + }, body: (params) => { const user: any = {} if (params.name) user.name = params.name - if (params.email) user.email = params.email + if (params.userEmail) user.email = params.userEmail if (params.role) user.role = params.role if (params.phone) user.phone = params.phone if (params.organizationId) user.organization_id = params.organizationId diff --git a/apps/sim/tools/zendesk/update_users_bulk.ts b/apps/sim/tools/zendesk/update_users_bulk.ts index 092ae162ed..bafd9fba08 100644 --- a/apps/sim/tools/zendesk/update_users_bulk.ts +++ b/apps/sim/tools/zendesk/update_users_bulk.ts @@ -5,6 +5,7 @@ import { buildZendeskUrl, handleZendeskError } from './types' const logger = createLogger('ZendeskUpdateUsersBulk') export interface ZendeskUpdateUsersBulkParams { + email: string apiToken: string subdomain: string users: string @@ -32,6 +33,12 @@ export const zendeskUpdateUsersBulkTool: ToolConfig< version: '1.0.0', params: { + email: { + type: 'string', + required: true, + visibility: 'user-only', + description: 'Your Zendesk email address', + }, apiToken: { type: 'string', required: true, @@ -55,10 +62,14 @@ export const zendeskUpdateUsersBulkTool: ToolConfig< request: { url: (params) => buildZendeskUrl(params.subdomain, '/users/update_many'), method: 'PUT', - headers: (params) => ({ - Authorization: `Bearer ${params.apiToken}`, - 'Content-Type': 'application/json', - }), + headers: (params) => { + const credentials = `${params.email}/token:${params.apiToken}` + const base64Credentials = Buffer.from(credentials).toString('base64') + return { + Authorization: `Basic ${base64Credentials}`, + 'Content-Type': 'application/json', + } + }, body: (params) => { try { const users = JSON.parse(params.users) From ed950870c44bb0777f15198f380211d782405c0e Mon Sep 17 00:00:00 2001 From: waleed Date: Thu, 27 Nov 2025 16:28:12 -0800 Subject: [PATCH 3/3] updated docs --- apps/docs/content/docs/en/tools/intercom.mdx | 15 +++++ apps/docs/content/docs/en/tools/mailchimp.mdx | 65 +++++++++---------- apps/docs/content/docs/en/tools/pylon.mdx | 38 +++++++++++ apps/docs/content/docs/en/tools/zendesk.mdx | 55 ++++++++-------- 4 files changed, 114 insertions(+), 59 deletions(-) diff --git a/apps/docs/content/docs/en/tools/intercom.mdx b/apps/docs/content/docs/en/tools/intercom.mdx index 75b42745dd..8e5799ae5b 100644 --- a/apps/docs/content/docs/en/tools/intercom.mdx +++ b/apps/docs/content/docs/en/tools/intercom.mdx @@ -10,6 +10,21 @@ import { BlockInfoCard } from "@/components/ui/block-info-card" color="#E0E0E0" /> +{/* MANUAL-CONTENT-START:intro */} +[Intercom](https://www.intercom.com/) is a leading customer communications platform that enables you to manage and automate your interactions with contacts, companies, conversations, tickets, and messages—all in one place. The Intercom integration in Sim lets your agents programmatically manage customer relationships, support requests, and conversations directly from your automated workflows. + +With the Intercom tools, you can: + +- **Contacts Management:** Create, get, update, list, search, and delete contacts—automate your CRM processes and keep your customer records up-to-date. +- **Company Management:** Create new companies, retrieve company details, and list all companies related to your users or business clients. +- **Conversation Handling:** Get, list, reply to, and search through conversations—allowing agents to track ongoing support threads, provide answers, and automate follow-up actions. +- **Ticket Management:** Create and retrieve tickets programmatically, helping you automate customer service, support issue tracking, and workflow escalations. +- **Send Messages:** Trigger messages to users or leads for onboarding, support, or marketing, all from within your workflow automation. + +By integrating Intercom tools into Sim, you empower your workflows to communicate directly with your users, automate customer support processes, manage leads, and streamline communications at scale. Whether you need to create new contacts, keep customer data synchronized, manage support tickets, or send personalized engagement messages, the Intercom tools provide a comprehensive way to manage customer interactions as part of your intelligent automations. +{/* MANUAL-CONTENT-END */} + + ## Usage Instructions Integrate Intercom into the workflow. Can create, get, update, list, search, and delete contacts; create, get, and list companies; get, list, reply, and search conversations; create and get tickets; and create messages. diff --git a/apps/docs/content/docs/en/tools/mailchimp.mdx b/apps/docs/content/docs/en/tools/mailchimp.mdx index b999e49703..4a5efcb821 100644 --- a/apps/docs/content/docs/en/tools/mailchimp.mdx +++ b/apps/docs/content/docs/en/tools/mailchimp.mdx @@ -11,39 +11,38 @@ import { BlockInfoCard } from "@/components/ui/block-info-card" /> {/* MANUAL-CONTENT-START:intro */} -[Mailchimp](https://mailchimp.com/) is the world's leading email marketing and automation platform that helps businesses connect with their audience through targeted campaigns, automated workflows, and powerful analytics. Its comprehensive API provides complete control over every aspect of email marketing, from audience management to campaign creation and reporting. - -With Mailchimp's extensive integration in Sim, your agents can automate virtually any marketing task programmatically. The Mailchimp integration provides comprehensive access to actions such as: - -- **Audience (List) management**: - - Retrieve audiences and manage list settings (`mailchimp_get_audiences`, `mailchimp_get_audience`) - - Create, update, and delete audiences (`mailchimp_create_audience`, `mailchimp_update_audience`, `mailchimp_delete_audience`) - - Manage audience members with full subscriber lifecycle (`mailchimp_get_members`, `mailchimp_add_member`, `mailchimp_add_or_update_member`, `mailchimp_update_member`, `mailchimp_delete_member`, `mailchimp_archive_member`, `mailchimp_unarchive_member`) -- **Campaign operations**: - - List, create, update, and manage email campaigns (`mailchimp_get_campaigns`, `mailchimp_create_campaign`, `mailchimp_update_campaign`) - - Send, schedule, and unschedule campaigns (`mailchimp_send_campaign`, `mailchimp_schedule_campaign`, `mailchimp_unschedule_campaign`) - - Manage campaign content and replicate successful campaigns (`mailchimp_get_campaign_content`, `mailchimp_set_campaign_content`, `mailchimp_replicate_campaign`) -- **Automation workflows**: - - Manage automated email sequences and triggers (`mailchimp_get_automations`, `mailchimp_get_automation`) - - Start and pause automation workflows (`mailchimp_start_automation`, `mailchimp_pause_automation`) - - Add subscribers to automation workflows (`mailchimp_add_subscriber_to_automation`) -- **Segmentation and targeting**: - - Create and manage audience segments for targeted campaigns (`mailchimp_get_segments`, `mailchimp_create_segment`, `mailchimp_update_segment`) - - Manage segment members (`mailchimp_get_segment_members`, `mailchimp_add_segment_member`, `mailchimp_remove_segment_member`) - - Tag management for flexible subscriber organization (`mailchimp_get_member_tags`, `mailchimp_add_member_tags`, `mailchimp_remove_member_tags`) -- **Template management**: - - Create, update, and manage email templates (`mailchimp_get_templates`, `mailchimp_create_template`, `mailchimp_update_template`) - - Reuse templates across campaigns for consistent branding -- **Advanced features**: - - Merge fields for personalization (`mailchimp_get_merge_fields`, `mailchimp_create_merge_field`) - - Interest categories and interests for subscriber preferences (`mailchimp_get_interest_categories`, `mailchimp_get_interests`, `mailchimp_create_interest_category`) - - Landing pages for lead generation (`mailchimp_get_landing_pages`, `mailchimp_create_landing_page`, `mailchimp_publish_landing_page`) - - Batch operations for bulk updates (`mailchimp_create_batch_operation`) - - Campaign reports and analytics (`mailchimp_get_campaign_reports`, `mailchimp_get_campaign_report`) - -The Mailchimp integration covers all major Marketing API endpoints including audiences (lists), members, campaigns, automation workflows, templates, segments, tags, merge fields, interest categories, landing pages, reports, and batch operations. This enables complete automation of email marketing workflows from subscriber onboarding to campaign execution and performance tracking. - -Whether you need to build automated welcome sequences, sync customer data across platforms, create targeted campaigns, or generate marketing reports, the Mailchimp integration in Sim provides comprehensive control for any email marketing automation need. +[Mailchimp](https://mailchimp.com/) is a powerful marketing automation platform that enables you to manage audiences, campaigns, and a wide range of marketing activities all in one place. Mailchimp’s robust API and integrations let you automate outreach, email marketing, reporting, and audience management directly from your workflows in Sim. + +With the Mailchimp tools in Sim, you can: + +- **Manage Audiences (Lists):** + - List and retrieve all your Mailchimp audiences (lists) for easy management. + - Get comprehensive information about a specific audience. + - Create new audiences and keep your segmentation up-to-date. + +- **List Members:** + - Access and manage list members (subscribers), retrieve member details, and keep your email lists synchronized. + +- **Campaign Management:** + - Automate campaign creation, send campaigns, and analyze campaign performance with comprehensive reporting. + +- **Marketing Automation:** + - Manage automated workflows, set up triggers, and schedule emails to streamline your nurture processes. + +- **Templates, Segments, and Tags:** + - Retrieve and manage your email templates for consistent branding. + - Access and update audience segments to target specific groups. + - Create and manage tags to further organize your contacts. + +- **Advanced List Controls:** + - Manage merge fields and interest categories (groups) to collect rich, structured data from your subscribers. + - Handle landing pages, signup forms, and other lead-capture tools to maximize conversions. + +- **Batch Operations and Reporting:** + - Run batch jobs for bulk operations and streamline large updates. + - Retrieve detailed reports on campaigns, automations, and audience growth to inform your marketing strategy. + +By using Mailchimp within Sim, your agents and workflows can automate email marketing at scale—growing your audience, personalizing outreach, optimizing engagement, and making data-driven decisions. Whether you’re syncing CRM records, triggering campaigns in response to in-product actions, or managing subscriber data, Mailchimp’s tools in Sim deliver complete programmatic control over your marketing automation. {/* MANUAL-CONTENT-END */} diff --git a/apps/docs/content/docs/en/tools/pylon.mdx b/apps/docs/content/docs/en/tools/pylon.mdx index b513e9d02e..ff81223f5d 100644 --- a/apps/docs/content/docs/en/tools/pylon.mdx +++ b/apps/docs/content/docs/en/tools/pylon.mdx @@ -10,6 +10,44 @@ import { BlockInfoCard } from "@/components/ui/block-info-card" color="#E8F4FA" /> +{/* MANUAL-CONTENT-START:intro */} +[Pylon](https://usepylon.com/) is an advanced customer support and success platform designed to help you manage every aspect of your customer relationships—from support issues to accounts, contacts, users, teams, and beyond. Pylon empowers support and success teams to operate efficiently and programmatically with a rich API and comprehensive toolset. + +With Pylon in Sim, you can: + +- **Manage Support Issues:** + - List, create, get, update, and delete support issues for efficient case tracking. + - Search and snooze issues to help agents stay focused and organized. + - Handle issue followers and external issues for seamless collaboration with internal and external stakeholders. + +- **Full Account Management:** + - List, create, get, update, and delete customer accounts. + - Bulk update accounts programmatically. + - Search accounts to quickly find customer information relevant for support or outreach. + +- **Contact Management:** + - List, create, get, update, delete, and search contacts—manage everyone connected to your accounts. + +- **User and Team Operations:** + - List, get, update, and search users in your Pylon workspace. + - List, create, get, and update teams to structure your support organization and workflows. + +- **Tagging and Organization:** + - List, get, create, update, and delete tags for categorizing issues, accounts, or contacts. + +- **Message Handling:** + - Redact sensitive message content directly from your workflows for privacy and compliance. + +By integrating Pylon tools into Sim, your agents can automate every aspect of support operations: +- Automatically open, update, or triage new issues when customer events occur. +- Maintain synchronized account and contact data across your tech stack. +- Route conversations, handle escalations, and organize your support data using tags and teams. +- Ensure sensitive data is properly managed by redacting messages as needed. + +Pylon's endpoints provide granular control for full-lifecycle management of customer issues and relationships. Whether scaling a support desk, powering proactive customer success, or integrating with other systems, Pylon in Sim enables best-in-class CRM automation—securely, flexibly, and at scale. +{/* MANUAL-CONTENT-END */} + + ## Usage Instructions Integrate Pylon into the workflow. Manage issues (list, create, get, update, delete, search, snooze, followers, external issues), accounts (list, create, get, update, delete, bulk update, search), contacts (list, create, get, update, delete, search), users (list, get, update, search), teams (list, get, create, update), tags (list, get, create, update, delete), and messages (redact). diff --git a/apps/docs/content/docs/en/tools/zendesk.mdx b/apps/docs/content/docs/en/tools/zendesk.mdx index e458539b7e..145936ad9a 100644 --- a/apps/docs/content/docs/en/tools/zendesk.mdx +++ b/apps/docs/content/docs/en/tools/zendesk.mdx @@ -11,34 +11,37 @@ import { BlockInfoCard } from "@/components/ui/block-info-card" /> {/* MANUAL-CONTENT-START:intro */} -[Zendesk](https://www.zendesk.com/) is a leading customer service and support platform that enables organizations to efficiently track, prioritize, and solve customer support tickets. Its robust API exposes granular control over all aspects of support, user management, and organizational data, making it a versatile tool for automating business workflows. - -With Zendesk’s rich integration in Sim, your agents can perform nearly any support-related task programmatically. The Zendesk integration provides comprehensive access to actions such as: - -- **Tickets management**: - - Retrieve lists of tickets or a single ticket (`zendesk_get_tickets`, `zendesk_get_ticket`) - - Create a new ticket or multiple tickets in bulk (`zendesk_create_ticket`, `zendesk_create_tickets_bulk`) - - Update a ticket or update multiple tickets at once (`zendesk_update_ticket`, `zendesk_update_tickets_bulk`) - - Delete tickets, merge tickets, and manage ticket lifecycle (`zendesk_delete_ticket`, `zendesk_merge_tickets`) -- **User operations**: - - Fetch all users, get a single user, or get your current Zendesk user (`zendesk_get_users`, `zendesk_get_user`, `zendesk_get_current_user`) - - Search users, create a user, create users in bulk, update users (single or bulk), and delete users (`zendesk_search_users`, `zendesk_create_user`, `zendesk_create_users_bulk`, `zendesk_update_user`, `zendesk_update_users_bulk`, `zendesk_delete_user`) -- **Organization operations**: - - List organizations, get a single organization, or search for organizations (`zendesk_get_organizations`, `zendesk_get_organization`, `zendesk_search_organizations`) - - Create a new organization or multiple at once, update, and delete organizations (`zendesk_create_organization`, `zendesk_create_organizations_bulk`, `zendesk_update_organization`, `zendesk_delete_organization`) -- **Advanced data access and search**: - - Powerful search capabilities across tickets, users, and organizations (`zendesk_search`) - - Count matched results for a search query (`zendesk_search_count`) - - Export search results for reporting or downstream automation (`zendesk_export_search`) - -**Bulk operations** are available for tickets, users, and organizations, allowing you to automate updates or creations at scale. Every major resource (tickets, users, orgs) can be created, listed, updated, deleted, or queried both individually and in batches. - -By leveraging these tools, Sim agents can take complex support scenarios such as onboarding, triage, escalations, ticket merging, and reporting and make them hands-free and fully automated. This enables your workflows to efficiently keep CRM data synchronized, support customers in real-time, and maintain clean, integrated records. - -Whether you need to power support chatbots, automate escalations, sync user databases, or generate cross-system reports, the Zendesk integration in Sim provides granular control for any customer support automation need. +[Zendesk](https://www.zendesk.com/) is a leading customer service and support platform that empowers organizations to efficiently manage support tickets, users, and organizations through a robust set of tools and APIs. The Zendesk integration in Sim lets your agents automate key support operations and synchronize your support data with the rest of your workflow. + +With Zendesk in Sim, you can: + +- **Manage Tickets:** + - Retrieve lists of support tickets with advanced filtering and sorting. + - Get detailed information on a single ticket for tracking and resolution. + - Create new tickets individually or in bulk to log customer issues programmatically. + - Update tickets or apply bulk updates to streamline complex workflows. + - Delete or merge tickets as cases are resolved or duplicates arise. + +- **User Management:** + - Retrieve lists of users or search users by criteria to keep your customer and agent directories up-to-date. + - Get detailed information on individual users or the current logged-in user. + - Create new users or onboard them in bulk, automating customer and agent provisioning. + - Update or bulk update user details to ensure information accuracy. + - Delete users as needed for privacy or account management. + +- **Organization Management:** + - List, search, and autocomplete organizations for streamlined support and account management. + - Get organization details and keep your database organized. + - Create, update, or delete organizations to reflect changes in your customer base. + - Perform bulk organization creation for large onboarding efforts. + +- **Advanced Search & Analytics:** + - Use versatile search endpoints to quickly locate tickets, users, or organizations by any field. + - Retrieve counts of search results to power reporting and analytics. + +By leveraging Zendesk’s Sim integration, your automated workflows can seamlessly handle support ticket triage, user onboarding/offboarding, company management, and keep your support operations running smoothly. Whether you’re integrating support with product, CRM, or automation systems, Zendesk tools in Sim provide robust, programmatic control to power best-in-class support at scale. {/* MANUAL-CONTENT-END */} - ## Usage Instructions Integrate Zendesk into the workflow. Can get tickets, get ticket, create ticket, create tickets bulk, update ticket, update tickets bulk, delete ticket, merge tickets, get users, get user, get current user, search users, create user, create users bulk, update user, update users bulk, delete user, get organizations, get organization, autocomplete organizations, create organization, create organizations bulk, update organization, delete organization, search, search count.