Skip to the docs
ae.deliverydevelopers

API reference

Create shipments, follow them, and settle cash on delivery with a delivery company on ae.delivery. JSON over HTTPS, one bearer key, errors you can show to people.

Base URL https://api.ae.delivery/v1 · Version 2026-09-25 · OpenAPI document

Quick start

Ask the delivery company for a test key, then create your first shipment. With a test key nothing is sent and no rider is involved.

Create a shipment (test key)
curl https://api.ae.delivery/v1/shipments \
  -H "Authorization: Bearer $AED_TEST_KEY" \
  -H "Content-Type: application/json" \
  -H "Idempotency-Key: order-10042-create" \
  -H "AE-Version: 2026-09-25" \
  -d '{
    "merchant_reference": "ORDER-10042",
    "service": "next_day",
    "payment_type": "cod",
    "cod_amount": 24500,
    "receiver": { "name": "Test Receiver", "phone": "+971500000000", "language": "ar" },
    "address": { "text": "Villa 12, Street 4, Al Nahda", "emirate": "SHJ", "area": "shj-al-nahda" }
  }'

The response is the shipment, with its tracking number and tracking link. Send the same request again with the same Idempotency-Key and you get the same shipment back, not a second one.

Authentication

Send your key in the Authorization header on every request. Keys are shown once when they are made; store them like passwords.

aed_test_sk_…

  • Never sends a message to anyone.
  • Never billed.
  • Never reaches a real rider.
  • Unlocks the simulator to move parcels through their life.

aed_live_sk_…

  • Real parcels, real riders, real money.
  • Every object carries livemode: true.
  • Only issued once the delivery company is live.

Each key has scopes, listed with every endpoint below. A merchant key only ever sees that merchant's parcels.

Errors

Errors follow RFC 9457 (problem+json). Each has a stable code to branch on, a title in English and Arabic you can show to people, and a request id to quote to support.

An error response
HTTP/1.1 409 Conflict
Content-Type: application/problem+json
AE-Request-Id: req_4f2a91c07be3d58a6e1f

{
  "type": "https://docs.ae.delivery/errors/cancellation_window_closed",
  "title": "It is too late to cancel this parcel",
  "title_ar": "فات أوان إلغاء هذا الطرد",
  "status": 409,
  "code": "cancellation_window_closed",
  "request_id": "req_4f2a91c07be3d58a6e1f"
}
Error codes
HTTPCodeTitle (English)Title (Arabic)
400invalid_requestThe request is not validالطلب غير صالح
401unauthorizedSign-in requiredيلزم تسجيل الدخول
403forbiddenYou can't do thisلا يمكنك تنفيذ هذا الإجراء
404not_foundNot foundغير موجود
409conflictThis conflicts with the current stateيتعارض هذا مع الحالة الحالية
409cancellation_window_closedIt is too late to cancel this parcelفات أوان إلغاء هذا الطرد
422duplicate_referenceThis merchant reference already existsهذا المرجع موجود مسبقاً
422no_rate_cardNo agreed rate for this parcelلا يوجد سعر متفق عليه لهذا الطرد
400idempotency_key_requiredAn Idempotency-Key header is requiredيلزم ترويسة Idempotency-Key
422idempotency_key_reusedThis Idempotency-Key was used for a different requestاستُخدم هذا المفتاح لطلب مختلف
403test_mode_onlyOnly available with test keysمتاح فقط بمفاتيح الاختبار
429too_many_attemptsToo many attempts, try again laterمحاولات كثيرة، حاول لاحقاً
500internalSomething went wrong; nothing was lostحدث خطأ؛ لم يُفقد أي شيء

Branch on code, never on the title text. Validation errors (422) also list each field that failed in errors.

Idempotency

Send an Idempotency-Key header on POST requests so a retry never creates something twice.

  • The same key with the same body returns the stored response, marked with Idempotent-Replayed: true.
  • The same key with a different body is refused with idempotency_key_reused.
  • The key is required on settlements; the endpoint list says where.
  • Your merchant_reference is also unique per merchant, so an order can only become one shipment.

