Tiendanube can notify an external application when an order is created, and that event can be the starting point for a reliable email workflow. This guide explains how to send email from Tiendanube with Volanea through a server-side webhook endpoint—without pretending there is a native Tiendanube marketplace app.

The integration model: Tiendanube webhook, your service, Volanea

Volanea does not ship a native Tiendanube app, marketplace listing, or one-click plugin. The dependable implementation is an integration you host: Tiendanube sends an order webhook to your HTTPS endpoint, your endpoint retrieves the authoritative order details from the Tiendanube API, and your server asks Volanea to deliver the message.

That architecture has an important benefit: the browser never sees either provider credential. It also gives you a place to apply business rules that are difficult to express in a basic automation, such as sending only for a particular sales channel, locale, fulfillment state, customer segment, or product combination.

The path looks like this:

  1. A shopper completes checkout and Tiendanube creates an order.
  2. Tiendanube emits the order/created webhook to an HTTPS URL you control.
  3. Your endpoint records the event durably and returns a successful HTTP response quickly.
  4. A worker uses the webhook's order ID and store ID to request the full order from Tiendanube.
  5. The worker maps the approved order data into a Volanea email request.
  6. Volanea accepts the message for delivery, and your application stores the result for auditing and support.

The concrete Tiendanube trigger in this guide is the order/created webhook event. It means an order record was created; it does not, by itself, mean a payment was approved, an item shipped, or an order was fulfilled. That distinction should shape the email you send.

What Tiendanube sends when an order is created

A Tiendanube webhook is intentionally small. For an order/created notification, the useful envelope identifies the event, store, resource, and creation time. It is not a complete order object and should not be treated as one.

A representative order/created body has this shape:

{
  "event": "order/created",
  "id": 123456789,
  "store_id": 987654,
  "created_at": "2025-03-08T14:22:31+00:00"
}

Here, id is the affected order's ID and store_id identifies the Tiendanube store. Your handler should use both values to fetch the order through the Tiendanube API rather than attempting to infer customer, item, or payment data from the webhook body.

This two-step approach is not needless overhead. Webhook payloads can evolve, a delivery can be retried later, and order data can be updated after creation. Fetching the resource gives your application a known API response to map and lets you explicitly decide which state is eligible for email.

Why the event name matters

order/created is a good trigger for an internal “new order” alert or an order-received email that clearly says the store has received the order. It is not automatically suitable for a “payment approved” receipt. If your promise to the customer depends on payment approval, use the payment/order lifecycle event documented for the condition you need, retrieve the order, and check the returned status before sending.

Likewise, do not use a webhook merely because it arrives first. A message saying “your package is on its way” should be tied to the fulfillment or shipping milestone your operation actually uses. Separating trigger selection from message content prevents confusing transactional mail and unnecessary support tickets.

Prerequisites before you connect anything

You need a Tiendanube application or integration with an access token for the store, a publicly reachable HTTPS endpoint, a database or durable queue, and a verified Volanea sending domain. The Tiendanube access token is required to retrieve the order after the webhook arrives. The Volanea key is required to submit mail.

For Volanea setup, start with the email API reference and setup guides to verify your sending domain and create a restricted server-side credential. Domain authentication matters here: a technically successful API request is not the same thing as strong inbox placement.

Before enabling a production event, prepare these operational basics:

  • A production HTTPS URL, such as https://integration.example.com/webhooks/tiendanube.
  • A separate test or staging store and a non-customer test recipient where possible.
  • A Tiendanube app access token stored as a server secret.
  • A Volanea API key stored as a server secret.
  • A database table or queue that can deduplicate webhook deliveries.
  • A verified From address on a domain controlled by the merchant.
  • Logs that include the Tiendanube store ID, order ID, event name, Volanea message ID, and outcome—but never full credentials or unnecessary customer data.

Do not put either secret in a storefront theme, a checkout script, a browser environment variable prefixed for public exposure, or a client-side tag manager. Anyone who can load the page can inspect client-visible configuration. A Volanea API key exposed there can be used to send mail from your account; an exposed Tiendanube token can reveal or modify store data within its granted permissions.

