File Upload
The Hatz API provides the functionality to upload files, which you can then use across chat, app builder, and workflows.
This API is for uploading source files into Hatz and polling their processing status. It does not expose arbitrary files from a code execution sandbox by filesystem path. If a chat or tool run creates an output inside a sandbox, have Hatz create a downloadable generated file for that output, then use the product-provided download flow or support diagnostics for that generated file.
Upload Methods
There are two ways to upload files:
| Method | Best for | How it works |
|---|---|---|
Single-request upload (POST /v1/files/upload) |
Server-to-server / API integrations | One multipart POST; the API streams the file to storage and returns a file_id for polling |
Presigned URL upload (POST /v1/files/upload-url) |
Browser / mobile clients | Request a signed URL, PUT the file directly, then poll for completion |
Both methods trigger the same asynchronous processing pipeline (text extraction, embeddings). Poll GET /v1/files/{file_id}/status until status is ready.
Firewall note: Presigned URL uploads use the domain
uploads.hatz.ai. Enterprise customers should whitelist this domain for outbound HTTPS traffic.
Single-Request Upload
Best for API integrations where you want a single HTTP call.
Step 1: Upload the file
curl -X POST 'https://ai.hatz.ai/v1/files/upload' \
-H 'X-API-Key: $HATZ_API_KEY' \
-F 'file=@report.pdf' \
-F 'scope_type=chat' \
-F 'scope_id=a90cb2a4-a4d5-4403-9b6a-6def06b0d4af'
Response:
{
"file_id": "8fb5bc1d-5a8d-4015-86a6-b0ca394e7793",
"status": "uploading",
"message": "File uploaded successfully. Poll GET /v1/files/{file_id}/status for processing status."
}
Step 2: Poll for completion
curl 'https://ai.hatz.ai/v1/files/8fb5bc1d-5a8d-4015-86a6-b0ca394e7793/status' \
-H 'X-API-Key: $HATZ_API_KEY'
Status values: uploading → processing → ready | failed
Presigned URL Upload
Best for browser and mobile clients. Keeps large file transfers off the API server and provides a stable domain (uploads.hatz.ai) for enterprise firewall whitelisting.
Step 1: Request an upload URL
curl -X POST 'https://ai.hatz.ai/v1/files/upload-url' \
-H 'X-API-Key: $HATZ_API_KEY' \
-H 'Content-Type: application/json' \
-d '{
"file_name": "report.pdf",
"file_size": 1048576,
"mime_type": "application/pdf",
"scope_type": "chat",
"scope_id": "a90cb2a4-a4d5-4403-9b6a-6def06b0d4af"
}'
Response:
{
"presigned_url": "https://uploads.hatz.ai/uploads/...",
"file_id": "8fb5bc1d-5a8d-4015-86a6-b0ca394e7793",
"expires_in": 900
}
Step 2: Upload the file
PUT the file directly to the presigned URL. The URL is valid for 15 minutes.
curl -X PUT "$PRESIGNED_URL" \
-H 'Content-Type: application/pdf' \
--data-binary '@report.pdf'
Step 3: Poll for completion
Same as single-request upload — poll GET /v1/files/{file_id}/status.
Parameters
POST /v1/files/upload (multipart form)
| Parameter | Required | Description |
|---|---|---|
file |
Yes | The file to upload. Max 75 MB for documents, images, audio and archives; 50 MB for text, code and spreadsheet files (see Size limits) |
scope_type |
Yes | Context where this file will be used. One of: chat, workflow, app, agent, workflow_run, user, entity |
scope_id |
Yes | The ID of the resource specified by scope_type (e.g. the chat_id, app_id, etc.) |
purpose |
No | File purpose. One of: context (default), tmp, tool_output |
only_calculate_tokens |
No | If true, returns the token count without storing the file |
POST /v1/files/upload-url (JSON body)
| Parameter | Required | Description |
|---|---|---|
file_name |
Yes | Original filename |
file_size |
Yes | File size in bytes. Max 75 MB for documents, images, audio and archives; 50 MB for text, code and spreadsheet files (see Size limits) |
mime_type |
Yes | MIME type of the file |
scope_type |
Yes | Context where this file will be used. One of: chat, workflow, app, agent, workflow_run, user, entity |
scope_id |
Yes | The ID of the resource specified by scope_type (e.g. the chat_id, app_id, etc.) |
purpose |
No | File purpose. One of: context (default), tmp, tool_output |
Size limits
Both upload routes enforce the same per-file ceiling, chosen by file type:
| File type | Maximum size |
|---|---|
| Documents (PDF, Word, PowerPoint, etc.), images, audio, archives | 75 MB |
| Text, structured text (Markdown, JSON, XML, etc. — SVG follows this row, not the image row), code, spreadsheets (CSV, XLSX, etc.) | 50 MB |
A further raise to 100 MB for documents, images, audio and archives is rolling out progressively; where it is enabled for your organization, those types accept up to 100 MB. Text, code and spreadsheet files stay at 50 MB either way.
A request over the applicable limit is rejected with 413 and a message naming the limit that applied to that file, so a 76 MB PDF and a 51 MB CSV get different messages.
Audio has a second, separate bound on POST /v1/files/batch-upload-url: at most 3 audio files per request, and at most 180 estimated minutes summed across them, estimated from bytes at an assumed 64 kbps. A batch is refused with 422 — not 413 — only when it breaks one of those two.
One recording at the 75 MB ceiling is about 164 estimated minutes, which leaves 16 minutes for the rest of that request: at 64 kbps that is a second file of up to 7,680,000 bytes (about 7.3 MB). Larger recordings do have to go in separate requests, but a short follow-up clip does not.
GET /v1/files/{file_id}/status
Returns the current processing status of a file.
| Field | Description |
|---|---|
file_uuid |
The file identifier |
status |
One of: uploading, processing, ready, failed |
tokens |
Token count (populated when ready) |
error |
Error message (populated when failed) |
Using Files
Once a file reaches ready status, use its file_id across the API.
Chat Completions
curl 'https://ai.hatz.ai/v1/chat/completions' \
-H 'X-API-Key: $HATZ_API_KEY' \
-H 'Content-Type: application/json' \
-d '{
"messages": [{"role": "user", "content": "tell me about this file"}],
"model": "gpt-4o",
"stream": false,
"file_uuids": ["8fb5bc1d-5a8d-4015-86a6-b0ca394e7793"]
}'
App Builder
curl 'https://ai.hatz.ai/v1/app/5ae6e9dd-0296-4409-8fe4-1fc646bb22f7/query' \
-H 'X-API-Key: $HATZ_API_KEY' \
-H 'Content-Type: application/json' \
-d '{
"inputs": {
"report_file": "8fb5bc1d-5a8d-4015-86a6-b0ca394e7793"
},
"stream": false
}'
Workflows
curl -X POST 'https://ai.hatz.ai/v1/workflows/run' \
-H 'X-API-Key: $HATZ_API_KEY' \
-H 'Content-Type: application/json' \
-d '{
"app_id": "5ae6e9dd-0296-4409-8fe4-1fc646bb22f7",
"inputs": {
"report_file": "8fb5bc1d-5a8d-4015-86a6-b0ca394e7793"
}
}'
In all cases, pass the file's UUID as the input value for any file_upload input.