Django
Use the maintained Django integration to protect a view and keep its result private until payment completes.
Use Python 3.11 through 3.14. From an empty directory, create and activate a virtual environment:
python -m venv .venv. .venv/bin/activateInstall the Django extra, then create a project with an api application:
pip install "recuut[django]"django-admin startproject my_app .python manage.py startapp apiSet the merchant test key in your server environment; the SDK reads RECUUT_API_KEY automatically unless you pass a client or api_key to the decorator.
export RECUUT_API_KEY="recuut_test_..."Before choosing a contract setup, complete step 1 of the Direct HTTP guide to create and publish the resource, revision, Price, and test key. You do not need to build its raw HTTP server.
Choose your contract setup
Generate a contract when your application can commit generated files. This keeps the revision ID and reporting fields in checked Python types.
After you publish the revision, add this output location to your project pyproject.toml:
[tool.recuut]contracts-output-dir = "my_app/recuut_contracts"Then pull the revision contract. The generated payment type makes the reporting fields part of the Python function signature, so a missing or misspelled field is caught by your type checker.
recuut pull-contracts -vAdd this typed view to api/views.py. TextGenerationV1 and TextGenerationPayment stand for the names generated for your published revision.
from django.http import HttpRequestfrom pydantic import BaseModelfrom recuut.django import recuutfrom my_app.recuut_contracts import TextGenerationPayment, TextGenerationV1class GenerateRequest(BaseModel): prompt: strclass GenerateResponse(BaseModel): text: str@recuut(TextGenerationV1)async def generate( request: HttpRequest, payload: GenerateRequest, payment: TextGenerationPayment,) -> GenerateResponse: text = payload.prompt.upper() payment.report( input_tokens=len(payload.prompt.split()), output_tokens=len(text.split()), ) return GenerateResponse(text=text)payment.report(input_tokens=..., output_tokens=...) is typed from that revision. The SDK validates the values again when it completes the transaction.
Register the view in api/urls.py:
from django.urls import pathfrom .views import generateurlpatterns = [path("generate", generate)]Include those application routes from the project URL configuration:
from django.urls import include, pathurlpatterns = [path("", include("api.urls"))]Start Django from the directory containing manage.py:
python manage.py runserverCheck the unpaid path before you use a wallet:
curl --include \ --request POST \ --url http://127.0.0.1:8000/generate \ --header 'Content-Type: application/json' \ --data '{"prompt":"paid testnet response"}'Expect HTTP 402, a PAYMENT-REQUIRED header, and no uppercase result. If the response differs, verify the published revision, active Price, Require payment setting, and test key before continuing.
The integration validates normal input before it asks Recuut for access. A successful paid request completes payment before it returns the view result with PAYMENT-RESPONSE. HTTP 202 remains private. A returned 4xx or 5xx response fails the transaction and reports only its status, duration, media type, and byte size. The response body and headers are not sent to recuut.
Use the wallet and Circle faucet preflight, then run the paid AWAL retry against this same URL. The receipt check is identical.