# Files (/api-v1/files)



The file store holds the input files [Batch](/api-v1/batches) jobs read, and the output files the batch executor writes back. Uploads are multipart, matching OpenAI. Files are tenant-scoped and transient: they are batch I/O, not durable customer state, and old files expire automatically.

## Upload a file [#upload-a-file]

```
POST https://api.zumik.ai/v1/files
```

Send `multipart/form-data` with a `file` part and an optional `purpose` part.

<ParamField body="file" type="file">
  The file contents. For a batch input, this is JSONL with one chat-completion request per line. Required.
</ParamField>

<ParamField body="purpose" type="string" default="batch">
  The file's purpose. Defaults to `batch`.
</ParamField>

### Request [#request]

<CodeGroup>
  ```bash title="curl"
  curl https://api.zumik.ai/v1/files \
    -H "Authorization: Bearer zk_live_..." \
    -F purpose=batch \
    -F file=@requests.jsonl
  ```

  ```python title="OpenAI SDK"
  from openai import OpenAI

  client = OpenAI(base_url="https://api.zumik.ai/v1", api_key="zk_live_...")

  f = client.files.create(file=open("requests.jsonl", "rb"), purpose="batch")
  print(f.id)
  ```
</CodeGroup>

### Response [#response]

```json
{
  "id": "file-9f2a3c1e7b4d8a6f2c1e7b4d",
  "object": "file",
  "bytes": 412,
  "created_at": 1750000123,
  "filename": "requests.jsonl",
  "purpose": "batch"
}
```

<ResponseField name="id" type="string">
  The file id, `file-...`. Pass this as `input_file_id` when creating a [batch](/api-v1/batches).
</ResponseField>

<ResponseField name="object" type="string">
  Always `"file"`.
</ResponseField>

<ResponseField name="bytes" type="integer">
  Size of the stored content in bytes.
</ResponseField>

<ResponseField name="filename" type="string">
  The uploaded filename.
</ResponseField>

<ResponseField name="purpose" type="string">
  The purpose, for example `batch` or `batch_output` (for executor-written outputs).
</ResponseField>

## Retrieve file metadata [#retrieve-file-metadata]

```
GET https://api.zumik.ai/v1/files/{file_id}
```

<ParamField path="file_id" type="string">
  The `file-...` id.
</ParamField>

Returns the file object (metadata, no content). `404` if it does not exist for this project.

## Download file content [#download-file-content]

```
GET https://api.zumik.ai/v1/files/{file_id}/content
```

Returns the raw stored bytes (for a batch output, the JSONL results). `404` if it does not exist for this project.

<CodeGroup>
  ```bash title="curl"
  curl https://api.zumik.ai/v1/files/file-9f2a.../content \
    -H "Authorization: Bearer zk_live_..."
  ```

  ```python title="OpenAI SDK"
  content = client.files.content("file-9f2a...")
  print(content.text)
  ```
</CodeGroup>

## Limits [#limits]

Per project: at most 200 files and 256 MiB total. An upload that would exceed either is rejected with `400`. Individual request bodies are capped at 2 MiB. Output files expire after a day; uploaded files are reclaimed alongside their batch.

## Errors [#errors]

| HTTP | `code`            | When                                                                                                           |
| ---- | ----------------- | -------------------------------------------------------------------------------------------------------------- |
| 400  | (none)            | The multipart upload is malformed, the `file` part is missing, or the project storage quota would be exceeded. |
| 401  | `invalid_api_key` | Missing or invalid bearer key.                                                                                 |
| 404  | (none)            | The file id does not exist for this project.                                                                   |

See the full [error reference](/api-reference/errors).
