Skip to main content

A generated client

The Recurso Python client (package recurso, version 1.4.0) is generated by openapi-python-client. Its shape is deliberately different from the Node and Go SDKs: there are no resource objects like client.plans.create(...). Instead, every API operation is its own module with plain functions, and every request/response body is a model class.
If you’ve read the Node or Go guides, don’t translate them literally. The generated idiom is operation_module.sync(client=client, body=Model(...)). Follow the shapes on this page.

Install

The client isn’t on PyPI yet. Install it from a checkout of the recurso-python repo (which sits beside the other Recurso repos):
Requires Python 3.11+. The only runtime dependencies are httpx and attrs.

Construct a client

There are two client classes in the top-level recurso package. Use AuthenticatedClient for the API (every endpoint requires a key); Client is the unauthenticated variant.
base_url and token are the two arguments you need. Under the hood the client sends Authorization: Bearer <token> (the prefix defaults to "Bearer" and auth_header_name to "Authorization"). Point base_url wherever your API runs:
  • Recurso cloud: https://api.recurso.dev
  • Self-hosted: your own host, e.g. https://billing.internal.example.com
  • Local make demo stack: http://localhost:8080
The client is also a context manager, which reuses one underlying HTTP connection pool for a batch of calls:

The generated idiom

Each path + method becomes a module under recurso.api.<tag>. Import the module (not a symbol from it) and call one of its four functions. Request bodies are model classes under recurso.models.
Every operation module exposes four functions with the same arguments: Notes that trip people up:
  • client is always a keyword argument (client=client).
  • The request body is passed as body=...; path parameters like an id are positional (e.g. get_plan.sync(plan_id, client=client)).
  • Model classes are re-exported from recurso.models, so from recurso.models import CreatePlanRequest works. Enum fields have their own classes (e.g. CreatePlanRequestIntervalUnit.MONTH).
  • Optional fields default to UNSET (from recurso.types) — omit them and they aren’t sent.
  • Amounts are integers in the currency’s minor unit (2900 = $29.00).

End-to-end example

Create a plan, a customer, and a subscription, then read the plan back and list plans. IDs returned on models are uuid.UUID values and can be passed straight into the next request.
1

Create a plan

2

Create a customer

3

Create a subscription

customer_id and plan_id take UUID values — pass the IDs from the models you just created.
4

Read the plan back

Path parameters are positional. The single-resource GET wraps the object in a response envelope whose payload is on .data.
5

List plans

List operations take q, limit, and a 1-based page. The results live on .data.

Error handling

The client sets raise_on_unexpected_status=True (a deliberate deviation from the generator’s default), so the two failure modes are:
  • Documented non-2xx statuses (e.g. 400, 401, 404) do not raise. They parse into an Error model, so sync returns a union — for example Plan | Error | None. Guard with isinstance:
  • Undocumented statuses raise recurso.errors.UnexpectedStatus, which carries .status_code and .content:
To branch on the raw status yourself, use sync_detailed and read response.status_code (an http.HTTPStatus); the typed body, if any, is on response.parsed:
Network timeouts surface as httpx.TimeoutException.

Pagination

List operations accept limit and a 1-based page (plus an optional q search string); some also take a filter such as status. Page through by incrementing page until a short page comes back:

Idempotency

Mutating calls honor the Idempotency-Key header so a retry settles at most once. Attach it with with_headers, which returns a new client:

Async

Every operation has asyncio / asyncio_detailed twins with identical arguments. Use the client as an async context manager:

Next

Bill a customer

Customer → plan → subscription → first invoice, end to end.

Usage-based billing

Define a metric, record usage, and rate it.