Register the Tiendanube order webhook

Tiendanube webhooks are registered against a store through its API. Registration belongs in an authenticated setup process, not in a public browser request. The exact access and application-installation flow depends on whether you are building for one merchant or distributing an app, but the webhook endpoint must be reachable by Tiendanube over HTTPS.

The registration request uses the store ID in the path and identifies the event and callback URL. Keep the callback URL stable: changing it without a deployment plan can create a silent gap in notifications.

curl --request POST "https://api.tiendanube.com/v1/987654/webhooks" \
  --header "Authentication: bearer $TIENDANUBE_ACCESS_TOKEN" \
  --header "User-Agent: OrderMailer (ops@example.com)" \
  --header "Content-Type: application/json" \
  --data '{
    "event": "order/created",
    "url": "https://integration.example.com/webhooks/tiendanube"
  }'

Use the store ID and application token for the merchant you are connecting. Do not hard-code either into source control. For an app serving multiple stores, store the token encrypted and associate it with the Tiendanube store ID after the merchant authorization flow completes.

Treat the callback URL as an ingress, not a business workflow

A webhook handler should acknowledge receipt promptly. It should not render a large template, make several slow third-party calls, or wait for a provider delivery result before replying. Those choices increase the chance that Tiendanube considers the request failed and retries it.

Instead, validate the basic event shape, make a durable deduplication claim, enqueue work, and return a 2xx response. A worker can then retrieve the order and send the email. This division is especially important during busy sales periods, when a few seconds of latency multiplied by many orders can become a retry storm.

Map the order to a Volanea email request

The webhook only identifies an order, so the worker retrieves it from Tiendanube first. The order response contains the customer/contact information and the commerce context your template needs. In practice, prefer the order contact email when present and use a customer email only as a fallback after confirming it is appropriate for your store's data model.

The following Node.js example shows the full mapping. It receives the documented webhook envelope, deduplicates by store, event, and order ID in PostgreSQL, fetches the order from Tiendanube, then submits an HTML and plain-text message to Volanea. The schema makes the duplicate guard explicit instead of relying on an in-memory variable that disappears on restart.

CREATE TABLE tiendanube_email_events (
  store_id BIGINT NOT NULL,
  event_name TEXT NOT NULL,
  resource_id BIGINT NOT NULL,
  template_version TEXT NOT NULL,
  received_at TIMESTAMPTZ NOT NULL DEFAULT now(),
  volanea_message_id TEXT,
  PRIMARY KEY (store_id, event_name, resource_id, template_version)
);
import express from "express";
import pg from "pg";

const app = express();
const pool = new pg.Pool({ connectionString: process.env.DATABASE_URL });

app.use(express.json({ type: "application/json" }));

app.post("/webhooks/tiendanube", async (req, res) => {
  const { event, id, store_id } = req.body ?? {};

  if (event !== "order/created" || !Number.isInteger(id) || !Number.isInteger(store_id)) {
    return res.status(400).json({ error: "Unsupported or malformed Tiendanube webhook" });
  }

  // The unique primary key makes repeated deliveries safe for this template version.
  const claim = await pool.query(
    `INSERT INTO tiendanube_email_events
       (store_id, event_name, resource_id, template_version)
     VALUES ($1, $2, $3, $4)
     ON CONFLICT DO NOTHING
     RETURNING store_id`,
    [store_id, event, id, "order-received-v1"]
  );

  if (claim.rowCount === 0) {
    return res.sendStatus(204); // Already accepted this order email.
  }

  // In production, publish this job to a durable queue before returning 204.
  await sendOrderReceivedEmail({ storeId: store_id, orderId: id });
  return res.sendStatus(204);
});

