The Files API is an org-scoped store for the datasets other endpoints consume. You upload a file once, get back an id, and hand that id to whatever needs it, rather than inlining the same bytes into every request. It is the input side of the Batch API and the same surface fine-tuning and other bulk endpoints read from.
The surface is OpenAI-compatible: point the official client at https://api.privatemind.com/v1 and client.files.* works unchanged (the one addition, /v1/files/usage, has no OpenAI equivalent). This is a REST API on the gateway and is separate from files you attach in a chat, which are per-conversation and never get a file id.
Purposes
Every file declares a purpose at upload, and the purpose is fixed for the life of the file. It tells the platform what the bytes are for, which validation to run, and how long to keep them.
| Purpose | For | Validated as |
|---|---|---|
batch |
Input for a batch | JSONL, one request per line |
fine-tune |
Fine-tuning datasets | JSONL |
vision |
Images referenced by requests | Passed through (not validated) |
assistants |
General-purpose reference files | Passed through |
Upload a file
POST /v1/files is a multipart upload. Send the purpose field first, then the file.
curl -s "https://api.privatemind.com/v1/files" \
-H "Authorization: Bearer $PMIND_KEY" \
-F purpose=batch \
-F file=@requests.jsonlfrom openai import OpenAI
client = OpenAI(base_url="https://api.privatemind.com/v1", api_key=PMIND_KEY)
f = client.files.create(file=open("requests.jsonl", "rb"), purpose="batch")
print(f.id) # file-...The upload is streamed and validated as it goes, so a file that fails validation (malformed JSONL for a line-oriented purpose, or a body over the size limit) is rejected without being stored. The response is a file object.
The file object
{
"id": "file-abc123",
"object": "file",
"bytes": 148923,
"created_at": 1730928000,
"filename": "requests.jsonl",
"purpose": "batch",
"status": "processed"
}id: the handle you pass to other endpoints. Keep it.bytes: size of the stored content.purpose: what you declared at upload.
Retrieve metadata
GET /v1/files/{id} returns the file object above. It does not return the content.
curl -s "https://api.privatemind.com/v1/files/file-abc123" \
-H "Authorization: Bearer $PMIND_KEY"f = client.files.retrieve("file-abc123")
print(f.filename, f.bytes)List files
GET /v1/files lists your org's files, newest first. Filter to one kind with ?purpose=.
curl -s "https://api.privatemind.com/v1/files?purpose=batch" \
-H "Authorization: Bearer $PMIND_KEY"for f in client.files.list(purpose="batch"):
print(f.id, f.filename)Download content
GET /v1/files/{id}/content streams the raw bytes. This is how you pull a batch's output and error files.
curl -s "https://api.privatemind.com/v1/files/file-out-abc123/content" \
-H "Authorization: Bearer $PMIND_KEY" -o output.jsonlcontent = client.files.content("file-out-abc123")
content.write_to_file("output.jsonl")Delete a file
DELETE /v1/files/{id} removes a general file and its content immediately.
curl -s -X DELETE "https://api.privatemind.com/v1/files/file-abc123" \
-H "Authorization: Bearer $PMIND_KEY"client.files.delete("file-abc123")Storage usage
GET /v1/files/usage summarises how much of your org's file storage is in use, so you can see where you stand against a quota before an upload is refused.
curl -s "https://api.privatemind.com/v1/files/usage" \
-H "Authorization: Bearer $PMIND_KEY"If your org has a storage quota, an upload that would cross it is rejected; without a quota, storage is unbounded. Uploaded files, including batch inputs, count toward usage until they age out. (A batch's generated output and error files are served from the run itself and do not add to the total.)
Limits and retention
- Maximum file size: 64 MB per file. A larger upload is rejected (413).
- Retention depends on purpose. Files tied to a batch (its input, output, and error files) are retained for a fixed window after the batch reaches a terminal state, then deleted. General files (
assistants, and other non-batch purposes) belong to you and stay until you delete them. - Content is stored server-side. See the Batch API for the batch-specific request cap and completion window.
Where next
- Batch API: the primary consumer of
purpose: batchfiles. - Errors: status codes and error shapes, including quota and validation rejections.
- Files and sources: the separate, per-conversation attachments in the chat app.