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

# Download files

> Stream file content, use range requests, and download specific versions.

## Stream a file

```http theme={null}
GET /files/{fileId}/stream
```

```bash theme={null}
curl -L "https://api.everabyte.io/api/files/FILE_ID/stream" \
  -H "X-Public-Key: $EVB_PUBLIC_KEY" \
  -H "X-Secret-Key: $EVB_SECRET_KEY" \
  --output ./file.bin
```

The response body is the decrypted file content. It is a binary response, not JSON.

### Response headers

| Header | Meaning |
| - | - |
| `Content-Type` | Media type |
| `Content-Length` | Full size, or the range length |
| `Content-Disposition` | Safe attachment filename |
| `X-File-Id` | File identifier |
| `X-File-Name` | URL-encoded filename |
| `X-File-Size` | Size in bytes |
| `X-File-Extension` | Extension |
| `X-Encryption` | `SSE` |
| `Content-Range` | Present on partial responses |
| `Accept-Ranges` | Advertised range support |

A full download returns `200`. A range request returns `206`.

## Range requests

Send a standard `Range` header:

```bash theme={null}
curl -L "https://api.everabyte.io/api/files/FILE_ID/stream" \
  -H "X-Public-Key: $EVB_PUBLIC_KEY" \
  -H "X-Secret-Key: $EVB_SECRET_KEY" \
  -H "Range: bytes=0-1048575" \
  --output ./first-megabyte.bin
```

Use this for resumable downloads, media seeking, and partial inspection. If you proxy the response, preserve both the `206` status and the `Content-Range` header. Converting a partial response into `200` corrupts resumable clients.

In a range request only the chunks intersecting the requested range are decrypted and authenticated; chunks outside the range are skipped without being verified. If you need end-to-end assurance for a file, download it whole.

## Delivery path

`GET /files/{fileId}/stream` is the documented way to fetch content. The backend may serve the bytes through an internal cache or directly from origin; that choice is server-side and not part of the contract. Do not build client logic that depends on a specific delivery route.

If you need a short-lived URL to hand to a browser or a third-party service, proxy the stream from your server instead of exposing your API keys.

## Download a specific version

```http theme={null}
GET /files/{fileId}/versions/{versionId}/download
```

This streams the bytes of an archived version. Use it for audit, comparison, or recovery workflows. Version downloads have the same binary semantics and headers as current-file downloads.

## Streaming in application code

```javascript Node.js theme={null}
import fs from "node:fs";
import { Readable } from "node:stream";
import { pipeline } from "node:stream/promises";

const response = await fetch(
  `https://api.everabyte.io/api/files/${fileId}/stream`,
  {
    headers: {
      "X-Public-Key": process.env.EVB_PUBLIC_KEY,
      "X-Secret-Key": process.env.EVB_SECRET_KEY,
    },
  },
);

if (!response.ok || !response.body) {
  throw new Error(`Download failed: ${response.status}`);
}

await pipeline(
  Readable.fromWeb(response.body),
  fs.createWriteStream("./download.bin"),
);
```

```python Python theme={null}
import os
import requests

with requests.get(
    f"https://api.everabyte.io/api/files/{file_id}/stream",
    headers={
        "X-Public-Key": os.environ["EVB_PUBLIC_KEY"],
        "X-Secret-Key": os.environ["EVB_SECRET_KEY"],
    },
    stream=True,
    timeout=(30, 300),
) as response:
    response.raise_for_status()
    with open("download.bin", "wb") as handle:
        for chunk in response.iter_content(chunk_size=1024 * 1024):
            if chunk:
                handle.write(chunk)
```

```go Go theme={null}
package main

import (
	"io"
	"net/http"
	"os"
)

func download(fileID string) error {
	req, err := http.NewRequest(
		http.MethodGet,
		"https://api.everabyte.io/api/files/"+fileID+"/stream",
		nil,
	)
	if err != nil {
		return err
	}
	req.Header.Set("X-Public-Key", os.Getenv("EVB_PUBLIC_KEY"))
	req.Header.Set("X-Secret-Key", os.Getenv("EVB_SECRET_KEY"))

	resp, err := http.DefaultClient.Do(req)
	if err != nil {
		return err
	}
	defer resp.Body.Close()

	out, err := os.Create("download.bin")
	if err != nil {
		return err
	}
	defer out.Close()

	_, err = io.Copy(out, resp.Body)
	return err
}
```

## Errors

| Status | Meaning |
| - | - |
| `401` | Missing or invalid key pair |
| `403` | Missing read capability, bucket outside scope, or file access denied |
| `404` | File not found or not visible to the caller |
| `500` | Key envelope or decryption state problem |
| `503` | Temporary capacity or dependency failure |

A decryption failure caused by rotated or missing owner keys is a server-side state issue, not something a retry fixes. Contact support with the `X-File-Id` value and the timestamp.

## Safety notes

* Do not load large files fully into memory.
* Do not expose signed URLs to untrusted users.
* Do not cache decrypted content longer than your application requires.
* Validate the downloaded bytes if they will be executed, parsed, or rendered.
* Close response bodies. Leaked connections exhaust your client pool before the API rate limit becomes relevant.


This documentation is built and hosted on [Mintlify](https://mintlify.com), a developer documentation platform.