A ShipStation email integration can send a branded shipment confirmation as soon as ShipStation creates a shipment, without exposing an email API key or relying on a marketplace plugin. The practical route is ShipStation’s webhook system, a server-side middleware endpoint, and Volanea’s REST email API.

ShipStation does not need a native Volanea listing for this workflow. Its webhook can notify an endpoint you control when a shipping event occurs; that endpoint retrieves the authoritative ShipStation shipment record, maps the relevant fields into an email, and makes the authenticated Volanea API request. That extra server-side hop is important: ShipStation webhooks are event notifications, not an email-template engine or a secure place to store a third-party sending key.

This guide uses a SHIP_NOTIFY webhook as the concrete trigger. In ShipStation’s webhook event model, SHIP_NOTIFY is sent when a shipment is created. It is a particularly useful trigger for an operational customer email because the shipment resource can contain the recipient email address, order number, carrier, service, ship date, and tracking number.

What you are building

The finished flow has four distinct stages:

  1. ShipStation creates a shipment and posts a SHIP_NOTIFY webhook to your HTTPS endpoint.
  2. Your endpoint validates the notification, reads its resource_url, and retrieves that shipment from ShipStation’s API using ShipStation API credentials.
  3. Your middleware checks that the shipment has a usable customer email address and builds a message from the returned shipment fields.
  4. The middleware sends the message through Volanea using an API key held only in server-side secret storage.

This division of responsibilities avoids a common mistake: treating a webhook body as a complete order or shipment object. ShipStation’s webhook notification is deliberately compact. Its key field is a resource_url that identifies the resource that changed. The integration should fetch that resource before deciding who receives an email or what the message says.

For a shipping-confirmation workflow, the architecture looks like this:

ShipStation shipment created
          |
          | POST SHIP_NOTIFY
          v
https://your-domain.example/webhooks/shipstation
          |
          | GET resource_url with ShipStation API credentials
          v
Shipment JSON: customerEmail, orderNumber, carrierCode, trackingNumber
          |
          | POST email payload with Volanea API key
          v
Volanea sends the transactional email

The webhook URL must be public and reachable over HTTPS. It can be an Express application, a serverless function, a worker, or an integration service. What matters is that it can keep secrets private, acknowledge ShipStation quickly, and perform reliable downstream processing.

The ShipStation trigger: SHIP_NOTIFY

ShipStation’s Webhooks API supports event subscriptions. For this use case, create a webhook with the event value SHIP_NOTIFY and set its target_url to your server-side endpoint. This is not a ShipStation Automation Rule, a customer-facing status email setting, or a marketplace installation: it is an API webhook subscription.

A representative webhook subscription request is:

curl --user "$SHIPSTATION_API_KEY:$SHIPSTATION_API_SECRET" \
  --request POST "https://ssapi.shipstation.com/webhooks" \
  --header "Content-Type: application/json" \
  --data '{
    "name": "Volanea shipment email trigger",
    "event": "SHIP_NOTIFY",
    "target_url": "https://app.example.com/webhooks/shipstation"
  }'

Keep the webhook name descriptive. If you later add events for order updates, cancellations, or internal alerts, a clear name makes it possible to distinguish their purpose during investigation and cleanup.

What ShipStation posts to your endpoint

The important detail is the notification payload shape. A ShipStation webhook notification identifies the changed resource through resource_url; it does not provide the full shipment document in the initial callback. It is shaped like this:

{
  "resource_url": "https://ssapi.shipstation.com/shipments/123456789"
}

Your handler should therefore treat resource_url as a pointer, not as a URL to forward blindly or use as an email destination. It should also restrict accepted URLs to ShipStation’s expected API host before fetching. That small validation step prevents a forged request from turning the server into a request proxy for arbitrary URLs.

SHIP_NOTIFY is appropriate when the business event is “a shipping label or shipment has been created.” It is not automatically the same as “the parcel has been delivered,” “the carrier accepted the parcel,” or “the customer clicked tracking.” If those are the events your email must represent, use a data source that actually supplies those lifecycle milestones rather than changing the words in the template.

Why a middleware endpoint is required