Money is integer fils

Every amount is a whole number of fils, the smallest unit of the dirham. There are no decimals anywhere in the API, and the currency is always AED.

24500 = AED 245.00100 = AED 1.005 = AED 0.05

Round in your own system before you send; a fractional amount is refused. Cash collected, fees and settlements all use the same unit, so statements add up to the fils.

Webhooks

Delivery is on

Webhooks are being delivered to registered endpoints.

Webhooks follow Standard Webhooks v1. Each endpoint has its own secret starting whsec_, shown once when you create the endpoint.

  • Every request carries webhook-id, webhook-timestamp and webhook-signature headers.
  • The signature is HMAC-SHA256 over id, timestamp and the raw body, joined by dots.
  • Failed deliveries are retried for about 27.5 hours; an endpoint failing for 5 days is disabled.
  • Payloads carry sequence and occurred_at, so you can put events in order and drop duplicates by webhook-id.
  • Personal details of the receiver are left out unless the endpoint opts in to include_pii.
Verify a webhook in Node
// Verify an ae.delivery webhook (Standard Webhooks v1) with Node's built-in crypto.
import { createHmac, timingSafeEqual } from "node:crypto";

export function verifyWebhook(rawBody, headers, secret /* "whsec_…" */) {
  const id = headers["webhook-id"];
  const ts = headers["webhook-timestamp"];
  const sigs = String(headers["webhook-signature"] ?? "").split(" ");
  if (!id || !ts) throw new Error("missing webhook headers");
  // Reject anything older or newer than 5 minutes (replay protection).
  if (Math.abs(Date.now() / 1000 - Number(ts)) > 300) throw new Error("timestamp outside tolerance");

  const key = Buffer.from(secret.replace(/^whsec_/, ""), "base64");
  const expected = createHmac("sha256", key).update(`${id}.${ts}.${rawBody}`).digest();
  const ok = sigs.some((s) => {
    const [version, value] = s.split(",");
    if (version !== "v1" || !value) return false;
    const got = Buffer.from(value, "base64");
    return got.length === expected.length && timingSafeEqual(got, expected);
  });
  if (!ok) throw new Error("bad signature");
  return JSON.parse(rawBody); // then de-duplicate on webhook-id and order by "sequence"
}

Event catalogue (67 events)

  • shipment.created
  • shipment.confirmed
  • shipment.updated
  • shipment.status_changed
  • shipment.pickup_assigned
  • shipment.picked_up
  • shipment.pickup_failed
  • shipment.received_at_hub
  • shipment.out_for_delivery
  • shipment.arrived
  • shipment.delivery_attempt_failed
  • shipment.rescheduled
  • shipment.address_changed
  • shipment.on_hold
  • shipment.released
  • shipment.delivered
  • shipment.return_initiated
  • shipment.returned
  • shipment.cancelled
  • shipment.corrected
  • pickup.created
  • pickup.assigned
  • pickup.completed
  • pickup.failed
  • pickup.cancelled
  • pod.captured
  • label.generated
  • shipment.feedback_received
  • complaint.created
  • cod.collected
  • cod.collection_failed
  • cod.handed_over
  • settlement.created
  • settlement.voided
  • statement.issued
  • import.completed
  • import.failed
  • carrier.status_unmapped
  • carrier.booking_failed
  • webhook_endpoint.disabled
  • api_key.created
  • api_key.revoked
  • ping
  • eta.updated
  • shipment.at_risk
  • shipment.pickup_requested
  • shipment.pickup_en_route
  • shipment.pickup_arrived
  • shipment.sorted
  • shipment.transfer_departed
  • shipment.transfer_arrived
  • shipment.handed_to_carrier
  • shipment.en_route
  • shipment.partially_delivered
  • shipment.reattempt_requested
  • shipment.return_assigned
  • shipment.return_out_for_delivery
  • shipment.return_attempt_failed
  • shipment.pieces_mismatch
  • shipment.issue_reported
  • shipment.exception_closed
  • shipment.reopened
  • shipment.exchange_created
  • shipment.reverse_pickup_created
  • cod.not_collected
  • cod.reversed
  • shipment.created_at_pickup

