Guide
Migrating from the old API
Every api-* route on app.tekipost.com, and what replaces it here. Each row was checked against both implementations — the old controller and the new one — so the differences below are the real ones, not a summary.
2 of these have no replacement yet. They are the B2B / heavy-shipment routes. Nothing on this API creates, prices, books or labels a B2B consignment today — the booking service refuses them outright. If your integration ships B2B, talk to us before you migrate anything else.
| Old route | Replacement | What changes |
|---|---|---|
| POST /api-login Exchange e-mail + password for a bearer token. | POST {gotrue}/token?grant_type=passwordContract changed | The CREDENTIAL is unchanged — the same token works. The CALL is not: a different host, and GoTrue answers {access_token, refresh_token, expires_in} where CI wrapped it as {data:{token,…}}. Any client parsing data.token must change. CI also threw a 429 with Retry-After; GoTrue does not. |
| POST /api-b2c-single-order Create a B2C order, and ship it unless `isorder` was set. | POST /v1/intake/order → POST /v1/shipping/bookSplits into two calls | One call becomes two, plus a poll. The body is restructured from ~30 flat fields into {customer_order_no, receiver:{}, product:{}, order:{}}. isorder:1 (create only) maps cleanly to just the first call. Booking answers 202, not an AWB — collect it from GET /v1/orders/status. order.pickup_address_id is now required and validated; CI tolerated an empty one. Multi-SKU productdetatis[] has no equivalent: one product block. |
| POST /api-b2c-quick-shipment The same handler as api-b2c-single-order, with auto-ship on. | POST /v1/intake/order → POST /v1/shipping/book/syncSplits into two calls | Use /book/sync rather than /book if you need the AWB inline as CI returned it. It BLOCKS for the courier call — 30–40s is normal, so set your client timeout to 45s+. |
| POST /api-bulk-b2c-order Post a JSON array of orders; get a result map keyed by your reference. | Loop POST /v1/intake/orderContract changed | There is no JSON-array bulk endpoint on the new API. POST /v1/intake/bulk exists but is a spreadsheet upload answering a job_id you poll — a different workflow, not a drop-in. For an array, loop the single-order endpoint and handle each result. |
| POST /api-b2b-single-order Create a B2B / heavy multi-box consignment. | none yet No replacement | Nothing on the new API creates, prices, books or labels a B2B shipment. The booking worker refuses them outright (unsupported_channel: B2B stays on CI) and the rate engine reads the B2C card only. If you ship B2B through the API, talk to us before migrating anything. |
| POST /api-b2b-quick-shipment The same handler, with auto-ship on. | none yet No replacement | Same gap as api-b2b-single-order. No replacement exists. |
| POST /api-calculate-price Quote a lane — B2C, or multi-box when `multiChecked` was set. | GET /v1/shipping/serviceableContract changed | B2C only. Field names all change: pickupPinCode→from_pin, deliveryPinCode→to_pin, apprWeight→physical_weight, declaredValue→collectable_amount, paymentMode→order_type. Volumetric weight is now yours to compute; CI derived it from L×W×H/5000. 🔴 The multiChecked multi-box branch has no replacement — see the B2B rows. In exchange you get dropped_couriers with reasons, an RTO leg and per-lane performance. |
| POST /api-logistic-price/{order_id} Price an order you had already created, across its couriers. | GET /v1/shipping/serviceableContract changed | There is no "price this existing order id" call. Read the order back, then assemble the pins, weight and COD for serviceable yourself. |
| POST /api-ship-order Book an order you had created. `logistic_id:0` meant auto. | POST /v1/shipping/bookDrop-in | Closest match on the list — same order_id semantics, and omitting logistic_id is the same AUTO fall-through. Two changes: it answers 202 (use /book/sync for inline), and ownership is now enforced — CI never checked that the order was yours. |
| POST /api-delete-order Cancel a shipment with the courier, by AWB. | POST /v1/shipping/cancelContract changed | 🔴 If you were sent to /v1/orders/{id}/delete-return or /hide by an earlier migration note, that is wrong and it matters: neither contacts the courier or refunds the wallet. /hide is a view preference. The real replacement is /v1/shipping/cancel, which takes {order_id, logistic_id} — not an AWB — so resolve it first with GET /v1/orders?awb_number=…. It also refunds, which CI did not. |
| GET /api-tracking-details/{awb} Scan history for an AWB. | GET /v1/orders/{id}/trackingContract changed | Keyed on the order id, not the AWB. If you hold only an AWB — the common case, since it is what booking returned — resolve it first with GET /v1/orders?awb_number=…. CI put no account predicate on this query at all, so it would return anyone's AWB; the new one is scoped to you. |
| POST /api-order-shipment-detail Look up tracking number and label by your own reference. | GET /v1/orders/status?order_no=…Drop-in | Strictly better. CI could only ever see booked rows, so a booking still in flight or failed looked identical to "no record found". The new one reports state — booked, booking_in_progress, failed (with failure_reason) or not_shipped — and a real 404 for a reference that is not yours. |
| GET /api-shipping-label-slip/{id} The label PDF, with no credential at all. | GET /v1/documents/label/{orderId}Contract changed | Same key, but it now requires your bearer token and 404s an order that is not yours. 🔴 If you stored CI label URLs, e-mailed them, or render them in a customer-facing page, those links will stop working — they were reachable by anyone who had them. For a shareable link use the signed GET /v1/documents/label/t/{token} instead. |
| POST /api-ndr-list List failed deliveries, paged with `page` / `pageRow`. | GET /v1/ndr?tab=…Contract changed | tab is required and has no default. Pagination is cursors, not page numbers. Field names are corrected (CI's reciver_* typo is gone). You also gain NDR actions, which CI had no API for. |
| POST /api-warehouse-add Create a warehouse, or update one by passing `id`. | POST /v1/warehouses · PATCH /v1/warehouses/{id}Splits into two calls | The upsert splits into two verbs. A return address is now required — send is_return_same: true to mirror the pickup address, or a full return_* block. CI silently renamed a duplicate warehouse name; the new API rejects it with a 400. |
Two things that are new
GET /v1/orders/status has no old equivalent and is now a required step: booking answers 202, and this is how you collect the AWB. The old API returned the AWB inline, so integrations that never polled anything will need to.
GET /v1/shipping/couriers is also new. Previously the only way to see your couriers was as a side-effect of asking for a price.
Credentials do not change
The bearer token you use today keeps working — it is the same GoTrue credential, verified the same way. Only the host and the login response envelope differ. See Authentication.