Skip to main content

postpin

Official Python SDK for the Postpin shipping-rate API — calculate courier charges between Indian pincodes, check serviceability, look up the pincode directory, and verify webhooks.

  • Fully typed — dataclass results and typed parameters; ships py.typed.
  • Robust by default — automatic retries with exponential backoff + jitter, Retry-After support, per-request timeouts, and idempotency keys.
  • Typed errors — catch RateLimitError, QuotaExceededError, ValidationError, and friends.
  • Secure webhooks — constant-time HMAC signature verification with replay protection.

Requirements

  • Python 3.8+

Install

pip install postpin

Quick start

import os
from postpin import Postpin

client = Postpin(os.environ["POSTPIN_API_KEY"])

rate = client.rates.calculate(
    origin="400001",       # Mumbai
    destination="110001",  # New Delhi
    weight=1200,           # grams
    service="express",     # "surface" | "express" | "same_day"
)

print(rate.total, rate.currency)  # 254.38 INR
print(rate.eta_days)              # [1, 3]
for line in rate.breakdown:
    print(line.label, line.amount)

Load your API key from an environment variable — never hard-code it.

The client can be used as a context manager to close the connection pool:

with Postpin(api_key) as client:
    rate = client.rates.calculate(origin="400001", destination="781001", weight=2500)

Configuration

client = Postpin(
    api_key,
    base_url="https://api.postpin.in/v1",  # override the API base (incl. version)
    timeout=30.0,                          # per-request timeout in seconds
    max_retries=2,                         # retries on 429/5xx/network errors
    headers={"x-team": "logistics"},       # extra headers on every request
)

Resources

# Rates
rate = client.rates.calculate(
    origin="400001", destination="781001", weight=2500,
    length=30, width=20, height=15,   # cm — enables volumetric weight
    cod=True, declared_value=4999,    # rupees
)

# Serviceability
check = client.serviceability.check("781001")
print(check.serviceable, check.city)

# Pincodes
pin = client.pincodes.get("302001")
states = client.pincodes.states()

# Plans
plans = client.plans.list()

Every method accepts timeout=, and rates.calculate also accepts idempotency_key=.

Error handling

from postpin import (
    Postpin, RateLimitError, QuotaExceededError,
    ValidationError, AuthenticationError, NotFoundError,
)

try:
    client.rates.calculate(origin="400001", destination="110001", weight=1200)
except RateLimitError as e:
    print(f"Rate limited — retry after {e.retry_after}s")
except QuotaExceededError:
    print("Monthly quota exhausted — upgrade your plan")
except ValidationError as e:
    print("Bad request:", e.message, e.details)
except AuthenticationError:
    print("Invalid API key")
Error HTTP When
AuthenticationError 401 Missing or invalid API key
PermissionDeniedError 403 Key lacks the required scope
ValidationError 400 / 422 Invalid parameters (.details)
NotFoundError 404 Resource does not exist
QuotaExceededError 402 Monthly quota used up
RateLimitError 429 Too many requests (.retry_after)
APIError 5xx Server-side error (auto-retried)
APITimeoutError — Request exceeded timeout
APIConnectionError — Network failure after retries

Every PostpinError carries code, status_code, request_id, details, and headers.

Webhooks

Verify against the raw request body — re-serializing the JSON breaks the signature.

from flask import Flask, request
from postpin import webhooks, SignatureVerificationError

app = Flask(__name__)

@app.post("/webhooks/postpin")
def handle():
    try:
        event = webhooks.construct_event(
            request.get_data(),                       # raw bytes
            request.headers.get("X-Postpin-Signature"),
            os.environ["POSTPIN_WEBHOOK_SECRET"],
        )
    except SignatureVerificationError:
        return "", 400

    if event["event"] == "rate.calculated":
        ...  # handle event["data"]
    return "", 200

verify() returns True or raises; construct_event() verifies and returns the parsed event. Both accept tolerance_seconds= (default 300; 0 disables the replay check).

License

MIT © Postpin

Metadata

Release files for postpin 0.1.0

For a detailed explanation of source distributions (sdists) and built distributions (wheels), please see the package formats documentation.

Source distribution (sdist)

Source distribution for postpin 0.1.0
File Size Uploaded
postpin-0.1.0.tar.gz 13.1 kB Details

Built distribution (wheel)

Table of built distributions (wheels) for postpin 0.1.0
File Interpreter ABI Platform
postpin-0.1.0-py3-none-any.whl Python 3 none any Details

Total release size: 27.6 kB

Release files / postpin-0.1.0.tar.gz

Download URL postpin-0.1.0.tar.gz
Size 13.1 kB
Tags Source
SHA-256 checksum
How to use checksums
ca340ffc906ae7f4e2b91442e2ed06e848b68c7e3f38ae4cd074271732c85289
BLAKE2b-256 checksum
How to use checksums
73df44677cbbe838675321aa6688d40ab883669829bfd4770dd8d0c20db6b6a0
Upload date
Uploaded using Trusted Publishing?
What is trusted publishing?
Yes
Uploaded via twine/6.1.0 CPython/3.13.12

Provenance

Provenance describes where a file came from. On PyPI, provenance is shared via attestations, which provide a verifiable record of the build or publishing details. View details, limitations and caveats.

PyPI Publish Attestation

PyPI verified that this artifact, at this checksum, originated from the publisher listed below.

Signed by GitHub Actions, verified by PyPI on Jul 13, 2026.

Transparency log

Release files / postpin-0.1.0-py3-none-any.whl

Download URL postpin-0.1.0-py3-none-any.whl
Size 14.5 kB
Tags Python 3
SHA-256 checksum
How to use checksums
928da641d6b6c9ee8fe0a746688ccfbb38e7c48891497cc4e1feece6f905e292
BLAKE2b-256 checksum
How to use checksums
fb8df8989ab7fcc67343650ae9fcfb73f628ece09bbb3136f34baad53ee92c18
Upload date
Uploaded using Trusted Publishing?
What is trusted publishing?
Yes
Uploaded via twine/6.1.0 CPython/3.13.12

Provenance

Provenance describes where a file came from. On PyPI, provenance is shared via attestations, which provide a verifiable record of the build or publishing details. View details, limitations and caveats.

PyPI Publish Attestation

PyPI verified that this artifact, at this checksum, originated from the publisher listed below.

Signed by GitHub Actions, verified by PyPI on Jul 13, 2026.

Transparency log

Release history Release notifications | RSS feed

This release

0.1.0 This release

2 release files

Anthropic, PBC Visionary sponsor Bloomberg Visionary sponsor Hudson River Trading Visionary sponsor Meta Visionary sponsor NVIDIA Visionary sponsor Microsoft Sustainability sponsor Depot Continuous Integration AWS Cloud computing and Security Sponsor Datadog Monitoring Fastly CDN Google Download Analytics Sentry Error logging StatusPage Status page