Skip to main content

Events

The append-only supply chain event log, one event or up to 1,000 at a time.

Record an event

POST https://api.dawatrack.com/partner-api/v1/events/

Add one event to the append-only supply chain log: commission, ship, receive, dispense, quarantine and more.

Scope events:write Limit 5,000 per day

You can only report events for a GTIN and batch you have a relationship with, as the ledger records it: you are the product's registered manufacturer or a contract packer it authorized for the GTIN; or an event for that batch was reported by you, by your linked supplier account (including a shipment a pharmacy recorded receiving from it), or by a facility you're linked to. Otherwise 403. The same rule decides which batches, units and event histories you can read. One exception: a RECEIVE of stock you received from a party outside DawaTrack, naming it as sender, may be of any product, as a pharmacy's delivery note from an outside supplier is: every trading partner records its own receipts. It needs an approved account and production credentials, and then the batch is yours to report on like any other. The same goes for your opening stock: a RECEIVE with opening_balance: true, once per batch, before any other event of yours on it, within 30 days of your first.

parent_event must be an event you can see for the same GTIN and batch, and corrects_event one of your own. occurred_at defaults to now.

A document you cancelled in your own system is a RETRACT: send event_type RETRACT and the event's id as corrects_event, nothing else. The event did not occur (GS1 EPCIS error declaration, reason did_not_occur): every reader leaves it out, the EPCIS export carries it with its errorDeclaration, and a consignment whose lines are all retracted is cancelled. Once per event, and not once something follows from it (a receipt of the shipment, a shipment from the receipt): retract that first. A wrong detail is a correction instead: a new event of the same type naming the old one as corrects_event.

A stock event names the event it follows from as parent_event, so the graph can walk to and from it; otherwise 400 with detail, field (parent_event) and event_type. A RECEIVE names the SHIP it received, or, for stock from outside DawaTrack, its sender (name, and its ppb_licence or gln; a sender on DawaTrack is 400: name its SHIP). A DISPENSE names its RECEIVE, a RELEASE its QUARANTINE, a DISAGGREGATE its AGGREGATE. A SHIP, QUARANTINE or TRANSFER names the RECEIVE its units came from once you have received the lot on DawaTrack; before that the stock is your own and it needs none.

