Skip to main content

Official Python SDK for the Postpin shipping-rate API

Project description

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

Project details


Download files

Download the file for your platform. If you're not sure which to choose, learn more about installing packages.

Source Distribution

postpin-0.1.0.tar.gz (13.1 kB view details)

Uploaded Source

Built Distribution

If you're not sure about the file name format, learn more about wheel file names.

postpin-0.1.0-py3-none-any.whl (14.5 kB view details)

Uploaded Python 3

File details

Details for the file postpin-0.1.0.tar.gz.

File metadata

  • Download URL: postpin-0.1.0.tar.gz
  • Upload date:
  • Size: 13.1 kB
  • Tags: Source
  • Uploaded using Trusted Publishing? Yes
  • Uploaded via: twine/6.1.0 CPython/3.13.12

File hashes

Hashes for postpin-0.1.0.tar.gz
Algorithm Hash digest
SHA256 ca340ffc906ae7f4e2b91442e2ed06e848b68c7e3f38ae4cd074271732c85289
MD5 3035ddd869422b1a04a3d53850ab7b8d
BLAKE2b-256 73df44677cbbe838675321aa6688d40ab883669829bfd4770dd8d0c20db6b6a0

See more details on using hashes here.

Provenance

The following attestation bundles were made for postpin-0.1.0.tar.gz:

Publisher: publish-python.yml on its-pradeependra/PostPin

Attestations: Values shown here reflect the state when the release was signed and may no longer be current.

File details

Details for the file postpin-0.1.0-py3-none-any.whl.

File metadata

  • Download URL: postpin-0.1.0-py3-none-any.whl
  • Upload date:
  • Size: 14.5 kB
  • Tags: Python 3
  • Uploaded using Trusted Publishing? Yes
  • Uploaded via: twine/6.1.0 CPython/3.13.12

File hashes

Hashes for postpin-0.1.0-py3-none-any.whl
Algorithm Hash digest
SHA256 928da641d6b6c9ee8fe0a746688ccfbb38e7c48891497cc4e1feece6f905e292
MD5 030b04035dfaf52873ee85caf3d8217d
BLAKE2b-256 fb8df8989ab7fcc67343650ae9fcfb73f628ece09bbb3136f34baad53ee92c18

See more details on using hashes here.

Provenance

The following attestation bundles were made for postpin-0.1.0-py3-none-any.whl:

Publisher: publish-python.yml on its-pradeependra/PostPin

Attestations: Values shown here reflect the state when the release was signed and may no longer be current.

Supported by

AWS Cloud computing and Security Sponsor Datadog Monitoring Depot Continuous Integration Fastly CDN Google Download Analytics Pingdom Monitoring Sentry Error logging StatusPage Status page