A ShipStation webhook lets ShipStation send an HTTP notification to your target URL. It does not transform a shipment into a Volanea email payload, render an HTML template, or attach your Volanea authorization header to a request. That is why the direct destination of the ShipStation webhook should be code or an automation platform you control, not the Volanea sending endpoint.

There are two security reasons for this design:

  • The Volanea API key authorizes email sending. It belongs in a server environment variable, a cloud secret manager, or an automation platform’s encrypted connection/credential store.
  • A browser bundle, mobile application, publicly readable configuration file, webhook URL query string, or client-side ShipStation setting is not an acceptable location for that key. Anyone who obtains it could send through your account.

On the ShipStation side, the webhook configuration stores only the target URL and event subscription. The Volanea key does not live in ShipStation. Your middleware holds VOLANEA_API_KEY; it also holds the ShipStation API key and API secret needed to fetch the shipment resource.

If you use an automation platform rather than custom code, the same principle applies. Put the Volanea key in that platform’s secure credential or connection field, not in a field that is copied into a workflow URL, template preview, or client-visible front end. Confirm that the platform can receive ShipStation’s webhook, make an authenticated GET request to the supplied resource URL, deduplicate events, and call a custom HTTP endpoint with headers. A simple one-step “webhook to email API” recipe is incomplete because the webhook does not contain all shipment fields.

Retrieve and map the shipment data

After receiving the notification, use the resource_url to retrieve the shipment. ShipStation API authentication uses your API key and API secret as HTTP Basic authentication. The resulting shipment object is the source of the data required for a shipping email.

Relevant fields in a shipment response include fields such as:

  • customerEmail for the recipient address.
  • orderNumber for the human-readable order reference.
  • trackingNumber for tracking information.
  • carrierCode and serviceCode for the carrier/service description.
  • shipDate for the date shown in the message.
  • shipmentId as a stable deduplication key.
  • voided to avoid mailing a label that has been voided.

Do not assume every shipment will have every value. Manual orders can lack a customer email. Some shipping services may not provide a tracking number at the point the shipment record is created. A carrier code is not necessarily customer-friendly text. The integration should define what to do in each case rather than sending broken copy such as “Track your order: undefined.”

A sensible first version sends only when customerEmail and trackingNumber are both present, and logs a structured “skipped” result otherwise. Another valid policy is to send a shipping confirmation without a tracking link when a tracking number is absent. The correct choice depends on the customer promise in the template.

Before enabling sends, validate addresses as close as possible to the source of truth. Volanea’s address verification tool can help assess an address before it becomes part of an automated customer-notification workflow, but it does not replace consent, suppression handling, or careful source-data validation.

Working Express middleware example

The following Node.js example receives ShipStation’s SHIP_NOTIFY payload, validates the ShipStation resource host, fetches the full shipment, maps its fields, and calls the Volanea REST email endpoint. It returns a response promptly after the work completes; in a production system with a queue, acknowledge after durable enqueueing instead.

import express from "express";

const app = express();
app.use(express.json({ limit: "100kb" }));

const SHIPSTATION_KEY = process.env.SHIPSTATION_API_KEY;
const SHIPSTATION_SECRET = process.env.SHIPSTATION_API_SECRET;
const VOLANEA_API_KEY = process.env.VOLANEA_API_KEY;
const FROM_EMAIL = process.env.FROM_EMAIL; // e.g. shipping@updates.example.com

function shipStationAuthorization() {
  const credentials = Buffer
    .from(`${SHIPSTATION_KEY}:${SHIPSTATION_SECRET}`)
    .toString("base64");
  return `Basic ${credentials}`;
}

function isExpectedShipStationResource(resourceUrl) {
  const url = new URL(resourceUrl);
  return url.protocol === "https:" &&
    url.hostname === "ssapi.shipstation.com" &&
    url.pathname.startsWith("/shipments/");
}

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