RECEIVE_LINK, SHIP_ANSWER (a supplier's answer to a delivery a pharmacy reported), RECALL_ACKNOWLEDGMENT (a party outside DawaTrack's answer to a recall notice) and RECEIPT_ANSWER (a receiver outside DawaTrack's report of a short, damaged or refused line) are written by DawaTrack, not by partners: each is 400.

The parent must be a type that can precede the event: a RECEIVE follows a SHIP or TRANSFER; a SHIP a RECEIVE, COMMISSION, AGGREGATE or DISAGGREGATE; a DISPENSE, QUARANTINE or TRANSFER a RECEIVE, COMMISSION or DISAGGREGATE; a RELEASE a QUARANTINE. A COMMISSION names none. Otherwise 400. A parent_event you can't reference is 400, the same answer as an id that doesn't exist.

On a SHIP, destination_schema_name (optional) names the DawaTrack facility receiving the shipment. When that facility receives the same GTIN and batch, its receipt is linked to your event, so traces and EPCIS show the hop from you to them. A name that isn't a DawaTrack facility is 400; on any other event type it's 400 too.

If your account is linked to a supplier, a SHIP can instead name another supplier with destination_supplier_ppb_license_number: the PPB licence number of an approved supplier on DawaTrack. That supplier is emailed and confirms receipt on its portal. An unknown or unapproved licence, your own, naming a facility as well, or a sandbox credential is 400.

Every SHIP is a line of a consignment (a despatch advice). Send consignment with your own number (1 to 40 letters, digits, ., _, / or -) and, optionally, reference, carrier_name, waybill_number, vehicle_registration, driver_name, driver_phone and expected_delivery_date: SHIP events with the same number are lines of one consignment, to one receiver, and a number you already used for another receiver is 400 (CONSIGNMENT_RECEIVER_MISMATCH in a bulk job). Leave it out and DawaTrack numbers a one-line consignment. The number goes on the ledger and in EPCIS as a desadv business transaction; the carrier, waybill, vehicle and driver are kept off the ledger. The response's consignment_number names it. consignment on any other event type is 400.

A SHIP that names an sscc: the carton's GS1 Digital Link URI, https://dawatrack.com/00/<SSCC> (the QR on a GS1 carton label), opens its receiver's page to confirm the consignment. Holding the carton shows only who sent it; confirming needs the code emailed to the receiver's address on file.

A sender (on a RECEIVE) or recipient (on a SHIP) outside DawaTrack needs an email and a phone, both: the email is how a recall reaches it now, the phone how an SMS will. The phone is given with its country code (+254…; a Kenyan 07… or 01… number works too) and kept in E.164. Otherwise 400. The recipient is emailed at once that the consignment is on its way, with one link to confirm what it received (it records the receipt on /capture/{token}/ or with POST /capture/receive/).

A gtin with a wrong GS1 check digit is 400, and the message says what the digit should be.

On a SHIP or COMMISSION, batch_number must be a GS1 batch (AI 10): at most 20 characters from GS1 character set 82, after spaces are removed, so it can be printed in a DataMatrix; otherwise 400. Other events aren't refused.

expiry_date and manufacture_date (optional, YYYY-MM-DD) are the lot's details. The first event for a GTIN and batch with an expiry records them for the lot, owned by the product's manufacturer when it is registered on DawaTrack. After that every event for the lot carries the same dates: one you send that differs is 400 naming the owner, and one you leave out takes the lot's. A manufacture date in the future, or on or after the expiry, is 400. An expiry_date inside raw_payload is still read for a lot not yet known, and never refused.

A SHIP or COMMISSION of a product saved as a draft on the supplier portal is 403 until its manufacturer activates it.

A SHIP by the product's own manufacturer is 403 while PPB's published register shows its registration expired, or DawaTrack staff confirmed it doesn't match its registration. Staff can allow shipping for a set time while a renewal is filed. Other partners' events for the product are not refused. GET /products/{gtin}/ shows the owner the reason under ppb_register.hold.

Request body

JSON. Send Content-Type: application/json.

  • event_type enum Required

    The kind of event.

    Possible values: COMMISSIONSHIPRECEIVETRANSFERDISPENSEQUARANTINERELEASEAGGREGATEDISAGGREGATERECEIVE_LINKSHIP_ANSWERRECALL_ACKNOWLEDGMENTRECEIPT_ANSWERRETRACT
  • gtin string Optional

    The product's GS1 GTIN, as 14 digits.

  • batch_number string Optional

    The batch or lot number.

  • serial_number string Optional

    The unit's serial number.

  • sscc string Optional

    An 18-digit GS1 Serial Shipping Container Code.

  • quantity integer Optional

    Quantity of units/items involved in this event (for batch-level or aggregated events).

  • expiry_date date or null Optional

    The lot's expiry date (GS1 AI 17). Optional. When the lot (GTIN and batch) is already on DawaTrack it must match the lot's, and a blank one takes the lot's; the first declaration with an expiry creates the lot. A raw_payload.expiry_date is still read for a lot not yet known.

  • manufacture_date date or null Optional

    The lot's manufacture date (GS1 AI 11). Optional, checked against the lot like expiry_date; not in the future, and before the expiry.

  • parent_event integer or null Optional

    Parent event forming the distribution graph (e.g. COMMISSION/RECEIVE -> SHIP/DISPENSE).

  • corrects_event integer or null Optional

    Event being corrected by this immutable record.

  • actor_id string Optional

    Who or what produced the event.

  • facility_id string Optional

    The facility where the event happened.

  • idempotency_key string Optional

    Optional key making this single event idempotent for your credential.

  • occurred_at datetime Optional

    Defaults to now if omitted.

  • raw_payload object Optional

    For AGGREGATE events, the packed children as a list of {gtin, serial}.

  • destination_schema_name string Optional

    SHIP only, optional: the DawaTrack facility (its schema_name) receiving this shipment. When that facility receives the same GTIN and batch, its receipt is linked to this event.

  • destination_supplier_ppb_license_number string Optional

    SHIP only, optional, for a partner linked to a supplier account: the PPB licence number of the approved DawaTrack supplier receiving this shipment. It confirms receipt on its Receiving screen. Use this or destination_schema_name, not both.

  • sender object Optional

    RECEIVE only, optional: the sender of stock that came from outside DawaTrack, so there is no SHIP to name as parent_event. The receipt is where the graph picks the lot up. Not with parent_event; not for a sender on DawaTrack, whose SHIP you name instead.

    • name string Required
    • ppb_licence string Optional
    • gln string Optional
    • email string Optional

      How a recall reaches this party: kept on its party record, off the ledger, and only used to send it recall notices. An email and a phone are both required; the email is what a recall notice is sent to now. The phone is stored in E.164 (+254...); a Kenyan number may be given as 07... or 01...

    • phone string Optional

      How a recall reaches this party: kept on its party record, off the ledger, and only used to send it recall notices. An email and a phone are both required; the email is what a recall notice is sent to now. The phone is stored in E.164 (+254...); a Kenyan number may be given as 07... or 01...

  • opening_balance boolean Optional

    RECEIVE only, optional: true when this is stock you held when you started on DawaTrack (opening stock, as an ERP's initial stock entry), so it came from no one on record: no parent_event, no sender. Once per lot, only for a lot you have no events on yet, and within 30 days of your first opening-stock receipt. The trace reads "Opening stock, declared by <you> on <date>".

    Default: False

  • recipient object Optional

    SHIP only, optional: the buyer of stock you sent outside DawaTrack, so a recall can reach it. Not with destination_schema_name or destination_supplier_ppb_license_number; not for a party on DawaTrack, which you name by those instead.

    • name string Required
    • ppb_licence string Optional
    • email string Optional

      How a recall reaches this party: kept on its party record, off the ledger, and only used to send it recall notices. An email and a phone are both required; the email is what a recall notice is sent to now. The phone is stored in E.164 (+254...); a Kenyan number may be given as 07... or 01...

    • phone string Optional

      How a recall reaches this party: kept on its party record, off the ledger, and only used to send it recall notices. An email and a phone are both required; the email is what a recall notice is sent to now. The phone is stored in E.164 (+254...); a Kenyan number may be given as 07... or 01...

  • consignment object Optional

    SHIP only, optional: the consignment (despatch advice) this shipment is a line of: your number, carrier, waybill, vehicle, driver and expected date. Without it, the SHIP is a one-line consignment DawaTrack numbers. The response's consignment_number names it.

    • number string Optional

      Your own despatch advice number, unique among your consignments (1 to 40 letters, digits, '.', '_', '/' or '-'). SHIP events with the same number are lines of one consignment, to one receiver. Leave it out and DawaTrack numbers a one-line consignment.

    • reference string Optional

      Your order.

    • carrier_name string Optional
    • waybill_number string Optional
    • vehicle_registration string Optional
    • driver_name string Optional
    • driver_phone string Optional
    • expected_delivery_date date or null Optional

Example request

curl -X POST https://api.dawatrack.com/partner-api/v1/events/ \
  -H "Authorization: Bearer $DAWATRACK_TOKEN" \
  -H "Idempotency-Key: $(uuidgen)" \
  -H "Content-Type: application/json" \
  -d '{
    "event_type": "SHIP",
    "gtin": "06164004321562",
    "batch_number": "BTH-2026-041",
    "quantity": 2600,
    "expiry_date": "2028-06-30",
    "manufacture_date": "2026-06-01",
    "destination_schema_name": "pharmacy_a",
    "consignment": {
      "number": "DESADV-0001",
      "carrier_name": "Lake Basin Couriers",
      "waybill_number": "WB-31",
      "expected_delivery_date": "2026-10-03"
    },
    "occurred_at": "2026-10-01T09:00:00Z"
  }'
import uuid
import requests

token = "..."  # from POST /oauth/token/
response = requests.post(
    "https://api.dawatrack.com/partner-api/v1/events/",
    headers={"Authorization": f"Bearer {token}", "Idempotency-Key": str(uuid.uuid4())},
    json={
      "event_type": "SHIP",
      "gtin": "06164004321562",
      "batch_number": "BTH-2026-041",
      "quantity": 2600,
      "expiry_date": "2028-06-30",
      "manufacture_date": "2026-06-01",
      "destination_schema_name": "pharmacy_a",
      "consignment": {
        "number": "DESADV-0001",
        "carrier_name": "Lake Basin Couriers",
        "waybill_number": "WB-31",
        "expected_delivery_date": "2026-10-03"
      },
      "occurred_at": "2026-10-01T09:00:00Z"
    },
)
response.raise_for_status()
print(response.json())
const token = "..."; // from POST /oauth/token/
const response = await fetch("https://api.dawatrack.com/partner-api/v1/events/", {
  method: "POST",
  headers: {
    Authorization: `Bearer ${token}`,
    "Idempotency-Key": crypto.randomUUID(),
    "Content-Type": "application/json",
  },
  body: JSON.stringify({
    "event_type": "SHIP",
    "gtin": "06164004321562",
    "batch_number": "BTH-2026-041",
    "quantity": 2600,
    "expiry_date": "2028-06-30",
    "manufacture_date": "2026-06-01",
    "destination_schema_name": "pharmacy_a",
    "consignment": {
      "number": "DESADV-0001",
      "carrier_name": "Lake Basin Couriers",
      "waybill_number": "WB-31",
      "expected_delivery_date": "2026-10-03"
    },
    "occurred_at": "2026-10-01T09:00:00Z"
  }),
});
console.log(await response.json());

Response fields

  • id integer Read-only

    The record's id.

  • event_type enum

    The kind of event.

    Possible values: COMMISSIONSHIPRECEIVETRANSFERDISPENSEQUARANTINERELEASEAGGREGATEDISAGGREGATERECEIVE_LINKSHIP_ANSWERRECALL_ACKNOWLEDGMENTRECEIPT_ANSWERRETRACT
  • gtin string

    The product's GS1 GTIN, as 14 digits.

  • batch_number string

    The batch or lot number.

  • serial_number string

    The unit's serial number.

  • sscc string

    An 18-digit GS1 Serial Shipping Container Code.

  • quantity integer

    Quantity of units/items involved in this event (for batch-level or aggregated events).

  • expiry_date date or null

    The lot's expiry date (GS1 AI 17). Optional. When the lot (GTIN and batch) is already on DawaTrack it must match the lot's, and a blank one takes the lot's; the first declaration with an expiry creates the lot. A raw_payload.expiry_date is still read for a lot not yet known.

  • manufacture_date date or null

    The lot's manufacture date (GS1 AI 11). Optional, checked against the lot like expiry_date; not in the future, and before the expiry.

  • parent_event integer or null

    Parent event forming the distribution graph (e.g. COMMISSION/RECEIVE -> SHIP/DISPENSE).

  • corrects_event integer or null

    Event being corrected by this immutable record.

  • actor_id string

    User, system, or API actor ID that produced this event.

  • facility_id string

    Facility node ID/schema in the network where the event occurred.

  • idempotency_key string

    Unique key ensuring event write idempotency per reporter. Required for every new event.

  • occurred_at datetime

    Defaults to now if omitted.

  • raw_payload object

    For AGGREGATE events: {'children': [{'gtin', 'serial'}, ...]}.

  • destination_schema_name string

    SHIP only, optional: the DawaTrack facility (its schema_name) receiving this shipment. When that facility receives the same GTIN and batch, its receipt is linked to this event.

  • destination_supplier_ppb_license_number string

    SHIP only, optional, for a partner linked to a supplier account: the PPB licence number of the approved DawaTrack supplier receiving this shipment. It confirms receipt on its Receiving screen. Use this or destination_schema_name, not both.

  • sender object

    RECEIVE only, optional: the sender of stock that came from outside DawaTrack, so there is no SHIP to name as parent_event. The receipt is where the graph picks the lot up. Not with parent_event; not for a sender on DawaTrack, whose SHIP you name instead.

    • name string
    • ppb_licence string
    • gln string
    • email string

      How a recall reaches this party: kept on its party record, off the ledger, and only used to send it recall notices. An email and a phone are both required; the email is what a recall notice is sent to now. The phone is stored in E.164 (+254...); a Kenyan number may be given as 07... or 01...

    • phone string

      How a recall reaches this party: kept on its party record, off the ledger, and only used to send it recall notices. An email and a phone are both required; the email is what a recall notice is sent to now. The phone is stored in E.164 (+254...); a Kenyan number may be given as 07... or 01...

  • opening_balance boolean

    RECEIVE only, optional: true when this is stock you held when you started on DawaTrack (opening stock, as an ERP's initial stock entry), so it came from no one on record: no parent_event, no sender. Once per lot, only for a lot you have no events on yet, and within 30 days of your first opening-stock receipt. The trace reads "Opening stock, declared by <you> on <date>".

    Default: False

  • recipient object

    SHIP only, optional: the buyer of stock you sent outside DawaTrack, so a recall can reach it. Not with destination_schema_name or destination_supplier_ppb_license_number; not for a party on DawaTrack, which you name by those instead.

    • name string
    • ppb_licence string
    • email string

      How a recall reaches this party: kept on its party record, off the ledger, and only used to send it recall notices. An email and a phone are both required; the email is what a recall notice is sent to now. The phone is stored in E.164 (+254...); a Kenyan number may be given as 07... or 01...

    • phone string

      How a recall reaches this party: kept on its party record, off the ledger, and only used to send it recall notices. An email and a phone are both required; the email is what a recall notice is sent to now. The phone is stored in E.164 (+254...); a Kenyan number may be given as 07... or 01...

  • consignment object

    SHIP only, optional: the consignment (despatch advice) this shipment is a line of: your number, carrier, waybill, vehicle, driver and expected date. Without it, the SHIP is a one-line consignment DawaTrack numbers. The response's consignment_number names it.

    • number string

      Your own despatch advice number, unique among your consignments (1 to 40 letters, digits, '.', '_', '/' or '-'). SHIP events with the same number are lines of one consignment, to one receiver. Leave it out and DawaTrack numbers a one-line consignment.

    • reference string

      Your order.

    • carrier_name string
    • waybill_number string
    • vehicle_registration string
    • driver_name string
    • driver_phone string
    • expected_delivery_date date or null
  • consignment_number string Read-only

    The consignment (despatch advice) a SHIP left on: its number, or blank.

  • created_at datetime Read-only

    When the record was created.

  • recall object or null Read-only

    The open recall of this lot, or null. Recalled stock is received, not refused: put it on hold.

    • recall_id integer
    • action enum

      quarantine: hold the stock; don't sell, dispense or ship it, and return it as the recall instructs. caution: a caution-in-use alert; the stock may be used following the instructions.

      Possible values: quarantinecaution
    • classification string
    • reason string
    • instructions string

      What facilities should do.

    • issued_by string
    • issued_at datetime

Example response

JSON
{
  "id": 42,
  "event_type": "SHIP",
  "gtin": "06164004321562",
  "batch_number": "BTH-2026-041",
  "serial_number": "SN-0007731",
  "sscc": "106164004000007317",
  "quantity": 2600,
  "expiry_date": "2026-10-10",
  "manufacture_date": "2026-10-10",
  "parent_event": 1,
  "corrects_event": 1,
  "actor_id": "actor_id",
  "facility_id": "pharmacy_a",
  "idempotency_key": "idempotency_key",
  "occurred_at": "2026-10-10T09:00:00Z",
  "raw_payload": "raw_payload",
  "destination_schema_name": "destination_schema_name",
  "destination_supplier_ppb_license_number": "destination_supplier_ppb_license_number",
  "sender": {
    "name": "name",
    "ppb_licence": "ppb_licence",
    "gln": "gln",
    "email": "email",
    "phone": "phone"
  },
  "opening_balance": false,
  "recipient": {
    "name": "name",
    "ppb_licence": "ppb_licence",
    "email": "email",
    "phone": "phone"
  },
  "consignment": {
    "number": "number",
    "reference": "reference",
    "carrier_name": "carrier_name",
    "waybill_number": "waybill_number",
    "vehicle_registration": "vehicle_registration",
    "driver_name": "driver_name",
    "driver_phone": "driver_phone",
    "expected_delivery_date": "2026-10-10"
  },
  "consignment_number": "consignment_number",
  "created_at": "2026-10-10T09:00:00Z",
  "recall": {
    "recall_id": 42,
    "action": "quarantine",
    "classification": "classification",
    "reason": "CONTAMINATION",
    "instructions": "Quarantine the batch and await collection instructions.",
    "issued_by": "issued_by",
    "issued_at": "2026-10-10T09:00:00Z"
  }
}

Status codes

201Created
400The request is invalid, for example a malformed GTIN or a missing field
401No valid access token
403Your credential lacks the scope, partner type or environment this needs
409Conflict: a request with this Idempotency-Key is in progress, or the record already exists
429Rate limit exceeded

Trace one of your events back to its origin

GET https://api.dawatrack.com/partner-api/v1/events/{id}/upstream/

The chain back from one of your events to where it began (a COMMISSION, or a first SHIP), nearest first.

Scope batches:read Limit 5,000 per day

Start from your own event only: another party's event, or an id that doesn't exist, returns 404.

Events you wrote (or your supplier account wrote) and the shipments you received are shown in full. Every other event on the chain is withheld: its type, when it happened and its place in the chain, with no id, party, quantity or location.

leads_to is the position of the event it leads to. truncated is true when the walk stopped at 20 facility hops. Requires batches:read.

Path parameters

  • id integer Required

Example request

curl -X GET https://api.dawatrack.com/partner-api/v1/events/42/upstream/ \
  -H "Authorization: Bearer $DAWATRACK_TOKEN"
import requests

token = "..."  # from POST /oauth/token/
response = requests.get(
    "https://api.dawatrack.com/partner-api/v1/events/42/upstream/",
    headers={"Authorization": f"Bearer {token}"},
)
response.raise_for_status()
print(response.json())
const token = "..."; // from POST /oauth/token/
const response = await fetch("https://api.dawatrack.com/partner-api/v1/events/42/upstream/", {
  method: "GET",
  headers: {
    Authorization: `Bearer ${token}`,
  },
});
console.log(await response.json());

Response fields

  • event integer
  • truncated boolean

    The walk stopped at the depth limit (20 facility hops).

  • chain array of objects
    • position integer

      0 is the event asked about; the origin is last.

    • hops_back integer

      Facility hops back from the event asked about.

    • leads_to integer or null

      The position of the event this one leads to.

    • event_type string

      The kind of event.

    • occurred_at datetime

      When the event happened.

    • withheld boolean

      Another party's event: only its type and time are shown.

    • id integer

      The record's id.

    • gtin string

      The product's GS1 GTIN, as 14 digits.

    • batch_number string

      The batch or lot number.

    • serial_number string

      The unit's serial number.

    • sscc string

      An 18-digit GS1 Serial Shipping Container Code.

    • quantity integer or null

      The number of units.

    • facility_id string
    • parent_event integer or null
    • yours boolean

      You wrote it (else you received it).

    • disputed boolean

      A delivery a pharmacy recorded that its supplier disputes (SHIP only).

Example response

JSON
{
  "event": 9123,
  "truncated": false,
  "chain": [
    {
      "position": 0,
      "hops_back": 0,
      "leads_to": null,
      "event_type": "SHIP",
      "occurred_at": "2026-10-20T09:15:00Z",
      "withheld": false,
      "id": 9123,
      "gtin": "06164004321562",
      "batch_number": "AMX-2026-041",
      "serial_number": "",
      "sscc": "",
      "quantity": 120,
      "facility_id": "WH-NAIROBI-01",
      "parent_event": 9101,
      "yours": true
    },
    {
      "position": 1,
      "hops_back": 1,
      "leads_to": 0,
      "event_type": "COMMISSION",
      "occurred_at": "2026-10-02T06:00:00Z",
      "withheld": true
    }
  ]
}

Status codes

200OK
401No valid access token
403Your credential lacks the scope, partner type or environment this needs
404Not found, or not visible to your credential
429Rate limit exceeded

Record events in bulk

POST https://api.dawatrack.com/partner-api/v1/events/bulk/

Submit up to 1,000 events in one request. They are processed in the background.

Scope events:write Limit 10 per hour

Returns 202 with a job_id. Each event is validated exactly like POST /events/, and failures are reported per event in the job's errors. An event that names no parent_event where one is needed fails with error_code PARENT_REQUIRED.

Every event must carry its own idempotency_key. The whole batch is refused, with no job created and nothing written, if any event has none (400, with offending_indexes), if two events share one (409, with collisions), or if one was already used by your events (409, with collisions naming the existing_event_id).

Resubmitting the same events with the same keys writes nothing new; events with new keys are a new submission. Events are no longer keyed by the job and their position when they have no key of their own: an integration that relied on that must send a key per event.

The Idempotency-Key header identifies the job: resubmitting with the same header returns the original job.

Request body

JSON. Send Content-Type: application/json.

  • events array of objects Required

    Up to 1,000 events, each with the same fields as Record an event, and each with its own idempotency_key (required).

Example request

curl -X POST https://api.dawatrack.com/partner-api/v1/events/bulk/ \
  -H "Authorization: Bearer $DAWATRACK_TOKEN" \
  -H "Idempotency-Key: $(uuidgen)" \
  -H "Content-Type: application/json" \
  -d '{
    "events": [
      {
        "idempotency_key": "commission-BTH-2026-041-SN-0007731",
        "event_type": "COMMISSION",
        "gtin": "06164004321562",
        "batch_number": "BTH-2026-041",
        "serial_number": "SN-0007731"
      },
      {
        "idempotency_key": "commission-BTH-2026-041-SN-0007732",
        "event_type": "COMMISSION",
        "gtin": "06164004321562",
        "batch_number": "BTH-2026-041",
        "serial_number": "SN-0007732"
      }
    ]
  }'
import uuid
import requests

token = "..."  # from POST /oauth/token/
response = requests.post(
    "https://api.dawatrack.com/partner-api/v1/events/bulk/",
    headers={"Authorization": f"Bearer {token}", "Idempotency-Key": str(uuid.uuid4())},
    json={
      "events": [
        {
          "idempotency_key": "commission-BTH-2026-041-SN-0007731",
          "event_type": "COMMISSION",
          "gtin": "06164004321562",
          "batch_number": "BTH-2026-041",
          "serial_number": "SN-0007731"
        },
        {
          "idempotency_key": "commission-BTH-2026-041-SN-0007732",
          "event_type": "COMMISSION",
          "gtin": "06164004321562",
          "batch_number": "BTH-2026-041",
          "serial_number": "SN-0007732"
        }
      ]
    },
)
response.raise_for_status()
print(response.json())
const token = "..."; // from POST /oauth/token/
const response = await fetch("https://api.dawatrack.com/partner-api/v1/events/bulk/", {
  method: "POST",
  headers: {
    Authorization: `Bearer ${token}`,
    "Idempotency-Key": crypto.randomUUID(),
    "Content-Type": "application/json",
  },
  body: JSON.stringify({
    "events": [
      {
        "idempotency_key": "commission-BTH-2026-041-SN-0007731",
        "event_type": "COMMISSION",
        "gtin": "06164004321562",
        "batch_number": "BTH-2026-041",
        "serial_number": "SN-0007731"
      },
      {
        "idempotency_key": "commission-BTH-2026-041-SN-0007732",
        "event_type": "COMMISSION",
        "gtin": "06164004321562",
        "batch_number": "BTH-2026-041",
        "serial_number": "SN-0007732"
      }
    ]
  }),
});
console.log(await response.json());

Response fields

  • job_id UUID Read-only
  • status enum
    Possible values: PENDINGPROCESSINGCOMPLETEDFAILEDPARTIAL
  • total_events integer

    Events in the job.

  • processed_events integer

    Events processed so far.

  • succeeded_events integer

    Events recorded.

  • failed_events integer

    Events rejected.

  • errors object

    One entry per failed event: index, error_code, error_message and field_errors.

  • created_at datetime Read-only

    When the record was created.

  • started_at datetime or null

    When processing started.

  • completed_at datetime or null

    When processing finished.

Example response

JSON
{
  "job_id": "3f2b8c1e-7a41-4d2b-9a0e-6c5d8b1f2a30",
  "status": "OPEN",
  "total_events": 1,
  "processed_events": 1,
  "succeeded_events": 1,
  "failed_events": 1,
  "errors": "errors",
  "created_at": "2026-10-10T09:00:00Z",
  "started_at": "2026-10-10T09:00:00Z",
  "completed_at": "2026-10-10T09:00:00Z"
}

Status codes

202Accepted: queued for processing
400The request is invalid, for example a malformed GTIN or a missing field
401No valid access token
403Your credential lacks the scope, partner type or environment this needs
409Conflict: a request with this Idempotency-Key is in progress, or the record already exists
413Too many events in one request
429Rate limit exceeded

Fetch a bulk job

GET https://api.dawatrack.com/partner-api/v1/events/bulk/{job_id}/

The status of a bulk submission, with counts and per-event errors.

Scope events:write Limit 5,000 per day

Path parameters

  • job_id UUID Required

Example request

curl -X GET https://api.dawatrack.com/partner-api/v1/events/bulk/3f2b8c1e-7a41-4d2b-9a0e-6c5d8b1f2a30/ \
  -H "Authorization: Bearer $DAWATRACK_TOKEN"
import requests

token = "..."  # from POST /oauth/token/
response = requests.get(
    "https://api.dawatrack.com/partner-api/v1/events/bulk/3f2b8c1e-7a41-4d2b-9a0e-6c5d8b1f2a30/",
    headers={"Authorization": f"Bearer {token}"},
)
response.raise_for_status()
print(response.json())
const token = "..."; // from POST /oauth/token/
const response = await fetch("https://api.dawatrack.com/partner-api/v1/events/bulk/3f2b8c1e-7a41-4d2b-9a0e-6c5d8b1f2a30/", {
  method: "GET",
  headers: {
    Authorization: `Bearer ${token}`,
  },
});
console.log(await response.json());

Response fields

  • job_id UUID Read-only
  • status enum
    Possible values: PENDINGPROCESSINGCOMPLETEDFAILEDPARTIAL
  • total_events integer

    Events in the job.

  • processed_events integer

    Events processed so far.

  • succeeded_events integer

    Events recorded.

  • failed_events integer

    Events rejected.

  • errors object

    One entry per failed event: index, error_code, error_message and field_errors.

  • created_at datetime Read-only

    When the record was created.

  • started_at datetime or null

    When processing started.

  • completed_at datetime or null

    When processing finished.

Example response

JSON
{
  "job_id": "3f2b8c1e-7a41-4d2b-9a0e-6c5d8b1f2a30",
  "status": "OPEN",
  "total_events": 1,
  "processed_events": 1,
  "succeeded_events": 1,
  "failed_events": 1,
  "errors": "errors",
  "created_at": "2026-10-10T09:00:00Z",
  "started_at": "2026-10-10T09:00:00Z",
  "completed_at": "2026-10-10T09:00:00Z"
}

Status codes

200OK
401No valid access token
403Your credential lacks the scope, partner type or environment this needs
404Not found, or not visible to your credential
429Rate limit exceeded

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