recuut Python SDK
The base package is a framework-neutral client for recuut's Merchant API.
pip install "recuut>=0.11.0"
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:
import asyncio
from recuut import AsyncRecuut
async def main() -> None:
async with AsyncRecuut() as client:
page = await client.payers.list(max=100, page_size=25)
async for payer in page:
print(payer.identifier, payer.created_at)
asyncio.run(main())
Client methods include: client.payers.list(),
client.transactions.list(), client.transactions.get(),
client.resources.list(), client.contracts.list(), and
client.payments.access(). 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)
Receipts
ReceiptDocument exposes fields directly, such as receipt.id and
receipt.payment. The SDK validates the receipt against its transaction.
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 share an immutable resource
key and public rvk_… revision key. Their res_… Resource IDs and internal
revision rows remain separate. 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 = "recuut_contracts"
recuut pull-contracts -v
The directory must be named recuut_contracts. recuut creates one
<resource_key>__generated.py module per resource 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
RESOURCE_KEY and GENERATED_RESOURCES. They bind revisions by the
public rvk_… ID without embedding an environment-specific Resource ID.
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 when generated source has
drifted. Authentication, connection, or schema errors also fail the command.
Files without recuut's generated banner are never overwritten or
deleted. The check covers every published revision visible to the key. The
schema digest describes immutable revision value shapes and does not include
environment-specific Resource IDs or 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.
Input and output variable values must be non-negative integers, including zero. Use Python integers or canonical digit strings with at most 18 digits. Decimal values, floats, booleans, signs and exponents are rejected. Prices retain their decimal precision.
FastAPI
pip install "recuut[fastapi]>=0.11.0"
from typing import Self
from fastapi import FastAPI
from pydantic import BaseModel, Field, model_validator
from recuut.fastapi import recuut
from recuut_contracts import (
TextGenerationV1,
TextGenerationV1Payment,
)
app = FastAPI()
class GenerateRequest(BaseModel):
prompt: str
input_tokens: int = Field(
default=0,
exclude=True,
ge=0,
json_schema_extra={"readOnly": True},
)
@model_validator(mode="after")
def derive_input_tokens(self) -> Self:
self.input_tokens = len(self.prompt.split())
return self
class GenerateResponse(BaseModel):
text: str
@app.post("/generate")
@recuut(TextGenerationV1)
def generate(
payload: GenerateRequest,
payment: TextGenerationV1Payment,
) -> GenerateResponse:
text = payload.prompt.upper()
return payment.complete(
GenerateResponse(text=text),
output_tokens=len(text.split()),
)
Generated Payment complete(...) and acomplete(...) methods require every handler-reported value, so mypy
and Pyright reject an omitted or misspelled keyword. Values marked as request
input are captured from an exact handler argument, one nested Pydantic field,
or an explicit input_map. Every input variable must be captured before access;
invalid or missing captured values return 422 before any payment request. For revisions
without input keys, the access dependency can relay a 402 challenge before FastAPI
validates a required body. The decorator leaves validated application inputs
unchanged. complete prepares and validates the response before settlement; the decorator releases that prepared response and attaches
PAYMENT-RESPONSE. 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 not supported.
Django REST Framework
pip install "recuut[django]>=0.11.0" djangorestframework
Use your normal serializer and view. Validate before payment access; save only after access succeeds.
from dataclasses import dataclass
from recuut.django import recuut
from rest_framework import serializers
from rest_framework.decorators import api_view
from rest_framework.response import Response
from recuut_contracts import TextGenerationV1, TextGenerationV1Payment
@dataclass
class GenerateResult:
text: str
output_tokens: int
class GenerateSerializer(serializers.Serializer):
prompt = serializers.CharField(max_length=10_000, write_only=True)
text = serializers.CharField(read_only=True)
def create(self, validated_data) -> GenerateResult:
# Replace this sample with your logic and measured usage.
text = validated_data["prompt"].upper()
return GenerateResult(text=text, output_tokens=len(text.split()))
@api_view(["POST"])
@recuut(TextGenerationV1)
def generate(request, payment: TextGenerationV1Payment) -> Response:
serializer = GenerateSerializer(data=request.data)
serializer.is_valid(raise_exception=True)
refusal = payment.access(input_tokens=len(serializer.validated_data["prompt"].split()))
if refusal is not None:
return refusal
result = serializer.save()
return payment.complete(Response(serializer.data), output_tokens=result.output_tokens)
@recuut binds payment to the request. After access succeeds, it reports failure if the view raises or returns 4xx/5xx.
A refusal is a native HTTP response; return it immediately. complete() finalizes
and renders the response before settlement, attaches the receipt, and returns
the native response. Put the same decorator directly on APIView.post() for a
class-based view. Preserve your existing authentication, permissions, and CSRF policy.
Plain Django views are also supported. They retain their application's request
parsing and validation. Sync views use access() / complete(); async Django
views use await aaccess() / await acomplete(). DRF examples use sync views.
Streaming responses are unsupported.
Shared payment lifecycle
Django and FastAPI use the same authorization, completion and failure policy. Framework adapters own request headers and final response preparation. FastAPI captures validated inputs automatically; Django supplies them explicitly after its normal validation. Completion happens once, after response validation and rendering. Success is not released until recuut returns a successful receipt.
Pulled contracts expose typed access, aaccess, complete, and acomplete
methods. Both completion methods return the supplied native Django response or
typed FastAPI value while the FastAPI decorator releases the
prepared response. Every reported field remains a required completion keyword.
Pull contracts again when upgrading. Previously generated RecuutResult
completion helpers remain supported by their existing decorated handlers.
For a revision that has not been pulled, use the explicit mapping fallback:
from recuut import RawPayment, RawRevision
from recuut.fastapi import recuut
from fastapi import FastAPI
app = FastAPI()
revision = RawRevision(revision_key="rvk_00000000000070008000000000000000")
@app.post("/raw")
@recuut(revision)
def raw_endpoint(payment: RawPayment) -> dict[str, bool]:
return payment.complete({"ok": True}, values={"items": 1})
Errors
Invalid contract construction raises RecuutConfigurationError. Detectable
decorator configuration problems warn by default or raise in strict mode.
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.11.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 | Provenance | Actions |
|---|---|---|---|---|
| recuut-0.11.0.tar.gz | 96.3 kB | With provenance | Details for recuut-0.11.0.tar.gz |
Built distribution (wheel)
| File | Interpreter | ABI | Platform | Actions Reset |
|---|---|---|---|---|
| recuut-0.11.0-py3-none-any.whl | Python 3 | none | any | Details for recuut-0.11.0-py3-none-any.whl |
Total release size: 327.8 kB
Release files / recuut-0.11.0.tar.gz
| Download URL | recuut-0.11.0.tar.gz |
|---|---|
| Size | 96.3 kB |
| Tags | Source |
|
SHA-256 checksum How to use checksums |
6af034a54db113aa14147244aa24a95eb0084dc157676d277e557280832ee312
|
|
BLAKE2b-256 checksum How to use checksums |
bb402ca25bbb9fa7a8ecef8f561c436ecb4df430c4e357695de707541089eb0f
|
| 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 Oct 6, 2026.
Transparency logRelease files / recuut-0.11.0-py3-none-any.whl
| Download URL | recuut-0.11.0-py3-none-any.whl |
|---|---|
| Size | 231.5 kB |
| Tags | Python 3 |
|
SHA-256 checksum How to use checksums |
cd3d427398eab51e330f94b4b589c1ceb72e22651352ab37d13a7ddaecfab955
|
|
BLAKE2b-256 checksum How to use checksums |
4f2b0f32d6fc8e65265582898302c29e4cb793c2ac1ffc3122ffbdd49224a732
|
| 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 Oct 6, 2026.
Transparency logSecurity for recuut 0.11.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.
Attestation for recuut-0.11.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 Oct 6, 2026.
Transparency logA 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.