> For the complete documentation index, see [llms.txt](https://docs.ninox.com/llms.txt). Markdown versions of documentation pages are available by appending `.md` to page URLs; this page is available as [Markdown](https://docs.ninox.com/ninox-api/de/api-reference/api-endpoints/files.md).

# Files

## Complete a file upload

> Confirms a completed direct upload and returns the file-type field value. Pass \`documentId\`, \`documentVersionId\`, and \`uploadId\` from the generate-upload-url step, and the \`etags\` S3 returned for each uploaded part. The returned object is the complete field value — pass it as-is when creating/updating a record.

```json
{"openapi":"3.0.0","info":{"title":"Ninox Public API","version":"1.0.0"},"security":[{"bearer":[]}],"components":{"securitySchemes":{"bearer":{"scheme":"bearer","bearerFormat":"API Key","description":"Enter your Workspace API key. \n\n API keys can be generated and managed within the **Workspace Integration** settings in the Ninox app.","in":"header","name":"Authorization","type":"http"}},"schemas":{"CompleteFileUploadBody":{"type":"object","properties":{"contentType":{"type":"string","minLength":1,"description":"MIME type of the uploaded file"},"documentId":{"description":"`documentId` returned by the generate-upload-url step","type":"string","minLength":12,"maxLength":12,"pattern":"^[a-z0-9]+$"},"documentVersionId":{"description":"`documentVersionId` returned by the generate-upload-url step","type":"string","minLength":12,"maxLength":12,"pattern":"^[a-z0-9]+$"},"etags":{"minItems":1,"type":"array","items":{"type":"string","minLength":1},"description":"ETag returned by S3 for each uploaded part, in order"},"fileName":{"type":"string","minLength":1,"description":"Original file name"},"fileSize":{"type":"integer","minimum":0,"maximum":9007199254740991,"description":"File size in bytes"},"uploadId":{"type":"string","minLength":1,"description":"`uploadId` returned by the generate-upload-url step"}},"required":["contentType","documentId","documentVersionId","etags","fileName","fileSize","uploadId"],"additionalProperties":false},"CompleteFileUploadResponse":{"type":"object","properties":{"data":{"type":"object","properties":{"documentId":{"type":"string","description":"Document id — store this as part of the field value"},"documentVersionId":{"type":"string","description":"Document version id — store this as part of the field value"},"fileName":{"type":"string","description":"Original file name"},"fileSize":{"type":"number","description":"File size in bytes"},"fileType":{"type":"string","description":"MIME type"}},"description":"The complete file-type field value — pass this object as-is when creating/updating a record"}},"required":["data"]},"ErrorResponse":{"type":"object","properties":{"error":{"type":"object","properties":{"message":{"type":"string","description":"Error message"}}}},"required":["error"]}}},"paths":{"/api/v1/workspace/{workspaceId}/files/complete":{"post":{"operationId":"FilesV1Controller_completeUpload","summary":"Complete a file upload","description":"Confirms a completed direct upload and returns the file-type field value. Pass `documentId`, `documentVersionId`, and `uploadId` from the generate-upload-url step, and the `etags` S3 returned for each uploaded part. The returned object is the complete field value — pass it as-is when creating/updating a record.","parameters":[{"name":"workspaceId","required":true,"in":"path","description":"Workspace ID","schema":{"minLength":12,"maxLength":12,"pattern":"^[a-z0-9]+$","type":"string"}}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/CompleteFileUploadBody"}}}},"responses":{"201":{"description":"Upload completed successfully","content":{"application/json":{"schema":{"$ref":"#/components/schemas/CompleteFileUploadResponse"}}}},"400":{"description":"Bad request","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}},"401":{"description":"Unauthorized","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}},"404":{"description":"Workspace not found","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}},"507":{"description":"Storage quota exceeded","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}}},"tags":["Files"]}}}}
```

## Start a file upload (get presigned URLs)

> Generates presigned URLs for uploading a file directly to storage — the first step of a file-type field upload. Upload the file bytes directly to the returned URL(s) (one per part), then call \`.../files/complete\` with the resulting ETags to finish. This never sends file bytes through this API.

```json
{"openapi":"3.0.0","info":{"title":"Ninox Public API","version":"1.0.0"},"security":[{"bearer":[]}],"components":{"securitySchemes":{"bearer":{"scheme":"bearer","bearerFormat":"API Key","description":"Enter your Workspace API key. \n\n API keys can be generated and managed within the **Workspace Integration** settings in the Ninox app.","in":"header","name":"Authorization","type":"http"}},"schemas":{"GenerateFileUploadUrlBody":{"type":"object","properties":{"contentType":{"type":"string","minLength":1,"description":"MIME type of the file being uploaded"},"parts":{"type":"integer","minimum":1,"maximum":10000,"description":"Number of multipart upload parts (1 for a single-part upload, max 10,000 per S3 limits)"}},"required":["contentType","parts"],"additionalProperties":false},"GenerateFileUploadUrlResponse":{"type":"object","properties":{"data":{"type":"object","properties":{"documentId":{"type":"string","description":"Document id — pass back at the complete step"},"documentVersionId":{"type":"string","description":"Document version id — pass back at the complete step"},"preSignedUrls":{"type":"array","items":{"type":"string"},"description":"One presigned PUT URL per upload part, in order"},"uploadId":{"type":"string","description":"Multipart upload id — pass back at the complete step"}}}},"required":["data"]},"ErrorResponse":{"type":"object","properties":{"error":{"type":"object","properties":{"message":{"type":"string","description":"Error message"}}}},"required":["error"]}}},"paths":{"/api/v1/workspace/{workspaceId}/files/upload-url":{"post":{"operationId":"FilesV1Controller_generateUploadUrl","summary":"Start a file upload (get presigned URLs)","description":"Generates presigned URLs for uploading a file directly to storage — the first step of a file-type field upload. Upload the file bytes directly to the returned URL(s) (one per part), then call `.../files/complete` with the resulting ETags to finish. This never sends file bytes through this API.","parameters":[{"name":"workspaceId","required":true,"in":"path","description":"Workspace ID","schema":{"minLength":12,"maxLength":12,"pattern":"^[a-z0-9]+$","type":"string"}}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/GenerateFileUploadUrlBody"}}}},"responses":{"201":{"description":"Presigned upload URLs generated successfully","content":{"application/json":{"schema":{"$ref":"#/components/schemas/GenerateFileUploadUrlResponse"}}}},"400":{"description":"Bad request","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}},"401":{"description":"Unauthorized","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}},"404":{"description":"Workspace not found","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}}},"tags":["Files"]}}}}
```

## Upload a file to a record

> Uploads a file and attaches it to a record in a single multipart/form-data request, with the file in the \`file\` form field, like the Ninox 3 files endpoint. No presigned URL or complete step is needed. The returned object can also be stored in a file-type field (max. 50 MB).

```json
{"openapi":"3.0.0","info":{"title":"Ninox Public API","version":"1.0.0"},"security":[{"bearer":[]}],"components":{"securitySchemes":{"bearer":{"scheme":"bearer","bearerFormat":"API Key","description":"Enter your Workspace API key. \n\n API keys can be generated and managed within the **Workspace Integration** settings in the Ninox app.","in":"header","name":"Authorization","type":"http"}},"schemas":{"UploadRecordFileResponse":{"type":"object","properties":{"data":{"type":"object","properties":{"documentId":{"type":"string","description":"Document id — store this as part of the field value"},"documentVersionId":{"type":"string","description":"Document version id — store this as part of the field value"},"fileName":{"type":"string","description":"Original file name"},"fileSize":{"type":"number","description":"File size in bytes"},"fileType":{"type":"string","description":"MIME type"}},"description":"The file now attached to the record. The same object can also be stored in a file-type field"}},"required":["data"]},"ErrorResponse":{"type":"object","properties":{"error":{"type":"object","properties":{"message":{"type":"string","description":"Error message"}}}},"required":["error"]}}},"paths":{"/api/v1/workspace/{workspaceId}/modules/{moduleName}/tables/{tableName}/records/{recordId}/files":{"post":{"operationId":"FilesV1Controller_uploadRecordFile","summary":"Upload a file to a record","description":"Uploads a file and attaches it to a record in a single multipart/form-data request, with the file in the `file` form field, like the Ninox 3 files endpoint. No presigned URL or complete step is needed. The returned object can also be stored in a file-type field (max. 50 MB).","parameters":[{"name":"moduleName","required":true,"in":"path","description":"Module name","schema":{"minLength":1,"type":"string"}},{"name":"recordId","required":true,"in":"path","description":"Record ID","schema":{"maximum":9007199254740991,"exclusiveMinimum":true,"type":"integer","minimum":0}},{"name":"tableName","required":true,"in":"path","description":"Table name","schema":{"minLength":1,"type":"string"}},{"name":"workspaceId","required":true,"in":"path","description":"Workspace ID","schema":{"minLength":12,"maxLength":12,"pattern":"^[a-z0-9]+$","type":"string"}}],"requestBody":{"required":true,"content":{"multipart/form-data":{"schema":{"properties":{"file":{"format":"binary","type":"string"}},"required":["file"],"type":"object"}}}},"responses":{"201":{"description":"File uploaded and attached","content":{"application/json":{"schema":{"$ref":"#/components/schemas/UploadRecordFileResponse"}}}},"400":{"description":"Bad request (missing file, etc.)","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}},"401":{"description":"Unauthorized","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}},"404":{"description":"Workspace, table or record not found","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}},"413":{"description":"File too large (max 50 MB)","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}},"507":{"description":"Storage quota exceeded","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}}},"tags":["Files"]}}}}
```


---

# Agent Instructions
This documentation is published with GitBook. GitBook is the documentation platform designed so that both humans and AI agents can read, navigate, and reason over technical content effectively. Learn more at gitbook.com.

## Querying This Documentation
If you need additional information that is not directly available in this page, you can query the documentation by asking a question.

Perform an HTTP GET request on the following URL with the `ask` and `goal` query parameters:

```
GET https://docs.ninox.com/ninox-api/de/api-reference/api-endpoints/files.md?ask=<question>&goal=<user_goal>
```

`ask` is the immediate question: it should be specific, self-contained, and written in natural language.
`goal` is what the user is ultimately trying to achieve, the reason they need the answer. Sharing it helps GitBook give you a better, more relevant answer. A goal is most helpful when it describes the outcome the user wants rather than restating the question. For example, with `ask=how do I create an API token`, a goal like `automate deployments from our CI pipeline` lets GitBook tailor the answer to that use case.

The response will contain a direct answer to the question and relevant excerpts and sources from the documentation.

Use this mechanism when the answer is not explicitly present in the current page, you need clarification or additional context, or you want to retrieve related documentation sections.
