Try an example
Optionally generate a runnable FastAPI app for your published revision before you change your own application.
This step is optional. recuut example writes a standalone FastAPI project for one published revision, so you can see a working paid endpoint before you protect your own route.
The command needs a published revision and a merchant test key from Set up your product.
Install the FastAPI extra in your Python environment and set the merchant key. The SDK uses https://api.recuut.com by default, so the usual path needs only RECUUT_API_KEY.
pip install "recuut[fastapi]>=0.11.0"export RECUUT_API_KEY="recuut_test_..."Generate the example for your published revision:
recuut example fastapi --revision rvk_... --output ./recuut-exampleThe command creates a new recuut-example directory containing app.py, a generated recuut_contracts package, pyproject.toml, and a README. It refuses to overwrite an existing path. If your revision belongs to a local, staging, or preview API, add --api-url https://your-api-origin to the command. The generated endpoint will use that same API origin.
From the generated directory, install its dependencies and start the server:
cd recuut-example && \ python -m pip install -e . && \ python -m uvicorn app:app --reloadYour generated app.py is similar to the following. Class names, input_map, and complete(...) arguments come from your revision.
"""Simulated FastAPI endpoint protected by one published Recuut revision."""from typing import Any, Selffrom fastapi import FastAPIfrom pydantic import BaseModel, Field, model_validatorfrom recuut.fastapi import recuutfrom recuut_contracts import TextGenerationV1, TextGenerationV1Paymentclass ExampleRequest(BaseModel): prompt: str = Field(min_length=1, max_length=10_000) # Usage is derived on the server; it is not request data. simulated_input_tokens: int = Field( default=0, exclude=True, ge=0, json_schema_extra={"readOnly": True} ) @model_validator(mode="before") @classmethod def reject_client_usage(cls, value: Any) -> Any: if isinstance(value, dict) and any( name in value for name in ("simulated_input_tokens",) ): raise ValueError("Usage is set by the server.") return value @model_validator(mode="after") def derive_usage(self) -> Self: # Simulated value for each contract input. self.simulated_input_tokens = 1 return selfclass ExampleResponse(BaseModel): text: strapp = FastAPI(title="Recuut FastAPI example")@app.post("/example")@recuut(TextGenerationV1, input_map={"input_tokens": "payload.simulated_input_tokens"})def example( payload: ExampleRequest, payment: TextGenerationV1Payment,) -> ExampleResponse: # These values are illustrative. # Replace them with real server measurements. return payment.complete( ExampleResponse(text=payload.prompt.upper()), output_tokens=1, )The example uppercases prompt and uses simulated value 1 for every contract input and reported value. The server sets those values; the request cannot set them. Replace the simulated handler and values with your application's real work and measurements before using the endpoint for real billing.
Once the server runs, send a request from another terminal:
curl --include \ --request POST \ --url http://127.0.0.1:8000/example \ --header 'Content-Type: application/json' \ --data '{"prompt":"hello world"}'For a paid revision, expect HTTP 402 with PAYMENT-REQUIRED and no uppercase result. If it differs, check the published revision, active Price, Require payment setting, and test key.
Then test a paid request against http://127.0.0.1:8000/example.
To protect your own application, pull contracts for Python, or continue with the Direct HTTP integration for any other server stack.