> ## Documentation Index
> Fetch the complete documentation index at: https://docs.hypastack.com/llms.txt
> Use this file to discover all available pages before exploring further.

# Files

> Expiring, zero-knowledge file storage endpoints.

Expiring file storage. Every file has a lifetime after which it deletes itself. Filenames are encrypted at rest; contents uploaded through the API are not, see [How Encryption Works](/how-encryption-works) before you build on this.

## List files

`GET /files`. Requires `files.read`.

| Query param | Type    | Description                                                      |
| ----------- | ------- | ---------------------------------------------------------------- |
| `limit`     | integer | How many to return. Default 50, maximum 100.                     |
| `cursor`    | string  | The `next_cursor` from a previous page. Omit for the first page. |

```bash theme={null}
curl "https://api.hypastack.com/v3/files?limit=10" \
  -H "Authorization: Bearer $HYPASTACK_API_KEY"
```

## Retrieve a file

`GET /files/{id}`. Returns 404 if it does not exist or is not yours, the two are deliberately indistinguishable. Requires `files.read`.

## Start an upload

`POST /files`. Reserves an id and returns a short-lived URL to PUT the bytes to. Nothing is stored until you call complete. Requires `files.write`.

| Body param     | Type    | Required | Description                                                                   |
| -------------- | ------- | -------- | ----------------------------------------------------------------------------- |
| `name`         | string  | Yes      | Filename, up to 200 characters.                                               |
| `size`         | integer | Yes      | Size in bytes. Must be within your plan's per-file cap.                       |
| `content_type` | string  | Yes      | MIME type, e.g. `text/plain`.                                                 |
| `expires_in`   | integer | No       | Lifetime in seconds. Clamped to your plan. Defaults to a size-based lifetime. |
| `burn_on_read` | boolean | No       | Delete the file shortly after its first download.                             |

## Finish an upload

`POST /files/{id}/complete`. Commits the upload once the bytes are in storage. Safe to call twice, a repeat returns the same file rather than an error, so retries are free. Requires `files.write`.

## Get a download URL

`GET /files/{id}/download`. Returns a signed URL valid for five minutes. JSON rather than a redirect, so a client that follows redirects can't accidentally stream a huge body into memory. Requires `files.read`.

## Delete a file

`DELETE /files/{id}`. Removes the record and the stored bytes. Cannot be undone. Requires `files.delete`.

```json Example file object theme={null}
{
  "object": "file",
  "id": "n4pdd98rh4la0uar",
  "name": "hello.txt",
  "size": 28,
  "content_type": "text/plain",
  "created_at": "2026-07-19T21:04:11.000Z",
  "expires_at": "2026-07-19T22:04:11.000Z",
  "burn_on_read": false
}
```
