How to Integrate Close with Your Headless CMS
Connect Close to structured content so sales teams can see campaign context, source details, and follow-up prompts the moment content changes.
What is Close?
Close is a CRM built for sales teams that rely on outbound calling, email, SMS, task queues, and pipeline tracking in one workflow. Teams use it to create leads, contacts, opportunities, activities, and follow-up sequences through the Close app or API. It's common with startups, agencies, and B2B sales teams that need fast rep workflows without a large CRM admin layer.
Why integrate Close with a headless CMS?
Sales teams lose context when campaign content, landing pages, gated assets, and CRM records live in separate systems. A rep may see a lead in Close with an email address and company name, but not the exact guide they downloaded, the industry page they visited, the persona they matched, or the offer that triggered the conversation. That missing context turns into slower follow-up and generic outreach.
Architecture overview
A typical Sanity and Close integration starts when a content editor publishes or updates a sales-related document in Sanity Studio, such as a campaign, gated asset, partner page, event lead, or sales play. The published document lands in the Content Lake as structured JSON. A Sanity webhook fires on the publish event, or a Sanity Function runs directly on the content mutation. The handler uses GROQ to fetch the document plus any referenced content, such as persona, product, region, CTA, and owner fields. It then calls Close's REST API at https://api.close.com/api/v1 using the Close API key as HTTP Basic auth. Depending on your workflow, the handler can create a lead with contacts, update custom fields, add a note activity, create a task for the assigned rep, or attach source content to an opportunity. The end result is practical: the website still renders from Sanity, while the sales rep sees the right campaign context in Close before making the first call.
Common use cases
Campaign-to-lead context
When a gated campaign is published in Sanity, send the campaign title, URL, persona, and source offer into Close lead fields.
Rep task creation
Create Close tasks for the right sales owner when a high-intent page, event list, or account-based landing page goes live.
Sales notes from content
Add Close note activities with approved talk tracks, objection handling, and case study links from Sanity Studio.
Persona-based routing
Map Sanity fields like industry, company size, region, and product interest to Close custom fields for better lead routing.
Step-by-step integration
- 1
Set up Close API access
Create or sign in to your Close account, then generate an API key from Close settings. Close uses HTTP Basic auth, with the API key as the username and an empty password. Keep the key in an environment variable such as CLOSE_API_KEY.
- 2
Install the Sanity client
In the app, webhook listener, or Sanity Function that will sync data, install the Sanity client with npm install @sanity/client. Add SANITY_PROJECT_ID, SANITY_DATASET, SANITY_API_VERSION, and a read token if your dataset isn't public.
- 3
Model sales-ready content in Sanity Studio
Create schemas for the content Close needs, such as campaignLead, gatedAsset, salesPlay, persona, and product. Useful fields include companyName, contactName, email, phone, website, campaign reference, persona reference, sourceUrl, closeLeadId, lifecycleStage, and assignedRepEmail.
- 4
Create the sync trigger
Use a Sanity webhook filtered to the document types you want to sync, for example _type == 'campaignLead'. For server-side logic inside Sanity, use Functions so the sync runs on content events without a separate job runner.
- 5
Call the Close API
Use GROQ to fetch the exact fields and references needed for Close, then call the Close Lead API to create a lead, update a lead, add a contact, or create a note activity. If you need idempotency, store the returned Close lead ID back on the Sanity document.
- 6
Test the full sales workflow
Publish a test document in Sanity Studio, confirm the webhook or Function runs, verify the lead or activity in Close, and open the frontend page to make sure the same content is visible to customers. Test updates and deletes too, not just first publish.
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,
});
export async function POST(req: Request) {
const {_id} = await req.json();
const lead = await sanity.fetch(`
*[_id == $id][0]{
companyName,
website,
contactName,
email,
phone,
sourceUrl,
campaign->{title},
persona->{name}
}
`, {id: _id});
const auth = Buffer.from(`${process.env.CLOSE_API_KEY!}:`).toString('base64');
const closeRes = await fetch('https://api.close.com/api/v1/lead/', {
method: 'POST',
headers: {
Authorization: `Basic ${auth}`,
'Content-Type': 'application/json',
},
body: JSON.stringify({
name: lead.companyName,
url: lead.website,
description: `Source: ${lead.sourceUrl}
Campaign: ${lead.campaign?.title}
Persona: ${lead.persona?.name}`,
contacts: [{
name: lead.contactName,
emails: [{email: lead.email, type: 'office'}],
phones: lead.phone ? [{phone: lead.phone, type: 'office'}] : [],
}],
}),
});
if (!closeRes.ok) {
return Response.json({error: await closeRes.text()}, {status: 500});
}
return Response.json(await closeRes.json());
}How Sanity + Close works
Build your Close integration on Sanity
Sanity's AI Content Operating System gives you the structured content foundation, real-time event system, and flexible APIs to connect Close with the channels your team already ships.
Start building free →CMS approaches to Close
| Capability | Traditional CMS | Sanity |
|---|---|---|
| CRM-ready content structure | Campaign and CTA data often live inside page layouts, plugins, or rich text fields, which makes CRM mapping brittle. | The Content Lake stores typed JSON with references, so one GROQ query can return campaign, persona, product, and owner data for Close. |
| Sync timing | Teams often rely on form plugins, exports, or scheduled jobs, so Close can lag behind published content. | Webhooks or Functions can run on publish, update, and delete events, then call the Close API without polling. |
| Field-level payload control | The CRM sync may receive too much page data or not enough structured metadata for sales follow-up. | GROQ selects only the fields Close needs, including joined references and computed labels for notes, tasks, and lead descriptions. |
| Sales context in rep workflows | Reps may need to open the website or ask marketing to understand which offer a lead responded to. | Sanity Studio can model sales plays, approved talk tracks, source pages, and campaign metadata that sync into Close activities. |
| Maintenance trade-off | Lower setup effort if a plugin exists, but custom CRM behavior can become hard to change. | Schema-as-code needs developer involvement up front, but it gives versioned models, clear field contracts, and event-driven sync paths. |
Keep building
Explore related integrations to complete your content stack.
Sanity + Salesforce
Sync structured campaign, account, and product content from Sanity into Salesforce workflows for larger revenue teams.
Sanity + HubSpot CRM
Connect Sanity content with HubSpot CRM records, forms, and lifecycle stages for marketing and sales handoff.
Sanity + Outreach
Use approved messaging, case studies, and persona content from Sanity inside outbound sales sequences.