Skip to main content

Recalls

Open, follow, acknowledge and report on recalls.

List recalls

GET https://api.dawatrack.com/partner-api/v1/recalls/

Recalls you opened as a manufacturer, or that affect a facility you're linked to.

Scope recalls:read Limit 5,000 per day

Query parameters

  • ordering string Optional

    Which field to use when ordering the results.

  • page integer Optional

    A page number within the paginated result set.

  • page_size integer Optional

    Number of results to return per page.

  • search string Optional

    A search term.

Example request

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

token = "..."  # from POST /oauth/token/
response = requests.get(
    "https://api.dawatrack.com/partner-api/v1/recalls/",
    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/recalls/", {
  method: "GET",
  headers: {
    Authorization: `Bearer ${token}`,
  },
});
console.log(await response.json());

Response fields

A page of results. These are the fields of each item in results. See Pagination.

  • id integer Read-only

    The record's id.

  • medicine_name string

    The product's name.

  • gtin string

    The product's GS1 GTIN, as 14 digits.

  • batch_number string

    The batch or lot number.

  • additional_batch_numbers array of strings

    Extra batch numbers this recall also covers, beyond batch_number.

  • sscc string Read-only

    Set when the recall is of one container and what it holds; blank for a batch.

  • all_batch_numbers array of strings Read-only

    batch_number plus additional_batch_numbers, deduped - the full set this recall covers.

  • reason enum
    Possible values: QUALITY_DEFECTCONTAMINATIONMISLABELINGADVERSE_REACTIONREGULATORY_WITHDRAWALOTHER
  • reason_display string Read-only

    The recall reason, in words.

  • severity_class enum
    Possible values: CLASS_ICLASS_IICLASS_IIICAUTION_IN_USE
  • severity_class_display string Read-only

    The severity class, in words.

  • trigger_type string

    VOLUNTARY or STATUTORY. Recalls opened through the API are always VOLUNTARY.

  • ppb_reference string

    PPB's reference for the recall, once assigned.

  • instructions string

    What facilities should do.

  • recall_level string

    How far into the supply chain the recall reaches, in PPB's own published wording.

  • geographic_scope string

    Geographic reach PPB publishes on the notice.

  • patient_instructions string

    What patients/caregivers who may have this product should do, if applicable.

  • manufacturer string Read-only

    The marketing authorisation holder or manufacturer, from the product's catalogue record.

  • generic_name string Read-only

    The active ingredient, from the product's catalogue record.

  • local_technical_representative string Read-only

    PPB's registered local technical representative for the recalled product.

  • status string
  • initiated_at datetime

    When the recall was opened.

  • closed_at datetime or null

    When the recall was closed, if it is closed.

  • defect_discovered_at datetime or null

    PPB Guidelines §2.10.3b: when this defect was first discovered.

  • ppb_notification_due_at datetime or null

    PPB Guidelines §2.10.3b: 24h after defect_discovered_at.

  • ppb_notified_at datetime or null Read-only

    When the supplier recorded that PPB was notified. Set in the supplier portal, not through the API.

  • initial_report_due_at datetime or null

    PPB Guidelines §2.13.1a: an initial report is due within 1 week.

  • progress_report_due_at datetime or null
  • reconciliation_due_at datetime or null
  • facilities_acknowledged integer Read-only
  • facilities_total integer Read-only
  • is_drill boolean Read-only
  • drill_facilities_reached integer Read-only
  • drill_facilities_by_hop object Read-only

Example response

JSON
{
  "count": 1,
  "next": null,
  "previous": null,
  "results": [
    {
      "id": 42,
      "medicine_name": "Amoxicillin 500 mg capsules",
      "gtin": "06164004321562",
      "batch_number": "BTH-2026-041",
      "additional_batch_numbers": [],
      "sscc": "106164004000007317",
      "all_batch_numbers": [
        "BTH-2026-041"
      ],
      "reason": "CONTAMINATION",
      "reason_display": "Contamination",
      "severity_class": "CLASS_II",
      "severity_class_display": "Class II",
      "trigger_type": "VOLUNTARY",
      "ppb_reference": "",
      "instructions": "Quarantine the batch and await collection instructions.",
      "recall_level": "Retail level",
      "geographic_scope": "Kenya",
      "patient_instructions": "",
      "manufacturer": "Example Pharmaceuticals Ltd",
      "generic_name": "Amoxicillin",
      "local_technical_representative": "",
      "status": "OPEN",
      "initiated_at": "2026-10-10T09:00:00Z",
      "closed_at": "2026-10-10T09:00:00Z",
      "defect_discovered_at": "2026-10-10T09:00:00Z",
      "ppb_notification_due_at": "2026-10-10T09:00:00Z",
      "ppb_notified_at": "2026-10-10T09:00:00Z",
      "initial_report_due_at": "2026-10-10T09:00:00Z",
      "progress_report_due_at": "2026-10-10T09:00:00Z",
      "reconciliation_due_at": "2026-10-10T09:00:00Z",
      "facilities_acknowledged": 4,
      "facilities_total": 6,
      "is_drill": true,
      "drill_facilities_reached": 6,
      "drill_facilities_by_hop": {
        "1": 4,
        "2": 2
      }
    }
  ]
}

Status codes

200OK
401No valid access token
403Your credential lacks the scope, partner type or environment this needs
429Rate limit exceeded

