Autopilot email integration does not require a marketplace app or a native plugin. You can use Autopilot’s Webhook action inside a Journey to call a server-side endpoint, then have that endpoint map the contact payload into a Volanea transactional email request.
This pattern is useful when an Autopilot Journey should trigger an operational message that is better owned by your application and email infrastructure: a trial activation notice, a completed-request receipt, a document-ready email, a sales handoff confirmation, or a message that needs application data not available in an Autopilot email template.
The integration model: Autopilot Journey to your webhook to Volanea
Autopilot supports a Webhook action in a Journey. When a contact reaches that action, Autopilot calls the URL you configure using the HTTP method you choose. The action can include custom headers, HTTP basic authentication, and a custom payload. It is explicitly intended for calling your own API.
There is no native Volanea listing to install in an Autopilot marketplace. That is a feature, not a limitation, when you need control over the message: the integration is simply an event-driven connection between an Autopilot Journey and an endpoint you operate.
The recommended path looks like this:
- A contact enters an Autopilot Journey.
- The contact reaches an Autopilot Webhook action.
- Autopilot sends the contact record or records to your HTTPS endpoint.
- Your endpoint authenticates and validates the request.
- Your endpoint decides whether the event has already been processed.
- Your endpoint maps Autopilot fields into a Volanea send request.
- Volanea accepts the email for delivery.
- Your endpoint returns a fast
2xxresponse to Autopilot.
This extra server-side hop is important. It keeps the Volanea API key out of browser code, lets you validate incomplete contact data, gives you a durable place to prevent duplicates, and lets you use business logic before email is sent.
For the exact Volanea endpoint, authentication header, and message schema used by your account, refer to the email API reference and setup guides. Keep that API call in your server environment rather than placing credentials in a public form, front-end bundle, or client-side tag manager.
The concrete Autopilot trigger that starts the email
In Autopilot, the immediate trigger is not an external “send email” button. It is a contact reaching a Webhook action shape on the Journey canvas.
That distinction matters because you control the event that places a contact onto the branch leading to the action. For example, a Journey can begin when a contact is added to a list, when an Autopilot form submission adds or updates a contact, or when a condition branch identifies a contact whose field value has changed. The actual outbound HTTP request occurs when that contact reaches the Webhook action.
A practical example: form submission confirmation
Suppose an Autopilot form collects requests for a product demo. You may want a transactional confirmation from your application’s sending domain rather than a marketing-style follow-up message.
A workable Journey design is:
- An Autopilot form submission creates or updates a contact.
- The contact is added to a list such as
Demo request received. - A Journey begins for contacts added to that list.
- A condition checks that the contact has an email address and the expected consent or request field.
- The contact reaches the Webhook action.
- Your webhook endpoint sends a Volanea email such as “We received your request.”
- The Journey continues to sales-routing, wait, or nurture steps.
The Webhook action is therefore the precise integration trigger. A form submit, list entry, or field-based Journey branch can lead to it, but the Webhook action is the point at which Autopilot calls your system.
Why use a Journey action instead of a browser request
A browser request is tied to an individual visitor session. It can be blocked, abandoned, replayed, exposed to client-side inspection, or sent before your contact profile is fully updated. A Journey action is tied to Autopilot’s contact processing and gives you a consistent automation point after the contact reaches the correct stage.
It also prevents your Volanea credentials from being included in JavaScript. The browser should submit a form or trigger an application event; Autopilot and your server should handle downstream automation.
Configure the Autopilot Webhook action
Add a Webhook action to the relevant Journey branch, then configure it to call an HTTPS endpoint you control. For example:
Method: POST
URL: https://app.example.com/webhooks/autopilot/volanea
Header: Content-Type: application/json
Header: X-Autopilot-Webhook-Secret: <long-random-secret>
Custom payload: demo-request-confirmation-v1
Autopilot lets you provide a URL and HTTP method for the action. It also supports custom headers, which are useful for request verification, plus a custom payload that can identify why the webhook was invoked.
Use a distinct endpoint or custom payload for each meaningful email workflow. A demo-request-confirmation-v1 value is more useful than a generic label such as email, because your receiving application can select the appropriate Volanea template, sender identity, reply-to policy, and idempotency behavior.
Keep the webhook endpoint HTTPS-only
The receiving endpoint should be publicly reachable over HTTPS. Do not expose an unencrypted HTTP endpoint, and do not use an endpoint that forwards blindly to Volanea without checking the request.
At a minimum, your endpoint should:
- Require a shared secret sent in an Autopilot custom header.
- Compare that secret using a timing-safe comparison where your platform supports it.
- Validate that the request body has a
recordsarray. - Validate the email address before sending.
- Reject unexpected workflow values or Journey IDs.
- Log a correlation ID without logging full credentials.
- Return quickly after the request is safely accepted or processed.
Use a secret unique to this webhook
Do not reuse a production application password, a Volanea API key, or a personal Autopilot credential as the X-Autopilot-Webhook-Secret. Generate a long, random value solely for this route.
The shared webhook secret proves that the request came through the configuration you control. It does not replace application-level validation. A valid secret with an invalid or unexpected payload should still be rejected.
The Autopilot webhook payload you should expect
Autopilot sends a JSON object containing a records array, a journey object, and any custom payload configured on the Webhook action. A contact record includes standard and custom contact data available to the Journey.
A representative shape is:
{
"records": [
{
"Name": "Avery Chen",
"FirstName": "Avery",
"LastName": "Chen",
"Email": "avery@example.com",
"Company": "Example Co",
"Status": "Lead",
"contact_id": "person_637C329C-4398-47BF-BA0E-AC19FC7A8117",
"created_at": "2020-04-26T23:09:25.000Z",
"updated_at": "2020-04-27T00:18:55.000Z",
"lists": [],
"custom_fields": []
}
],
"journey": {
"name": "Demo request confirmation",
"id": "campaign_A230A520-D08E-4E19-BAD4-F22C76A667A0"
},
"custom": "demo-request-confirmation-v1"
}
The important implementation detail is that records is an array. Do not write an endpoint that processes only records[0] and silently ignores everyone else. Autopilot can send multiple contacts in one webhook payload, with up to 200 records in the array.
Field mapping rules
Before writing your Volanea call, decide which Autopilot fields are mandatory and which are optional. A safe mapping for a confirmation email might be:
| Autopilot field | Volanea email value | Handling rule |
|---|---|---|
records[].Email | recipient address | Required; skip and log invalid or absent values |
records[].FirstName | recipient display name and template variable | Optional; use a neutral fallback such as there |
records[].Name | fallback display name | Use only when FirstName is absent |
records[].Company | template variable | Optional |
records[].contact_id | idempotency and event metadata | Required for reliable duplicate prevention |
journey.id | idempotency and workflow allowlist | Required for workflow-specific processing |
custom | template selection | Validate against an allowlist |
Field names can vary depending on the contact data available in your Autopilot account and Journey. Your receiver should treat missing optional fields as normal rather than letting a missing company name turn into a server error.
Working server-side mapping: Autopilot payload to a Volanea email
The following Node.js example shows the integration boundary. Autopilot posts its payload to your endpoint; the endpoint verifies a secret, loops through every record, prevents duplicate sends, and makes the Volanea REST request from server-side environment variables.
The Volanea request below is intentionally isolated in sendWithVolanea(). Keep the current request URL, authentication format, and payload fields aligned with the Volanea API documentation for your account rather than duplicating credentials or API details throughout your application.
import crypto from "node:crypto";
import express from "express";
const app = express();
app.use(express.json({ limit: "1mb" }));
const processedEvents = new Set(); // Replace with Redis or a database in production.
function timingSafeEqual(a, b) {
const aBuffer = Buffer.from(a || "");
const bBuffer = Buffer.from(b || "");
return aBuffer.length === bBuffer.length && crypto.timingSafeEqual(aBuffer, bBuffer);
}
function isValidEmail(value) {
return typeof value === "string" && /^[^\s@]+@[^\s@]+\.[^\s@]+$/.test(value);
}
async function sendWithVolanea({ to, name, subject, html, text, idempotencyKey, metadata }) {
const response = await fetch(process.env.VOLANEA_EMAIL_API_URL, {
method: "POST",
headers: {
"Content-Type": "application/json",
"Authorization": `Bearer ${process.env.VOLANEA_API_KEY}`,
"Idempotency-Key": idempotencyKey
},
body: JSON.stringify({
from: {
email: process.env.VOLANEA_FROM_EMAIL,
name: "Example Co"
},
to: [{ email: to, name }],
subject,
html,
text,
metadata
})
});
if (!response.ok) {
const responseText = await response.text();
throw new Error(`Volanea send failed: ${response.status} ${responseText}`);
}
return response.json();
}
app.post("/webhooks/autopilot/volanea", async (req, res) => {
const suppliedSecret = req.get("X-Autopilot-Webhook-Secret");
if (!timingSafeEqual(suppliedSecret, process.env.AUTOPILOT_WEBHOOK_SECRET)) {
return res.status(401).json({ error: "Unauthorized webhook" });
}
const { records, journey, custom } = req.body || {};
if (!Array.isArray(records) || !journey?.id) {
return res.status(400).json({ error: "Invalid Autopilot webhook payload" });
}
if (custom !== "demo-request-confirmation-v1") {
return res.status(400).json({ error: "Unexpected webhook workflow" });
}
try {
for (const record of records) {
const email = record.Email;
const firstName = record.FirstName || record.Name || "there";
const contactId = record.contact_id;
if (!contactId || !isValidEmail(email)) {
console.warn("Skipping incomplete Autopilot contact", {
contactId,
journeyId: journey.id
});
continue;
}
// A stable key makes retries safe for this workflow and contact.
const idempotencyKey = `autopilot:${journey.id}:${custom}:${contactId}`;
if (processedEvents.has(idempotencyKey)) {
continue;
}
await sendWithVolanea({
to: email,
name: firstName,
subject: "We received your demo request",
text: `Hi ${firstName}, we received your request and will be in touch shortly.`,
html: `<p>Hi ${escapeHtml(firstName)},</p><p>We received your request and will be in touch shortly.</p>`,
idempotencyKey,
metadata: {
autopilot_contact_id: contactId,
autopilot_journey_id: journey.id,
autopilot_journey_name: journey.name || "",
autopilot_workflow: custom
}
});
processedEvents.add(idempotencyKey);
}
return res.status(202).json({ accepted: records.length });
} catch (error) {
console.error("Autopilot-to-Volanea webhook failed", error);
return res.status(500).json({ error: "Email processing failed" });
}
});
function escapeHtml(value) {
return String(value)
.replaceAll("&", "&")
.replaceAll("<", "<")
.replaceAll(">", ">")
.replaceAll('"', """)
.replaceAll("'", "'");
}
app.listen(3000);
The example separates the variables that belong to each system:
# Stored in your server or secret manager
AUTOPILOT_WEBHOOK_SECRET=long-random-shared-secret
VOLANEA_EMAIL_API_URL=https://your-volanea-api-endpoint
VOLANEA_API_KEY=your-volanea-api-key
VOLANEA_FROM_EMAIL=notifications@your-verified-domain.example
Replace the in-memory Set with Redis, Postgres, DynamoDB, or another durable store before production. An in-memory set disappears on deploys, does not work reliably across multiple server instances, and cannot protect you from retry duplicates after a restart.
Where the Volanea API key belongs
The Volanea API key belongs in a server-side secret store or protected runtime environment variable. It should not live in client-visible configuration, form code, a JavaScript bundle, browser network request, public repository, or a mobile application.
For this recommended integration, the Volanea API key does not need to be stored in Autopilot at all. Autopilot stores only the URL for your webhook endpoint and a separate shared webhook secret in the configured custom header. Your endpoint holds the Volanea key and performs the send.
This is safer than calling Volanea directly from the Autopilot Webhook action for several reasons:
- A Journey editor should not need access to a provider-wide sending credential.
- The Volanea key remains rotatable without editing every Journey.
- You can apply recipient validation and suppression checks before sending.
- You can add idempotency logic to make webhook retries safe.
- You can change templates, senders, or Volanea request details centrally.
- You avoid putting a privileged email-sending key into a UI configuration that may have broad team access.
If you choose a direct Autopilot-to-Volanea call
A direct call can reduce infrastructure, but it also reduces control. If your Volanea API supports the authentication method required by Autopilot’s Webhook action, you could configure the Volanea endpoint and API credential in that action’s headers.
Use that option only after reviewing who can view or edit Journey configuration in your Autopilot workspace and whether the credential can be scoped tightly. You would still need a plan for duplicate sends, field validation, template selection, monitoring, and handling batches of up to 200 records.
For most production workflows, the small middleware endpoint is the more reliable design.
Make the email content safe and purposeful
The Webhook action provides contact data, but it should not become a way to copy arbitrary contact fields directly into HTML. Treat Autopilot contact fields as data, not trusted markup.
In the code example, escapeHtml() prevents a contact name containing characters such as < or & from altering the email HTML. Use the same discipline for company names, product labels, request descriptions, and any custom field included in message content.
Use explicit workflow identifiers
The custom payload is useful as a workflow identifier. Your endpoint should allow only known values, such as:
trial-started-v1
passwordless-login-v1
demo-request-confirmation-v1
document-ready-v1
Do not allow a custom payload to specify an arbitrary sender address, arbitrary subject line, or raw HTML. That turns a marketing automation integration into an email relay and makes security, deliverability, and auditability much harder.
Instead, map each approved workflow to server-owned configuration:
const workflows = {
"demo-request-confirmation-v1": {
subject: "We received your demo request",
template: "demo-request-confirmation"
},
"document-ready-v1": {
subject: "Your document is ready",
template: "document-ready"
}
};
This provides an approval boundary. Autopilot determines when a contact reaches a Journey action; your application determines exactly what transactional message is permitted to be sent.
When this breaks: Autopilot webhook failure modes
Every webhook integration needs to assume failure. The most common problems are not syntax errors; they are timing, retries, incomplete data, and differences between a test contact and the contacts your automation sees in production.
Webhook retries can create duplicate sends
Autopilot gives the webhook endpoint a short window to accept the request. If the request does not succeed in time, Autopilot retries the connection two more times. That means a slow endpoint can send an email successfully through Volanea, fail to return a response in time, and then receive the same Autopilot payload again.
Without idempotency, the result is duplicate email.
Use a deterministic key based on stable workflow and contact identifiers, such as:
autopilot:{journey.id}:{custom}:{contact_id}
Store that key durably before or as part of processing. If Volanea supports idempotency headers or keys, pass the same key to the Volanea request as an additional protection layer. Your own database record is still useful because it tells you whether your application has already accepted the event, even if an upstream response was ambiguous.
Do not build an idempotency key from Date.now(), a random UUID generated per request, or the webhook attempt number. Those values change on retries and therefore do not prevent duplicates.
A five-second timeout changes how you design the route
Autopilot’s Webhook action expects the receiving endpoint to accept the request within five seconds. A request that takes longer can be retried even when downstream work eventually succeeds.
If your Volanea API request, database query, template rendering, or third-party enrichment can exceed that limit, use an asynchronous architecture:
- Verify the Autopilot request.
- Validate the payload shape and workflow.
- Write each event to a durable queue or database table with a unique idempotency key.
- Return
202 Acceptedimmediately. - Let a worker send through Volanea.
- Record the Volanea result and retry only according to your own controlled policy.
This approach keeps the Autopilot request fast and moves email delivery work to a process that can be observed and retried safely.
Some contacts will not contain every field you tested with
A contact that entered through an Autopilot form may have Email, FirstName, and form-specific custom data. A contact synced from another source may only have an email address and contact ID. Other records may have stale data, placeholder addresses, or a missing custom field because they entered the Journey through a different branch.
Your route should distinguish between required and optional fields:
- Require a syntactically valid email address and a contact ID.
- Treat first name, company, list membership, and custom fields as optional unless the workflow truly needs them.
- Reject or quarantine a record that lacks a required business field instead of sending a misleading message.
- Log the Journey ID, contact ID, workflow identifier, and missing field names.
- Avoid logging the entire contact payload unless your privacy policy and operational needs justify it.
If a field is unavailable in the payload for the Journey or plan configuration you use, pass only the data actually present. Do not assume a UI field or contact attribute will always be available just because it existed in a single test contact.
Batch payloads can surprise single-contact code
The records array can contain more than one contact. This is efficient for Autopilot, but it introduces a decision: should your endpoint handle the batch atomically or process records independently?
For transactional sends, independent processing is usually better. One malformed recipient should not prevent 20 valid recipients from receiving their messages. Record an individual status for each contact, then return a successful response after the batch has been accepted for processing.
If an email should only ever be sent to one contact at a time, do not depend on that behavior implicitly. Write the code to handle a batch anyway, then constrain the Journey entry behavior if your operational process requires it.
A 4xx and a 5xx mean different things
Use status codes intentionally:
- Return
401when the shared secret is missing or wrong. - Return
400when the JSON structure, Journey, or custom workflow identifier is invalid. - Return
202when events have been durably queued for processing. - Return
500only when a transient server failure means the request should be retried.
Do not return 200 after discarding an event you could not process. That hides a problem. Conversely, do not return 500 for an email address that is permanently invalid; that can encourage retries of an event that will never succeed.
Monitoring, audit trails, and deliverability ownership
An Autopilot email integration should be operated like any other production event pipeline. The email is only the visible result; the underlying system should tell you which contact reached which Journey action, whether the webhook was received, whether the event was deduplicated, and whether Volanea accepted the send.
Store at least these values for each attempted send:
- Autopilot contact ID.
- Autopilot Journey ID and Journey name.
- Custom workflow identifier.
- Your idempotency key.
- Recipient email or a privacy-preserving identifier, depending on your logging policy.
- Volanea message or request identifier when available.
- Final processing status and failure category.
- Timestamps for receipt, queueing, send attempt, and acceptance.
These fields make it possible to answer practical support questions: “Why did this person receive two messages?”, “Did the Journey reach the webhook?”, “Was the recipient skipped because the email field was empty?”, and “Was Volanea unavailable or did our worker fail before making the request?”
Protect sender reputation with workflow boundaries
A transactional email route should not be a back door for bulk sends. Keep each Volanea workflow narrow, with approved content, a verified sender, and a known reason for triggering.
For example, an account-access message, requested document link, or form receipt can be sent immediately. A promotional follow-up should stay in the appropriate marketing and consent workflow. Separating these message types improves auditability and helps teams avoid mixing operational delivery with campaign logic.
Test the full integration before publishing the Journey
A webhook that returns a 2xx response is not necessarily a successful email integration. Test the full path from a real Autopilot contact entering the Journey through to the Volanea acceptance response and the final message rendering.
Use this pre-launch checklist:
- Create a test contact with a controlled inbox you can inspect.
- Enter the contact through the same list, form, or branch used in production.
- Confirm the contact reaches the Webhook action.
- Confirm your endpoint receives a payload with the expected
journey,custom, andrecordsfields. - Test a record with only
Emailandcontact_idto verify optional-field fallbacks. - Test two records in one payload through a local or staging replay.
- Simulate a slow or failed first attempt and verify your idempotency protection prevents a second email.
- Verify the Volanea request uses an approved sender identity and expected recipient mapping.
- Inspect the received HTML and plain-text alternatives.
- Confirm logs make it easy to correlate the Autopilot contact and the Volanea send.
Keep staging and production secrets separate. A staging Autopilot Journey should call a staging endpoint and use a non-production Volanea sending configuration where possible. That separation prevents test submissions from reaching real recipients.
Alternatives: direct webhooks, Zapier or Make, and custom middleware
Autopilot’s native Webhook action is the direct outbound HTTP capability for this use case. It is the best starting point when you can operate a small endpoint and want control over authentication, logic, logging, and duplicate prevention.
A no-code middleware platform such as Zapier or Make can be useful for a proof of concept, especially when a team does not yet have an application backend. The typical pattern is Autopilot Webhook action to middleware webhook trigger to an HTTP request action that calls an email API.
That approach has trade-offs:
- It can be faster to prototype.
- It adds another system that stores credentials and event history.
- It can make idempotency and batch handling harder to customize.
- It may add task costs and execution delays.
- It requires careful review of how API keys and recipient data are stored.
For a production transactional flow, custom middleware is usually the cleanest long-term option. It gives your team a stable integration contract even if Journey details, templates, or providers change later.
Conclusion
A reliable Autopilot email integration starts when a contact reaches Autopilot’s Webhook action in a Journey. From there, send the contact payload to a secure server-side endpoint, validate the records array and workflow context, use a stable idempotency key, and make the Volanea transactional send from protected server credentials.
Do not treat the webhook as a simple one-line forwarding rule. Build it as a small event-processing boundary: fast enough for Autopilot’s timeout, strict enough to reject unexpected requests, durable enough to handle retries, and observable enough to explain every send.
FAQ
Does Volanea have a native Autopilot integration?
No. This setup uses Autopilot’s native Webhook action to call an endpoint you control, which then sends through Volanea’s API. There is no marketplace installation step required.
What triggers the Volanea email in Autopilot?
The immediate trigger is a contact reaching the Webhook action in an Autopilot Journey. The Journey can be entered by a list addition, form-related contact update, or another Journey condition you configure.
Can Autopilot send more than one contact in a webhook request?
Yes. The payload uses a records array and can include multiple contacts. Your endpoint should iterate through every record rather than assuming only one recipient.
Why should I use a middleware endpoint instead of putting the Volanea API key in Autopilot?
A middleware endpoint keeps the Volanea key in a server-side secret store, supports validation and idempotency, and gives you reliable logs and retry handling. Autopilot only needs the endpoint URL and a separate shared webhook secret.
How do I stop duplicate emails after a webhook retry?
Use a durable idempotency key based on stable values such as the Autopilot Journey ID, workflow identifier, and contact ID. Save that key in a database or queue, and reuse it for the associated Volanea send request.