How to Integrate Outreach with Your Headless CMS
Connect Outreach to structured content so sales teams can enroll prospects, route sequences, and use fresh campaign messaging without copying data by hand.
What is Outreach?
Outreach is a sales execution platform used by revenue teams to run sequences, manage prospect engagement, track rep activity, and coordinate follow-up across email, calls, and tasks. Teams use it to turn account data, buyer signals, and sales plays into repeatable workflows for SDRs, account executives, and customer teams. Its API exposes resources like prospects, accounts, sequences, sequence states, mailboxes, and tasks through OAuth 2.0 and JSON:API endpoints.
Why integrate Outreach with a headless CMS?
Sales teams move fast, but content usually moves slower. A campaign page gets updated, a new industry proof point ships, or a gated guide starts collecting qualified leads, and then someone has to copy that context into Outreach, update sequence notes, assign the right follow-up path, or export a CSV. That works for 20 leads. It breaks when you have 2,000 prospects, 8 regional campaigns, and reps asking which message is current.
Connecting Outreach to a headless CMS category tool gives your sales workflows a reliable source of structured campaign data. With Sanity, content in the Content Lake is typed JSON, so a webhook can send exactly the lead, campaign, persona, offer, and sequence ID that Outreach needs. No HTML scraping. No parsing page blobs. No nightly spreadsheet job that misses the launch window.
The trade-off is that you do need to design the data model carefully. If Outreach sequences are tied to campaigns, regions, or personas, those relationships should exist in your Sanity schema instead of living in someone’s notes. Once that structure is in place, webhooks and Functions can sync changes the moment content is published, submitted, or updated.
Architecture overview
A typical Sanity and Outreach integration starts with structured content in the Content Lake. For example, a campaign document can reference a persona, offer, region, and Outreach sequence ID, while a lead form submission can capture email, company, job title, campaign source, and consent status. When a relevant document is created or published, a Sanity webhook fires with the document ID and mutation details. A Sanity Function, or a small webhook listener, receives the event and runs a GROQ query against the Content Lake to fetch only the fields Outreach needs. That query can join references, such as pulling `campaign->outreachSequenceId` or `persona->salesMessaging`, in one request. The server-side handler then calls Outreach’s REST API at `https://api.outreach.io/api/v2` using an OAuth access token. For a lead capture flow, it can create or update a prospect with `POST /prospects`, then enroll that prospect in a sequence with `POST /sequenceStates` using the sequence and mailbox IDs stored in Sanity. The sales rep sees the prospect in Outreach, the prospect receives the right sequence, and the same structured campaign content can still feed your website, mobile app, and AI agents.
Common use cases
Route gated-content leads into sequences
Send form submissions from Sanity to Outreach as prospects, then enroll them in the sequence tied to the campaign they converted on.
Keep sales plays tied to live campaign content
Model personas, objections, offers, and proof points in Sanity, then sync the right fields into Outreach workflows for each campaign.
Handle regional follow-up rules
Use Sanity fields like region, language, segment, and consent status to choose the correct Outreach sequence, mailbox, and owner.
Publish approved messaging for reps
Give sales teams current email snippets, call notes, and CTA copy from approved Sanity content instead of stale docs or chat threads.
Step-by-step integration
- 1
Set up Outreach API access
Create an OAuth application in Outreach, set the redirect URI, and request scopes for the resources you’ll call, such as prospects, sequence states, sequences, and mailboxes. Complete the OAuth flow, store the refresh token in a secret manager, and use it to mint access tokens for server-side API calls.
- 2
Model the sales content in Sanity Studio
Create schemas for campaign, persona, offer, and lead submission. Include fields like `email`, `company`, `title`, `campaign`, `outreachSequenceId`, `outreachMailboxId`, `region`, `consentStatus`, and `sourceUrl` so the sync code doesn’t need to infer sales routing from unstructured text.
- 3
Create a webhook or Function trigger
Configure a Sanity webhook to fire when a `leadSubmission` document is created, or when a campaign moves to a published state. Use a GROQ filter such as `_type == 'leadSubmission' && consentStatus == 'marketing_accepted'` to avoid sending drafts, tests, or unqualified records to Outreach.
- 4
Fetch exactly what Outreach needs with GROQ
In your handler, use `@sanity/client` to fetch the submitted lead and join the referenced campaign in one query. Pull only the fields required for the Outreach API call, such as name, email, company, sequence ID, mailbox ID, and source campaign.
- 5
Call Outreach’s REST API
Use `POST /api/v2/prospects` to create the prospect, then `POST /api/v2/sequenceStates` to add that prospect to the correct sequence. Outreach uses JSON:API payloads, so send resources inside a top-level `data` object with `type`, `attributes`, and `relationships`.
- 6
Test the full sales path
Submit a test lead from your frontend, confirm the document appears in Sanity Studio, check the webhook delivery log, and verify that the prospect and sequence state appear in Outreach. Test duplicate emails, missing sequence IDs, revoked consent, and API rate-limit responses before you turn it on for production traffic.
Code example
import {createClient} from '@sanity/client'
const sanity = createClient({
projectId: process.env.SANITY_PROJECT_ID!,
dataset: process.env.SANITY_DATASET!,
apiVersion: '2025-01-01',
token: process.env.SANITY_READ_TOKEN!,
useCdn: false
})
async function outreach(path: string, body: unknown) {
const res = await fetch(`https://api.outreach.io/api/v2${path}`, {
method: 'POST',
headers: {
Authorization: `Bearer ${process.env.OUTREACH_ACCESS_TOKEN}`,
'Content-Type': 'application/vnd.api+json',
Accept: 'application/vnd.api+json'
},
body: JSON.stringify(body)
})
if (!res.ok) throw new Error(`Outreach ${res.status}: ${await res.text()}`)
return res.json()
}
export default async function handler(req: any, res: any) {
const docId = req.body?._id
const lead = await sanity.fetch(`*[_id == $id][0]{
firstName,
lastName,
email,
company,
title,
"sequenceId": campaign->outreachSequenceId,
"mailboxId": campaign->outreachMailboxId
}`, {id: docId})
if (!lead?.email || !lead?.sequenceId || !lead?.mailboxId) {
return res.status(202).json({skipped: true})
}
const prospect = await outreach('/prospects', {
data: {
type: 'prospect',
attributes: {
firstName: lead.firstName,
lastName: lead.lastName,
emails: [lead.email],
company: lead.company,
title: lead.title
}
}
})
await outreach('/sequenceStates', {
data: {
type: 'sequenceState',
relationships: {
prospect: {data: {type: 'prospect', id: prospect.data.id}},
sequence: {data: {type: 'sequence', id: lead.sequenceId}},
mailbox: {data: {type: 'mailbox', id: lead.mailboxId}}
}
}
})
res.status(200).json({ok: true, outreachProspectId: prospect.data.id})
}How Sanity + Outreach works
Build your Outreach integration on Sanity
Sanity gives you the structured content foundation, real-time event system, and flexible APIs to connect Outreach with the sales workflows your team already runs.
Start building free →CMS approaches to Outreach
| Capability | Traditional CMS | Sanity |
|---|---|---|
| Lead capture to Outreach | Often needs form plugins, CSV exports, or custom database access before a lead can become an Outreach prospect. | A webhook or Function can react to a lead document, fetch routing fields with GROQ, and call Outreach’s prospects and sequence state APIs. |
| Campaign-to-sequence mapping | Sequence IDs and campaign rules are usually kept in plugin settings, spreadsheets, or hidden custom fields. | Schema fields can model campaign, persona, region, offer, sequence ID, mailbox ID, and consent rules in Sanity Studio. |
| Real-time sales follow-up | Sales handoff often depends on scheduled exports, manual imports, or third-party automation tools. | Webhooks and Functions can run server-side sync logic on content events, with no separate polling job. |
| Field-level control | Content is frequently stored as page-oriented HTML, so extracting clean fields for Outreach takes extra parsing. | GROQ selects exactly the fields Outreach needs, including joins across references, arrays, and localized content. |
| Multi-channel reuse | Sales copy, website copy, and rep notes often drift because each channel keeps its own version. | One structured back end can feed web, mobile, Outreach, and AI agents through APIs, webhooks, Functions, and Agent Context. |
Keep building
Explore related integrations to complete your content stack.
Sanity + Salesforce
Sync structured campaign and lead context between Sanity and Salesforce so sales records reflect the content journey that created them.
Sanity + HubSpot CRM
Connect Sanity content and form data with HubSpot CRM to route contacts, campaigns, and lifecycle updates from one structured source.
Sanity + Gong
Pair approved sales messaging in Sanity with Gong insights so teams can compare what reps say with the content buyers see.