List Projects
Retrieve all projects in your account with their statistics and metadata. Returns all projects including inactive ones.
Endpoint
GET /api/projectsAuthentication
Required: API key
Authorization: Bearer YOUR_API_KEYRequest
Headers
| Header | Value | Required |
|---|---|---|
Authorization | Bearer YOUR_API_KEY | Yes |
Query Parameters
None. Returns all projects for the authenticated user.
Response
Success Response (200 OK)
{
"projects": [
{
"id": "a1b2c3d4-e5f6-7890-abcd-ef1234567890",
"name": "AI Articles 2025",
"description": "Collection of AI-generated articles",
"bucket_name": "markdown-api-user123-a1b2c3d4",
"is_default": false,
"is_active": true,
"file_count": 42,
"total_size_bytes": 2097152,
"created_date": "2025-01-09T10:00:00Z",
"updated_date": "2025-01-09T15:30:00Z"
},
{
"id": "b2c3d4e5-f6a7-8901-bcde-f1234567890a",
"name": "Default Project",
"description": null,
"bucket_name": "markdown-api-user123-b2c3d4e5",
"is_default": true,
"is_active": true,
"file_count": 15,
"total_size_bytes": 524288,
"created_date": "2025-01-01T00:00:00Z",
"updated_date": "2025-01-05T12:00:00Z"
}
],
"total_count": 2
}Response Fields
| Field | Type | Description |
|---|---|---|
projects | array | Array of project objects |
total_count | integer | Total number of projects returned |
Project Object Fields:
| Field | Type | Description |
|---|---|---|
id | UUID | Unique project identifier |
name | string | Project name |
description | string|null | Project description |
bucket_name | string | GCS bucket name |
is_default | boolean | Whether this is the default project |
is_active | boolean | Whether project is active |
file_count | integer | Number of files in project |
total_size_bytes | integer | Total size of all files in bytes |
created_date | datetime | When project was created (ISO 8601 UTC) |
updated_date | datetime | When project was last updated (ISO 8601 UTC) |
Error Responses
| Status | Error | Description | Solution |
|---|---|---|---|
| 401 | Unauthorized | Missing or invalid authentication | Verify Bearer token or API key |
| 429 | Too Many Requests | Rate limit exceeded | Wait and retry with exponential backoff |
| 500 | Internal Server Error | Server error | Contact support if error persists |
Examples
cURL
curl "https://markdownapi.io/api/projects" \
-H "Authorization: Bearer YOUR_TOKEN"Python (httpx)
import httpx
import os
async def list_projects():
"""List all projects with error handling."""
api_key = os.getenv("MARKDOWN_API_KEY")
async with httpx.AsyncClient() as client:
try:
response = await client.get(
"https://markdownapi.io/api/projects",
headers={"Authorization": f"Bearer {api_key}"},
timeout=10.0
)
response.raise_for_status()
data = response.json()
print(f"Found {data['total_count']} projects:")
for project in data['projects']:
print(f" • {project['name']}")
print(f" Files: {project['file_count']}, "
f"Size: {project['total_size_bytes']} bytes")
return data['projects']
except httpx.HTTPStatusError as e:
print(f"✗ HTTP error: {e.response.status_code}")
raise
except Exception as e:
print(f"✗ Unexpected error: {e}")
raise
# Usage
# projects = await list_projects()TypeScript
interface Project {
id: string;
name: string;
description: string | null;
bucket_name: string;
is_default: boolean;
is_active: boolean;
file_count: number;
total_size_bytes: number;
created_date: string;
updated_date: string;
}
interface ListProjectsResponse {
projects: Project[];
total_count: number;
}
async function listProjects(): Promise<Project[]> {
const apiKey = process.env.MARKDOWN_API_KEY;
try {
const response = await fetch('https://markdownapi.io/api/projects', {
headers: {
'Authorization': `Bearer ${apiKey!}`,
},
});
if (!response.ok) {
throw new Error(`HTTP ${response.status}: ${response.statusText}`);
}
const data: ListProjectsResponse = await response.json();
console.log(`Found ${data.total_count} projects:`);
data.projects.forEach(project => {
console.log(` • ${project.name}`);
console.log(` Files: ${project.file_count}, Size: ${project.total_size_bytes} bytes`);
});
return data.projects;
} catch (error) {
console.error('✗ Failed to list projects:', error);
throw error;
}
}
// Usage
// const projects = await listProjects();Common Use Cases
1. Find Project by Name
async def find_project_by_name(name: str):
"""Find project by exact name match."""
projects = await list_projects()
return next((p for p in projects if p['name'] == name), None)
# Usage
# project = await find_project_by_name("AI Articles 2025")2. Get Default Project
async def get_default_project():
"""Get the default project."""
projects = await list_projects()
return next((p for p in projects if p['is_default']), None)
# Usage
# default_project = await get_default_project()3. Get Active Projects Only
async def get_active_projects():
"""Filter to only active projects."""
projects = await list_projects()
return [p for p in projects if p['is_active']]
# Usage
# active_projects = await get_active_projects()4. Calculate Total Storage
async def calculate_total_storage():
"""Calculate total storage across all projects."""
projects = await list_projects()
total_bytes = sum(p['total_size_bytes'] for p in projects)
total_mb = total_bytes / (1024 * 1024)
print(f"Total storage: {total_mb:.2f} MB")
return total_bytes
# Usage
# total = await calculate_total_storage()5. Sort Projects by Size
async def get_largest_projects(limit: int = 5):
"""Get projects sorted by size (largest first)."""
projects = await list_projects()
sorted_projects = sorted(
projects,
key=lambda p: p['total_size_bytes'],
reverse=True
)
return sorted_projects[:limit]
# Usage
# largest = await get_largest_projects(5)Performance Characteristics
Timing
- Typical duration: 50-150ms
- Scales with: Number of projects (minimal impact up to 1000 projects)
- Optimization: Results include pre-calculated statistics
Caching Recommendations
Projects change infrequently - implement caching:
from datetime import datetime, timedelta
class ProjectCache:
def __init__(self, ttl_minutes: int = 5):
self.cache = None
self.cached_at = None
self.ttl = timedelta(minutes=ttl_minutes)
async def get_projects(self):
"""Get projects with 5-minute cache."""
now = datetime.utcnow()
if self.cache is None or \
self.cached_at is None or \
now - self.cached_at > self.ttl:
self.cache = await list_projects()
self.cached_at = now
return self.cache
# Usage
# cache = ProjectCache(ttl_minutes=5)
# projects = await cache.get_projects() # Cached for 5 minutesBest Practices
1. Cache Results
List projects API is ideal for caching since projects change infrequently.
2. Filter Client-Side
Since all projects are returned, filter in your application rather than making multiple API calls.
3. Store Project IDs
After listing once, store project IDs in your application configuration.
# On application startup
projects = await list_projects()
project_map = {p['name']: p['id'] for p in projects}
# Later, use cached IDs
project_id = project_map['AI Articles 2025']4. Monitor Growth
Track project count over time to plan capacity:
async def check_project_limits():
"""Alert if approaching soft limits."""
projects = await list_projects()
count = len(projects)
if count > 900:
print(f"⚠ Warning: {count} projects (soft limit: 1000)")
elif count > 500:
print(f"ℹ Info: {count} projects")Pagination
Currently, this endpoint returns all projects without pagination. For accounts with many projects (>100), future versions may introduce pagination.
Future API (example):
GET /api/projects?limit=50&offset=100For now, all projects are returned in a single response.
See Also
- Get Project - Get specific project details
- Create Project - Create new projects
- Projects Overview - Learn about projects