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 userequest.body; in FastAPI useawait 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_baseURLs unless the host islocalhost/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-Keyon every mutating request; the same key is sent on every retry. - Retries attempt only on
5xx,429, and network errors. Never on other4xx.
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
hatchlingbuild backend, nosetup.pywith executable logic, no build/lifecycle hooks. Installingplaticocannot 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.
Release files for platico 0.1.0
For a detailed explanation of source distributions (sdists) and built distributions (wheels), please see the package formats documentation.
Source distribution (sdist)
| File | Size | Uploaded | |
|---|---|---|---|
| platico-0.1.0.tar.gz | 18.0 kB | Details |
Built distribution (wheel)
| File | Interpreter | ABI | Platform | Reset |
|---|---|---|---|---|
| platico-0.1.0-py3-none-any.whl | Python 3 | none | any | Details |
Total release size: 45.0 kB
Release files / platico-0.1.0.tar.gz
| Download URL | platico-0.1.0.tar.gz |
|---|---|
| Size | 18.0 kB |
| Tags | Source |
|
SHA-256 checksum How to use checksums |
aa7da1f8686411444e4f0d5499fdc56febac0406a4c5e34a06c302604c1c09d0
|
|
BLAKE2b-256 checksum How to use checksums |
37c0e64e1b67427a53b34a191ff5f678adfba96c365b6f4d679fed39b4c5d557
|
| Upload date | |
|
Uploaded using Trusted Publishing? What is trusted publishing? |
Yes |
| Uploaded via |
twine/6.1.0 CPython/3.12.9
|
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 Jun 12, 2026.
Transparency logRelease files / platico-0.1.0-py3-none-any.whl
| Download URL | platico-0.1.0-py3-none-any.whl |
|---|---|
| Size | 27.1 kB |
| Tags | Python 3 |
|
SHA-256 checksum How to use checksums |
f3904c4e9952c3dea51b0e0563dc7ba44846e2bc18dc042dd60881f1ff1103f5
|
|
BLAKE2b-256 checksum How to use checksums |
f54dd12c91d26fbe94769912ef013d8399675b69749c67cbde5df8a004f47d88
|
| Upload date | |
|
Uploaded using Trusted Publishing? What is trusted publishing? |
Yes |
| Uploaded via |
twine/6.1.0 CPython/3.12.9
|
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 Jun 12, 2026.
Transparency log