Merchant endpoints never receive company-only events such as cash handovers between riders and the company.

Test mode

With a test key, parcels move only when you move them. Advance a parcel one step, or run a whole scenario:

happy_path
Picked up, at the hub, out for delivery, delivered.
failed_then_delivered
The first delivery attempt fails with a reason, the second succeeds.
rto
Delivery fails and the parcel goes back to the sender.
cod_short
Delivered, but the rider collects less cash than asked, so the statement shows the difference.
Run a scenario
curl -X POST https://api.ae.delivery/v1/test/shipments/shp_…/simulate \
  -H "Authorization: Bearer $AED_TEST_KEY" \
  -H "Content-Type: application/json" \
  -d '{ "scenario": "failed_then_delivered" }'

Scenarios are chosen by the request, never by special phone numbers. The simulator endpoints refuse live keys with test_mode_only.

Status model

A shipment has one status from this fixed set, plus a finer sub-status. The receiver wording is what the tracking page shows. The same list is served at GET /v1/meta/statuses.

Status model
StatusWhat the receiver seesFinalSub-statuses
draftNot shown to receiversNodraft
ready_for_pickupOrder receivedتم استلام الطلبNoawaiting_pickup_assignmentpickup_assignedrider_en_route_to_pickuprider_arrived_at_pickuppickup_attempt_failedawaiting_dropoff_at_hub
picked_upPicked upتم الاستلام من المتجرNopicked_upin_transit_to_hubpicked_up_partialawaiting_details
at_hubAt our facilityفي مركز التوزيعNoreceived_at_hubsortedin_transferreceived_at_destination_hubawaiting_rider_assignmentassigned_to_riderheld_for_self_collectionscheduled_for_future_date
out_for_deliveryOn the wayفي الطريق إليكNoout_for_deliveryrider_en_routearrived_at_dropoff
attempt_failedDelivery attemptedتمت محاولة التوصيلNoattempt_failedreattempt_scheduledawaiting_merchant_instructionawaiting_receiver_response
on_holdOn holdمعلّقNoheld_by_merchantheld_by_tenantaddress_verificationid_verificationpayment_verificationdamaged_under_reviewheld_by_receivermissing_under_investigation
returningReturning to senderقيد الإرجاعNoreturn_requestedreturn_at_hubreturn_out_for_deliveryreturn_attempt_failedreturn_assignedreturn_arrived_at_merchant
deliveredDeliveredتم التوصيلYesdelivered_to_recipientdelivered_to_alternatedelivered_to_safe_placepartially_deliveredcollected_by_recipient
returnedReturnedتم الإرجاعYesreturned_to_merchantreturned_to_merchant_partial
cancelledCancelledأُلغيYescancelled_by_merchantcancelled_by_tenantcancelled_no_service_areacancelled_duplicate
closed_exceptionIssue with shipmentمشكلة في الشحنةYeslostdamageddisposed_on_requestdisposed_unclaimed

A final status does not change again, except by a correction, which arrives as shipment.corrected.

Endpoints

Generated from the same route list as the OpenAPI document. Paths are relative to the base URL.

Quotes

  • post/v1/quotes

    Quote a price, promised date and serviceability

    Scopes: quotes:write
    Request body (19 fields)
    Request body fields
    FieldTypeNotes
    merchant_idstringRequired for tenant keys; ignored for merchant keys
    serviceenumnext_day · same_day · scheduled · express · return_pickup — default "next_day"
    payment_typeenumprepaid · cod · card_on_delivery · pay_by_link — default "prepaid"
    cod_amountintegerInteger fils (AED 1.00 = 100) — default 0 — 0…100000000
    pickup_location_idstring
    destinationobject
    destination.textstringThe address exactly as entered, in its original language — length 3…500
    destination.emirateenumAUH · DXB · SHJ · AJM · UAQ · RAK · FUJ
    destination.areastringArea/community name (EN or AR) or a gazetteer id like shj-al-nahda — length 0…120
    destination.streetstringlength 0…200
    destination.buildingstringlength 0…120
    destination.floorstringlength 0…20
    destination.unitstringlength 0…40
    destination.landmarkstringlength 0…200
    destination.latnumber22…27
    destination.lngnumber51…57
    destination.pin_sourceenumreceiver · merchant · geocoder · rider · makani
    destination.makanistring
    ready_for_pickup_atstringdate-time

    * required. Field notes are in English, as in the OpenAPI document.

