{"openapi":"3.0.3","info":{"title":"Elayne API","description":"Document parsing and extraction API for Elayne","version":"0.1.0"},"servers":[{"url":"http://localhost:3000","description":"Local"},{"url":"https://api.elayne.com","description":"Production"}],"components":{"securitySchemes":{"bearerAuth":{"type":"http","scheme":"bearer","description":"API key passed as Bearer token"}},"schemas":{"JobPayload":{"type":"object","required":["s3Key","personId","uploadedByUserId","documentId"],"properties":{"s3Key":{"type":"string","description":"S3 object key for the document","example":"uploads/123/doc.pdf"},"personId":{"type":"integer","description":"Person ID this document belongs to","example":42},"uploadedByUserId":{"type":"integer","description":"User ID who uploaded the document","example":7},"documentId":{"type":"integer","description":"Document record ID in estate_documents","example":101},"documentTypeHint":{"type":"string","description":"Optional hint for document type","example":"will"},"uploaderName":{"type":"string","description":"Name of the uploader for contact matching","example":"Jane Smith"}}},"JobResponse":{"type":"object","properties":{"jobId":{"type":"string","example":"doc-101-1711820400000"},"status":{"type":"string","enum":["queued","processing","completed","failed","partial"]},"progress":{"type":"number","example":50},"result":{"type":"object"},"error":{"type":"string"},"createdAt":{"type":"string","format":"date-time"},"finishedAt":{"type":"string","format":"date-time"}}},"HealthResponse":{"type":"object","properties":{"status":{"type":"string","enum":["healthy","degraded"]},"checks":{"type":"object","properties":{"redis":{"type":"string","enum":["ok","degraded","down"]}}}}},"Error":{"type":"object","properties":{"error":{"type":"string"}}}}},"paths":{"/health":{"get":{"tags":["System"],"summary":"Health check","description":"Returns health status of the API and its dependencies","responses":{"200":{"description":"All systems healthy","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HealthResponse"}}}},"503":{"description":"One or more systems degraded","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HealthResponse"}}}}}}},"/jobs":{"post":{"tags":["Jobs"],"summary":"Create a document parsing job","description":"Enqueues a new document for parsing. The worker will pick it up and process it asynchronously.","security":[{"bearerAuth":[]}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/JobPayload"}}}},"responses":{"201":{"description":"Job enqueued","content":{"application/json":{"schema":{"$ref":"#/components/schemas/JobResponse"}}}},"400":{"description":"Missing required fields","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"401":{"description":"Invalid or missing API key","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}}}},"get":{"tags":["Jobs"],"summary":"List jobs","description":"Returns a list of jobs, optionally filtered by status","security":[{"bearerAuth":[]}],"parameters":[{"name":"status","in":"query","schema":{"type":"string","enum":["queued","processing","completed","failed"]},"description":"Filter by job status"},{"name":"limit","in":"query","schema":{"type":"integer","default":20,"maximum":100},"description":"Max results to return"}],"responses":{"200":{"description":"List of jobs","content":{"application/json":{"schema":{"type":"array","items":{"$ref":"#/components/schemas/JobResponse"}}}}},"401":{"description":"Invalid or missing API key","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}}}}},"/jobs/{jobId}":{"get":{"tags":["Jobs"],"summary":"Get job status","description":"Returns the current status and result of a specific job","security":[{"bearerAuth":[]}],"parameters":[{"name":"jobId","in":"path","required":true,"schema":{"type":"string"},"description":"Job ID returned from POST /jobs"}],"responses":{"200":{"description":"Job details","content":{"application/json":{"schema":{"$ref":"#/components/schemas/JobResponse"}}}},"401":{"description":"Invalid or missing API key","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"404":{"description":"Job not found","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}}}}},"/dev/documents/{documentId}/reset":{"delete":{"tags":["Dev"],"summary":"Reset document extraction (dev only)","description":"Deletes all contacts, estate items, beneficiaries, and provenance rows created by this document's extraction. Resets the document to pending. Blocked in production.","security":[{"bearerAuth":[]}],"parameters":[{"name":"documentId","in":"path","required":true,"schema":{"type":"integer"},"description":"Document ID to reset"}],"responses":{"200":{"description":"Reset complete","content":{"application/json":{"schema":{"type":"object","properties":{"documentId":{"type":"integer"},"deleted":{"type":"object","properties":{"contacts":{"type":"integer"},"estateItems":{"type":"integer"},"beneficiaries":{"type":"integer"},"contactReferences":{"type":"integer"},"itemReferences":{"type":"integer"},"beneficiaryReferences":{"type":"integer"}}}}}}}},"403":{"description":"Blocked in production","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}}}}},"/jobs/quick-role-check":{"post":{"tags":["Jobs"],"summary":"Quick legal role check","description":"Synchronous endpoint for onboarding. Determines if the uploader is named as executor, trustee, or administrator in a will, trust, or court document. Returns in ~10-15 seconds.","security":[{"bearerAuth":[]}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","properties":{"s3Key":{"type":"string","description":"S3 key of the uploaded document"},"uploaderName":{"type":"string","description":"Full name of the person uploading"},"environment":{"type":"string","enum":["dev","prod"],"description":"Optional environment override"}},"required":["s3Key","uploaderName"]}}}},"responses":{"200":{"description":"Role check result","content":{"application/json":{"schema":{"type":"object","properties":{"documentType":{"type":"string"},"legalRole":{"type":"string","enum":["nominated","executor","administrator","trustee"],"nullable":true},"confidence":{"type":"string","enum":["high","medium","low"]},"reasoning":{"type":"string"}}}}}}}}},"/webhooks/reducto":{"post":{"tags":["Webhooks"],"summary":"Reducto Extract webhook","description":"Called by Reducto when an async Extract job completes. Backfills citations and confidence scores on provenance reference rows.","requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","properties":{"job_id":{"type":"string","description":"Reducto job ID","example":"abc123"},"status":{"type":"string","enum":["Completed","Failed"],"description":"Job completion status"},"metadata":{"type":"object","properties":{"documentId":{"type":"integer","description":"Document ID passed during job submission","example":42}}}},"required":["job_id","status"]}}}},"responses":{"200":{"description":"Webhook received","content":{"application/json":{"schema":{"type":"object","properties":{"received":{"type":"boolean"}}}}}}}}}}}