> ## Documentation Index
> Fetch the complete documentation index at: https://docs.gu1.ai/llms.txt
> Use this file to discover all available pages before exploring further.

# Upload Document

> Upload a document and optionally associate it with an entity and category — in the gu1 platform for KYC, KYB, and compliance evidence.

Upload files associated with entities using multipart/form-data.

## Authentication

This endpoint requires authentication via Bearer token and organization context.

**Required Headers:**

* `Authorization: Bearer <jwt-token>`
* `X-Organization-ID: <organization-id>`

## Form Data Parameters

<ParamField body="file" type="File" required>
  The file to upload (any type supported)
</ParamField>

<ParamField body="entityId" type="UUID">
  ID of the entity to associate the document with
</ParamField>

<ParamField body="categoryId" type="UUID">
  ID of the document category (UBO, Legal Representative, Corporate, etc.)
</ParamField>

## Request Example

<CodeGroup>
  ```bash cURL theme={null}
  curl -X POST https://api.gu1.ai/documents/upload \
    -H "Authorization: Bearer YOUR_JWT_TOKEN" \
    -H "X-Organization-ID: YOUR_ORG_ID" \
    -F "file=@/path/to/document.pdf" \
    -F "entityId=bb0c2d24-b519-40ec-b765-86de831ca0af" \
    -F "categoryId=c5e9a3f2-1234-5678-9abc-def012345678"
  ```

  ```javascript JavaScript theme={null}
  const formData = new FormData();
  formData.append('file', fileInput.files[0]);
  formData.append('entityId', 'bb0c2d24-b519-40ec-b765-86de831ca0af');
  formData.append('categoryId', 'c5e9a3f2-1234-5678-9abc-def012345678');

  const response = await fetch('https://api.gu1.ai/documents/upload', {
    method: 'POST',
    headers: {
      'Authorization': `Bearer ${token}`,
      'X-Organization-ID': organizationId
    },
    body: formData
  });

  const document = await response.json();
  ```

  ```python Python theme={null}
  import requests

  files = {'file': open('/path/to/document.pdf', 'rb')}
  data = {
      'entityId': 'bb0c2d24-b519-40ec-b765-86de831ca0af',
      'categoryId': 'c5e9a3f2-1234-5678-9abc-def012345678'
  }

  response = requests.post(
      'https://api.gu1.ai/documents/upload',
      headers={
          'Authorization': f'Bearer {token}',
          'X-Organization-ID': org_id
      },
      files=files,
      data=data
  )

  document = response.json()
  ```
</CodeGroup>

## Response

<ResponseField name="id" type="UUID">
  Unique identifier for the document
</ResponseField>

<ResponseField name="name" type="string">
  Display name of the document
</ResponseField>

<ResponseField name="originalFileName" type="string">
  Original filename of the uploaded file
</ResponseField>

<ResponseField name="fileSize" type="number">
  File size in bytes
</ResponseField>

<ResponseField name="mimeType" type="string">
  MIME type of the file
</ResponseField>

<ResponseField name="storagePath" type="string">
  Path where the file is stored (S3 key or local path)
</ResponseField>

<ResponseField name="storageProvider" type="string">
  Storage provider used ('s3' or 'local')
</ResponseField>

<ResponseField name="categoryId" type="UUID">
  ID of the document category (if assigned)
</ResponseField>

<ResponseField name="organizationId" type="UUID">
  ID of the organization that owns the document
</ResponseField>

<ResponseField name="createdAt" type="timestamp">
  When the document was created
</ResponseField>

## Response Example

```json theme={null}
{
  "id": "d7f8e9c0-1234-5678-9abc-def012345678",
  "name": "document.pdf",
  "description": "Documento subido: document.pdf",
  "type": "other",
  "fileName": "1730649606123_document.pdf",
  "originalFileName": "document.pdf",
  "fileSize": 245678,
  "mimeType": "application/pdf",
  "fileExtension": "pdf",
  "storagePath": "/uploads/1730649606123_document.pdf",
  "storageProvider": "local",
  "securityLevel": "internal",
  "categoryId": "c5e9a3f2-1234-5678-9abc-def012345678",
  "organizationId": "24236b0a-e34d-4218-b3d2-76b101ce8aa9",
  "createdBy": "a1b2c3d4-5678-90ab-cdef-1234567890ab",
  "createdAt": "2025-11-03T15:30:45.123Z",
  "updatedAt": "2025-11-03T15:30:45.123Z"
}
```

## What Happens After Upload

1. **Storage**: File is uploaded to S3 (if enabled) or local storage
2. **Database Record**: Document record is created in the database
3. **Versioning**: Initial version (v1) is automatically created
4. **Entity Relationship**: If `entityId` is provided, a relationship is created automatically
5. **Risk Analysis**: Automatic risk analysis is triggered if rules are configured

## Supported File Types

* **Documents**: PDF, DOC, DOCX, TXT
* **Images**: PNG, JPG, JPEG, GIF
* **Spreadsheets**: XLS, XLSX, CSV
* **Others**: Any file type

## Document Categories

To get available categories, use:

```bash theme={null}
GET /documents/categories
```

Common categories include:

* **UBO (Ultimate Beneficial Owner)**
* **Legal Representative**
* **Corporate Documents**
* **Enhanced Due Diligence**

## Error Responses

<ResponseField name="400" type="error">
  Bad Request - Missing file or authentication

  ```json theme={null}
  {
    "error": "No file provided"
  }
  ```
</ResponseField>

<ResponseField name="401" type="error">
  Unauthorized - Invalid token

  ```json theme={null}
  {
    "error": "Unauthorized - No token provided"
  }
  ```
</ResponseField>

<ResponseField name="500" type="error">
  Internal Server Error

  ```json theme={null}
  {
    "error": "Error interno del servidor",
    "details": "Error message here"
  }
  ```
</ResponseField>

## Notes

<Note>
  The system automatically detects if S3 storage is configured and uses it, otherwise falls back to local storage.
</Note>

<Warning>
  Maximum file size depends on server configuration (typically 50MB).
</Warning>

<Tip>
  Even if `entityId` or `categoryId` don't exist, the document will still be created. The relationship or category assignment will simply be skipped.
</Tip>