Open a recall

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

Open a voluntary recall for a batch you have shipped.

Scope recalls:write Manufacturers only Production credentials only Limit 5,000 per day Limit 20 per day

Every affected facility is notified before the call returns, including facilities that received the batch through wholesale resale. Unless the class is CAUTION_IN_USE, the batch is quarantined at each facility.

Re-notification of facilities that haven't acknowledged follows the severity class. Recalls opened through the API are always VOLUNTARY.

To try this without notifying anyone, use the recall drill.

A batch has one open recall at a time: when one already covers it (the whole batch, or the same sscc), a new one is 409, with that recall's recall_id. Escalate or update it instead. A recall of the whole batch while one of its containers is recalled is allowed.

A manufacturer with no supplier account on DawaTrack names the gtin too, and may recall only a product it is the registered manufacturer of (otherwise 403). It owns the recall, which reaches every facility that received the batch, whoever shipped it, and every supplier that shipped it is told. A batch number with no event of that GTIN on DawaTrack is 404; a recall by sscc is a supplier account's (400). It follows the recall with the same endpoints, and gets its PPB report.

Request body

JSON. Send Content-Type: application/json.

  • batch_number string Optional

    The batch to recall. Optional with sscc: then the batch of what it holds.

  • additional_batch_numbers array of strings Optional

    Extra batch numbers of the same product/defect this recall should also cover. Each must be one your supplier account shipped.

  • sscc string Optional

    Recall one container (GS1 SSCC) and what it holds, through splits and repacks, instead of the whole batch. It must be one your supplier account packed or shipped.

  • reason enum Required

    Why the batch is being recalled.

    Possible values: QUALITY_DEFECTCONTAMINATIONMISLABELINGADVERSE_REACTIONREGULATORY_WITHDRAWALOTHER
  • severity_class enum Required

    The PPB severity class. CAUTION_IN_USE alerts facilities without quarantining the batch.

    Possible values: CLASS_ICLASS_IICLASS_IIICAUTION_IN_USE
  • instructions string Required

    What facilities should do.

  • defect_discovered_at datetime Optional

    PPB Guidelines §2.10.3b: when this defect was first discovered - you must notify PPB within 24h of this. Defaults to now if omitted.

Example request

curl -X POST https://api.dawatrack.com/partner-api/v1/recalls/ \
  -H "Authorization: Bearer $DAWATRACK_TOKEN" \
  -H "Idempotency-Key: $(uuidgen)" \
  -H "Content-Type: application/json" \
  -d '{
    "batch_number": "BTH-2026-041",
    "reason": "CONTAMINATION",
    "severity_class": "CLASS_II",
    "instructions": "Quarantine the batch and await collection instructions."
  }'
import uuid
import requests

token = "..."  # from POST /oauth/token/
response = requests.post(
    "https://api.dawatrack.com/partner-api/v1/recalls/",
    headers={"Authorization": f"Bearer {token}", "Idempotency-Key": str(uuid.uuid4())},
    json={
      "batch_number": "BTH-2026-041",
      "reason": "CONTAMINATION",
      "severity_class": "CLASS_II",
      "instructions": "Quarantine the batch and await collection instructions."
    },
)
response.raise_for_status()
print(response.json())
const token = "..."; // from POST /oauth/token/
const response = await fetch("https://api.dawatrack.com/partner-api/v1/recalls/", {
  method: "POST",
  headers: {
    Authorization: `Bearer ${token}`,
    "Idempotency-Key": crypto.randomUUID(),
    "Content-Type": "application/json",
  },
  body: JSON.stringify({
    "batch_number": "BTH-2026-041",
    "reason": "CONTAMINATION",
    "severity_class": "CLASS_II",
    "instructions": "Quarantine the batch and await collection instructions."
  }),
});
console.log(await response.json());

Response fields

  • id integer Read-only

    The record's id.

  • medicine_name string

    The product's name.

  • gtin string

    The product's GS1 GTIN, as 14 digits.

  • batch_number string

    The batch or lot number.

  • additional_batch_numbers array of strings

    Extra batch numbers this recall also covers, beyond batch_number.

  • sscc string Read-only

    Set when the recall is of one container and what it holds; blank for a batch.

  • all_batch_numbers array of strings Read-only

    batch_number plus additional_batch_numbers, deduped - the full set this recall covers.

  • reason enum
    Possible values: QUALITY_DEFECTCONTAMINATIONMISLABELINGADVERSE_REACTIONREGULATORY_WITHDRAWALOTHER
  • reason_display string Read-only

    The recall reason, in words.

  • severity_class enum
    Possible values: CLASS_ICLASS_IICLASS_IIICAUTION_IN_USE
  • severity_class_display string Read-only

    The severity class, in words.

  • trigger_type string

    VOLUNTARY or STATUTORY. Recalls opened through the API are always VOLUNTARY.

  • ppb_reference string

    PPB's reference for the recall, once assigned.

  • instructions string

    What facilities should do.

  • recall_level string

    How far into the supply chain the recall reaches, in PPB's own published wording.

  • geographic_scope string

    Geographic reach PPB publishes on the notice.

  • patient_instructions string

    What patients/caregivers who may have this product should do, if applicable.

  • manufacturer string Read-only

    The marketing authorisation holder or manufacturer, from the product's catalogue record.

  • generic_name string Read-only

    The active ingredient, from the product's catalogue record.

  • local_technical_representative string Read-only

    PPB's registered local technical representative for the recalled product.

  • status string
  • initiated_at datetime

    When the recall was opened.

  • closed_at datetime or null

    When the recall was closed, if it is closed.

  • defect_discovered_at datetime or null

    PPB Guidelines §2.10.3b: when this defect was first discovered.

  • ppb_notification_due_at datetime or null

    PPB Guidelines §2.10.3b: 24h after defect_discovered_at.

  • ppb_notified_at datetime or null Read-only

    When the supplier recorded that PPB was notified. Set in the supplier portal, not through the API.

  • initial_report_due_at datetime or null

    PPB Guidelines §2.13.1a: an initial report is due within 1 week.

  • progress_report_due_at datetime or null
  • reconciliation_due_at datetime or null
  • facilities_acknowledged integer Read-only
  • facilities_total integer Read-only
  • is_drill boolean Read-only
  • drill_facilities_reached integer Read-only
  • drill_facilities_by_hop object Read-only

