# Get generation

Source: https://docs.foodshot.ai/reference/get-generation

> Returns one generation, with a fresh output.url on every call.

`GET https://api.foodshot.ai/v1/generations/{id}`

To follow a job, use webhooks, or poll about 20 seconds after you create it, then every 5 seconds.

## Parameters

| Name | In | Type | Required | Description |
| --- | --- | --- | --- | --- |
| `id` | path | string | yes | The generation id (`gen_…`). |

## Responses

### 200

The generation.

```json
{
  "id": "gen_4Kq9xT2mVb7Zp1Ls8Hc3Rw",
  "object": "generation",
  "environment": "live",
  "status": "succeeded",
  "created_at": "2026-10-18T10:42:07.512Z",
  "started_at": "2026-10-18T10:42:09.031Z",
  "completed_at": "2026-10-18T10:42:42.870Z",
  "style_id": "pure-shot",
  "instruction": null,
  "aspect_ratio": "1:1",
  "resolution": "4k",
  "format": "jpeg",
  "metadata": {
    "dish_id": "d_456",
    "vendor_id": "v_1029"
  },
  "credits_charged": 1,
  "output": {
    "url": "https://api.foodshot.ai/v1/files/gen_4Kq9xT2mVb7Zp1Ls8Hc3Rw/image.jpg?exp=1792406595&sig=VT5DMYyFzJsUzoKdU9fob--vTZ1Nx5PFShO290vXCjc",
    "url_expires_at": "2026-10-19T10:43:15.000Z",
    "available_until": "2026-11-17T10:42:42.870Z",
    "content_type": "image/jpeg",
    "width": 4096,
    "height": 4096,
    "bytes": 8734516
  },
  "error": null,
  "delivery": {
    "status": "delivered",
    "attempts": 1,
    "last_status_code": 200,
    "last_attempt_at": "2026-10-18T10:42:43.402Z"
  }
}
```

### 400

A query parameter is wrong or unknown.

```json
{
  "error": {
    "code": "invalid_request",
    "message": "The query parameter named in param is invalid.",
    "param": "limit",
    "request_id": "req_daJCWaeLcd6uXjfMaJeplG"
  }
}
```

### 401

The key is missing, wrong or revoked.

```json
{
  "error": {
    "code": "invalid_api_key",
    "message": "The API key is missing, malformed, unknown or revoked.",
    "param": null,
    "request_id": "req_NPfzXU77n1f2QYM559fGL8"
  }
}
```

### 403

This key may not make this request.

```json
{
  "error": {
    "code": "permission_denied",
    "message": "Live keys work only from your server.",
    "param": null,
    "request_id": "req_NPfzXU77n1f2QYM559fGL8"
  }
}
```

### 404

No such generation for this key in the last 90 days.

```json
{
  "error": {
    "code": "not_found",
    "message": "No generation with this id in this environment.",
    "param": "id",
    "request_id": "req_UTyanAcKR2uQdufRHA9T5L"
  }
}
```

### 429

Over the request limit of this key. Retry after `Retry-After` seconds.

```json
{
  "error": {
    "code": "rate_limited",
    "message": "Too many requests. Retry after the number of seconds in Retry-After.",
    "param": null,
    "request_id": "req_BTBBPZA0oirxnw23MU0t7E"
  }
}
```

### 500

Something went wrong on our side. Retry; for a `POST`, with the same `Idempotency-Key` and body.

```json
{
  "error": {
    "code": "internal_error",
    "message": "Something went wrong on our side. Retry the request; for POST /v1/generations, use the same Idempotency-Key.",
    "param": null,
    "request_id": "req_8d4DxP5n53EgewaJFOqGyS"
  }
}
```

### 503

Temporarily unavailable. Retry after `Retry-After` seconds.

```json
{
  "error": {
    "code": "service_unavailable",
    "message": "The service is temporarily unavailable. Retry after the number of seconds in Retry-After.",
    "param": null,
    "request_id": "req_8d4DxP5n53EgewaJFOqGyS"
  }
}
```

## Code samples

### curl

```bash
curl -sS "https://api.foodshot.ai/v1/generations/$GENERATION_ID" \
  --max-time 60 \
  -H "Authorization: Bearer $FOODSHOT_API_KEY"
```

### Node

```js
import { setTimeout as sleep } from 'node:timers/promises';

const id = process.env.GENERATION_ID; // the id that POST /v1/generations returned
await sleep(20_000); // first poll after about 20 seconds
for (;;) {
  const res = await fetch(`https://api.foodshot.ai/v1/generations/${id}`, {
    headers: { Authorization: `Bearer ${process.env.FOODSHOT_API_KEY}` },
    signal: AbortSignal.timeout(60_000),
  });
  if (res.status === 429 || res.status >= 500) {
    await sleep(Number(res.headers.get('retry-after') ?? 5) * 1000);
    continue;
  }
  if (!res.ok) throw new Error(`FoodShot ${res.status}: ${await res.text()}`);
  const generation = await res.json();
  if (generation.status === 'succeeded') {
    console.log(generation.output.url); // a 24-hour link: download it from your server
    break;
  }
  if (generation.status === 'failed') {
    console.log(generation.error.code); // the credit was refunded
    break;
  }
  await sleep(5_000); // then every 5 seconds
}
```

### Python

```python
import os
import time

import requests

generation_id = os.environ["GENERATION_ID"]  # the id that POST /v1/generations returned
headers = {"Authorization": f"Bearer {os.environ['FOODSHOT_API_KEY']}"}
time.sleep(20)  # first poll after about 20 seconds
while True:
    response = requests.get(
        f"https://api.foodshot.ai/v1/generations/{generation_id}", headers=headers, timeout=60
    )
    if response.status_code == 429 or response.status_code >= 500:
        time.sleep(int(response.headers.get("Retry-After", "5")))
        continue
    response.raise_for_status()
    generation = response.json()
    if generation["status"] == "succeeded":
        print(generation["output"]["url"])  # a 24-hour link: download it from your server
        break
    if generation["status"] == "failed":
        print(generation["error"]["code"])  # the credit was refunded
        break
    time.sleep(5)  # then every 5 seconds
```
