# Data Retention

Control how long your generated media and request records are stored — per request, with two independent headers

Source: https://atlascloud.ai/docs/en/data-retention

import { Callout } from 'fumadocs-ui/components/callout';
import { Tab, Tabs } from 'fumadocs-ui/components/tabs';

## Overview

Every async generation creates two separate things:

- **Generated media** — the image, video, or audio file Atlas Cloud hosts for you and returns as an output URL.
- **A request record** — the task's metadata: the model, your prompt and parameters, the status, timestamps, and the output URLs. This is what the [Predictions](/predictions) endpoint reads when you poll a task.

You can set how long each one is kept, **per request**, with two headers:

| Header | Range | Controls |
| --- | --- | --- |
| `X-AtlasCloud-Object-Expiration-Hours` | `1`–`336` | How long the **generated media files** are stored. |
| `X-AtlasCloud-Request-Retention-Hours` | `0`–`336` | How long the **request record** is kept. |

Both are optional whole numbers of hours. `336` hours is 14 days.

<Callout title="The two settings are independent">
  Deleting the record does **not** delete the media, and deleting the media does **not** delete the record. Set either one, both, or neither — each follows its own clock.
</Callout>

## Quick start

Send the headers with a normal submit request:

<Tabs items={['cURL', 'Python', 'Node.js']}>
<Tab value="cURL">
```bash
curl -X POST https://api.atlascloud.ai/api/v1/model/generateImage \
  -H "Authorization: Bearer your-api-key" \
  -H "Content-Type: application/json" \
  -H "X-AtlasCloud-Object-Expiration-Hours: 24" \
  -H "X-AtlasCloud-Request-Retention-Hours: 0" \
  -d '{
        "model": "bytedance/seedream-v5.0-pro/text-to-image",
        "prompt": "A calico kitten chasing a butterfly in a garden"
      }'
```
</Tab>
<Tab value="Python">
```python
import requests

response = requests.post(
    "https://api.atlascloud.ai/api/v1/model/generateImage",
    headers={
        "Authorization": "Bearer your-api-key",
        "Content-Type": "application/json",
        # delete the generated image after 24 hours
        "X-AtlasCloud-Object-Expiration-Hours": "24",
        # drop the request record as soon as the task finishes
        "X-AtlasCloud-Request-Retention-Hours": "0",
    },
    json={
        "model": "bytedance/seedream-v5.0-pro/text-to-image",
        "prompt": "A calico kitten chasing a butterfly in a garden",
    },
)

print(response.json()["data"]["id"])  # the task id (session_id)
```
</Tab>
<Tab value="Node.js">
```javascript
const res = await fetch("https://api.atlascloud.ai/api/v1/model/generateImage", {
  method: "POST",
  headers: {
    Authorization: "Bearer your-api-key",
    "Content-Type": "application/json",
    // delete the generated image after 24 hours
    "X-AtlasCloud-Object-Expiration-Hours": "24",
    // drop the request record as soon as the task finishes
    "X-AtlasCloud-Request-Retention-Hours": "0",
  },
  body: JSON.stringify({
    model: "bytedance/seedream-v5.0-pro/text-to-image",
    prompt: "A calico kitten chasing a butterfly in a garden",
  }),
});

const { data } = await res.json();
console.log(data.id); // the task id (session_id)
```
</Tab>
</Tabs>

The submit response is unchanged — you get a task `id` back immediately and the generation runs exactly as it normally would. Retention only decides what happens **after** the task finishes.

Both headers work on all three async submit endpoints:

- `POST /api/v1/model/generateImage`
- `POST /api/v1/model/generateVideo`
- `POST /api/v1/model/generateAudio`

## `X-AtlasCloud-Object-Expiration-Hours`

Sets how long Atlas Cloud stores the **media files this request generates**, counted from the moment the task is submitted.

- **Range:** `1` to `336` hours (1 hour to 14 days).
- **Default when omitted:** **14 days**.
- Because the maximum equals the default, this header can only ever make media expire **sooner** — it cannot extend storage beyond 14 days.

Once the media expires, its output URLs stop working (requests to them return `404`). Download or copy anything you need to keep before then.

<Callout type="warn">
  This header covers the **generated outputs** of the request. It does not change the retention of files **you** uploaded as inputs (reference images, source videos, audio clips) — those follow the standard [file upload](/upload-files) retention.
</Callout>

## `X-AtlasCloud-Request-Retention-Hours`

Sets how long Atlas Cloud keeps the **request record** — the metadata row behind the [Predictions](/predictions) endpoint.