app.post("/webhooks/shipstation", async (req, res) => {
  const { resource_url: resourceUrl } = req.body ?? {};

  if (typeof resourceUrl !== "string" || !isExpectedShipStationResource(resourceUrl)) {
    return res.status(400).json({ error: "Unexpected ShipStation resource_url" });
  }

  try {
    // 1. Fetch the complete shipment represented by the webhook notification.
    const shipmentResponse = await fetch(resourceUrl, {
      headers: {
        Authorization: shipStationAuthorization(),
        Accept: "application/json"
      }
    });

    if (!shipmentResponse.ok) {
      throw new Error(`ShipStation shipment fetch failed: ${shipmentResponse.status}`);
    }

    const shipment = await shipmentResponse.json();

    // 2. Apply sending policy before calling the email API.
    if (shipment.voided === true) {
      return res.status(200).json({ status: "skipped", reason: "voided shipment" });
    }
    if (!shipment.customerEmail || !shipment.trackingNumber) {
      return res.status(200).json({
        status: "skipped",
        reason: "missing customerEmail or trackingNumber",
        shipmentId: shipment.shipmentId
      });
    }

    const orderNumber = shipment.orderNumber || String(shipment.orderId || "your order");
    const carrier = shipment.carrierCode || "carrier";
    const tracking = shipment.trackingNumber;

    // 3. Field mapping: ShipStation shipment -> Volanea email payload.
    const emailPayload = {
      from: { email: FROM_EMAIL, name: "Example Store" },
      to: [{ email: shipment.customerEmail }],
      subject: `Your order ${orderNumber} has shipped`,
      html: `<p>Your order <strong>${escapeHtml(orderNumber)}</strong> has shipped.</p>
<p>Carrier: ${escapeHtml(carrier)}</p>
<p>Tracking number: <strong>${escapeHtml(tracking)}</strong></p>`,
      text: `Your order ${orderNumber} has shipped. Carrier: ${carrier}. Tracking number: ${tracking}.`,
      headers: {
        "X-ShipStation-Shipment-ID": String(shipment.shipmentId)
      }
    };

    // 4. Send through Volanea. The API key remains only on this server.
    const volaneaResponse = await fetch("https://api.volanea.com/v1/emails", {
      method: "POST",
      headers: {
        Authorization: `Bearer ${VOLANEA_API_KEY}`,
        "Content-Type": "application/json",
        Accept: "application/json"
      },
      body: JSON.stringify(emailPayload)
    });

    if (!volaneaResponse.ok) {
      const detail = await volaneaResponse.text();
      throw new Error(`Volanea send failed: ${volaneaResponse.status} ${detail}`);
    }

    const sent = await volaneaResponse.json();
    return res.status(200).json({
      status: "sent",
      shipmentId: shipment.shipmentId,
      emailId: sent.id
    });
  } catch (error) {
    console.error("ShipStation webhook processing failed", error);
    return res.status(500).json({ error: "Webhook processing failed" });
  }
});

app.listen(3000);

The payload maps shipment.customerEmail to to[0].email, a verified sender identity to from, and shipment values to the subject and message content. The X-ShipStation-Shipment-ID header is useful for tracing, but it is not by itself a deduplication mechanism. For implementation-specific endpoint details, supported fields, and authentication conventions, consult the email API reference and setup guides before deploying.

Add a tracking URL deliberately

The ShipStation shipment object provides a tracking number, but a tracking URL may be absent or may need carrier-specific construction. Do not concatenate a generic URL and claim it works across carriers. Maintain a tested carrier-code mapping, or send the tracking number in plain text until you have reliable URL logic.

If your store already has an order-status page, a better option is often to link to that page with a signed, customer-specific token generated by your application. That keeps carrier differences behind your own application and lets the customer see order details in one place.

Authentication, sender identity, and deliverability

There are three separate authentication concerns in this integration, and combining them causes operational problems.

First, ShipStation API credentials authenticate your middleware when it retrieves the resource URL. Second, the Volanea API key authenticates your middleware when it requests an email send. Third, your sending domain needs properly configured email authentication so recipient systems can evaluate mail from your chosen From address.

Use environment variables locally only for development. In production, use the platform’s secret manager and grant the application the smallest possible permission set. Rotate keys when a team member leaves, when a secret appears in logs or a commit, or according to your organization’s normal credential-rotation schedule.

The From address should belong to a domain you control and have configured for sending. Avoid using a customer’s marketplace email address as your From identity. Keep the customer’s shipping email as the recipient, and use a stable store-owned address such as shipping@updates.example.com as the sender.

