Developers
API overview
Base URL, authentication, environments, scopes, idempotency, pagination, rate limits and the one error shape.
The QCS REST API is version 1 and lives under https://qcs.com.pk/api/v1. It is JSON in, JSON out, over HTTPS only. Everything a merchant can do in the portal that matters to a shop can be done here: quote, book, label, forward for pickup, track and reconcile.
Getting a key
- 01Open the integration portalGo to /m/integrations/keys in the merchant portal. Only a merchant user with the integration permission can issue keys.
- 02Choose the environmentSandbox for building, live for real parcels. Keys are not interchangeable and a sandbox key can never move a real parcel.
- 03Grant only the scopes you needA key that only quotes rates should carry only the rate scope. Scopes are checked on every request.
- 04Copy the secret onceThe secret is shown exactly once, at creation. It is stored hashed with a pepper and cannot be recovered. Rotate the key if you lose it.
Authentication
Send the key id and the secret on every request. Either form is accepted; use the bearer form unless your HTTP client makes custom headers easier.
Bearer <keyId>.<keySecret>x-qcs-key-id: <keyId>
x-qcs-key-secret: <keySecret>Environments
Sandbox isolation is enforced in the database, not only in the application: a sandbox parcel cannot be attached to a pickup request, a rider or a delivery run, and cannot move beyond booked or cancelled.
Scopes
Idempotency
Send idempotency-key on every write. A repeat of the same key with the same body returns the original response instead of booking a second parcel, which is what makes a retry after a timeout safe. A repeat of the same key with a different body is a conflict.
- Required on order creation, bulk creation and pickup creation.
- Optional but recommended on cancellation, label requests and webhook writes.
- Use a value your own system can regenerate for the same order, such as your order number plus the action.
Pagination
List endpoints are cursor-paginated. Pass limit up to 200; the default is 50. The response carries the next cursor, and an absent cursor means you have reached the end. Do not build page numbers; cursors are stable while rows are being inserted and page numbers are not.
Rate limits
Each key carries its own per-minute allowance, set when the key is issued and visible on the key. Exceeding it returns the rate-limited error. Treat it as back-pressure: pause, then retry with the same idempotency key.
Errors
Every failure returns the same envelope. There is no second error shape to handle, and no stack trace, SQL fragment or internal identifier ever appears in it.
{
"error": {
"code": "QCS_VALIDATION_FAILED",
"message": "Enter the parcel weight in kilograms, up to three decimal places, such as 1.25.",
"details": { "fieldErrors": { "weightKg": ["Enter the parcel weight in kilograms."] } },
"requestId": "req_01hz..."
}
}Money, weight and time
- Money on the wire is whole rupees, as a string or a number. QCS stores paisa internally and never uses floating point for money.
- Weight on the wire is kilograms with up to three decimals. Dimensions are centimetres with up to one decimal.
- Timestamps are ISO 8601 in UTC. Operational dates are Asia/Karachi calendar dates in YYYY-MM-DD form.