{"openapi":"3.1.0","info":{"title":"iFillPDF API","version":"1.0.0","summary":"Analyze, label, update, and fill PDFs with iFillPDF.","description":"The iFillPDF API lets teams upload PDFs, run AI field detection, persist document values, and generate filled PDFs."},"servers":[{"url":"https://www.ifillpdf.com","description":"Production"}],"tags":[{"name":"Uploads","description":"Temporary PDF upload helpers."},{"name":"Documents","description":"Create, analyze, list, update, and delete documents."},{"name":"Fill","description":"Generate filled PDFs from analyzed documents."},{"name":"Templates","description":"Snapshot documents into reusable templates and instantiate them."},{"name":"Vault","description":"Store personal ID and financial documents for pre-filling."}],"security":[{"bearerAuth":[]}],"paths":{"/api/pending-uploads":{"post":{"tags":["Uploads"],"security":[],"summary":"Create a pending upload","description":"Upload a PDF anonymously with multipart/form-data, or request a signed Supabase upload token with JSON. The returned id can be passed as pending_upload_id to the document endpoints.","requestBody":{"required":true,"content":{"multipart/form-data":{"schema":{"type":"object","required":["pdf"],"properties":{"pdf":{"type":"string","format":"binary"}}}},"application/json":{"schema":{"$ref":"#/components/schemas/PendingUploadRequest"}}}},"responses":{"200":{"description":"Pending upload created.","content":{"application/json":{"schema":{"oneOf":[{"$ref":"#/components/schemas/PendingUpload"},{"$ref":"#/components/schemas/SignedPendingUpload"}]}}}},"400":{"$ref":"#/components/responses/BadRequest"},"413":{"$ref":"#/components/responses/PdfTooLarge"},"429":{"$ref":"#/components/responses/RateLimited"}}}},"/api/v1/documents":{"get":{"tags":["Documents"],"summary":"List documents","description":"Returns documents for the authenticated team, newest first.","parameters":[{"name":"limit","in":"query","schema":{"type":"integer","minimum":1,"maximum":100,"default":20}},{"name":"cursor","in":"query","schema":{"type":"string"},"description":"Cursor returned as next_cursor."},{"name":"q","in":"query","schema":{"type":"string"},"description":"Search by document name."},{"name":"status","in":"query","schema":{"type":"string","enum":["analyzing","completed","failed","draft","filling","no_fields","analysis_failed","sent","declined","expired","voided"]}},{"name":"include_voided","in":"query","schema":{"type":"boolean","default":false}}],"responses":{"200":{"description":"Document page.","content":{"application/json":{"schema":{"type":"object","required":["documents","next_cursor"],"properties":{"documents":{"type":"array","items":{"$ref":"#/components/schemas/DocumentSummary"}},"next_cursor":{"type":["string","null"]}}}}}},"401":{"$ref":"#/components/responses/Unauthenticated"}}},"post":{"tags":["Documents"],"summary":"Create and analyze a document asynchronously","description":"Creates a document, debits quota, renders page images when possible, starts semantic analysis, and returns 202 for polling. Poll GET /api/v1/documents/{id} until status changes.","requestBody":{"required":true,"content":{"multipart/form-data":{"schema":{"$ref":"#/components/schemas/CreateDocumentMultipart"}},"application/json":{"schema":{"$ref":"#/components/schemas/CreateDocumentJson"}}}},"responses":{"202":{"description":"Analysis started.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/DocumentStartResponse"}}}},"400":{"$ref":"#/components/responses/BadRequest"},"401":{"$ref":"#/components/responses/Unauthenticated"},"402":{"$ref":"#/components/responses/PageQuotaExhausted"},"429":{"$ref":"#/components/responses/RateLimited"}}}},"/api/v1/documents/analyze":{"post":{"tags":["Documents"],"summary":"Create and analyze a document synchronously","description":"Runs the full analysis before responding. Best for short documents where the caller can hold a 10-30 second request.","requestBody":{"required":true,"content":{"multipart/form-data":{"schema":{"$ref":"#/components/schemas/CreateDocumentMultipart"}},"application/json":{"schema":{"$ref":"#/components/schemas/CreateDocumentJson"}}}},"responses":{"200":{"description":"Analysis complete.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/AnalyzeResponse"}}}},"401":{"$ref":"#/components/responses/Unauthenticated"},"402":{"$ref":"#/components/responses/PageQuotaExhausted"},"429":{"$ref":"#/components/responses/RateLimited"}}}},"/api/v1/documents/{document_id}":{"get":{"tags":["Documents"],"summary":"Get a document","parameters":[{"$ref":"#/components/parameters/DocumentId"}],"responses":{"200":{"description":"Document state, schema, and values.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Document"}}}},"401":{"$ref":"#/components/responses/Unauthenticated"},"404":{"$ref":"#/components/responses/NotFound"},"410":{"$ref":"#/components/responses/DocumentVoided"}}},"patch":{"tags":["Documents"],"summary":"Update document metadata or values","parameters":[{"$ref":"#/components/parameters/DocumentId"}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/UpdateDocumentRequest"}}}},"responses":{"200":{"description":"Updated document.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Document"}}}},"400":{"$ref":"#/components/responses/BadRequest"},"404":{"$ref":"#/components/responses/NotFound"},"410":{"$ref":"#/components/responses/DocumentVoided"}}},"delete":{"tags":["Documents"],"summary":"Delete a document","description":"Soft deletes the document by moving it to state voided.","parameters":[{"$ref":"#/components/parameters/DocumentId"}],"responses":{"200":{"description":"Document voided.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/DeleteDocumentResponse"}}}},"404":{"$ref":"#/components/responses/NotFound"}}}},"/api/v1/documents/{document_id}/reanalyze":{"post":{"tags":["Documents"],"summary":"Re-run analysis","parameters":[{"$ref":"#/components/parameters/DocumentId"}],"responses":{"200":{"description":"Analysis was already running.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ReanalyzeResponse"}}}},"202":{"description":"Re-analysis started.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ReanalyzeResponse"}}}},"402":{"$ref":"#/components/responses/PageQuotaExhausted"},"410":{"$ref":"#/components/responses/DocumentVoided"}}}},"/api/v1/documents/{document_id}/fill":{"post":{"tags":["Fill"],"summary":"Fill a document","description":"Applies values to the analyzed schema and returns the filled PDF, or a signed URL when format=url is requested or the PDF is too large for a direct response.","parameters":[{"$ref":"#/components/parameters/DocumentId"},{"name":"format","in":"query","schema":{"type":"string","enum":["pdf","url"],"default":"pdf"}}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/FillRequest"}}}},"responses":{"200":{"description":"Filled PDF binary, or a signed URL response.","content":{"application/pdf":{"schema":{"type":"string","format":"binary"}},"application/json":{"schema":{"$ref":"#/components/schemas/FillUrlResponse"}}}},"409":{"$ref":"#/components/responses/SchemaNotReady"}}}},"/api/v1/uploads":{"post":{"tags":["Uploads"],"summary":"Request a signed upload URL","description":"Returns a one-time Supabase Storage signed PUT URL so the caller can upload a PDF (up to the returned max_bytes) directly, bypassing the function body limit. PUT the bytes, then call POST /api/v1/documents with pending_upload_id set to the returned id.","requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/RequestUploadRequest"}}}},"responses":{"200":{"description":"Signed upload created.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/SignedUpload"}}}},"400":{"$ref":"#/components/responses/BadRequest"},"401":{"$ref":"#/components/responses/Unauthenticated"},"413":{"$ref":"#/components/responses/PdfTooLarge"},"415":{"$ref":"#/components/responses/UnsupportedUpload"},"429":{"$ref":"#/components/responses/RateLimited"}}}},"/api/v1/templates":{"get":{"tags":["Templates"],"summary":"List templates","description":"Lists public-library templates (scope=public) or your own team/private templates (scope=mine). Cursor-paginated, newest first.","parameters":[{"name":"scope","in":"query","schema":{"type":"string","enum":["public","mine"],"default":"public"}},{"name":"category","in":"query","schema":{"type":"string"}},{"name":"language","in":"query","schema":{"type":"string"},"description":"Language code, e.g. fr."},{"name":"q","in":"query","schema":{"type":"string"},"description":"Search by template name."},{"name":"limit","in":"query","schema":{"type":"integer","minimum":1,"maximum":100,"default":24}},{"name":"cursor","in":"query","schema":{"type":"string"},"description":"Cursor returned as next_cursor."}],"responses":{"200":{"description":"Template page.","content":{"application/json":{"schema":{"type":"object","required":["templates","next_cursor"],"properties":{"templates":{"type":"array","items":{"$ref":"#/components/schemas/Template"}},"next_cursor":{"type":["string","null"]}}}}}},"401":{"$ref":"#/components/responses/Unauthenticated"}}},"post":{"tags":["Templates"],"summary":"Create a template from a document","description":"Snapshots an analyzed document into a reusable template. Regular keys can create private or team templates only — public publishing is admin-only.","requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/CreateTemplateRequest"}}}},"responses":{"201":{"description":"Template created.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/TemplateEnvelope"}}}},"400":{"$ref":"#/components/responses/BadRequest"},"401":{"$ref":"#/components/responses/Unauthenticated"},"429":{"$ref":"#/components/responses/RateLimited"}}}},"/api/v1/templates/{template_id}":{"get":{"tags":["Templates"],"summary":"Get a template","description":"Returns a single template with its field and party structure. Visibility-gated; never returns stored default values.","parameters":[{"$ref":"#/components/parameters/TemplateId"}],"responses":{"200":{"description":"Template detail.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/TemplateDetailEnvelope"}}}},"401":{"$ref":"#/components/responses/Unauthenticated"},"404":{"$ref":"#/components/responses/NotFound"}}},"patch":{"tags":["Templates"],"summary":"Update a template","description":"Updates your own template metadata and visibility. Only the creator can edit. Public publishing stays admin-only.","parameters":[{"$ref":"#/components/parameters/TemplateId"}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/UpdateTemplateRequest"}}}},"responses":{"200":{"description":"Updated template.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/TemplateEnvelope"}}}},"400":{"$ref":"#/components/responses/BadRequest"},"403":{"$ref":"#/components/responses/Forbidden"},"404":{"$ref":"#/components/responses/NotFound"},"409":{"$ref":"#/components/responses/BadRequest"}}},"delete":{"tags":["Templates"],"summary":"Delete a template","description":"Permanently deletes your own template and its stored assets. Documents already created from it are unaffected. Only the creator can delete.","parameters":[{"$ref":"#/components/parameters/TemplateId"}],"responses":{"200":{"description":"Template deleted.","content":{"application/json":{"schema":{"type":"object","required":["deleted","id"],"properties":{"deleted":{"type":"boolean"},"id":{"type":"string"}}}}}},"403":{"$ref":"#/components/responses/Forbidden"},"404":{"$ref":"#/components/responses/NotFound"}}}},"/api/v1/templates/{template_id}/use":{"post":{"tags":["Templates"],"summary":"Instantiate a template","description":"Clones a template into a new working document pre-filled with its frozen defaults. Free — duplication never re-runs analysis, so it does not debit the page quota. The new document starts in state filling.","parameters":[{"$ref":"#/components/parameters/TemplateId"}],"responses":{"201":{"description":"Document created from template.","content":{"application/json":{"schema":{"type":"object","required":["document_id","status"],"properties":{"document_id":{"type":"string","format":"uuid"},"status":{"type":"string","enum":["filling"]}}}}}},"401":{"$ref":"#/components/responses/Unauthenticated"},"404":{"$ref":"#/components/responses/NotFound"},"429":{"$ref":"#/components/responses/RateLimited"}}}},"/api/v1/templates/by-slug/{slug}":{"get":{"tags":["Templates"],"security":[],"summary":"Resolve a public template by marketplace slug","description":"Public, no auth. Resolves a marketplace slug to the published public template that backs it, when a real fillable PDF exists. Used by the SEO model pages.","parameters":[{"name":"slug","in":"path","required":true,"schema":{"type":"string"}}],"responses":{"200":{"description":"Template found.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/TemplateEnvelope"}}}},"404":{"$ref":"#/components/responses/NotFound"}}}},"/api/v1/vault/documents":{"post":{"tags":["Vault"],"summary":"Add a document to the vault","description":"Uploads a personal ID or financial document (payslip, RIB, KBIS, passport) to the per-user vault. The declared mime_type is re-checked against the file magic bytes. iFillPDF can later reuse it to pre-fill forms.","requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/VaultUploadRequest"}}}},"responses":{"200":{"description":"Vault document stored.","content":{"application/json":{"schema":{"type":"object","required":["document"],"properties":{"document":{"$ref":"#/components/schemas/VaultDocument"}}}}}},"400":{"$ref":"#/components/responses/BadRequest"},"401":{"$ref":"#/components/responses/Unauthenticated"},"413":{"$ref":"#/components/responses/PdfTooLarge"},"429":{"$ref":"#/components/responses/RateLimited"}}}}},"components":{"securitySchemes":{"bearerAuth":{"type":"http","scheme":"bearer","bearerFormat":"API key"}},"parameters":{"DocumentId":{"name":"document_id","in":"path","required":true,"schema":{"type":"string","format":"uuid"}},"TemplateId":{"name":"template_id","in":"path","required":true,"schema":{"type":"string","format":"uuid"}}},"responses":{"BadRequest":{"description":"Invalid request.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"Unauthenticated":{"description":"Missing or invalid API key.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"Forbidden":{"description":"Authenticated but not allowed (not the creator, or public publishing).","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"NotFound":{"description":"Resource not found.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"UnsupportedUpload":{"description":"fileName is not a .pdf, or contentType is not application/pdf.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"RateLimited":{"description":"Rate limit exceeded.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"PdfTooLarge":{"description":"PDF exceeds the accepted size.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"PageQuotaExhausted":{"description":"Team page quota is exhausted.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"DocumentVoided":{"description":"Document was deleted.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"SchemaNotReady":{"description":"Document analysis has not produced a schema yet.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}}},"schemas":{"Error":{"type":"object","required":["error"],"properties":{"error":{"type":"string","examples":["invalid_json","rate_limited","schema_not_ready"]},"detail":{},"message":{"type":"string"}}},"PendingUploadRequest":{"type":"object","required":["fileName","sizeBytes"],"properties":{"fileName":{"type":"string","examples":["cerfa-13750.pdf"]},"sizeBytes":{"type":"integer","minimum":1},"contentType":{"type":"string","default":"application/pdf"}}},"PendingUpload":{"type":"object","required":["id","expires_at"],"properties":{"id":{"type":"string"},"expires_at":{"type":"string","format":"date-time"}}},"SignedPendingUpload":{"allOf":[{"$ref":"#/components/schemas/PendingUpload"},{"type":"object","required":["path","token"],"properties":{"path":{"type":"string"},"token":{"type":"string"}}}]},"SuggestedEntity":{"type":"object","required":["id","label"],"properties":{"id":{"type":"string","examples":["declarant"]},"label":{"type":"string","maxLength":120,"examples":["Declarant"]},"color":{"type":"string","pattern":"^#[0-9a-fA-F]{3,8}$","examples":["#6D7BFF"]},"source":{"type":"string","enum":["user","history"]}}},"CreateDocumentMultipart":{"type":"object","required":["pdf"],"properties":{"pdf":{"type":"string","format":"binary"},"name":{"type":"string"},"description":{"type":"string","maxLength":2000},"suggested_entities":{"type":"string","description":"JSON encoded array of SuggestedEntity objects."}}},"CreateDocumentJson":{"type":"object","properties":{"pending_upload_id":{"type":"string"},"pdf_url":{"type":"string","format":"uri"},"name":{"type":"string"},"description":{"type":"string","maxLength":2000},"suggested_entities":{"type":"array","maxItems":20,"items":{"$ref":"#/components/schemas/SuggestedEntity"}}},"anyOf":[{"required":["pending_upload_id"]},{"required":["pdf_url"]}]},"DocumentStartResponse":{"type":"object","required":["document_id","status","page_count","quota"],"properties":{"document_id":{"type":"string","format":"uuid"},"status":{"type":"string","enum":["analyzing"]},"page_count":{"type":"integer"},"page_images_ready":{"type":"boolean"},"page_images_count":{"type":"integer"},"preview_image_url":{"type":["string","null"]},"quota":{"$ref":"#/components/schemas/Quota"}}},"AnalyzeResponse":{"type":"object","required":["document_id","page_count","schema","quota"],"properties":{"document_id":{"type":"string","format":"uuid"},"page_count":{"type":"integer"},"schema":{"$ref":"#/components/schemas/DocumentSchema"},"page_dimensions":{"type":"array","items":{"type":"object"}},"page_images_count":{"type":"integer"},"preview_image_url":{"type":["string","null"]},"quota":{"$ref":"#/components/schemas/Quota"}}},"DocumentSummary":{"type":"object","required":["document_id","name","status","state","page_count"],"properties":{"document_id":{"type":"string","format":"uuid"},"name":{"type":"string"},"status":{"type":"string","enum":["analyzing","completed","failed"]},"state":{"type":"string"},"error":{"type":["string","null"]},"page_count":{"type":"integer"},"page_images_count":{"type":"integer"},"preview_image_url":{"type":["string","null"]},"document_type":{"type":["string","null"]},"entities":{"type":"array","items":{"$ref":"#/components/schemas/DocumentEntity"}},"analysis_started_at":{"type":["string","null"],"format":"date-time"},"analysis_completed_at":{"type":["string","null"],"format":"date-time"},"created_at":{"type":"string","format":"date-time"},"updated_at":{"type":"string","format":"date-time"}}},"Document":{"allOf":[{"$ref":"#/components/schemas/DocumentSummary"},{"type":"object","properties":{"schema":{"oneOf":[{"$ref":"#/components/schemas/DocumentSchema"},{"type":"null"}]},"values":{"$ref":"#/components/schemas/DocumentValues"}}}]},"DocumentSchema":{"type":"object","properties":{"version":{"type":"integer"},"documentType":{"type":"string"},"pages":{"type":"array","items":{"type":"object"}},"parties":{"type":"array","items":{"$ref":"#/components/schemas/DocumentEntity"}},"fields":{"type":"array","items":{"$ref":"#/components/schemas/DocumentField"}}}},"DocumentEntity":{"type":"object","properties":{"id":{"type":"string"},"label":{"type":"string"},"description":{"type":"string"},"color":{"type":"string"}}},"DocumentField":{"type":"object","properties":{"id":{"type":"string"},"name":{"type":"string"},"label":{"type":"string"},"type":{"type":"string","enum":["text","checkbox","signature","date","number"]},"page":{"type":"integer"},"partyId":{"type":"string"},"rect":{"type":"object"}}},"DocumentValues":{"type":"object","additionalProperties":{"oneOf":[{"type":"string"},{"type":"boolean"},{"type":"number"},{"type":"object","required":["dataUrl"],"properties":{"dataUrl":{"type":"string"}}}]}},"UpdateDocumentRequest":{"type":"object","properties":{"name":{"type":"string","maxLength":120},"description":{"type":["string","null"],"maxLength":2000},"user_context":{"type":["object","null"],"properties":{"description":{"type":"string","maxLength":2000}}},"suggested_entities":{"type":["array","null"],"maxItems":20,"items":{"$ref":"#/components/schemas/SuggestedEntity"}},"values":{"$ref":"#/components/schemas/DocumentValues"}}},"DeleteDocumentResponse":{"type":"object","required":["ok","document_id","state"],"properties":{"ok":{"type":"boolean"},"document_id":{"type":"string","format":"uuid"},"state":{"type":"string","enum":["voided"]}}},"ReanalyzeResponse":{"type":"object","required":["ok","status","document_id","already_started","quota"],"properties":{"ok":{"type":"boolean"},"status":{"type":"string","enum":["analyzing"]},"document_id":{"type":"string","format":"uuid"},"page_count":{"type":"integer"},"pages_consumed":{"type":"integer"},"already_started":{"type":"boolean"},"page_images":{"type":"object"},"quota":{"$ref":"#/components/schemas/Quota"}}},"FillRequest":{"type":"object","required":["values"],"properties":{"values":{"$ref":"#/components/schemas/DocumentValues"},"watermark":{"type":"boolean"}}},"FillUrlResponse":{"type":"object","required":["url","expires_in","filled","failed"],"properties":{"url":{"type":"string","format":"uri"},"expires_in":{"type":"integer"},"filled":{"type":"integer"},"failed":{"type":"array","items":{"type":"string"}}}},"Quota":{"type":"object","properties":{"remaining":{"type":"integer"},"plan":{"type":"string"}}},"RequestUploadRequest":{"type":"object","required":["fileName","sizeBytes"],"properties":{"fileName":{"type":"string","description":"Must end with .pdf.","examples":["contrat.pdf"]},"sizeBytes":{"type":"integer","minimum":1,"description":"Up to the returned max_bytes."},"contentType":{"type":"string","default":"application/pdf","enum":["application/pdf"]}}},"SignedUpload":{"type":"object","required":["id","upload_url","token","storage_path","expires_at","max_bytes"],"properties":{"id":{"type":"string","description":"Pass as pending_upload_id to POST /api/v1/documents."},"upload_url":{"type":"string","format":"uri","description":"PUT the PDF bytes here."},"token":{"type":"string","description":"Send as Authorization: Bearer <token> on the PUT."},"storage_path":{"type":"string"},"expires_at":{"type":"string","format":"date-time"},"max_bytes":{"type":"integer"}}},"Template":{"type":"object","required":["id","name","visibility"],"properties":{"id":{"type":"string","format":"uuid"},"name":{"type":"string"},"description":{"type":["string","null"]},"category":{"type":["string","null"]},"language":{"type":["string","null"]},"tags":{"type":"array","items":{"type":"string"}},"visibility":{"type":"string","enum":["public","team","private"]},"is_published":{"type":"boolean"},"page_count":{"type":"integer"},"preview_image_url":{"type":["string","null"]},"created_at":{"type":"string","format":"date-time"}}},"TemplateDetail":{"allOf":[{"$ref":"#/components/schemas/Template"},{"type":"object","properties":{"parties":{"type":"array","items":{"$ref":"#/components/schemas/DocumentEntity"}},"fields":{"type":"array","items":{"$ref":"#/components/schemas/DocumentField"}}}}]},"TemplateEnvelope":{"type":"object","required":["template"],"properties":{"template":{"$ref":"#/components/schemas/Template"}}},"TemplateDetailEnvelope":{"type":"object","required":["template"],"properties":{"template":{"$ref":"#/components/schemas/TemplateDetail"}}},"CreateTemplateRequest":{"type":"object","required":["source_document_id"],"properties":{"source_document_id":{"type":"string","format":"uuid"},"name":{"type":"string"},"description":{"type":["string","null"],"maxLength":2000},"category":{"type":["string","null"]},"tags":{"type":"array","maxItems":20,"items":{"type":"string","maxLength":40}},"language":{"type":"string","default":"fr"},"visibility":{"type":"string","enum":["private","team"],"default":"private","description":"Public publishing is admin-only."}}},"UpdateTemplateRequest":{"type":"object","properties":{"name":{"type":"string","maxLength":200},"description":{"type":"string","maxLength":2000},"category":{"type":"string","maxLength":80},"tags":{"type":"array","maxItems":20,"items":{"type":"string","maxLength":40}},"language":{"type":"string","maxLength":8},"visibility":{"type":"string","enum":["private","team"],"description":"public is rejected (admin-only)."}}},"VaultUploadRequest":{"type":"object","required":["file_base64","file_name","mime_type"],"properties":{"file_base64":{"type":"string","description":"Base64-encoded file bytes."},"file_name":{"type":"string"},"mime_type":{"type":"string","enum":["application/pdf","image/jpeg","image/png","image/webp","image/heic"],"description":"Re-checked against the file magic bytes."},"label":{"type":"string","maxLength":120}}},"VaultDocument":{"type":"object","properties":{"id":{"type":"string","format":"uuid"},"file_name":{"type":"string"},"mime_type":{"type":"string"},"label":{"type":["string","null"]},"url":{"type":["string","null"],"format":"uri","description":"Signed, time-limited URL."},"created_at":{"type":"string","format":"date-time"}}}}}}