Zendesk Sell can be the event source for customer communication, while Volanea handles the actual delivery. This guide shows how to send email from Zendesk Sell without a native marketplace app: Sell emits a webhook, your server-side relay validates and maps the event, and Volanea’s email API delivers the message.
There is an important architectural detail up front: Volanea does not provide a native Zendesk Sell app, listing, or marketplace plugin. The safe implementation is therefore an event-driven integration. Zendesk Sell is responsible for telling your endpoint that a record changed; your endpoint decides whether an email is appropriate and sends it through Volanea.
That separation is useful. It keeps delivery credentials out of Sell and out of browser-visible code, lets you apply business rules that go beyond a simple field mapping, and gives you one place to prevent duplicate customer messages when a webhook is retried.
What this integration does
The integration has three distinct hops:
- A user or another integration creates or updates a record in Zendesk Sell.
- A Zendesk Sell webhook posts an event notification to an HTTPS endpoint you operate.
- That endpoint maps the Sell record into a Volanea email request and sends the message using a Volanea API key stored in server-side secret storage.
A practical trigger is a deal stage change. For example, when a deal is moved to a stage named Closed won, your relay can send a welcome or implementation email to the deal’s primary contact. Another common trigger is a lead created event, which can send an acknowledgement after a lead enters Sell.
Do not treat every Sell event as permission to email someone. A record update says that data changed; it does not establish marketing consent, prove an email address is valid, or tell you whether the customer has already received the message. Your relay should enforce those decisions.
Why use a relay instead of calling Volanea from Sell directly?
A webhook destination receives an HTTP request. It is not a secure template runtime where you should embed a delivery-provider credential. A relay gives you a protected environment for the Volanea API key and lets you:
- fetch additional record data when the webhook is intentionally minimal;
- select the right recipient and template based on a stage, owner, region, or custom field;
- enforce suppression, consent, and idempotency rules;
- return a fast success response to Sell while delivery runs safely in a queue;
- record a trace linking the Sell event, your send attempt, and the Volanea response.
For teams that need to compare message volume with delivery costs before building the workflow, review transactional email pricing alongside the expected number of lead and deal events.
Zendesk Sell webhook events and the concrete trigger
Zendesk Sell’s API includes webhooks for receiving notifications when supported Sell resources change. Configure the webhook around the business event you want, rather than around a vague “contact updated” signal.
For this guide, the business rule is:
When a deal is updated and its current stage is
Closed won, send the primary contact a customer welcome email exactly once.
The webhook-level event is a deal update. The stage test belongs in your relay because a webhook reports that the resource changed, while the relay is where you can inspect the current record and decide whether this particular update warrants a message.
This distinction matters. A deal may be updated several times after it has reached Closed won: an owner might add a note, correct an amount, or update a custom field. If the relay only checks stage === "Closed won", it can send the welcome message repeatedly. The integration must additionally keep an idempotency record for the deal and the message purpose.
Create the webhook with the Sell API
Sell API webhook configuration is an administrative/API setup task. Use an API client or deployment script authenticated for your Sell account; do not expose that credential in frontend code. The exact event names and supported resources can vary with the Sell API version and account capabilities, so confirm them in the current Sell Webhooks API reference before provisioning production subscriptions.
Conceptually, the subscription specifies your HTTPS endpoint and the event to receive. A deal-update subscription has the following form:
POST https://api.getbase.com/v2/webhooks
Authorization: Bearer $ZENDESK_SELL_ACCESS_TOKEN
Content-Type: application/json
{
"url": "https://integrations.example.com/webhooks/zendesk-sell",
"events": ["deal.updated"]
}
Use a unique endpoint path for this integration and require HTTPS. In production, also use the webhook verification mechanism documented by Zendesk for your webhook type, and reject requests that do not pass verification.
If your account or workflow does not expose the native webhook feature you need, do not simulate a direct integration by putting a Volanea key into an automation field. Use an intermediary such as Zapier or Make to receive a Zendesk Sell trigger and invoke your relay. The relay design in this article remains the same: the automation platform sends a normalized payload to your HTTPS endpoint, and only that endpoint holds the Volanea key.
Understand the webhook payload before mapping fields
Webhook payloads are notifications, not a durable source of truth. The event includes metadata identifying the resource and action plus a data object containing the resource representation. In Sell’s API conventions, webhook notifications use a structure like this:
{
"meta": {
"type": "deal",
"event": "updated",
"timestamp": "2026-10-16T14:22:31Z"
},
"data": {
"id": 84721,
"name": "Acme annual plan",
"stage_id": 310001,
"value": 12000,
"currency": "USD",
"owner_id": 923,
"contact_id": 55390,
"updated_at": "2026-10-16T14:22:31Z"
}
}
Treat this as an illustrative deal-update notification shape, not as a reason to hard-code every possible field. The fields included in a resource representation depend on the resource, API version, permissions, and configured/custom fields. A deal event generally identifies the deal and its linked contact; it may not provide the recipient email address or the human-readable stage name you need for a customer message.
That is why the robust pattern is to use data.id as the authoritative identifier, then retrieve the current deal and contact from Sell’s API within the relay. Doing so is also safer when events arrive out of order. The relay can make its send decision using current state rather than relying on an older event body.
Field mapping for a closed-won email
For the example, the relay resolves these values:
| Email value | Zendesk Sell source | Notes |
|---|---|---|
| Recipient address | linked contact’s primary email | Reject or suppress if absent or invalid. |
| Recipient name | contact first and last name | Escape before inserting into HTML. |
| Deal name | deal.name | Useful for a confirmation or onboarding message. |
| Deal value | deal.value and deal.currency | Format server-side; never assume a currency symbol. |
| Current stage | retrieved deal stage | Compare a stable stage ID where possible, not only a display label. |
| Idempotency key | deal ID + message purpose | Example: sell-deal-84721-welcome-v1. |
A person may have multiple email addresses, no email address, or an address that should not be contacted. Make the recipient-selection policy explicit. In most CRM flows, use the primary email marked on the contact record, not an arbitrary custom-field string.
Before the first production send, it is sensible to run recipient addresses through an email address verification tool. Verification is not consent management, but it can help catch malformed or non-deliverable addresses before they become avoidable bounces.
Build a secure webhook relay
The relay can run as a Node.js service, serverless function, container worker, or endpoint in your existing backend. The important properties are not the hosting model; they are authentication, fast acknowledgement, durable processing, and idempotency.
Store the following as server-side secrets or environment variables:
ZENDESK_SELL_ACCESS_TOKENfor retrieving current Sell records when required;VOLANEA_API_KEYfor authenticated email sends;- the expected Zendesk webhook verification secret or verification configuration, if applicable;
VOLANEA_FROM_EMAILand a controlled sender display name.
Never put VOLANEA_API_KEY in a Sell custom field, a webhook URL query parameter, a browser application, a public repository, or a client-side automation configuration. Anyone who can read such a value can potentially send mail as your authenticated account, consume your sending quota, and damage your domain reputation.
Example Node.js endpoint and Volanea request
The following Express example shows the full mapping path. It accepts a Sell-style webhook body, acknowledges the request quickly, fetches the current deal and contact, checks a stage ID, uses a database-backed idempotency function, and posts the resulting email to Volanea.
Replace the endpoint and request-field names in the sendWithVolanea function with the current syntax in the Volanea API reference and setup guides before deployment. Keep the API key on the server exactly as shown; it must not be returned to Zendesk Sell, a browser, or an automation platform.
import express from "express";
const app = express();
app.use(express.json({ limit: "256kb" }));
const SELL_API = "https://api.getbase.com/v2";
const CLOSED_WON_STAGE_ID = Number(process.env.ZENDESK_SELL_CLOSED_WON_STAGE_ID);
async function sellGet(path) {
const response = await fetch(`${SELL_API}${path}`, {
headers: {
Authorization: `Bearer ${process.env.ZENDESK_SELL_ACCESS_TOKEN}`,
Accept: "application/json"
}
});
if (!response.ok) {
throw new Error(`Zendesk Sell GET ${path} failed: ${response.status}`);
}
return response.json();
}
function escapeHtml(value = "") {
return String(value)
.replaceAll("&", "&")
.replaceAll("<", "<")
.replaceAll(">", ">")
.replaceAll('"', """)
.replaceAll("'", "'");
}
async function sendWithVolanea({ to, recipientName, dealName, dealValue }) {
// Use the current Volanea REST endpoint and JSON schema from /docs.
const response = await fetch(process.env.VOLANEA_EMAIL_API_URL, {
method: "POST",
headers: {
Authorization: `Bearer ${process.env.VOLANEA_API_KEY}`,
"Content-Type": "application/json",
Accept: "application/json"
},
body: JSON.stringify({
from: {
email: process.env.VOLANEA_FROM_EMAIL,
name: "Acme Customer Team"
},
to: [{ email: to, name: recipientName }],
subject: `Welcome — your ${dealName} is ready`,
html: `
<h1>Welcome, ${escapeHtml(recipientName)}</h1>
<p>Thanks for choosing us for <strong>${escapeHtml(dealName)}</strong>.</p>
<p>Your recorded deal value is ${escapeHtml(dealValue)}.</p>
<p>Reply to this message if you need help getting started.</p>
`,
text: `Welcome, ${recipientName}. Thanks for choosing us for ${dealName}. Reply to this email if you need help getting started.`
})
});
if (!response.ok) {
throw new Error(`Volanea send failed: ${response.status} ${await response.text()}`);
}
return response.json();
}
app.post("/webhooks/zendesk-sell", async (req, res) => {
// Verify the Zendesk webhook according to the current Sell webhook docs
// before processing. Do not rely on IP allowlists alone.
const event = req.body;
if (event?.meta?.type !== "deal" || event?.meta?.event !== "updated") {
return res.sendStatus(204);
}
const dealId = event?.data?.id;
if (!dealId) return res.status(400).json({ error: "Missing deal ID" });
// Acknowledge quickly. In production, enqueue { dealId, event } here and
// process the queue in a worker rather than doing network calls inline.
res.sendStatus(202);
try {
const dealEnvelope = await sellGet(`/deals/${dealId}`);
const deal = dealEnvelope.data;
if (deal.stage_id !== CLOSED_WON_STAGE_ID || !deal.contact_id) return;
const contactEnvelope = await sellGet(`/contacts/${deal.contact_id}`);
const contact = contactEnvelope.data;
const primaryEmail = contact.email;
if (!primaryEmail) return;
const recipientName = [contact.first_name, contact.last_name]
.filter(Boolean)
.join(" ") || "there";
const dealValue = new Intl.NumberFormat("en-US", {
style: "currency",
currency: deal.currency || "USD"
}).format(Number(deal.value || 0));
const idempotencyKey = `sell-deal-${deal.id}-welcome-v1`;
const claimed = await database.claimIdempotencyKey(idempotencyKey);
if (!claimed) return; // This deal already received this email purpose.
const result = await sendWithVolanea({
to: primaryEmail,
recipientName,
dealName: deal.name || "new account",
dealValue
});
await database.markSent(idempotencyKey, result);
} catch (error) {
console.error("Zendesk Sell to Volanea worker failed", { dealId, error });
// Mark the job retryable or send it to a dead-letter queue as appropriate.
}
});
The example deliberately returns 202 Accepted before the external API calls. In a production system, enqueue the validated event before returning the response, then let a worker perform Sell lookups and the Volanea send. That avoids making webhook delivery depend on two additional network calls finishing within the webhook timeout window.
Configure sender identity and message content
A technically successful API call is not the same as a deliverable customer email. The sender domain used in VOLANEA_FROM_EMAIL should be a domain you control and have authenticated in Volanea. Configure the DNS records requested during sender-domain setup, then use a consistent From address such as onboarding@updates.example.com or support@example.com.
Do not use the contact owner’s personal address as the From address merely because Sell stores it. That creates reply-routing, ownership, and domain-authentication complications. Instead, choose a role address with a monitored reply path, and optionally set a Reply-To address in the Volanea request when the current API supports it.
Keep transactional and marketing logic separate
A closed-won welcome is often an operational or transactional communication, but classification depends on its content and jurisdiction. If the message promotes unrelated products, newsletter content, or future offers, treat it as marketing and apply the applicable consent and unsubscribe rules.
Build those controls before sending, not after a complaint. Your relay can check a custom Sell field such as marketing_opt_in, but only if that field is maintained as a reliable consent record. For critical consent and suppression decisions, maintain a dedicated preference system or synchronize a clearly governed source of truth.
Use templates that degrade well in inboxes:
- include a plain-text part as well as HTML;
- keep the subject specific to the action that caused the send;
- avoid placing important information only in images;
- use a real support or onboarding reply path;
- include required compliance text appropriate to the message category and recipients.
Make stage-based automation reliable
Stage names change. An administrator may rename Closed won to Customer, localize the label, or add a similar stage. A comparison against a display label will then silently alter automation behavior. Prefer a stable Sell stage identifier stored in ZENDESK_SELL_CLOSED_WON_STAGE_ID, and document what the ID represents.
You should also decide whether the event means “entered this stage” or merely “is currently in this stage.” Those are not equivalent. If you need the former, store the previously processed stage ID in your own database or audit trail and only send when the persisted value differs from the current target stage.
Recommended decision sequence
A reliable worker makes decisions in this order:
- Verify that the request is an authentic Sell webhook.
- Confirm the event resource is relevant, such as a deal update.
- Fetch the current resource when the event body does not include every required value.
- Confirm the stable stage ID and recipient eligibility.
- Build a deterministic idempotency key for the business action.
- Atomically claim that key before calling Volanea.
- Send the email and persist the provider response and timestamp.
- Retry only failures that are safe and likely transient.
The atomic claim is important. Two webhook deliveries can arrive nearly simultaneously. A simple “check whether sent” query followed by an insert is vulnerable to a race; both workers may observe no row and both send. Use a unique database constraint, conditional write, or queue-level deduplication keyed by the same idempotency key.
When this breaks: diagnose the Sell-to-Volanea hop
Every integration eventually sees malformed data, retries, and slow downstream services. Design for those conditions before enabling customer-facing messages.
Zendesk Sell retries can create duplicate sends
A webhook sender may retry when it does not receive a timely successful response or encounters a transient delivery problem. Retries are normal behavior, not necessarily a Sell defect. In addition, users can make multiple qualifying updates to the same deal.
Never depend on the webhook being delivered exactly once. The sell-deal-84721-welcome-v1 key in the example makes the intended business action exactly-once from your application’s perspective. If the process fails after Volanea accepts the message but before your database is marked sent, investigate the provider response and use a delivery/request identifier where available before blindly retrying.
Webhook timeouts can turn a slow workflow into a retry storm
Fetching a deal, fetching a contact, rendering a message, calling Volanea, and writing logs inside the HTTP request can exceed a webhook sender’s timeout. Even if the first send eventually completes, Sell may regard the request as failed and post it again.
Return a 2xx response quickly after validating and durably queuing the event. Make the queue worker responsible for the slower operations. Monitor queue lag, worker failures, and API latency separately, because they point to different fixes.
Payload fields may be missing
A webhook’s data object may not include the email address, linked contact, custom field, or stage details expected by your template. Availability can differ by resource, account configuration, permissions, API version, and Sell plan.
Do not substitute an empty string into a recipient field or guess an address from a company domain. Fetch the resource when needed, then stop the job with a clear reason such as missing_contact_email, missing_contact_id, or unrecognized_stage. Alert the responsible team only after grouping recurring errors; one incomplete CRM record should not create hundreds of alerts.
The stage identifier or custom-field model can change
An administrator can modify pipeline stages and custom fields without deploying application code. Maintain an integration configuration screen or environment configuration that records the target pipeline and stage IDs. Add a periodic test that checks whether the configured stage still exists and whether a sample deal has the fields your relay requires.
Volanea accepts the request but inbox delivery is delayed
A successful API response means Volanea accepted the send request; it does not guarantee immediate inbox placement. Delivery can be affected by recipient-server behavior, sender-domain authentication, reputation, content, and recipient mailbox state.
Record the Volanea message identifier alongside the Sell deal ID. That correlation lets support teams investigate a customer report without searching a CRM timeline and a delivery system independently.
Alternatives when native Sell webhooks are not available to you
Some teams cannot use the required Sell webhook capability because of their plan, permissions, change-control policy, or existing integration tooling. In that case, use Zapier or Make as the event collector, but keep the Volanea call behind your own endpoint.
The automation platform can watch a supported Zendesk Sell event such as a new lead, new deal, or updated deal, then issue an HTTP POST to your relay. Give that POST a normalized body you own, for example:
{
"source": "zendesk-sell-via-automation",
"event": "deal.updated",
"deal_id": "84721",
"received_at": "2026-10-16T14:22:31Z"
}
Your relay then uses deal_id to retrieve authoritative data from Sell, applies the same idempotency and consent checks, and sends through Volanea. This approach is more portable, but it adds another vendor, another retry policy, and another place where mappings can be edited. Secure the automation-to-relay request with a secret header or signed request and rotate that secret when access changes.
Avoid placing the Volanea API key directly in a generic “custom request” action in a third-party workflow unless you fully understand the platform’s secret handling, audit model, and access controls. A relay gives you more control over rotation, logging, policy enforcement, and provider changes.
Test the integration before enabling live sends
Start with a sandbox-like path: a test pipeline stage, a test contact address you control, and a sender domain already authenticated in Volanea. Do not test by repeatedly moving real customer deals through a production stage.
Use this test checklist:
- Create or update a test deal so that it enters the configured target stage.
- Confirm Sell delivered the webhook to the expected endpoint.
- Confirm the relay verified the request and queued one job.
- Confirm the worker retrieved the correct deal and primary contact.
- Check the rendered recipient, subject, text, and HTML before accepting the send.
- Move or update the same deal again and confirm idempotency prevents a second welcome message.
- Test a deal with no linked contact and a contact with no email; both should fail safely without sending.
- Force a temporary Volanea API failure and verify the worker retries without creating a duplicate message.
- Check that the email arrives with the expected From domain and working reply path.
Log structured identifiers rather than raw email bodies wherever possible. At minimum, log the Sell resource ID, event type, idempotency key, recipient domain or a protected recipient reference, Volanea message/request ID, response status, and timestamps. Apply your organization’s retention and privacy policies to logs because CRM-derived data is customer data.
Operational ownership and monitoring
This integration crosses sales operations, engineering, customer success, and deliverability. Assign an owner for each concern. Sales operations should own stage semantics and CRM data quality. Engineering should own webhook authentication, queue health, secret rotation, and code changes. The messaging owner should own sender identity, template content, suppression policy, and deliverability review.
Track operational metrics that expose failure modes early:
- webhook requests received, verified, rejected, and queued;
- jobs skipped for missing contact, missing email, ineligible stage, or duplicate key;
- Volanea request success and error rates by response category;
- age of the oldest queued job;
- messages sent by template and by Sell stage;
- bounce, complaint, and suppression signals associated with this workflow.
A sudden increase in skipped records often indicates a CRM configuration change. A sudden rise in retries may indicate an endpoint outage, a Sell API access issue, or a delivery API problem. Separating these metrics prevents a vague “emails are broken” incident from becoming a long manual investigation.
Conclusion
The dependable way to send email from Zendesk Sell with Volanea is not a marketplace installation. It is a controlled server-side workflow: use a Sell webhook or supported automation trigger, identify the relevant lead or deal event, retrieve the current record when necessary, make a consent-aware decision, and send through Volanea using a protected API key.
The technical center of the design is idempotency. Webhooks can be retried, CRM records can be updated repeatedly, and external APIs can be slow. A durable queue, an atomic business-action key, and clear event-to-message mapping turn those ordinary conditions into predictable behavior rather than duplicate customer mail.
FAQ
Can Zendesk Sell send directly through Volanea?
Volanea does not provide a native Zendesk Sell marketplace app or plugin. Use a Zendesk Sell webhook that calls your server-side relay, then have that relay call the Volanea API with a protected API key.
What Zendesk Sell event should trigger the email?
Use the event that represents a real business action, such as a deal update followed by a check that the deal is in your closed-won stage, or a lead-created event for a lead acknowledgement. Use stable resource and stage identifiers where possible.
Where should the Volanea API key be stored?
Store it only in server-side secret storage, such as encrypted environment variables or a managed secrets service used by the relay. Do not put it in client-visible code, webhook URLs, Sell fields, or public automation configuration.
How do I stop duplicate emails after webhook retries?
Create an idempotency key based on the Sell record ID and message purpose, such as sell-deal-84721-welcome-v1, and enforce it with an atomic database insert or conditional write before sending.
What if the Sell webhook does not contain the contact email?
Use the webhook’s resource ID to retrieve the current deal and linked contact through the Sell API. If the contact or primary email is absent, skip the send safely and record a specific reason for follow-up.