Shipments

  • post/v1/shipments

    Create a shipment (or a draft)

    Scopes: shipments:writeIdempotency-Key: optional
    Request body (46 fields)
    Request body fields
    FieldTypeNotes
    merchant_idstringRequired for tenant keys; ignored for merchant keys
    merchant_reference *stringYour order id; unique per merchant; echoed everywhere — length 1…64
    serviceenumnext_day · same_day · scheduled · express · return_pickup — default "next_day"
    payment_type *enumprepaid · cod · card_on_delivery · pay_by_link
    cod_amountintegerInteger fils (AED 1.00 = 100) — default 0 — 0…100000000
    declared_valueintegerInteger fils (AED 1.00 = 100) — 0…100000000
    quote_idstring
    pickup_location_idstring
    ready_for_pickup_atstringdate-time
    requested_delivery_datestringCalendar date in Asia/Dubai
    receiver *object
    receiver.name *stringlength 1…120
    receiver.phone *stringUAE mobile; normalised to E.164 — length 7…20
    receiver.alt_phonestringlength 7…20
    receiver.emailstringemail
    receiver.languageenumar · en — default "ar"
    address *object
    address.text *stringThe address exactly as entered, in its original language — length 3…500
    address.emirateenumAUH · DXB · SHJ · AJM · UAQ · RAK · FUJ
    address.areastringArea/community name (EN or AR) or a gazetteer id like shj-al-nahda — length 0…120
    address.streetstringlength 0…200
    address.buildingstringlength 0…120
    address.floorstringlength 0…20
    address.unitstringlength 0…40
    address.landmarkstringlength 0…200
    address.latnumber22…27
    address.lngnumber51…57
    address.pin_sourceenumreceiver · merchant · geocoder · rider · makani
    address.makanistring
    parcelobjectdefault {"pieces":1,"flags":[]}
    parcel.descriptionstringlength 0…300
    parcel.piecesintegerdefault 1 — 1…50
    parcel.weight_gramsinteger1…100000
    parcel.size_classenumS · M · L · XL
    parcel.flagsarray<enum>default []
    notesstringlength 0…500
    consentobject
    consent.channelsarray<enum>items 1…
    consent.wordingstringThe exact wording the receiver agreed to; it must name the delivery company — length 10…1000
    consent.captured_atstringdate-time
    consent.sourcestringlength 0…80
    metadatamap
    draftbooleandefault false
    exchangeobjectExchange: also collect an item from the receiver at the same stop (creates a linked return pickup)
    exchange.descriptionstringlength 0…300
    exchange.piecesintegerdefault 1 — 1…50

    * required. Field notes are in English, as in the OpenAPI document.

  • get/v1/shipments

    List shipments (cursor pagination)

    Scopes: shipments:read
  • get/v1/shipments/{id}

    Retrieve a shipment

    Scopes: shipments:read
  • patch/v1/shipments/{id}

    Edit a draft (any field, re-priced); after confirming, notes and metadata only

    Scopes: shipments:write
    Request body (31 fields)
    Request body fields
    FieldTypeNotes
    merchant_referencestringlength 1…64
    serviceenumnext_day · same_day · scheduled · express · return_pickup
    payment_typeenumprepaid · cod · card_on_delivery · pay_by_link
    cod_amountintegerInteger fils (AED 1.00 = 100) — 0…100000000
    requested_delivery_datestringCalendar date in Asia/Dubai
    receiverobject
    receiver.namestringlength 1…120
    receiver.phonestringUAE mobile; normalised to E.164 — length 7…20
    receiver.alt_phonestringlength 7…20
    receiver.emailstringemail
    receiver.languageenumar · en — default "ar"
    addressobject
    address.textstringThe address exactly as entered, in its original language — length 3…500
    address.emirateenumAUH · DXB · SHJ · AJM · UAQ · RAK · FUJ
    address.areastringArea/community name (EN or AR) or a gazetteer id like shj-al-nahda — length 0…120
    address.streetstringlength 0…200
    address.buildingstringlength 0…120
    address.floorstringlength 0…20
    address.unitstringlength 0…40
    address.landmarkstringlength 0…200
    address.latnumber22…27
    address.lngnumber51…57
    address.pin_sourceenumreceiver · merchant · geocoder · rider · makani
    address.makanistring
    parcelobject
    parcel.descriptionstringlength 0…300
    parcel.weight_gramsinteger1…100000
    parcel.size_classenumS · M · L · XL
    parcel.flagsarray<enum>
    notesstringlength 0…500
    metadatamap

    * required. Field notes are in English, as in the OpenAPI document.

  • post/v1/shipments/{id}/confirm

    Confirm a draft

    Scopes: shipments:write
  • post/v1/shipments/{id}/cancel

    Cancel (before pickup only; 409 cancellation_window_closed after). Optional {reason, note}

    Scopes: shipments:write
    Request body (2 fields)
    Request body fields
    FieldTypeNotes
    reasonenummerchant_request · customer_changed_mind · duplicate · no_service_area · company_decision
    notestringlength 0…500

    * required. Field notes are in English, as in the OpenAPI document.

  • post/v1/shipments/{id}/return

    Request return to origin. Optional {reason, note}

    Scopes: shipments:write
    Request body (2 fields)
    Request body fields
    FieldTypeNotes
    reasonenummerchant_request · cancelled_after_pickup · recipient_refused · max_attempts · unclaimed · address_unresolvable · out_of_service_area · damaged · company_decision · partial_delivery_remainder
    notestringlength 0…500

    * required. Field notes are in English, as in the OpenAPI document.

  • post/v1/shipments/{id}/hold

    Put a parcel on hold (merchants: reason merchant_request; before pickup or at the hub)

    Scopes: shipments:write
    Request body (2 fields)
    Request body fields
    FieldTypeNotes
    reasonenumMerchants may use merchant_request only — merchant_request · receiver_request · address_check · id_check · payment_check · damaged · missing · company_check — default "merchant_request"
    notestringlength 0…500

    * required. Field notes are in English, as in the OpenAPI document.

  • post/v1/shipments/{id}/release

    Release your own hold (back to awaiting pickup, or to the hub queue)

    Scopes: shipments:write
    Request body (1 field)
    Request body fields
    FieldTypeNotes
    notestringlength 0…500

    * required. Field notes are in English, as in the OpenAPI document.

  • post/v1/shipments/{id}/reattempt

    Ask for another delivery attempt after a failure (optionally on a day)

    Scopes: shipments:write
    Request body (2 fields)
    Request body fields
    FieldTypeNotes
    datestringOptional new day (GST); omit for the next working day
    notestringlength 0…500

    * required. Field notes are in English, as in the OpenAPI document.

  • post/v1/shipments/{id}/reverse-pickup

    Book a return pickup from the receiver of a delivered parcel (linked; priced as return_pickup)

    Scopes: shipments:write
    Request body (4 fields)
    Request body fields
    FieldTypeNotes
    descriptionstringlength 0…300
    piecesintegerdefault 1 — 1…50
    datestringCalendar date in Asia/Dubai
    notesstringlength 0…500

    * required. Field notes are in English, as in the OpenAPI document.

  • get/v1/shipments/{id}/timeline

    The stage timeline (stage keys, EN/AR labels, times in GST, who) and the stage stepper

    Scopes: shipments:read
  • post/v1/shipments/{id}/forget-receiver

    Forget the receiver: replace name, phones, email, address and pin with a pseudonymous token (company keys only; idempotent; body {reason})

    Scopes: shipments:write
  • post/v1/shipments/{id}/reschedule

    Reschedule delivery

    Scopes: shipments:write
    Request body (2 fields)
    Request body fields
    FieldTypeNotes
    date *stringCalendar date in Asia/Dubai
    reasonstringlength 0…300

    * required. Field notes are in English, as in the OpenAPI document.

  • post/v1/shipments/{id}/change-requests

    Request a change after pickup

    Scopes: shipments:write
    Request body (3 fields)
    Request body fields
    FieldTypeNotes
    field *enumaddress · phone · date · cod
    value *any
    reasonstringlength 0…300

    * required. Field notes are in English, as in the OpenAPI document.

  • post/v1/shipments/{id}/delivery-details

    Add the receiver and address to a parcel a rider collected by your own barcode/QR (status picked_up / awaiting_details; it cannot go out until this is done)

    Scopes: shipments:write
    Request body (35 fields)
    Request body fields
    FieldTypeNotes
    receiver *object
    receiver.name *stringlength 1…120
    receiver.phone *stringUAE mobile; normalised to E.164 — length 7…20
    receiver.alt_phonestringlength 7…20
    receiver.emailstringemail
    receiver.languageenumar · en — default "ar"
    address *object
    address.text *stringThe address exactly as entered, in its original language — length 3…500
    address.emirateenumAUH · DXB · SHJ · AJM · UAQ · RAK · FUJ
    address.areastringArea/community name (EN or AR) or a gazetteer id like shj-al-nahda — length 0…120
    address.streetstringlength 0…200
    address.buildingstringlength 0…120
    address.floorstringlength 0…20
    address.unitstringlength 0…40
    address.landmarkstringlength 0…200
    address.latnumber22…27
    address.lngnumber51…57
    address.pin_sourceenumreceiver · merchant · geocoder · rider · makani
    address.makanistring
    serviceenumDefaults to the service the parcel was collected under (next_day) — next_day · same_day · scheduled · express · return_pickup
    payment_typeenumprepaid · cod · card_on_delivery · pay_by_link — default "prepaid"
    cod_amountintegerInteger fils (AED 1.00 = 100) — default 0 — 0…100000000
    declared_valueintegerInteger fils (AED 1.00 = 100) — 0…100000000
    requested_delivery_datestringCalendar date in Asia/Dubai
    parcelobject
    parcel.descriptionstringlength 0…300
    parcel.weight_gramsinteger1…100000
    parcel.size_classenumS · M · L · XL
    parcel.flagsarray<enum>default []
    notesstringlength 0…500
    consentobject
    consent.channelsarray<enum>items 1…
    consent.wordingstringThe exact wording the receiver agreed to; it must name the delivery company — length 10…1000
    consent.captured_atstringdate-time
    consent.sourcestringlength 0…80

    * required. Field notes are in English, as in the OpenAPI document.

  • get/v1/shipments/{id}/events

    The shipment's event history

    Scopes: shipments:read