Example response

JSON
{
  "id": 42,
  "medicine_name": "Amoxicillin 500 mg capsules",
  "gtin": "06164004321562",
  "batch_number": "BTH-2026-041",
  "additional_batch_numbers": [],
  "sscc": "106164004000007317",
  "all_batch_numbers": [
    "BTH-2026-041"
  ],
  "reason": "CONTAMINATION",
  "reason_display": "Contamination",
  "severity_class": "CLASS_II",
  "severity_class_display": "Class II",
  "trigger_type": "VOLUNTARY",
  "ppb_reference": "",
  "instructions": "Quarantine the batch and await collection instructions.",
  "recall_level": "Retail level",
  "geographic_scope": "Kenya",
  "patient_instructions": "",
  "manufacturer": "Example Pharmaceuticals Ltd",
  "generic_name": "Amoxicillin",
  "local_technical_representative": "",
  "status": "OPEN",
  "initiated_at": "2026-10-10T09:00:00Z",
  "closed_at": "2026-10-10T09:00:00Z",
  "defect_discovered_at": "2026-10-10T09:00:00Z",
  "ppb_notification_due_at": "2026-10-10T09:00:00Z",
  "ppb_notified_at": "2026-10-10T09:00:00Z",
  "initial_report_due_at": "2026-10-10T09:00:00Z",
  "progress_report_due_at": "2026-10-10T09:00:00Z",
  "reconciliation_due_at": "2026-10-10T09:00:00Z",
  "facilities_acknowledged": 4,
  "facilities_total": 6,
  "is_drill": true,
  "drill_facilities_reached": 6,
  "drill_facilities_by_hop": {
    "1": 4,
    "2": 2
  }
}

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
404Not found, or not visible to your credential
409Conflict: a request with this Idempotency-Key is in progress, or the record already exists
429Rate limit exceeded

Run a recall drill

POST https://api.dawatrack.com/partner-api/v1/recalls/drill/

Rehearse a recall without notifying anyone, for PPB's annual recall-system challenge.

Scope recalls:write Manufacturers only Limit 5,000 per day

Takes the same body as opening a recall. It counts how many facilities a real recall would reach (drill_facilities_reached, by hop in drill_facilities_by_hop) but sends nothing and quarantines nothing.

The returned record has is_drill: true and is your audit evidence. Drills never appear in the public recall lookup.

Request body

JSON. Send Content-Type: application/json.

  • batch_number string Optional

    The batch to recall. Optional with sscc: then the batch of what it holds.

  • additional_batch_numbers array of strings Optional

    Extra batch numbers of the same product/defect this recall should also cover. Each must be one your supplier account shipped.

  • sscc string Optional

    Recall one container (GS1 SSCC) and what it holds, through splits and repacks, instead of the whole batch. It must be one your supplier account packed or shipped.

  • reason enum Required

    Why the batch is being recalled.

    Possible values: QUALITY_DEFECTCONTAMINATIONMISLABELINGADVERSE_REACTIONREGULATORY_WITHDRAWALOTHER
  • severity_class enum Required

    The PPB severity class. CAUTION_IN_USE alerts facilities without quarantining the batch.

    Possible values: CLASS_ICLASS_IICLASS_IIICAUTION_IN_USE
  • instructions string Required

    What facilities should do.

  • defect_discovered_at datetime Optional

    PPB Guidelines §2.10.3b: when this defect was first discovered - you must notify PPB within 24h of this. Defaults to now if omitted.

Example request

curl -X POST https://api.dawatrack.com/partner-api/v1/recalls/drill/ \
  -H "Authorization: Bearer $DAWATRACK_TOKEN" \
  -H "Idempotency-Key: $(uuidgen)" \
  -H "Content-Type: application/json" \
  -d '{
    "batch_number": "BTH-2026-041",
    "reason": "CONTAMINATION",
    "severity_class": "CLASS_II",
    "instructions": "DRILL - no action required."
  }'
import uuid
import requests

