Store connectors
Custom API wizard
Push an order from any system in whatever shape it already has, and tell QCS where to read each value.
If your system can post JSON but cannot be rewritten to match somebody else’s shape, use the custom connection. You post your own payload, and a field map tells QCS which path in that payload holds each value it needs.
When to use this instead of the API
The REST API at /api/v1/orders is the better choice when you control the request. The custom connection exists for systems that can only fire a fixed webhook: an ERP, a POS, a legacy order manager, or a no-code automation.
Setting it up
- 01Create the connectionOpen /m/integrations/custom. QCS gives you a connection key and shows the signing secret once.
- 02Post a sample payloadSend one real order to the push endpoint, or paste it into the wizard. QCS reads every path in it and offers them in the mapping editor.
- 03Map the fieldsFor each QCS field, pick the path in your payload. Paths are dotted, with array indexes, such as shipping.address.line1 or items[0].weight.
- 04Validate and go liveThe wizard prices the mapped order and shows you the parcel it would create. When that looks right, switch the connection live.
The endpoint
The signature is HMAC-SHA256 over the unix timestamp, a full stop, and the exact raw body, using your connection secret. Sign the bytes you send, not a re-serialised copy. QCS allows five minutes of clock drift.
import { createHmac } from 'node:crypto'
const body = JSON.stringify(order)
const timestamp = Math.floor(Date.now() / 1000)
const digest = createHmac('sha256', process.env.QCS_CONNECTION_SECRET)
.update(`${timestamp}.${body}`, 'utf8')
.digest('hex')
await fetch('https://qcs.com.pk/api/webhooks/custom/orders', {
method: 'POST',
headers: {
'x-qcs-connection': process.env.QCS_CONNECTION_KEY,
'x-qcs-signature': `t=${timestamp},v1=${digest}`,
'Content-Type': 'application/json',
},
body,
})The fields QCS needs
Use a dotted path into your payload, such as customer.phone or items[0].sku.
Reading the result
The response carries the tracking number and the frozen charge. Every push, accepted or rejected, is recorded at /m/integrations/logs with your order id, the mapped values and the reason for a rejection.