Skip to Content

Update Project

Update a project’s name or description. This operation does not affect the project’s files or storage.

Endpoint

PUT /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
Content-Typeapplication/jsonYes

Request Body

{ "name": "AI Articles 2025 - Updated", "description": "Updated description for AI articles collection" }

Fields

FieldTypeRequiredConstraintsDescription
namestringNo1-255 chars, uniqueNew project name
descriptionstring|nullNoAny lengthNew project description

Update Behavior:

  • Both fields are optional - provide only fields you want to update
  • null for description will clear the description
  • Name must still be unique if provided
  • At least one field must be provided

Response

Success Response (200 OK)

{ "id": "a1b2c3d4-e5f6-7890-abcd-ef1234567890", "name": "AI Articles 2025 - Updated", "description": "Updated description for AI articles collection", "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-09T16:00:00Z" }

Error Responses

StatusErrorDescriptionSolution
400Bad RequestNo fields provided or invalid JSONProvide at least one field to update
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
409ConflictNew name already existsChoose different name
422Unprocessable EntityValidation errorCheck field constraints
429Too Many RequestsRate limit exceededWait and retry
500Internal Server ErrorServer errorContact support if persists

Examples

cURL

# Update name only curl -X PUT "https://markdownapi.io/api/projects/a1b2c3d4-e5f6-7890-abcd-ef1234567890" \ -H "Authorization: Bearer YOUR_TOKEN" \ -H "Content-Type: application/json" \ -d '{"name": "AI Articles 2025 - Updated"}' # Update description only curl -X PUT "https://markdownapi.io/api/projects/a1b2c3d4-e5f6-7890-abcd-ef1234567890" \ -H "Authorization: Bearer YOUR_TOKEN" \ -H "Content-Type: application/json" \ -d '{"description": "New description"}' # Update both curl -X PUT "https://markdownapi.io/api/projects/a1b2c3d4-e5f6-7890-abcd-ef1234567890" \ -H "Authorization: Bearer YOUR_TOKEN" \ -H "Content-Type: application/json" \ -d '{ "name": "AI Articles 2025 - Updated", "description": "New description" }' # Clear description curl -X PUT "https://markdownapi.io/api/projects/a1b2c3d4-e5f6-7890-abcd-ef1234567890" \ -H "Authorization: Bearer YOUR_TOKEN" \ -H "Content-Type: application/json" \ -d '{"description": null}'

Python (httpx)

import httpx import os from uuid import UUID async def update_project( project_id: UUID, name: str | None = None, description: str | None = None ): """Update project with optional name and description.""" if name is None and description is None: raise ValueError("Must provide at least one field to update") api_key = os.getenv("MARKDOWN_API_KEY") update_data = {} if name is not None: update_data["name"] = name if description is not None: update_data["description"] = description async with httpx.AsyncClient() as client: try: response = await client.put( f"https://markdownapi.io/api/projects/{project_id}", headers={"Authorization": f"Bearer {api_key}"}, json=update_data, timeout=10.0 ) response.raise_for_status() project = response.json() print(f"✓ Project updated: {project['name']}") print(f" Updated: {project['updated_date']}") return project except httpx.HTTPStatusError as e: if e.response.status_code == 409: print(f"✗ Name already exists") elif e.response.status_code == 404: print(f"✗ Project not found") else: print(f"✗ HTTP error: {e.response.status_code}") raise # Usage # project = await update_project( # project_id=UUID("a1b2c3d4-e5f6-7890-abcd-ef1234567890"), # name="New Name", # description="New description" # )

TypeScript

interface UpdateProjectRequest { name?: string; description?: string | null; } async function updateProject( projectId: string, updates: UpdateProjectRequest ): Promise<ProjectResponse> { if (!updates.name && updates.description === undefined) { throw new Error('Must provide at least one field to update'); } const apiKey = process.env.MARKDOWN_API_KEY; try { const response = await fetch( `https://markdownapi.io/api/projects/${projectId}`, { method: 'PUT', headers: { 'Authorization': `Bearer ${apiKey!}`, 'Content-Type': 'application/json', }, body: JSON.stringify(updates), } ); if (!response.ok) { if (response.status === 409) { throw new Error('Name already exists'); } else if (response.status === 404) { throw new Error('Project not found'); } throw new Error(`HTTP ${response.status}: ${response.statusText}`); } const project: ProjectResponse = await response.json(); console.log(`✓ Project updated: ${project.name}`); console.log(` Updated: ${project.updated_date}`); return project; } catch (error) { console.error('✗ Failed to update project:', error); throw error; } } // Usage // await updateProject('a1b2c3d4-e5f6-7890-abcd-ef1234567890', { // name: 'New Name', // description: 'New description' // });

Common Use Cases

1. Rename Project

async def rename_project(project_id: UUID, new_name: str): """Rename project without changing description.""" return await update_project(project_id, name=new_name)

2. Update Description Only

async def update_project_description(project_id: UUID, description: str): """Update description without changing name.""" return await update_project(project_id, description=description)

3. Clear Description

async def clear_project_description(project_id: UUID): """Remove project description.""" return await update_project(project_id, description=None)

4. Add Timestamp to Name

from datetime import datetime async def archive_project(project_id: UUID): """Add archive timestamp to project name.""" project = await get_project(project_id) timestamp = datetime.utcnow().strftime("%Y-%m-%d") new_name = f"[ARCHIVED {timestamp}] {project['name']}" return await update_project(project_id, name=new_name)

Best Practices

  1. Partial updates - Only send fields you want to change
  2. Verify uniqueness - Check name doesn’t exist before updating
  3. Handle conflicts - Gracefully handle 409 errors for duplicate names
  4. Preserve data - Use null explicitly to clear description, not to preserve it

See Also

Last updated on