A shipping confirmation is transactional mail, not a marketing campaign. Its content should be directly related to the order event that caused it. If you include promotional content, make a deliberate policy decision about consent, regional rules, and message classification rather than quietly mixing advertising into a critical delivery update.

When this breaks

This integration crosses two remote HTTP systems, so it needs failure behavior, not merely a happy-path request. The most important failure modes are specific to the ShipStation-webhook-to-middleware-to-email hop.

Retries can produce duplicate sends

A webhook sender may retry when it does not receive a successful response quickly enough, when the endpoint returns a 5xx response, or when a network failure makes delivery uncertain. Your own server can also time out after Volanea accepts the send but before it records the result. In both cases, processing the same shipment twice can send two shipping confirmations.

Use shipment.shipmentId as the idempotency key in durable storage. Create a record before sending, with states such as received, sending, sent, skipped, and failed. Make the record unique on the shipment ID and email purpose, for example shipment:123456789:shipping-confirmation. If the key is already sent, return 200 without sending again.

Do not rely only on in-memory sets. They disappear on restart and do not work across multiple serverless instances. Also consider the business rule: a new shipment for a split order may have a different shipment ID and should usually generate a distinct notification.

Webhook timeouts and slow downstream calls

Fetching ShipStation and then sending through Volanea adds latency. If the receiving endpoint waits for every step to finish, a slow API can make ShipStation consider the webhook delivery unsuccessful and retry it.

The resilient pattern is to validate the minimal notification, write a durable queue job keyed by the resource URL or shipment ID, then return a 2xx response immediately. A worker fetches the shipment and sends the email outside the webhook request window. This also gives you controlled retries with exponential backoff when ShipStation or Volanea is temporarily unavailable.

If you keep synchronous handling for a low-volume first release, set conservative outbound timeouts, record enough context to replay safely, and measure webhook response duration. Never retry a request indiscriminately after an ambiguous email-send timeout without checking your idempotency record.

Fields can be missing or differently populated

The initial webhook payload has only resource_url; it does not include customerEmail, order number, or tracking data. Even after the follow-up API request, customer email and tracking number may be empty for certain order sources, manual entries, shipment methods, or timing conditions.

Build explicit fallbacks. For example, skip and alert on a missing recipient; use orderId only as an internal fallback if orderNumber is empty; and suppress a tracking CTA when no tracking number exists. Log the shipment ID, store ID where available, and the exact missing-field reason, but avoid logging full email content or unnecessary personal data.

A label can be voided or changed

A shipment-created event does not guarantee that the label remains valid. Shipments can be voided, and a tracking number can change when an order is reprocessed. Check the voided value when fetching the resource, and decide whether later corrections require a separate “updated tracking” workflow.

The safest customer experience is often to send after a shipment meets your chosen operational threshold, not simply because the earliest possible event exists. That may be SHIP_NOTIFY for many operations, but validate it against your fulfillment process before making it the customer promise.

Template design and data hygiene

A useful shipping email answers four questions immediately: what happened, which order it concerns, who is carrying it, and what the recipient can do next. It should work in a plain-text mail client as well as an HTML client.

Keep the first version small:

  • Subject: Your order 10482 has shipped
  • Opening: confirm that the order has shipped.
  • Reference: show the order number.
  • Tracking: show the carrier and tracking number, plus a tested tracking link when available.
  • Support path: provide a store-controlled support address or order-status link.

Escape every ShipStation value inserted into HTML. Order references and carrier codes may be operational data, but any externally supplied string can still break markup or create an injection risk if it is inserted raw. The example’s escapeHtml function handles the basic HTML characters; use a robust templating library for larger templates.

Keep an equivalent text body. It improves accessibility and provides a readable fallback. It also makes it easier for support teams to understand exactly what customers received when reviewing message logs.

Testing the integration before production

Do not begin with live customer shipments. Create a controlled test order and walk through the complete sequence from ShipStation event to inbox. Verify both system behavior and message content.

