Pre-Alerts API β
Pre-alerts are the way retailers and marketplaces notify LogirAI of inbound shipments before they arrive at destination. One pre-alert = one Master Air Waybill (MAWB) = many House Air Waybills (HAWBs / guides).
The Pre-Alerts API is the integration surface for client systems. The multipart upload route is onboarded for Chile today; Peru/Argentina Excel parsers are added per client format (a non-CL destination without an onboarded parser β 400 no_parser_for_format). For multi-country ingestion now, use the canonical-JSON endpoint process-pre-alert-json (CL/PE/AR, country derived from destination). The API exposes four endpoints:
| Method | Path | Purpose |
|---|---|---|
POST | /api/public/pre-alerts/v1/upload | Submit a new pre-alert (Excel manifest + invoice). |
GET | /api/public/pre-alerts/v1/mawbs | List your last 50 MAWBs with per-status guide counts. |
GET | /api/public/pre-alerts/v1/mawbs/:mawb | Detail of one MAWB with the full guide list. |
GET | /api/public/pre-alerts/v1/guides/:tracking_code | One guide with its event timeline. |
All four require Authorization: Bearer <api_password>. The company is inferred from the token β every list and detail endpoint scopes results server-side. See Authentication.
Upload a pre-alert β
POST /api/public/pre-alerts/v1/upload
Content-Type: multipart/form-data
Authorization: Bearer YOUR_COMPANY_API_PASSWORDSubmits an Excel manifest plus an optional invoice PDF. The MAWB is read from the Excel β you don't pass it as a field.
Form fields β
| Field | Type | Required | Description |
|---|---|---|---|
manifest_file | file (.xlsx) | yes | Excel manifest with HAWB rows. Max 20 MB. |
invoice_file | file (.pdf) | no | Invoice PDF for customs. Max 20 MB. |
flight_number | string | no | Carrier flight number (e.g. LA807). |
origin_airport | string | no | IATA code (e.g. HKG). |
destination_airport | string | no | IATA code (e.g. SCL). |
origin_country | string (ISO-2) | no | E.g. CN. |
scheduled_departure | ISO 8601 datetime | no | 2026-04-18T02:00:00+08:00. |
scheduled_arrival | ISO 8601 datetime | no | 2026-04-18T14:00:00-03:00. |
Example β
curl -X POST https://api.logirai.com/api/public/pre-alerts/v1/upload \
-H "Authorization: Bearer YOUR_COMPANY_API_PASSWORD" \
-F "manifest_file=@manifest_2026-04.xlsx" \
-F "invoice_file=@invoice_125-87654321.pdf" \
-F "flight_number=LA807" \
-F "origin_airport=HKG" \
-F "destination_airport=SCL" \
-F "scheduled_arrival=2026-04-18T14:00:00-03:00"Response β 201 Created β
{
"success": true,
"manifest_id": "d4e5f6a7-b8c9-0123-4567-89abcdef0123",
"flight_id": "f1a2b3c4-d5e6-7890-abcd-ef1234567890",
"mawb": "125-87654321",
"eta": "2026-04-18T14:00:00-03:00",
"guides_created": 143,
"guides": [
{ "hawb": "DRL-2026-00001", "tracking_code": "LR2026..." }
],
"rut_invalid_count": 2,
"warnings": [
{
"row_index": 17,
"hawb": "DRL-2026-00017",
"field": "consignee_rut",
"error_code": "rut_invalid_format",
"severity": "warning",
"message": "RUT does not match Chilean format β guide persisted, flagged for manual review"
}
]
}warnings aggregates parser warnings and synthetic per-row RUT warnings. A guide with rut_invalid_format is still created and flagged for manual review β uploads do not fail because of bad RUTs.
Error responses β
| HTTP | error | When |
|---|---|---|
400 | manifest_file_required | The manifest_file field is missing. |
400 | excel_parse_error | Excel is corrupt, encrypted, or unreadable. message carries the parser's reason. |
400 | mawb_not_found_in_file | No MAWB cell could be located in the Excel. |
400 | validation_failed | Flight fields failed validation. details lists the bad fields. |
401 | missing_api_key / invalid_api_key | See Authentication. |
400 | no_parser_for_format | The destination country has no onboarded multipart parser yet (PE/AR added per client). Use the JSON endpoint meanwhile. |
403 | country_not_allowed | The destination country is not in your allowed_countries. |
409 | mawb_already_exists | This MAWB has already been ingested. Response includes the existing manifest_id. |
500 | internal_server_error | Unexpected failure. Open a support ticket with the timestamp. |
Duplicate MAWB
A 409 mawb_already_exists includes the prior manifest_id. Use it with GET /v1/mawbs/:mawb to confirm what's already there before you panic.
List your MAWBs β
GET /api/public/pre-alerts/v1/mawbs
Authorization: Bearer YOUR_COMPANY_API_PASSWORDReturns the 50 most recent MAWBs you've uploaded, with totals and per-status guide counts. There are no query parameters in v1 β it's a fixed window.
Response β 200 OK β
{
"mawbs": [
{
"manifest_id": "d4e5f6a7-b8c9-0123-4567-89abcdef0123",
"mawb": "125-87654321",
"status": "in_transit",
"eta": "2026-04-18T14:00:00-03:00",
"total_guides": 143,
"total_weight_kg": 412.5,
"total_pieces": 143,
"total_fob_usd": 18432.27,
"guides_by_status": {
"in_transit": 140,
"customs_held": 3
},
"created_at": "2026-04-15T10:00:00Z"
}
]
}guides_by_status is a map of <status>: <count>, summed across all guides in that MAWB. Use it as the primary signal for "is this batch healthy" without paginating through every guide.
If you have no MAWBs yet, the response is { "mawbs": [] }.
Get one MAWB β
GET /api/public/pre-alerts/v1/mawbs/:mawb
Authorization: Bearer YOUR_COMPANY_API_PASSWORDPath param is the MAWB number (e.g. 125-87654321).
Response β 200 OK β
{
"manifest_id": "d4e5f6a7-b8c9-0123-4567-89abcdef0123",
"mawb": "125-87654321",
"status": "in_transit",
"eta": "2026-04-18T14:00:00-03:00",
"total_guides": 143,
"total_weight_kg": 412.5,
"total_pieces": 143,
"total_fob_usd": 18432.27,
"guides_by_status": { "in_transit": 140, "customs_held": 3 },
"guides": [
{
"hawb": "DRL-2026-00001",
"tracking_code": "LR2026A1B2C3",
"status": "in_transit",
"status_code": 4
}
]
}Errors β
| HTTP | error | When |
|---|---|---|
404 | not_found | The MAWB is not yours, or doesn't exist. |
Get one guide (by tracking code) β
GET /api/public/pre-alerts/v1/guides/:tracking_code
Authorization: Bearer YOUR_COMPANY_API_PASSWORDReturns one guide with its full event timeline. The tracking_code is the LogirAI-issued identifier you got back from the upload response (guides[].tracking_code).
Response β 200 OK β
{
"hawb": "DRL-2026-00001",
"tracking_code": "LR2026A1B2C3",
"mawb": "125-87654321",
"status": "delivered",
"status_code": 6,
"consignee_name": "MarΓa GonzΓ‘lez",
"weight_kg": 2.75,
"packages_count": 1,
"description_original": "Bluetooth Speaker",
"fob_usd": 29.99,
"events": [
{ "status": "registered", "status_code": 1, "timestamp": "2026-04-15T10:00:01Z", "source": "pre_alert" },
{ "status": "in_transit", "status_code": 4, "timestamp": "2026-04-16T18:30:00Z", "source": "carrier" },
{ "status": "customs_released", "status_code": 3, "timestamp": "2026-04-18T11:20:00Z", "source": "customs" },
{ "status": "out_for_delivery", "status_code": 5, "timestamp": "2026-04-19T08:15:00Z", "source": "courier_scan" },
{ "status": "delivered", "status_code": 6, "timestamp": "2026-04-19T11:45:00Z", "source": "courier_scan" }
]
}Errors β
| HTTP | error | When |
|---|---|---|
404 | not_found | The tracking code is not yours, or doesn't exist. |
Status reference β
The status and status_code fields you'll see across responses:
| Code | status | Meaning |
|---|---|---|
1 | registered | Pre-alert ingested; guide created. |
2 | customs_processing | Awaiting clearance. |
3 | customs_released | Cleared by customs. |
4 | in_transit | Moving (international or domestic leg). |
5 | out_for_delivery | With last-mile carrier for final delivery. |
6 | delivered | Delivered to consignee. |
Exception states like customs_held may appear in guides_by_status and on the timeline.
Polling vs webhooks β
The four GET endpoints are the system of record β always treat them as authoritative. Webhooks are an optimization to avoid frequent polling.
- For at-a-glance dashboards: poll
/v1/mawbsevery few minutes. - For per-shipment live updates: subscribe to Client Webhooks and reconcile on a slower cadence.
- For one-off lookups (customer asks "where's my package?"): hit
/v1/guides/:tracking_codeon demand.