async function sendOrderReceivedEmail({ storeId, orderId }) {
  const orderResponse = await fetch(
    `https://api.tiendanube.com/v1/${storeId}/orders/${orderId}`,
    {
      headers: {
        Authentication: `bearer ${process.env.TIENDANUBE_ACCESS_TOKEN}`,
        "User-Agent": "OrderMailer (ops@example.com)",
        Accept: "application/json"
      }
    }
  );

  if (!orderResponse.ok) {
    throw new Error(`Tiendanube order fetch failed: ${orderResponse.status}`);
  }

  const order = await orderResponse.json();
  const recipient = order.contact_email || order.customer?.email;

  if (!recipient) {
    throw new Error(`Order ${orderId} has no usable contact email`);
  }

  const customerName = order.customer?.name || "there";
  const orderNumber = order.number || String(order.id);
  const total = order.total || "";
  const currency = order.currency || "";

  const volaneaResponse = await fetch("https://api.volanea.com/v1/emails", {
    method: "POST",
    headers: {
      Authorization: `Bearer ${process.env.VOLANEA_API_KEY}`,
      "Content-Type": "application/json",
      Accept: "application/json"
    },
    body: JSON.stringify({
      from: "Orders <orders@example.com>",
      to: [recipient],
      subject: `We received your order #${orderNumber}`,
      text: `Hi ${customerName}, we received order #${orderNumber}. Total: ${total} ${currency}.`,
      html: `<p>Hi ${escapeHtml(customerName)},</p><p>We received order <strong>#${escapeHtml(orderNumber)}</strong>.</p><p>Total: ${escapeHtml(total)} ${escapeHtml(currency)}</p>`
    })
  });

  if (!volaneaResponse.ok) {
    throw new Error(`Volanea email request failed: ${volaneaResponse.status}`);
  }

  const message = await volaneaResponse.json();
  await pool.query(
    `UPDATE tiendanube_email_events
       SET volanea_message_id = $1
     WHERE store_id = $2 AND event_name = $3 AND resource_id = $4 AND template_version = $5`,
    [message.id ?? null, storeId, "order/created", orderId, "order-received-v1"]
  );
}

function escapeHtml(value) {
  return String(value)
    .replaceAll("&", "&amp;")
    .replaceAll("<", "&lt;")
    .replaceAll(">", "&gt;")
    .replaceAll('"', "&quot;")
    .replaceAll("'", "&#039;");
}

The field mapping in that example is deliberate:

  • Tiendanube webhook store_id becomes the store context used in the order API path.
  • Tiendanube webhook id becomes the order ID used in the order API path.
  • order.contact_email, then order.customer.email, becomes Volanea to.
  • order.number becomes the human-readable order reference in the subject and content.
  • order.total and order.currency become contextual order details.
  • A verified mailbox at the merchant's authenticated domain becomes Volanea from.

Keep content rendering separate from raw data retrieval as the implementation grows. Product titles, address fields, customer-entered names, and custom checkout fields may contain characters that must be escaped in HTML. For more elaborate templates, use a well-maintained templating library with HTML escaping enabled by default.

Put credentials on the server, not in Tiendanube storefront code

There are two credentials in this integration, and both belong in your server-side secret store.

The Tiendanube access token belongs in encrypted application storage or a secret manager, associated with the relevant store. It is used only by the backend worker when it requests /orders/{order_id}. If a merchant revokes an app installation or changes authorization, handle the API failure and require a renewed connection rather than silently using a stale token.

The Volanea API key belongs in the same kind of server-side secret store, exposed to your running process as VOLANEA_API_KEY or retrieved at runtime from a managed secret service. Rotate it if it may have been logged, committed, or exposed. Give production and staging separate keys so a test deployment cannot send as the production domain.

A Tiendanube webhook is an inbound notification, not a safe place to embed a Volanea credential. Never create a URL such as https://api.volanea.com/...?...api_key=... and point Tiendanube at it. That would expose a sending credential in configuration, logs, and potentially error reporting. Your middleware is the security boundary that converts a Tiendanube event into a Volanea API call.

Protect the endpoint as well as the keys

Use TLS, a difficult-to-guess endpoint path, request-size limits, and application-level validation. Confirm that the event is one your service accepts, that IDs have the expected type, and that the order lookup succeeds with the token associated with that store.

Do not make a security assumption about webhook signatures unless you have implemented the exact verification mechanism documented by Tiendanube for your integration. If no verified signature is available for your setup, treat the webhook body as a notification to look up a resource—not as trusted customer data—and use the authenticated order API response as the source of truth.

