Use Your Own Documents
Learn how to upload text documents and integrate them to enable your assistant to deliver context-aware responses based on the content of your files.
You can upload files. The Copilot uses them as extra context when it generates answers. This guide describes the full lifecycle of a file.
Supported File Types
| Type | MIME Type |
|---|---|
application/pdf | |
| Word (DOCX) | application/vnd.openxmlformats-officedocument.wordprocessingml.document |
| Excel (XLSX) | application/vnd.openxmlformats-officedocument.spreadsheetml.sheet |
| CSV | text/csv |
| Plain Text | text/plain |
Maximum file size: 10 MB.
Get a Signed Upload URL
Request a pre-signed URL to upload your file. The API returns a file_id and a file_url. Use the file_url to PUT the file content.
GET https://api.haufe.ai/agents/v1/files/signed-url
Query Parameters
| Parameter | Type | Required | Description |
|---|---|---|---|
filename | string | Yes | Name of the file including extension |
persist | boolean | No | When true (default), the file is stored permanently. When false, the file is automatically deleted after 24 hours. |
curl --request GET \
--url "https://api.haufe.ai/agents/v1/files/signed-url?filename=report.pdf&persist=true" \
--header 'api-key: <API_KEY>' \
--header 'user-id: <USER_ID>'Response
{
"file_url": "https://example-bucket.s3.amazonaws.com/example-file.txt",
"expires_in": 600,
"file_id": "123e4567-e89b-12d3-a456-426614174000",
"file_limits": {
"max_size": 10485760,
"allowed_types": [
"text/csv",
"text/plain",
"application/pdf",
"application/vnd.openxmlformats-officedocument.wordprocessingml.document",
"application/vnd.openxmlformats-officedocument.spreadsheetml.sheet"
]
}
}The signed URL expires after the time in expires_in (typically 600 seconds). If the upload does not
finish in time, request a new URL.
Upload the File
Use the returned file_url to upload the file content via a PUT request.
curl --request PUT \
--url "<FILE_URL>" \
--header 'Content-Type: application/pdf' \
--data-binary @report.pdfMake sure the Content-Type header matches one of the allowed_types from the signed URL response.
A file with an unsupported type causes a processing error.
Check Processing Status
After the upload, the service processes the file asynchronously. Check the status to confirm the file is ready.
GET https://api.haufe.ai/agents/v1/files/{file_id}/status
curl --request GET \
--url "https://api.haufe.ai/agents/v1/files/<FILE_ID>/status" \
--header 'api-key: <API_KEY>' \
--header 'user-id: <USER_ID>'Response
{
"processing_status": "PROCESSED",
"warnings": {
"length": false,
"infected": false,
"empty": false
}
}processing_status currently takes one of these values:
processing_status | Meaning |
|---|---|
PROCESSED | Terminal. The file is ready to be referenced in a message |
FAILED | Terminal. Processing did not succeed — see processing_steps and validation_steps for the cause |
PENDING_UPLOAD | In progress. The upload has not been completed yet |
PROCESSING | In progress. Text extraction is running |
ANTIVIRUS_SCANNING | In progress. The file is being scanned |
Poll this endpoint until processing_status is PROCESSED or FAILED. Do this before you reference
the file in a message. Treat every other value as "not finished yet". Do not branch on the individual
in-progress states — they are short-lived, and the list above can grow without notice.
On FAILED, read the processing_steps and validation_steps arrays to find the cause.
On PROCESSED, also check the warnings object. The service rejects a file with empty: true or
length: true when you attach it to a message. See
Message Validation for the error codes.
Verify the Upload
List All Files
Retrieve a paginated list of all persisted files for your user. This list includes only files uploaded with persist=true. Temporary files (persist=false) do not appear.
GET https://api.haufe.ai/agents/v1/files
Query Parameters
| Parameter | Type | Required | Description |
|---|---|---|---|
page | integer | No | Page number (1-based). Defaults to 1 |
limit | integer | No | Number of files per page (1–100). Defaults to 30 |
curl --request GET \
--url "https://api.haufe.ai/agents/v1/files?page=1&limit=30" \
--header 'api-key: <API_KEY>' \
--header 'user-id: <USER_ID>'Response
{
"files": [
{
"file_id": "9c3e00fe-1b42-413a-bf44-39ad9491ad86",
"file_name": "report.pdf"
},
{
"file_id": "cbfe557e-144e-43f3-823f-d72be00084a2",
"file_name": "expenses.xlsx"
}
],
"page": 1,
"limit": 30,
"total": 2
}Retrieve File Content
Fetch the extracted text of a file to confirm the service processed it correctly.
GET https://api.haufe.ai/agents/v1/files/{file_id}
curl --request GET \
--url "https://api.haufe.ai/agents/v1/files/<FILE_ID>" \
--header 'api-key: <API_KEY>' \
--header 'user-id: <USER_ID>'The endpoint returns the extracted text of the file as a plain string.
Use with Chat Completions
After the service processes a file, you can reference it in a single stateless request.
Add the file as an attachments entry on a user message:
The top-level user_id must match the user-id header you used during file upload.
Do not set user_id on the attachment itself. At most 3 attachments per message are allowed.
curl --request POST \
--url https://api.haufe.ai/agents/v1/chat/completions \
--header 'content-type: application/json' \
--header 'api-key: <API_KEY>' \
--data '{
"assistant_id": "<ASSISTANT_ID>",
"user_id": "<USER_ID>",
"messages": [
{
"role": "user",
"content": "Summarize the attached report.",
"attachments": [
{
"file_id": "<FILE_ID>"
}
]
}
],
"meta_data": {
"user_data": {
"licence": "<LICENSE_ID>"
}
}
}'Use with Threads
For conversational workflows, create a thread, post a message with the attachment, and run the thread to get a response.
The user_id on the thread must match the user-id header you used during file upload.
Do not set user_id on the attachment itself. At most 3 attachments per message are allowed.
1. Create a thread:
curl --request POST \
--url https://api.haufe.ai/agents/v1/threads \
--header 'content-type: application/json' \
--header 'api-key: <API_KEY>' \
--data '{
"assistant_id": "<ASSISTANT_ID>",
"user_id": "<USER_ID>"
}'2. Post a message with the attachment:
curl --request POST \
--url "https://api.haufe.ai/agents/v1/threads/<THREAD_ID>/messages" \
--header 'content-type: application/json' \
--header 'api-key: <API_KEY>' \
--data '{
"role": "user",
"content": "Summarize the attached report.",
"attachments": [
{
"file_id": "<FILE_ID>"
}
]
}'3. Run the thread:
curl --request POST \
--url "https://api.haufe.ai/agents/v1/threads/<THREAD_ID>/run" \
--header 'content-type: application/json' \
--header 'api-key: <API_KEY>' \
--data '{
"meta_data": {
"user_data": {
"licence": "<LICENSE_ID>"
}
}
}'Check Which Attachments Were Used
The service loads the file content when it generates the answer, not when you attach the file.
So the assistant message reports, per file, whether its content reached the answer. This is in
meta_data.attachments:
{
"role": "assistant",
"content": "The report covers ...",
"meta_data": {
"attachments": [
{ "file_id": "<FILE_ID_1>", "file_name": "report.pdf", "status": "ok" },
{ "file_id": "<FILE_ID_2>", "file_name": "notes.txt", "status": "not_found" }
]
}
}| Field | Meaning |
|---|---|
file_id | The file_id you attached to the message |
file_name | Original name of the file, or null when it is unknown to the service |
status | Whether the content was loaded and considered for the answer, see below |
status | Meaning |
|---|---|
ok | The content was loaded and considered for the answer |
not_found | The file no longer exists on the storage service and was therefore not considered |
error | The file exists but could not be loaded, e.g. the storage service was temporarily unreachable |
empty | The file exists but no text could be extracted from it |
error and empty do not mean the file is gone. The file is still there, but its content
could not be used for this answer.
A file that you deleted via DELETE /files/{file_id} does not appear in the list. The service
skips it on purpose and does not report it as a failure.
In streaming mode this data arrives in a separate chunk with an empty content.
Like the rest of meta_data, this field is part of the assistant response schema. Use
GET /assistants/{assistant_id} to check whether your assistant returns it.
Delete a File
Remove a file that you no longer need. After deletion, you cannot reference the file in new messages. The service also stops using it for response generation in threads that contained it.
DELETE https://api.haufe.ai/agents/v1/files/{file_id}
curl --request DELETE \
--url "https://api.haufe.ai/agents/v1/files/<FILE_ID>" \
--header 'api-key: <API_KEY>' \
--header 'user-id: <USER_ID>'Returns 204 No Content on success with an empty response body.