Labels

  • get/v1/shipments/{id}/label

    Label with your default label profile (?profile=<id>; ?format=pdf|png|tspl; png takes ?page=n)

    Scopes: labels:read
  • get/v1/labels

    Labels for many parcels in one file (?ids=a,b,c up to 500; ?profile, ?format=pdf|png, ?page)

    Scopes: labels:read

Print stations

  • post/v1/print-station/heartbeat

    Print station: report host and printers (print-station keys only)

    Scopes: print:station
  • post/v1/print-station/claim

    Print station: take the next queued job, or 204

    Scopes: print:station
  • get/v1/print-station/jobs/{id}/document

    Print station: the job's file (?format=pdf|png, ?page)

    Scopes: print:station
  • post/v1/print-station/jobs/{id}/ack

    Print station: report done or failed ({ ok, error?, station_job_ref? })

    Scopes: print:station

Pickups

  • post/v1/pickups

    Request a pickup

    Scopes: pickups:write
    Request body (7 fields)
    Request body fields
    FieldTypeNotes
    merchant_idstring
    pickup_location_id *string
    date *stringCalendar date in Asia/Dubai
    window_fromstring
    window_tostring
    expected_countinteger1…500
    shipment_idsarray<string>items 0…500

    * required. Field notes are in English, as in the OpenAPI document.

  • get/v1/pickups

    List pickups

    Scopes: pickups:write

