# Credits

> What consumes credits, when the charge happens, how to know the price upfront and how to check the statement.

Credits are the workspace balance. Every route that charges tells you the price before charging, and every debit shows up in the statement with the id of what caused it.

## What is charged

| Action | When it is charged | How to know the price upfront |
|---|---|---|
| Clipping (`POST /clips`) | when the submission is created | `credits_cost` in `POST /clips/info` |
| Caption translation (`translate_to`) | together with the clipping | `credits_charged` in the `POST /clips` response |
| Transcription (`POST /transcriptions`) | on creation, per minute of audio, plus an extra with `speaker_labels` | `credits_charged` in the response |
| Live monitoring | for each 10-minute block that generated clips, only while the monitor is on | |
| Image, video and voice generation | on creation, at the price you sent | `GET /generations/models` |
| Persona: photo and video | on creation | `GET /personas/catalog` and `GET /personas/swap/quote` |

Reading, listing, analyzing, rendering and publishing do not charge.

## Check the price upfront

`POST /clips/info` charges nothing and returns the exact clipping cost:

```json title="200 OK"
{
  "id": "7412908365112823",
  "duration": 213,
  "credits_cost": 4,
  "credits_original": 5,
  "discount_percent": 20,
  "current_balance": 120,
  "credits_unlimited": false
}
```

`credits_original` and `discount_percent` show the discount applied, when there is one.

## Balance

```bash
curl https://api.cut.pro/api/v1/balance \
  -H "X-Api-Key: $CUTPRO_API_KEY"
```

```json title="200 OK"
{ "balance": 120, "unlimited": false, "unlimited_until": null }
```

## Insufficient balance

The route returns `402` before creating the job, and nothing is charged:

```json title="402 Payment Required"
{
  "code": "INSUFFICIENT_CREDITS",
  "extra": { "credits_needed": 121, "current_balance": 40, "is_owner": true }
}
```

- `credits_needed` and `current_balance` tell you how much is missing.
- `is_owner` tells you whether the key's owner can buy credits for this workspace.
- In generation and persona, `extra.top_up_url` is the page where credits are bought. Show it to the person.

## Statement

`GET /balance/history` lists every movement, from newest to oldest:

```bash
curl "https://api.cut.pro/api/v1/balance/history?type=debit&limit=20" \
  -H "X-Api-Key: $CUTPRO_API_KEY"
```

```json title="200 OK"
{
  "transactions": [
    {
      "id": "7412908372201188",
      "type": "debit",
      "amount": -4,
      "balance_after": 116,
      "reference_type": "usage",
      "reference_id": "7412908371004912",
      "description": null,
      "waived": false,
      "expires_at": null,
      "created_at": "2026-10-29T18:01:12.000Z"
    }
  ],
  "pagination": { "current_page": 1, "total_pages": 1, "total_count": 1, "has_next_page": false, "has_previous_page": false, "limit": 20 }
}
```

`amount` is negative on a debit and positive on a credit. `reference_id` points to what caused the movement (the submission, the subscription, the refund). `expires_at` is only filled in for credits that expire. Filter by `type` and `reference_type`.

## Refunds

- **Canceled clipping:** `DELETE` on a submission still processing cancels it and returns the credits.
- **Failed generation:** comes back on its own. A finished generation that came out wrong can have a refund requested at `POST /generations/{id}/refund`, before downloading or posting, and the team decides.
- **Repeated or speechless transcription:** audio already transcribed comes back from the cache with `credits_charged: 0`, and audio with no speech ends as `no_speech` with no charge.
- **Unnecessary translation:** if the video is already in the `translate_to` language, the translation extra is returned.

## Free usage

A workspace can be on free usage. While it lasts, jobs run without consuming credits and are never refused for balance.

- `GET /balance` shows `unlimited: true` and `unlimited_until` (`null` means no end date).
- `GET /workspace` returns the same in `credits_unlimited` and `credits_unlimited_until`.
- `POST /clips/info` returns `credits_unlimited` alongside `credits_cost`.

The statement keeps recording everything: each job appears with the amount it would have cost and `waived: true`, and `balance_after` does not change. Real charge fields, like `credits_charged`, come as `0`.

> AI generation and personas always consume credits, even on free usage.
