# Try an example (/guides/example)

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](/guides/setup/).

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`.

```bash
pip install "recuut[fastapi]>=0.11.0"
```

```bash
export RECUUT_API_KEY="recuut_test_..."
```

Generate the example for your published revision:

```bash
recuut example fastapi --revision rvk_... --output ./recuut-example
```

The 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:

```bash
cd recuut-example && \
  python -m pip install -e . && \
  python -m uvicorn app:app --reload
```

Your generated `app.py` is similar to the following. Class names, `input_map`, and `complete(...)` arguments come from your revision.

```python title="app.py"
"""Simulated FastAPI endpoint protected by one published Recuut revision."""

from typing import Any, Self

from fastapi import FastAPI
from pydantic import BaseModel, Field, model_validator
from recuut.fastapi import recuut
from recuut_contracts import TextGenerationV1, TextGenerationV1Payment


class 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 self


class ExampleResponse(BaseModel):
    text: str


app = 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:

```bash
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](/guides/test-paid-request/) against `http://127.0.0.1:8000/example`.

To protect your own application, [pull contracts](/guides/pull-contracts/) for Python, or continue with the [Direct HTTP integration](/guides/http/) for any other server stack.
