Skip to Content

Get Project

Retrieve detailed information about a specific project by its ID.

Endpoint

GET /api/projects/{project_id}

Authentication

Required: API key

Authorization: Bearer YOUR_API_KEY

Request

Path Parameters

ParameterTypeRequiredDescription
project_idUUIDYesUnique project identifier

Headers

HeaderValueRequired
AuthorizationBearer YOUR_API_KEYYes

Response

Success Response (200 OK)

{ "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" }

Response Fields

FieldTypeDescription
idUUIDUnique project identifier
namestringProject name
descriptionstring|nullProject description
bucket_namestringGCS bucket name
is_defaultbooleanWhether this is the default project
is_activebooleanWhether project is active
file_countintegerNumber of files in project
total_size_bytesintegerTotal size of all files in bytes
created_datedatetimeWhen project was created (ISO 8601 UTC)
updated_datedatetimeWhen project was last updated (ISO 8601 UTC)

Error Responses

StatusErrorDescriptionSolution
401UnauthorizedMissing or invalid authenticationVerify Bearer token or API key
403ForbiddenProject belongs to another userVerify project_id belongs to your account
404Not FoundProject doesn’t existCheck project_id is correct
422Unprocessable EntityInvalid UUID formatEnsure project_id is valid UUID
429Too Many RequestsRate limit exceededWait and retry with exponential backoff
500Internal Server ErrorServer errorContact support if error persists

Example Error Response (404 Not Found):

{ "detail": "Project not found" }

Example Error Response (422 Validation):

{ "detail": [ { "loc": ["path", "project_id"], "msg": "value is not a valid uuid", "type": "type_error.uuid" } ] }

Examples

cURL

curl "https://markdownapi.io/api/projects/a1b2c3d4-e5f6-7890-abcd-ef1234567890" \ -H "Authorization: Bearer YOUR_TOKEN"

Python (httpx)

import httpx import os from uuid import UUID async def get_project(project_id: UUID | str): """Get project details by ID with error handling.""" api_key = os.getenv("MARKDOWN_API_KEY") async with httpx.AsyncClient() as client: try: response = await client.get( f"https://markdownapi.io/api/projects/{project_id}", headers={"Authorization": f"Bearer {api_key}"}, timeout=10.0 ) response.raise_for_status() project = response.json() print(f"Project: {project['name']}") print(f" Files: {project['file_count']}") print(f" Size: {project['total_size_bytes']:,} bytes") print(f" Created: {project['created_date']}") return project except httpx.HTTPStatusError as e: if e.response.status_code == 404: print(f"✗ Project not found") elif e.response.status_code == 403: print(f"✗ Access denied - not your project") else: print(f"✗ HTTP error: {e.response.status_code}") raise except Exception as e: print(f"✗ Unexpected error: {e}") raise # Usage # project = await get_project("a1b2c3d4-e5f6-7890-abcd-ef1234567890")

TypeScript

interface ProjectResponse { 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; } async function getProject(projectId: string): Promise<ProjectResponse> { const apiKey = process.env.MARKDOWN_API_KEY; try { const response = await fetch( `https://markdownapi.io/api/projects/${projectId}`, { headers: { 'Authorization': `Bearer ${apiKey!}`, }, } ); if (!response.ok) { if (response.status === 404) { throw new Error('Project not found'); } else if (response.status === 403) { throw new Error('Access denied - not your project'); } throw new Error(`HTTP ${response.status}: ${response.statusText}`); } const project: ProjectResponse = await response.json(); console.log(`Project: ${project.name}`); console.log(` Files: ${project.file_count}`); console.log(` Size: ${project.total_size_bytes.toLocaleString()} bytes`); console.log(` Created: ${project.created_date}`); return project; } catch (error) { console.error('✗ Failed to get project:', error); throw error; } } // Usage // const project = await getProject('a1b2c3d4-e5f6-7890-abcd-ef1234567890');

Common Use Cases

