Agent skill

Nash Webhooks Skill

Receive and verify Nash (usenash.com, now nash.ai) delivery orchestration webhooks. Nash sends webhooks through Svix, so verify the svix-id, svix-timestamp and svix-signature headers (HMAC-SHA256, base64, over "{svix-id}.{svix-timestamp}.{raw body}" keyed with the endpoint's whsec_ signing secret) with the svix SDK or manually. Use when setting up a Nash webhook handler, debugging Nash signature verification, or handling the { type, event, data } payload for delivery events (dropoff_complete, canceled_by_provider), task events (task.created, task.canceled_by_provider), courier_location.updated, courier_name.updated and shift.dispatched.

Install this skill

npx skills add hookdeck/webhook-skills --skill nash-webhooks


Nash (usenash.com, now nash.ai) is a delivery orchestration platform: one API to quote and dispatch deliveries across courier networks, local fleets and your own drivers. Nash webhooks push every job, task and courier change to your endpoint so you don't poll. Docs: docs.usenash.com/reference/webhooks.

When to Use This Skill

  • How do I receive Nash webhooks?
  • How do I verify Nash webhook signatures (svix-signature)?
  • Where do I find the Nash webhook signing secret?
  • How do I handle task.created, task.canceled_by_provider or shift.dispatched?
  • How do I track delivery status (dropoff_complete, canceled_by_provider) from Nash webhooks?
  • Why is my Nash webhook signature verification failing?

How Nash Signs Webhooks

Nash delivers through Svix. Every request carries three headers:

HeaderContent
svix-idMessage ID, identical on every retry (use it to deduplicate)
svix-timestampUnix seconds when the attempt was signed
svix-signatureSpace-delimited list of v1,<base64 signature> entries

The signature is base64(HMAC-SHA256(key, "{svix-id}.{svix-timestamp}.{raw body}")), where key is the base64-decoded part of the signing secret after whsec_. Get the secret in the Nash Portal: Settings > Webhook Management > click an endpoint > Signing Secret. Nash recommends the Svix SDKs; they also enforce a 5-minute timestamp tolerance.

Verification (core)

// svix 2.x is ESM-only: use import (or `await import('svix')` from CommonJS).
// Python: pip install svix; from svix.webhooks import Webhook
import { Webhook } from 'svix';

// rawBody: the exact request body string/bytes, read BEFORE any JSON parsing.
function verifyNashWebhook(rawBody, headers, secret = process.env.NASH_WEBHOOK_SECRET) {
  // Throws on a bad signature or a timestamp more than 5 minutes off.
  // svix 2.x returns nothing, so parse the body yourself afterwards.
  new Webhook(secret).verify(rawBody, {
    'svix-id': headers['svix-id'],
    'svix-timestamp': headers['svix-timestamp'],
    'svix-signature': headers['svix-signature'],
  });
  const { type, event, data } = JSON.parse(rawBody);
  return { eventType: `${type}.${event}`, data };
}

For complete handlers with tests, see examples/express/, examples/nextjs/, examples/fastapi/.

The manual algorithm (no SDK) is in references/verification.md.

Payload and Event Types

Every payload is { "type", "event", "data" }. type is the entity and event the status within it; the examples dispatch on `${type}.${event}`.

typeExample event valuesdata
deliverycreated, assigned_driver, pickup_complete, dropoff_complete, canceled_by_provider, failedFull Job object
taskcreated, canceled_by_provider, canceled_by_reassign, failed, dispatch_failureFull Job object
courier_locationupdated (every 1-2 minutes)Full Job object
courier_nameupdated (same provider swapped drivers)Full Job object
shiftdispatched{ eventSourceId, created_job_ids, errors }

The examples handle delivery.created, delivery.assigned_driver, delivery.dropoff_complete, delivery.canceled_by_provider, delivery.failed, task.created, task.canceled_by_provider, task.failed, courier_location.updated, courier_name.updated and shift.dispatched. The full lists are in references/overview.md.

Things that trip people up:

  • Each payload is a snapshot of the whole job, not a diff. A job can hold several tasks (delivery attempts), so the same delivery event can arrive once per task.
  • Reassignment creates a new task. The old task emits a terminal event (task.canceled_by_provider, task.canceled_by_auto_reassign, ...) and the new one emits task.created. Treat a task cancellation as terminal for that task only.
  • Timestamps in data are UTC ISO 8601 with microseconds and no timezone suffix.

Environment Variables

# Nash Portal > Settings > Webhook Management > endpoint > Signing Secret
NASH_WEBHOOK_SECRET=whsec_your_signing_secret_here

Local Development

npx hookdeck-cli listen 3000 nash --path /webhooks/nash

No account required. The CLI creates a guest account on first run and gives you a public URL to register under Settings > Webhook Management, plus a web UI for inspecting requests. Use port 8000 for the FastAPI example.

Retries

Svix retries failed deliveries (network errors, 5xx, and 408/409/429) immediately, then after 5 seconds, 5 minutes, 30 minutes, 2 hours, 5 hours, 10 hours and 10 hours. Return 2xx quickly and do the work asynchronously. Failed messages can be replayed from the Portal (Webhook Management > endpoint > Attempts). Returning 410 Gone disables the endpoint.

Reference Materials


Repository

hookdeck/webhook-skills

v0.1.0 · MIT · Updated Oct 28, 2026

View on GitHub →