Skip to content
Afi Planner

Does Afi Planner have an API with webhooks?

Short answer

Yes. Every Afi Planner plan, including the free trial, comes with a REST API (described in OpenAPI 3.1) to create orders, plan and dispatch routes and read statuses, ETAs and proof of delivery, plus signed webhooks for every change. POST requests accept an Idempotency-Key so a retry never creates a second order, and every webhook carries a sequence number so your system can put events back in order after a retry.

How it works in Afi Planner

Retries that never double an order

Send an Idempotency-Key header with a POST request: the same key with the same body within 24 hours gets the first answer back instead of a second action. Orders also carry your own order ID, so sending the same ID for the same day again updates the order, as long as no driver has worked on it. Once a driver has, the order stays as the delivery record: sending it again is refused with 409 order_worked and the order’s id, and PATCH /api/v1/orders/{id} changes its fields.

  • The same key with another body or path is refused (409 idempotency_conflict)
  • A retry that arrives while the first request is still running is refused too (409 idempotency_in_progress)
  • Up to 1,000 orders per batch request, and 600 requests a minute per key
  • A day’s plan holds at most your package’s stops per plan (500 on the free trial): a batch with more new orders than still fit is refused whole (403 with planFull)

Events you can put back in order

Every webhook carries a sequence number: the company’s own counter, one more for each event, never reused. A retry brings the same id, sequence and body as the first attempt, so your system applies an event only if its sequence is higher than the last one it applied for that order. occurredAt says when the thing happened, such as the delivery time of the report.

  • order.created, order.updated, order.status_changed, order.loaded (the driver’s load check put it in the van), order.eta_changed, order.rescheduled_by_customer, order.instructions_changed, order.rated, order.not_attempted, order.moved_back, order.cancelled, order.deleted
  • plan.optimized, plan.job_failed, route.dispatched
  • An endpoint that listens to some event types sees gaps in the sequence (test pings to other endpoints leave gaps too); it only goes up

Signed, retried, and visible

Each request is signed with HMAC-SHA256 and a timestamp in the Afi-Signature header. Answer with a 2xx within 10 seconds; failed deliveries are retried with growing delays for about a day, and every attempt shows in a delivery log with its HTTP status, with “Send test” and “Retry now” in Settings.

Webhook endpoint with a successful test delivery and the list of recent events

Frequently asked questions

Does the API cost extra?

No. The API and webhooks are part of every plan, including the free trial.

What happens if our endpoint is down?

Each event is retried for about a day. An endpoint that keeps failing for three days in a row is turned off and shows as such in Settings → Developers. Events raised while an endpoint is off (turned off by you or after failing) are not kept for it, and its sequence does not show they were missed: after turning it back on, read the day’s orders with GET /api/v1/orders?day=.

Is there a Shopify or Zapier app?

Not yet. Today you connect them through the API and webhooks.

More answers

Plan tomorrow’s routes in the next 3 minutes

Start your free 3-month trial. No credit card, no setup call, no installation.