token = "..."  # from POST /oauth/token/
response = requests.post(
    "https://api.dawatrack.com/partner-api/v1/recalls/drill/",
    headers={"Authorization": f"Bearer {token}", "Idempotency-Key": str(uuid.uuid4())},
    json={
      "batch_number": "BTH-2026-041",
      "reason": "CONTAMINATION",
      "severity_class": "CLASS_II",
      "instructions": "DRILL - no action required."
    },
)
response.raise_for_status()
print(response.json())
const token = "..."; // from POST /oauth/token/
const response = await fetch("https://api.dawatrack.com/partner-api/v1/recalls/drill/", {
  method: "POST",
  headers: {
    Authorization: `Bearer ${token}`,
    "Idempotency-Key": crypto.randomUUID(),
    "Content-Type": "application/json",
  },
  body: JSON.stringify({
    "batch_number": "BTH-2026-041",
    "reason": "CONTAMINATION",
    "severity_class": "CLASS_II",
    "instructions": "DRILL - no action required."
  }),
});
console.log(await response.json());

Response fields

  • id integer Read-only

    The record's id.

  • medicine_name string

    The product's name.

  • gtin string

    The product's GS1 GTIN, as 14 digits.

  • batch_number string

    The batch or lot number.

  • additional_batch_numbers array of strings

    Extra batch numbers this recall also covers, beyond batch_number.

  • sscc string Read-only

    Set when the recall is of one container and what it holds; blank for a batch.

  • all_batch_numbers array of strings Read-only

    batch_number plus additional_batch_numbers, deduped - the full set this recall covers.

  • reason enum
    Possible values: QUALITY_DEFECTCONTAMINATIONMISLABELINGADVERSE_REACTIONREGULATORY_WITHDRAWALOTHER
  • reason_display string Read-only

    The recall reason, in words.

  • severity_class enum
    Possible values: CLASS_ICLASS_IICLASS_IIICAUTION_IN_USE
  • severity_class_display string Read-only

    The severity class, in words.

  • trigger_type string

    VOLUNTARY or STATUTORY. Recalls opened through the API are always VOLUNTARY.

  • ppb_reference string

    PPB's reference for the recall, once assigned.

  • instructions string

    What facilities should do.

  • recall_level string

    How far into the supply chain the recall reaches, in PPB's own published wording.

  • geographic_scope string

    Geographic reach PPB publishes on the notice.

  • patient_instructions string

    What patients/caregivers who may have this product should do, if applicable.

  • manufacturer string Read-only

    The marketing authorisation holder or manufacturer, from the product's catalogue record.

  • generic_name string Read-only

    The active ingredient, from the product's catalogue record.

  • local_technical_representative string Read-only

    PPB's registered local technical representative for the recalled product.

  • status string
  • initiated_at datetime

    When the recall was opened.

  • closed_at datetime or null

    When the recall was closed, if it is closed.

  • defect_discovered_at datetime or null

    PPB Guidelines §2.10.3b: when this defect was first discovered.

  • ppb_notification_due_at datetime or null

    PPB Guidelines §2.10.3b: 24h after defect_discovered_at.

  • ppb_notified_at datetime or null Read-only

    When the supplier recorded that PPB was notified. Set in the supplier portal, not through the API.

  • initial_report_due_at datetime or null

    PPB Guidelines §2.13.1a: an initial report is due within 1 week.

  • progress_report_due_at datetime or null
  • reconciliation_due_at datetime or null
  • facilities_acknowledged integer Read-only
  • facilities_total integer Read-only
  • is_drill boolean Read-only
  • drill_facilities_reached integer Read-only
  • drill_facilities_by_hop object Read-only

Example response

JSON
{
  "id": 42,
  "medicine_name": "Amoxicillin 500 mg capsules",
  "gtin": "06164004321562",
  "batch_number": "BTH-2026-041",
  "additional_batch_numbers": [],
  "sscc": "106164004000007317",
  "all_batch_numbers": [
    "BTH-2026-041"
  ],
  "reason": "CONTAMINATION",
  "reason_display": "Contamination",
  "severity_class": "CLASS_II",
  "severity_class_display": "Class II",
  "trigger_type": "VOLUNTARY",
  "ppb_reference": "",
  "instructions": "Quarantine the batch and await collection instructions.",
  "recall_level": "Retail level",
  "geographic_scope": "Kenya",
  "patient_instructions": "",
  "manufacturer": "Example Pharmaceuticals Ltd",
  "generic_name": "Amoxicillin",
  "local_technical_representative": "",
  "status": "OPEN",
  "initiated_at": "2026-10-10T09:00:00Z",
  "closed_at": "2026-10-10T09:00:00Z",
  "defect_discovered_at": "2026-10-10T09:00:00Z",
  "ppb_notification_due_at": "2026-10-10T09:00:00Z",
  "ppb_notified_at": "2026-10-10T09:00:00Z",
  "initial_report_due_at": "2026-10-10T09:00:00Z",
  "progress_report_due_at": "2026-10-10T09:00:00Z",
  "reconciliation_due_at": "2026-10-10T09:00:00Z",
  "facilities_acknowledged": 4,
  "facilities_total": 6,
  "is_drill": true,
  "drill_facilities_reached": 6,
  "drill_facilities_by_hop": {
    "1": 4,
    "2": 2
  }
}

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
404Not found, or not visible to your credential
409Conflict: a request with this Idempotency-Key is in progress, or the record already exists
429Rate limit exceeded

Fetch a recall

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

One recall in full: its PPB deadlines, acknowledgement progress and product details.

