> ## Documentation Index
> Fetch the complete documentation index at: https://docs.recovea.ai/llms.txt
> Use this file to discover all available pages before exploring further.

# Quickstart

Change one base URL and send one request: the headers that come back, the first receipt, and what an armed cap answers.

Recovea is an in-path gateway. You keep your provider account, your SDK, your models and your request shape; you change the base URL your SDK calls and the key it sends. Every request that goes through the gateway is metered and written as a receipt, and a cap you arm is enforced before your provider is called.

## Before you start

- **An organization.** Sign up at [platform.recovea.ai](https://platform.recovea.ai/signup). The platform is [platform.recovea.ai](https://platform.recovea.ai).
- **A Recovea key.** In the platform, **Settings → Organization → API keys → Mint key**. The secret starts `rcv_live_` and is shown once: *"Recovea stores a hash of this key, never the secret itself."* Put it in your environment as `RECOVEA_API_KEY`.
- **Your provider key**, added once on the same page under **Provider keys → Add provider key**. The platform calls your provider with it before it is saved, and then it is *"Sealed with envelope encryption at rest. Plaintext only in flight to your provider."*

Your code sends the Recovea key. The gateway signs the call to your provider with the provider key it holds for your organization.

## OpenAI-compatible SDKs

The OpenAI clients keep the `/v1` they already use. The base URL is the only change.

```python
import os
from openai import OpenAI

client = OpenAI(
    api_key=os.environ["RECOVEA_API_KEY"],
    base_url="https://api.recovea.ai/v1",   # the only change
)
```

```ts
import OpenAI from "openai"

const client = new OpenAI({
  apiKey: process.env.RECOVEA_API_KEY,
  baseURL: "https://api.recovea.ai/v1",  // the only change
})
```

Send one request. `-D -` prints the response headers above the body.

```bash
curl -sS -D - https://api.recovea.ai/v1/chat/completions \
  -H "Authorization: Bearer $RECOVEA_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{"model":"gpt-4o","messages":[{"role":"user","content":"ping"}]}'
```

Every path under `/v1` is forwarded as it arrives: `/v1/chat/completions`, `/v1/responses`, `/v1/embeddings` and any endpoint your provider adds. One change is made to one kind of request: a streaming `/v1/chat/completions` request that says nothing about `stream_options` is sent with `"stream_options":{"include_usage":true}` added, so the stream reports its token counts. The usage chunk comes back to you as your provider sent it. A request that sets `stream_options` in any form, including `"include_usage": false`, is forwarded untouched.

## Anthropic SDKs

The Anthropic clients take the bare host, with no `/v1`. Both wire formats are served on the same host because their paths do not overlap: `/v1/messages` is Anthropic's.

```python
import os
from anthropic import Anthropic

client = Anthropic(
    api_key=os.environ["RECOVEA_API_KEY"],
    base_url="https://api.recovea.ai",   # the only change
)
```

The SDK sends the key in `x-api-key`, the way it does with Anthropic.

```bash
curl -sS -D - https://api.recovea.ai/v1/messages \
  -H "x-api-key: $RECOVEA_API_KEY" \
  -H "anthropic-version: 2023-06-01" \
  -H "content-type: application/json" \
  -d '{"model":"claude-sonnet-4-5","max_tokens":64,"messages":[{"role":"user","content":"ping"}]}'
```

An integration written against `https://api.recovea.ai/anthropic` keeps working. It is a deprecated alias for the same surface.

## Any other OpenAI-compatible endpoint

A destination you declare is reached through its own prefix, `https://api.recovea.ai/upstream/v1`. Traffic sent to `/v1` never moves to it: the destination is decided by the request path.

1. In **Settings → Organization → API keys**, under **Your upstream**, give the destination a name and its `https` address, and save it.
2. Connect its key. The platform calls the destination with the key and keeps the key only if the destination answers.
3. **Start sending traffic.** The section reads **Live**.

```python
client = OpenAI(
    api_key=os.environ["RECOVEA_API_KEY"],
    base_url="https://api.recovea.ai/upstream/v1",
)
```

Requests through it are metered and capped like the rest. The receipt carries the cost your destination reported, or no cost where it reports none. Until a destination is declared, requests to `/upstream/v1` are refused.

## What comes back

A served response is your provider's response, headers and body, byte for byte. The gateway adds one header of its own:

```http
x-recovea-request-id: req_0192f3a4b5c6d7e8f9a0b1c2d3e4f5a6
```

The id is `req_` and 32 lowercase hex characters, and it is on every response, refusals included. Keep it in your logs: it is the join between a response and its receipt.

When an armed cap stands over the request, the response also names the kind of cap and its window:

```http
x-recovea-budget-scope: organization
x-recovea-budget-window: month
```

`x-recovea-budget-scope` is `organization`, `key` or `run`, and `x-recovea-budget-window` is `day`, `week`, `month`, `year`, `lifetime` or `run`. They name the tightest armed cap the request is bound by. With no armed cap, neither header is sent.

Nothing Recovea reads from your request reaches your provider: the `x-recovea-*` request headers are removed before the call is forwarded.

## The first receipt

The request is metered as it returns: its model, route, token counts and cost are recorded with no prompt and no completion, and it is written as a receipt in your organization's hash-chained ledger. The receipt's `request_id` is the `x-recovea-request-id` your response carried. Receipts are on for every plan.

In the platform, the request is on the **Requests** page, and the **Ledger** page exports the period's receipts with everything needed to re-derive the chain yourself. [Prove](https://docs.recovea.ai/products/prove/) describes the receipt and the recipe.

## When a cap refuses

An armed cap decides before your provider is contacted. At the cap, the request is refused and the provider is never called, so the refused request costs nothing. This is what a monthly cap on the organization answers:

```http
HTTP/1.1 402 Payment Required

{
  "error": {
    "message": "Monthly budget reached. Traffic resumes at reset, or raise the cap.",
    "type": "insufficient_quota",
    "param": null,
    "code": "budget_exceeded"
  }
}
```

The refusal carries `x-recovea-budget-scope: organization` and `x-recovea-budget-window: month`. Branch on the status, `error.type` and `error.code`; the message is prose and names the window that was reached. [Cap](https://docs.recovea.ai/products/cap/) has every window's sentence.

## When spend cannot be confirmed

An armed cap that cannot confirm the spend it is counting refuses rather than let spend run unwatched, and says so with its own status:

```http
HTTP/1.1 503 Service Unavailable
retry-after: 1
x-recovea-budget-scope: organization
x-recovea-budget-window: month

{
  "error": {
    "message": "Monthly spend cannot be confirmed right now. Retry in a moment.",
    "type": "insufficient_quota",
    "param": null,
    "code": "budget_unverifiable"
  }
}
```

It is `503` with `Retry-After: 1`, not `402`: nothing was spent past a line, and it clears on its own. Retry after the interval, and do not treat it as your budget running out. Read the status and `error.code` together, because the `type` is the same as the `402`'s.

## If the gateway degrades

Designed to fail open: if the gateway degrades, traffic goes straight to your provider. The only stop is a cap you armed. [Fail-open and fail-closed](https://docs.recovea.ai/concepts/fail-open-vs-fail-closed/) says which is which.

## Next

[Cap your AI spend](https://docs.recovea.ai/guides/cap-your-ai-spend/) sets a cap in the platform and shows the refusal it answers with.
