Skip to main content

Recuut Python SDK

The base package is a framework-neutral client for Recuut's Merchant API.

pip install recuut
export RECUUT_API_KEY="recuut_test_..."
from recuut import Recuut
from recuut.merchant_api import TransactionFilter, TransactionStatus

with Recuut() as client:
    for transaction in client.transactions.list(
        max=100,
        page_size=50,
        filter=TransactionFilter(status=TransactionStatus.SUCCEEDED),
    ):
        print(transaction.id, transaction.status)

    for resource in client.resources.list(max=100, page_size=25):
        print(resource.id, resource.name)

The same namespaces are available asynchronously:

from recuut import AsyncRecuut
async with AsyncRecuut(api_key="recuut_live_...") as client:
    page = await client.payers.list(max=100, page_size=25)
    async for payer in page:
        print(payer.identifier, payer.created_at)

The top-level resource groups come from Merchant OpenAPI tags, while method names come from each operation ID: client.payers.list(), client.transactions.list(), client.transactions.get(), and client.resources.list(). A list call returns the first page immediately. Its items, count, resolved as_of, and nullable next describe that HTTP page. Iterate over the page to fetch later pages lazily; max bounds the total items yielded by that iterator. Generated filter objects contain backend-owned selection fields. page_size and order are sent to the backend, while max only limits SDK iteration.

Every operation accepts request_options with per-request headers and timeout. Use with_raw_response when successful HTTP metadata matters:

with Recuut() as client:
    response = client.resources.with_raw_response.list(
        page_size=25,
        request_options={"headers": {"X-Trace-ID": "trace-123"}},
    )
    print(response.status_code, response.headers, response.data.items)

Test and live isolation

The API key selects one environment. A recuut_test_* key sees only test resources, contracts, payers, and transactions, while a recuut_live_* key sees only live data. Equivalent resources may use the same immutable integration key in both environments even though their res_… and revision IDs differ. Client methods intentionally accept no organization or environment parameter.

Pull typed contracts

Configure the only directory the generator may manage:

[tool.recuut]
contracts-output-dir = "src/my_app/recuut_contracts"
recuut pull-contracts -v

The directory must be named recuut_contracts. Recuut creates one <integration_key>__generated.py module per integration and re-exports its public symbols from a generated __init__.py. Existing generated packages keep their module and symbol names when upgraded. Generated packages expose INTEGRATION_KEY and GENERATED_INTEGRATIONS while retaining RESOURCE_ID and GENERATED_RESOURCES.

Before creating, updating, or deleting managed files, the command prints a plan and asks for confirmation. --yes applies it non-interactively. --check never writes or prompts and exits unsuccessfully only when generated source has drifted. Files without Recuut's generated banner are never overwritten or deleted. The schema digest describes immutable revision value shapes and does not include mutable pricing policy.

RECUUT_API_URL defaults to https://api.recuut.com; set it, pass --api-url, or configure api-url under [tool.recuut] for local or staging use.

FastAPI

pip install "recuut[fastapi]"
from fastapi import FastAPI
from pydantic import BaseModel
from recuut import recuut
from my_app.recuut_contracts import TextGenerationPayment, TextGenerationV1

app = FastAPI()

class GenerateRequest(BaseModel):
    prompt: str

class GenerateResponse(BaseModel):
    text: str

@app.post("/generate")
@recuut(TextGenerationV1)
async def generate(
    payload: GenerateRequest,
    payment: TextGenerationPayment,
) -> GenerateResponse:
    payment.report(input_tokens=len(payload.prompt.split()))
    return GenerateResponse(text=payload.prompt.upper())

The decorator hides and injects payment, validates the request before access negotiation, relays a 402 challenge unchanged, completes a paid transaction, then attaches PAYMENT-RESPONSE and releases the protected result. Sync handlers run through FastAPI's thread pool. A returned 4xx or 5xx fails the transaction and reports only status, duration, media type, and response size when available. Response bodies and headers are never sent to recuut. Streaming responses are rejected in v1.

Django

pip install "recuut[django]"
from django.http import HttpRequest
from pydantic import BaseModel
from recuut.django import recuut
from my_app.recuut_contracts import TextGenerationPayment, TextGenerationV1

class GenerateRequest(BaseModel):
    prompt: str

class GenerateResponse(BaseModel):
    text: str

