Webhooks Guide

Webhooks push event data to your server the moment something happens — a label is created, a package is delivered, or a tracking status changes. This eliminates the need to poll the tracking endpoint repeatedly.

How it works

sequenceDiagram
  participant App as Your App
  participant Envia as Envia API
  participant Carrier as Carrier Network

  App->>Envia: Register webhook (Queries API)
  Envia-->>App: Webhook ID confirmed
  App->>Envia: Create label (Shipping API)
  Carrier->>Envia: Status update (picked up)
  Envia->>App: POST to your webhook URL
  App-->>Envia: 200 OK

Step 1 — List available webhook types

Before registering, check which event types are available.

curl --request GET \
  --url https://queries-test.envia.com/webhook-types \
  --header "Authorization: Bearer $ENVIA_SANDBOX_TOKEN"

The response returns an array of webhook types, each with an id, name, and description. Use the id value as the type_id when creating a webhook in the next step.

💡

Tip: The tracking status update webhook is the most commonly used type. It replaces the need to poll POST /ship/generaltrack/.

Step 2 — Register a webhook

Register your HTTPS endpoint for the event type you want to receive.

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

Response

The response includes a meta field set to "webhook_created" and a data object with the webhook details:

{
  "meta": "webhook_created",
  "data": {
    "id": 4421,
    "type": "...",
    "url": "https://your-app.com/webhooks/envia",
    "active": 1
  }
}

Save the data.id — you need it to update, deactivate, or test the webhook later.

Step 3 — Handle incoming events

When an event fires, Envia sends an HTTP POST to your registered URL with a JSON payload. The payload includes tracking details such as carrierName, trackingNumber, and status.

⚠️

Important: The exact payload structure may vary by event type. Use the Test Webhook endpoint (Step 4) to see the real payload format for your webhook type before building your handler.

Receiver implementation

Your endpoint must respond with a 2xx status quickly. Process the payload asynchronously to avoid timeouts.

app.post("/webhooks/envia", (req, res) => {
  // Respond immediately
  res.status(200).json({ received: true });

  // Process asynchronously
  const payload = req.body;
  console.log("Webhook received:", JSON.stringify(payload));

  // Update your database, notify customers, etc.
  processWebhookEvent(payload).catch(console.error);
});

Step 4 — Test your webhook

Use the Test Webhook endpoint to send a test event to your URL without waiting for a real carrier event.

curl --request POST \
  --url https://api-test.envia.com/ship/webhooktest/ \
  --header "Authorization: Bearer $ENVIA_SANDBOX_TOKEN" \
  --header "Content-Type: application/json" \
  --data '{
    "tracking_number": "7520610403",
    "webhook_url": "https://your-app.com/webhooks/envia"
  }'

The test endpoint sends a sample payload to the specified webhook_url using the given tracking_number. Check your server logs to confirm the payload arrived.

Managing webhooks

List your webhooks

curl --request GET \
  --url https://queries-test.envia.com/webhooks \
  --header "Authorization: Bearer $ENVIA_SANDBOX_TOKEN"

Update a webhook

curl --request PUT \
  --url https://queries-test.envia.com/webhooks/4421 \
  --header "Authorization: Bearer $ENVIA_SANDBOX_TOKEN" \
  --header "Content-Type: application/json" \
  --data '{"url": "https://your-app.com/webhooks/envia-v2", "active": 1}'

Deactivate a webhook

Set active to 0 to pause deliveries without deleting the webhook:

curl --request PUT \
  --url https://queries-test.envia.com/webhooks/4421 \
  --header "Authorization: Bearer $ENVIA_SANDBOX_TOKEN" \
  --header "Content-Type: application/json" \
  --data '{"active": 0}'

Production checklist

Before going live with webhooks, verify:

  • Endpoint is publicly reachable via HTTPS
  • Responds with 2xx within 5 seconds
  • Processes payloads asynchronously (don't block the response)
  • Handles duplicate deliveries with idempotency (use a unique key from the payload to deduplicate)
  • Uses separate webhook URLs for sandbox and production
  • Tested using the Test Webhook endpoint
  • Logs all incoming events for debugging

Troubleshooting

Webhook events are not arriving
  1. Check that your URL is publicly accessible (not localhost).
  2. Verify the webhook is active: 1 with GET /webhooks.
  3. Test manually with the Test Webhook endpoint.
  4. Confirm your firewall/proxy allows POST requests from Envia's servers.
Receiving duplicate events

Implement idempotency by tracking processed events. Use a combination of fields from the payload as a unique key. If you've already processed that combination, skip it.

Webhook endpoint timing out

Return 200 OK immediately and process the payload in a background job or queue. Do not make external API calls before responding.

📚

Related pages: