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.