Decide which messages should be sent

The technical ability to send a message does not mean every Tiendanube event should create one. Stores often already have native transactional notifications enabled. A second “order confirmed” email from an external system can confuse customers, create conflicting support instructions, and damage trust.

Good first use cases include:

  • An internal new-order alert to a fulfillment or sales inbox.
  • A branded post-purchase onboarding email that adds information not present in the store's native notification.
  • A B2B order acknowledgment that includes account-specific instructions.
  • A manual-review request when a particular product, destination, or total requires intervention.
  • A message to an operations system address after a qualifying order event.

For customer-facing email, be precise about state. On order/created, wording such as “We received your order and will update you as it is processed” is safer than “Your payment is confirmed” or “Your order has shipped.” Retrieve the order and inspect the relevant lifecycle fields before making a stronger claim.

Keep marketing consent separate

An order notification is transactional when it is necessary to communicate about that order. Promotional content, newsletter opt-in, cross-selling, and ongoing marketing automation are different purposes and can require consent and unsubscribe handling depending on applicable law and your store policy.

Do not turn an operational webhook into a blanket marketing trigger. Store consent evidence separately, send marketing only through a flow built for that purpose, and preserve suppression choices. This protects customers and makes deliverability metrics more meaningful because transactional and promotional mail have different engagement patterns.

When this breaks: failures specific to this hop

Every integration eventually sees failures. Planning for them is more valuable than adding a second webhook URL after an incident.

Tiendanube retries can cause duplicate sends

Webhook systems retry when they do not receive a timely successful response, or when a network interruption makes the outcome uncertain. Your server may even complete the email request while the acknowledgment back to Tiendanube is lost. From Tiendanube's perspective, that can look like a failed delivery; from your customer's perspective, it can become two identical emails.

The remedy is application-level idempotency. Use a durable unique key such as (store_id, event_name, order_id, template_version), as shown in the SQL example. Claim that key before sending. If a duplicate webhook arrives, return 2xx without creating another message. Adding template_version lets you intentionally send a newly designed one-time message later while preventing unplanned repeats of the same version.

Do not deduplicate only by timestamp. Retries can arrive minutes later, and different orders can share a timestamp. Do not deduplicate only by email address either: a legitimate customer may place several orders.

Webhook timeouts make synchronous processing risky

Fetching an order, rendering a template, contacting Volanea, and writing an audit record can take longer than a webhook sender allows. A dependency can also be slow exactly when traffic is high. If your endpoint waits for all of this before it responds, you create a timeout and retry risk.

In production, replace the inline await sendOrderReceivedEmail(...) in the sample with a durable queue job. The request handler should atomically record the event and enqueue work, then respond. A worker can retry order retrieval and Volanea submission with controlled backoff. Monitor the age of the oldest queued job, not only HTTP error rates.

Fields may be absent or different for some orders

Not every order will contain every field your template expects. Guest checkout, incomplete customer profiles, store configuration, payment methods, historic orders, and app-created orders can produce missing contact or customer attributes. A field that was populated in your initial test order is not a guarantee for all real orders.

Code defensively. Require a usable recipient before attempting mail, provide safe fallbacks for optional display fields, and route exceptions to an operations queue with the order ID rather than trying to send to an empty address. If a field is essential to the message, check it after retrieving the order and skip the send with a clear logged reason when it is absent.

API authorization and store mismatches are common

A 401 or 403 from the Tiendanube order endpoint commonly points to a revoked, expired, incorrect, or improperly scoped token. A 404 can also be a store/order mismatch if a multi-store application looks up an order with the wrong store context. Always take the store ID from the event and load the token associated with that exact store.

A Volanea 4xx response generally means the request, sender identity, recipient, or API credential needs attention; a transient 5xx or network failure should be retried by the worker according to your policy. Record provider response codes and message identifiers, but redact recipient details in broadly accessible logs.

Test the complete flow before enabling customers

Test with a real development or test store order where possible. Manually posting a sample webhook verifies only the first half of the system; it does not prove that your Tiendanube authorization can retrieve a real order or that the actual response fields match your assumptions.