Scope recalls:read Limit 5,000 per day

Path parameters

  • id integer Required

Example request

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

token = "..."  # from POST /oauth/token/
response = requests.get(
    "https://api.dawatrack.com/partner-api/v1/recalls/42/",
    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/recalls/42/", {
  method: "GET",
  headers: {
    Authorization: `Bearer ${token}`,
  },
});
console.log(await response.json());

Response fields

  • id integer Read-only

    The record's id.

  • medicine_name string

    The product's name.

  • gtin string

    The product's GS1 GTIN, as 14 digits.

  • batch_number string

    The batch or lot number.

  • additional_batch_numbers array of strings

    Extra batch numbers this recall also covers, beyond batch_number.

  • sscc string Read-only

    Set when the recall is of one container and what it holds; blank for a batch.

  • all_batch_numbers array of strings Read-only

    batch_number plus additional_batch_numbers, deduped - the full set this recall covers.

  • reason enum
    Possible values: QUALITY_DEFECTCONTAMINATIONMISLABELINGADVERSE_REACTIONREGULATORY_WITHDRAWALOTHER
  • reason_display string Read-only

    The recall reason, in words.

  • severity_class enum
    Possible values: CLASS_ICLASS_IICLASS_IIICAUTION_IN_USE
  • severity_class_display string Read-only

    The severity class, in words.

  • trigger_type string

    VOLUNTARY or STATUTORY. Recalls opened through the API are always VOLUNTARY.

  • ppb_reference string

    PPB's reference for the recall, once assigned.

  • instructions string

    What facilities should do.

  • recall_level string

    How far into the supply chain the recall reaches, in PPB's own published wording.

  • geographic_scope string

    Geographic reach PPB publishes on the notice.

  • patient_instructions string

    What patients/caregivers who may have this product should do, if applicable.

  • manufacturer string Read-only

    The marketing authorisation holder or manufacturer, from the product's catalogue record.

  • generic_name string Read-only

    The active ingredient, from the product's catalogue record.

  • local_technical_representative string Read-only

    PPB's registered local technical representative for the recalled product.

  • status string
  • initiated_at datetime

    When the recall was opened.

  • closed_at datetime or null

    When the recall was closed, if it is closed.

  • defect_discovered_at datetime or null

    PPB Guidelines §2.10.3b: when this defect was first discovered.

  • ppb_notification_due_at datetime or null

    PPB Guidelines §2.10.3b: 24h after defect_discovered_at.

  • ppb_notified_at datetime or null Read-only

    When the supplier recorded that PPB was notified. Set in the supplier portal, not through the API.

  • initial_report_due_at datetime or null

    PPB Guidelines §2.13.1a: an initial report is due within 1 week.

  • progress_report_due_at datetime or null
  • reconciliation_due_at datetime or null
  • facilities_acknowledged integer Read-only
  • facilities_total integer Read-only
  • is_drill boolean Read-only
  • drill_facilities_reached integer Read-only
  • drill_facilities_by_hop object Read-only

Example response

JSON
{
  "id": 42,
  "medicine_name": "Amoxicillin 500 mg capsules",
  "gtin": "06164004321562",
  "batch_number": "BTH-2026-041",
  "additional_batch_numbers": [],
  "sscc": "106164004000007317",
  "all_batch_numbers": [
    "BTH-2026-041"
  ],
  "reason": "CONTAMINATION",
  "reason_display": "Contamination",
  "severity_class": "CLASS_II",
  "severity_class_display": "Class II",
  "trigger_type": "VOLUNTARY",
  "ppb_reference": "",
  "instructions": "Quarantine the batch and await collection instructions.",
  "recall_level": "Retail level",
  "geographic_scope": "Kenya",
  "patient_instructions": "",
  "manufacturer": "Example Pharmaceuticals Ltd",
  "generic_name": "Amoxicillin",
  "local_technical_representative": "",
  "status": "OPEN",
  "initiated_at": "2026-10-10T09:00:00Z",
  "closed_at": "2026-10-10T09:00:00Z",
  "defect_discovered_at": "2026-10-10T09:00:00Z",
  "ppb_notification_due_at": "2026-10-10T09:00:00Z",
  "ppb_notified_at": "2026-10-10T09:00:00Z",
  "initial_report_due_at": "2026-10-10T09:00:00Z",
  "progress_report_due_at": "2026-10-10T09:00:00Z",
  "reconciliation_due_at": "2026-10-10T09:00:00Z",
  "facilities_acknowledged": 4,
  "facilities_total": 6,
  "is_drill": true,
  "drill_facilities_reached": 6,
  "drill_facilities_by_hop": {
    "1": 4,
    "2": 2
  }
}

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

Get a recall's distribution tree

GET https://api.dawatrack.com/partner-api/v1/recalls/{id}/tree/

Every facility the recall reached, nested under whoever resold to whom.

Scope recalls:read Limit 5,000 per day

A manufacturer gets the whole tree. A distributor or pharmacy gets one root per linked facility, with only that facility's downstream reach.

Path parameters

  • id integer Required

Example request

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

token = "..."  # from POST /oauth/token/
response = requests.get(
    "https://api.dawatrack.com/partner-api/v1/recalls/42/tree/",
    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/recalls/42/tree/", {
  method: "GET",
  headers: {
    Authorization: `Bearer ${token}`,
  },
});
console.log(await response.json());