A practical test checklist is:

  1. Register the webhook against a non-production endpoint and confirm ShipStation can reach it over HTTPS.
  2. Capture one real SHIP_NOTIFY notification and verify that it contains the expected resource_url shape.
  3. Fetch that URL with a non-production ShipStation credential and inspect which shipment fields are actually populated for your carrier and store.
  4. Send to a test mailbox under your control and inspect the subject, From identity, text body, HTML rendering, and any tracking link.
  5. Replay the same notification twice and confirm the second attempt does not send another email.
  6. Test missing customerEmail, missing tracking number, a voided shipment, a ShipStation fetch failure, and a Volanea API failure.
  7. Review logs to ensure credentials, authorization headers, and unnecessary customer data are not recorded.

Use a separate sender identity or a clearly marked test subject while developing. A production-looking shipment confirmation sent to an employee can still trigger support work or confusion if it resembles a real order update.

Operational monitoring and reporting

A successful HTTP response from your middleware does not by itself prove that a customer received a message. Monitor each stage separately: webhook received, shipment fetched, send accepted, and email delivery events where available.

Store correlation values that make support investigations possible without retaining entire payloads forever. Useful fields include ShipStation shipmentId, orderId, orderNumber, the webhook resource URL, your internal job ID, and the Volanea message ID returned by the send request.

Create alerts for sustained missing-recipient skips, ShipStation API authorization failures, Volanea authentication failures, and retry queues that exceed a threshold. A spike in missing tracking numbers can be an integration timing issue; a spike in missing emails can indicate a store, marketplace, or order-import configuration change.

Set a retention policy for logs and job records. Shipment data and email addresses are customer data. Keep enough information for reconciliation and support, then remove or minimize it according to your privacy and security requirements.

Alternatives to a custom endpoint

A small custom endpoint is usually the clearest option when you need idempotency, custom templates, safe secret handling, and reliable observability. It is also portable: the same handler can run as a container, a serverless function, or a worker.

An automation platform can be suitable for lower-volume workflows if it can receive ShipStation’s webhook and complete the required follow-up GET request before calling Volanea. Evaluate it against the same technical requirements, not just whether it appears in an integrations directory:

  • Can it preserve and securely use ShipStation API credentials for the resource fetch?
  • Can it store the Volanea key as a protected credential?
  • Can it parse resource_url and validate or restrict the host?
  • Can it enforce a durable uniqueness key on shipmentId?
  • Can it return quickly enough to prevent webhook retries?
  • Can it expose useful execution logs without exposing secrets?

If the answer to idempotency is no, use a database-backed middleware service even if an automation platform performs other tasks. The cost of one small server-side component is usually lower than the support cost of duplicate shipping emails.

Conclusion

A reliable ShipStation email integration starts with ShipStation’s SHIP_NOTIFY event but does not stop at the webhook notification. Fetch the resource identified by resource_url, map authoritative shipment data into a transactional message, and send through Volanea from a server-side environment where credentials remain private.

Build for retries, missing fields, and label changes from day one. With a shipment-ID idempotency record, a queue or fast acknowledgement strategy, and a narrowly scoped shipping template, the integration can provide timely customer updates without a native marketplace app.

FAQ

Can ShipStation send directly to the Volanea email API?

Not as a complete secure integration. ShipStation can post a webhook notification to your endpoint, but the notification provides a resource_url rather than a fully mapped email payload, and the Volanea API key should remain in server-side secret storage. Use middleware or an automation workflow that performs the follow-up fetch and authenticated send.

What ShipStation event should trigger a shipping confirmation?

Use SHIP_NOTIFY when the desired trigger is creation of a shipment in ShipStation. Confirm that this timing matches your operations, because shipment creation is not necessarily the same as carrier acceptance or delivery.

Why does the webhook handler need to fetch resource_url?

ShipStation’s webhook notification identifies the changed resource through resource_url. The full shipment data needed for the email, such as customerEmail, orderNumber, and trackingNumber, is retrieved from that resource.

How do I prevent duplicate shipment emails?

Create a durable, unique record using shipmentId plus the message purpose before sending. On repeated webhook deliveries, return success without sending if that key is already marked as sent.

Where should the Volanea API key be stored?

Store it only in server-side environment or secret-management configuration, or in an automation platform’s encrypted credential store. Do not put it in a ShipStation webhook URL, browser code, public configuration, or a client-visible application setting.