# Preview cost

> Find out what a run would cost, and whether it would be allowed, without starting it.

Canonical page: https://www.rundiffusion.com/docs/api/generate/preview-cost
Endpoint: POST /api/v2/generate/preview-cost
Authorization: OAuth device flow or Personal API Access Token or Company API Access Token

---

> **Agents recommended**
>
> **Generate endpoints are built for agents, not ideal for static integrations.**
>
> We strongly advise against building a fixed, hand-coded integration on top of these endpoints.
>
> The tool catalog is a living, evolving, and dynamic list. Tools gain and lose fields, and tools themselves arrive and disappear, at any time. That is why every generate call carries a `tool_fields_hash`: it is a fingerprint of the exact field schema you built your inputs from. When a tool changes, your hash stops matching and the call answers `409 TOOL_SCHEMA_STALE` instead of running something you did not describe.
>
> An agent handles that in a way a static client cannot. It would be capable of refetching the tool with [Get a tool](/docs/api/tools/get), reads the new `tool_fields_hash` and the new fields, rebuilds the request, and sends it again. If a tool is gone, or no longer does the job it used to, an agent can pick a different one from [List tools](/docs/api/tools/list). That self-recovery is the assumption these endpoints are designed around.
>
> **An MCP server is coming very soon** that uses this API underneath. If you are building an agent, it will almost certainly be a better interface to build on than calling Generate directly.

Takes the same body as [Create generation](/docs/api/generate/create) and reports
what it would cost without starting anything. Handling a block here is
considerably cheaper than a failed generation.

`POST /api/v2/generate/preview-cost`

Authorization: OAuth device flow or Personal API Access Token or Company API Access Token

## Request

**Headers**

| Name | Type | Required | Description |
| --- | --- | --- | --- |
| `Authorization` | string | Yes | Bearer token. This endpoint accepts an OAuth device flow token, a Personal API Access Token, or a Company API Access Token. See [Authentication](/docs/api/authentication). |

Takes the same body as `generate` and tells you what the run would cost without
starting it. This endpoint is JSON only, so it does not accept file parts.

## Response

`200 OK`, whether or not the run would be allowed.

```json
{
  "can_run": true,
  "blocking_reason": null,
  "tokens_per_result": 85,
  "total_tokens": 170,
  "free_tokens_per_result": 0,
  "estimated_seconds": 12
}
```

`total_tokens` is `tokens_per_result` multiplied by `num_results`, less anything
covered by `free_tokens_per_result`. All three are whole tokens.

A blocked run returns `200` as well, with the reason attached:

```json
{
  "can_run": false,
  "blocking_reason": "Your balance of (12) is too low to run this tool",
  "tokens_per_result": 85,
  "total_tokens": 170,
  "free_tokens_per_result": 0,
  "estimated_seconds": 12
}
```

Check `can_run` before submitting. Handling a block here is considerably cheaper
than a failed generation.

| Name | Type | Description |
| --- | --- | --- |
| `can_run` | boolean | Whether generate would accept this exact body. This is the field to branch on, and the only one whose meaning is stable. |
| `blocking_reason` | string \| null | Human-readable explanation when can_run is false, and null otherwise. For display only, never for branching. |
| `tokens_per_result` | integer | Authoritative cost for one result on this account, in whole tokens. This can differ from the list price on the tool. |
| `total_tokens` | integer | tokens_per_result multiplied by num_results, less anything covered by free_tokens_per_result. This is what the run will actually deduct. |
| `free_tokens_per_result` | integer | Per-result tokens covered by the account's free allowance, already subtracted from total_tokens. Zero when no allowance applies. |
| `estimated_seconds` | integer | The tool's average generation time per result, for setting expectations. |

> **blocking_reason is a display string, not a code**
>
> `blocking_reason` is a human-readable sentence intended for showing to a
> person, such as `Your balance of (12) is too low to run this tool` or `You are
> not authorized to generate on this team`. Its wording can change at any time,
> so branch on `can_run` rather than parsing it, and it is `null` whenever
> `can_run` is `true`. For programmatic handling, submit the run and branch on
> the `code` in the [error envelope](/docs/api/errors), which is stable.

## Errors

| Code | What to do |
| --- | --- |
| `TOOL_NOT_FOUND` | Returns `404`. No such tool, or not one this credential can see. |
| `TOOL_SCHEMA_STALE` | Returns `409` with `details.expected_tool_fields_hash`. Re-fetch the tool and rebuild the request with the new hash. |
| `TOOL_NOT_RUNNABLE_V1` | Returns `400`. The tool uses a field type this API cannot run yet. |
| `INVALID_REQUEST` | Returns `400`. A missing or malformed field in the body. |
| `RATE_LIMITED` | Returns `429`. See [Rate limits](/docs/api/rate-limits#generation). See [Rate limits](/docs/api/rate-limits#generation). |

The full list is in [Errors](/docs/api/errors).