Response fields

  • notice object

    This facility's entry.

    • id integer Read-only

      The record's id.

    • hop_depth integer Read-only

      1 for a direct delivery, 2 or more for each wholesale hop further on.

    • pharmacy_name string

      The facility's name.

    • branch_name string

      The facility branch.

    • schema_name string

      The facility's identifier on DawaTrack.

    • quantity_on_hand_at_recall integer Read-only
    • quarantined_at datetime or null

      When the batch was quarantined at this facility.

    • acknowledged_at datetime or null

      When the facility acknowledged the recall, if it has.

    • acknowledged_by_name string

      Who acknowledged it.

    • is_overdue boolean Read-only

      Whether acknowledgement is past its deadline.

    • in_transit boolean Read-only

      Stock dispatched to this facility that it hasn't received yet (no lot yet).

    • pending boolean Read-only

      Reached since the recall's last fan-out: its notice goes out within 15 minutes (id is null).

      Default: False

  • children array of objects Read-only

    The facilities it passed the batch on to, in the same shape.

Example response

JSON
[
  {
    "notice": {
      "id": 501,
      "hop_depth": 1,
      "pharmacy_name": "Pharmacy C",
      "branch_name": "Main branch",
      "schema_name": "pharmacy_c",
      "quantity_on_hand_at_recall": 400,
      "quarantined_at": "2026-10-05T13:19:57Z",
      "acknowledged_at": null,
      "acknowledged_by_name": "",
      "is_overdue": false
    },
    "children": []
  }
]

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

List affected facilities

GET https://api.dawatrack.com/partner-api/v1/recalls/{id}/affected/

The facilities a recall affects, with quantities, SSCCs and units, plus a summary across all of them.

Scope recalls:read Limit 5,000 per day

The response adds a summary object: total_facilities, total_ssccs, total_units, total_quantity_affected and total_quantity_recovered. It always covers every facility you can see, even when filtered.

Path parameters

  • id integer Required

Query parameters

  • page integer Optional

    A page number within the paginated result set.

  • page_size integer Optional

    Number of results to return per page.

  • schema_name string Optional

    Only this facility schema.

Example request

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

token = "..."  # from POST /oauth/token/
response = requests.get(
    "https://api.dawatrack.com/partner-api/v1/recalls/42/affected/",
    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/recalls/42/affected/", {
  method: "GET",
  headers: {
    Authorization: `Bearer ${token}`,
  },
});
console.log(await response.json());

Response fields

A page of results. These are the fields of each item in results. See Pagination.

  • facility_schema string

    The facility's identifier on DawaTrack.

  • facility_name string

    The facility's name.

  • facility_license_number string
  • facility_type string
  • facility_county string
  • quantity_affected integer
  • quantity_recovered integer
  • acknowledged_at datetime or null

    When the facility acknowledged the recall, if it has.

  • ssccs array of strings
  • units array of objects

Example response

JSON
{
  "count": 1,
  "next": null,
  "previous": null,
  "results": [
    {
      "facility_schema": "pharmacy_a",
      "facility_name": "Pharmacy A",
      "facility_license_number": "PPB/R/2026/0001",
      "facility_type": "RETAIL",
      "facility_county": "Nairobi",
      "quantity_affected": 1284,
      "quantity_recovered": 1284,
      "acknowledged_at": "2026-10-10T09:00:00Z",
      "ssccs": [
        "string"
      ],
      "units": [
        {}
      ]
    }
  ]
}

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

List affected units at a facility

GET https://api.dawatrack.com/partner-api/v1/recalls/{id}/affected/{facility_schema}/units/

The serialized units of the recalled batches held at one facility.

Scope recalls:read Limit 5,000 per day

Returns 404 if you can't see that facility on this recall.

Path parameters

  • facility_schema string Required
  • id integer Required

Query parameters

  • ordering string Optional

    Which field to use when ordering the results.

  • page integer Optional

    A page number within the paginated result set.

  • page_size integer Optional

    Number of results to return per page.

  • search string Optional

    A search term.

Example request

curl -X GET https://api.dawatrack.com/partner-api/v1/recalls/42/affected/pharmacy_a/units/ \
  -H "Authorization: Bearer $DAWATRACK_TOKEN"
import requests

token = "..."  # from POST /oauth/token/
response = requests.get(
    "https://api.dawatrack.com/partner-api/v1/recalls/42/affected/pharmacy_a/units/",
    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/recalls/42/affected/pharmacy_a/units/", {
  method: "GET",
  headers: {
    Authorization: `Bearer ${token}`,
  },
});
console.log(await response.json());

Response fields

A page of results. These are the fields of each item in results. See Pagination.

  • gtin string

    The product's GS1 GTIN, as 14 digits.

  • serial_number string

    The unit's serial number.

  • batch_number string

    The batch or lot number.

  • current_sscc string or null Read-only

    The SSCC the unit is currently packed in, if any.

  • current_status string

    The type of the unit's latest event.

  • facility_schema string

    The facility's identifier on DawaTrack.

  • last_event_at datetime

    When the unit's latest event happened.

Example response