- **Range:** `0` to `336` hours (up to 14 days).
- **Default when omitted:** the record is kept under the platform's standard retention policy.
- **`0` means "delete as soon as the generation is done"** — the record is removed shortly after the task reaches a terminal state (`completed`, `failed`, or `timeout`).

<Callout title="Records are never deleted mid-flight">
  A record is only removed once the task has actually finished **and** its billing and any [webhook](/webhooks) delivery have settled. A retention of `0` never interrupts a running generation or costs you a callback.
</Callout>

Once the record is deleted, polling that task with [`GET /api/v1/model/prediction/{id}`](/predictions) no longer returns the result payload — the outputs, parameters, and error details are gone. Retrieve what you need (or use a [webhook](/webhooks)) before the record expires.

<Callout type="info">
  Deleting the record does not delete the media. With `X-AtlasCloud-Request-Retention-Hours: 0` and no object header, the generated file still lives its full 14 days at its output URL — you simply have to keep that URL yourself, because Atlas Cloud no longer has a record of it.
</Callout>

## Choosing values

| Goal | Headers |
| --- | --- |
| Keep nothing longer than a day | `X-AtlasCloud-Object-Expiration-Hours: 24` + `X-AtlasCloud-Request-Retention-Hours: 24` |
| Minimize stored metadata, keep the file | `X-AtlasCloud-Request-Retention-Hours: 0` (save the output URL yourself) |
| Short-lived preview media, normal history | `X-AtlasCloud-Object-Expiration-Hours: 1` |
| Platform defaults | Send neither header |

## Validation

Both headers are validated **before** anything happens — before the request is billed, before any file is stored, and before the model provider is called. If a value is invalid, the request is rejected with `HTTP 400`, **no task is created, and you are not charged**.

| Rule | Detail |
| --- | --- |
| **Format** | A whole number of hours. Decimals (`1.5`), durations (`24h`), and other text are rejected. |
| **`X-AtlasCloud-Object-Expiration-Hours` range** | `1`–`336`. `0` is rejected — use `1` for the shortest retention. |
| **`X-AtlasCloud-Request-Retention-Hours` range** | `0`–`336`. `0` is valid and means "delete once finished". |
| **Omitted or empty** | Treated as "not set" — the default applies. |

Example rejection:

```json
{
  "code": 400,
  "msg": "invalid X-AtlasCloud-Object-Expiration-Hours header: 500 is out of range [1, 336]"
}
```

If you call the API from a browser, both header names are allowed by the CORS policy, so cross-origin requests can send them.

## Cost

Custom retention is **free**. Shortening or keeping the defaults does not change what a generation costs.

## Best practices

- **Download what you need to keep.** Treat Atlas Cloud storage as a delivery buffer, not an archive — especially with a short object expiration.
- **Use [webhooks](/webhooks) with `X-AtlasCloud-Request-Retention-Hours: 0`.** The callback delivers the result the moment the task finishes, so you never need the record afterwards.
- **Store the output URL on your side** when you shorten record retention but keep the media.
- **Send the headers on every request** you want covered. They are per-request; there is no account-wide default setting.
- **Don't rely on a deleted record's URLs.** Once media expires, its URL returns `404` — re-generate rather than retrying the dead link.

## Troubleshooting

| Symptom | Likely cause / action |
| --- | --- |
| `400 ... is not a whole number of hours` | The value isn't a plain integer. Send `24`, not `24h` or `1.5`. |
| `400 ... is out of range [1, 336]` | Object expiration must be at least `1` hour and at most 14 days. |
| `400 ... is out of range [0, 336]` | Request retention must be between `0` and 14 days. |
| Output URL returns `404` sooner than expected | The object expiration you set has elapsed. Media is gone; re-generate if you still need it. |
| Polling returns no outputs for a finished task | The request record was deleted by your retention setting. Use a [webhook](/webhooks), or lengthen the retention. |
| Media still available after the record disappeared | Expected — the two settings are independent. The file lives until its own expiration. |

## Reference

- **Endpoints:** `POST /api/v1/model/generateImage`, `POST /api/v1/model/generateVideo`, `POST /api/v1/model/generateAudio`.
- **`X-AtlasCloud-Object-Expiration-Hours`:** integer `1`–`336`; generated media only; default 14 days; can only shorten.
- **`X-AtlasCloud-Request-Retention-Hours`:** integer `0`–`336`; request record only; `0` = delete once terminal and settled.
- **Invalid value:** `HTTP 400`, no task created, no charge.
- **Related:** [Predictions](/predictions) · [Webhooks](/webhooks) · [Upload files](/upload-files) · [Data deletion policy](/data-deletion)