Use this practical test sequence:

  1. Register order/created against a non-production callback URL.
  2. Place a test order with a known recipient and simple customer details.
  3. Confirm the webhook arrived and that the database contains the expected unique key.
  4. Confirm the worker fetched the same order ID under the same store ID.
  5. Inspect the rendered text and HTML for escaping, correct order reference, sender identity, and recipient mapping.
  6. Confirm Volanea returned an accepted message ID and that the message appears in your delivery records.
  7. Replay the exact webhook body and verify that no second message is created.
  8. Test an order lacking a nonessential field and verify your fallback behavior.

Use a separate template or an explicit test-recipient override only in a non-production environment. Never leave an override that redirects production customer mail to an employee inbox. It creates a privacy incident and can hide a broken recipient mapping until launch day.

Alternatives when you do not want to host code

If your team cannot operate a webhook endpoint and queue, an automation middleware may be appropriate—but it should still be evaluated as a server-side bridge, not as a client-side workaround. A platform such as Make or Zapier can receive a supported Tiendanube event, apply a filter, and call an HTTP action that submits to Volanea, provided the relevant connector capabilities and plan are available in your account.

The trade-off is control. Middleware can be quick for a low-volume internal alert, but you need to check how it stores secrets, handles retries, exposes run history, and deduplicates repeated deliveries. It may be a poor fit for a high-volume customer transaction flow where you need detailed auditability, precise idempotency, custom templates, and data-minimization controls.

A small service is usually the better long-term choice when email is operationally important. It gives you a single source of truth for event processing, lets you migrate providers without changing Tiendanube's webhook model, and keeps the decision logic under your control.

Operational checklist for a durable launch

Before switching on a customer-facing workflow, verify the following:

  • The trigger is order/created only if its semantics match the claim in the email.
  • The webhook URL uses HTTPS and responds rapidly after persisting work.
  • The application fetches the order by store_id and id; it does not depend on missing details in the webhook envelope.
  • Tiendanube and Volanea credentials are server-side secrets, not browser configuration.
  • Duplicate webhook notifications cannot create duplicate emails.
  • Your sender domain is authenticated and the From identity is intentional.
  • Missing recipient or optional order fields have defined behavior.
  • The email has both text and HTML representations.
  • Logs and dashboards can correlate order ID, event, processing result, and Volanea message ID.
  • Customer-facing transactional messages do not duplicate existing Tiendanube notifications.

This checklist is also useful during incident response. It turns “an email was not sent” into specific questions: Did Tiendanube emit the event? Did the ingress persist it? Did the worker retrieve the order? Did the mapping find an address? Did Volanea accept the request? Each boundary has a measurable answer.

Conclusion

The reliable way to send email from Tiendanube with Volanea is a webhook-to-server-to-API workflow, not a nonexistent native plugin. Start with Tiendanube's order/created event, retrieve the full order with the authenticated API, map only the fields your message needs, and submit the finished message from a protected backend.

The engineering details—fast webhook acknowledgment, durable deduplication, server-side secrets, truthful lifecycle messaging, and observability—are what turn a demo into a dependable transactional email system. Build those pieces first, then expand to the additional lifecycle messages your store genuinely needs.

FAQ

Can I install Volanea from the Tiendanube marketplace?

No. Volanea does not provide a native Tiendanube marketplace app or plugin. Connect it through a Tiendanube webhook, middleware you operate, and the Volanea API.

What Tiendanube event should trigger an order-received email?

Use order/created for an order-received message. Do not describe payment approval or shipment unless you trigger from and verify the appropriate later lifecycle state.

Does the Tiendanube webhook include the complete customer order?

No. The webhook envelope identifies the event, order ID, and store ID. Retrieve the full order from the Tiendanube Orders API before selecting a recipient or rendering order details.

Where should I store the Volanea API key?

Store it only in a server-side environment variable or managed secret store used by your integration service. Never place it in a storefront theme, browser JavaScript, public environment configuration, or webhook URL.

How do I stop duplicate emails after webhook retries?

Create a durable unique key using the store ID, event name, order ID, and template version before sending. If that key already exists, acknowledge the repeated webhook without sending another message.