JSON
{
  "count": 1,
  "next": null,
  "previous": null,
  "results": [
    {
      "gtin": "06164004321562",
      "serial_number": "SN-0007731",
      "batch_number": "BTH-2026-041",
      "current_sscc": "106164004000007317",
      "current_status": "SHIP",
      "facility_schema": "pharmacy_a",
      "last_event_at": "2026-10-10T09:00:00Z"
    }
  ]
}

Status codes

200OK
401No valid access token
403Your credential lacks the scope, partner type or environment this needs
429Rate limit exceeded

Acknowledge a recall

POST https://api.dawatrack.com/partner-api/v1/recalls/{id}/acknowledge/

Confirm receipt of a recall notice for a facility you're linked to.

Scope recalls:acknowledge Limit 5,000 per day

schema_name can be left out if your credential is linked to exactly one facility.

Path parameters

  • id integer Required

Request body

JSON. Send Content-Type: application/json.

  • schema_name string Optional

    Required unless this partner is linked to exactly one facility.

  • notes string Optional

Example request

curl -X POST https://api.dawatrack.com/partner-api/v1/recalls/42/acknowledge/ \
  -H "Authorization: Bearer $DAWATRACK_TOKEN" \
  -H "Idempotency-Key: $(uuidgen)" \
  -H "Content-Type: application/json" \
  -d '{
    "schema_name": "pharmacy_a",
    "notes": "Stock pulled from the shelf."
  }'
import uuid
import requests

token = "..."  # from POST /oauth/token/
response = requests.post(
    "https://api.dawatrack.com/partner-api/v1/recalls/42/acknowledge/",
    headers={"Authorization": f"Bearer {token}", "Idempotency-Key": str(uuid.uuid4())},
    json={
      "schema_name": "pharmacy_a",
      "notes": "Stock pulled from the shelf."
    },
)
response.raise_for_status()
print(response.json())
const token = "..."; // from POST /oauth/token/
const response = await fetch("https://api.dawatrack.com/partner-api/v1/recalls/42/acknowledge/", {
  method: "POST",
  headers: {
    Authorization: `Bearer ${token}`,
    "Idempotency-Key": crypto.randomUUID(),
    "Content-Type": "application/json",
  },
  body: JSON.stringify({
    "schema_name": "pharmacy_a",
    "notes": "Stock pulled from the shelf."
  }),
});
console.log(await response.json());

Response fields

  • id integer Read-only

    The record's id.

  • hop_depth integer Read-only

    1 for a direct delivery, 2 or more for each wholesale hop further on.

  • pharmacy_name string

    The facility's name.

  • branch_name string

    The facility branch.

  • schema_name string

    The facility's identifier on DawaTrack.

  • quantity_on_hand_at_recall integer Read-only
  • quarantined_at datetime or null

    When the batch was quarantined at this facility.

  • acknowledged_at datetime or null

    When the facility acknowledged the recall, if it has.

  • acknowledged_by_name string

    Who acknowledged it.

  • is_overdue boolean Read-only

    Whether acknowledgement is past its deadline.

  • in_transit boolean Read-only

    Stock dispatched to this facility that it hasn't received yet (no lot yet).

  • pending boolean Read-only

    Reached since the recall's last fan-out: its notice goes out within 15 minutes (id is null).

    Default: False

Example response

JSON
{
  "id": 42,
  "hop_depth": 1,
  "pharmacy_name": "Pharmacy A",
  "branch_name": "Main branch",
  "schema_name": "pharmacy_a",
  "quantity_on_hand_at_recall": 1284,
  "quarantined_at": "2026-10-10T09:00:00Z",
  "acknowledged_at": "2026-10-10T09:00:00Z",
  "acknowledged_by_name": "acknowledged_by_name",
  "is_overdue": true,
  "in_transit": false,
  "pending": false
}

Status codes

200OK
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
404Not found, or not visible to your credential
409Conflict: a request with this Idempotency-Key is in progress, or the record already exists
429Rate limit exceeded

Get a recall report

GET https://api.dawatrack.com/partner-api/v1/recalls/{id}/report/

One of the three reports PPB requires per recall: initial, follow-up and final.

Scope recalls:read Manufacturers only Limit 5,000 per day

Choose the report with ?stage=initial, follow_up or final. It reports acknowledgements and quantity-on-hand snapshots only. It doesn't estimate returned or destroyed quantities that weren't recorded.

facilities_* count pharmacies on DawaTrack. outside_parties lists the parties outside DawaTrack the recall reaches: each one's status (notified, not-acknowledged after 24 hours with a second notice, acknowledged, unreachable, phone-only, no-contact), when it was notified, its answer (quantity_held, action) and who it received the lot from. Never its email or phone.

Path parameters

  • id integer Required

Query parameters

  • stage enum Required

    Which report to generate.

    Possible values: initialfollow_upfinal

Example request

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

token = "..."  # from POST /oauth/token/
response = requests.get(
    "https://api.dawatrack.com/partner-api/v1/recalls/42/report/",
    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/recalls/42/report/", {
  method: "GET",
  headers: {
    Authorization: `Bearer ${token}`,
  },
});
console.log(await response.json());