Reference

  • get/v1/meta/statuses

    The versioned status set with EN/AR labels

    Scopes: none (public)
  • get/v1/service-areas

    Emirates and areas served

    Scopes: none (public)
  • post/v1/addresses/validate

    Resolve an address to an area and a quality score

    Scopes: none (public)
    Request body (12 fields)
    Request body fields
    FieldTypeNotes
    text *stringThe address exactly as entered, in its original language — length 3…500
    emirateenumAUH · DXB · SHJ · AJM · UAQ · RAK · FUJ
    areastringArea/community name (EN or AR) or a gazetteer id like shj-al-nahda — length 0…120
    streetstringlength 0…200
    buildingstringlength 0…120
    floorstringlength 0…20
    unitstringlength 0…40
    landmarkstringlength 0…200
    latnumber22…27
    lngnumber51…57
    pin_sourceenumreceiver · merchant · geocoder · rider · makani
    makanistring

    * required. Field notes are in English, as in the OpenAPI document.

Tracking

  • get/v1/tracking/{tracking_number}

    Public tracking (receiver-safe fields only)

    Scopes: tracking:read

Webhooks

  • get/v1/webhook-endpoints

    List webhook endpoints

    Scopes: webhooks:manage
  • post/v1/webhook-endpoints

    Create a webhook endpoint (secret shown once)

    Scopes: webhooks:manage
    Request body (4 fields)
    Request body fields
    FieldTypeNotes
    url *stringuri — length 0…2000
    descriptionstringlength 0…200
    events *array<string>Event types, or ["*"] — items 1…
    include_piibooleandefault false

    * required. Field notes are in English, as in the OpenAPI document.

  • delete/v1/webhook-endpoints/{id}

    Delete a webhook endpoint

    Scopes: webhooks:manage
  • post/v1/webhook-endpoints/{id}/test

    Send a ping event

    Scopes: webhooks:manage
  • get/v1/webhook-endpoints/{id}/deliveries

    Delivery log

    Scopes: webhooks:manage
  • post/v1/webhook-deliveries/{id}/retry

    Resend a delivery

    Scopes: webhooks:manage
  • get/v1/events

    Events feed (?after=<cursor>), 30-day retention

    Scopes: shipments:read

