Unofficial Python client for the Presscart API.
Project description
pypresscart — A Python Library for the Presscart API
📚 Documentation · PyPI · Issues
⚠️ Unofficial library. This project is not affiliated with, endorsed by, or supported by Presscart. It's a community-maintained Python client for the Presscart API.
- Pythonic, typed resource methods (
client.outlets.list(...),client.orders.create_checkout(...), ...) - Dual-mode: pass Pydantic models or plain dicts; get Pydantic models or plain dicts back
- Single dependency stack —
requests+pydantic - Built-in exponential-backoff retry for
429/5xxresponses, honoringRetry-After - Typed exception hierarchy (
BadRequestError,AuthenticationError,RateLimitError, ...)
Install
uv add pypresscart
# or
pip install pypresscart
Python 3.10+.
Quickstart
from pypresscart import PresscartClient
client = PresscartClient(api_token="pc_...")
me = client.auth.whoami()
print(me.team_id, me.scopes)
outlets = client.outlets.list(limit=5, filters={"country": "United States"})
for row in outlets.records:
print(row.outlet_name, row.website_url)
Dual-mode usage
The library accepts both Pydantic models and raw dicts on the way in, and returns either on the way out.
from pypresscart import CheckoutLineItem, CheckoutRequest, PresscartClient
client = PresscartClient(api_token="pc_...")
# Pydantic in, Pydantic out (default)
order = client.orders.create_checkout(
CheckoutRequest(
profile_id="YOUR_PROFILE_ID",
line_items=[CheckoutLineItem(product_id="YOUR_PRODUCT_ID", quantity=1)],
)
)
print(order.reference_number)
# Dict in, dict out
raw = client.orders.create_checkout(
{
"profile_id": "YOUR_PROFILE_ID",
"line_items": [
{"product_id": "YOUR_PRODUCT_ID", "quantity": 1, "is_add_on": False}
],
"discount": 0,
},
as_json=True,
)
print(raw["reference_number"])
You can also set the default for the whole client:
client = PresscartClient(api_token="pc_...", response_mode="json")
Per-call as_json=True / as_json=False always wins over the client default.
Error handling
from pypresscart import (
AuthenticationError,
NotFoundError,
PresscartAPIError,
RateLimitError,
ValidationError,
)
try:
client.campaigns.get("missing")
except NotFoundError as exc:
print("not found:", exc.message)
except AuthenticationError:
print("token invalid or expired")
except RateLimitError as exc:
print("slow down; retry after", exc.retry_after)
except ValidationError as exc:
for issue in exc.issues:
print("field", issue["path"], issue["message"])
except PresscartAPIError as exc:
print(exc.status_code, exc.name, exc.message, exc.payload)
All API errors inherit from PresscartAPIError. Network-level failures raise
PresscartTransportError (wrapping the underlying requests exception).
Client options
| Parameter | Default | Description |
|---|---|---|
api_token |
(required) | Bearer token (pc_...) |
base_url |
https://api.presscart.com |
API origin |
timeout |
30.0 |
Per-request timeout (seconds) |
max_retries |
3 |
Additional attempts on 429/5xx/network errors |
retry_backoff_base |
0.25 |
Base backoff seconds |
retry_backoff_max |
4.0 |
Backoff cap |
retry_jitter |
0.1 |
Fractional jitter |
response_mode |
"pydantic" |
"pydantic" or "json" |
user_agent |
"pypresscart/<version>" |
User-Agent header |
session |
None |
Inject a pre-configured requests.Session |
Use as a context manager to close the session automatically:
with PresscartClient(api_token="pc_...") as client:
...
Endpoints
Every endpoint documented at docs.presscart.com is covered by a method on one of the resource services:
| Service | Methods |
|---|---|
client.auth |
whoami |
client.outlets |
list, get, list_products, list_countries, list_states, list_cities, list_tags, list_disclaimers |
client.products |
get, list_listings, list_categories |
client.orders |
list, get, create_checkout |
client.order_items |
list |
client.profiles |
list_team_profiles, list_orders, list_order_items, list_campaigns |
client.campaigns |
list, get, create, update, list_articles, article_status_counts, assign_order_items, link_questionnaire |
client.articles |
get, update, approve_brief, approve_draft |
client.files |
list, get, upload, download, move, delete |
client.folders |
list, create, rename, delete |
Each method's docstring includes the required token scope.
Documentation
Full documentation lives at https://pypresscart.github.io/py-presscart/ — Sphinx site built from docs/ and deployed automatically by .github/workflows/docs.yml on every push to main.
Build locally:
uv sync --group docs
uv run sphinx-build -b html -n -W --keep-going docs docs/_build/html
open docs/_build/html/index.html
# Or with live reload:
uv run sphinx-autobuild docs docs/_build/html --watch src/pypresscart
Development
uv sync --group dev
uv run pytest -v
uv run ruff check .
uv run ruff format --check .
uv run mypy src
uv build
Pre-commit hooks
This repo ships a .pre-commit-config.yaml with ruff,
mypy, whitespace/EOL/yaml/toml checks, and a pytest hook on pre-push.
uv run pre-commit install # ruff + mypy on every commit
uv run pre-commit install --hook-type pre-push # pytest on every push
uv run pre-commit run --all-files # run everything now
Branch protection
main is protected — no direct pushes. Every change goes through a pull
request that must pass CI (ruff, ruff format, mypy, pytest on Python 3.10
through 3.13, and the distribution build) before it can merge. Force-pushes
and branch deletion are denied.
Releasing
Releases are cut by a human via the Release GitHub Actions workflow, which
uses OIDC trusted publishing — no PyPI tokens are stored anywhere.
Prerequisites (one-time)
- Project
pypresscartregistered as a trusted publisher on both PyPI and TestPyPI, pointing at this repo + workflowrelease.yml+ environmentspypi/testpypi. - GitHub repo environments
pypiandtestpypiexist. Optionally add required reviewers onpypiif you want a human to approve every prod publish.
Cutting a new release
-
Decide the version. Follow SemVer:
MAJOR— anything that could break existing callers (renames, removed fields, changed defaults, raised minimum Python).MINOR— backwards-compatible additions (new endpoints, new optional parameters).PATCH— bug fixes only.
-
Open a bump PR. On a branch, update both:
src/pypresscart/_version.py—__version__ = "X.Y.Z"pyproject.toml—[project].version = "X.Y.Z"
Also add an entry to
docs/changelog.mdunder## [Unreleased]and roll it into a new## [X.Y.Z] — <date>heading. -
Merge the PR. Wait for CI to go green, then merge. The docs site rebuilds and picks up the new version string automatically.
-
Publish to TestPyPI first. Actions → Release → Run workflow → pick
testpypi→ run. Wait for green. -
Smoke-test from TestPyPI in a throwaway environment:
uv run --no-project \ --with pypresscart==X.Y.Z \ --index-url https://test.pypi.org/simple/ \ --extra-index-url https://pypi.org/simple/ \ python -c "from pypresscart import PresscartClient, __version__; print(__version__)"
-
Publish to PyPI. Actions → Release → Run workflow → pick
pypi→ run. (If you added required reviewers on thepypienvironment, approve the deployment when prompted.) -
Tag and announce.
git tag -a vX.Y.Z -m "pypresscart X.Y.Z" git push origin vX.Y.Z gh release create vX.Y.Z \ --title "pypresscart X.Y.Z" \ --notes-file <(awk '/^## \[X\.Y\.Z\]/,/^## \[/' docs/changelog.md | sed '$d')
If something goes wrong
- Published a broken version? You can't overwrite a PyPI release. Cut a
new patch release (
X.Y.Z+1) that reverts or fixes the issue.yankon PyPI hides the broken version from resolvers but keeps it available to pinned installs. - TestPyPI upload failed but PyPI didn't run? Re-dispatch with
target=testpypi. The workflow hasskip-existing: trueon TestPyPI so re-uploading the same version is a no-op. - Trusted publisher rejected the OIDC token? Confirm the pending
publisher on PyPI has the exact workflow filename (
release.yml) and environment name (pypi/testpypi). One-character typos fail silently.
License
MIT — see LICENSE.
Presscart™ and the Presscart logo are trademarks of their respective owners. This library is an independent, unofficial client.
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
Built Distribution
Filter files by name, interpreter, ABI, and platform.
If you're not sure about the file name format, learn more about wheel file names.
Copy a direct link to the current filters
File details
Details for the file pypresscart-0.1.2.tar.gz.
File metadata
- Download URL: pypresscart-0.1.2.tar.gz
- Upload date:
- Size: 25.7 kB
- Tags: Source
- Uploaded using Trusted Publishing? Yes
- Uploaded via: twine/6.1.0 CPython/3.13.12
File hashes
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
6125181f1a8451d55922ed4c21e9bedc857e93019fe4131c90b0f9f6643032a3
|
|
| MD5 |
a0e23cbc83303affd44e9b116d273fe1
|
|
| BLAKE2b-256 |
e75f0f41c8174dce95b448ea8e07744fbd7eb04ce7429422298947de9caee927
|
Provenance
The following attestation bundles were made for pypresscart-0.1.2.tar.gz:
Publisher:
release.yml on pypresscart/py-presscart
-
Statement:
-
Statement type:
https://in-toto.io/Statement/v1 -
Predicate type:
https://docs.pypi.org/attestations/publish/v1 -
Subject name:
pypresscart-0.1.2.tar.gz -
Subject digest:
6125181f1a8451d55922ed4c21e9bedc857e93019fe4131c90b0f9f6643032a3 - Sigstore transparency entry: 1338584663
- Sigstore integration time:
-
Permalink:
pypresscart/py-presscart@8cf3ae3e19f895cc6d3f721cac230a53c1edc38d -
Branch / Tag:
refs/heads/main - Owner: https://github.com/pypresscart
-
Access:
public
-
Token Issuer:
https://token.actions.githubusercontent.com -
Runner Environment:
github-hosted -
Publication workflow:
release.yml@8cf3ae3e19f895cc6d3f721cac230a53c1edc38d -
Trigger Event:
workflow_dispatch
-
Statement type:
File details
Details for the file pypresscart-0.1.2-py3-none-any.whl.
File metadata
- Download URL: pypresscart-0.1.2-py3-none-any.whl
- Upload date:
- Size: 35.8 kB
- Tags: Python 3
- Uploaded using Trusted Publishing? Yes
- Uploaded via: twine/6.1.0 CPython/3.13.12
File hashes
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
372bebc0f9957a9b36a5087a96a6d5fb066fdc7611aaa7fccad0f1573739bf97
|
|
| MD5 |
4b7dc875b117a129d4b7e82dc12a81d5
|
|
| BLAKE2b-256 |
a920602e14cc177af09dc7c6e1df1466a831b6ef5d2ca331cf0f3724f74a6906
|
Provenance
The following attestation bundles were made for pypresscart-0.1.2-py3-none-any.whl:
Publisher:
release.yml on pypresscart/py-presscart
-
Statement:
-
Statement type:
https://in-toto.io/Statement/v1 -
Predicate type:
https://docs.pypi.org/attestations/publish/v1 -
Subject name:
pypresscart-0.1.2-py3-none-any.whl -
Subject digest:
372bebc0f9957a9b36a5087a96a6d5fb066fdc7611aaa7fccad0f1573739bf97 - Sigstore transparency entry: 1338584679
- Sigstore integration time:
-
Permalink:
pypresscart/py-presscart@8cf3ae3e19f895cc6d3f721cac230a53c1edc38d -
Branch / Tag:
refs/heads/main - Owner: https://github.com/pypresscart
-
Access:
public
-
Token Issuer:
https://token.actions.githubusercontent.com -
Runner Environment:
github-hosted -
Publication workflow:
release.yml@8cf3ae3e19f895cc6d3f721cac230a53c1edc38d -
Trigger Event:
workflow_dispatch
-
Statement type: