{"info":{"name":"Tekipost Merchant API","description":"Generated from the live route definitions at api.tekipost.com/api/postman.json.\n\nSet the `token` collection variable to your GoTrue JWT — the same credential the merchant portal signs in with — and every request here will work.\n\n`webhook.tekipost.com` is a working alias for `baseUrl` if you are already integrated against it.","schema":"https://schema.getpostman.com/json/collection/v2.1.0/collection.json"},"auth":{"type":"bearer","bearer":[{"key":"token","value":"{{token}}","type":"string"}]},"variable":[{"key":"baseUrl","value":"https://api.tekipost.com","type":"string"},{"key":"token","value":"","type":"string"}],"item":[{"name":"Create orders","description":"One at a time, in bulk, or as a return. Creating does not book — see Booking & couriers.","item":[{"name":"POST /v1/intake/order","request":{"method":"POST","description":"Creates a forward order. It does **not** book — call `POST /v1/shipping/book` next.\n\nIdempotent on `customer_order_no`: re-sending the same reference answers `200 {order_id, deduped:true}` instead of creating a second order. `order.pickup_address_id` must be one of your own warehouses; an id that is not yours is `400 invalid_pickup_address`, never a 403 that would confirm it exists.\n\nRequires `orders.write`.","header":[{"key":"Content-Type","value":"application/json","type":"text"}],"url":{"raw":"{{baseUrl}}/v1/intake/order","host":["{{baseUrl}}"],"path":["v1","intake","order"]},"body":{"mode":"raw","raw":"{\n  \"customer_order_no\": \"<Your reference. The idempotency key>\",\n  \"channel\": \"<Where the order came from>\",\n  \"receiver\": {},\n  \"product\": {},\n  \"order\": {}\n}","options":{"raw":{"language":"json"}}}}},{"name":"POST /v1/intake/bulk","request":{"method":"POST","description":"`multipart/form-data`. Answers 202 with a `job_id`; poll `GET /v1/intake/jobs/{id}`. Rows that need a human decision land in the job's review queue rather than failing the upload.\n\nRequires `orders.write`.","header":[{"key":"Content-Type","value":"application/json","type":"text"}],"url":{"raw":"{{baseUrl}}/v1/intake/bulk","host":["{{baseUrl}}"],"path":["v1","intake","bulk"]},"body":{"mode":"raw","raw":"{\n  \"import_file\": \"<The spreadsheet. Maximum 25 MB>\",\n  \"sender_address_id\": 0\n}","options":{"raw":{"language":"json"}}}}},{"name":"POST /v1/intake/reverse","request":{"method":"POST","description":"Same block shape as a forward order, plus the original leg. Your reference is stored with a `-R` suffix so a return never collides with its forward order.\n\nRequires `orders.write`.","header":[{"key":"Content-Type","value":"application/json","type":"text"}],"url":{"raw":"{{baseUrl}}/v1/intake/reverse","host":["{{baseUrl}}"],"path":["v1","intake","reverse"]},"body":{"mode":"raw","raw":"{\n  \"order\": {}\n}","options":{"raw":{"language":"json"}}}}},{"name":"GET /v1/intake/jobs/{id}","request":{"method":"GET","description":"Progress and per-row outcome for a bulk upload.","header":[],"url":{"raw":"{{baseUrl}}/v1/intake/jobs/{id}","host":["{{baseUrl}}"],"path":["v1","intake","jobs",":id"],"variable":[{"key":"id","value":"","description":"The `job_id` from the upload."}]}}}]},{"name":"Booking & couriers","description":"Price a lane, book it, cancel it, and choose which couriers carry your parcels.","item":[{"name":"GET /v1/shipping/serviceable","request":{"method":"GET","description":"Which couriers will carry this lane and what each charges, cheapest decided by you. `dropped_couriers` is the honest half: every courier that was considered and excluded, with the reason — `no_rate_card`, `cod_config_missing`, `reverse_not_supported` and so on.\n\n`performance` carries the delivered/RTO percentages and TAT for the lane where there is enough history; `null` where there is not. It is never invented.","header":[],"url":{"raw":"{{baseUrl}}/v1/shipping/serviceable","host":["{{baseUrl}}"],"path":["v1","shipping","serviceable"],"query":[{"key":"from_pin","value":"","description":"REQUIRED — Pickup pincode.","disabled":false},{"key":"to_pin","value":"","description":"REQUIRED — Delivery pincode.","disabled":false},{"key":"physical_weight","value":"0.5","description":"REQUIRED — Kilograms, greater than zero.","disabled":false},{"key":"volumetric_weight","value":"","description":"Kilograms. Defaults to 0.","disabled":true},{"key":"order_type","value":"","description":"`\"1\"` for COD, anything else prepaid.","disabled":true},{"key":"collectable_amount","value":"","description":"COD amount to collect.","disabled":true},{"key":"operation","value":"","description":"Set `reverse` to price the return leg.","disabled":true}]}}},{"name":"POST /v1/shipping/book","request":{"method":"POST","description":"Queues the booking and answers **202 immediately** — the AWB is not in this response and will not be.\n\nThat is deliberate: returning anything else restarts the courier-fallback loop and risks booking one parcel with two couriers and debiting the wallet twice. The AWB usually exists within 8 seconds; collect it from `GET /v1/orders/status?order_no=…`.\n\nOmit `logistic_id` for AUTO mode, where the courier is chosen by your ranking and rules. Supply it to force one.","header":[{"key":"Content-Type","value":"application/json","type":"text"}],"url":{"raw":"{{baseUrl}}/v1/shipping/book","host":["{{baseUrl}}"],"path":["v1","shipping","book"]},"body":{"mode":"raw","raw":"{\n  \"order_id\": 0,\n  \"logistic_id\": 0\n}","options":{"raw":{"language":"json"}}}}},{"name":"POST /v1/shipping/book/sync","request":{"method":"POST","description":"Books inside the request and returns the AWB. It BLOCKS for the courier call — typically 30–40 seconds — so set your client timeout to at least 45s.\n\nPrefer the asynchronous `POST /v1/shipping/book` unless your integration genuinely cannot poll. A transient courier failure here is handed to the durable worker, so a timeout on your side does not mean the parcel was not booked — check `GET /v1/orders/status` before retrying.","header":[{"key":"Content-Type","value":"application/json","type":"text"}],"url":{"raw":"{{baseUrl}}/v1/shipping/book/sync","host":["{{baseUrl}}"],"path":["v1","shipping","book","sync"]},"body":{"mode":"raw","raw":"{\n  \"order_id\": 0,\n  \"logistic_id\": 0,\n  \"operation\": \"<Forward booking or a return>\"\n}","options":{"raw":{"language":"json"}}}}},{"name":"POST /v1/shipping/cancel","request":{"method":"POST","description":"Cancels with the courier and releases the order number for reuse. `refunded` reports what went back to your wallet.","header":[{"key":"Content-Type","value":"application/json","type":"text"}],"url":{"raw":"{{baseUrl}}/v1/shipping/cancel","host":["{{baseUrl}}"],"path":["v1","shipping","cancel"]},"body":{"mode":"raw","raw":"{\n  \"order_id\": 0,\n  \"logistic_id\": 0\n}","options":{"raw":{"language":"json"}}}}},{"name":"POST /v1/shipping/ndr","request":{"method":"POST","description":"Tells the courier what to do with a parcel they could not deliver.","header":[{"key":"Content-Type","value":"application/json","type":"text"}],"url":{"raw":"{{baseUrl}}/v1/shipping/ndr","host":["{{baseUrl}}"],"path":["v1","shipping","ndr"]},"body":{"mode":"raw","raw":"{\n  \"order_id\": 0,\n  \"logistic_id\": 0,\n  \"ndr_act\": \"<What to do. Defaults to `RE-ATTEMPT`>\",\n  \"deferred_date\": \"<Required for `DEFER_DLV`>\"\n}","options":{"raw":{"language":"json"}}}}},{"name":"GET /v1/shipping/couriers","request":{"method":"GET","description":"Every courier on your rate card, whether it is enabled, its position in your AUTO ranking, and how many pincodes it serves.","header":[],"url":{"raw":"{{baseUrl}}/v1/shipping/couriers","host":["{{baseUrl}}"],"path":["v1","shipping","couriers"],"query":[{"key":"shipment_type","value":"","description":"Forward or reverse. Defaults to `\"0\"`.","disabled":true}]}}},{"name":"PATCH /v1/shipping/couriers/priority","request":{"method":"PATCH","description":"Reorder only. You must send the **complete** ranking as a permutation of 1..n over the couriers already on your active rate card — this cannot add or remove a courier.\n\nRequires `courier.rank`.","header":[{"key":"Content-Type","value":"application/json","type":"text"}],"url":{"raw":"{{baseUrl}}/v1/shipping/couriers/priority","host":["{{baseUrl}}"],"path":["v1","shipping","couriers","priority"]},"body":{"mode":"raw","raw":"{\n  \"shipment_type\": \"<Forward or reverse>\",\n  \"order\": []\n}","options":{"raw":{"language":"json"}}}}}]},{"name":"Orders & tracking","description":"Read what you have created: status, lists, scans. Creating happens under Create orders.","item":[{"name":"GET /v1/orders/status","request":{"method":"GET","description":"The supported way to collect an AWB after `POST /v1/shipping/book` answers 202. Poll this, not the order row — `awb_number` on the pending-order table is never populated, by design.\n\n`state` is one of `booked` (done; `awb_number` and `courier` are filled), `booking_in_progress` (still on the worker — poll again in a few seconds), `failed` (it will not complete, and `failure_reason` says why in plain words), or `not_shipped` (the order exists, no ship was requested).\n\nBack off to every 10–15 seconds. A booking unsettled after a couple of minutes has almost certainly failed, and the response will say so.","header":[],"url":{"raw":"{{baseUrl}}/v1/orders/status","host":["{{baseUrl}}"],"path":["v1","orders","status"],"query":[{"key":"order_no","value":"ORD-4471","description":"REQUIRED — Your own reference, exactly as you sent it on create.","disabled":false}]}}},{"name":"GET /v1/orders","request":{"method":"GET","description":"Booked shipments, newest first, cursor-paginated. `bucket` is the lifecycle slice — the same slices the portal draws — and is the filter you usually want.","header":[],"url":{"raw":"{{baseUrl}}/v1/orders","host":["{{baseUrl}}"],"path":["v1","orders"],"query":[{"key":"bucket","value":"","description":"Lifecycle slice.","disabled":true},{"key":"limit","value":"50","description":"Page size, 1–1000.","disabled":true},{"key":"cursor","value":"","description":"From the previous page's `nextCursor`.","disabled":true},{"key":"awb_number","value":"","description":"Exact AWB.","disabled":true},{"key":"order_no","value":"","description":"Your own reference.","disabled":true},{"key":"shipment_type","value":"","description":"Forward or reverse.","disabled":true},{"key":"date_from","value":"","description":"Inclusive, `YYYY-MM-DD`.","disabled":true},{"key":"date_to","value":"","description":"Inclusive, `YYYY-MM-DD`.","disabled":true},{"key":"city","value":"","description":"Destination city, ≤100 characters.","disabled":true}]}}},{"name":"GET /v1/orders/{id}","request":{"method":"GET","description":"The full row for one order, plus `channel` and `tracking_url`.","header":[],"url":{"raw":"{{baseUrl}}/v1/orders/{id}","host":["{{baseUrl}}"],"path":["v1","orders",":id"],"variable":[{"key":"id","value":"","description":"The `order_id` from create."}]}}},{"name":"GET /v1/orders/{id}/tracking","request":{"method":"GET","description":"Courier scans oldest-first. `truncated` tells you the list was capped at `scan_limit`.","header":[],"url":{"raw":"{{baseUrl}}/v1/orders/{id}/tracking","host":["{{baseUrl}}"],"path":["v1","orders",":id","tracking"],"variable":[{"key":"id","value":"","description":"The `order_id`."}]}}},{"name":"GET /v1/orders/unshipped","request":{"method":"GET","description":"Created but not yet booked, with the reason each one is stuck. Cursor-paginated and heavily filterable.","header":[],"url":{"raw":"{{baseUrl}}/v1/orders/unshipped","host":["{{baseUrl}}"],"path":["v1","orders","unshipped"],"query":[{"key":"limit","value":"","description":"Page size, 1–1000.","disabled":true},{"key":"cursor","value":"","description":"From `nextCursor`.","disabled":true},{"key":"error_type","value":"","description":"One of the values `/v1/orders/unshipped/error-types` returns.","disabled":true},{"key":"customer_order_no","value":"","description":"Your own reference.","disabled":true},{"key":"pickup_address_id","value":"","description":"Warehouse id.","disabled":true},{"key":"order_type","value":"","description":"Prepaid or COD.","disabled":true},{"key":"amount_min","value":"","description":"Rupee amount.","disabled":true},{"key":"amount_max","value":"","description":"Rupee amount.","disabled":true}]}}},{"name":"GET /v1/orders/unshipped/counts","request":{"method":"GET","description":"Forward answers `{total, unshipped, failed, in_queue}`; reverse answers `{unshipped, failed}`.","header":[],"url":{"raw":"{{baseUrl}}/v1/orders/unshipped/counts","host":["{{baseUrl}}"],"path":["v1","orders","unshipped","counts"],"query":[{"key":"shipment_type","value":"","description":"Forward or reverse.","disabled":true}]}}},{"name":"PATCH /v1/orders/unshipped/{id}","request":{"method":"PATCH","description":"Change buyer details on an order that has not shipped. The writable set is a closed allow-list; `sender_id` is stripped. Once booked, an order is no longer editable.\n\nRequires `orders.write`.","header":[],"url":{"raw":"{{baseUrl}}/v1/orders/unshipped/{id}","host":["{{baseUrl}}"],"path":["v1","orders","unshipped",":id"],"variable":[{"key":"id","value":"","description":"The `order_id`."}]}}},{"name":"POST /v1/orders/{id}/hide","request":{"method":"POST","description":"Soft-removes an order from your lists. Closes any open cancellation and reports what was refunded.\n\nRequires `orders.write`.","header":[],"url":{"raw":"{{baseUrl}}/v1/orders/{id}/hide","host":["{{baseUrl}}"],"path":["v1","orders",":id","hide"],"variable":[{"key":"id","value":"","description":"The `order_id`."}]}}}]},{"name":"Labels & manifests","description":"The paperwork: labels, packing slips, and the handover manifest.","item":[{"name":"GET /v1/documents/label/{orderId}","request":{"method":"GET","description":"The label PDF, or the carrier's own file where they issue it. Fetching it stamps `label_downloaded_at`.","header":[],"url":{"raw":"{{baseUrl}}/v1/documents/label/{orderId}","host":["{{baseUrl}}"],"path":["v1","documents","label",":orderId"],"variable":[{"key":"orderId","value":"","description":"The `order_id`."}]}}},{"name":"POST /v1/documents/label","request":{"method":"POST","description":"One merged PDF, pages in the order you asked for. Maximum 200 orders. One missing label fails the whole batch rather than silently shipping a short PDF.","header":[{"key":"Content-Type","value":"application/json","type":"text"}],"url":{"raw":"{{baseUrl}}/v1/documents/label","host":["{{baseUrl}}"],"path":["v1","documents","label"]},"body":{"mode":"raw","raw":"{\n  \"order_ids\": []\n}","options":{"raw":{"language":"json"}}}}},{"name":"POST /v1/documents/manifest","request":{"method":"POST","description":"Builds the handover manifest, one section per courier, and **moves those packages to Ready-for-pickup**. This is a write with side effects, not a report: it inserts manifest rows and fires `shipment.status_changed`.","header":[{"key":"Content-Type","value":"application/json","type":"text"}],"url":{"raw":"{{baseUrl}}/v1/documents/manifest","host":["{{baseUrl}}"],"path":["v1","documents","manifest"]},"body":{"mode":"raw","raw":"{\n  \"order_ids\": []\n}","options":{"raw":{"language":"json"}}}}},{"name":"GET /v1/documents/label/t/{token}","request":{"method":"GET","description":"Open — **no Authorization header**. The token is `\"{awb}.{hmac}\"` and is itself the credential, so a label link can be forwarded to a packer who has no login. Rate-limited at the edge.\n\nServed with `Content-Disposition: attachment`, `X-Content-Type-Options: nosniff` and a `sandbox` CSP. Treat the URL as a secret: anyone holding it can fetch that label.","header":[],"url":{"raw":"{{baseUrl}}/v1/documents/label/t/{token}","host":["{{baseUrl}}"],"path":["v1","documents","label","t",":token"],"variable":[{"key":"token","value":"","description":"`{awb}.{hmac}`, as issued."}]}}}]},{"name":"Warehouses","description":"Your pickup addresses. A courier will not collect from one it does not know.","item":[{"name":"GET /v1/warehouses","request":{"method":"GET","description":"Every pickup address, with its courier-registration state and 30-day shipped count.","header":[],"url":{"raw":"{{baseUrl}}/v1/warehouses","host":["{{baseUrl}}"],"path":["v1","warehouses"],"query":[{"key":"include","value":"","description":"CSV. `inactive` also returns retired rows.","disabled":true}]}}},{"name":"POST /v1/warehouses","request":{"method":"POST","description":"The validation here is the courier's, not ours: Delhivery rejects a name under three characters and a sparse address, and a warehouse that passes here but fails there is one no courier will collect from.\n\nSet `is_return_same` truthy to mirror the forward address onto the return leg; otherwise every `return_*` field is required and validated the same way. Creating a warehouse also adopts any orders that arrived before you had one.\n\nRequires `warehouses.write`.","header":[{"key":"Content-Type","value":"application/json","type":"text"}],"url":{"raw":"{{baseUrl}}/v1/warehouses","host":["{{baseUrl}}"],"path":["v1","warehouses"]},"body":{"mode":"raw","raw":"{\n  \"warehouse_name\": \"<Unique to you>\",\n  \"contact_person_name\": \"<Who the courier asks for>\",\n  \"contact_no\": \"<Collection contact>\",\n  \"address_line_1\": \"<Street address>\",\n  \"city\": \"<City>\",\n  \"state\": \"<State>\",\n  \"pincode\": \"<Pickup pincode>\",\n  \"contact_email\": \"<Optional, validated when present>\",\n  \"gstin\": \"<GSTIN for the state the goods are stocked in>\",\n  \"warehouse_type\": \"<Defaults to `fulfillment_pickup`>\",\n  \"is_return_same\": false\n}","options":{"raw":{"language":"json"}}}}},{"name":"DELETE /v1/warehouses/{id}","request":{"method":"DELETE","description":"A soft delete, and it refuses while orders still ship from the address. The 409 is the point of the endpoint: deleting a warehouse an open order points at strands that order at a collection point nothing resolves.\n\nRequires `warehouses.write`.","header":[],"url":{"raw":"{{baseUrl}}/v1/warehouses/{id}","host":["{{baseUrl}}"],"path":["v1","warehouses",":id"],"variable":[{"key":"id","value":"","description":"The warehouse id."}]}}}]},{"name":"Failed deliveries (NDR)","description":"Parcels the courier could not deliver, and what to tell them to do next.","item":[{"name":"GET /v1/ndr","request":{"method":"GET","description":"Failed-delivery parcels by tab, cursor-paginated, each with the notification we sent the buyer and how it landed.","header":[],"url":{"raw":"{{baseUrl}}/v1/ndr","host":["{{baseUrl}}"],"path":["v1","ndr"],"query":[{"key":"tab","value":"","description":"REQUIRED — Which slice of the queue.","disabled":false},{"key":"limit","value":"","description":"Page size.","disabled":true},{"key":"cursor","value":"","description":"From `nextCursor`.","disabled":true},{"key":"awb_number","value":"","description":"Exact AWB.","disabled":true},{"key":"date_from","value":"","description":"Inclusive.","disabled":true}]}}},{"name":"GET /v1/ndr/counts","request":{"method":"GET","description":"One number per tab, so you can badge a queue without pulling every page of it. The keys are the same tab values `GET /v1/ndr` accepts, so you can drive both the badge and the link from one response.","header":[],"url":{"raw":"{{baseUrl}}/v1/ndr/counts","host":["{{baseUrl}}"],"path":["v1","ndr","counts"]}}},{"name":"POST /v1/ndr/{id}/comment","request":{"method":"POST","description":"Adds a note to the NDR thread. Note `merchant_support` holds the `ndr.act` capability but is a read-only role, so the mount refuses it here — a known inconsistency, stated rather than hidden.","header":[{"key":"Content-Type","value":"application/json","type":"text"}],"url":{"raw":"{{baseUrl}}/v1/ndr/{id}/comment","host":["{{baseUrl}}"],"path":["v1","ndr",":id","comment"],"variable":[{"key":"id","value":"","description":"The order id."}]},"body":{"mode":"raw","raw":"{\n  \"comment\": \"<The note>\"\n}","options":{"raw":{"language":"json"}}}}}]},{"name":"Lookups","description":"Shared reference data. Nothing here is specific to your account.","item":[{"name":"GET /v1/pincode/{pincode}","request":{"method":"GET","description":"An unknown pincode is **200 with `found:false`**, not a 404 — so you can call it on every keystroke of an address form without treating \"not yet six digits\" as an error.","header":[],"url":{"raw":"{{baseUrl}}/v1/pincode/{pincode}","host":["{{baseUrl}}"],"path":["v1","pincode",":pincode"],"variable":[{"key":"pincode","value":"","description":"Six digits."}]}}}]}]}