How to Integrate Tray.io with Your Headless CMS
Connect Tray.io to your headless CMS so content changes can trigger CRM updates, product syncs, approval workflows, and customer notifications without manual copy-paste.
What is Tray.io?
Tray.io is an automation and integration platform used by operations, RevOps, IT, and product teams to connect SaaS apps, internal systems, APIs, and data workflows. Teams build automations in Tray.io using visual workflows, connectors, callable triggers, branching logic, and API calls. It sits in the same category as Workato, Zapier, Make, and n8n, with a strong fit for business-critical workflows that need more control than simple one-step automations.
Why integrate Tray.io with a headless CMS?
If your content changes need to kick off work in Salesforce, HubSpot, Slack, Jira, Airtable, Snowflake, or an internal API, Tray.io is often where that logic already lives. Connecting it to a headless CMS lets a publish event do real work: create a launch checklist, notify a regional sales team, update a product catalog, send a localization request, or start a compliance review.
Architecture overview
A typical Tray.io integration starts when an editor publishes or updates a document in Sanity Studio. Sanity writes that structured JSON document to the Content Lake. A GROQ-powered webhook filters the event, for example only published product pages where status == "live", and sends the document ID to a webhook handler or Sanity Function. That server-side handler fetches the latest document from the Content Lake with @sanity/client and GROQ. This keeps the Tray.io payload small and current. The query can join references, such as author, product family, region, or campaign, so Tray.io receives one clean JSON object. The handler then calls a Tray.io Callable Trigger URL with an HTTP POST request. In Tray.io, that callable workflow can map the incoming fields, call connectors like Salesforce or Slack, branch based on locale or content type, and write results to other systems. The end user might see a Slack notification, a CRM record update, a Jira task, a product feed update, or a customer-facing page that reflects the same published content.
Common use cases
Launch operations
When a campaign page is published in Sanity, Tray.io can create Jira tasks, notify Slack channels, update Salesforce campaign records, and log the launch in Airtable.
Product data routing
Send structured product copy, SKU metadata, release dates, and regional availability from Sanity to commerce, PIM, ERP, and spreadsheet workflows through Tray.io.
Localization handoffs
Trigger Tray.io workflows that send approved source content to translation tools, route locale-specific reviews, and write translation status back to your operations stack.
Sales and support updates
Use Tray.io to push newly published help articles, release notes, or pricing updates from Sanity into Slack, Zendesk, HubSpot, or internal enablement tools.
Step-by-step integration
- 1
Create the Tray.io workflow
In Tray.io, create a new workflow with a Callable Trigger. Copy the generated trigger URL. Add steps for the downstream systems you need, such as Slack, Salesforce, HubSpot, Jira, Google Sheets, or an HTTP Client call to an internal API. If the trigger should be private, require an Authorization header and store the token as a Tray.io config value.
- 2
Model the content in Sanity Studio
Define schema fields that Tray.io can route without guessing. For a product launch, include fields like title, slug, sku, launchDate, regions, lifecycleStatus, owner, relatedCampaign, and integrations.syncToTray. Keep IDs stable, use references for related documents, and avoid hiding workflow-critical data inside freeform rich text.
- 3
Create a Sanity webhook or Sanity Function
Use a Sanity webhook when you want Sanity to call your own endpoint on publish, update, or delete. Use a Sanity Function when you want the sync logic to run inside Sanity's server-side event system. In both cases, filter events with GROQ so Tray.io isn't called for drafts, internal notes, or content types that don't need automation.
- 4
Fetch the exact payload with GROQ
In your handler, use @sanity/client to fetch the current document from the Content Lake. Project only the fields Tray.io needs, and join references in the same query, for example author->name, categories[]->title, or productFamily->slug.current.
- 5
Post the payload to Tray.io
Call the Tray.io Callable Trigger URL with fetch, set content-type to application/json, and include your auth header if configured. In Tray.io, map the JSON fields to connector steps, add conditions for content type or region, and handle failures with Tray.io's workflow logs and retry settings.
- 6
Test the full path
Publish a test document in a non-production Sanity dataset, confirm the webhook fires, inspect the request body in your handler logs, and check the Tray.io run history. Then test update and delete events, not just first publish. Frontend apps should read from Sanity as usual, while Tray.io handles the operational side effects.
Code example
import {createClient} from '@sanity/client'
import type {VercelRequest, VercelResponse} from '@vercel/node'
const sanity = createClient({
projectId: process.env.SANITY_PROJECT_ID!,
dataset: process.env.SANITY_DATASET!,
apiVersion: '2025-02-19',
token: process.env.SANITY_READ_TOKEN,
useCdn: false,
})
export default async function handler(req: VercelRequest, res: VercelResponse) {
if (req.method !== 'POST') return res.status(405).end()
const {documentId} = req.body
const id = String(documentId).replace(/^drafts\./, '')
const doc = await sanity.fetch(
`*[_id == $id][0]{
_id,
_type,
title,
"slug": slug.current,
sku,
launchDate,
lifecycleStatus,
"regions": regions[],
"owner": owner->name
}`,
{id}
)
if (!doc) return res.status(204).end()
const trayRes = await fetch(process.env.TRAY_CALLABLE_TRIGGER_URL!, {
method: 'POST',
headers: {
'content-type': 'application/json',
authorization: `Bearer ${process.env.TRAY_TRIGGER_TOKEN}`,
},
body: JSON.stringify({event: 'sanity.content.published', document: doc}),
})
if (!trayRes.ok) {
const body = await trayRes.text()
return res.status(502).json({error: 'Tray.io trigger failed', body})
}
return res.status(200).json({ok: true})
}How Sanity + Tray.io works
Build your Tray.io integration on Sanity
Sanity gives you the structured content foundation, real-time event system, and flexible APIs you need to connect Tray.io workflows to the rest of your business systems.
Start building free →CMS approaches to Tray.io
| Capability | Traditional CMS | Sanity |
|---|---|---|
| Triggering Tray.io workflows | Often needs plugins, scheduled exports, or custom code tied to page publish events. | GROQ-powered webhooks and Functions can trigger Tray.io only for the documents and fields that matter. |
| Payload shape | Content is frequently mixed with layout markup, which makes routing fields into Tray.io steps harder. | GROQ can return one clean JSON payload with projected fields and referenced data in a single query. |
| Server-side sync logic | Custom sync code often lives in theme code, plugins, or a separate job runner. | Functions can run event-driven logic close to content changes, which reduces the extra infrastructure needed for Tray.io syncs. |
| Content model control | Models are often page-centric, so operational fields like lifecycleStatus or region can become ad hoc. | Schema-as-code lets teams version fields that Tray.io depends on, such as sku, owner, locale, and sync flags. |
| Multi-channel delivery | Automations may be tied to website pages, which makes reuse across apps and workflows harder. | One structured back end can serve web, mobile, Tray.io, and AI agents from the same modeled content. |
| Trade-offs | Fast for simple page publishing, but automation can become fragile as systems multiply. | Best results require thoughtful schemas and stable operational fields, especially when Tray.io workflows depend on specific values. |
Keep building
Explore related integrations to complete your content stack.
Sanity + Zapier
Connect Sanity publish events to quick no-code automations for notifications, spreadsheets, and lightweight operational tasks.
Sanity + Workato
Run enterprise-grade business workflows that connect structured Sanity content with finance, sales, support, and data systems.
Sanity + n8n
Build self-hosted automation flows that react to Sanity webhooks, call APIs, transform payloads, and sync content across tools.