Skip to main content

Official Python SDK for the Platico payment API

Project description

platico — Python SDK

Official Python SDK for the Platico payment API. Stripe-shaped, zero runtime dependencies, Python 3.9+, fully typed (PEP 561).

Status: v0.1.0 — initial release. API surface stable enough to integrate against; minor versions may include breaking changes until v1.0.

Install

pip install platico

Requires Python 3.9 or newer. Zero runtime dependencies — the SDK uses only the standard library (urllib, ssl, hmac, json).

Quickstart

import os
from platico import Platico

client = Platico(os.environ["PLATICO_API_KEY"])

intent = client.payment_intents.create({
    "amount": 999,  # minor units — 9.99 RSD
    "currency": "rsd",
    "description": "Order #4581",
})

print(intent["id"], intent["status"])

Responses are plain dicts (typed as TypedDicts), so unknown new API fields never break your integration — access them as intent["id"].

Customers and saved cards

customer = client.customers.create({
    "email": "jane@example.com",
    "name": "Jane Doe",
})

# Walk every customer with auto-pagination — one page in memory at a time.
for c in client.customers.list():
    print(c["id"], c["email"])

# Or collect a bounded slice (limit is required — prevents accidental OOM):
first50 = client.customers.list().auto_paging_to_list(limit=50)

The same pagination shape works on every list endpoint: payment_intents.list, payment_methods.list, refunds.list, disputes.list, events.list, webhook_endpoints.list. The returned object is also a single page — read .data, .has_more, .url directly if that's all you need.

Webhook signature verification

from flask import Flask, request
from platico import construct_event
from platico import (
    WebhookSignatureInvalidError,
    WebhookTimestampStaleError,
    WebhookMalformedHeaderError,
)

app = Flask(__name__)
WEBHOOK_SECRET = os.environ["PLATICO_WEBHOOK_SECRET"]

@app.post("/webhooks/platico")
def webhook():
    try:
        event = construct_event(
            request.get_data(),  # RAW bytes — NOT request.json
            request.headers.get("Platico-Signature", ""),
            WEBHOOK_SECRET,
        )
    except (
        WebhookSignatureInvalidError,
        WebhookTimestampStaleError,
        WebhookMalformedHeaderError,
    ) as err:
        return str(err), 400

    # event is parsed and verified — safe to act on
    print(event["type"], event["data"]["object"])
    return "", 200

IMPORTANT: webhooks need the raw request body bytes. JSON body parsers re-serialize the payload, which changes the bytes and breaks the HMAC. In Flask use request.get_data(); in Django use request.body; in FastAPI use await request.body().

Configuration

Platico(
    api_key,
    api_base="https://api.platico.rs",  # default
    timeout=30.0,                        # seconds, default
    max_network_retries=3,               # retries on 5xx / 429 / network only
    telemetry=False,                     # opt-in only
)

Environment variables: PLATICO_API_BASE overrides the base URL, PLATICO_CLIENT_TELEMETRY=true opts into telemetry. The API key is passed explicitly (read it from PLATICO_API_KEY yourself — the SDK never reads a key from the environment implicitly).

Error handling

from platico import CardError, RateLimitError, ApiError

try:
    client.payment_intents.create({"amount": 999, "currency": "rsd", "confirm": True})
except CardError as err:
    print("Declined:", err.code, err.decline_code)
except RateLimitError as err:
    print("Slow down, retry after:", err.retry_after)
except ApiError as err:
    print(err.status_code, err.code, err.request_id)

Error objects never carry your API key, the request/response body, headers, or a stack trace — err.to_dict(), repr(err), and logging are all leak-safe.

Security

  • The SDK refuses non-HTTPS api_base URLs unless the host is localhost / 127.0.0.1 / ::1.
  • TLS is always verified (certificate chain + hostname) via the system trust store. There is no option to disable it.
  • API keys are never written to logs or attached to error objects (not even via a traceback or pickle).
  • Webhook signature verification uses hmac.compare_digest (constant time) with replay protection — rejects both stale and future-dated timestamps.
  • Auto-generated Idempotency-Key on every mutating request; the same key is sent on every retry.
  • Retries attempt only on 5xx, 429, and network errors. Never on other 4xx.

Report security issues to security@platico.rs. See SECURITY.md.

Supply-chain trust

  • Zero runtime dependencies — imports only the Python standard library. No transitive surface to audit.
  • No install-time code — declarative hatchling build backend, no setup.py with executable logic, no build/lifecycle hooks. Installing platico cannot run arbitrary code.
  • PyPI Trusted Publishing (OIDC) + PEP 740 attestations — from the first CI-published release, every artifact is linked to the exact GitHub Actions run and commit SHA that built it. No long-lived publish token exists.
  • Artifact file allowlist — the wheel/sdist contain only the source package, README, LICENSE, and CHANGELOG. Asserted in CI before every publish.
  • Pinned GitHub Actions — every workflow uses: pins a full commit SHA.

Detailed posture in SECURITY.md.

License

Proprietary. See LICENSE.

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

platico-0.1.0.tar.gz (18.0 kB view details)

Uploaded Source

Built Distribution

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

platico-0.1.0-py3-none-any.whl (27.1 kB view details)

Uploaded Python 3

File details

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

File metadata

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

File hashes

Hashes for platico-0.1.0.tar.gz
Algorithm Hash digest
SHA256 aa7da1f8686411444e4f0d5499fdc56febac0406a4c5e34a06c302604c1c09d0
MD5 38ed540f9ec7ff40244036f5168a0ad9
BLAKE2b-256 37c0e64e1b67427a53b34a191ff5f678adfba96c365b6f4d679fed39b4c5d557

See more details on using hashes here.

Provenance

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

Publisher: publish-python.yml on StonyAiHub/platico-sdks

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

File details

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

File metadata

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

File hashes

Hashes for platico-0.1.0-py3-none-any.whl
Algorithm Hash digest
SHA256 f3904c4e9952c3dea51b0e0563dc7ba44846e2bc18dc042dd60881f1ff1103f5
MD5 2c82e9525655fb5e6e3c187d8f7c201d
BLAKE2b-256 f54dd12c91d26fbe94769912ef013d8399675b69749c67cbde5df8a004f47d88

See more details on using hashes here.

Provenance

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

Publisher: publish-python.yml on StonyAiHub/platico-sdks

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