Finance

  • get/v1/finance/balances

    Live balances (COD held, fees due, remittable now)

    Scopes: finance:read
  • get/v1/statements

    Statement for a period (?from&to), from the one builder

    Scopes: finance:read
  • post/v1/settlements

    Record a settlement (tenant keys; idempotent)

    Scopes: finance:writeIdempotency-Key: required
    Request body (7 fields)
    Request body fields
    FieldTypeNotes
    merchant_id *string
    shipment_ids *array<string>items 1…2000
    method *enumbank_transfer · cash · ziina
    external_reference *stringThe real-world reference: bank transfer ref, Ziina payment id or cash receipt — length 3…80
    value_date *stringCalendar date in Asia/Dubai
    directionenumto_merchant: the company pays the merchant its COD minus fees. from_merchant: fees exceed the COD held, and the merchant pays the difference. — to_merchant · from_merchant — default "to_merchant"
    expected_transfer_amount *integerThe amount that actually moved (always positive); must equal the computed net in the stated direction or the request is refused — 0…100000000

    * required. Field notes are in English, as in the OpenAPI document.

  • get/v1/settlements

    List settlements

    Scopes: finance:read

Test mode

  • post/v1/test/shipments/{id}/advance

    Test mode: advance one step

    Scopes: shipments:writeTest mode only
  • post/v1/test/shipments/{id}/simulate

    Test mode: run a scenario

    Scopes: shipments:writeTest mode only
    Request body (1 field)
    Request body fields
    FieldTypeNotes
    scenario *enumhappy_path · failed_then_delivered · rto · cod_short

    * required. Field notes are in English, as in the OpenAPI document.

ae.delivery API. Examples use fictional data and a test key.