Get from zero to an accurate INR shipping rate in a single call. REST, JSON, India-first — keys, pincodes and zones included.
Getting started
Send your first POST /rates request. Use your test or live key in the Authorization header — the example below prices Jaipur (302001) → Guwahati (781001).
Grab a key
Create a project and copy your pp_live_… key.
Send pincodes + parcel
POST origin, destination, weight & dimensions.
Receive itemised INR
Get zone, billable weight and a GST breakdown.
https://api.postpin.creatibyte.in/v1/ratescurl https://api.postpin.creatibyte.in/v1/rates/calculate \
-H "Authorization: Bearer pp_live_3kQ9xR2pLmZ" \
-H "Content-Type: application/json" \
-d '{
"origin": "302001",
"destination": "781001",
"weight": 400,
"dimensions": { "length": 30, "width": 25, "height": 8, "unit": "cm" },
"service": "surface",
"cod": true,
"declared_value": 1499
}'Security
Postpin uses bearer API keys. Pass your key in the Authorization header on every request. Keep live keys server-side only.
Authorization: Bearer pp_live_3kQ9xR2pLmZKey types
pp_test_… runs against the sandbox. pp_live_… bills real usage. Rotate keys anytime from the dashboard.
Allowed domains
Restrict each key to specific domains or IPs. Requests from elsewhere return 403 domain_not_allowed.
Core
Calculate an itemised shipping charge between two Indian pincodes. Returns the zone, billable weight (max of actual & volumetric) and a GST-inclusive breakdown.
https://api.postpin.creatibyte.in/v1/rates| Parameter | Type | Required | Description |
|---|---|---|---|
| origin | string | Required | Pickup pincode (6 digits). |
| destination | string | Required | Delivery pincode (6 digits). |
| weight | integer | Required | Actual parcel weight in grams. |
| dimensions | object | Optional | length, width, height (in cm). Used for volumetric weight = L×W×H/5000. |
| service | enum | Optional | surface (default), express, or same_day. |
| cod | boolean | Optional | Set true for cash-on-delivery to add COD handling. |
| declared_value | integer | Optional | Declared parcel value in INR. Drives the 1.5% COD fee. |
{
"origin": "302001",
"destination": "781001",
"weight": 400,
"dimensions": { "length": 30, "width": 25, "height": 8, "unit": "cm" },
"service": "surface",
"cod": true,
"declared_value": 1499
}{
"currency": "INR",
"zone": "special",
"zone_label": "Special / Remote",
"service": "surface",
"chargeable_weight_g": 1200,
"volumetric_weight_g": 1200,
"eta_days": [5, 9],
"breakdown": [
{ "label": "Base charge", "amount": 95.00, "hint": "Special / Remote · Surface" },
{ "label": "Weight charge", "amount": 108.00, "hint": "1.50 kg chargeable" },
{ "label": "Fuel surcharge", "amount": 24.36, "hint": "12%" },
{ "label": "COD handling", "amount": 57.49, "hint": "₹35 + 1.5%" },
{ "label": "GST", "amount": 51.27, "hint": "18%" }
],
"total": 336.12,
"origin": { "pincode": "302001", "city": "Jaipur", "state": "Rajasthan" },
"destination": { "pincode": "781001", "city": "Guwahati", "state": "Assam" },
"serviceable": true,
"meta": { "engine_ms": 11, "cached": false, "request_id": "req_7Yh2mKp" }
}| Field | Type | Description |
|---|---|---|
| currency | string | Always INR. |
| zone | string | local · regional · metro · national · special. |
| chargeable_weight_g | integer | max(actual, volumetric) in grams. |
| volumetric_weight_g | integer | Volumetric weight in grams. |
| eta_days | [int, int] | Estimated delivery window, low–high. |
| breakdown | array | Itemised charge lines (label, amount, hint). |
| total | number | Grand total in INR, GST inclusive. |
| serviceable | boolean | False when a pincode is unknown or off-network. |
Core
Check whether a single pincode is on-network before you quote. Returns city, state, zone, COD availability and an ETA window.
https://api.postpin.creatibyte.in/v1/serviceability/:pincodecurl https://api.postpin.creatibyte.in/v1/serviceability/781001 \
-H "Authorization: Bearer pp_live_3kQ9xR2pLmZ"{
"data": {
"pincode": "781001",
"serviceable": true,
"found": true,
"city": "Guwahati",
"state": "Assam"
},
"meta": { "request_id": "req_7Yh2mKp", "api_version": "v1" }
}Reference
Search the India Post-synced pincode master by code or city. The master refreshes nightly at 00:30 IST; synced_at tells you the last refresh.
https://api.postpin.creatibyte.in/v1/pincodescurl "https://api.postpin.creatibyte.in/v1/pincodes?q=jaipur&limit=5" \
-H "Authorization: Bearer pp_live_3kQ9xR2pLmZ"{
"data": [
{ "pincode": "302001", "city": "Jaipur", "state": "Rajasthan", "metro": false, "serviceable": true },
{ "pincode": "302002", "city": "Jaipur", "state": "Rajasthan", "metro": false, "serviceable": true }
],
"meta": { "request_id": "req_9Kd4nQw", "api_version": "v1", "has_more": false }
}Results are paginated with limit (max 100) and a starting_after cursor. The full master covers 19,000+ serviceable pincodes.
Reference
Subscribe to events and Postpin will POST a signed JSON payload to your endpoint. Always verify the Postpin-Signature header before trusting a payload.
| Event | Triggered when |
|---|---|
rate.calculated | A rate was successfully computed via the API. |
serviceability.checked | A serviceability lookup was performed. |
sync.completed | Nightly India Post pincode sync finished. |
sync.failed | A pincode sync run failed and needs attention. |
subscription.updated | Plan, status or limits changed for the tenant. |
invoice.paid | A usage / subscription invoice was paid. |
POST /your-endpoint HTTP/1.1
Postpin-Signature: t=1718900000,v1=5257a869e7ec...
Content-Type: application/json
{
"id": "evt_2nKp7Yh",
"type": "rate.calculated",
"created": 1718900000,
"livemode": true,
"data": {
"request_id": "req_7Yh2mKp",
"origin": "302001",
"destination": "781001",
"zone": "special",
"total": 336.12,
"currency": "INR"
}
}import crypto from "node:crypto";
function verify(rawBody, header, secret) {
const [t, v1] = header.split(",").map((p) => p.split("=")[1]);
const expected = crypto
.createHmac("sha256", secret)
.update(`${t}.${rawBody}`)
.digest("hex");
// Constant-time compare; reject if t is older than 5 minutes.
return crypto.timingSafeEqual(Buffer.from(v1), Buffer.from(expected));
}Reference
Postpin uses conventional HTTP status codes and a stable error envelope: { error: { code, message, request_id } }. Quote the request_id when contacting support.
| Status | Code | Meaning |
|---|---|---|
| 400 | invalid_request | A required field is missing or malformed. |
| 401 | authentication_failed | Missing, revoked or invalid API key. |
| 403 | domain_not_allowed | Request origin is not in the key's allow-list. |
| 404 | pincode_not_found | Pincode is unknown to the master. |
| 422 | not_serviceable | Route exists but is not currently serviceable. |
| 429 | rate_limited | Plan RPM exceeded. Inspect Retry-After. |
| 500 | engine_error | Unexpected error. Safe to retry with backoff. |
{
"error": {
"code": "rate_limited",
"message": "Plan limit of 300 requests/min exceeded.",
"request_id": "req_7Yh2mKp"
}
}Tooling
Official, typed SDKs wrap authentication, retries and idempotency. Install your language and you're a few lines from a rate.
Node
npm install @postpin/nodePython
pip install postpinPHP
composer require postpin/postpin-phpGo
go get github.com/postpin/postpin-goUpdates
Every API change, newest first. The /v1 surface is stable; breaking changes ship behind a new version.
Create a key in seconds — 1,000 free calls every month.