Response fields

  • recall_id integer
  • stage string
  • generated_at datetime
  • batch_number string

    The batch or lot number.

  • medicine_name string

    The product's name.

  • trigger_type string

    VOLUNTARY or STATUTORY. Recalls opened through the API are always VOLUNTARY.

  • severity_class string
  • status string
  • ppb_reference string

    PPB's reference for the recall, once assigned.

  • initiated_at datetime

    When the recall was opened.

  • due_at datetime or null

    This stage's deadline: the initial, progress or reconciliation report due date.

  • filed_at datetime or null

    This stage's filed timestamp, if filed.

  • initial_report_due_at datetime or null
  • progress_report_due_at datetime or null
  • reconciliation_due_at datetime or null
  • facilities_total integer
  • facilities_acknowledged integer
  • facilities_pending integer
  • percentage_acknowledged number
  • total_units_on_hand_at_recall integer
  • unrecorded_sources integer

    Units of the recalled lots that a facility sent on from a receipt DawaTrack didn't see (stock bought outside the platform): the {"event": null} entries of the shipments' sources. The shipments are recorded; the graph can't trace these units back to a delivery.

  • notices array of objects
    • id integer Read-only

      The record's id.

    • hop_depth integer Read-only

      1 for a direct delivery, 2 or more for each wholesale hop further on.

    • pharmacy_name string

      The facility's name.

    • branch_name string

      The facility branch.

    • schema_name string

      The facility's identifier on DawaTrack.

    • quantity_on_hand_at_recall integer Read-only
    • quarantined_at datetime or null

      When the batch was quarantined at this facility.

    • acknowledged_at datetime or null

      When the facility acknowledged the recall, if it has.

    • acknowledged_by_name string

      Who acknowledged it.

    • is_overdue boolean Read-only

      Whether acknowledgement is past its deadline.

    • in_transit boolean Read-only

      Stock dispatched to this facility that it hasn't received yet (no lot yet).

    • pending boolean Read-only

      Reached since the recall's last fan-out: its notice goes out within 15 minutes (id is null).

      Default: False

  • outside_parties array of objects

    Parties outside DawaTrack the recall reaches (they have no recall console): each notice and answer. The facilities_* figures count DawaTrack facilities only.

    • party_id integer or null

      Its record on GET /parties/, when it has one.

    • name string
    • identifier string

      ppb:<licence>, gln:<GLN> or name:<name>.

    • status enum

      acknowledged; unreachable (the recalling firm marked it so); not-acknowledged (notified, no answer 24 hours on: a second notice was sent); notified; failed (the mail server refused the notice); queued; phone-only; no-contact.

      Possible values: acknowledgedunreachablenot-acknowledgednotifiedfailedqueuedphone-onlyno-contact
    • reachable boolean

      An email on file a notice can go to.

    • notified_at datetime or null
    • second_notice_at datetime or null

      The automatic notice 24 hours on.

    • reminders integer

      Reminders the recalling firm sent by hand.

    • acknowledged_at datetime or null

      When the facility acknowledged the recall, if it has.

    • quantity_held integer or null

      Units it said it holds, when it answered.

    • action string

      What it said it did with the stock.

    • unreachable_note string

      How the firm tried, when unreachable.

    • received_from array of strings

      Who it received the lot from, by name (incl. a declaring party).

    • supplied_to array of strings

      Who received the lot from it.

  • outside_parties_acknowledged integer

Example response

JSON
{
  "recall_id": 42,
  "stage": "initial",
  "generated_at": "2026-10-10T09:00:00Z",
  "batch_number": "BTH-2026-041",
  "medicine_name": "Amoxicillin 500 mg capsules",
  "trigger_type": "VOLUNTARY",
  "severity_class": "CLASS_II",
  "status": "OPEN",
  "ppb_reference": "",
  "initiated_at": "2026-10-10T09:00:00Z",
  "due_at": "2026-10-10T09:00:00Z",
  "filed_at": "2026-10-10T09:00:00Z",
  "initial_report_due_at": "2026-10-10T09:00:00Z",
  "progress_report_due_at": "2026-10-10T09:00:00Z",
  "reconciliation_due_at": "2026-10-10T09:00:00Z",
  "facilities_total": 6,
  "facilities_acknowledged": 4,
  "facilities_pending": 2,
  "percentage_acknowledged": 66.7,
  "total_units_on_hand_at_recall": 7354,
  "unrecorded_sources": 120,
  "notices": [
    {
      "id": 42,
      "hop_depth": 1,
      "pharmacy_name": "Pharmacy A",
      "branch_name": "Main branch",
      "schema_name": "pharmacy_a",
      "quantity_on_hand_at_recall": 1284,
      "quarantined_at": "2026-10-10T09:00:00Z",
      "acknowledged_at": "2026-10-10T09:00:00Z",
      "acknowledged_by_name": "acknowledged_by_name",
      "is_overdue": true,
      "in_transit": false,
      "pending": false
    }
  ],
  "outside_parties": [
    {
      "party_id": 1,
      "name": "name",
      "identifier": "identifier",
      "status": "OPEN",
      "reachable": false,
      "notified_at": "2026-10-10T09:00:00Z",
      "second_notice_at": "2026-10-10T09:00:00Z",
      "reminders": 1,
      "acknowledged_at": "2026-10-10T09:00:00Z",
      "quantity_held": 1,
      "action": "action",
      "unreachable_note": "unreachable_note",
      "received_from": [
        "string"
      ],
      "supplied_to": [
        "string"
      ]
    }
  ],
  "outside_parties_acknowledged": 1
}

Status codes

200OK
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
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.