Upload File
Upload a file directly to create a knowledge item. This endpoint handles file uploads using multipart/form-data and automatically processes the file into searchable knowledge.
Endpoint
POST /v1/workspaces/{workspaceId}/knowledge/fileAuthentication
This endpoint requires a Bearer token obtained through the two-step authentication flow:
- First, generate an access token using your API key
- Use that access token in the Authorization header
See Authentication for the complete authentication flow.
Required Headers:
Authorization: Bearer {access_token}- The JWT access token (NOT your raw API key)organizationid: {your-organization-id}- Your organization ID
Path Parameters
| Parameter | Type | Required | Description |
|---|---|---|---|
workspaceId | string (UUID) | Yes | The ID of your workspace |
Request Body
This endpoint uses multipart/form-data encoding to handle file uploads.
| Field | Type | Required | Description |
|---|---|---|---|
file | File | Yes | The file to upload (binary data) |
title | string | No | Optional title for the knowledge item |
description | string | No | Optional description for the knowledge item |
language | string | No | Optional language code (e.g., 'en', 'es', 'fr') |
status | string | No | Processing mode: BACKGROUND_START for async. Default: synchronous |
Supported File Types
Documents
application/pdf- PDF documentsapplication/msword- Word documents (.doc)application/vnd.openxmlformats-officedocument.wordprocessingml.document- Word documents (.docx)text/plain- Text filestext/markdown- Markdown files
Spreadsheets
application/vnd.ms-excel- Excel files (.xls)application/vnd.openxmlformats-officedocument.spreadsheetml.sheet- Excel files (.xlsx)text/csv- CSV files
Images
image/jpeg- JPEG imagesimage/png- PNG imagesimage/gif- GIF imagesimage/webp- WebP images
Media
video/mp4- MP4 videosaudio/mpeg- MP3 audioaudio/wav- WAV audio
Archives
application/zip- ZIP archivesapplication/x-zip-compressed- ZIP archives (alternate)
Data
application/json- JSON files
Response
Success Response
Status Code: 200 OK
Body:
{
"uploadFileMetadataId": "550e8400-e29b-41d4-a716-446655440000",
"title": "Product Documentation",
"description": "Complete product documentation",
"language": "en",
"status": "BACKGROUND_START"
}| Field | Type | Description |
|---|---|---|
uploadFileMetadataId | string (UUID) | Unique identifier to track the upload and retrieve the knowledge item |
title | string | Title provided in the request |
description | string | Description provided in the request |
language | string | Language code provided in the request |
status | string | Processing mode from request |
Important: The uploadFileMetadataId is returned immediately after the file is uploaded. Use this ID to track the processing status and retrieve the created knowledge item.
Tracking Upload Progress
After uploading a file, you can track its processing status using a two-step approach:
Step 1: Get the Knowledge ID
Use the uploadFileMetadataId from the upload response to retrieve the knowledge item ID:
curl -X GET \
'https://api.sharely.ai/v1/workspaces/your-workspace-id/upload-file-metadata/550e8400-e29b-41d4-a716-446655440000' \
-H "Authorization: Bearer $ACCESS_TOKEN" \
-H 'organizationid: your-organization-id'Response (while processing):
{
"knowledge": null,
"spaceKnowledge": null
}Response (after knowledge is created):
{
"knowledge": {
"id": "123e4567-e89b-12d3-a456-426614174000",
"metadata": {
"title": "Product Documentation",
"type": "FILE"
}
},
"spaceKnowledge": null
}Note: The knowledge field will be null until the background processing creates the knowledge item. Poll this endpoint until knowledge is not null.
Step 2: Check Processing Status
Once you have the knowledge ID, check the current processing status:
curl -X GET \
'https://api.sharely.ai/v1/workspaces/your-workspace-id/knowledge/123e4567-e89b-12d3-a456-426614174000' \
-H "Authorization: Bearer $ACCESS_TOKEN" \
-H 'organizationid: your-organization-id'Response:
{
"id": "123e4567-e89b-12d3-a456-426614174000",
"type": "FILE",
"content": "workspaces/your-workspace-id/knowledge/pdf/product-documentation.pdf",
"status": "COMPLETED",
"metadata": {
"title": "Product Documentation",
"description": "Complete product documentation"
},
"createdAt": "2025-01-15T10:30:00.000Z"
}Status Values
| Status | Description |
|---|---|
BACKGROUND_START | File is being processed (extraction, indexing) |
COMPLETED | Processing finished successfully |
BACKGROUND_ERROR | Processing failed - check file format or contact support |
Polling Example
Here's a complete example that uploads a file and polls for completion:
async function uploadAndWaitForCompletion(accessToken, file, options = {}) {
// Step 1: Upload the file
const formData = new FormData();
formData.append('file', file);
formData.append('title', options.title || file.name);
formData.append('status', 'BACKGROUND_START');
const uploadResponse = await fetch(
`${API_BASE_URL}/v1/workspaces/${WORKSPACE_ID}/knowledge/file`,
{
method: 'POST',
headers: {
'Authorization': `Bearer ${accessToken}`,
'organizationid': ORGANIZATION_ID
},
body: formData
}
);
const { uploadFileMetadataId } = await uploadResponse.json();
// Step 2: Poll until knowledge ID is available
let knowledgeId = null;
const maxMetadataAttempts = 60;
for (let attempt = 0; attempt < maxMetadataAttempts; attempt++) {
const metadataResponse = await fetch(
`${API_BASE_URL}/v1/workspaces/${WORKSPACE_ID}/upload-file-metadata/${uploadFileMetadataId}`,
{
headers: {
'Authorization': `Bearer ${accessToken}`,
'organizationid': ORGANIZATION_ID
}
}
);
const { knowledge } = await metadataResponse.json();
if (knowledge?.id) {
knowledgeId = knowledge.id;
break;
}
// Wait 5 seconds before next poll
await new Promise(resolve => setTimeout(resolve, 5000));
}
if (!knowledgeId) {
throw new Error('Timed out waiting for knowledge to be created');
}
// Step 3: Poll for processing completion
const maxStatusAttempts = 60;
for (let attempt = 0; attempt < maxStatusAttempts; attempt++) {
const statusResponse = await fetch(
`${API_BASE_URL}/v1/workspaces/${WORKSPACE_ID}/knowledge/${knowledgeId}`,
{
headers: {
'Authorization': `Bearer ${accessToken}`,
'organizationid': ORGANIZATION_ID
}
}
);
const knowledgeItem = await statusResponse.json();
if (knowledgeItem.status === 'COMPLETED') {
return knowledgeItem;
}
if (knowledgeItem.status === 'BACKGROUND_ERROR') {
throw new Error(`File processing failed: ${knowledgeItem.messageError || 'Unknown error'}`);
}
// Wait 5 seconds before next poll
await new Promise(resolve => setTimeout(resolve, 5000));
}
throw new Error('Timed out waiting for processing to complete');
}
// Usage
const accessToken = await getAccessToken();
const result = await uploadAndWaitForCompletion(accessToken, file, {
title: 'My Document'
});
console.log('Upload complete:', result.id);import time
import requests
def upload_and_wait_for_completion(access_token, file_path, title=None, timeout=300):
headers = {
'Authorization': f'Bearer {access_token}',
'organizationid': ORGANIZATION_ID
}
# Step 1: Upload the file
with open(file_path, 'rb') as f:
files = {'file': f}
data = {
'title': title or file_path.split('/')[-1],
'status': 'BACKGROUND_START'
}
upload_response = requests.post(
f'{API_BASE_URL}/v1/workspaces/{WORKSPACE_ID}/knowledge/file',
headers=headers,
files=files,
data=data
)
upload_file_metadata_id = upload_response.json()['uploadFileMetadataId']
# Step 2: Poll until knowledge ID is available
knowledge_id = None
start_time = time.time()
while time.time() - start_time < timeout:
metadata_response = requests.get(
f'{API_BASE_URL}/v1/workspaces/{WORKSPACE_ID}/upload-file-metadata/{upload_file_metadata_id}',
headers=headers
)
knowledge = metadata_response.json().get('knowledge')
if knowledge and knowledge.get('id'):
knowledge_id = knowledge['id']
break
time.sleep(5) # Wait 5 seconds before next poll
if not knowledge_id:
raise Exception('Timed out waiting for knowledge to be created')
# Step 3: Poll for processing completion
while time.time() - start_time < timeout:
status_response = requests.get(
f'{API_BASE_URL}/v1/workspaces/{WORKSPACE_ID}/knowledge/{knowledge_id}',
headers=headers
)
knowledge_item = status_response.json()
if knowledge_item['status'] == 'COMPLETED':
return knowledge_item
if knowledge_item['status'] == 'BACKGROUND_ERROR':
error_msg = knowledge_item.get('messageError', 'Unknown error')
raise Exception(f'File processing failed: {error_msg}')
time.sleep(5) # Wait 5 seconds before next poll
raise Exception('Timed out waiting for processing to complete')
# Usage
access_token = get_access_token()
result = upload_and_wait_for_completion(access_token, './document.pdf', title='My Document')
print(f"Upload complete: {result['id']}")Upload Workflow
This endpoint provides a simple, single-step file upload process using multipart/form-data.
Direct Upload (Single Request)
Upload a file and create the knowledge item in one request:
# Step 1: Generate access token (do this once, reuse for multiple requests)
ACCESS_TOKEN=$(curl -s -X POST \
'https://api.sharely.ai/workspaces/your-workspace-id/generate-access-key-token' \
-H 'Content-Type: application/json' \
-H 'x-api-key: sk-sharely-your-api-key' \
-d '{}' | jq -r '.token')
# Step 2: Upload the file using the access token
curl -X POST \
'https://api.sharely.ai/v1/workspaces/your-workspace-id/knowledge/file' \
-H "Authorization: Bearer $ACCESS_TOKEN" \
-H 'organizationid: your-organization-id' \
-F 'file=@/path/to/product-documentation.pdf' \
-F 'title=Product Documentation' \
-F 'status=BACKGROUND_START'Response:
{
"id": "123e4567-e89b-12d3-a456-426614174000",
"knowledgeId": "123e4567-e89b-12d3-a456-426614174000",
"title": "Product Documentation",
"type": "FILE",
"status": "PROCESSING"
}With Description and Language
Include optional description and language with your upload:
# Using the access token from Step 1 above
curl -X POST \
'https://api.sharely.ai/v1/workspaces/your-workspace-id/knowledge/file' \
-H "Authorization: Bearer $ACCESS_TOKEN" \
-H 'organizationid: your-organization-id' \
-F 'file=@/path/to/document.pdf' \
-F 'title=Technical Specification' \
-F 'description=Complete technical specification for version 2.0' \
-F 'language=en' \
-F 'status=BACKGROUND_START'Complete Example
Here's a complete example in different languages:
cURL
# Step 1: Generate access token
ACCESS_TOKEN=$(curl -s -X POST \
'https://api.sharely.ai/workspaces/your-workspace-id/generate-access-key-token' \
-H 'Content-Type: application/json' \
-H 'x-api-key: sk-sharely-your-api-key' \
-d '{}' | jq -r '.token')
# Step 2: Upload a file and create knowledge item
curl -X POST \
'https://api.sharely.ai/v1/workspaces/your-workspace-id/knowledge/file' \
-H "Authorization: Bearer $ACCESS_TOKEN" \
-H 'organizationid: your-organization-id' \
-F 'file=@./document.pdf' \
-F 'title=My Document' \
-F 'description=Documentation for my project' \
-F 'language=en' \
-F 'status=BACKGROUND_START'JavaScript/TypeScript
const API_KEY = 'sk-sharely-your-api-key';
const WORKSPACE_ID = 'your-workspace-id';
const ORGANIZATION_ID = 'your-organization-id';
const API_BASE_URL = 'https://api.sharely.ai';
// Step 1: Generate access token
async function getAccessToken() {
const response = await fetch(
`${API_BASE_URL}/workspaces/${WORKSPACE_ID}/generate-access-key-token`,
{
method: 'POST',
headers: {
'Content-Type': 'application/json',
'x-api-key': API_KEY
},
body: JSON.stringify({})
}
);
if (!response.ok) {
throw new Error(`Failed to get access token: ${response.statusText}`);
}
const data = await response.json();
return data.token;
}
// Step 2: Upload file using access token
async function uploadFile(accessToken, file, options = {}) {
const formData = new FormData();
formData.append('file', file);
formData.append('title', options.title || file.name);
if (options.description) {
formData.append('description', options.description);
}
if (options.language) {
formData.append('language', options.language);
}
formData.append('status', 'BACKGROUND_START');
const response = await fetch(
`${API_BASE_URL}/v1/workspaces/${WORKSPACE_ID}/knowledge/file`,
{
method: 'POST',
headers: {
'Authorization': `Bearer ${accessToken}`,
'organizationid': ORGANIZATION_ID
},
body: formData
}
);
if (!response.ok) {
throw new Error(`Upload failed: ${response.statusText}`);
}
return await response.json();
}
// Usage
const fileInput = document.querySelector('input[type="file"]');
const file = fileInput.files[0];
// Get token and upload
const accessToken = await getAccessToken();
const result = await uploadFile(accessToken, file, {
title: 'My Document',
description: 'Documentation for my project',
language: 'en'
});
console.log('Knowledge created:', result.id);Python
import requests
API_KEY = 'sk-sharely-your-api-key'
WORKSPACE_ID = 'your-workspace-id'
ORGANIZATION_ID = 'your-organization-id'
API_BASE_URL = 'https://api.sharely.ai'
# Step 1: Generate access token
def get_access_token():
response = requests.post(
f'{API_BASE_URL}/workspaces/{WORKSPACE_ID}/generate-access-key-token',
headers={
'Content-Type': 'application/json',
'x-api-key': API_KEY
},
json={}
)
response.raise_for_status()
return response.json()['token']
# Step 2: Upload file using access token
def upload_file(access_token, file_path, title=None, description=None, language=None):
# Prepare the multipart form data
files = {
'file': open(file_path, 'rb')
}
data = {
'title': title or file_path.split('/')[-1],
'status': 'BACKGROUND_START'
}
if description:
data['description'] = description
if language:
data['language'] = language
# Upload the file
response = requests.post(
f'{API_BASE_URL}/v1/workspaces/{WORKSPACE_ID}/knowledge/file',
headers={
'Authorization': f'Bearer {access_token}',
'organizationid': ORGANIZATION_ID
},
files=files,
data=data
)
response.raise_for_status()
return response.json()
# Usage
access_token = get_access_token()
result = upload_file(
access_token,
'./document.pdf',
title='My Document',
description='Documentation for my project',
language='en'
)
print(f"Knowledge created: {result['id']}")Error Responses
400 Bad Request
Missing or invalid request parameters:
{
"error": "Bad Request",
"message": "Missing required field: fileName"
}Or unsupported file type:
{
"error": "Bad Request",
"message": "Unsupported file type"
}401 Unauthorized
Invalid or missing API key:
{
"error": "Unauthorized",
"message": "Invalid or missing API key"
}403 Forbidden
Insufficient permissions or storage quota exceeded:
{
"error": "Forbidden",
"message": "Storage quota exceeded"
}500 Internal Server Error
Failed to generate signed URL:
{
"error": "Internal Server Error",
"message": "Failed to generate upload URL"
}Best Practices
Use Async Processing for Large Files
- For files larger than 10MB, set
status: "BACKGROUND_START" - This prevents timeout errors during processing
- Poll the knowledge status to check processing completion
Set Clear Titles
- Always provide a descriptive title
- If omitted, the filename will be used
- Clear titles improve searchability
Include Description and Language
- Add descriptions for better context and searchability
- Specify the language code for multilingual content
- Use clear, concise descriptions that explain the document's purpose
Error Handling
try {
const response = await uploadFile(file);
console.log('Upload successful:', response.id);
} catch (error) {
if (error.status === 403) {
console.error('Storage quota exceeded');
} else if (error.status === 400) {
console.error('Invalid file type or parameters');
} else if (error.status === 413) {
console.error('File too large');
} else {
console.error('Upload failed:', error.message);
}
}Check File Size Limits
- Verify file size before upload
- Check your workspace plan for limits
- Split large documents if necessary
Notes
Direct Upload
- This endpoint provides a single-step upload process
- Files are uploaded using multipart/form-data
- Processing begins immediately after upload completes
File Size Limits
- Check your workspace plan for file size limits
- Free tier: Up to 10MB per file
- Pro tier: Up to 50MB per file
- Enterprise plans support larger files
- Contact support for custom limits
Processing Time
- Small files (< 10MB): Typically under 1 minute
- Medium files (10-50MB): 1-5 minutes
- Large files (> 50MB): 5+ minutes
- Use
status: "BACKGROUND_START"for async processing
Content Extraction
- PDFs: Text and embedded images are extracted
- Office docs: Full content extraction with formatting preserved
- Images: OCR is applied to extract text
- Archives: Contents are extracted and processed individually
Related Endpoints
- Get Upload File Metadata - Track upload progress and get knowledge ID
- Get Knowledge - Check processing status and retrieve knowledge details
- Create Knowledge - Create other types of knowledge
- Create Link - Create link references without upload
- Search Knowledge - Find uploaded files
- Delete Knowledge - Remove uploaded files