Skip to main content

Shipments and confirmation

How a shipment you record reaches its receiver, how the receiver confirms what arrived, and how your system finds out. It works the same whether the receiver is on DawaTrack or not.

The flow

  1. You record a SHIP with a consignment: your despatch advice.
  2. A receiver on DawaTrack records receiving it there. A receiver outside DawaTrack is emailed a link at once.
  3. The receiver confirms each line: received, damaged, refused. Whatever is neither received nor refused is recorded short.
  4. You read the answer with GET /consignments/, or are told with the consignment.received webhook.
  5. If the receiver sends some on, or uses some, it records that on its own page. Those hops appear on your batch tree, marked as declared by it.
  6. A recall reaches every party on the way, those outside DawaTrack by email.

1. Record the shipment

Each SHIP is one line of a consignment. Give your own consignment number, and the same number on every line of the same delivery. Name the receiver one of three ways:

  • destination_schema_name: a pharmacy on DawaTrack.
  • destination_supplier_ppb_license_number: a supplier on DawaTrack, if your account is linked to a supplier.
  • recipient: anyone outside DawaTrack. It needs a name, and both an email and a phone. The email is how its link and any recall reach it. Both are kept off the ledger.
POST /events/
{
  "event_type": "SHIP",
  "gtin": "06164004321562",
  "batch_number": "BTH-2026-041",
  "quantity": 30,
  "expiry_date": "2028-06-30",
  "recipient": {
    "name": "Upcountry Wholesalers",
    "ppb_licence": "PPB/W/4410",
    "email": "stores@upcountry.example",
    "phone": "+254700004410"
  },
  "consignment": {
    "number": "DESADV-0001",
    "carrier_name": "Lake Basin Couriers",
    "waybill_number": "WB-31",
    "expected_delivery_date": "2026-11-06"
  }
}

An email that belongs to a DawaTrack account is refused as a receiver outside DawaTrack: name that facility or supplier instead. See Events for every field.

2. The receiver confirms

A receiver outside DawaTrack gets an email that the consignment is on its way, with one link. The link works once and lasts 30 days. Before it can see or confirm anything, the receiver enters a 6-digit code sent to the email on file, so a forwarded link is no use to anyone else. If it hasn't confirmed after 2 days it gets one reminder, with a new link.

It confirms on the page, scanning packs or carton labels or typing the counts, or from its own system with POST /capture/code/ and POST /capture/receive/ (Capture links). Either way, each line gets:

  • a RECEIVE for the units received, whose parent is your SHIP, with link_confidence INFERRED: the receiver's word, recording whether a scan matched the batch;
  • a RECEIPT_ANSWER when the line was short, damaged or refused, as in a GS1 receiving advice. It moves no stock. Refused units are still yours to record as a return.

3. Find out what arrived

GET /consignments/ lists your consignments with each line's answer. This includes the ones your linked supplier account declared on the portal and the ones your linked facilities dispatched. state is confirmed, partly_confirmed, waiting, or not_confirmed when a receiver outside DawaTrack hasn't answered 7 days after the consignment left.

GET /consignments/DESADV-0001/
{
  "number": "DESADV-0001",
  "biz_transaction": "urn:dawatrack:desadv:partner-42:DESADV-0001",
  "receiver": {"name": "Upcountry Wholesalers", "on_dawatrack": false, "party_id": 918, "reachable": true},
  "state": "confirmed",
  "lines": [
    {"event_id": 5531, "batch_number": "BTH-2026-041", "quantity": 30, "received": 28,
     "short": 0, "damaged": 2, "refused": 2, "confirmation": "scanned", "received_at": "2026-11-06T10:12:00+03:00"}
  ],
  "link": {"sent_to": "s•••@upcountry.example", "sent_at": "2026-11-04T09:00:02+03:00", "reminded_at": null}
}

To be told rather than poll, subscribe to consignment.received and consignment.not_confirmed. Their body is the same consignment object, under consignment.

4. Onward hops

After confirming, a receiver outside DawaTrack can record on its own page what it did with the stock. The page opens with a code sent to its verified email. It can record units it sent on to someone else, who is then emailed a link of their own, and units it dispensed or used, as one count with no patient details. Both are limited to what it confirmed receiving.

These are a SHIP and a DISPENSE parented to its RECEIVE, both INFERRED. The API has no endpoint for them, because a party outside DawaTrack has no API credential.

5. The batch tree

GET /batches/{gtin}/{batch_number}/tree/ shows every party the batch reached, hop by hop. For each party it shows:

  • confirmation: recorded, scanned, typed or declared, with declared_by naming the party that declared it;
  • the consignments it arrived on;
  • its short, damaged and refused units;
  • for a party outside DawaTrack, whether it is reachable: an email it verified and a phone on file.

A shipment nobody has confirmed is waiting, or not-confirmed after 7 days, with the sender it is waiting on. GET /parties/ lists the parties outside DawaTrack you recorded, and PATCH /parties/{id}/ sets one's email and phone.

6. Recalls

A recall reaches pharmacies on DawaTrack through their recall console. It reaches every party outside DawaTrack on the batch's way, declared ones included, by an email with a link to answer. A party that hasn't answered after 24 hours gets a second notice. GET /recalls/{id}/report/ lists them under outside_parties, each with its status, when it was notified, and its answer.

7. EPCIS

In GET /batches/{gtin}/{batch_number}/epcis/, each SHIP, and each RECEIVE of it, carries its consignment as a CBV desadv business transaction. That is the same URI as biz_transaction on GET /consignments/, so the two join. A RECEIPT_ANSWER isn't an EPCIS event: read it from GET /consignments/.

What you never get back

A receiver's email and phone are kept off the ledger. They are used only to send its links and recall notices. The API returns whether a party can be reached, and the address a link went to masked, never the contact itself. Regulators see the contacts on their own view.

Partner API v1. The API reference is generated from the API's own code.