@recuut(TextGenerationV1)
async def generate(
    request: HttpRequest,
    payload: GenerateRequest,
    payment: TextGenerationPayment,
) -> GenerateResponse:
    payment.report(input_tokens=len(payload.prompt.split()))
    return GenerateResponse(text=payload.prompt.upper())

Django uses the same negotiation and completion client. It validates Pydantic payloads and responses, runs sync views through Django's thread-sensitive worker path, relays challenges, reports only safe response metadata, and rejects streaming before protected content is read.

Runtime and raw contracts

Framework integrations call the generated payments.access and transactions.complete façade methods. Generated payments validate exact value keys and decimal constraints before completion. For a revision that has not been pulled into your application, use the explicit escape hatch:

from recuut import RawPayment, RawRevision, recuut

@recuut(RawRevision("acr_00000000000070008000000000000000"))
async def raw_endpoint(payment: RawPayment) -> dict[str, bool]:
    payment.report({"items": 1})
    return {"ok": True}

Errors

Configuration problems raise RecuutConfigurationError, and network failures raise RecuutTransportError. Documented non-successful HTTP responses raise a generated RecuutResponseError; future statuses, undocumented error codes, and malformed payloads raise RecuutUnexpectedResponseError. Response errors retain the exact status, body, and headers so integrations can preserve protocol challenges.

Runnable examples

Each example is an independently locked consumer project kept beside the SDK:

Metadata

Release files for recuut 0.5.0

For a detailed explanation of source distributions (sdists) and built distributions (wheels), please see the package formats documentation.

Source distribution (sdist)

Source distribution for recuut 0.5.0
File Size Uploaded Provenance Actions
recuut-0.5.0.tar.gz 84.2 kB With provenance Details for recuut-0.5.0.tar.gz

Built distribution (wheel)

Table of built distributions (wheels) for recuut 0.5.0
File Interpreter ABI Platform Actions
recuut-0.5.0-py3-none-any.whl Python 3 none any Details for recuut-0.5.0-py3-none-any.whl

Total release size: 302.3 kB

Release files / recuut-0.5.0.tar.gz

Download URL recuut-0.5.0.tar.gz
Size 84.2 kB
Tags Source
SHA-256 checksum
How to use checksums
361ad0c1f40f999b58e57b5b30977950c5239268ecce4dd1667835de1ce58f30
BLAKE2b-256 checksum
How to use checksums
e4a820a80ce40b7f4291984499f82066cad89cf94cc154f37fa7fc2303057f45
Upload date
Uploaded using Trusted Publishing?
What is trusted publishing?
Yes
Uploaded via twine/7.0.0 CPython/3.13.14

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 Sep 9, 2026.

Transparency log

Release files / recuut-0.5.0-py3-none-any.whl

Download URL recuut-0.5.0-py3-none-any.whl
Size 218.1 kB
Tags Python 3
SHA-256 checksum
How to use checksums
67788651c22955eee3c5f2ada55db25bc3c3c18509871006e045a14b844df1d4
BLAKE2b-256 checksum
How to use checksums
7d0456715438ae408c2ce3b3f66f2e8b15088647febc9e85875ac7d979a62237
Upload date
Uploaded using Trusted Publishing?
What is trusted publishing?
Yes
Uploaded via twine/7.0.0 CPython/3.13.14

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 Sep 9, 2026.

Transparency log

Security for recuut 0.5.0

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.

Full provenance

All 2 files in this release have been uploaded with provenance metadata.

Select from 2 files

Attestation for recuut-0.5.0.tar.gz

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 Sep 9, 2026.

Transparency log

A note on package security

PyPI is a repository for distributing packages, not a service for auditing them. While third-party security researchers and our staff do their best to detect and remove malicious packages, PyPI cannot guarantee the quality, security or suitability of any given package.

To learn more about protecting yourself from malicious actors, visit our package security documentation.

Release history Release notifications | RSS feed

This release

0.5.0 This release

2 release files Full provenance

Anthropic, PBC Visionary sponsor Bloomberg Visionary sponsor Hudson River Trading Visionary sponsor Meta Visionary sponsor NVIDIA Visionary sponsor Microsoft Sustainability sponsor Depot Continuous Integration AWS Cloud computing and Security Sponsor Datadog Monitoring Fastly CDN Google Download Analytics Sentry Error logging StatusPage Status page