Upload File
Upload a Markdown or MDX file to a project. Files are stored in Google Cloud Storage and can be retrieved later.
Endpoint
POST /api/projects/{project_id}/filesAuthentication
Required: API key in Authorization header
Authorization: Bearer YOUR_API_KEYRequest
Path Parameters
| Parameter | Type | Required | Description |
|---|---|---|---|
project_id | UUID | Yes | The project ID |
Headers
| Header | Value | Required |
|---|---|---|
Content-Type | multipart/form-data | Yes |
Request Body
| Field | Type | Required | Constraints | Description |
|---|---|---|---|---|
file | file | Yes | .md or .mdx, max 10MB | The Markdown/MDX file |
metadata | JSON string | No | Valid JSON object | Optional metadata |
File Constraints:
- Extensions:
.md,.mdx - Maximum size: 10 MB
- Unique filename within project
- UTF-8 encoding
Response
Success Response (201 Created)
{
"filename": "article.mdx",
"project_id": "a1b2c3d4-e5f6-7890-abcd-ef1234567890",
"size_bytes": 4096,
"content_type": "text/markdown",
"metadata": {
"title": "My Article",
"author": "John Doe"
},
"storage_path": "gs://markdown-api-user123-a1b2c3d4/article.mdx",
"created_date": "2025-01-09T10:00:00Z",
"updated_date": "2025-01-09T10:00:00Z"
}Error Responses
| Status | Error | Description |
|---|---|---|
| 400 | Bad Request | Invalid file format |
| 401 | Unauthorized | Invalid authentication |
| 404 | Not Found | Project does not exist |
| 409 | Conflict | File already exists |
| 413 | Payload Too Large | File exceeds 10MB |
| 415 | Unsupported Media Type | Invalid extension |
Examples
cURL
curl -X POST "https://markdownapi.io/api/projects/PROJECT_ID/files" \
-H "Authorization: Bearer YOUR_TOKEN" \
-F "file=@article.mdx" \
-F 'metadata={"title":"My Article","author":"John Doe"}'Python (httpx)
import httpx
import os
import json
async def upload_file(project_id: str, file_path: str, metadata: dict | None = None):
api_key = os.getenv("MARKDOWN_API_KEY")
async with httpx.AsyncClient() as client:
with open(file_path, 'rb') as f:
files = {'file': (os.path.basename(file_path), f, 'text/markdown')}
data = {}
if metadata:
data['metadata'] = json.dumps(metadata)
response = await client.post(
f"https://markdownapi.io/api/projects/{project_id}/files",
headers={"Authorization": f"Bearer {api_key}"},
files=files,
data=data,
timeout=60.0
)
response.raise_for_status()
file_info = response.json()
print(f"✓ File uploaded: {file_info['filename']}")
print(f" Size: {file_info['size_bytes']} bytes")
return file_infoTypeScript
interface UploadFileOptions {
projectId: string;
file: File;
metadata?: Record<string, any>;
}
async function uploadFile({ projectId, file, metadata }: UploadFileOptions) {
const apiKey = process.env.MARKDOWN_API_KEY;
const formData = new FormData();
formData.append('file', file);
if (metadata) {
formData.append('metadata', JSON.stringify(metadata));
}
const response = await fetch(
`https://markdownapi.io/api/projects/${projectId}/files`,
{
method: 'POST',
headers: { 'Authorization': `Bearer ${apiKey!}` },
body: formData,
}
);
if (!response.ok) throw new Error(`HTTP ${response.status}`);
const fileInfo = await response.json();
console.log(`✓ File uploaded: ${fileInfo.filename}`);
return fileInfo;
}Best Practices
Unique Filenames
Use descriptive, unique filenames:
# Good
"2025-01-09-introduction-to-ai.mdx"
"client-abc-report-q1-2025.md"
# Avoid
"article.mdx"
"file.md"Rich Metadata
Include comprehensive metadata:
metadata = {
"title": "Introduction to AI",
"author": "Jane Doe",
"date": "2025-01-09",
"tags": ["ai", "tutorial"],
"status": "published"
}Error Handling
Always handle upload errors:
try:
file_info = await upload_file(project_id, file_path)
except httpx.HTTPStatusError as e:
if e.response.status_code == 409:
# Handle duplicate
pass
elif e.response.status_code == 413:
# Handle file too large
passValidate Before Upload
Check file validity:
def validate_file(file_path: str):
# Check extension
if not file_path.endswith(('.md', '.mdx')):
raise ValueError("File must be .md or .mdx")
# Check size
import os
size_mb = os.path.getsize(file_path) / (1024 * 1024)
if size_mb > 10:
raise ValueError(f"File too large: {size_mb:.2f}MB (max 10MB)")Rate Limiting
Upload operations are rate-limited:
- Standard accounts: 1000 requests/hour
- Recommended: 10-50 uploads/minute
- Burst allowance: Up to 100 uploads/minute
See Also
- List Files - View files in project
- Download File - Retrieve file content
- Update Content - Modify file content
- Delete File - Remove files
- Files Concepts - Deep dive into file concepts
Last updated on