1. Check Project Storage

async def check_project_storage(project_id: UUID): """Check if project is approaching storage limits.""" project = await get_project(project_id) size_mb = project['total_size_bytes'] / (1024 * 1024) if size_mb > 90 * 1024: # 90 GB print(f"⚠ Warning: {size_mb:.1f} MB (limit: 100 GB)") else: print(f"Storage: {size_mb:.1f} MB") return size_mb # Usage # storage = await check_project_storage(project_id)

2. Verify Project Exists

async def project_exists(project_id: UUID) -> bool: """Check if project exists and is accessible.""" try: await get_project(project_id) return True except httpx.HTTPStatusError as e: if e.response.status_code in (404, 403): return False raise # Usage # if await project_exists(project_id): # print("Project exists")

3. Get Project Statistics

async def get_project_stats(project_id: UUID): """Get formatted project statistics.""" project = await get_project(project_id) return { 'name': project['name'], 'files': project['file_count'], 'size_mb': project['total_size_bytes'] / (1024 * 1024), 'avg_file_size_kb': (project['total_size_bytes'] / project['file_count'] / 1024) if project['file_count'] > 0 else 0, 'is_active': project['is_active'], } # Usage # stats = await get_project_stats(project_id)

4. Refresh Project Info

async def refresh_project_info(project_id: UUID): """Refresh cached project information.""" project = await get_project(project_id) # Update your cache/state app.state.projects[project_id] = project print(f"✓ Refreshed: {project['name']}") print(f" Files: {project['file_count']}") print(f" Last updated: {project['updated_date']}") return project # Usage # project = await refresh_project_info(project_id)

5. Compare Project Sizes

async def compare_projects(project_ids: list[UUID]): """Compare storage usage across projects.""" projects = await asyncio.gather(*[ get_project(pid) for pid in project_ids ]) for project in sorted(projects, key=lambda p: p['total_size_bytes'], reverse=True): size_mb = project['total_size_bytes'] / (1024 * 1024) print(f"{project['name']}: {size_mb:.2f} MB ({project['file_count']} files)") # Usage # await compare_projects([project_id_1, project_id_2, project_id_3])

Performance Characteristics

Timing

  • Typical duration: 20-50ms
  • Single database query with pre-calculated statistics
  • Fast lookups using indexed project_id

Caching Strategy

Since statistics update with every file operation, caching should be short-lived:

from functools import lru_cache from datetime import datetime, timedelta class ProjectInfoCache: def __init__(self): self.cache = {} self.ttl = timedelta(minutes=1) async def get(self, project_id: UUID): """Get project with 1-minute cache.""" cache_entry = self.cache.get(project_id) if cache_entry: cached_at, project = cache_entry if datetime.utcnow() - cached_at < self.ttl: return project project = await get_project(project_id) self.cache[project_id] = (datetime.utcnow(), project) return project # Usage # cache = ProjectInfoCache() # project = await cache.get(project_id)

Best Practices

1. Validate UUID Format

from uuid import UUID def validate_project_id(project_id: str) -> UUID: """Validate and convert project ID to UUID.""" try: return UUID(project_id) except ValueError: raise ValueError(f"Invalid project ID format: {project_id}") # Usage # project_id = validate_project_id(user_input)

2. Handle Not Found Gracefully

async def get_project_safe(project_id: UUID): """Get project with graceful not-found handling.""" try: return await get_project(project_id) except httpx.HTTPStatusError as e: if e.response.status_code == 404: return None # Or default project raise # Usage # project = await get_project_safe(project_id) # if project is None: # project = await get_default_project()

3. Use for Verification

Always verify project exists before file operations:

async def upload_file_to_project(project_id: UUID, file_path: str): """Upload file with project verification.""" # Verify project exists first project = await get_project(project_id) if not project['is_active']: raise ValueError("Cannot upload to inactive project") # Proceed with upload await upload_file(project_id, file_path)

See Also

Last updated on