diff --git a/apps/docs/components/icons.tsx b/apps/docs/components/icons.tsx index 1d50d0d068..5eb321929a 100644 --- a/apps/docs/components/icons.tsx +++ b/apps/docs/components/icons.tsx @@ -710,6 +710,17 @@ export function NotionIcon(props: SVGProps) { ) } +export function GongIcon(props: SVGProps) { + return ( + + + + ) +} + export function GmailIcon(props: SVGProps) { return ( ) { return ( diff --git a/apps/docs/components/ui/icon-mapping.ts b/apps/docs/components/ui/icon-mapping.ts index 5929ccca3d..a0e7129090 100644 --- a/apps/docs/components/ui/icon-mapping.ts +++ b/apps/docs/components/ui/icon-mapping.ts @@ -37,9 +37,10 @@ import { EyeIcon, FirecrawlIcon, FirefliesIcon, - GithubIcon, GitLabIcon, + GithubIcon, GmailIcon, + GongIcon, GoogleBooksIcon, GoogleCalendarIcon, GoogleDocsIcon, @@ -70,9 +71,9 @@ import { LinearIcon, LinkedInIcon, LinkupIcon, + MailServerIcon, MailchimpIcon, MailgunIcon, - MailServerIcon, Mem0Icon, MicrosoftDataverseIcon, MicrosoftExcelIcon, @@ -105,6 +106,8 @@ import { ResendIcon, RevenueCatIcon, S3Icon, + SQSIcon, + STTIcon, SalesforceIcon, SearchIcon, SendgridIcon, @@ -116,19 +119,17 @@ import { SimilarwebIcon, SlackIcon, SmtpIcon, - SQSIcon, SshIcon, - STTIcon, StagehandIcon, StripeIcon, SupabaseIcon, + TTSIcon, TavilyIcon, TelegramIcon, TextractIcon, TinybirdIcon, TranslateIcon, TrelloIcon, - TTSIcon, TwilioIcon, TypeformIcon, UpstashIcon, @@ -139,11 +140,11 @@ import { WhatsAppIcon, WikipediaIcon, WordpressIcon, - xIcon, YouTubeIcon, ZendeskIcon, ZepIcon, ZoomIcon, + xIcon, } from '@/components/icons' type IconComponent = ComponentType> @@ -183,6 +184,7 @@ export const blockTypeToIconMap: Record = { github_v2: GithubIcon, gitlab: GitLabIcon, gmail_v2: GmailIcon, + gong: GongIcon, google_books: GoogleBooksIcon, google_calendar_v2: GoogleCalendarIcon, google_docs: GoogleDocsIcon, diff --git a/apps/docs/content/docs/en/tools/gong.mdx b/apps/docs/content/docs/en/tools/gong.mdx new file mode 100644 index 0000000000..34ef1563d6 --- /dev/null +++ b/apps/docs/content/docs/en/tools/gong.mdx @@ -0,0 +1,774 @@ +--- +title: Gong +description: Revenue intelligence and conversation analytics +--- + +import { BlockInfoCard } from "@/components/ui/block-info-card" + + + +{/* MANUAL-CONTENT-START:intro */} +[Gong](https://www.gong.io/) is a revenue intelligence platform that captures and analyzes customer interactions across calls, emails, and meetings. By integrating Gong with Sim, your agents can access conversation data, user analytics, coaching metrics, and more through automated workflows. + +The Gong integration in Sim provides tools to: + +- **List and retrieve calls:** Fetch calls by date range, get individual call details, or retrieve extensive call data including trackers, topics, interaction stats, and points of interest. +- **Access call transcripts:** Retrieve full transcripts with speaker turns, topics, and sentence-level timestamps for any recorded call. +- **Manage users:** List all Gong users in your account or retrieve detailed information for a specific user, including settings, spoken languages, and contact details. +- **Analyze activity and performance:** Pull aggregated activity statistics, interaction stats (longest monologue, interactivity, patience, question rate), and answered scorecard data for your team. +- **Work with scorecards and trackers:** List scorecard definitions and keyword tracker configurations to understand how your team's conversations are being evaluated and monitored. +- **Browse the call library:** List library folders and retrieve their contents, including call snippets and notes curated by your team. +- **Access coaching metrics:** Retrieve coaching data for managers and their direct reports to track team development. +- **List Engage flows:** Fetch sales engagement sequences (flows) with visibility and ownership details. +- **Look up contacts by email or phone:** Find all Gong references to a specific email address or phone number, including related calls, emails, meetings, CRM data, and customer engagement events. + +By combining these capabilities, you can automate sales coaching workflows, extract conversation insights, monitor team performance, sync Gong data with other systems, and build intelligent pipelines around your organization's revenue conversations -- all securely using your Gong API credentials. +{/* MANUAL-CONTENT-END */} + + +## Usage Instructions + +Integrate Gong into your workflow. Access call recordings, transcripts, user data, activity stats, scorecards, trackers, library content, coaching metrics, and more via the Gong API. + + + +## Tools + +### `gong_list_calls` + +Retrieve call data by date range from Gong. + +#### Input + +| Parameter | Type | Required | Description | +| --------- | ---- | -------- | ----------- | +| `accessKey` | string | Yes | Gong API Access Key | +| `accessKeySecret` | string | Yes | Gong API Access Key Secret | +| `fromDateTime` | string | Yes | Start date/time in ISO-8601 format \(e.g., 2024-01-01T00:00:00Z\) | +| `toDateTime` | string | No | End date/time in ISO-8601 format \(e.g., 2024-01-31T23:59:59Z\). If omitted, lists calls up to the most recent. | +| `cursor` | string | No | Pagination cursor from a previous response | +| `workspaceId` | string | No | Gong workspace ID to filter calls | + +#### Output + +| Parameter | Type | Description | +| --------- | ---- | ----------- | +| `calls` | array | List of calls matching the date range | +| ↳ `id` | string | Gong's unique numeric identifier for the call | +| ↳ `title` | string | Call title | +| ↳ `scheduled` | string | Scheduled call time in ISO-8601 format | +| ↳ `started` | string | Recording start time in ISO-8601 format | +| ↳ `duration` | number | Call duration in seconds | +| ↳ `direction` | string | Call direction \(Inbound/Outbound\) | +| ↳ `system` | string | Communication platform used \(e.g., Outreach\) | +| ↳ `scope` | string | Call scope: 'Internal', 'External', or 'Unknown' | +| ↳ `media` | string | Media type \(e.g., Video\) | +| ↳ `language` | string | Language code in ISO-639-2B format | +| ↳ `url` | string | URL to the call in the Gong web app | +| ↳ `primaryUserId` | string | Host team member identifier | +| ↳ `workspaceId` | string | Workspace identifier | +| ↳ `sdrDisposition` | string | SDR disposition classification | +| ↳ `clientUniqueId` | string | Call identifier from the origin recording system | +| ↳ `customData` | string | Metadata provided during call creation | +| ↳ `purpose` | string | Call purpose | +| ↳ `meetingUrl` | string | Web conference provider URL | +| ↳ `isPrivate` | boolean | Whether the call is private | +| ↳ `calendarEventId` | string | Calendar event identifier | +| `cursor` | string | Pagination cursor for the next page | +| `totalRecords` | number | Total number of records matching the filter | + +### `gong_get_call` + +Retrieve detailed data for a specific call from Gong. + +#### Input + +| Parameter | Type | Required | Description | +| --------- | ---- | -------- | ----------- | +| `accessKey` | string | Yes | Gong API Access Key | +| `accessKeySecret` | string | Yes | Gong API Access Key Secret | +| `callId` | string | Yes | The Gong call ID to retrieve | + +#### Output + +| Parameter | Type | Description | +| --------- | ---- | ----------- | +| `id` | string | Gong's unique numeric identifier for the call | +| `title` | string | Call title | +| `url` | string | URL to the call in the Gong web app | +| `scheduled` | string | Scheduled call time in ISO-8601 format | +| `started` | string | Recording start time in ISO-8601 format | +| `duration` | number | Call duration in seconds | +| `direction` | string | Call direction \(Inbound/Outbound\) | +| `system` | string | Communication platform used \(e.g., Outreach\) | +| `scope` | string | Call scope: 'Internal', 'External', or 'Unknown' | +| `media` | string | Media type \(e.g., Video\) | +| `language` | string | Language code in ISO-639-2B format | +| `primaryUserId` | string | Host team member identifier | +| `workspaceId` | string | Workspace identifier | +| `sdrDisposition` | string | SDR disposition classification | +| `clientUniqueId` | string | Call identifier from the origin recording system | +| `customData` | string | Metadata provided during call creation | +| `purpose` | string | Call purpose | +| `meetingUrl` | string | Web conference provider URL | +| `isPrivate` | boolean | Whether the call is private | +| `calendarEventId` | string | Calendar event identifier | + +### `gong_get_call_transcript` + +Retrieve transcripts of calls from Gong by call IDs or date range. + +#### Input + +| Parameter | Type | Required | Description | +| --------- | ---- | -------- | ----------- | +| `accessKey` | string | Yes | Gong API Access Key | +| `accessKeySecret` | string | Yes | Gong API Access Key Secret | +| `callIds` | string | No | Comma-separated list of call IDs to retrieve transcripts for | +| `fromDateTime` | string | No | Start date/time filter in ISO-8601 format | +| `toDateTime` | string | No | End date/time filter in ISO-8601 format | +| `workspaceId` | string | No | Gong workspace ID to filter calls | +| `cursor` | string | No | Pagination cursor from a previous response | + +#### Output + +| Parameter | Type | Description | +| --------- | ---- | ----------- | +| `callTranscripts` | array | List of call transcripts with speaker turns and sentences | +| ↳ `callId` | string | Gong's unique numeric identifier for the call | +| ↳ `transcript` | array | List of monologues in the call | +| ↳ `speakerId` | string | Unique ID of the speaker, cross-reference with parties | +| ↳ `topic` | string | Name of the topic being discussed | +| ↳ `sentences` | array | List of sentences spoken in the monologue | +| ↳ `start` | number | Start time of the sentence in milliseconds from call start | +| ↳ `end` | number | End time of the sentence in milliseconds from call start | +| ↳ `text` | string | The sentence text | +| `cursor` | string | Pagination cursor for the next page | + +### `gong_get_extensive_calls` + +Retrieve detailed call data including trackers, topics, and highlights from Gong. + +#### Input + +| Parameter | Type | Required | Description | +| --------- | ---- | -------- | ----------- | +| `accessKey` | string | Yes | Gong API Access Key | +| `accessKeySecret` | string | Yes | Gong API Access Key Secret | +| `callIds` | string | No | Comma-separated list of call IDs to retrieve detailed data for | +| `fromDateTime` | string | No | Start date/time filter in ISO-8601 format | +| `toDateTime` | string | No | End date/time filter in ISO-8601 format | +| `workspaceId` | string | No | Gong workspace ID to filter calls | +| `primaryUserIds` | string | No | Comma-separated list of user IDs to filter calls by host | +| `cursor` | string | No | Pagination cursor from a previous response | + +#### Output + +| Parameter | Type | Description | +| --------- | ---- | ----------- | +| `calls` | array | List of detailed call objects with metadata, content, interaction stats, and collaboration data | +| ↳ `metaData` | object | Call metadata \(same fields as CallBasicData\) | +| ↳ `id` | string | Call ID | +| ↳ `title` | string | Call title | +| ↳ `scheduled` | string | Scheduled time in ISO-8601 | +| ↳ `started` | string | Start time in ISO-8601 | +| ↳ `duration` | number | Duration in seconds | +| ↳ `direction` | string | Call direction | +| ↳ `system` | string | Communication platform | +| ↳ `scope` | string | Internal/External/Unknown | +| ↳ `media` | string | Media type | +| ↳ `language` | string | Language code \(ISO-639-2B\) | +| ↳ `url` | string | Gong web app URL | +| ↳ `primaryUserId` | string | Host user ID | +| ↳ `workspaceId` | string | Workspace ID | +| ↳ `sdrDisposition` | string | SDR disposition | +| ↳ `clientUniqueId` | string | Origin system call ID | +| ↳ `customData` | string | Custom metadata | +| ↳ `purpose` | string | Call purpose | +| ↳ `meetingUrl` | string | Meeting URL | +| ↳ `isPrivate` | boolean | Whether call is private | +| ↳ `calendarEventId` | string | Calendar event ID | +| ↳ `context` | array | Links to external systems \(CRM, Dialer, etc.\) | +| ↳ `system` | string | External system name \(e.g., Salesforce\) | +| ↳ `objects` | array | List of objects within the external system | +| ↳ `parties` | array | List of call participants | +| ↳ `id` | string | Unique participant ID in the call | +| ↳ `name` | string | Participant name | +| ↳ `emailAddress` | string | Email address | +| ↳ `title` | string | Job title | +| ↳ `phoneNumber` | string | Phone number | +| ↳ `speakerId` | string | Speaker ID for transcript cross-reference | +| ↳ `userId` | string | Gong user ID | +| ↳ `affiliation` | string | Company or non-company | +| ↳ `methods` | array | Whether invited or attended | +| ↳ `context` | array | Links to external systems for this party | +| ↳ `content` | object | Call content data | +| ↳ `structure` | array | Call agenda parts | +| ↳ `name` | string | Agenda name | +| ↳ `duration` | number | Duration of this part in seconds | +| ↳ `topics` | array | Topics and their durations | +| ↳ `name` | string | Topic name \(e.g., Pricing\) | +| ↳ `duration` | number | Time spent on topic in seconds | +| ↳ `trackers` | array | Trackers found in the call | +| ↳ `id` | string | Tracker ID | +| ↳ `name` | string | Tracker name | +| ↳ `count` | number | Number of occurrences | +| ↳ `type` | string | Keyword or Smart | +| ↳ `occurrences` | array | Details for each occurrence | +| ↳ `speakerId` | string | Speaker who said it | +| ↳ `startTime` | number | Seconds from call start | +| ↳ `phrases` | array | Per-phrase occurrence counts | +| ↳ `phrase` | string | Specific phrase | +| ↳ `count` | number | Occurrences of this phrase | +| ↳ `occurrences` | array | Details per occurrence | +| ↳ `highlights` | array | AI-generated highlights including next steps, action items, and key moments | +| ↳ `title` | string | Title of the highlight | +| ↳ `interaction` | object | Interaction statistics | +| ↳ `interactionStats` | array | Interaction stats per user | +| ↳ `userId` | string | Gong user ID | +| ↳ `userEmailAddress` | string | User email | +| ↳ `personInteractionStats` | array | Stats list \(Longest Monologue, Interactivity, Patience, etc.\) | +| ↳ `name` | string | Stat name | +| ↳ `value` | number | Stat value | +| ↳ `speakers` | array | Talk duration per speaker | +| ↳ `id` | string | Participant ID | +| ↳ `userId` | string | Gong user ID | +| ↳ `talkTime` | number | Talk duration in seconds | +| ↳ `video` | array | Video statistics | +| ↳ `name` | string | Segment type: Browser, Presentation, WebcamPrimaryUser, WebcamNonCompany, Webcam | +| ↳ `duration` | number | Total segment duration in seconds | +| ↳ `questions` | object | Question counts | +| ↳ `companyCount` | number | Questions by company speakers | +| ↳ `nonCompanyCount` | number | Questions by non-company speakers | +| ↳ `collaboration` | object | Collaboration data | +| ↳ `publicComments` | array | Public comments on the call | +| ↳ `id` | string | Comment ID | +| ↳ `commenterUserId` | string | Commenter user ID | +| ↳ `comment` | string | Comment text | +| ↳ `posted` | string | Posted time in ISO-8601 | +| ↳ `audioStartTime` | number | Seconds from call start the comment refers to | +| ↳ `audioEndTime` | number | Seconds from call start the comment end refers to | +| ↳ `duringCall` | boolean | Whether the comment was posted during the call | +| ↳ `inReplyTo` | string | ID of original comment if this is a reply | +| ↳ `media` | object | Media download URLs \(available for 8 hours\) | +| ↳ `audioUrl` | string | Audio download URL | +| ↳ `videoUrl` | string | Video download URL | +| `cursor` | string | Pagination cursor for the next page | + +### `gong_list_users` + +List all users in your Gong account. + +#### Input + +| Parameter | Type | Required | Description | +| --------- | ---- | -------- | ----------- | +| `accessKey` | string | Yes | Gong API Access Key | +| `accessKeySecret` | string | Yes | Gong API Access Key Secret | +| `cursor` | string | No | Pagination cursor from a previous response | +| `includeAvatars` | string | No | Whether to include avatar URLs \(true/false\) | + +#### Output + +| Parameter | Type | Description | +| --------- | ---- | ----------- | +| `users` | array | List of Gong users | +| ↳ `id` | string | Unique numeric user ID \(up to 20 digits\) | +| ↳ `emailAddress` | string | User email address | +| ↳ `created` | string | User creation timestamp \(ISO-8601\) | +| ↳ `active` | boolean | Whether the user is active | +| ↳ `emailAliases` | array | Alternative email addresses for the user | +| ↳ `trustedEmailAddress` | string | Trusted email address for the user | +| ↳ `firstName` | string | First name | +| ↳ `lastName` | string | Last name | +| ↳ `title` | string | Job title | +| ↳ `phoneNumber` | string | Phone number | +| ↳ `extension` | string | Phone extension number | +| ↳ `personalMeetingUrls` | array | Personal meeting URLs | +| ↳ `settings` | object | User settings | +| ↳ `webConferencesRecorded` | boolean | Whether web conferences are recorded | +| ↳ `preventWebConferenceRecording` | boolean | Whether web conference recording is prevented | +| ↳ `telephonyCallsImported` | boolean | Whether telephony calls are imported | +| ↳ `emailsImported` | boolean | Whether emails are imported | +| ↳ `preventEmailImport` | boolean | Whether email import is prevented | +| ↳ `nonRecordedMeetingsImported` | boolean | Whether non-recorded meetings are imported | +| ↳ `gongConnectEnabled` | boolean | Whether Gong Connect is enabled | +| ↳ `managerId` | string | Manager user ID | +| ↳ `meetingConsentPageUrl` | string | Meeting consent page URL | +| ↳ `spokenLanguages` | array | Languages spoken by the user | +| ↳ `language` | string | Language code | +| ↳ `primary` | boolean | Whether this is the primary language | +| `cursor` | string | Pagination cursor for the next page | +| `totalRecords` | number | Total number of user records | +| `currentPageSize` | number | Number of records in the current page | +| `currentPageNumber` | number | Current page number | + +### `gong_get_user` + +Retrieve details for a specific user from Gong. + +#### Input + +| Parameter | Type | Required | Description | +| --------- | ---- | -------- | ----------- | +| `accessKey` | string | Yes | Gong API Access Key | +| `accessKeySecret` | string | Yes | Gong API Access Key Secret | +| `userId` | string | Yes | The Gong user ID to retrieve | + +#### Output + +| Parameter | Type | Description | +| --------- | ---- | ----------- | +| `id` | string | Unique numeric user ID \(up to 20 digits\) | +| `emailAddress` | string | User email address | +| `created` | string | User creation timestamp \(ISO-8601\) | +| `active` | boolean | Whether the user is active | +| `emailAliases` | array | Alternative email addresses for the user | +| `trustedEmailAddress` | string | Trusted email address for the user | +| `firstName` | string | First name | +| `lastName` | string | Last name | +| `title` | string | Job title | +| `phoneNumber` | string | Phone number | +| `extension` | string | Phone extension number | +| `personalMeetingUrls` | array | Personal meeting URLs | +| `settings` | object | User settings | +| ↳ `webConferencesRecorded` | boolean | Whether web conferences are recorded | +| ↳ `preventWebConferenceRecording` | boolean | Whether web conference recording is prevented | +| ↳ `telephonyCallsImported` | boolean | Whether telephony calls are imported | +| ↳ `emailsImported` | boolean | Whether emails are imported | +| ↳ `preventEmailImport` | boolean | Whether email import is prevented | +| ↳ `nonRecordedMeetingsImported` | boolean | Whether non-recorded meetings are imported | +| ↳ `gongConnectEnabled` | boolean | Whether Gong Connect is enabled | +| `managerId` | string | Manager user ID | +| `meetingConsentPageUrl` | string | Meeting consent page URL | +| `spokenLanguages` | array | Languages spoken by the user | +| ↳ `language` | string | Language code | +| ↳ `primary` | boolean | Whether this is the primary language | + +### `gong_aggregate_activity` + +Retrieve aggregated activity statistics for users by date range from Gong. + +#### Input + +| Parameter | Type | Required | Description | +| --------- | ---- | -------- | ----------- | +| `accessKey` | string | Yes | Gong API Access Key | +| `accessKeySecret` | string | Yes | Gong API Access Key Secret | +| `userIds` | string | No | Comma-separated list of Gong user IDs \(up to 20 digits each\) | +| `fromDate` | string | Yes | Start date in YYYY-MM-DD format \(inclusive, in company timezone\) | +| `toDate` | string | Yes | End date in YYYY-MM-DD format \(exclusive, in company timezone, cannot exceed current day\) | +| `cursor` | string | No | Pagination cursor from a previous response | + +#### Output + +| Parameter | Type | Description | +| --------- | ---- | ----------- | +| `usersActivity` | array | Aggregated activity statistics per user | +| ↳ `userId` | string | Gong's unique numeric identifier for the user | +| ↳ `userEmailAddress` | string | Email address of the Gong user | +| ↳ `callsAsHost` | number | Number of recorded calls this user hosted | +| ↳ `callsAttended` | number | Number of calls where this user was a participant \(not host\) | +| ↳ `callsGaveFeedback` | number | Number of recorded calls the user gave feedback on | +| ↳ `callsReceivedFeedback` | number | Number of recorded calls the user received feedback on | +| ↳ `callsRequestedFeedback` | number | Number of recorded calls the user requested feedback on | +| ↳ `callsScorecardsFilled` | number | Number of scorecards the user completed | +| ↳ `callsScorecardsReceived` | number | Number of calls where someone filled a scorecard on the user's calls | +| ↳ `ownCallsListenedTo` | number | Number of the user's own calls the user listened to | +| ↳ `othersCallsListenedTo` | number | Number of other users' calls the user listened to | +| ↳ `callsSharedInternally` | number | Number of calls the user shared internally | +| ↳ `callsSharedExternally` | number | Number of calls the user shared externally | +| ↳ `callsCommentsGiven` | number | Number of calls where the user provided at least one comment | +| ↳ `callsCommentsReceived` | number | Number of calls where the user received at least one comment | +| ↳ `callsMarkedAsFeedbackGiven` | number | Number of calls where the user selected Mark as reviewed | +| ↳ `callsMarkedAsFeedbackReceived` | number | Number of calls where others selected Mark as reviewed on the user's calls | +| `timeZone` | string | The company's defined timezone in Gong | +| `fromDateTime` | string | Start of results in ISO-8601 format | +| `toDateTime` | string | End of results in ISO-8601 format | +| `cursor` | string | Pagination cursor for the next page | + +### `gong_interaction_stats` + +Retrieve interaction statistics for users by date range from Gong. Only includes calls with Whisper enabled. + +#### Input + +| Parameter | Type | Required | Description | +| --------- | ---- | -------- | ----------- | +| `accessKey` | string | Yes | Gong API Access Key | +| `accessKeySecret` | string | Yes | Gong API Access Key Secret | +| `userIds` | string | No | Comma-separated list of Gong user IDs \(up to 20 digits each\) | +| `fromDate` | string | Yes | Start date in YYYY-MM-DD format \(inclusive, in company timezone\) | +| `toDate` | string | Yes | End date in YYYY-MM-DD format \(exclusive, in company timezone, cannot exceed current day\) | +| `cursor` | string | No | Pagination cursor from a previous response | + +#### Output + +| Parameter | Type | Description | +| --------- | ---- | ----------- | +| `peopleInteractionStats` | array | Email address of the Gong user | +| ↳ `userId` | string | Gong's unique numeric identifier for the user | +| ↳ `userEmailAddress` | string | Email address of the Gong user | +| ↳ `personInteractionStats` | array | List of interaction stat measurements for this user | +| ↳ `name` | string | Stat name \(e.g. Longest Monologue, Interactivity, Patience, Question Rate\) | +| ↳ `value` | number | Stat measurement value \(can be double or integer\) | +| `timeZone` | string | The company's defined timezone in Gong | +| `fromDateTime` | string | Start of results in ISO-8601 format | +| `toDateTime` | string | End of results in ISO-8601 format | +| `cursor` | string | Pagination cursor for the next page | + +### `gong_answered_scorecards` + +Retrieve answered scorecards for reviewed users or by date range from Gong. + +#### Input + +| Parameter | Type | Required | Description | +| --------- | ---- | -------- | ----------- | +| `accessKey` | string | Yes | Gong API Access Key | +| `accessKeySecret` | string | Yes | Gong API Access Key Secret | +| `callFromDate` | string | No | Start date for calls in YYYY-MM-DD format \(inclusive, in company timezone\). Defaults to earliest recorded call. | +| `callToDate` | string | No | End date for calls in YYYY-MM-DD format \(exclusive, in company timezone\). Defaults to latest recorded call. | +| `reviewFromDate` | string | No | Start date for reviews in YYYY-MM-DD format \(inclusive, in company timezone\). Defaults to earliest reviewed call. | +| `reviewToDate` | string | No | End date for reviews in YYYY-MM-DD format \(exclusive, in company timezone\). Defaults to latest reviewed call. | +| `scorecardIds` | string | No | Comma-separated list of scorecard IDs to filter by | +| `reviewedUserIds` | string | No | Comma-separated list of reviewed user IDs to filter by | +| `cursor` | string | No | Pagination cursor from a previous response | + +#### Output + +| Parameter | Type | Description | +| --------- | ---- | ----------- | +| `answeredScorecards` | array | List of answered scorecards with scores and answers | +| ↳ `answeredScorecardId` | number | Identifier of the answered scorecard | +| ↳ `scorecardId` | number | Identifier of the scorecard | +| ↳ `scorecardName` | string | Scorecard name | +| ↳ `callId` | number | Gong's unique numeric identifier for the call | +| ↳ `callStartTime` | string | Date/time of the call in ISO-8601 format | +| ↳ `reviewedUserId` | number | User ID of the team member being reviewed | +| ↳ `reviewerUserId` | number | User ID of the team member who completed the scorecard | +| ↳ `reviewTime` | string | Date/time when the review was completed in ISO-8601 format | +| ↳ `visibilityType` | string | Visibility type of the scorecard answer | +| ↳ `answers` | array | Answers in the answered scorecard | +| ↳ `questionId` | number | Identifier of the question | +| ↳ `questionRevisionId` | number | Identifier of the revision version of the question | +| ↳ `isOverall` | boolean | Whether this is the overall question | +| ↳ `score` | number | Score between 1 to 5 if answered, null otherwise | +| ↳ `answerText` | string | The answer's text if answered, null otherwise | +| ↳ `notApplicable` | boolean | Whether the question is not applicable to this call | +| `cursor` | string | Pagination cursor for the next page | + +### `gong_list_library_folders` + +Retrieve library folders from Gong. + +#### Input + +| Parameter | Type | Required | Description | +| --------- | ---- | -------- | ----------- | +| `accessKey` | string | Yes | Gong API Access Key | +| `accessKeySecret` | string | Yes | Gong API Access Key Secret | +| `workspaceId` | string | No | Gong workspace ID to filter folders | + +#### Output + +| Parameter | Type | Description | +| --------- | ---- | ----------- | +| `folders` | array | List of library folders with id, name, and parent relationships | +| ↳ `id` | string | Gong unique numeric identifier for the folder | +| ↳ `name` | string | Display name of the folder | +| ↳ `parentFolderId` | string | Gong unique numeric identifier for the parent folder \(null for root folder\) | +| ↳ `createdBy` | string | Gong unique numeric identifier for the user who added the folder | +| ↳ `updated` | string | Folder's last update time in ISO-8601 format | + +### `gong_get_folder_content` + +Retrieve the list of calls in a specific library folder from Gong. + +#### Input + +| Parameter | Type | Required | Description | +| --------- | ---- | -------- | ----------- | +| `accessKey` | string | Yes | Gong API Access Key | +| `accessKeySecret` | string | Yes | Gong API Access Key Secret | +| `folderId` | string | Yes | The library folder ID to retrieve content for | + +#### Output + +| Parameter | Type | Description | +| --------- | ---- | ----------- | +| `folderId` | string | Gong's unique numeric identifier for the folder | +| `folderName` | string | Display name of the folder | +| `createdBy` | string | Gong's unique numeric identifier for the user who added the folder | +| `updated` | string | Folder's last update time in ISO-8601 format | +| `calls` | array | List of calls in the library folder | +| ↳ `id` | string | Gong unique numeric identifier of the call | +| ↳ `title` | string | The title of the call | +| ↳ `note` | string | A note attached to the call in the folder | +| ↳ `addedBy` | string | Gong unique numeric identifier for the user who added the call | +| ↳ `created` | string | Date and time the call was added to folder in ISO-8601 format | +| ↳ `url` | string | URL of the call | +| ↳ `snippet` | object | Call snippet time range | +| ↳ `fromSec` | number | Snippet start in seconds relative to call start | +| ↳ `toSec` | number | Snippet end in seconds relative to call start | + +### `gong_list_scorecards` + +Retrieve scorecard definitions from Gong settings. + +#### Input + +| Parameter | Type | Required | Description | +| --------- | ---- | -------- | ----------- | +| `accessKey` | string | Yes | Gong API Access Key | +| `accessKeySecret` | string | Yes | Gong API Access Key Secret | + +#### Output + +| Parameter | Type | Description | +| --------- | ---- | ----------- | +| `scorecards` | array | List of scorecard definitions with questions | +| ↳ `scorecardId` | string | Unique identifier for the scorecard | +| ↳ `scorecardName` | string | Display name of the scorecard | +| ↳ `workspaceId` | string | Workspace identifier associated with this scorecard | +| ↳ `enabled` | boolean | Whether the scorecard is active | +| ↳ `updaterUserId` | string | ID of the user who last modified the scorecard | +| ↳ `created` | string | Creation timestamp in ISO-8601 format | +| ↳ `updated` | string | Last update timestamp in ISO-8601 format | +| ↳ `questions` | array | List of questions in the scorecard | +| ↳ `questionId` | string | Unique identifier for the question | +| ↳ `questionText` | string | The text content of the question | +| ↳ `questionRevisionId` | string | Identifier for the specific revision of the question | +| ↳ `isOverall` | boolean | Whether this is the primary overall question | +| ↳ `created` | string | Question creation timestamp in ISO-8601 format | +| ↳ `updated` | string | Question last update timestamp in ISO-8601 format | +| ↳ `updaterUserId` | string | ID of the user who last modified the question | + +### `gong_list_trackers` + +Retrieve smart tracker and keyword tracker definitions from Gong settings. + +#### Input + +| Parameter | Type | Required | Description | +| --------- | ---- | -------- | ----------- | +| `accessKey` | string | Yes | Gong API Access Key | +| `accessKeySecret` | string | Yes | Gong API Access Key Secret | +| `workspaceId` | string | No | The ID of the workspace the keyword trackers are in. When empty, all trackers in all workspaces are returned. | + +#### Output + +| Parameter | Type | Description | +| --------- | ---- | ----------- | +| `trackers` | array | List of keyword tracker definitions | +| ↳ `trackerId` | string | Unique identifier for the tracker | +| ↳ `trackerName` | string | Display name of the tracker | +| ↳ `workspaceId` | string | ID of the workspace containing the tracker | +| ↳ `languageKeywords` | array | Keywords organized by language | +| ↳ `language` | string | ISO 639-2/B language code \("mul" means keywords apply across all languages\) | +| ↳ `keywords` | array | Words and phrases in the designated language | +| ↳ `includeRelatedForms` | boolean | Whether to include different word forms | +| ↳ `affiliation` | string | Speaker affiliation filter: "Anyone", "Company", or "NonCompany" | +| ↳ `partOfQuestion` | boolean | Whether to track keywords only within questions | +| ↳ `saidAt` | string | Position in call: "Anytime", "First", or "Last" | +| ↳ `saidAtInterval` | number | Duration to search \(in minutes or percentage\) | +| ↳ `saidAtUnit` | string | Unit for saidAtInterval | +| ↳ `saidInTopics` | array | Topics where keywords should be detected | +| ↳ `saidInCallParts` | array | Specific call segments to monitor | +| ↳ `filterQuery` | string | JSON-formatted call filtering criteria | +| ↳ `created` | string | Creation timestamp in ISO-8601 format | +| ↳ `creatorUserId` | string | ID of the user who created the tracker \(null for built-in trackers\) | +| ↳ `updated` | string | Last modification timestamp in ISO-8601 format | +| ↳ `updaterUserId` | string | ID of the user who last modified the tracker | + +### `gong_list_workspaces` + +List all company workspaces in Gong. + +#### Input + +| Parameter | Type | Required | Description | +| --------- | ---- | -------- | ----------- | +| `accessKey` | string | Yes | Gong API Access Key | +| `accessKeySecret` | string | Yes | Gong API Access Key Secret | + +#### Output + +| Parameter | Type | Description | +| --------- | ---- | ----------- | +| `workspaces` | array | List of Gong workspaces | +| ↳ `id` | string | Gong unique numeric identifier for the workspace | +| ↳ `name` | string | Display name of the workspace | +| ↳ `description` | string | Description of the workspace's purpose or content | + +### `gong_list_flows` + +List Gong Engage flows (sales engagement sequences). + +#### Input + +| Parameter | Type | Required | Description | +| --------- | ---- | -------- | ----------- | +| `accessKey` | string | Yes | Gong API Access Key | +| `accessKeySecret` | string | Yes | Gong API Access Key Secret | +| `flowOwnerEmail` | string | Yes | Email of a Gong user. The API will return 'PERSONAL' flows belonging to this user in addition to 'COMPANY' flows. | +| `workspaceId` | string | No | Optional workspace ID to filter flows to a specific workspace | +| `cursor` | string | No | Pagination cursor from a previous API call to retrieve the next page of records | + +#### Output + +| Parameter | Type | Description | +| --------- | ---- | ----------- | +| `requestId` | string | A Gong request reference ID for troubleshooting purposes | +| `flows` | array | List of Gong Engage flows | +| ↳ `id` | string | The ID of the flow | +| ↳ `name` | string | The name of the flow | +| ↳ `folderId` | string | The ID of the folder this flow is under | +| ↳ `folderName` | string | The name of the folder this flow is under | +| ↳ `visibility` | string | The flow visibility type \(COMPANY, PERSONAL, or SHARED\) | +| ↳ `creationDate` | string | Creation time of the flow in ISO-8601 format | +| ↳ `exclusive` | boolean | Indicates whether a prospect in this flow can be added to other flows | +| `totalRecords` | number | Total number of flow records available | +| `currentPageSize` | number | Number of records returned in the current page | +| `currentPageNumber` | number | Current page number | +| `cursor` | string | Pagination cursor for retrieving the next page of records | + +### `gong_get_coaching` + +Retrieve coaching metrics for a manager from Gong. + +#### Input + +| Parameter | Type | Required | Description | +| --------- | ---- | -------- | ----------- | +| `accessKey` | string | Yes | Gong API Access Key | +| `accessKeySecret` | string | Yes | Gong API Access Key Secret | +| `managerId` | string | Yes | Gong user ID of the manager | +| `workspaceId` | string | Yes | Gong workspace ID | +| `fromDate` | string | Yes | Start date in ISO-8601 format | +| `toDate` | string | Yes | End date in ISO-8601 format | + +#### Output + +| Parameter | Type | Description | +| --------- | ---- | ----------- | +| `requestId` | string | A Gong request reference ID for troubleshooting purposes | +| `coachingData` | array | The manager user information | +| ↳ `manager` | object | The manager user information | +| ↳ `id` | string | Gong unique numeric identifier for the user | +| ↳ `emailAddress` | string | Email address of the Gong user | +| ↳ `firstName` | string | First name of the Gong user | +| ↳ `lastName` | string | Last name of the Gong user | +| ↳ `title` | string | Job title of the Gong user | +| ↳ `directReportsMetrics` | array | Coaching metrics for each direct report | +| ↳ `report` | object | The direct report user information | +| ↳ `id` | string | Gong unique numeric identifier for the user | +| ↳ `emailAddress` | string | Email address of the Gong user | +| ↳ `firstName` | string | First name of the Gong user | +| ↳ `lastName` | string | Last name of the Gong user | +| ↳ `title` | string | Job title of the Gong user | +| ↳ `metrics` | json | A map of metric names to arrays of string values representing coaching metrics | + +### `gong_lookup_email` + +Find all references to an email address in Gong (calls, email messages, meetings, CRM data, engagement). + +#### Input + +| Parameter | Type | Required | Description | +| --------- | ---- | -------- | ----------- | +| `accessKey` | string | Yes | Gong API Access Key | +| `accessKeySecret` | string | Yes | Gong API Access Key Secret | +| `emailAddress` | string | Yes | Email address to look up | + +#### Output + +| Parameter | Type | Description | +| --------- | ---- | ----------- | +| `requestId` | string | Gong request reference ID for troubleshooting | +| `calls` | array | Related calls referencing this email address | +| ↳ `id` | string | Gong's unique numeric identifier for the call \(up to 20 digits\) | +| ↳ `status` | string | Call status | +| ↳ `externalSystems` | array | Links to external systems such as CRM, Telephony System, etc. | +| ↳ `system` | string | External system name | +| ↳ `objects` | array | List of objects within the external system | +| ↳ `objectType` | string | Object type | +| ↳ `externalId` | string | External ID | +| `emails` | array | Related email messages referencing this email address | +| ↳ `id` | string | Gong's unique 32 character identifier for the email message | +| ↳ `from` | string | The sender's email address | +| ↳ `sentTime` | string | Date and time the email was sent in ISO-8601 format | +| ↳ `mailbox` | string | The mailbox from which the email was retrieved | +| ↳ `messageHash` | string | Hash code of the email message | +| `meetings` | array | Related meetings referencing this email address | +| ↳ `id` | string | Gong's unique identifier for the meeting | +| `customerData` | array | Links to data from external systems \(CRM, Telephony, etc.\) that reference this email | +| ↳ `system` | string | External system name | +| ↳ `objects` | array | List of objects in the external system | +| ↳ `id` | string | Gong's unique numeric identifier for the Lead or Contact \(up to 20 digits\) | +| ↳ `objectType` | string | Object type | +| ↳ `externalId` | string | External ID | +| ↳ `mirrorId` | string | CRM Mirror ID | +| ↳ `fields` | array | Object fields | +| ↳ `name` | string | Field name | +| ↳ `value` | json | Field value | +| `customerEngagement` | array | Customer engagement events \(such as viewing external shared calls\) | +| ↳ `eventType` | string | Event type | +| ↳ `eventName` | string | Event name | +| ↳ `timestamp` | string | Date and time the event occurred in ISO-8601 format | +| ↳ `contentId` | string | Event content ID | +| ↳ `contentUrl` | string | Event content URL | +| ↳ `reportingSystem` | string | Event reporting system | +| ↳ `sourceEventId` | string | Source event ID | + +### `gong_lookup_phone` + +Find all references to a phone number in Gong (calls, email messages, meetings, CRM data, and associated contacts). + +#### Input + +| Parameter | Type | Required | Description | +| --------- | ---- | -------- | ----------- | +| `accessKey` | string | Yes | Gong API Access Key | +| `accessKeySecret` | string | Yes | Gong API Access Key Secret | +| `phoneNumber` | string | Yes | Phone number to look up \(must start with + followed by country code\) | + +#### Output + +| Parameter | Type | Description | +| --------- | ---- | ----------- | +| `requestId` | string | Gong request reference ID for troubleshooting | +| `suppliedPhoneNumber` | string | The phone number that was supplied in the request | +| `matchingPhoneNumbers` | array | Phone numbers found in the system that match the supplied number | +| `emailAddresses` | array | Email addresses associated with the phone number | +| `calls` | array | Related calls referencing this phone number | +| ↳ `id` | string | Gong's unique numeric identifier for the call \(up to 20 digits\) | +| ↳ `status` | string | Call status | +| ↳ `externalSystems` | array | Links to external systems such as CRM, Telephony System, etc. | +| ↳ `system` | string | External system name | +| ↳ `objects` | array | List of objects within the external system | +| ↳ `objectType` | string | Object type | +| ↳ `externalId` | string | External ID | +| `emails` | array | Related email messages associated with contacts matching this phone number | +| ↳ `id` | string | Gong's unique 32 character identifier for the email message | +| ↳ `from` | string | The sender's email address | +| ↳ `sentTime` | string | Date and time the email was sent in ISO-8601 format | +| ↳ `mailbox` | string | The mailbox from which the email was retrieved | +| ↳ `messageHash` | string | Hash code of the email message | +| `meetings` | array | Related meetings associated with this phone number | +| ↳ `id` | string | Gong's unique identifier for the meeting | +| `customerData` | array | Links to data from external systems \(CRM, Telephony, etc.\) that reference this phone number | +| ↳ `system` | string | External system name | +| ↳ `objects` | array | List of objects in the external system | +| ↳ `id` | string | Gong's unique numeric identifier for the Lead or Contact \(up to 20 digits\) | +| ↳ `objectType` | string | Object type | +| ↳ `externalId` | string | External ID | +| ↳ `mirrorId` | string | CRM Mirror ID | +| ↳ `fields` | array | Object fields | +| ↳ `name` | string | Field name | +| ↳ `value` | json | Field value | + + diff --git a/apps/docs/content/docs/en/tools/hex.mdx b/apps/docs/content/docs/en/tools/hex.mdx index c979333847..28e2a18647 100644 --- a/apps/docs/content/docs/en/tools/hex.mdx +++ b/apps/docs/content/docs/en/tools/hex.mdx @@ -7,7 +7,7 @@ import { BlockInfoCard } from "@/components/ui/block-info-card" {/* MANUAL-CONTENT-START:intro */} diff --git a/apps/docs/content/docs/en/tools/meta.json b/apps/docs/content/docs/en/tools/meta.json index 3a3a1cc16d..b933326cea 100644 --- a/apps/docs/content/docs/en/tools/meta.json +++ b/apps/docs/content/docs/en/tools/meta.json @@ -35,6 +35,7 @@ "github", "gitlab", "gmail", + "gong", "google_books", "google_calendar", "google_docs", @@ -144,4 +145,4 @@ "zep", "zoom" ] -} +} \ No newline at end of file diff --git a/apps/sim/blocks/blocks/gong.ts b/apps/sim/blocks/blocks/gong.ts new file mode 100644 index 0000000000..5623efe408 --- /dev/null +++ b/apps/sim/blocks/blocks/gong.ts @@ -0,0 +1,569 @@ +import { GongIcon } from '@/components/icons' +import { AuthMode, type BlockConfig } from '@/blocks/types' +import type { GongResponse } from '@/tools/gong/types' + +export const GongBlock: BlockConfig = { + type: 'gong', + name: 'Gong', + description: 'Revenue intelligence and conversation analytics', + authMode: AuthMode.ApiKey, + longDescription: + 'Integrate Gong into your workflow. Access call recordings, transcripts, user data, activity stats, scorecards, trackers, library content, coaching metrics, and more via the Gong API.', + docsLink: 'https://docs.sim.ai/tools/gong', + category: 'tools', + bgColor: '#8039DF', + icon: GongIcon, + subBlocks: [ + { + id: 'operation', + title: 'Operation', + type: 'dropdown', + options: [ + { label: 'List Calls', id: 'list_calls' }, + { label: 'Get Call', id: 'get_call' }, + { label: 'Get Call Transcript', id: 'get_call_transcript' }, + { label: 'Get Extensive Calls', id: 'get_extensive_calls' }, + { label: 'List Users', id: 'list_users' }, + { label: 'Get User', id: 'get_user' }, + { label: 'Aggregate Activity', id: 'aggregate_activity' }, + { label: 'Interaction Stats', id: 'interaction_stats' }, + { label: 'Answered Scorecards', id: 'answered_scorecards' }, + { label: 'List Library Folders', id: 'list_library_folders' }, + { label: 'Get Folder Content', id: 'get_folder_content' }, + { label: 'List Scorecards', id: 'list_scorecards' }, + { label: 'List Trackers', id: 'list_trackers' }, + { label: 'List Workspaces', id: 'list_workspaces' }, + { label: 'List Flows', id: 'list_flows' }, + { label: 'Get Coaching', id: 'get_coaching' }, + { label: 'Lookup Email', id: 'lookup_email' }, + { label: 'Lookup Phone', id: 'lookup_phone' }, + ], + value: () => 'list_calls', + }, + + // List Calls inputs + { + id: 'fromDateTime', + title: 'From Date/Time', + type: 'short-input', + placeholder: '2024-01-01T00:00:00Z', + condition: { + field: 'operation', + value: ['list_calls'], + }, + required: { field: 'operation', value: 'list_calls' }, + wandConfig: { + enabled: true, + prompt: `Generate an ISO 8601 timestamp based on the user's description. +The timestamp should be in the format: YYYY-MM-DDTHH:MM:SSZ (UTC timezone). +Examples: +- "today" -> Today's date at 00:00:00Z +- "beginning of this week" -> Monday of the current week at 00:00:00Z +- "start of month" -> First day of current month at 00:00:00Z +- "last week" -> 7 days ago at 00:00:00Z + +Return ONLY the timestamp string in ISO 8601 format - no explanations, no quotes, no extra text.`, + placeholder: 'Describe the start time (e.g., "beginning of last month")...', + generationType: 'timestamp', + }, + }, + { + id: 'toDateTime', + title: 'To Date/Time', + type: 'short-input', + placeholder: '2024-01-31T23:59:59Z', + condition: { + field: 'operation', + value: ['list_calls'], + }, + mode: 'advanced', + wandConfig: { + enabled: true, + prompt: `Generate an ISO 8601 timestamp based on the user's description. +The timestamp should be in the format: YYYY-MM-DDTHH:MM:SSZ (UTC timezone). +Examples: +- "now" -> Current date and time in UTC +- "end of this week" -> Sunday of the current week at 23:59:59Z +- "end of month" -> Last day of current month at 23:59:59Z +- "yesterday" -> Yesterday at 23:59:59Z + +Return ONLY the timestamp string in ISO 8601 format - no explanations, no quotes, no extra text.`, + placeholder: 'Describe the end time (e.g., "end of last month")...', + generationType: 'timestamp', + }, + }, + + // Get Call inputs + { + id: 'callId', + title: 'Call ID', + type: 'short-input', + placeholder: 'Enter the Gong call ID', + condition: { field: 'operation', value: 'get_call' }, + required: { field: 'operation', value: 'get_call' }, + }, + + // Get Call Transcript / Get Extensive Calls inputs + { + id: 'callIds', + title: 'Call IDs', + type: 'short-input', + placeholder: 'Comma-separated call IDs (optional)', + condition: { field: 'operation', value: ['get_call_transcript', 'get_extensive_calls'] }, + }, + { + id: 'transcriptFromDateTime', + title: 'From Date/Time', + type: 'short-input', + placeholder: '2024-01-01T00:00:00Z (optional)', + condition: { field: 'operation', value: ['get_call_transcript', 'get_extensive_calls'] }, + mode: 'advanced', + wandConfig: { + enabled: true, + prompt: `Generate an ISO 8601 timestamp based on the user's description. +The timestamp should be in the format: YYYY-MM-DDTHH:MM:SSZ (UTC timezone). +Examples: +- "today" -> Today's date at 00:00:00Z +- "beginning of this week" -> Monday of the current week at 00:00:00Z +- "start of month" -> First day of current month at 00:00:00Z + +Return ONLY the timestamp string in ISO 8601 format - no explanations, no quotes, no extra text.`, + placeholder: 'Describe the start time (e.g., "start of last week")...', + generationType: 'timestamp', + }, + }, + { + id: 'transcriptToDateTime', + title: 'To Date/Time', + type: 'short-input', + placeholder: '2024-01-31T23:59:59Z (optional)', + condition: { field: 'operation', value: ['get_call_transcript', 'get_extensive_calls'] }, + mode: 'advanced', + wandConfig: { + enabled: true, + prompt: `Generate an ISO 8601 timestamp based on the user's description. +The timestamp should be in the format: YYYY-MM-DDTHH:MM:SSZ (UTC timezone). +Examples: +- "now" -> Current date and time in UTC +- "end of this week" -> Sunday of the current week at 23:59:59Z +- "end of month" -> Last day of current month at 23:59:59Z + +Return ONLY the timestamp string in ISO 8601 format - no explanations, no quotes, no extra text.`, + placeholder: 'Describe the end time (e.g., "end of last week")...', + generationType: 'timestamp', + }, + }, + { + id: 'primaryUserIds', + title: 'Primary User IDs', + type: 'short-input', + placeholder: 'Comma-separated user IDs (optional)', + condition: { field: 'operation', value: 'get_extensive_calls' }, + mode: 'advanced', + }, + + // List Users inputs + { + id: 'includeAvatars', + title: 'Include Avatars', + type: 'dropdown', + options: [ + { label: 'No', id: 'false' }, + { label: 'Yes', id: 'true' }, + ], + value: () => 'false', + condition: { field: 'operation', value: 'list_users' }, + mode: 'advanced', + }, + + // Get User inputs + { + id: 'userId', + title: 'User ID', + type: 'short-input', + placeholder: 'Enter the Gong user ID', + condition: { field: 'operation', value: 'get_user' }, + required: { field: 'operation', value: 'get_user' }, + }, + + // Aggregate Activity & Interaction Stats inputs + { + id: 'statsFromDate', + title: 'From Date', + type: 'short-input', + placeholder: '2024-01-01 (YYYY-MM-DD, inclusive)', + condition: { field: 'operation', value: ['aggregate_activity', 'interaction_stats'] }, + required: { field: 'operation', value: ['aggregate_activity', 'interaction_stats'] }, + wandConfig: { + enabled: true, + prompt: `Generate a date string in YYYY-MM-DD format based on the user's description. +Examples: +- "today" -> Today's date +- "beginning of this month" -> First day of current month +- "start of last quarter" -> First day of the previous quarter +- "30 days ago" -> Date 30 days in the past + +Return ONLY the date string in YYYY-MM-DD format - no explanations, no quotes, no extra text.`, + placeholder: 'Describe the start date (e.g., "beginning of last month")...', + generationType: 'timestamp', + }, + }, + { + id: 'statsToDate', + title: 'To Date', + type: 'short-input', + placeholder: '2024-01-31 (YYYY-MM-DD, exclusive)', + condition: { field: 'operation', value: ['aggregate_activity', 'interaction_stats'] }, + required: { field: 'operation', value: ['aggregate_activity', 'interaction_stats'] }, + wandConfig: { + enabled: true, + prompt: `Generate a date string in YYYY-MM-DD format based on the user's description. +The date is exclusive (results up to but not including this date). +Examples: +- "today" -> Today's date +- "end of this month" -> First day of next month +- "end of last quarter" -> First day of current quarter + +Return ONLY the date string in YYYY-MM-DD format - no explanations, no quotes, no extra text.`, + placeholder: 'Describe the end date (e.g., "end of last month")...', + generationType: 'timestamp', + }, + }, + { + id: 'userIds', + title: 'User IDs', + type: 'short-input', + placeholder: 'Comma-separated user IDs (optional)', + condition: { field: 'operation', value: ['aggregate_activity', 'interaction_stats'] }, + mode: 'advanced', + }, + + // Answered Scorecards inputs + { + id: 'callFromDate', + title: 'Call From Date', + type: 'short-input', + placeholder: '2024-01-01 (YYYY-MM-DD, optional)', + condition: { field: 'operation', value: 'answered_scorecards' }, + wandConfig: { + enabled: true, + prompt: `Generate a date string in YYYY-MM-DD format based on the user's description. +Examples: +- "today" -> Today's date +- "beginning of this month" -> First day of current month +- "start of last quarter" -> First day of the previous quarter + +Return ONLY the date string in YYYY-MM-DD format - no explanations, no quotes, no extra text.`, + placeholder: 'Describe the call start date...', + generationType: 'timestamp', + }, + }, + { + id: 'callToDate', + title: 'Call To Date', + type: 'short-input', + placeholder: '2024-01-31 (YYYY-MM-DD, optional)', + condition: { field: 'operation', value: 'answered_scorecards' }, + wandConfig: { + enabled: true, + prompt: `Generate a date string in YYYY-MM-DD format based on the user's description. +Examples: +- "today" -> Today's date +- "end of this month" -> First day of next month + +Return ONLY the date string in YYYY-MM-DD format - no explanations, no quotes, no extra text.`, + placeholder: 'Describe the call end date...', + generationType: 'timestamp', + }, + }, + { + id: 'reviewFromDate', + title: 'Review From Date', + type: 'short-input', + placeholder: '2024-01-01 (YYYY-MM-DD, optional)', + condition: { field: 'operation', value: 'answered_scorecards' }, + mode: 'advanced', + wandConfig: { + enabled: true, + prompt: `Generate a date string in YYYY-MM-DD format based on the user's description. +Return ONLY the date string in YYYY-MM-DD format - no explanations, no quotes, no extra text.`, + placeholder: 'Describe the review start date...', + generationType: 'timestamp', + }, + }, + { + id: 'reviewToDate', + title: 'Review To Date', + type: 'short-input', + placeholder: '2024-01-31 (YYYY-MM-DD, optional)', + condition: { field: 'operation', value: 'answered_scorecards' }, + mode: 'advanced', + wandConfig: { + enabled: true, + prompt: `Generate a date string in YYYY-MM-DD format based on the user's description. +Return ONLY the date string in YYYY-MM-DD format - no explanations, no quotes, no extra text.`, + placeholder: 'Describe the review end date...', + generationType: 'timestamp', + }, + }, + { + id: 'scorecardIds', + title: 'Scorecard IDs', + type: 'short-input', + placeholder: 'Comma-separated scorecard IDs (optional)', + condition: { field: 'operation', value: 'answered_scorecards' }, + mode: 'advanced', + }, + { + id: 'reviewedUserIds', + title: 'Reviewed User IDs', + type: 'short-input', + placeholder: 'Comma-separated user IDs (optional)', + condition: { field: 'operation', value: 'answered_scorecards' }, + mode: 'advanced', + }, + + // Get Folder Content inputs + { + id: 'folderId', + title: 'Folder ID', + type: 'short-input', + placeholder: 'Enter the library folder ID', + condition: { field: 'operation', value: 'get_folder_content' }, + required: { field: 'operation', value: 'get_folder_content' }, + }, + + // Workspace ID (shared by multiple operations) + { + id: 'workspaceId', + title: 'Workspace ID', + type: 'short-input', + placeholder: 'Gong workspace ID (optional)', + condition: { + field: 'operation', + value: [ + 'list_calls', + 'get_call_transcript', + 'get_extensive_calls', + 'list_library_folders', + 'list_flows', + 'list_trackers', + ], + }, + mode: 'advanced', + }, + + // List Flows inputs + { + id: 'flowOwnerEmail', + title: 'Flow Owner Email', + type: 'short-input', + placeholder: 'user@example.com', + condition: { field: 'operation', value: 'list_flows' }, + required: { field: 'operation', value: 'list_flows' }, + }, + + // Get Coaching inputs + { + id: 'managerId', + title: 'Manager ID', + type: 'short-input', + placeholder: 'Manager user ID', + condition: { field: 'operation', value: 'get_coaching' }, + required: { field: 'operation', value: 'get_coaching' }, + }, + { + id: 'coachingWorkspaceId', + title: 'Workspace ID', + type: 'short-input', + placeholder: 'Gong workspace ID', + condition: { field: 'operation', value: 'get_coaching' }, + required: { field: 'operation', value: 'get_coaching' }, + }, + { + id: 'coachingFromDate', + title: 'From Date', + type: 'short-input', + placeholder: '2024-01-01T00:00:00Z', + condition: { field: 'operation', value: 'get_coaching' }, + required: { field: 'operation', value: 'get_coaching' }, + wandConfig: { + enabled: true, + prompt: `Generate an ISO 8601 timestamp based on the user's description. +The timestamp should be in the format: YYYY-MM-DDTHH:MM:SSZ (UTC timezone). +Examples: +- "today" -> Today's date at 00:00:00Z +- "beginning of this month" -> First day of current month at 00:00:00Z +- "start of last quarter" -> First day of the previous quarter at 00:00:00Z + +Return ONLY the timestamp string in ISO 8601 format - no explanations, no quotes, no extra text.`, + placeholder: 'Describe the start time (e.g., "beginning of last month")...', + generationType: 'timestamp', + }, + }, + { + id: 'coachingToDate', + title: 'To Date', + type: 'short-input', + placeholder: '2024-01-31T23:59:59Z', + condition: { field: 'operation', value: 'get_coaching' }, + required: { field: 'operation', value: 'get_coaching' }, + wandConfig: { + enabled: true, + prompt: `Generate an ISO 8601 timestamp based on the user's description. +The timestamp should be in the format: YYYY-MM-DDTHH:MM:SSZ (UTC timezone). +Examples: +- "now" -> Current date and time in UTC +- "end of this month" -> Last day of current month at 23:59:59Z +- "end of last quarter" -> Last day of the previous quarter at 23:59:59Z + +Return ONLY the timestamp string in ISO 8601 format - no explanations, no quotes, no extra text.`, + placeholder: 'Describe the end time (e.g., "end of last month")...', + generationType: 'timestamp', + }, + }, + + // Lookup Email inputs + { + id: 'emailAddress', + title: 'Email Address', + type: 'short-input', + placeholder: 'user@example.com', + condition: { field: 'operation', value: 'lookup_email' }, + required: { field: 'operation', value: 'lookup_email' }, + }, + + // Lookup Phone inputs + { + id: 'phoneNumber', + title: 'Phone Number', + type: 'short-input', + placeholder: '+1234567890', + condition: { field: 'operation', value: 'lookup_phone' }, + required: { field: 'operation', value: 'lookup_phone' }, + }, + + // Pagination cursor (shared) + { + id: 'cursor', + title: 'Cursor', + type: 'short-input', + placeholder: 'Pagination cursor (optional)', + condition: { + field: 'operation', + value: [ + 'list_calls', + 'get_call_transcript', + 'get_extensive_calls', + 'list_users', + 'aggregate_activity', + 'interaction_stats', + 'answered_scorecards', + 'list_flows', + ], + }, + mode: 'advanced', + }, + + // API credentials + { + id: 'accessKey', + title: 'Access Key', + type: 'short-input', + placeholder: 'Enter your Gong API access key', + password: true, + required: true, + }, + { + id: 'accessKeySecret', + title: 'Access Key Secret', + type: 'short-input', + placeholder: 'Enter your Gong API access key secret', + password: true, + required: true, + }, + ], + tools: { + access: [ + 'gong_list_calls', + 'gong_get_call', + 'gong_get_call_transcript', + 'gong_get_extensive_calls', + 'gong_list_users', + 'gong_get_user', + 'gong_aggregate_activity', + 'gong_interaction_stats', + 'gong_answered_scorecards', + 'gong_list_library_folders', + 'gong_get_folder_content', + 'gong_list_scorecards', + 'gong_list_trackers', + 'gong_list_workspaces', + 'gong_list_flows', + 'gong_get_coaching', + 'gong_lookup_email', + 'gong_lookup_phone', + ], + config: { + tool: (params) => `gong_${params.operation}`, + params: (params) => { + const result: Record = {} + // Map operation-specific subBlock IDs to tool param names + if (params.transcriptFromDateTime) result.fromDateTime = params.transcriptFromDateTime + if (params.transcriptToDateTime) result.toDateTime = params.transcriptToDateTime + if (params.statsFromDate) result.fromDate = params.statsFromDate + if (params.statsToDate) result.toDate = params.statsToDate + if (params.callFromDate) result.callFromDate = params.callFromDate + if (params.callToDate) result.callToDate = params.callToDate + if (params.reviewFromDate) result.reviewFromDate = params.reviewFromDate + if (params.reviewToDate) result.reviewToDate = params.reviewToDate + if (params.coachingWorkspaceId) result.workspaceId = params.coachingWorkspaceId + if (params.coachingFromDate) result.fromDate = params.coachingFromDate + if (params.coachingToDate) result.toDate = params.coachingToDate + return result + }, + }, + }, + inputs: { + operation: { type: 'string', description: 'Operation to perform' }, + accessKey: { type: 'string', description: 'Gong API Access Key' }, + accessKeySecret: { type: 'string', description: 'Gong API Access Key Secret' }, + fromDateTime: { + type: 'string', + description: 'Start date/time in ISO-8601 format (list calls)', + }, + toDateTime: { type: 'string', description: 'End date/time in ISO-8601 format (list calls)' }, + callId: { type: 'string', description: 'Gong call ID' }, + callIds: { type: 'string', description: 'Comma-separated call IDs' }, + userId: { type: 'string', description: 'Gong user ID' }, + userIds: { type: 'string', description: 'Comma-separated user IDs' }, + statsFromDate: { type: 'string', description: 'Start date in YYYY-MM-DD format (stats)' }, + statsToDate: { type: 'string', description: 'End date in YYYY-MM-DD format (stats)' }, + callFromDate: { type: 'string', description: 'Call start date in YYYY-MM-DD (scorecards)' }, + callToDate: { type: 'string', description: 'Call end date in YYYY-MM-DD (scorecards)' }, + reviewFromDate: { type: 'string', description: 'Review start date in YYYY-MM-DD (scorecards)' }, + reviewToDate: { type: 'string', description: 'Review end date in YYYY-MM-DD (scorecards)' }, + scorecardIds: { type: 'string', description: 'Comma-separated scorecard IDs' }, + reviewedUserIds: { type: 'string', description: 'Comma-separated reviewed user IDs' }, + primaryUserIds: { + type: 'string', + description: 'Comma-separated primary user IDs (extensive calls)', + }, + folderId: { type: 'string', description: 'Library folder ID' }, + workspaceId: { type: 'string', description: 'Gong workspace ID' }, + managerId: { type: 'string', description: 'Manager user ID for coaching' }, + flowOwnerEmail: { + type: 'string', + description: 'Email of a Gong user to retrieve personal and company flows', + }, + emailAddress: { type: 'string', description: 'Email address to look up' }, + phoneNumber: { type: 'string', description: 'Phone number to look up' }, + cursor: { type: 'string', description: 'Pagination cursor' }, + }, + outputs: { + response: { + type: 'json', + description: 'Gong API response data', + }, + }, +} diff --git a/apps/sim/blocks/blocks/hex.ts b/apps/sim/blocks/blocks/hex.ts index db902fff48..f3ea6a2cb8 100644 --- a/apps/sim/blocks/blocks/hex.ts +++ b/apps/sim/blocks/blocks/hex.ts @@ -11,7 +11,7 @@ export const HexBlock: BlockConfig = { 'Integrate Hex into your workflow. Run projects, check run status, manage collections and groups, list users, and view data connections. Requires a Hex API token.', docsLink: 'https://docs.sim.ai/tools/hex', category: 'tools', - bgColor: '#F5E6FF', + bgColor: '#14151A', icon: HexIcon, authMode: AuthMode.ApiKey, diff --git a/apps/sim/blocks/registry.ts b/apps/sim/blocks/registry.ts index 70b9e915bf..abc25f764f 100644 --- a/apps/sim/blocks/registry.ts +++ b/apps/sim/blocks/registry.ts @@ -40,6 +40,7 @@ import { GenericWebhookBlock } from '@/blocks/blocks/generic_webhook' import { GitHubBlock, GitHubV2Block } from '@/blocks/blocks/github' import { GitLabBlock } from '@/blocks/blocks/gitlab' import { GmailBlock, GmailV2Block } from '@/blocks/blocks/gmail' +import { GongBlock } from '@/blocks/blocks/gong' import { GoogleSearchBlock } from '@/blocks/blocks/google' import { GoogleBooksBlock } from '@/blocks/blocks/google_books' import { GoogleCalendarBlock, GoogleCalendarV2Block } from '@/blocks/blocks/google_calendar' @@ -231,6 +232,7 @@ export const registry: Record = { google_forms: GoogleFormsBlock, google_groups: GoogleGroupsBlock, google_maps: GoogleMapsBlock, + gong: GongBlock, google_search: GoogleSearchBlock, google_sheets: GoogleSheetsBlock, google_sheets_v2: GoogleSheetsV2Block, diff --git a/apps/sim/components/icons.tsx b/apps/sim/components/icons.tsx index 1d50d0d068..5eb321929a 100644 --- a/apps/sim/components/icons.tsx +++ b/apps/sim/components/icons.tsx @@ -710,6 +710,17 @@ export function NotionIcon(props: SVGProps) { ) } +export function GongIcon(props: SVGProps) { + return ( + + + + ) +} + export function GmailIcon(props: SVGProps) { return ( ) { return ( diff --git a/apps/sim/tools/gong/aggregate_activity.ts b/apps/sim/tools/gong/aggregate_activity.ts new file mode 100644 index 0000000000..d0c3388b0e --- /dev/null +++ b/apps/sim/tools/gong/aggregate_activity.ts @@ -0,0 +1,204 @@ +import type { GongAggregateActivityParams, GongAggregateActivityResponse } from '@/tools/gong/types' +import type { ToolConfig } from '@/tools/types' + +export const aggregateActivityTool: ToolConfig< + GongAggregateActivityParams, + GongAggregateActivityResponse +> = { + id: 'gong_aggregate_activity', + name: 'Gong Aggregate Activity', + description: 'Retrieve aggregated activity statistics for users by date range from Gong.', + version: '1.0.0', + + params: { + accessKey: { + type: 'string', + required: true, + visibility: 'user-only', + description: 'Gong API Access Key', + }, + accessKeySecret: { + type: 'string', + required: true, + visibility: 'user-only', + description: 'Gong API Access Key Secret', + }, + userIds: { + type: 'string', + required: false, + visibility: 'user-or-llm', + description: 'Comma-separated list of Gong user IDs (up to 20 digits each)', + }, + fromDate: { + type: 'string', + required: true, + visibility: 'user-or-llm', + description: 'Start date in YYYY-MM-DD format (inclusive, in company timezone)', + }, + toDate: { + type: 'string', + required: true, + visibility: 'user-or-llm', + description: + 'End date in YYYY-MM-DD format (exclusive, in company timezone, cannot exceed current day)', + }, + cursor: { + type: 'string', + required: false, + visibility: 'user-or-llm', + description: 'Pagination cursor from a previous response', + }, + }, + + request: { + url: 'https://api.gong.io/v2/stats/activity/aggregate', + method: 'POST', + headers: (params) => ({ + 'Content-Type': 'application/json', + Authorization: `Basic ${btoa(`${params.accessKey}:${params.accessKeySecret}`)}`, + }), + body: (params) => { + const filter: Record = { + fromDate: params.fromDate, + toDate: params.toDate, + } + if (params.userIds) { + filter.userIds = params.userIds.split(',').map((id) => id.trim()) + } + const body: Record = { filter } + if (params.cursor) body.cursor = params.cursor + return body + }, + }, + + transformResponse: async (response: Response) => { + const data = await response.json() + if (!response.ok) { + throw new Error( + data.errors?.[0]?.message || data.message || 'Failed to get aggregate activity' + ) + } + const usersActivity = (data.usersAggregateActivityStats ?? []).map( + (ua: Record) => { + const stats = (ua.userAggregateActivityStats ?? {}) as Record + return { + userId: ua.userId ?? '', + userEmailAddress: ua.userEmailAddress ?? null, + callsAsHost: stats.callsAsHost ?? null, + callsAttended: stats.callsAttended ?? null, + callsGaveFeedback: stats.callsGaveFeedback ?? null, + callsReceivedFeedback: stats.callsReceivedFeedback ?? null, + callsRequestedFeedback: stats.callsRequestedFeedback ?? null, + callsScorecardsFilled: stats.callsScorecardsFilled ?? null, + callsScorecardsReceived: stats.callsScorecardsReceived ?? null, + ownCallsListenedTo: stats.ownCallsListenedTo ?? null, + othersCallsListenedTo: stats.othersCallsListenedTo ?? null, + callsSharedInternally: stats.callsSharedInternally ?? null, + callsSharedExternally: stats.callsSharedExternally ?? null, + callsCommentsGiven: stats.callsCommentsGiven ?? null, + callsCommentsReceived: stats.callsCommentsReceived ?? null, + callsMarkedAsFeedbackGiven: stats.callsMarkedAsFeedbackGiven ?? null, + callsMarkedAsFeedbackReceived: stats.callsMarkedAsFeedbackReceived ?? null, + } + } + ) + return { + success: true, + output: { + usersActivity, + timeZone: data.timeZone ?? null, + fromDateTime: data.fromDateTime ?? null, + toDateTime: data.toDateTime ?? null, + cursor: data.records?.cursor ?? null, + }, + } + }, + + outputs: { + usersActivity: { + type: 'array', + description: 'Aggregated activity statistics per user', + items: { + type: 'object', + properties: { + userId: { type: 'string', description: "Gong's unique numeric identifier for the user" }, + userEmailAddress: { type: 'string', description: 'Email address of the Gong user' }, + callsAsHost: { type: 'number', description: 'Number of recorded calls this user hosted' }, + callsAttended: { + type: 'number', + description: 'Number of calls where this user was a participant (not host)', + }, + callsGaveFeedback: { + type: 'number', + description: 'Number of recorded calls the user gave feedback on', + }, + callsReceivedFeedback: { + type: 'number', + description: 'Number of recorded calls the user received feedback on', + }, + callsRequestedFeedback: { + type: 'number', + description: 'Number of recorded calls the user requested feedback on', + }, + callsScorecardsFilled: { + type: 'number', + description: 'Number of scorecards the user completed', + }, + callsScorecardsReceived: { + type: 'number', + description: "Number of calls where someone filled a scorecard on the user's calls", + }, + ownCallsListenedTo: { + type: 'number', + description: "Number of the user's own calls the user listened to", + }, + othersCallsListenedTo: { + type: 'number', + description: "Number of other users' calls the user listened to", + }, + callsSharedInternally: { + type: 'number', + description: 'Number of calls the user shared internally', + }, + callsSharedExternally: { + type: 'number', + description: 'Number of calls the user shared externally', + }, + callsCommentsGiven: { + type: 'number', + description: 'Number of calls where the user provided at least one comment', + }, + callsCommentsReceived: { + type: 'number', + description: 'Number of calls where the user received at least one comment', + }, + callsMarkedAsFeedbackGiven: { + type: 'number', + description: 'Number of calls where the user selected Mark as reviewed', + }, + callsMarkedAsFeedbackReceived: { + type: 'number', + description: + "Number of calls where others selected Mark as reviewed on the user's calls", + }, + }, + }, + }, + timeZone: { + type: 'string', + description: "The company's defined timezone in Gong", + }, + fromDateTime: { + type: 'string', + description: 'Start of results in ISO-8601 format', + }, + toDateTime: { + type: 'string', + description: 'End of results in ISO-8601 format', + }, + cursor: { + type: 'string', + description: 'Pagination cursor for the next page', + }, + }, +} diff --git a/apps/sim/tools/gong/answered_scorecards.ts b/apps/sim/tools/gong/answered_scorecards.ts new file mode 100644 index 0000000000..a37899477d --- /dev/null +++ b/apps/sim/tools/gong/answered_scorecards.ts @@ -0,0 +1,210 @@ +import type { + GongAnsweredScorecardsParams, + GongAnsweredScorecardsResponse, +} from '@/tools/gong/types' +import type { ToolConfig } from '@/tools/types' + +export const answeredScorecardsTool: ToolConfig< + GongAnsweredScorecardsParams, + GongAnsweredScorecardsResponse +> = { + id: 'gong_answered_scorecards', + name: 'Gong Answered Scorecards', + description: 'Retrieve answered scorecards for reviewed users or by date range from Gong.', + version: '1.0.0', + + params: { + accessKey: { + type: 'string', + required: true, + visibility: 'user-only', + description: 'Gong API Access Key', + }, + accessKeySecret: { + type: 'string', + required: true, + visibility: 'user-only', + description: 'Gong API Access Key Secret', + }, + callFromDate: { + type: 'string', + required: false, + visibility: 'user-or-llm', + description: + 'Start date for calls in YYYY-MM-DD format (inclusive, in company timezone). Defaults to earliest recorded call.', + }, + callToDate: { + type: 'string', + required: false, + visibility: 'user-or-llm', + description: + 'End date for calls in YYYY-MM-DD format (exclusive, in company timezone). Defaults to latest recorded call.', + }, + reviewFromDate: { + type: 'string', + required: false, + visibility: 'user-or-llm', + description: + 'Start date for reviews in YYYY-MM-DD format (inclusive, in company timezone). Defaults to earliest reviewed call.', + }, + reviewToDate: { + type: 'string', + required: false, + visibility: 'user-or-llm', + description: + 'End date for reviews in YYYY-MM-DD format (exclusive, in company timezone). Defaults to latest reviewed call.', + }, + scorecardIds: { + type: 'string', + required: false, + visibility: 'user-or-llm', + description: 'Comma-separated list of scorecard IDs to filter by', + }, + reviewedUserIds: { + type: 'string', + required: false, + visibility: 'user-or-llm', + description: 'Comma-separated list of reviewed user IDs to filter by', + }, + cursor: { + type: 'string', + required: false, + visibility: 'user-or-llm', + description: 'Pagination cursor from a previous response', + }, + }, + + request: { + url: 'https://api.gong.io/v2/stats/activity/scorecards', + method: 'POST', + headers: (params) => ({ + 'Content-Type': 'application/json', + Authorization: `Basic ${btoa(`${params.accessKey}:${params.accessKeySecret}`)}`, + }), + body: (params) => { + const filter: Record = {} + if (params.callFromDate) filter.callFromDate = params.callFromDate + if (params.callToDate) filter.callToDate = params.callToDate + if (params.reviewFromDate) filter.reviewFromDate = params.reviewFromDate + if (params.reviewToDate) filter.reviewToDate = params.reviewToDate + if (params.scorecardIds) { + filter.scorecardIds = params.scorecardIds.split(',').map((id) => id.trim()) + } + if (params.reviewedUserIds) { + filter.reviewedUserIds = params.reviewedUserIds.split(',').map((id) => id.trim()) + } + const body: Record = { filter } + if (params.cursor) body.cursor = params.cursor + return body + }, + }, + + transformResponse: async (response: Response) => { + const data = await response.json() + if (!response.ok) { + throw new Error( + data.errors?.[0]?.message || data.message || 'Failed to get answered scorecards' + ) + } + const answeredScorecards = (data.answeredScorecards ?? []).map( + (sc: Record) => ({ + answeredScorecardId: sc.answeredScorecardId ?? 0, + scorecardId: sc.scorecardId ?? null, + scorecardName: sc.scorecardName ?? null, + callId: sc.callId ?? null, + callStartTime: sc.callStartTime ?? null, + reviewedUserId: sc.reviewedUserId ?? null, + reviewerUserId: sc.reviewerUserId ?? null, + reviewTime: sc.reviewTime ?? null, + visibilityType: sc.visibilityType ?? null, + answers: ((sc.answers as Record[]) ?? []).map( + (answer: Record) => ({ + questionId: answer.questionId ?? null, + questionRevisionId: answer.questionRevisionId ?? null, + isOverall: answer.isOverall ?? null, + score: answer.score ?? null, + answerText: answer.answerText ?? null, + notApplicable: answer.notApplicable ?? null, + }) + ), + }) + ) + return { + success: true, + output: { + answeredScorecards, + cursor: data.records?.cursor ?? null, + }, + } + }, + + outputs: { + answeredScorecards: { + type: 'array', + description: 'List of answered scorecards with scores and answers', + items: { + type: 'object', + properties: { + answeredScorecardId: { + type: 'number', + description: 'Identifier of the answered scorecard', + }, + scorecardId: { type: 'number', description: 'Identifier of the scorecard' }, + scorecardName: { type: 'string', description: 'Scorecard name' }, + callId: { type: 'number', description: "Gong's unique numeric identifier for the call" }, + callStartTime: { + type: 'string', + description: 'Date/time of the call in ISO-8601 format', + }, + reviewedUserId: { + type: 'number', + description: 'User ID of the team member being reviewed', + }, + reviewerUserId: { + type: 'number', + description: 'User ID of the team member who completed the scorecard', + }, + reviewTime: { + type: 'string', + description: 'Date/time when the review was completed in ISO-8601 format', + }, + visibilityType: { + type: 'string', + description: 'Visibility type of the scorecard answer', + }, + answers: { + type: 'array', + description: 'Answers in the answered scorecard', + items: { + type: 'object', + properties: { + questionId: { type: 'number', description: 'Identifier of the question' }, + questionRevisionId: { + type: 'number', + description: 'Identifier of the revision version of the question', + }, + isOverall: { type: 'boolean', description: 'Whether this is the overall question' }, + score: { + type: 'number', + description: 'Score between 1 to 5 if answered, null otherwise', + }, + answerText: { + type: 'string', + description: "The answer's text if answered, null otherwise", + }, + notApplicable: { + type: 'boolean', + description: 'Whether the question is not applicable to this call', + }, + }, + }, + }, + }, + }, + }, + cursor: { + type: 'string', + description: 'Pagination cursor for the next page', + }, + }, +} diff --git a/apps/sim/tools/gong/get_call.ts b/apps/sim/tools/gong/get_call.ts new file mode 100644 index 0000000000..d9595a049a --- /dev/null +++ b/apps/sim/tools/gong/get_call.ts @@ -0,0 +1,139 @@ +import type { GongGetCallParams, GongGetCallResponse } from '@/tools/gong/types' +import type { ToolConfig } from '@/tools/types' + +export const getCallTool: ToolConfig = { + id: 'gong_get_call', + name: 'Gong Get Call', + description: 'Retrieve detailed data for a specific call from Gong.', + version: '1.0.0', + + params: { + accessKey: { + type: 'string', + required: true, + visibility: 'user-only', + description: 'Gong API Access Key', + }, + accessKeySecret: { + type: 'string', + required: true, + visibility: 'user-only', + description: 'Gong API Access Key Secret', + }, + callId: { + type: 'string', + required: true, + visibility: 'user-or-llm', + description: 'The Gong call ID to retrieve', + }, + }, + + request: { + url: (params) => `https://api.gong.io/v2/calls/${params.callId}`, + method: 'GET', + headers: (params) => ({ + 'Content-Type': 'application/json', + Authorization: `Basic ${btoa(`${params.accessKey}:${params.accessKeySecret}`)}`, + }), + }, + + transformResponse: async (response: Response) => { + const data = await response.json() + if (!response.ok) { + throw new Error(data.errors?.[0]?.message || data.message || 'Failed to get call') + } + const call = data.call ?? data + return { + success: true, + output: { + id: call.id ?? '', + title: call.title ?? null, + url: call.url ?? null, + scheduled: call.scheduled ?? null, + started: call.started ?? '', + duration: call.duration ?? 0, + direction: call.direction ?? null, + system: call.system ?? null, + scope: call.scope ?? null, + media: call.media ?? null, + language: call.language ?? null, + primaryUserId: call.primaryUserId ?? null, + workspaceId: call.workspaceId ?? null, + sdrDisposition: call.sdrDisposition ?? null, + clientUniqueId: call.clientUniqueId ?? null, + customData: call.customData ?? null, + purpose: call.purpose ?? null, + meetingUrl: call.meetingUrl ?? null, + isPrivate: call.isPrivate ?? false, + calendarEventId: call.calendarEventId ?? null, + }, + } + }, + + outputs: { + id: { type: 'string', description: "Gong's unique numeric identifier for the call" }, + title: { type: 'string', description: 'Call title', optional: true }, + url: { type: 'string', description: 'URL to the call in the Gong web app', optional: true }, + scheduled: { + type: 'string', + description: 'Scheduled call time in ISO-8601 format', + optional: true, + }, + started: { type: 'string', description: 'Recording start time in ISO-8601 format' }, + duration: { type: 'number', description: 'Call duration in seconds' }, + direction: { + type: 'string', + description: 'Call direction (Inbound/Outbound)', + optional: true, + }, + system: { + type: 'string', + description: 'Communication platform used (e.g., Outreach)', + optional: true, + }, + scope: { + type: 'string', + description: "Call scope: 'Internal', 'External', or 'Unknown'", + optional: true, + }, + media: { type: 'string', description: 'Media type (e.g., Video)', optional: true }, + language: { + type: 'string', + description: 'Language code in ISO-639-2B format', + optional: true, + }, + primaryUserId: { + type: 'string', + description: 'Host team member identifier', + optional: true, + }, + workspaceId: { type: 'string', description: 'Workspace identifier', optional: true }, + sdrDisposition: { + type: 'string', + description: 'SDR disposition classification', + optional: true, + }, + clientUniqueId: { + type: 'string', + description: 'Call identifier from the origin recording system', + optional: true, + }, + customData: { + type: 'string', + description: 'Metadata provided during call creation', + optional: true, + }, + purpose: { type: 'string', description: 'Call purpose', optional: true }, + meetingUrl: { + type: 'string', + description: 'Web conference provider URL', + optional: true, + }, + isPrivate: { type: 'boolean', description: 'Whether the call is private' }, + calendarEventId: { + type: 'string', + description: 'Calendar event identifier', + optional: true, + }, + }, +} diff --git a/apps/sim/tools/gong/get_call_transcript.ts b/apps/sim/tools/gong/get_call_transcript.ts new file mode 100644 index 0000000000..31f327fd6b --- /dev/null +++ b/apps/sim/tools/gong/get_call_transcript.ts @@ -0,0 +1,154 @@ +import type { GongGetCallTranscriptParams, GongGetCallTranscriptResponse } from '@/tools/gong/types' +import type { ToolConfig } from '@/tools/types' + +export const getCallTranscriptTool: ToolConfig< + GongGetCallTranscriptParams, + GongGetCallTranscriptResponse +> = { + id: 'gong_get_call_transcript', + name: 'Gong Get Call Transcript', + description: 'Retrieve transcripts of calls from Gong by call IDs or date range.', + version: '1.0.0', + + params: { + accessKey: { + type: 'string', + required: true, + visibility: 'user-only', + description: 'Gong API Access Key', + }, + accessKeySecret: { + type: 'string', + required: true, + visibility: 'user-only', + description: 'Gong API Access Key Secret', + }, + callIds: { + type: 'string', + required: false, + visibility: 'user-or-llm', + description: 'Comma-separated list of call IDs to retrieve transcripts for', + }, + fromDateTime: { + type: 'string', + required: false, + visibility: 'user-or-llm', + description: 'Start date/time filter in ISO-8601 format', + }, + toDateTime: { + type: 'string', + required: false, + visibility: 'user-or-llm', + description: 'End date/time filter in ISO-8601 format', + }, + workspaceId: { + type: 'string', + required: false, + visibility: 'user-or-llm', + description: 'Gong workspace ID to filter calls', + }, + cursor: { + type: 'string', + required: false, + visibility: 'user-or-llm', + description: 'Pagination cursor from a previous response', + }, + }, + + request: { + url: 'https://api.gong.io/v2/calls/transcript', + method: 'POST', + headers: (params) => ({ + 'Content-Type': 'application/json', + Authorization: `Basic ${btoa(`${params.accessKey}:${params.accessKeySecret}`)}`, + }), + body: (params) => { + const filter: Record = {} + if (params.callIds) { + filter.callIds = params.callIds.split(',').map((id) => id.trim()) + } + if (params.fromDateTime) filter.fromDateTime = params.fromDateTime + if (params.toDateTime) filter.toDateTime = params.toDateTime + if (params.workspaceId) filter.workspaceId = params.workspaceId + const body: Record = { filter } + if (params.cursor) body.cursor = params.cursor + return body + }, + }, + + transformResponse: async (response: Response) => { + const data = await response.json() + if (!response.ok) { + throw new Error(data.errors?.[0]?.message || data.message || 'Failed to get call transcript') + } + const callTranscripts = (data.callTranscripts ?? []).map((ct: Record) => ({ + callId: ct.callId ?? '', + transcript: ((ct.transcript as Record[]) ?? []).map((t) => ({ + speakerId: t.speakerId ?? null, + topic: t.topic ?? null, + sentences: ((t.sentences as Record[]) ?? []).map((s) => ({ + start: s.start ?? 0, + end: s.end ?? 0, + text: s.text ?? '', + })), + })), + })) + return { + success: true, + output: { + callTranscripts, + cursor: data.records?.cursor ?? null, + }, + } + }, + + outputs: { + callTranscripts: { + type: 'array', + description: 'List of call transcripts with speaker turns and sentences', + items: { + type: 'object', + properties: { + callId: { type: 'string', description: "Gong's unique numeric identifier for the call" }, + transcript: { + type: 'array', + description: 'List of monologues in the call', + items: { + type: 'object', + properties: { + speakerId: { + type: 'string', + description: 'Unique ID of the speaker, cross-reference with parties', + }, + topic: { type: 'string', description: 'Name of the topic being discussed' }, + sentences: { + type: 'array', + description: 'List of sentences spoken in the monologue', + items: { + type: 'object', + properties: { + start: { + type: 'number', + description: 'Start time of the sentence in milliseconds from call start', + }, + end: { + type: 'number', + description: 'End time of the sentence in milliseconds from call start', + }, + text: { type: 'string', description: 'The sentence text' }, + }, + }, + }, + }, + }, + }, + }, + }, + }, + cursor: { + type: 'string', + description: 'Pagination cursor for the next page', + optional: true, + }, + }, +} diff --git a/apps/sim/tools/gong/get_coaching.ts b/apps/sim/tools/gong/get_coaching.ts new file mode 100644 index 0000000000..b16e3b28ce --- /dev/null +++ b/apps/sim/tools/gong/get_coaching.ts @@ -0,0 +1,170 @@ +import type { + GongCoachingMetricsData, + GongCoachingRepData, + GongCoachingUser, + GongGetCoachingParams, + GongGetCoachingResponse, +} from '@/tools/gong/types' +import type { ToolConfig } from '@/tools/types' + +export const getCoachingTool: ToolConfig = { + id: 'gong_get_coaching', + name: 'Gong Get Coaching', + description: 'Retrieve coaching metrics for a manager from Gong.', + version: '1.0.0', + + params: { + accessKey: { + type: 'string', + required: true, + visibility: 'user-only', + description: 'Gong API Access Key', + }, + accessKeySecret: { + type: 'string', + required: true, + visibility: 'user-only', + description: 'Gong API Access Key Secret', + }, + managerId: { + type: 'string', + required: true, + visibility: 'user-or-llm', + description: 'Gong user ID of the manager', + }, + workspaceId: { + type: 'string', + required: true, + visibility: 'user-or-llm', + description: 'Gong workspace ID', + }, + fromDate: { + type: 'string', + required: true, + visibility: 'user-or-llm', + description: 'Start date in ISO-8601 format', + }, + toDate: { + type: 'string', + required: true, + visibility: 'user-or-llm', + description: 'End date in ISO-8601 format', + }, + }, + + request: { + url: (params) => { + const url = new URL('https://api.gong.io/v2/coaching') + url.searchParams.set('manager-id', params.managerId) + url.searchParams.set('workspace-id', params.workspaceId) + url.searchParams.set('from', params.fromDate) + url.searchParams.set('to', params.toDate) + return url.toString() + }, + method: 'GET', + headers: (params) => ({ + 'Content-Type': 'application/json', + Authorization: `Basic ${btoa(`${params.accessKey}:${params.accessKeySecret}`)}`, + }), + }, + + transformResponse: async (response: Response) => { + const data = await response.json() + if (!response.ok) { + throw new Error(data.errors?.[0]?.message || data.message || 'Failed to get coaching metrics') + } + + const mapUser = (u: Record | null | undefined): GongCoachingUser | null => { + if (!u) return null + return { + id: (u.id as string) ?? null, + emailAddress: (u.emailAddress as string) ?? null, + firstName: (u.firstName as string) ?? null, + lastName: (u.lastName as string) ?? null, + title: (u.title as string) ?? null, + } + } + + const coachingData: GongCoachingMetricsData[] = (data.coachingData ?? []).map( + (item: Record) => { + const directReportsMetrics: GongCoachingRepData[] = ( + (item.directReportsMetrics as Record[]) ?? [] + ).map((rep: Record) => ({ + report: mapUser(rep.report as Record | null), + metrics: (rep.metrics as Record) ?? null, + })) + + return { + manager: mapUser(item.manager as Record | null), + directReportsMetrics, + } + } + ) + + return { + success: true, + output: { + requestId: (data.requestId as string) ?? null, + coachingData, + }, + } + }, + + outputs: { + requestId: { + type: 'string', + description: 'A Gong request reference ID for troubleshooting purposes', + }, + coachingData: { + type: 'array', + description: "A list of coaching data entries, one per manager's team", + items: { + type: 'object', + properties: { + manager: { + type: 'object', + description: 'The manager user information', + properties: { + id: { type: 'string', description: 'Gong unique numeric identifier for the user' }, + emailAddress: { type: 'string', description: 'Email address of the Gong user' }, + firstName: { type: 'string', description: 'First name of the Gong user' }, + lastName: { type: 'string', description: 'Last name of the Gong user' }, + title: { type: 'string', description: 'Job title of the Gong user' }, + }, + }, + directReportsMetrics: { + type: 'array', + description: 'Coaching metrics for each direct report', + items: { + type: 'object', + properties: { + report: { + type: 'object', + description: 'The direct report user information', + properties: { + id: { + type: 'string', + description: 'Gong unique numeric identifier for the user', + }, + emailAddress: { + type: 'string', + description: 'Email address of the Gong user', + }, + firstName: { type: 'string', description: 'First name of the Gong user' }, + lastName: { type: 'string', description: 'Last name of the Gong user' }, + title: { type: 'string', description: 'Job title of the Gong user' }, + }, + }, + metrics: { + type: 'json', + description: + 'A map of metric names to arrays of string values representing coaching metrics', + }, + }, + }, + }, + }, + }, + }, + }, +} diff --git a/apps/sim/tools/gong/get_extensive_calls.ts b/apps/sim/tools/gong/get_extensive_calls.ts new file mode 100644 index 0000000000..6a7c91b431 --- /dev/null +++ b/apps/sim/tools/gong/get_extensive_calls.ts @@ -0,0 +1,403 @@ +import type { GongGetExtensiveCallsParams, GongGetExtensiveCallsResponse } from '@/tools/gong/types' +import type { ToolConfig } from '@/tools/types' + +export const getExtensiveCallsTool: ToolConfig< + GongGetExtensiveCallsParams, + GongGetExtensiveCallsResponse +> = { + id: 'gong_get_extensive_calls', + name: 'Gong Get Extensive Calls', + description: 'Retrieve detailed call data including trackers, topics, and highlights from Gong.', + version: '1.0.0', + + params: { + accessKey: { + type: 'string', + required: true, + visibility: 'user-only', + description: 'Gong API Access Key', + }, + accessKeySecret: { + type: 'string', + required: true, + visibility: 'user-only', + description: 'Gong API Access Key Secret', + }, + callIds: { + type: 'string', + required: false, + visibility: 'user-or-llm', + description: 'Comma-separated list of call IDs to retrieve detailed data for', + }, + fromDateTime: { + type: 'string', + required: false, + visibility: 'user-or-llm', + description: 'Start date/time filter in ISO-8601 format', + }, + toDateTime: { + type: 'string', + required: false, + visibility: 'user-or-llm', + description: 'End date/time filter in ISO-8601 format', + }, + workspaceId: { + type: 'string', + required: false, + visibility: 'user-or-llm', + description: 'Gong workspace ID to filter calls', + }, + primaryUserIds: { + type: 'string', + required: false, + visibility: 'user-or-llm', + description: 'Comma-separated list of user IDs to filter calls by host', + }, + cursor: { + type: 'string', + required: false, + visibility: 'user-or-llm', + description: 'Pagination cursor from a previous response', + }, + }, + + request: { + url: 'https://api.gong.io/v2/calls/extensive', + method: 'POST', + headers: (params) => ({ + 'Content-Type': 'application/json', + Authorization: `Basic ${btoa(`${params.accessKey}:${params.accessKeySecret}`)}`, + }), + body: (params) => { + const filter: Record = {} + if (params.callIds) { + filter.callIds = params.callIds.split(',').map((id) => id.trim()) + } + if (params.fromDateTime) filter.fromDateTime = params.fromDateTime + if (params.toDateTime) filter.toDateTime = params.toDateTime + if (params.workspaceId) filter.workspaceId = params.workspaceId + if (params.primaryUserIds) { + filter.primaryUserIds = params.primaryUserIds.split(',').map((id) => id.trim()) + } + const body: Record = { + filter, + contentSelector: { + exposedFields: { + parties: true, + content: { + structure: true, + topics: true, + trackers: true, + trackerOccurrences: true, + highlights: true, + }, + collaboration: { publicComments: true }, + interaction: { + personInteractionStats: true, + speakers: true, + video: true, + questions: true, + }, + media: true, + }, + }, + } + if (params.cursor) body.cursor = params.cursor + return body + }, + }, + + transformResponse: async (response: Response) => { + const data = await response.json() + if (!response.ok) { + throw new Error( + data.errors?.[0]?.message || data.message || 'Failed to get extensive call data' + ) + } + return { + success: true, + output: { + calls: data.calls ?? [], + cursor: data.records?.cursor ?? null, + }, + } + }, + + outputs: { + calls: { + type: 'array', + description: + 'List of detailed call objects with metadata, content, interaction stats, and collaboration data', + items: { + type: 'object', + properties: { + metaData: { + type: 'object', + description: 'Call metadata (same fields as CallBasicData)', + properties: { + id: { type: 'string', description: 'Call ID' }, + title: { type: 'string', description: 'Call title' }, + scheduled: { type: 'string', description: 'Scheduled time in ISO-8601' }, + started: { type: 'string', description: 'Start time in ISO-8601' }, + duration: { type: 'number', description: 'Duration in seconds' }, + direction: { type: 'string', description: 'Call direction' }, + system: { type: 'string', description: 'Communication platform' }, + scope: { type: 'string', description: 'Internal/External/Unknown' }, + media: { type: 'string', description: 'Media type' }, + language: { type: 'string', description: 'Language code (ISO-639-2B)' }, + url: { type: 'string', description: 'Gong web app URL' }, + primaryUserId: { type: 'string', description: 'Host user ID' }, + workspaceId: { type: 'string', description: 'Workspace ID' }, + sdrDisposition: { type: 'string', description: 'SDR disposition' }, + clientUniqueId: { type: 'string', description: 'Origin system call ID' }, + customData: { type: 'string', description: 'Custom metadata' }, + purpose: { type: 'string', description: 'Call purpose' }, + meetingUrl: { type: 'string', description: 'Meeting URL' }, + isPrivate: { type: 'boolean', description: 'Whether call is private' }, + calendarEventId: { type: 'string', description: 'Calendar event ID' }, + }, + }, + context: { + type: 'array', + description: 'Links to external systems (CRM, Dialer, etc.)', + items: { + type: 'object', + properties: { + system: { type: 'string', description: 'External system name (e.g., Salesforce)' }, + objects: { + type: 'array', + description: 'List of objects within the external system', + }, + }, + }, + }, + parties: { + type: 'array', + description: 'List of call participants', + items: { + type: 'object', + properties: { + id: { type: 'string', description: 'Unique participant ID in the call' }, + name: { type: 'string', description: 'Participant name' }, + emailAddress: { type: 'string', description: 'Email address' }, + title: { type: 'string', description: 'Job title' }, + phoneNumber: { type: 'string', description: 'Phone number' }, + speakerId: { + type: 'string', + description: 'Speaker ID for transcript cross-reference', + }, + userId: { type: 'string', description: 'Gong user ID' }, + affiliation: { type: 'string', description: 'Company or non-company' }, + methods: { type: 'array', description: 'Whether invited or attended' }, + context: { type: 'array', description: 'Links to external systems for this party' }, + }, + }, + }, + content: { + type: 'object', + description: 'Call content data', + properties: { + structure: { + type: 'array', + description: 'Call agenda parts', + items: { + type: 'object', + properties: { + name: { type: 'string', description: 'Agenda name' }, + duration: { type: 'number', description: 'Duration of this part in seconds' }, + }, + }, + }, + topics: { + type: 'array', + description: 'Topics and their durations', + items: { + type: 'object', + properties: { + name: { type: 'string', description: 'Topic name (e.g., Pricing)' }, + duration: { type: 'number', description: 'Time spent on topic in seconds' }, + }, + }, + }, + trackers: { + type: 'array', + description: 'Trackers found in the call', + items: { + type: 'object', + properties: { + id: { type: 'string', description: 'Tracker ID' }, + name: { type: 'string', description: 'Tracker name' }, + count: { type: 'number', description: 'Number of occurrences' }, + type: { type: 'string', description: 'Keyword or Smart' }, + occurrences: { + type: 'array', + description: 'Details for each occurrence', + items: { + type: 'object', + properties: { + speakerId: { type: 'string', description: 'Speaker who said it' }, + startTime: { type: 'number', description: 'Seconds from call start' }, + }, + }, + }, + phrases: { + type: 'array', + description: 'Per-phrase occurrence counts', + items: { + type: 'object', + properties: { + phrase: { type: 'string', description: 'Specific phrase' }, + count: { type: 'number', description: 'Occurrences of this phrase' }, + occurrences: { type: 'array', description: 'Details per occurrence' }, + }, + }, + }, + }, + }, + }, + highlights: { + type: 'array', + description: + 'AI-generated highlights including next steps, action items, and key moments', + items: { + type: 'object', + properties: { + title: { type: 'string', description: 'Title of the highlight' }, + items: { + type: 'array', + description: 'Individual highlight items', + items: { + type: 'object', + properties: { + text: { type: 'string', description: 'Text of the highlight item' }, + startTimes: { + type: 'array', + description: 'Start times in seconds from call start', + }, + }, + }, + }, + }, + }, + }, + }, + }, + interaction: { + type: 'object', + description: 'Interaction statistics', + properties: { + interactionStats: { + type: 'array', + description: 'Interaction stats per user', + items: { + type: 'object', + properties: { + userId: { type: 'string', description: 'Gong user ID' }, + userEmailAddress: { type: 'string', description: 'User email' }, + personInteractionStats: { + type: 'array', + description: 'Stats list (Longest Monologue, Interactivity, Patience, etc.)', + items: { + type: 'object', + properties: { + name: { type: 'string', description: 'Stat name' }, + value: { type: 'number', description: 'Stat value' }, + }, + }, + }, + }, + }, + }, + speakers: { + type: 'array', + description: 'Talk duration per speaker', + items: { + type: 'object', + properties: { + id: { type: 'string', description: 'Participant ID' }, + userId: { type: 'string', description: 'Gong user ID' }, + talkTime: { type: 'number', description: 'Talk duration in seconds' }, + }, + }, + }, + video: { + type: 'array', + description: 'Video statistics', + items: { + type: 'object', + properties: { + name: { + type: 'string', + description: + 'Segment type: Browser, Presentation, WebcamPrimaryUser, WebcamNonCompany, Webcam', + }, + duration: { type: 'number', description: 'Total segment duration in seconds' }, + }, + }, + }, + questions: { + type: 'object', + description: 'Question counts', + properties: { + companyCount: { type: 'number', description: 'Questions by company speakers' }, + nonCompanyCount: { + type: 'number', + description: 'Questions by non-company speakers', + }, + }, + }, + }, + }, + collaboration: { + type: 'object', + description: 'Collaboration data', + properties: { + publicComments: { + type: 'array', + description: 'Public comments on the call', + items: { + type: 'object', + properties: { + id: { type: 'string', description: 'Comment ID' }, + commenterUserId: { type: 'string', description: 'Commenter user ID' }, + comment: { type: 'string', description: 'Comment text' }, + posted: { type: 'string', description: 'Posted time in ISO-8601' }, + audioStartTime: { + type: 'number', + description: 'Seconds from call start the comment refers to', + }, + audioEndTime: { + type: 'number', + description: 'Seconds from call start the comment end refers to', + }, + duringCall: { + type: 'boolean', + description: 'Whether the comment was posted during the call', + }, + inReplyTo: { + type: 'string', + description: 'ID of original comment if this is a reply', + }, + }, + }, + }, + }, + }, + media: { + type: 'object', + description: 'Media download URLs (available for 8 hours)', + properties: { + audioUrl: { type: 'string', description: 'Audio download URL' }, + videoUrl: { type: 'string', description: 'Video download URL' }, + }, + }, + }, + }, + }, + cursor: { + type: 'string', + description: 'Pagination cursor for the next page', + optional: true, + }, + }, +} diff --git a/apps/sim/tools/gong/get_folder_content.ts b/apps/sim/tools/gong/get_folder_content.ts new file mode 100644 index 0000000000..6704d7ce8e --- /dev/null +++ b/apps/sim/tools/gong/get_folder_content.ts @@ -0,0 +1,131 @@ +import type { GongGetFolderContentParams, GongGetFolderContentResponse } from '@/tools/gong/types' +import type { ToolConfig } from '@/tools/types' + +export const getFolderContentTool: ToolConfig< + GongGetFolderContentParams, + GongGetFolderContentResponse +> = { + id: 'gong_get_folder_content', + name: 'Gong Get Folder Content', + description: 'Retrieve the list of calls in a specific library folder from Gong.', + version: '1.0.0', + + params: { + accessKey: { + type: 'string', + required: true, + visibility: 'user-only', + description: 'Gong API Access Key', + }, + accessKeySecret: { + type: 'string', + required: true, + visibility: 'user-only', + description: 'Gong API Access Key Secret', + }, + folderId: { + type: 'string', + required: true, + visibility: 'user-or-llm', + description: 'The library folder ID to retrieve content for', + }, + }, + + request: { + url: (params) => { + const url = new URL('https://api.gong.io/v2/library/folder-content') + url.searchParams.set('folderId', params.folderId) + return url.toString() + }, + method: 'GET', + headers: (params) => ({ + 'Content-Type': 'application/json', + Authorization: `Basic ${btoa(`${params.accessKey}:${params.accessKeySecret}`)}`, + }), + }, + + transformResponse: async (response: Response) => { + const data = await response.json() + if (!response.ok) { + throw new Error(data.errors?.[0]?.message || data.message || 'Failed to get folder content') + } + const calls = (data.calls ?? []).map((c: Record) => ({ + id: (c.id as string) ?? '', + title: c.title ?? null, + note: c.note ?? null, + addedBy: c.addedBy ?? null, + created: c.created ?? null, + url: c.url ?? null, + snippet: c.snippet + ? { + fromSec: (c.snippet as Record).fromSec ?? null, + toSec: (c.snippet as Record).toSec ?? null, + } + : null, + })) + return { + success: true, + output: { + folderId: data.id ?? null, + folderName: data.name ?? null, + createdBy: data.createdBy ?? null, + updated: data.updated ?? null, + calls, + }, + } + }, + + outputs: { + folderId: { + type: 'string', + description: "Gong's unique numeric identifier for the folder", + }, + folderName: { + type: 'string', + description: 'Display name of the folder', + }, + createdBy: { + type: 'string', + description: "Gong's unique numeric identifier for the user who added the folder", + }, + updated: { + type: 'string', + description: "Folder's last update time in ISO-8601 format", + }, + calls: { + type: 'array', + description: 'List of calls in the library folder', + items: { + type: 'object', + properties: { + id: { type: 'string', description: 'Gong unique numeric identifier of the call' }, + title: { type: 'string', description: 'The title of the call' }, + note: { type: 'string', description: 'A note attached to the call in the folder' }, + addedBy: { + type: 'string', + description: 'Gong unique numeric identifier for the user who added the call', + }, + created: { + type: 'string', + description: 'Date and time the call was added to folder in ISO-8601 format', + }, + url: { type: 'string', description: 'URL of the call' }, + snippet: { + type: 'object', + description: 'Call snippet time range', + properties: { + fromSec: { + type: 'number', + description: 'Snippet start in seconds relative to call start', + }, + toSec: { + type: 'number', + description: 'Snippet end in seconds relative to call start', + }, + }, + }, + }, + }, + }, + }, +} diff --git a/apps/sim/tools/gong/get_user.ts b/apps/sim/tools/gong/get_user.ts new file mode 100644 index 0000000000..a8b071389f --- /dev/null +++ b/apps/sim/tools/gong/get_user.ts @@ -0,0 +1,141 @@ +import type { GongGetUserParams, GongGetUserResponse } from '@/tools/gong/types' +import type { ToolConfig } from '@/tools/types' + +export const getUserTool: ToolConfig = { + id: 'gong_get_user', + name: 'Gong Get User', + description: 'Retrieve details for a specific user from Gong.', + version: '1.0.0', + + params: { + accessKey: { + type: 'string', + required: true, + visibility: 'user-only', + description: 'Gong API Access Key', + }, + accessKeySecret: { + type: 'string', + required: true, + visibility: 'user-only', + description: 'Gong API Access Key Secret', + }, + userId: { + type: 'string', + required: true, + visibility: 'user-or-llm', + description: 'The Gong user ID to retrieve', + }, + }, + + request: { + url: (params) => `https://api.gong.io/v2/users/${params.userId}`, + method: 'GET', + headers: (params) => ({ + 'Content-Type': 'application/json', + Authorization: `Basic ${btoa(`${params.accessKey}:${params.accessKeySecret}`)}`, + }), + }, + + transformResponse: async (response: Response) => { + const data = await response.json() + if (!response.ok) { + throw new Error(data.errors?.[0]?.message || data.message || 'Failed to get user') + } + const user = data.user ?? data + return { + success: true, + output: { + id: user.id ?? '', + emailAddress: user.emailAddress ?? null, + created: user.created ?? null, + active: user.active ?? false, + emailAliases: user.emailAliases ?? [], + trustedEmailAddress: user.trustedEmailAddress ?? null, + firstName: user.firstName ?? null, + lastName: user.lastName ?? null, + title: user.title ?? null, + phoneNumber: user.phoneNumber ?? null, + extension: user.extension ?? null, + personalMeetingUrls: user.personalMeetingUrls ?? [], + settings: user.settings ?? null, + managerId: user.managerId ?? null, + meetingConsentPageUrl: user.meetingConsentPageUrl ?? null, + spokenLanguages: user.spokenLanguages ?? [], + }, + } + }, + + outputs: { + id: { type: 'string', description: 'Unique numeric user ID (up to 20 digits)' }, + emailAddress: { type: 'string', description: 'User email address', optional: true }, + created: { type: 'string', description: 'User creation timestamp (ISO-8601)', optional: true }, + active: { type: 'boolean', description: 'Whether the user is active' }, + emailAliases: { + type: 'array', + description: 'Alternative email addresses for the user', + optional: true, + items: { type: 'string' }, + }, + trustedEmailAddress: { + type: 'string', + description: 'Trusted email address for the user', + optional: true, + }, + firstName: { type: 'string', description: 'First name', optional: true }, + lastName: { type: 'string', description: 'Last name', optional: true }, + title: { type: 'string', description: 'Job title', optional: true }, + phoneNumber: { type: 'string', description: 'Phone number', optional: true }, + extension: { type: 'string', description: 'Phone extension number', optional: true }, + personalMeetingUrls: { + type: 'array', + description: 'Personal meeting URLs', + optional: true, + items: { type: 'string' }, + }, + settings: { + type: 'object', + description: 'User settings', + optional: true, + properties: { + webConferencesRecorded: { + type: 'boolean', + description: 'Whether web conferences are recorded', + }, + preventWebConferenceRecording: { + type: 'boolean', + description: 'Whether web conference recording is prevented', + }, + telephonyCallsImported: { + type: 'boolean', + description: 'Whether telephony calls are imported', + }, + emailsImported: { type: 'boolean', description: 'Whether emails are imported' }, + preventEmailImport: { type: 'boolean', description: 'Whether email import is prevented' }, + nonRecordedMeetingsImported: { + type: 'boolean', + description: 'Whether non-recorded meetings are imported', + }, + gongConnectEnabled: { type: 'boolean', description: 'Whether Gong Connect is enabled' }, + }, + }, + managerId: { type: 'string', description: 'Manager user ID', optional: true }, + meetingConsentPageUrl: { + type: 'string', + description: 'Meeting consent page URL', + optional: true, + }, + spokenLanguages: { + type: 'array', + description: 'Languages spoken by the user', + optional: true, + items: { + type: 'object', + properties: { + language: { type: 'string', description: 'Language code' }, + primary: { type: 'boolean', description: 'Whether this is the primary language' }, + }, + }, + }, + }, +} diff --git a/apps/sim/tools/gong/index.ts b/apps/sim/tools/gong/index.ts new file mode 100644 index 0000000000..89c6b80e8c --- /dev/null +++ b/apps/sim/tools/gong/index.ts @@ -0,0 +1,37 @@ +import { aggregateActivityTool } from '@/tools/gong/aggregate_activity' +import { answeredScorecardsTool } from '@/tools/gong/answered_scorecards' +import { getCallTool } from '@/tools/gong/get_call' +import { getCallTranscriptTool } from '@/tools/gong/get_call_transcript' +import { getCoachingTool } from '@/tools/gong/get_coaching' +import { getExtensiveCallsTool } from '@/tools/gong/get_extensive_calls' +import { getFolderContentTool } from '@/tools/gong/get_folder_content' +import { getUserTool } from '@/tools/gong/get_user' +import { interactionStatsTool } from '@/tools/gong/interaction_stats' +import { listCallsTool } from '@/tools/gong/list_calls' +import { listFlowsTool } from '@/tools/gong/list_flows' +import { listLibraryFoldersTool } from '@/tools/gong/list_library_folders' +import { listScorecardsTool } from '@/tools/gong/list_scorecards' +import { listTrackersTool } from '@/tools/gong/list_trackers' +import { listUsersTool } from '@/tools/gong/list_users' +import { listWorkspacesTool } from '@/tools/gong/list_workspaces' +import { lookupEmailTool } from '@/tools/gong/lookup_email' +import { lookupPhoneTool } from '@/tools/gong/lookup_phone' + +export const gongListCallsTool = listCallsTool +export const gongGetCallTool = getCallTool +export const gongGetCallTranscriptTool = getCallTranscriptTool +export const gongGetExtensiveCallsTool = getExtensiveCallsTool +export const gongListUsersTool = listUsersTool +export const gongGetUserTool = getUserTool +export const gongAggregateActivityTool = aggregateActivityTool +export const gongInteractionStatsTool = interactionStatsTool +export const gongAnsweredScorecardsTool = answeredScorecardsTool +export const gongListLibraryFoldersTool = listLibraryFoldersTool +export const gongGetFolderContentTool = getFolderContentTool +export const gongListScorecardsTool = listScorecardsTool +export const gongListTrackersTool = listTrackersTool +export const gongListWorkspacesTool = listWorkspacesTool +export const gongListFlowsTool = listFlowsTool +export const gongGetCoachingTool = getCoachingTool +export const gongLookupEmailTool = lookupEmailTool +export const gongLookupPhoneTool = lookupPhoneTool diff --git a/apps/sim/tools/gong/interaction_stats.ts b/apps/sim/tools/gong/interaction_stats.ts new file mode 100644 index 0000000000..6ec3cdca4f --- /dev/null +++ b/apps/sim/tools/gong/interaction_stats.ts @@ -0,0 +1,154 @@ +import type { GongInteractionStatsParams, GongInteractionStatsResponse } from '@/tools/gong/types' +import type { ToolConfig } from '@/tools/types' + +export const interactionStatsTool: ToolConfig< + GongInteractionStatsParams, + GongInteractionStatsResponse +> = { + id: 'gong_interaction_stats', + name: 'Gong Interaction Stats', + description: + 'Retrieve interaction statistics for users by date range from Gong. Only includes calls with Whisper enabled.', + version: '1.0.0', + + params: { + accessKey: { + type: 'string', + required: true, + visibility: 'user-only', + description: 'Gong API Access Key', + }, + accessKeySecret: { + type: 'string', + required: true, + visibility: 'user-only', + description: 'Gong API Access Key Secret', + }, + userIds: { + type: 'string', + required: false, + visibility: 'user-or-llm', + description: 'Comma-separated list of Gong user IDs (up to 20 digits each)', + }, + fromDate: { + type: 'string', + required: true, + visibility: 'user-or-llm', + description: 'Start date in YYYY-MM-DD format (inclusive, in company timezone)', + }, + toDate: { + type: 'string', + required: true, + visibility: 'user-or-llm', + description: + 'End date in YYYY-MM-DD format (exclusive, in company timezone, cannot exceed current day)', + }, + cursor: { + type: 'string', + required: false, + visibility: 'user-or-llm', + description: 'Pagination cursor from a previous response', + }, + }, + + request: { + url: 'https://api.gong.io/v2/stats/interaction', + method: 'POST', + headers: (params) => ({ + 'Content-Type': 'application/json', + Authorization: `Basic ${btoa(`${params.accessKey}:${params.accessKeySecret}`)}`, + }), + body: (params) => { + const filter: Record = { + fromDate: params.fromDate, + toDate: params.toDate, + } + if (params.userIds) { + filter.userIds = params.userIds.split(',').map((id) => id.trim()) + } + const body: Record = { filter } + if (params.cursor) body.cursor = params.cursor + return body + }, + }, + + transformResponse: async (response: Response) => { + const data = await response.json() + if (!response.ok) { + throw new Error( + data.errors?.[0]?.message || data.message || 'Failed to get interaction stats' + ) + } + const peopleInteractionStats = (data.peopleInteractionStats ?? []).map( + (entry: Record) => ({ + userId: entry.userId ?? '', + userEmailAddress: entry.userEmailAddress ?? null, + personInteractionStats: ( + (entry.personInteractionStats as Record[]) ?? [] + ).map((stat: Record) => ({ + name: stat.name ?? '', + value: stat.value ?? null, + })), + }) + ) + return { + success: true, + output: { + peopleInteractionStats, + timeZone: data.timeZone ?? null, + fromDateTime: data.fromDateTime ?? null, + toDateTime: data.toDateTime ?? null, + cursor: data.records?.cursor ?? null, + }, + } + }, + + outputs: { + peopleInteractionStats: { + type: 'array', + description: + "Interaction statistics per user. Applicable stat names: 'Longest Monologue', 'Longest Customer Story', 'Interactivity', 'Patience', 'Question Rate'.", + items: { + type: 'object', + properties: { + userId: { type: 'string', description: "Gong's unique numeric identifier for the user" }, + userEmailAddress: { type: 'string', description: 'Email address of the Gong user' }, + personInteractionStats: { + type: 'array', + description: 'List of interaction stat measurements for this user', + items: { + type: 'object', + properties: { + name: { + type: 'string', + description: + 'Stat name (e.g. Longest Monologue, Interactivity, Patience, Question Rate)', + }, + value: { + type: 'number', + description: 'Stat measurement value (can be double or integer)', + }, + }, + }, + }, + }, + }, + }, + timeZone: { + type: 'string', + description: "The company's defined timezone in Gong", + }, + fromDateTime: { + type: 'string', + description: 'Start of results in ISO-8601 format', + }, + toDateTime: { + type: 'string', + description: 'End of results in ISO-8601 format', + }, + cursor: { + type: 'string', + description: 'Pagination cursor for the next page', + }, + }, +} diff --git a/apps/sim/tools/gong/list_calls.ts b/apps/sim/tools/gong/list_calls.ts new file mode 100644 index 0000000000..3ef67dee7b --- /dev/null +++ b/apps/sim/tools/gong/list_calls.ts @@ -0,0 +1,149 @@ +import type { GongListCallsParams, GongListCallsResponse } from '@/tools/gong/types' +import type { ToolConfig } from '@/tools/types' + +export const listCallsTool: ToolConfig = { + id: 'gong_list_calls', + name: 'Gong List Calls', + description: 'Retrieve call data by date range from Gong.', + version: '1.0.0', + + params: { + accessKey: { + type: 'string', + required: true, + visibility: 'user-only', + description: 'Gong API Access Key', + }, + accessKeySecret: { + type: 'string', + required: true, + visibility: 'user-only', + description: 'Gong API Access Key Secret', + }, + fromDateTime: { + type: 'string', + required: true, + visibility: 'user-or-llm', + description: 'Start date/time in ISO-8601 format (e.g., 2024-01-01T00:00:00Z)', + }, + toDateTime: { + type: 'string', + required: false, + visibility: 'user-or-llm', + description: + 'End date/time in ISO-8601 format (e.g., 2024-01-31T23:59:59Z). If omitted, lists calls up to the most recent.', + }, + cursor: { + type: 'string', + required: false, + visibility: 'user-or-llm', + description: 'Pagination cursor from a previous response', + }, + workspaceId: { + type: 'string', + required: false, + visibility: 'user-or-llm', + description: 'Gong workspace ID to filter calls', + }, + }, + + request: { + url: (params) => { + const url = new URL('https://api.gong.io/v2/calls') + url.searchParams.set('fromDateTime', params.fromDateTime) + if (params.toDateTime) url.searchParams.set('toDateTime', params.toDateTime) + if (params.cursor) url.searchParams.set('cursor', params.cursor) + if (params.workspaceId) url.searchParams.set('workspaceId', params.workspaceId) + return url.toString() + }, + method: 'GET', + headers: (params) => ({ + 'Content-Type': 'application/json', + Authorization: `Basic ${btoa(`${params.accessKey}:${params.accessKeySecret}`)}`, + }), + }, + + transformResponse: async (response: Response) => { + const data = await response.json() + if (!response.ok) { + throw new Error(data.errors?.[0]?.message || data.message || 'Failed to list calls') + } + const calls = (data.calls ?? []).map((call: Record) => ({ + id: call.id ?? '', + title: call.title ?? null, + scheduled: call.scheduled ?? null, + started: call.started ?? '', + duration: call.duration ?? 0, + direction: call.direction ?? null, + system: call.system ?? null, + scope: call.scope ?? null, + media: call.media ?? null, + language: call.language ?? null, + url: call.url ?? null, + primaryUserId: call.primaryUserId ?? null, + workspaceId: call.workspaceId ?? null, + sdrDisposition: call.sdrDisposition ?? null, + clientUniqueId: call.clientUniqueId ?? null, + customData: call.customData ?? null, + purpose: call.purpose ?? null, + meetingUrl: call.meetingUrl ?? null, + isPrivate: call.isPrivate ?? false, + calendarEventId: call.calendarEventId ?? null, + })) + return { + success: true, + output: { + calls, + cursor: data.records?.cursor ?? null, + totalRecords: data.records?.totalRecords ?? calls.length, + }, + } + }, + + outputs: { + calls: { + type: 'array', + description: 'List of calls matching the date range', + items: { + type: 'object', + properties: { + id: { type: 'string', description: "Gong's unique numeric identifier for the call" }, + title: { type: 'string', description: 'Call title' }, + scheduled: { type: 'string', description: 'Scheduled call time in ISO-8601 format' }, + started: { type: 'string', description: 'Recording start time in ISO-8601 format' }, + duration: { type: 'number', description: 'Call duration in seconds' }, + direction: { type: 'string', description: 'Call direction (Inbound/Outbound)' }, + system: { type: 'string', description: 'Communication platform used (e.g., Outreach)' }, + scope: { + type: 'string', + description: "Call scope: 'Internal', 'External', or 'Unknown'", + }, + media: { type: 'string', description: 'Media type (e.g., Video)' }, + language: { type: 'string', description: 'Language code in ISO-639-2B format' }, + url: { type: 'string', description: 'URL to the call in the Gong web app' }, + primaryUserId: { type: 'string', description: 'Host team member identifier' }, + workspaceId: { type: 'string', description: 'Workspace identifier' }, + sdrDisposition: { type: 'string', description: 'SDR disposition classification' }, + clientUniqueId: { + type: 'string', + description: 'Call identifier from the origin recording system', + }, + customData: { type: 'string', description: 'Metadata provided during call creation' }, + purpose: { type: 'string', description: 'Call purpose' }, + meetingUrl: { type: 'string', description: 'Web conference provider URL' }, + isPrivate: { type: 'boolean', description: 'Whether the call is private' }, + calendarEventId: { type: 'string', description: 'Calendar event identifier' }, + }, + }, + }, + cursor: { + type: 'string', + description: 'Pagination cursor for the next page', + optional: true, + }, + totalRecords: { + type: 'number', + description: 'Total number of records matching the filter', + }, + }, +} diff --git a/apps/sim/tools/gong/list_flows.ts b/apps/sim/tools/gong/list_flows.ts new file mode 100644 index 0000000000..4f51ecc701 --- /dev/null +++ b/apps/sim/tools/gong/list_flows.ts @@ -0,0 +1,134 @@ +import type { GongListFlowsParams, GongListFlowsResponse } from '@/tools/gong/types' +import type { ToolConfig } from '@/tools/types' + +export const listFlowsTool: ToolConfig = { + id: 'gong_list_flows', + name: 'Gong List Flows', + description: 'List Gong Engage flows (sales engagement sequences).', + version: '1.0.0', + + params: { + accessKey: { + type: 'string', + required: true, + visibility: 'user-only', + description: 'Gong API Access Key', + }, + accessKeySecret: { + type: 'string', + required: true, + visibility: 'user-only', + description: 'Gong API Access Key Secret', + }, + flowOwnerEmail: { + type: 'string', + required: true, + visibility: 'user-or-llm', + description: + "Email of a Gong user. The API will return 'PERSONAL' flows belonging to this user in addition to 'COMPANY' flows.", + }, + workspaceId: { + type: 'string', + required: false, + visibility: 'user-or-llm', + description: 'Optional workspace ID to filter flows to a specific workspace', + }, + cursor: { + type: 'string', + required: false, + visibility: 'user-or-llm', + description: + 'Pagination cursor from a previous API call to retrieve the next page of records', + }, + }, + + request: { + url: (params) => { + const url = new URL('https://api.gong.io/v2/flows') + url.searchParams.set('flowOwnerEmail', params.flowOwnerEmail) + if (params.workspaceId) url.searchParams.set('workspaceId', params.workspaceId) + if (params.cursor) url.searchParams.set('cursor', params.cursor) + return url.toString() + }, + method: 'GET', + headers: (params) => ({ + 'Content-Type': 'application/json', + Authorization: `Basic ${btoa(`${params.accessKey}:${params.accessKeySecret}`)}`, + }), + }, + + transformResponse: async (response: Response) => { + const data = await response.json() + if (!response.ok) { + throw new Error(data.errors?.[0]?.message || data.message || 'Failed to list flows') + } + const flows = (data.flows ?? []).map((f: Record) => ({ + id: f.id ?? '', + name: f.name ?? null, + folderId: f.folderId ?? null, + folderName: f.folderName ?? null, + visibility: f.visibility ?? null, + creationDate: f.creationDate ?? null, + exclusive: f.exclusive ?? null, + })) + return { + success: true, + output: { + requestId: data.requestId ?? null, + flows, + totalRecords: data.records?.totalRecords ?? null, + currentPageSize: data.records?.currentPageSize ?? null, + currentPageNumber: data.records?.currentPageNumber ?? null, + cursor: data.records?.cursor ?? null, + }, + } + }, + + outputs: { + requestId: { + type: 'string', + description: 'A Gong request reference ID for troubleshooting purposes', + }, + flows: { + type: 'array', + description: 'List of Gong Engage flows', + items: { + type: 'object', + properties: { + id: { type: 'string', description: 'The ID of the flow' }, + name: { type: 'string', description: 'The name of the flow' }, + folderId: { type: 'string', description: 'The ID of the folder this flow is under' }, + folderName: { type: 'string', description: 'The name of the folder this flow is under' }, + visibility: { + type: 'string', + description: 'The flow visibility type (COMPANY, PERSONAL, or SHARED)', + }, + creationDate: { + type: 'string', + description: 'Creation time of the flow in ISO-8601 format', + }, + exclusive: { + type: 'boolean', + description: 'Indicates whether a prospect in this flow can be added to other flows', + }, + }, + }, + }, + totalRecords: { + type: 'number', + description: 'Total number of flow records available', + }, + currentPageSize: { + type: 'number', + description: 'Number of records returned in the current page', + }, + currentPageNumber: { + type: 'number', + description: 'Current page number', + }, + cursor: { + type: 'string', + description: 'Pagination cursor for retrieving the next page of records', + }, + }, +} diff --git a/apps/sim/tools/gong/list_library_folders.ts b/apps/sim/tools/gong/list_library_folders.ts new file mode 100644 index 0000000000..d947a4f78b --- /dev/null +++ b/apps/sim/tools/gong/list_library_folders.ts @@ -0,0 +1,94 @@ +import type { + GongListLibraryFoldersParams, + GongListLibraryFoldersResponse, +} from '@/tools/gong/types' +import type { ToolConfig } from '@/tools/types' + +export const listLibraryFoldersTool: ToolConfig< + GongListLibraryFoldersParams, + GongListLibraryFoldersResponse +> = { + id: 'gong_list_library_folders', + name: 'Gong List Library Folders', + description: 'Retrieve library folders from Gong.', + version: '1.0.0', + + params: { + accessKey: { + type: 'string', + required: true, + visibility: 'user-only', + description: 'Gong API Access Key', + }, + accessKeySecret: { + type: 'string', + required: true, + visibility: 'user-only', + description: 'Gong API Access Key Secret', + }, + workspaceId: { + type: 'string', + required: false, + visibility: 'user-or-llm', + description: 'Gong workspace ID to filter folders', + }, + }, + + request: { + url: (params) => { + const url = new URL('https://api.gong.io/v2/library/folders') + if (params.workspaceId) url.searchParams.set('workspaceId', params.workspaceId) + return url.toString() + }, + method: 'GET', + headers: (params) => ({ + 'Content-Type': 'application/json', + Authorization: `Basic ${btoa(`${params.accessKey}:${params.accessKeySecret}`)}`, + }), + }, + + transformResponse: async (response: Response) => { + const data = await response.json() + if (!response.ok) { + throw new Error(data.errors?.[0]?.message || data.message || 'Failed to list library folders') + } + const folders = (data.folders ?? []).map((f: Record) => ({ + id: f.id ?? '', + name: f.name ?? '', + parentFolderId: f.parentFolderId ?? null, + createdBy: f.createdBy ?? null, + updated: f.updated ?? null, + })) + return { + success: true, + output: { folders }, + } + }, + + outputs: { + folders: { + type: 'array', + description: 'List of library folders with id, name, and parent relationships', + items: { + type: 'object', + properties: { + id: { type: 'string', description: 'Gong unique numeric identifier for the folder' }, + name: { type: 'string', description: 'Display name of the folder' }, + parentFolderId: { + type: 'string', + description: + 'Gong unique numeric identifier for the parent folder (null for root folder)', + }, + createdBy: { + type: 'string', + description: 'Gong unique numeric identifier for the user who added the folder', + }, + updated: { + type: 'string', + description: "Folder's last update time in ISO-8601 format", + }, + }, + }, + }, + }, +} diff --git a/apps/sim/tools/gong/list_scorecards.ts b/apps/sim/tools/gong/list_scorecards.ts new file mode 100644 index 0000000000..742b520ced --- /dev/null +++ b/apps/sim/tools/gong/list_scorecards.ts @@ -0,0 +1,127 @@ +import type { GongListScorecardsParams, GongListScorecardsResponse } from '@/tools/gong/types' +import type { ToolConfig } from '@/tools/types' + +export const listScorecardsTool: ToolConfig = + { + id: 'gong_list_scorecards', + name: 'Gong List Scorecards', + description: 'Retrieve scorecard definitions from Gong settings.', + version: '1.0.0', + + params: { + accessKey: { + type: 'string', + required: true, + visibility: 'user-only', + description: 'Gong API Access Key', + }, + accessKeySecret: { + type: 'string', + required: true, + visibility: 'user-only', + description: 'Gong API Access Key Secret', + }, + }, + + request: { + url: 'https://api.gong.io/v2/settings/scorecards', + method: 'GET', + headers: (params) => ({ + 'Content-Type': 'application/json', + Authorization: `Basic ${btoa(`${params.accessKey}:${params.accessKeySecret}`)}`, + }), + }, + + transformResponse: async (response: Response) => { + const data = await response.json() + if (!response.ok) { + throw new Error(data.errors?.[0]?.message || data.message || 'Failed to list scorecards') + } + const scorecards = (data.scorecards ?? []).map((sc: Record) => ({ + scorecardId: sc.scorecardId ?? '', + scorecardName: sc.scorecardName ?? '', + workspaceId: sc.workspaceId ?? null, + enabled: sc.enabled ?? false, + updaterUserId: sc.updaterUserId ?? null, + created: sc.created ?? null, + updated: sc.updated ?? null, + questions: ((sc.questions as Record[] | undefined) ?? []).map( + (q: Record) => ({ + questionId: q.questionId ?? '', + questionText: q.questionText ?? '', + questionRevisionId: q.questionRevisionId ?? null, + isOverall: q.isOverall ?? false, + created: q.created ?? null, + updated: q.updated ?? null, + updaterUserId: q.updaterUserId ?? null, + }) + ), + })) + return { + success: true, + output: { scorecards }, + } + }, + + outputs: { + scorecards: { + type: 'array', + description: 'List of scorecard definitions with questions', + items: { + type: 'object', + properties: { + scorecardId: { type: 'string', description: 'Unique identifier for the scorecard' }, + scorecardName: { type: 'string', description: 'Display name of the scorecard' }, + workspaceId: { + type: 'string', + description: 'Workspace identifier associated with this scorecard', + }, + enabled: { type: 'boolean', description: 'Whether the scorecard is active' }, + updaterUserId: { + type: 'string', + description: 'ID of the user who last modified the scorecard', + }, + created: { + type: 'string', + description: 'Creation timestamp in ISO-8601 format', + }, + updated: { + type: 'string', + description: 'Last update timestamp in ISO-8601 format', + }, + questions: { + type: 'array', + description: 'List of questions in the scorecard', + items: { + type: 'object', + properties: { + questionId: { type: 'string', description: 'Unique identifier for the question' }, + questionText: { type: 'string', description: 'The text content of the question' }, + questionRevisionId: { + type: 'string', + description: 'Identifier for the specific revision of the question', + }, + isOverall: { + type: 'boolean', + description: 'Whether this is the primary overall question', + }, + created: { + type: 'string', + description: 'Question creation timestamp in ISO-8601 format', + }, + updated: { + type: 'string', + description: 'Question last update timestamp in ISO-8601 format', + }, + updaterUserId: { + type: 'string', + description: 'ID of the user who last modified the question', + }, + }, + }, + }, + }, + }, + }, + }, + } diff --git a/apps/sim/tools/gong/list_trackers.ts b/apps/sim/tools/gong/list_trackers.ts new file mode 100644 index 0000000000..2c54e3eea8 --- /dev/null +++ b/apps/sim/tools/gong/list_trackers.ts @@ -0,0 +1,164 @@ +import type { GongListTrackersParams, GongListTrackersResponse } from '@/tools/gong/types' +import type { ToolConfig } from '@/tools/types' + +export const listTrackersTool: ToolConfig = { + id: 'gong_list_trackers', + name: 'Gong List Trackers', + description: 'Retrieve smart tracker and keyword tracker definitions from Gong settings.', + version: '1.0.0', + + params: { + accessKey: { + type: 'string', + required: true, + visibility: 'user-only', + description: 'Gong API Access Key', + }, + accessKeySecret: { + type: 'string', + required: true, + visibility: 'user-only', + description: 'Gong API Access Key Secret', + }, + workspaceId: { + type: 'string', + required: false, + visibility: 'user-or-llm', + description: + 'The ID of the workspace the keyword trackers are in. When empty, all trackers in all workspaces are returned.', + }, + }, + + request: { + url: (params) => { + const url = new URL('https://api.gong.io/v2/settings/trackers') + if (params.workspaceId) url.searchParams.set('workspaceId', params.workspaceId) + return url.toString() + }, + method: 'GET', + headers: (params) => ({ + 'Content-Type': 'application/json', + Authorization: `Basic ${btoa(`${params.accessKey}:${params.accessKeySecret}`)}`, + }), + }, + + transformResponse: async (response: Response) => { + const data = await response.json() + if (!response.ok) { + throw new Error(data.errors?.[0]?.message || data.message || 'Failed to list trackers') + } + const trackers = (data.keywordTrackers ?? []).map((t: Record) => ({ + trackerId: t.trackerId ?? '', + trackerName: t.trackerName ?? '', + workspaceId: t.workspaceId ?? null, + languageKeywords: ((t.languageKeywords as Record[] | undefined) ?? []).map( + (lk: Record) => ({ + language: lk.language ?? null, + keywords: lk.keywords ?? [], + includeRelatedForms: lk.includeRelatedForms ?? false, + }) + ), + affiliation: t.affiliation ?? null, + partOfQuestion: t.partOfQuestion ?? null, + saidAt: t.saidAt ?? null, + saidAtInterval: t.saidAtInterval ?? null, + saidAtUnit: t.saidAtUnit ?? null, + saidInTopics: t.saidInTopics ?? [], + saidInCallParts: t.saidInCallParts ?? [], + filterQuery: t.filterQuery ?? null, + created: t.created ?? null, + creatorUserId: t.creatorUserId ?? null, + updated: t.updated ?? null, + updaterUserId: t.updaterUserId ?? null, + })) + return { + success: true, + output: { trackers }, + } + }, + + outputs: { + trackers: { + type: 'array', + description: 'List of keyword tracker definitions', + items: { + type: 'object', + properties: { + trackerId: { type: 'string', description: 'Unique identifier for the tracker' }, + trackerName: { type: 'string', description: 'Display name of the tracker' }, + workspaceId: { + type: 'string', + description: 'ID of the workspace containing the tracker', + }, + languageKeywords: { + type: 'array', + description: 'Keywords organized by language', + items: { + type: 'object', + properties: { + language: { + type: 'string', + description: + 'ISO 639-2/B language code ("mul" means keywords apply across all languages)', + }, + keywords: { + type: 'array', + description: 'Words and phrases in the designated language', + }, + includeRelatedForms: { + type: 'boolean', + description: 'Whether to include different word forms', + }, + }, + }, + }, + affiliation: { + type: 'string', + description: 'Speaker affiliation filter: "Anyone", "Company", or "NonCompany"', + }, + partOfQuestion: { + type: 'boolean', + description: 'Whether to track keywords only within questions', + }, + saidAt: { + type: 'string', + description: 'Position in call: "Anytime", "First", or "Last"', + }, + saidAtInterval: { + type: 'number', + description: 'Duration to search (in minutes or percentage)', + }, + saidAtUnit: { type: 'string', description: 'Unit for saidAtInterval' }, + saidInTopics: { + type: 'array', + description: 'Topics where keywords should be detected', + }, + saidInCallParts: { + type: 'array', + description: 'Specific call segments to monitor', + }, + filterQuery: { + type: 'string', + description: 'JSON-formatted call filtering criteria', + }, + created: { + type: 'string', + description: 'Creation timestamp in ISO-8601 format', + }, + creatorUserId: { + type: 'string', + description: 'ID of the user who created the tracker (null for built-in trackers)', + }, + updated: { + type: 'string', + description: 'Last modification timestamp in ISO-8601 format', + }, + updaterUserId: { + type: 'string', + description: 'ID of the user who last modified the tracker', + }, + }, + }, + }, + }, +} diff --git a/apps/sim/tools/gong/list_users.ts b/apps/sim/tools/gong/list_users.ts new file mode 100644 index 0000000000..54ac830393 --- /dev/null +++ b/apps/sim/tools/gong/list_users.ts @@ -0,0 +1,172 @@ +import type { GongListUsersParams, GongListUsersResponse } from '@/tools/gong/types' +import type { ToolConfig } from '@/tools/types' + +export const listUsersTool: ToolConfig = { + id: 'gong_list_users', + name: 'Gong List Users', + description: 'List all users in your Gong account.', + version: '1.0.0', + + params: { + accessKey: { + type: 'string', + required: true, + visibility: 'user-only', + description: 'Gong API Access Key', + }, + accessKeySecret: { + type: 'string', + required: true, + visibility: 'user-only', + description: 'Gong API Access Key Secret', + }, + cursor: { + type: 'string', + required: false, + visibility: 'user-or-llm', + description: 'Pagination cursor from a previous response', + }, + includeAvatars: { + type: 'string', + required: false, + visibility: 'user-or-llm', + description: 'Whether to include avatar URLs (true/false)', + }, + }, + + request: { + url: (params) => { + const url = new URL('https://api.gong.io/v2/users') + if (params.cursor) url.searchParams.set('cursor', params.cursor) + if (params.includeAvatars) url.searchParams.set('includeAvatars', params.includeAvatars) + return url.toString() + }, + method: 'GET', + headers: (params) => ({ + 'Content-Type': 'application/json', + Authorization: `Basic ${btoa(`${params.accessKey}:${params.accessKeySecret}`)}`, + }), + }, + + transformResponse: async (response: Response) => { + const data = await response.json() + if (!response.ok) { + throw new Error(data.errors?.[0]?.message || data.message || 'Failed to list users') + } + const users = (data.users ?? []).map((user: Record) => ({ + id: user.id ?? '', + emailAddress: user.emailAddress ?? null, + created: user.created ?? null, + active: user.active ?? false, + emailAliases: user.emailAliases ?? [], + trustedEmailAddress: user.trustedEmailAddress ?? null, + firstName: user.firstName ?? null, + lastName: user.lastName ?? null, + title: user.title ?? null, + phoneNumber: user.phoneNumber ?? null, + extension: user.extension ?? null, + personalMeetingUrls: user.personalMeetingUrls ?? [], + settings: user.settings ?? null, + managerId: user.managerId ?? null, + meetingConsentPageUrl: user.meetingConsentPageUrl ?? null, + spokenLanguages: user.spokenLanguages ?? [], + })) + return { + success: true, + output: { + users, + cursor: data.records?.cursor ?? null, + totalRecords: data.records?.totalRecords ?? null, + currentPageSize: data.records?.currentPageSize ?? null, + currentPageNumber: data.records?.currentPageNumber ?? null, + }, + } + }, + + outputs: { + users: { + type: 'array', + description: 'List of Gong users', + items: { + type: 'object', + properties: { + id: { type: 'string', description: 'Unique numeric user ID (up to 20 digits)' }, + emailAddress: { type: 'string', description: 'User email address' }, + created: { type: 'string', description: 'User creation timestamp (ISO-8601)' }, + active: { type: 'boolean', description: 'Whether the user is active' }, + emailAliases: { + type: 'array', + description: 'Alternative email addresses for the user', + items: { type: 'string' }, + }, + trustedEmailAddress: { + type: 'string', + description: 'Trusted email address for the user', + }, + firstName: { type: 'string', description: 'First name' }, + lastName: { type: 'string', description: 'Last name' }, + title: { type: 'string', description: 'Job title' }, + phoneNumber: { type: 'string', description: 'Phone number' }, + extension: { type: 'string', description: 'Phone extension number' }, + personalMeetingUrls: { + type: 'array', + description: 'Personal meeting URLs', + items: { type: 'string' }, + }, + settings: { + type: 'object', + description: 'User settings', + properties: { + webConferencesRecorded: { + type: 'boolean', + description: 'Whether web conferences are recorded', + }, + preventWebConferenceRecording: { + type: 'boolean', + description: 'Whether web conference recording is prevented', + }, + telephonyCallsImported: { + type: 'boolean', + description: 'Whether telephony calls are imported', + }, + emailsImported: { type: 'boolean', description: 'Whether emails are imported' }, + preventEmailImport: { + type: 'boolean', + description: 'Whether email import is prevented', + }, + nonRecordedMeetingsImported: { + type: 'boolean', + description: 'Whether non-recorded meetings are imported', + }, + gongConnectEnabled: { + type: 'boolean', + description: 'Whether Gong Connect is enabled', + }, + }, + }, + managerId: { type: 'string', description: 'Manager user ID' }, + meetingConsentPageUrl: { type: 'string', description: 'Meeting consent page URL' }, + spokenLanguages: { + type: 'array', + description: 'Languages spoken by the user', + items: { + type: 'object', + properties: { + language: { type: 'string', description: 'Language code' }, + primary: { type: 'boolean', description: 'Whether this is the primary language' }, + }, + }, + }, + }, + }, + }, + cursor: { type: 'string', description: 'Pagination cursor for the next page', optional: true }, + totalRecords: { type: 'number', description: 'Total number of user records', optional: true }, + currentPageSize: { + type: 'number', + description: 'Number of records in the current page', + optional: true, + }, + currentPageNumber: { type: 'number', description: 'Current page number', optional: true }, + }, +} diff --git a/apps/sim/tools/gong/list_workspaces.ts b/apps/sim/tools/gong/list_workspaces.ts new file mode 100644 index 0000000000..a1e89c09d7 --- /dev/null +++ b/apps/sim/tools/gong/list_workspaces.ts @@ -0,0 +1,68 @@ +import type { GongListWorkspacesParams, GongListWorkspacesResponse } from '@/tools/gong/types' +import type { ToolConfig } from '@/tools/types' + +export const listWorkspacesTool: ToolConfig = + { + id: 'gong_list_workspaces', + name: 'Gong List Workspaces', + description: 'List all company workspaces in Gong.', + version: '1.0.0', + + params: { + accessKey: { + type: 'string', + required: true, + visibility: 'user-only', + description: 'Gong API Access Key', + }, + accessKeySecret: { + type: 'string', + required: true, + visibility: 'user-only', + description: 'Gong API Access Key Secret', + }, + }, + + request: { + url: 'https://api.gong.io/v2/workspaces', + method: 'GET', + headers: (params) => ({ + 'Content-Type': 'application/json', + Authorization: `Basic ${btoa(`${params.accessKey}:${params.accessKeySecret}`)}`, + }), + }, + + transformResponse: async (response: Response) => { + const data = await response.json() + if (!response.ok) { + throw new Error(data.errors?.[0]?.message || data.message || 'Failed to list workspaces') + } + const workspaces = (data.workspaces ?? []).map((w: Record) => ({ + id: w.id ?? '', + name: w.name ?? null, + description: w.description ?? null, + })) + return { + success: true, + output: { workspaces }, + } + }, + + outputs: { + workspaces: { + type: 'array', + description: 'List of Gong workspaces', + items: { + type: 'object', + properties: { + id: { type: 'string', description: 'Gong unique numeric identifier for the workspace' }, + name: { type: 'string', description: 'Display name of the workspace' }, + description: { + type: 'string', + description: "Description of the workspace's purpose or content", + }, + }, + }, + }, + }, + } diff --git a/apps/sim/tools/gong/lookup_email.ts b/apps/sim/tools/gong/lookup_email.ts new file mode 100644 index 0000000000..16e9376830 --- /dev/null +++ b/apps/sim/tools/gong/lookup_email.ts @@ -0,0 +1,195 @@ +import type { GongLookupEmailParams, GongLookupEmailResponse } from '@/tools/gong/types' +import type { ToolConfig } from '@/tools/types' + +export const lookupEmailTool: ToolConfig = { + id: 'gong_lookup_email', + name: 'Gong Lookup Email', + description: + 'Find all references to an email address in Gong (calls, email messages, meetings, CRM data, engagement).', + version: '1.0.0', + + params: { + accessKey: { + type: 'string', + required: true, + visibility: 'user-only', + description: 'Gong API Access Key', + }, + accessKeySecret: { + type: 'string', + required: true, + visibility: 'user-only', + description: 'Gong API Access Key Secret', + }, + emailAddress: { + type: 'string', + required: true, + visibility: 'user-or-llm', + description: 'Email address to look up', + }, + }, + + request: { + url: (params) => { + const url = new URL('https://api.gong.io/v2/data-privacy/data-for-email-address') + url.searchParams.set('emailAddress', params.emailAddress) + return url.toString() + }, + method: 'GET', + headers: (params) => ({ + 'Content-Type': 'application/json', + Authorization: `Basic ${btoa(`${params.accessKey}:${params.accessKeySecret}`)}`, + }), + }, + + transformResponse: async (response: Response) => { + const data = await response.json() + if (!response.ok) { + throw new Error(data.errors?.[0]?.message || data.message || 'Failed to lookup email address') + } + return { + success: true, + output: { + requestId: data.requestId ?? '', + calls: data.calls ?? [], + emails: data.emails ?? [], + meetings: data.meetings ?? [], + customerData: data.customerData ?? [], + customerEngagement: data.customerEngagement ?? [], + }, + } + }, + + outputs: { + requestId: { + type: 'string', + description: 'Gong request reference ID for troubleshooting', + }, + calls: { + type: 'array', + description: 'Related calls referencing this email address', + items: { + type: 'object', + properties: { + id: { + type: 'string', + description: "Gong's unique numeric identifier for the call (up to 20 digits)", + }, + status: { type: 'string', description: 'Call status' }, + externalSystems: { + type: 'array', + description: 'Links to external systems such as CRM, Telephony System, etc.', + items: { + type: 'object', + properties: { + system: { type: 'string', description: 'External system name' }, + objects: { + type: 'array', + description: 'List of objects within the external system', + items: { + type: 'object', + properties: { + objectType: { type: 'string', description: 'Object type' }, + externalId: { type: 'string', description: 'External ID' }, + }, + }, + }, + }, + }, + }, + }, + }, + }, + emails: { + type: 'array', + description: 'Related email messages referencing this email address', + items: { + type: 'object', + properties: { + id: { + type: 'string', + description: "Gong's unique 32 character identifier for the email message", + }, + from: { type: 'string', description: "The sender's email address" }, + sentTime: { + type: 'string', + description: 'Date and time the email was sent in ISO-8601 format', + }, + mailbox: { + type: 'string', + description: 'The mailbox from which the email was retrieved', + }, + messageHash: { type: 'string', description: 'Hash code of the email message' }, + }, + }, + }, + meetings: { + type: 'array', + description: 'Related meetings referencing this email address', + items: { + type: 'object', + properties: { + id: { type: 'string', description: "Gong's unique identifier for the meeting" }, + }, + }, + }, + customerData: { + type: 'array', + description: + 'Links to data from external systems (CRM, Telephony, etc.) that reference this email', + items: { + type: 'object', + properties: { + system: { type: 'string', description: 'External system name' }, + objects: { + type: 'array', + description: 'List of objects in the external system', + items: { + type: 'object', + properties: { + id: { + type: 'string', + description: + "Gong's unique numeric identifier for the Lead or Contact (up to 20 digits)", + }, + objectType: { type: 'string', description: 'Object type' }, + externalId: { type: 'string', description: 'External ID' }, + mirrorId: { type: 'string', description: 'CRM Mirror ID' }, + fields: { + type: 'array', + description: 'Object fields', + items: { + type: 'object', + properties: { + name: { type: 'string', description: 'Field name' }, + value: { type: 'json', description: 'Field value' }, + }, + }, + }, + }, + }, + }, + }, + }, + }, + customerEngagement: { + type: 'array', + description: 'Customer engagement events (such as viewing external shared calls)', + items: { + type: 'object', + properties: { + eventType: { type: 'string', description: 'Event type' }, + eventName: { type: 'string', description: 'Event name' }, + timestamp: { + type: 'string', + description: 'Date and time the event occurred in ISO-8601 format', + }, + contentId: { type: 'string', description: 'Event content ID' }, + contentUrl: { type: 'string', description: 'Event content URL' }, + reportingSystem: { type: 'string', description: 'Event reporting system' }, + sourceEventId: { type: 'string', description: 'Source event ID' }, + }, + }, + }, + }, +} diff --git a/apps/sim/tools/gong/lookup_phone.ts b/apps/sim/tools/gong/lookup_phone.ts new file mode 100644 index 0000000000..fd5c214de2 --- /dev/null +++ b/apps/sim/tools/gong/lookup_phone.ts @@ -0,0 +1,196 @@ +import type { GongLookupPhoneParams, GongLookupPhoneResponse } from '@/tools/gong/types' +import type { ToolConfig } from '@/tools/types' + +export const lookupPhoneTool: ToolConfig = { + id: 'gong_lookup_phone', + name: 'Gong Lookup Phone', + description: + 'Find all references to a phone number in Gong (calls, email messages, meetings, CRM data, and associated contacts).', + version: '1.0.0', + + params: { + accessKey: { + type: 'string', + required: true, + visibility: 'user-only', + description: 'Gong API Access Key', + }, + accessKeySecret: { + type: 'string', + required: true, + visibility: 'user-only', + description: 'Gong API Access Key Secret', + }, + phoneNumber: { + type: 'string', + required: true, + visibility: 'user-or-llm', + description: 'Phone number to look up (must start with + followed by country code)', + }, + }, + + request: { + url: (params) => { + const url = new URL('https://api.gong.io/v2/data-privacy/data-for-phone-number') + url.searchParams.set('phoneNumber', params.phoneNumber) + return url.toString() + }, + method: 'GET', + headers: (params) => ({ + 'Content-Type': 'application/json', + Authorization: `Basic ${btoa(`${params.accessKey}:${params.accessKeySecret}`)}`, + }), + }, + + transformResponse: async (response: Response) => { + const data = await response.json() + if (!response.ok) { + throw new Error(data.errors?.[0]?.message || data.message || 'Failed to lookup phone number') + } + return { + success: true, + output: { + requestId: data.requestId ?? '', + suppliedPhoneNumber: data.suppliedPhoneNumber ?? '', + matchingPhoneNumbers: data.matchingPhoneNumbers ?? [], + emailAddresses: data.emailAddresses ?? [], + calls: data.calls ?? [], + emails: data.emails ?? [], + meetings: data.meetings ?? [], + customerData: data.customerData ?? [], + }, + } + }, + + outputs: { + requestId: { + type: 'string', + description: 'Gong request reference ID for troubleshooting', + }, + suppliedPhoneNumber: { + type: 'string', + description: 'The phone number that was supplied in the request', + }, + matchingPhoneNumbers: { + type: 'array', + description: 'Phone numbers found in the system that match the supplied number', + items: { + type: 'string', + }, + }, + emailAddresses: { + type: 'array', + description: 'Email addresses associated with the phone number', + items: { + type: 'string', + }, + }, + calls: { + type: 'array', + description: 'Related calls referencing this phone number', + items: { + type: 'object', + properties: { + id: { + type: 'string', + description: "Gong's unique numeric identifier for the call (up to 20 digits)", + }, + status: { type: 'string', description: 'Call status' }, + externalSystems: { + type: 'array', + description: 'Links to external systems such as CRM, Telephony System, etc.', + items: { + type: 'object', + properties: { + system: { type: 'string', description: 'External system name' }, + objects: { + type: 'array', + description: 'List of objects within the external system', + items: { + type: 'object', + properties: { + objectType: { type: 'string', description: 'Object type' }, + externalId: { type: 'string', description: 'External ID' }, + }, + }, + }, + }, + }, + }, + }, + }, + }, + emails: { + type: 'array', + description: 'Related email messages associated with contacts matching this phone number', + items: { + type: 'object', + properties: { + id: { + type: 'string', + description: "Gong's unique 32 character identifier for the email message", + }, + from: { type: 'string', description: "The sender's email address" }, + sentTime: { + type: 'string', + description: 'Date and time the email was sent in ISO-8601 format', + }, + mailbox: { + type: 'string', + description: 'The mailbox from which the email was retrieved', + }, + messageHash: { type: 'string', description: 'Hash code of the email message' }, + }, + }, + }, + meetings: { + type: 'array', + description: 'Related meetings associated with this phone number', + items: { + type: 'object', + properties: { + id: { type: 'string', description: "Gong's unique identifier for the meeting" }, + }, + }, + }, + customerData: { + type: 'array', + description: + 'Links to data from external systems (CRM, Telephony, etc.) that reference this phone number', + items: { + type: 'object', + properties: { + system: { type: 'string', description: 'External system name' }, + objects: { + type: 'array', + description: 'List of objects in the external system', + items: { + type: 'object', + properties: { + id: { + type: 'string', + description: + "Gong's unique numeric identifier for the Lead or Contact (up to 20 digits)", + }, + objectType: { type: 'string', description: 'Object type' }, + externalId: { type: 'string', description: 'External ID' }, + mirrorId: { type: 'string', description: 'CRM Mirror ID' }, + fields: { + type: 'array', + description: 'Object fields', + items: { + type: 'object', + properties: { + name: { type: 'string', description: 'Field name' }, + value: { type: 'json', description: 'Field value' }, + }, + }, + }, + }, + }, + }, + }, + }, + }, + }, +} diff --git a/apps/sim/tools/gong/types.ts b/apps/sim/tools/gong/types.ts new file mode 100644 index 0000000000..e5c682c547 --- /dev/null +++ b/apps/sim/tools/gong/types.ts @@ -0,0 +1,604 @@ +import type { ToolResponse } from '@/tools/types' + +/** Base parameters shared by all Gong tools */ +export interface GongBaseParams { + accessKey: string + accessKeySecret: string +} + +/** List Calls */ +export interface GongListCallsParams extends GongBaseParams { + fromDateTime: string + toDateTime?: string + cursor?: string + workspaceId?: string +} + +export interface GongCallBasic { + id: string + title: string | null + scheduled: string | null + started: string + duration: number + direction: string | null + system: string | null + scope: string | null + media: string | null + language: string | null + url: string | null + primaryUserId: string | null + workspaceId: string | null + sdrDisposition: string | null + clientUniqueId: string | null + customData: string | null + purpose: string | null + meetingUrl: string | null + isPrivate: boolean + calendarEventId: string | null +} + +export interface GongParty { + id: string | null + name: string | null + emailAddress: string | null + phoneNumber: string | null + title: string | null + speakerId: string | null + userId: string | null + affiliation: string | null + methods: string[] + context: { system: string; objects: Record[] }[] +} + +export interface GongListCallsResponse extends ToolResponse { + output: { + calls: GongCallBasic[] + cursor: string | null + totalRecords: number + } +} + +/** Get Call */ +export interface GongGetCallParams extends GongBaseParams { + callId: string +} + +export interface GongGetCallResponse extends ToolResponse { + output: GongCallBasic +} + +/** Get Call Transcript */ +export interface GongGetCallTranscriptParams extends GongBaseParams { + callIds?: string + fromDateTime?: string + toDateTime?: string + workspaceId?: string + cursor?: string +} + +export interface GongTranscriptSentence { + start: number + end: number + text: string +} + +export interface GongTranscriptEntry { + speakerId: string | null + topic: string | null + sentences: GongTranscriptSentence[] +} + +export interface GongCallTranscript { + callId: string + transcript: GongTranscriptEntry[] +} + +export interface GongGetCallTranscriptResponse extends ToolResponse { + output: { + callTranscripts: GongCallTranscript[] + cursor: string | null + } +} + +/** Get Extensive Calls */ +export interface GongGetExtensiveCallsParams extends GongBaseParams { + callIds?: string + fromDateTime?: string + toDateTime?: string + workspaceId?: string + primaryUserIds?: string + cursor?: string +} + +export interface GongExtensiveCall { + metaData: Record + parties: GongParty[] + content: Record + interaction: Record + collaboration: Record + media: Record +} + +export interface GongGetExtensiveCallsResponse extends ToolResponse { + output: { + calls: GongExtensiveCall[] + cursor: string | null + } +} + +/** List Users */ +export interface GongListUsersParams extends GongBaseParams { + cursor?: string + includeAvatars?: string +} + +export interface GongUserSettings { + webConferencesRecorded: boolean + preventWebConferenceRecording: boolean + telephonyCallsImported: boolean + emailsImported: boolean + preventEmailImport: boolean + nonRecordedMeetingsImported: boolean + gongConnectEnabled: boolean +} + +export interface GongSpokenLanguage { + language: string + primary: boolean +} + +export interface GongUser { + id: string + emailAddress: string | null + created: string | null + active: boolean + emailAliases: string[] + trustedEmailAddress: string | null + firstName: string | null + lastName: string | null + title: string | null + phoneNumber: string | null + extension: string | null + personalMeetingUrls: string[] + settings: GongUserSettings | null + managerId: string | null + meetingConsentPageUrl: string | null + spokenLanguages: GongSpokenLanguage[] +} + +export interface GongListUsersResponse extends ToolResponse { + output: { + users: GongUser[] + cursor: string | null + totalRecords: number | null + currentPageSize: number | null + currentPageNumber: number | null + } +} + +/** Get User */ +export interface GongGetUserParams extends GongBaseParams { + userId: string +} + +export interface GongGetUserResponse extends ToolResponse { + output: { + id: string + emailAddress: string | null + created: string | null + active: boolean + emailAliases: string[] + trustedEmailAddress: string | null + firstName: string | null + lastName: string | null + title: string | null + phoneNumber: string | null + extension: string | null + personalMeetingUrls: string[] + settings: GongUserSettings | null + managerId: string | null + meetingConsentPageUrl: string | null + spokenLanguages: GongSpokenLanguage[] + } +} + +/** Aggregate Activity */ +export interface GongAggregateActivityParams extends GongBaseParams { + userIds?: string + fromDate: string + toDate: string + cursor?: string +} + +export interface GongUserActivity { + userId: string + userEmailAddress: string | null + callsAsHost: number | null + callsAttended: number | null + callsGaveFeedback: number | null + callsReceivedFeedback: number | null + callsRequestedFeedback: number | null + callsScorecardsFilled: number | null + callsScorecardsReceived: number | null + ownCallsListenedTo: number | null + othersCallsListenedTo: number | null + callsSharedInternally: number | null + callsSharedExternally: number | null + callsCommentsGiven: number | null + callsCommentsReceived: number | null + callsMarkedAsFeedbackGiven: number | null + callsMarkedAsFeedbackReceived: number | null +} + +export interface GongAggregateActivityResponse extends ToolResponse { + output: { + usersActivity: GongUserActivity[] + timeZone: string | null + fromDateTime: string | null + toDateTime: string | null + cursor: string | null + } +} + +/** Interaction Stats */ +export interface GongInteractionStatEntry { + name: string + value: number | null +} + +export interface GongUserInteractionStats { + userId: string + userEmailAddress: string | null + personInteractionStats: GongInteractionStatEntry[] +} + +export interface GongInteractionStatsParams extends GongBaseParams { + userIds?: string + fromDate: string + toDate: string + cursor?: string +} + +export interface GongInteractionStatsResponse extends ToolResponse { + output: { + peopleInteractionStats: GongUserInteractionStats[] + timeZone: string | null + fromDateTime: string | null + toDateTime: string | null + cursor: string | null + } +} + +/** Answered Scorecards */ +export interface GongAnsweredScorecardsParams extends GongBaseParams { + callFromDate?: string + callToDate?: string + reviewFromDate?: string + reviewToDate?: string + scorecardIds?: string + reviewedUserIds?: string + cursor?: string +} + +export interface GongScorecardAnswer { + questionId: number | null + questionRevisionId: number | null + isOverall: boolean | null + score: number | null + answerText: string | null + notApplicable: boolean | null +} + +export interface GongAnsweredScorecard { + answeredScorecardId: number + scorecardId: number | null + scorecardName: string | null + callId: number | null + callStartTime: string | null + reviewedUserId: number | null + reviewerUserId: number | null + reviewTime: string | null + visibilityType: string | null + answers: GongScorecardAnswer[] +} + +export interface GongAnsweredScorecardsResponse extends ToolResponse { + output: { + answeredScorecards: GongAnsweredScorecard[] + cursor: string | null + } +} + +/** List Library Folders */ +export interface GongListLibraryFoldersParams extends GongBaseParams { + workspaceId?: string +} + +export interface GongLibraryFolder { + id: string + name: string + parentFolderId: string | null + createdBy: string | null + updated: string | null +} + +export interface GongListLibraryFoldersResponse extends ToolResponse { + output: { + folders: GongLibraryFolder[] + } +} + +/** Get Folder Content */ +export interface GongGetFolderContentParams extends GongBaseParams { + folderId: string +} + +export interface GongFolderCallSnippet { + fromSec: number | null + toSec: number | null +} + +export interface GongFolderCall { + id: string + title: string | null + note: string | null + addedBy: string | null + created: string | null + url: string | null + snippet: GongFolderCallSnippet | null +} + +export interface GongGetFolderContentResponse extends ToolResponse { + output: { + folderId: string | null + folderName: string | null + createdBy: string | null + updated: string | null + calls: GongFolderCall[] + } +} + +/** List Scorecards */ +export interface GongListScorecardsParams extends GongBaseParams {} + +export interface GongScorecardQuestion { + questionId: string + questionText: string + questionRevisionId: string | null + isOverall: boolean + created: string | null + updated: string | null + updaterUserId: string | null +} + +export interface GongScorecard { + scorecardId: string + scorecardName: string + workspaceId: string | null + enabled: boolean + updaterUserId: string | null + created: string | null + updated: string | null + questions: GongScorecardQuestion[] +} + +export interface GongListScorecardsResponse extends ToolResponse { + output: { + scorecards: GongScorecard[] + } +} + +/** List Trackers */ +export interface GongListTrackersParams extends GongBaseParams { + workspaceId?: string +} + +export interface GongTrackerLanguageKeyword { + language: string | null + keywords: string[] + includeRelatedForms: boolean +} + +export interface GongTracker { + trackerId: string + trackerName: string + workspaceId: string | null + languageKeywords: GongTrackerLanguageKeyword[] + affiliation: string | null + partOfQuestion: boolean | null + saidAt: string | null + saidAtInterval: number | null + saidAtUnit: string | null + saidInTopics: string[] + saidInCallParts: string[] + filterQuery: string | null + created: string | null + creatorUserId: string | null + updated: string | null + updaterUserId: string | null +} + +export interface GongListTrackersResponse extends ToolResponse { + output: { + trackers: GongTracker[] + } +} + +/** List Workspaces */ +export interface GongListWorkspacesParams extends GongBaseParams {} + +export interface GongWorkspace { + id: string + name: string | null + description: string | null +} + +export interface GongListWorkspacesResponse extends ToolResponse { + output: { + workspaces: GongWorkspace[] + } +} + +/** List Flows */ +export interface GongListFlowsParams extends GongBaseParams { + flowOwnerEmail: string + workspaceId?: string + cursor?: string +} + +export interface GongFlow { + id: string + name: string | null + folderId: string | null + folderName: string | null + visibility: string | null + creationDate: string | null + exclusive: boolean | null +} + +export interface GongListFlowsResponse extends ToolResponse { + output: { + requestId: string | null + flows: GongFlow[] + totalRecords: number | null + currentPageSize: number | null + currentPageNumber: number | null + cursor: string | null + } +} + +/** Get Coaching */ +export interface GongGetCoachingParams extends GongBaseParams { + managerId: string + workspaceId: string + fromDate: string + toDate: string +} + +export interface GongCoachingUser { + id: string | null + emailAddress: string | null + firstName: string | null + lastName: string | null + title: string | null +} + +export interface GongCoachingRepData { + report: GongCoachingUser | null + metrics: Record | null +} + +export interface GongCoachingMetricsData { + manager: GongCoachingUser | null + directReportsMetrics: GongCoachingRepData[] +} + +export interface GongGetCoachingResponse extends ToolResponse { + output: { + requestId: string | null + coachingData: GongCoachingMetricsData[] + } +} + +/** Shared data-privacy sub-types */ +export interface GongCallReference { + id: string + status: string + externalSystems: { + system: string + objects: { + objectType: string + externalId: string + }[] + }[] +} + +export interface GongEmailMessage { + id: string + from: string + sentTime: string + mailbox: string + messageHash: string +} + +export interface GongMeeting { + id: string +} + +export interface GongCustomerDataObject { + id: string + objectType: string + externalId: string + mirrorId: string + fields: { name: string; value: unknown }[] +} + +export interface GongCustomerData { + system: string + objects: GongCustomerDataObject[] +} + +export interface GongCustomerEngagement { + eventType: string + eventName: string + timestamp: string + contentId: string + contentUrl: string + reportingSystem: string + sourceEventId: string +} + +/** Lookup Email */ +export interface GongLookupEmailParams extends GongBaseParams { + emailAddress: string +} + +export interface GongLookupEmailResponse extends ToolResponse { + output: { + requestId: string + calls: GongCallReference[] + emails: GongEmailMessage[] + meetings: GongMeeting[] + customerData: GongCustomerData[] + customerEngagement: GongCustomerEngagement[] + } +} + +/** Lookup Phone */ +export interface GongLookupPhoneParams extends GongBaseParams { + phoneNumber: string +} + +export interface GongLookupPhoneResponse extends ToolResponse { + output: { + requestId: string + suppliedPhoneNumber: string + matchingPhoneNumbers: string[] + emailAddresses: string[] + calls: GongCallReference[] + emails: GongEmailMessage[] + meetings: GongMeeting[] + customerData: GongCustomerData[] + } +} + +/** Union type for all Gong responses */ +export type GongResponse = + | GongListCallsResponse + | GongGetCallResponse + | GongGetCallTranscriptResponse + | GongGetExtensiveCallsResponse + | GongListUsersResponse + | GongGetUserResponse + | GongAggregateActivityResponse + | GongInteractionStatsResponse + | GongAnsweredScorecardsResponse + | GongListLibraryFoldersResponse + | GongGetFolderContentResponse + | GongListScorecardsResponse + | GongListTrackersResponse + | GongListWorkspacesResponse + | GongListFlowsResponse + | GongGetCoachingResponse + | GongLookupEmailResponse + | GongLookupPhoneResponse diff --git a/apps/sim/tools/registry.ts b/apps/sim/tools/registry.ts index 7642dfa0bb..54909993ab 100644 --- a/apps/sim/tools/registry.ts +++ b/apps/sim/tools/registry.ts @@ -557,6 +557,26 @@ import { gmailUnarchiveTool, gmailUnarchiveV2Tool, } from '@/tools/gmail' +import { + gongAggregateActivityTool, + gongAnsweredScorecardsTool, + gongGetCallTool, + gongGetCallTranscriptTool, + gongGetCoachingTool, + gongGetExtensiveCallsTool, + gongGetFolderContentTool, + gongGetUserTool, + gongInteractionStatsTool, + gongListCallsTool, + gongListFlowsTool, + gongListLibraryFoldersTool, + gongListScorecardsTool, + gongListTrackersTool, + gongListUsersTool, + gongListWorkspacesTool, + gongLookupEmailTool, + gongLookupPhoneTool, +} from '@/tools/gong' import { googleSearchTool } from '@/tools/google' import { googleBooksVolumeDetailsTool, googleBooksVolumeSearchTool } from '@/tools/google_books' import { @@ -2055,6 +2075,24 @@ export const tools: Record = { fireflies_create_bite: firefliesCreateBiteTool, fireflies_list_bites: firefliesListBitesTool, fireflies_list_contacts: firefliesListContactsTool, + gong_list_calls: gongListCallsTool, + gong_get_call: gongGetCallTool, + gong_get_call_transcript: gongGetCallTranscriptTool, + gong_get_extensive_calls: gongGetExtensiveCallsTool, + gong_list_users: gongListUsersTool, + gong_get_user: gongGetUserTool, + gong_aggregate_activity: gongAggregateActivityTool, + gong_interaction_stats: gongInteractionStatsTool, + gong_answered_scorecards: gongAnsweredScorecardsTool, + gong_list_library_folders: gongListLibraryFoldersTool, + gong_get_folder_content: gongGetFolderContentTool, + gong_list_scorecards: gongListScorecardsTool, + gong_list_trackers: gongListTrackersTool, + gong_list_workspaces: gongListWorkspacesTool, + gong_list_flows: gongListFlowsTool, + gong_get_coaching: gongGetCoachingTool, + gong_lookup_email: gongLookupEmailTool, + gong_lookup_phone: gongLookupPhoneTool, grafana_get_dashboard: grafanaGetDashboardTool, grafana_list_dashboards: grafanaListDashboardsTool, grafana_create_dashboard: grafanaCreateDashboardTool,