Introduction
This page provides an instruction & guide for developers building middleware to connect a GPT Action to a specific application. Before you proceed, make sure to first familiarize yourself with the following information:
- Introduction to GPT Actions
- Introduction to GPT Actions Library
- Example of Building a GPT Action from Scratch
This particular GPT Action provides an overview of how to build a GPT that retrieves information from Salesforce and Gong. This will include creating multiple custom actions which are documented in existing cookbooks. We will highlight these cookbooks in the next section.
Value + Example Business Use Cases
Value: Users can now leverage ChatGPT's capabilities to:
- Connect to Salesforce
- Search for customer accounts
- Retrieve Gong transcripts from previous calls
Example Use Cases:
A sales rep is preparing for an upcoming customer meeting. Using this integration, they can quickly retrieve relevant account details from Salesforce, access recent Gong call transcripts, and receive AI-generated summaries and insights structured around proven sales methodologies like MEDPICC or SPICED. This empowers the rep with a clear, actionable understanding of the customer's current state and next steps — all in minutes
Application Information
In this example, we are connecting to Salesforce and Gong (via a middleware). We are going to refer to existing cookbooks for basic setup and authentication instructions for Salesforce and creating a middleware.
Salesforce GPT Action
Refer to our cookbook on setting up a GPT Action for Salesforce. The two settings to pay attention to in that cookbook are:
- Application Information - this covers the necessary concepts to be familiar with in Salesforce
- Authentication Instructions - this covers creating a Connected App in Salesforce and configuring OAuth (on both Salesforce and ChatGPT)
Middleware GPT Action
Refer to any one of our cookbooks on creating a middleware:
- GPT Actions library (Middleware) - AWS
- GPT Actions library (Middleware) - Azure Functions
- GPT Actions library (Middleware) - Google Cloud Function
Application Prerequisites
In addition to the prerequisites in the cookbooks above, please ensure that you have access to a Gong API key
Application Setup
Deploying a serverless function
This serverless function will accept an array of callIds
, fetch the transcripts from Gong and clean up the response that it sends to ChatGPT. Here is an example of what it looks like on Azure Functions (Javascript)
const { app } = require('@azure/functions');
const axios = require('axios');
// Replace with your Gong API token
const GONG_API_BASE_URL = "https://api.gong.io/v2";
const GONG_API_KEY = process.env.GONG_API_KEY;
app.http('callTranscripts', {
methods: ['POST'],
authLevel: 'function',
handler: async (request, context) => {
try {
const body = await request.json();
const callIds = body.callIds;
if (!Array.isArray(callIds) || callIds.length === 0) {
return {
status: 400,
body: "Please provide call IDs in the 'callIds' array."
};
}
// Fetch call transcripts
const transcriptPayload = { filter: { callIds } };
const transcriptResponse = await axios.post(`${GONG_API_BASE_URL}/calls/transcript`, transcriptPayload, {
headers: {
'Authorization': `Basic ${GONG_API_KEY}`,
'Content-Type': 'application/json'
}
});
const transcriptData = transcriptResponse.data;
// Fetch extensive call details
const extensivePayload = {
filter: { callIds },
contentSelector: {
exposedFields: { parties: true }
}
};
const extensiveResponse = await axios.post(`${GONG_API_BASE_URL}/calls/extensive`, extensivePayload, {
headers: {
'Authorization': `Basic ${GONG_API_KEY}`,
'Content-Type': 'application/json'
}
});
const extensiveData = extensiveResponse.data;
// Create a map of call IDs to metadata and speaker details
const callMetaMap = {};
extensiveData.calls.forEach(call => {
callMetaMap[call.metaData.id] = {
title: call.metaData.title,
started: call.metaData.started,
duration: call.metaData.duration,
url: call.metaData.url,
speakers: {}
};
call.parties.forEach(party => {
callMetaMap[call.metaData.id].speakers[party.speakerId] = party.name;
});
});
// Transform transcript data into content and include metadata
transcriptData.callTranscripts.forEach(call => {
const meta = callMetaMap[call.callId];
if (!meta) {
throw new Error(`Metadata for callId ${call.callId} not found.`);
}
let content = '';
call.transcript.forEach(segment => {
const speakerName = meta.speakers[segment.speakerId] || "Unknown Speaker";
// Combine all sentences for the speaker into a paragraph
const sentences = segment.sentences.map(sentence => sentence.text).join(' ');
content += `${speakerName}: ${sentences}\n\n`; // Add a newline between speaker turns
});
// Add metadata and content to the call object
call.title = meta.title;
call.started = meta.started;
call.duration = meta.duration;
call.url = meta.url;
call.content = content;
delete call.transcript;
});
// Return the modified transcript data
return {
status: 200,
headers: { 'Content-Type': 'application/json' },
body: JSON.stringify(transcriptData)
};
} catch (error) {
context.log('[ERROR]', "Error processing request:", error);
return {
status: error.response?.status || 500,
body: {
message: "An error occurred while fetching or processing call data.",
details: error.response?.data || error.message
}
};
}
}
});
Here are the dependencies that you would include in your package.json
file
"dependencies": {
"@azure/functions": "^4.0.0",
"axios": "^1.7.7"
}
ChatGPT Steps
Custom GPT Instructions
Once you've created a Custom GPT, copy the text below in the Instructions panel. Have questions? Check out Getting Started Example to see how this step works in more detail.
# Trigger
User enters the name of an account that they want to prepare for
# Steps
1. Retrieve Account Names - Make a call to the `executeSOSLSearch` custom action searching for a Salesforce Account with that name (SOSL). Retrieve up to 5 accounts. This is what the query should look like - `FIND {Acme} IN ALL FIELDS RETURNING Account(Id, Name) LIMIT 5`
2. Show the accounts in this format - `Account Name - salesforceID`. Ask the user to confirm which account they are interested in.
3. Get Gong Call IDs for the account - For the confirmed account, make a call to `executeSOQLQuery` to get all the Gong Call IDs. It should look like this - `SELECT XXX, YYY, ZZZ
FROM Gong__Gong_Call__c
WHERE Gong__Primary_Account__c = '<AccountId>'
ORDER BY Gong__Call_Start__c DESC
LIMIT 2
`
4. Pass in the callIds to `getTranscriptsByCallIds `
# Trigger
User says "Summarize call"
# Steps
Use both the transcripts and provide the following output
## Account Name
Print out the account name
## Details of calls
>Please list the calls for which you retrieved the transcripts along with their dates and attendees in this table format:
>>Headers: <Title of Call>, <Date>, <Attendees>, <Gong URL>
## Recommended Meeting Focus Areas:
>Analyze the transcripts to identify themes, challenges, and opportunities. Based on this, generate a list of recommended focus areas for the next meeting. These should be actionable and specific to the client’s needs. Explain **why** each item should be a meeting focus.
For each of the following insights, specify **which call and date** you sourced the insight from:
### Metrics
Quantifiable outcomes the customer is trying to achieve. These could be cost reduction, increased revenue, user growth, efficiency gains, etc. Look for KPIs or success measures mentioned.
### Economic Buyer
Identify if the true economic decision-maker was mentioned or involved. This includes titles, names, or hints at budget ownership or final authority.
### Decision Criteria
What are the key factors the customer will use to evaluate solutions? These could include price, performance, support, integrations, ease of use, etc.
### Decision Process
Describe how the customer plans to make the buying decision: stages, stakeholders involved, approval processes, timelines.
### Paper Process
Any mention of legal, procurement, compliance, or contract-related steps and timelines should be captured here.
### Identify Pain
Highlight the core business challenges the customer is facing, ideally in their own words. Understand what’s driving urgency.
### Champion
Is there someone internally who is championing our solution? Mention names, roles, or behaviors that indicate advocacy (e.g., “I’m pushing this internally”).
### (Optional) Competition
Mention any competing vendors, internal builds, or alternative solutions discussed.
In the above example, replace the query in (3) to retrieves the Gong Call IDs from your custom Salesforce object.
You will now create 2 separate actions - one to connect to Salesforce and the other to connect to the middleware that calls the Gong APIs
OpenAPI Schema for Salesforce custom action
Once you've created a Custom GPT, copy the text below in the Actions panel. Have questions? Check out Getting Started Example to see how this step works in more detail.
Below is an example of what connecting to Salesforce might look like. You'll need to insert your URL in this section.
openapi: 3.1.0
info:
title: Salesforce API
version: 1.0.0
description: API for accessing Salesforce sObjects and executing queries.
servers:
- url: https://<subdomain>.my.salesforce.com/services/data/v59.0
description: Salesforce API server
paths:
/query:
get:
summary: Execute a SOQL Query
description: Executes a given SOQL query and returns the results.
operationId: executeSOQLQuery
parameters:
- name: q
in: query
description: The SOQL query string to be executed.
required: true
schema:
type: string
responses:
'200':
description: Query executed successfully.
content:
application/json:
schema:
$ref: '#/components/schemas/QueryResult'
/search:
get:
summary: Execute a SOSL Search
description: Executes a SOSL search based on the given query and returns matching records.
operationId: executeSOSLSearch
parameters:
- name: q
in: query
description: The SOSL search string (e.g., 'FIND {Acme}').
required: true
schema:
type: string
responses:
'200':
description: Search executed successfully.
content:
application/json:
schema:
$ref: '#/components/schemas/SearchResult'
components:
schemas:
QueryResult:
type: object
description: Result of a SOQL query.
properties:
totalSize:
type: integer
description: The total number of records matching the query.
done:
type: boolean
description: Indicates if the query result includes all records.
records:
type: array
description: The list of records returned by the query.
items:
$ref: '#/components/schemas/SObject'
SearchResult:
type: object
description: Result of a SOSL search.
properties:
searchRecords:
type: array
description: The list of records matching the search query.
items:
$ref: '#/components/schemas/SObject'
SObject:
type: object
description: A Salesforce sObject, which represents a database table record.
properties:
attributes:
type: object
description: Metadata about the sObject, such as type and URL.
properties:
type:
type: string
description: The sObject type.
url:
type: string
description: The URL of the record.
Id:
type: string
description: The unique identifier for the sObject.
additionalProperties: true
Authentication instructions for Salesforce custom actions
Please follow the steps shown in GPT Actions library - Salesforce
OpenAPI Schema for the middleware that connects to Gong
In this example, we are setting this up for an Azure Function that calls the Gong APIs. Replace url
with your own Middleware URL
openapi: 3.1.0
info:
title: Call Transcripts API
description: API to retrieve call transcripts and associated metadata by specific call IDs.
version: 1.0.1
servers:
- url: https://<subdomain>.azurewebsites.net/api
description: Production server
paths:
/callTranscripts:
post:
operationId: getTranscriptsByCallIds
x-openai-isConsequential: false
summary: Retrieve call transcripts by call IDs
description: Fetches specific call transcripts based on the provided call IDs in the request body.
requestBody:
required: true
content:
application/json:
schema:
type: object
properties:
callIds:
type: array
description: List of call IDs for which transcripts need to be fetched.
items:
type: string
required:
- callIds
responses:
'200':
description: A successful response containing the requested call transcripts and metadata.
content:
application/json:
schema:
type: object
properties:
requestId:
type: string
description: Unique request identifier.
records:
type: object
description: Metadata about the pagination.
properties:
totalRecords:
type: integer
description: Total number of records available.
currentPageSize:
type: integer
description: Number of records in the current page.
currentPageNumber:
type: integer
description: The current page number.
callTranscripts:
type: array
description: List of call transcripts.
items:
type: object
properties:
callId:
type: string
description: Unique identifier for the call.
title:
type: string
description: Title of the call or meeting.
started:
type: string
format: date-time
description: Timestamp when the call started.
duration:
type: integer
description: Duration of the call in seconds.
url:
type: string
format: uri
description: URL to access the call recording or details.
content:
type: string
description: Transcript content of the call.
'400':
description: Invalid request. Possibly due to missing or invalid `callIds` parameter.
'401':
description: Unauthorized access due to invalid or missing API key.
'500':
description: Internal server error.
Are there integrations that you’d like us to prioritize? Are there errors in our integrations? File a PR or issue in our github, and we’ll take a look.