{"openapi":"3.1.0","info":{"title":"Tiny CV Developer API","version":"1.0.0","description":"Create, validate, publish, and export Tiny CV resumes for users and agents."},"servers":[{"url":"https://tinycv.app"},{"url":"http://localhost:3000"}],"components":{"securitySchemes":{"bearerAuth":{"scheme":"bearer","type":"http"},"bootstrapSecret":{"in":"header","name":"x-tinycv-bootstrap-secret","type":"apiKey"},"workerSecret":{"in":"header","name":"x-tinycv-worker-secret","type":"apiKey"}},"schemas":{"ApiError":{"properties":{"error":{"properties":{"code":{"type":"string"},"details":{"type":"object"},"message":{"type":"string"},"request_id":{"type":"string"}},"required":["code","message","request_id"],"type":"object"}},"required":["error"],"type":"object"},"ResumeJsonInput":{"$schema":"https://json-schema.org/draft/2020-12/schema","additionalProperties":false,"properties":{"contact":{"items":{"additionalProperties":false,"properties":{"href":{"type":"string"},"kind":{"enum":["email","phone","location","url","linkedin","github","x","text"],"type":"string"},"label":{"type":"string"},"value":{"type":"string"}},"required":["kind","value"],"type":"object"},"type":"array"},"headline":{"type":"string"},"name":{"type":"string"},"sections":{"items":{"oneOf":[{"additionalProperties":false,"properties":{"paragraphs":{"items":{"type":"string"},"minItems":1,"type":"array"},"title":{"type":"string"},"type":{"const":"summary","type":"string"}},"required":["type","paragraphs"],"type":"object"},{"additionalProperties":false,"properties":{"entries":{"items":{"additionalProperties":false,"properties":{"bullets":{"items":{"type":"string"},"type":"array"},"meta_left":{"type":"string"},"meta_right":{"type":"string"},"paragraphs":{"items":{"type":"string"},"type":"array"},"title":{"type":"string"},"title_extras":{"items":{"type":"string"},"type":"array"}},"required":["title"],"type":"object"},"minItems":1,"type":"array"},"title":{"type":"string"},"type":{"const":"entries","type":"string"}},"required":["type","title","entries"],"type":"object"},{"additionalProperties":false,"properties":{"bullets":{"items":{"type":"string"},"minItems":1,"type":"array"},"title":{"type":"string"},"type":{"const":"bullets","type":"string"}},"required":["type","title","bullets"],"type":"object"},{"additionalProperties":false,"properties":{"groups":{"items":{"additionalProperties":false,"properties":{"label":{"type":"string"},"value":{"type":"string"}},"required":["label","value"],"type":"object"},"minItems":1,"type":"array"},"title":{"type":"string"},"type":{"const":"skills","type":"string"}},"required":["type","groups"],"type":"object"}]},"minItems":1,"type":"array"}},"required":["name","sections"],"type":"object"}}},"paths":{"/api/v1/projects/bootstrap":{"post":{"description":"Create a project and its first API key. Protected by the platform bootstrap secret.","responses":{"201":{"description":"Project created"},"401":{"description":"Invalid bootstrap secret"},"429":{"description":"Rate limited. Retry after the seconds in the Retry-After header.","headers":{"Retry-After":{"schema":{"type":"integer"}}}}},"security":[{"bootstrapSecret":[]}]}},"/api/v1/templates":{"get":{"description":"List Tiny CV templates.","responses":{"200":{"description":"Template list"}}}},"/api/v1/templates/{key}":{"get":{"description":"Fetch one Tiny CV template.","parameters":[{"in":"path","name":"key","required":true,"schema":{"type":"string"}}],"responses":{"200":{"description":"Template detail"},"404":{"description":"Template not found"}}}},"/api/v1/spec/markdown":{"get":{"description":"Fetch the Tiny CV markdown guide.","responses":{"200":{"description":"Markdown guide"}}}},"/api/v1/spec/json-schema":{"get":{"description":"Fetch JSON schema for structured resume input.","responses":{"200":{"description":"JSON schema"}}}},"/api/v1/resumes/validate":{"post":{"description":"Validate markdown or JSON resume input without persisting it.","responses":{"200":{"description":"Validation result"},"401":{"description":"Unauthorized"},"404":{"description":"Not found"},"429":{"description":"Rate limited. Retry after the seconds in the Retry-After header.","headers":{"Retry-After":{"schema":{"type":"integer"}}}}},"security":[{"bearerAuth":[]}]}},"/api/v1/resumes":{"post":{"description":"Create a Tiny CV draft from markdown or JSON. Requires Idempotency-Key for safe retries.","parameters":[{"in":"header","name":"Idempotency-Key","required":true,"schema":{"type":"string"}}],"responses":{"201":{"description":"Draft created"},"400":{"description":"Invalid input or missing idempotency key"},"401":{"description":"Unauthorized"},"404":{"description":"Not found"},"429":{"description":"Rate limited. Retry after the seconds in the Retry-After header.","headers":{"Retry-After":{"schema":{"type":"integer"}}}}},"security":[{"bearerAuth":[]}]}},"/api/v1/resumes/{resume_id}":{"get":{"description":"Read a draft or published resume.","parameters":[{"in":"path","name":"resume_id","required":true,"schema":{"type":"string"}}],"responses":{"200":{"description":"Resume detail"},"401":{"description":"Unauthorized"},"404":{"description":"Not found"},"429":{"description":"Rate limited. Retry after the seconds in the Retry-After header.","headers":{"Retry-After":{"schema":{"type":"integer"}}}}},"security":[{"bearerAuth":[]}]},"patch":{"description":"Update a draft resume. Requires Idempotency-Key for safe retries.","parameters":[{"in":"path","name":"resume_id","required":true,"schema":{"type":"string"}},{"in":"header","name":"Idempotency-Key","required":true,"schema":{"type":"string"}}],"responses":{"200":{"description":"Resume updated"},"400":{"description":"Invalid input or missing idempotency key"},"401":{"description":"Unauthorized"},"404":{"description":"Not found"},"429":{"description":"Rate limited. Retry after the seconds in the Retry-After header.","headers":{"Retry-After":{"schema":{"type":"integer"}}}}},"security":[{"bearerAuth":[]}]}},"/api/v1/resumes/{resume_id}/publish":{"post":{"description":"Publish the current draft snapshot and return a public URL. Requires Idempotency-Key.","parameters":[{"in":"path","name":"resume_id","required":true,"schema":{"type":"string"}},{"in":"header","name":"Idempotency-Key","required":true,"schema":{"type":"string"}}],"responses":{"200":{"description":"Resume published"},"400":{"description":"Missing idempotency key"},"401":{"description":"Unauthorized"},"404":{"description":"Not found"},"429":{"description":"Rate limited. Retry after the seconds in the Retry-After header.","headers":{"Retry-After":{"schema":{"type":"integer"}}}}},"security":[{"bearerAuth":[]}]}},"/api/v1/resumes/{resume_id}/pdf-jobs":{"post":{"description":"Queue a durable PDF generation job for a published resume. Requires Idempotency-Key.","parameters":[{"in":"path","name":"resume_id","required":true,"schema":{"type":"string"}},{"in":"header","name":"Idempotency-Key","required":true,"schema":{"type":"string"}}],"responses":{"202":{"description":"PDF job queued"},"400":{"description":"Missing idempotency key"},"401":{"description":"Unauthorized"},"404":{"description":"Not found"},"409":{"description":"Resume is not published"},"429":{"description":"Rate limited. Retry after the seconds in the Retry-After header.","headers":{"Retry-After":{"schema":{"type":"integer"}}}}},"security":[{"bearerAuth":[]}]}},"/api/v1/pdf-jobs/{job_id}":{"get":{"description":"Get PDF job status and a signed PDF URL when complete.","parameters":[{"in":"path","name":"job_id","required":true,"schema":{"type":"string"}}],"responses":{"200":{"description":"PDF job detail"},"401":{"description":"Unauthorized"},"404":{"description":"Not found"},"429":{"description":"Rate limited. Retry after the seconds in the Retry-After header.","headers":{"Retry-After":{"schema":{"type":"integer"}}}}},"security":[{"bearerAuth":[]}]}},"/api/v1/edit-claims/{claim_id}/consume":{"post":{"description":"Consume a one-time edit claim and attach the resume to the current browser workspace.","parameters":[{"in":"path","name":"claim_id","required":true,"schema":{"type":"string"}}],"responses":{"200":{"description":"Claim consumed"},"404":{"description":"Claim not found"},"409":{"description":"Claim expired or already consumed"},"429":{"description":"Rate limited. Retry after the seconds in the Retry-After header.","headers":{"Retry-After":{"schema":{"type":"integer"}}}}}}},"/api/v1/mcp":{"get":{"description":"Describe the Tiny CV MCP endpoint.","responses":{"200":{"description":"MCP server metadata"}}},"post":{"description":"Remote MCP endpoint for Tiny CV tools over JSON-RPC.","responses":{"200":{"description":"MCP JSON-RPC response"},"401":{"description":"Unauthorized"},"404":{"description":"Not found"},"429":{"description":"Rate limited. Retry after the seconds in the Retry-After header.","headers":{"Retry-After":{"schema":{"type":"integer"}}}}},"security":[{"bearerAuth":[]}]}},"/api/v1/jobs/process":{"post":{"description":"Internal worker endpoint for durable PDF and webhook processing.","responses":{"200":{"description":"Worker batch processed"},"401":{"description":"Invalid worker secret"},"503":{"description":"Worker not configured"}},"security":[{"workerSecret":[]}]}}}}