E-commerce Checkout Integration

This guide shows how to integrate Envia into an e-commerce checkout flow — from displaying shipping options to the buyer, to printing a label after payment.

What you'll build

flowchart LR
  Cart["Cart Page"] --> Checkout["Checkout\n(show rates)"] --> Payment["Payment\nConfirmed"] --> Label["Generate\nLabel"] --> Fulfill["Fulfill\n& Track"]
  style Checkout fill:#1873dc,color:#fff
  style Label fill:#059669,color:#fff

Your checkout will:

  1. Show real-time carrier rates with delivery estimates when the buyer enters their address
  2. Automatically generate a shipping label after payment
  3. Send the tracking number to your customer

Architecture overview

Buyer enters address
  → Your frontend calls your backend
    → Your backend calls Envia POST /ship/rate/ (one per carrier)
      → Returns rates + delivery estimates
  → Buyer selects a rate and pays
    → Your backend calls Envia POST /ship/generate/
      → Returns tracking number + label PDF
  → You email the tracking link to the buyer
  → Envia webhook notifies you of delivery status changes

Setup

All code examples below use these base URLs and token. Set ENVIA_ENV=production when you are ready to go live.

// Configuration — defaults to sandbox
const ENVIA_BASE    = "https://api-test.envia.com";
const QUERIES_BASE  = "https://queries-test.envia.com";
const GEOCODES_BASE = "https://geocodes.envia.com";
// Set ENVIA_TOKEN as an environment variable (see Authentication guide)
# Configuration — defaults to sandbox
import os, requests
ENVIA_BASE    = "https://api-test.envia.com"
QUERIES_BASE  = "https://queries-test.envia.com"
GEOCODES_BASE = "https://geocodes.envia.com"
ENVIA_TOKEN   = os.environ["ENVIA_TOKEN"]

Step 1 — Validate the address at checkout

When the buyer enters their shipping address, validate it before requesting rates. This prevents failed label purchases later.

curl --request GET \
  --url "https://geocodes.envia.com/zipcode/MX/03100" \
  --header "Authorization: Bearer $ENVIA_TOKEN"

Step 2 — Fetch rates for the checkout page

When the buyer reaches the shipping options step, call the rate endpoint for each carrier you want to offer. The rate endpoint accepts one carrier per request, so call it in parallel for speed.

// Fetch rates from multiple carriers in parallel
async function getShippingRates(origin, destination, packages) {
  const carriers = ["dhl", "fedex", "estafeta"];

  const ratePromises = carriers.map((carrier) =>
    fetch(`${ENVIA_BASE}/ship/rate/`, {
      method: "POST",
      headers: {
        Authorization: `Bearer ${process.env.ENVIA_TOKEN}`,
        "Content-Type": "application/json",
      },
      body: JSON.stringify({
        origin,
        destination,
        packages,
        shipment: { type: 1, carrier },
      }),
    }).then((r) => r.json())
  );

  const results = await Promise.allSettled(ratePromises);

  // Flatten and sort by price
  return results
    .filter((r) => r.status === "fulfilled" && r.value.data?.length)
    .flatMap((r) => r.value.data)
    .sort((a, b) => parseFloat(a.totalPrice) - parseFloat(b.totalPrice));
}

Display rates to the buyer

Show the buyer the available options with price and delivery estimate:

CarrierServicePriceDelivery
DHLEconomy$185.20 MXN3-5 business days
FedExStandard$210.00 MXN2-3 business days
EstafetaExpress$245.50 MXN1-2 business days

Step 3 — Generate the label after payment

Once the buyer selects a rate and completes payment, create the label using the chosen carrier and service.

// Called after payment confirmation
async function createLabel(origin, destination, packages, carrier, service) {
  const response = await fetch(`${ENVIA_BASE}/ship/generate/`, {
    method: "POST",
    headers: {
      Authorization: `Bearer ${process.env.ENVIA_TOKEN}`,
      "Content-Type": "application/json",
    },
    body: JSON.stringify({
      origin,
      destination,
      packages,
      shipment: { type: 1, carrier, service },
    }),
  });

  const result = await response.json();
  const shipment = result.data[0];

  return {
    trackingNumber: shipment.trackingNumber,
    labelUrl: shipment.label,
    trackUrl: shipment.trackUrl,
    price: shipment.totalPrice,
  };
}

Step 4 — Register a webhook for tracking updates

Instead of polling, register a webhook to receive delivery status changes automatically.

curl --request POST \
  --url https://queries-test.envia.com/webhooks \
  --header "Authorization: Bearer $ENVIA_TOKEN" \
  --header "Content-Type: application/json" \
  --data '{"type_id": 3, "url": "https://your-store.com/webhooks/envia", "active": 1}'

When a status changes, Envia sends a POST to your URL. Use it to update order status and notify the buyer. See the Webhooks Guide for full setup details.

Error handling for checkout

Shipping errors at checkout directly impact conversion. Handle them gracefully:

ScenarioWhat to show the buyerWhat to do
No rates returned"Shipping unavailable for this address"Validate address first; try different carriers
402 on label creation"Payment processing error"Check your Envia account balance
422 on label creation"Please verify your shipping address"Re-validate with Geocodes API
5xx errors"Temporary issue — please try again"Retry with backoff; see Error Response Formats

Related pages