---
title: "Retrieve a batch"
method: GET
path: "/v1/batches/{id}"
tags: ["Batches"]
---

# Retrieve a batch

`GET /v1/batches/{id}`

## Request

- Base URL: `https://api.tryleap.ai`
- URL: `https://api.tryleap.ai/v1/batches/{id}`
- Auth: one of:
  - API key in header `x-api-key`
  - HTTP bearer

A batch with every generation in it, each as `GET /v1/generations/{id}` would return it. Send `Prefer: wait=60` to hold the read until every run is final or 60 seconds pass. While any run isn't final, `Retry-After` says how many seconds to wait before the next read.

Needs an API key with the `generations:read` scope.

## Path parameters

- `id` string, required: The batch's ID, `bat_...`.

## Headers

- `Prefer` string: `wait=N` holds the request open for up to N seconds (at most 60) until the generation finishes, and `Preference-Applied` echoes the wait used. Most images finish inside the wait. If the run is still going when it ends, you get it back `queued` or `running`; poll it from there. Without this header the generation comes back queued at once.

## Response `200`

The batch, as it is now or when the wait ends.

- Batch: Up to 50 generations priced and held together, each run on its own.
  - `id` string, required: The batch's ID, `bat_...`.
  - `object` 'batch', required
  - `data` Generation[], required: Its generations, in the order you sent them.
    - `id` string, required: The generation's ID, `gen_` and 24 letters and digits.
    - `object` 'generation', required
    - `model` string, required: The model or preset it runs, with a preset's version.
    - `modality` 'image' | 'video' | 'audio' | '3d' | 'text', required: What it makes: `image`, `video`, `audio`, `3d` or `text`.
    - `status` 'queued' | 'running' | 'succeeded' | 'failed' | 'canceled', required: `queued`, then `running`, then one of `succeeded`, `failed` or `canceled`. Only `succeeded` is charged.
    - `provider` string, nullable, required: Which upstream ran it, once one did. Informational: the model ID and input stay the same whichever runs it.
    - `revision` string, required: The model's schema and price revision the run used.
    - `input` object, required: The input as it runs, with the defaults filled in.
    - `output` object[], required
      - `type` 'image' | 'video' | 'audio' | '3d' | 'text', required: What the file is: `image`, `video`, `audio`, `3d` or `text`.
      - `url` string, uri, required: A signed link to the file. Download what you keep: links expire after 24 hours, and reading the generation again signs fresh ones.
      - `expires_at` string, date-time, required: When `url` stops working, 24 hours after it was signed.
      - `content_type` string, required: The file's media type, such as `image/jpeg` or `video/mp4`.
      - `width` integer, nullable, required: Width in pixels; null for a sound.
      - `height` integer, nullable, required: Height in pixels; null for a sound.
      - `poster` object: For a video: a JPEG of a frame from its middle, about 720 pixels on the long side. Absent when none was made.
        - `url` string, uri, required: A signed link to the poster, which expires with the video's link.
        - `expires_at` string, date-time, required
        - `width` integer, required
        - `height` integer, required
    - `preview` object: While a preset that makes a still first is running: that still, once it exists, before the video it becomes. Absent for every other run, and for a run whose video also reads words or a photo you sent, such as a line to say or a photo the clip starts from: that still comes with the video. Also absent for the rest of a UTC day once 10 of the workspace's runs that showed one failed for their input.
      - `url` string, uri, required: A signed link to a smaller JPEG of the still, about 960 pixels on the long side. It works for 10 minutes; read the run again for a fresh one. The still itself comes with the finished run's output.
      - `expires_at` string, date-time, required
      - `width` integer, nullable, required
      - `height` integer, nullable, required
    - `error` object, nullable, required: Why a `failed` run failed, such as a refused prompt or a provider error; null otherwise. A failed run isn't charged.
      - `message` string, required
    - `failure_cause` 'provider_error' | 'provider_refused' | 'photo_blocked' | 'timeout' | 'outage' | 'input_removed' | 'input_rejected', nullable, required: What made a `failed` run fail, for a program to branch on: `provider_error`, `provider_refused` (the model's safety filter said no), `photo_blocked` (the photo check refused the photo), `timeout`, `outage` (the provider had a declared incident or could not serve Leap), `input_removed` (an input file was gone) or `input_rejected` (the provider couldn't use an input file: too small, an unreadable format, or no face). Null for any other run, and for a failure from before causes were recorded.
    - `usage` object, required: What the run cost your workspace.
      - `cost_usd` string, nullable, required: What the run cost, as an exact decimal string in US dollars; null until it's charged.
    - `source` 'studio' | 'api' | 'mcp', nullable, required: Where it was started: `api`, `mcp` or `studio`.
    - `batch_id` string, nullable, required: The batch it belongs to, `bat_...`; null if none.
    - `created_at` string, date-time, required: When it was created.
    - `started_at` string, date-time, nullable, required: When it started running; null while queued.
    - `completed_at` string, date-time, nullable, required: When it reached a final status; null before.
    - `slow_at` string, date-time, nullable, required: While a preset runs: when it counts as slow, one and a half times what Leap's runs of it take after `started_at`, scaled to this run's length, resolution and count. From then on a cancel works whatever the run has done, even once its `preview` shows. Null for any other run.
    - `deadline_at` string, date-time, nullable, required: While a preset runs: when Leap stops it if it hasn't finished, three times what Leap's runs of it take after `started_at`, scaled to this run's length, resolution and count, between 5 minutes (2 for a picture) and 12. It then fails with the `failure_cause` `timeout` and costs nothing. Null for any other run.
    - `suggested_recipe` object, nullable, required: For a run of a model, not a recipe: the recipe made for what its words and files ask, when they clearly ask for one, such as two photos and "put the outfit from photo 2 on photo 1" on an image model (Virtual try-on), or a character sheet from a picture (Consistent character). Read from the words and files alone, so the same request always gets the same answer. Null when nothing matches clearly.
      - `model` string, required: The recipe, with its version, such as `leap/virtual-try-on@1`.
      - `name` string, required: The recipe's name: `Virtual try-on`.
      - `tuned_for` string, required: What it is tuned for, in a few words: `outfits`.
      - `input` object, required: The recipe's input from this run: its files in the recipe's slots, and the words it could fill. Send it to `POST /v1/generations` with `model` as it is, or add what the recipe still needs; `GET /v1/models/{creator}/{name}` has its schema.
      - `cost_usd` string, nullable, required: What a run of it with `input` costs, as an exact decimal string in US dollars; null for a recipe priced on the length of your video or sound, which `POST /v1/quotes` prices.

## Other responses

- `400`: `conflicting_credentials`
- `401`: `authentication_required`
- `403`: `permission_denied`
- `404`: `resource_not_found`
- `429`: `rate_limit_exceeded`

## Changes

- **2026-10-20** `b6c075ed9135`: 1 info
  - added the required property `data/items/suggested_recipe` to the response with the `200` status

[Operation history](https://skmtc.dev/tryleap/apis/leap-api/changes/v1/batches/:id/get.md)

---

[API](https://skmtc.dev/tryleap/apis/leap-api.md) · [All operations](https://skmtc.dev/tryleap/apis/leap-api/llms.txt) · [OpenAPI document](https://skmtc.dev/tryleap/apis/leap-api/revisions/b6c075ed9135?raw)
