{"components":{"responses":{"NotFound":{"content":{"application/json":{"example":{"code":"NOT_FOUND","error":"Job not found","status":404},"schema":{"$ref":"#/components/schemas/ErrorResponse"}}},"description":"Requested resource was not found"},"ProcessingError":{"content":{"application/json":{"example":{"code":"PROCESSING_ERROR","error":"Unable to process request","status":500},"schema":{"$ref":"#/components/schemas/ErrorResponse"}}},"description":"Processing failed or an internal error occurred"},"RateLimited":{"content":{"application/json":{"example":{"code":"RATE_LIMIT_EXCEEDED","error":"Rate limit exceeded","status":429},"schema":{"$ref":"#/components/schemas/ErrorResponse"}}},"description":"The API key exceeded its configured request rate"},"Unauthorized":{"content":{"application/json":{"example":{"code":"VALIDATION_ERROR","error":"Unauthorized - Missing or invalid API key","status":401},"schema":{"$ref":"#/components/schemas/ErrorResponse"}}},"description":"Missing or invalid API key"},"ValidationError":{"content":{"application/json":{"example":{"code":"VALIDATION_ERROR","error":"image_base64 is required","status":400},"schema":{"$ref":"#/components/schemas/ErrorResponse"}}},"description":"Request validation failed"},"WorkspaceMismatch":{"content":{"application/json":{"example":{"error":"client_id must match the workspace bound to the calling API key","workspace_id":"8a1b7bb0-3538-4d8f-a86d-1cc4b40a764f"},"schema":{"$ref":"#/components/schemas/WorkspaceBindingError"}}},"description":"The supplied client_id does not match the workspace bound to the calling API key"}},"schemas":{"ApproveJobRequest":{"properties":{"notes":{"description":"Free-form approval notes","type":"string"},"statement_accepted":{"description":"Whether the validator statement was accepted","type":"boolean"},"validator_name":{"description":"Reviewer / validator identity","type":"string"}},"type":"object"},"ApproveJobResponse":{"properties":{"approval_status":{"enum":["approved"],"type":"string"},"approved_at":{"format":"date-time","type":"string"},"approved_by":{"type":"string"},"job_id":{"format":"uuid","type":"string"},"notes":{"nullable":true,"type":"string"},"statement_accepted":{"nullable":true,"type":"boolean"},"success":{"type":"boolean"},"validator_name":{"nullable":true,"type":"string"}},"type":"object"},"AutofillField":{"properties":{"confidence":{"example":0.97,"maximum":1,"minimum":0,"type":"number"},"field_name":{"example":"invoice_number","type":"string"},"required":{"example":true,"type":"boolean"},"source_page":{"example":1,"nullable":true,"type":"integer"},"source_snippet":{"example":"Invoice Number INV-2026-00124","nullable":true,"type":"string"},"transform":{"example":"trim","nullable":true,"type":"string"},"value":{"example":"INV-2026-00124","nullable":true,"type":"string"}},"required":["field_name","confidence"],"type":"object"},"AutofillRequest":{"properties":{"client_id":{"description":"Workspace identifier bound to the calling API key and provisioned with the integration. This is not a free-form ERP field identifier and is not derived from upload responses.","example":"8a1b7bb0-3538-4d8f-a86d-1cc4b40a764f","type":"string"},"document_id":{"example":"doc-2026-00124","type":"string"},"fields":{"items":{"$ref":"#/components/schemas/AutofillField"},"minItems":1,"type":"array"},"generated_at":{"format":"date-time","nullable":true,"type":"string"},"job_id":{"description":"Approved completed processing job owned by the calling API key.","example":"12345678-90ab-cdef-1234-567890abcdef","format":"uuid","type":"string"},"profile_id":{"example":"invoice-ap-sync","nullable":true,"type":"string"},"source":{"enum":["validation","reprocess"],"example":"validation","type":"string"}},"required":["job_id","document_id","client_id","source","fields"],"type":"object"},"AutofillResponse":{"properties":{"confidence_avg":{"example":0.954,"type":"number"},"fields_flagged":{"example":0,"type":"integer"},"fields_written":{"example":6,"type":"integer"},"flagged":{"items":{"properties":{"confidence":{"type":"number"},"field_name":{"type":"string"},"reason":{"type":"string"},"value":{"nullable":true,"type":"string"}},"type":"object"},"nullable":true,"type":"array"},"job_id":{"format":"uuid","type":"string"},"review_job_id":{"format":"uuid","type":"string"},"status":{"enum":["accepted","needs_review"],"example":"accepted","type":"string"},"workspace_id":{"nullable":true,"type":"string"}},"type":"object"},"BatchAcceptedResponse":{"properties":{"batch_id":{"description":"Informational batch token returned for logging only. Poll and review individual job IDs instead of using batch_id as a lookup handle.","example":"batch_1714789200.123","type":"string"},"job_count":{"description":"Number of document jobs accepted in this request.","example":2,"type":"integer"},"jobs":{"description":"Individual job IDs to poll through GET /api/v1/status/{job_id}. Each completed job enters pending_review before autofill intake.","items":{"format":"uuid","type":"string"},"type":"array"},"message":{"example":"Batch submitted for processing","type":"string"}},"type":"object"},"BatchDocument":{"properties":{"doc_type":{"description":"Optional document category trigger. Use a known label like invoice or receipt, or send your own label such as delivery_note or service_report; the backend will use it to choose or infer the extraction schema. Maximum 50 characters.","type":"string"},"image_base64":{"description":"Base64-encoded image. Supported formats: jpeg, png, gif, tiff. Maximum size 10MB.","type":"string"},"output_format":{"description":"Optional response-shaping hint recorded with the batch item, such as json, markdown, structured_profile, csv, xml, fhir, or fhir_observation.","type":"string"}},"required":["image_base64"],"type":"object"},"BatchRequest":{"properties":{"documents":{"items":{"$ref":"#/components/schemas/BatchDocument"},"maxItems":100,"minItems":1,"type":"array"}},"required":["documents"],"type":"object"},"ErrorResponse":{"properties":{"code":{"example":"VALIDATION_ERROR","type":"string"},"error":{"example":"image_base64 is required","type":"string"},"status":{"example":400,"type":"integer"}},"type":"object"},"HealthStatus":{"properties":{"service":{"example":"immenzo-api","type":"string"},"status":{"example":"healthy","type":"string"},"timestamp":{"format":"date-time","type":"string"},"version":{"example":"1.0.0","type":"string"}},"type":"object"},"JobAcceptedResponse":{"properties":{"estimated_completion":{"example":"5-10 seconds","type":"string"},"job_id":{"description":"Poll this job_id with GET /api/v1/status/{job_id}. Completed jobs then move into pending_review until approved or rejected.","example":"12345678-90ab-cdef-1234-567890abcdef","format":"uuid","type":"string"},"message":{"example":"Document submitted for processing","type":"string"},"status":{"enum":["pending"],"example":"pending","type":"string"}},"type":"object"},"JobStatusResponse":{"properties":{"approval_status":{"description":"Workflow review state. Defaults to pending_review when the job completes.","enum":["pending_review","approved","rejected"],"type":"string"},"approved_at":{"format":"date-time","nullable":true,"type":"string"},"attempts":{"description":"Number of worker attempts so far. Capped by WORKER_MAX_ATTEMPTS server-side.","example":1,"minimum":0,"type":"integer"},"completed_at":{"format":"date-time","nullable":true,"type":"string"},"created_at":{"format":"date-time","nullable":true,"type":"string"},"error":{"description":"Populated for failed jobs. Common values include OCR engine and processing availability errors.","nullable":true,"type":"string"},"extracted_data":{"nullable":true,"type":"object"},"job_id":{"example":"12345678-90ab-cdef-1234-567890abcdef","format":"uuid","type":"string"},"processing_time_ms":{"description":"Wall-clock duration from started_at to completed_at, in milliseconds. Null until completion.","example":7320,"nullable":true,"type":"integer"},"progress":{"example":100,"maximum":100,"minimum":0,"type":"integer"},"started_at":{"description":"Set when the worker first claims the job.","format":"date-time","nullable":true,"type":"string"},"status":{"enum":["pending","processing","completed","failed"],"type":"string"},"validator_name":{"nullable":true,"type":"string"}},"type":"object"},"LivenessStatus":{"properties":{"alive":{"example":true,"type":"boolean"}},"type":"object"},"ReadinessStatus":{"properties":{"ready":{"example":true,"type":"boolean"}},"type":"object"},"RejectJobRequest":{"properties":{"reason":{"description":"Reason for rejection","type":"string"},"validator_name":{"type":"string"}},"type":"object"},"RejectJobResponse":{"properties":{"approval_status":{"enum":["rejected"],"type":"string"},"approved_at":{"format":"date-time","type":"string"},"approved_by":{"type":"string"},"job_id":{"format":"uuid","type":"string"},"rejection_reason":{"nullable":true,"type":"string"},"success":{"type":"boolean"},"validator_name":{"nullable":true,"type":"string"}},"type":"object"},"ReviewQueueItem":{"properties":{"approval_status":{"enum":["pending_review","approved","rejected"],"type":"string"},"approved_at":{"format":"date-time","nullable":true,"type":"string"},"completed_at":{"format":"date-time","nullable":true,"type":"string"},"doc_type":{"nullable":true,"type":"string"},"document_type":{"type":"string"},"job_id":{"format":"uuid","type":"string"},"output_format":{"type":"string"},"validator_name":{"nullable":true,"type":"string"}},"type":"object"},"ReviewQueueResponse":{"properties":{"approval_status":{"type":"string"},"count":{"type":"integer"},"items":{"items":{"$ref":"#/components/schemas/ReviewQueueItem"},"type":"array"}},"type":"object"},"WorkspaceBindingError":{"properties":{"error":{"example":"client_id must match the workspace bound to the calling API key","type":"string"},"workspace_id":{"example":"8a1b7bb0-3538-4d8f-a86d-1cc4b40a764f","type":"string"}},"type":"object"}},"securitySchemes":{"bearerAuth":{"bearerFormat":"API Key","description":"IngestX by Immenzo API key sent in the Authorization header","scheme":"bearer","type":"http"}}},"info":{"description":"Authenticated API for asynchronous OCR processing, review, and handoff to downstream systems.\n\nIngestX by Immenzo is commonly integrated as a licensed OCR component within ERP systems and other business applications. Its public processing endpoints accept JSON request bodies containing base64-encoded images and return a job ID that clients use to poll for status. Once processing completes, the reviewed output can be approved, rejected, or forwarded to downstream connector workflows.\n\nJob status progresses from pending to processing and then to either completed or failed. Status responses include the fields started_at, attempts, and processing_time_ms. When the OCR backend is reachable, typical end-to-end latency for a single image is 5\u201315 seconds.","license":{"name":"Proprietary","url":"https://www.immenzo.com/terms"},"title":"IngestX by Immenzo OCR Integration API","version":"1.0.0"},"openapi":"3.0.3","paths":{"/api/v1/autofill/receive":{"post":{"description":"Submit normalized extracted fields from review or reprocess flows into IngestX by Immenzo downstream intake. This endpoint records the reviewed payload for connector pickup, managed handoff, or audit history; the referenced job_id must already be completed and approved for the calling API key. Direct ERP writeback is deployment-specific.","requestBody":{"content":{"application/json":{"example":{"client_id":"8a1b7bb0-3538-4d8f-a86d-1cc4b40a764f","document_id":"doc-2026-00124","fields":[{"confidence":0.98,"field_name":"invoice_number","required":true,"source_page":1,"transform":"trim","value":"INV-2026-00124"},{"confidence":0.96,"field_name":"total_amount","required":true,"source_page":1,"value":"1250000.00"}],"job_id":"12345678-90ab-cdef-1234-567890abcdef","profile_id":"invoice-ap-sync","source":"validation"},"schema":{"$ref":"#/components/schemas/AutofillRequest"}}},"required":true},"responses":{"201":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/AutofillResponse"}}},"description":"Reviewed field payload accepted for downstream intake after approved-job and workspace validation"},"401":{"$ref":"#/components/responses/Unauthorized"},"403":{"$ref":"#/components/responses/WorkspaceMismatch"},"404":{"$ref":"#/components/responses/NotFound"},"409":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}},"description":"Referenced job is not completed and approved"},"422":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}},"description":"Payload rejected"},"500":{"$ref":"#/components/responses/ProcessingError"}},"summary":"Submit reviewed fields for downstream intake","tags":["ERP Handoff"]}},"/api/v1/batch":{"post":{"description":"Submit up to 100 image documents into the asynchronous OCR workflow. For each document, doc_type acts as the extraction trigger: known labels map to managed schemas and unknown labels trigger dynamic schema inference from the provided label plus OCR text. Store each returned job_id, poll /api/v1/status/{job_id}, review completed output, then hand approved fields to /api/v1/autofill/receive; batch_id is informational only. Completed jobs enter review with approval_status=pending_review until you approve or reject them.","requestBody":{"content":{"application/json":{"example":{"documents":[{"doc_type":"invoice","image_base64":"<base64-encoded-image>","output_format":"json"},{"doc_type":"receipt","image_base64":"<base64-encoded-image>","output_format":"markdown"}]},"schema":{"$ref":"#/components/schemas/BatchRequest"}}},"required":true},"responses":{"202":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/BatchAcceptedResponse"}}},"description":"Batch accepted for asynchronous processing. Poll each returned job_id individually; completed jobs enter pending_review before downstream handoff."},"400":{"$ref":"#/components/responses/ValidationError"},"401":{"$ref":"#/components/responses/Unauthorized"},"429":{"$ref":"#/components/responses/RateLimited"},"500":{"$ref":"#/components/responses/ProcessingError"}},"summary":"Upload one or more documents","tags":["Upload & Submission"]}},"/api/v1/jobs/{job_id}/approve":{"post":{"description":"Mark a completed job as approved before downstream intake or export.","parameters":[{"in":"path","name":"job_id","required":true,"schema":{"format":"uuid","type":"string"}}],"requestBody":{"content":{"application/json":{"example":{"notes":"Reviewed against source PDF","statement_accepted":true,"validator_name":"REZA"},"schema":{"$ref":"#/components/schemas/ApproveJobRequest"}}},"required":false},"responses":{"200":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApproveJobResponse"}}},"description":"Job approved"},"400":{"$ref":"#/components/responses/ValidationError"},"401":{"$ref":"#/components/responses/Unauthorized"},"404":{"$ref":"#/components/responses/NotFound"},"409":{"content":{"application/json":{"example":{"code":"INVALID_STATE","error":"Job is in status 'processing'; only completed jobs can be approved.","status":409},"schema":{"$ref":"#/components/schemas/ErrorResponse"}}},"description":"Job is not in completed/pending_review state"}},"summary":"Approve a completed job","tags":["Review Queue"]}},"/api/v1/jobs/{job_id}/reject":{"post":{"description":"Mark a completed job as rejected with an optional reason before downstream intake.","parameters":[{"in":"path","name":"job_id","required":true,"schema":{"format":"uuid","type":"string"}}],"requestBody":{"content":{"application/json":{"example":{"reason":"OCR captured the wrong supplier invoice number","validator_name":"REZA"},"schema":{"$ref":"#/components/schemas/RejectJobRequest"}}},"required":false},"responses":{"200":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/RejectJobResponse"}}},"description":"Job rejected"},"400":{"$ref":"#/components/responses/ValidationError"},"401":{"$ref":"#/components/responses/Unauthorized"},"404":{"$ref":"#/components/responses/NotFound"},"409":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}},"description":"Job is not in completed/pending_review state"}},"summary":"Reject a completed job","tags":["Review Queue"]}},"/api/v1/queue":{"get":{"description":"List completed jobs awaiting (or finished with) operator review for the calling API key.","parameters":[{"in":"query","name":"approval_status","required":false,"schema":{"default":"pending_review","enum":["pending_review","approved","rejected","all"],"type":"string"}},{"in":"query","name":"limit","required":false,"schema":{"default":20,"maximum":100,"minimum":1,"type":"integer"}}],"responses":{"200":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ReviewQueueResponse"}}},"description":"Queue listing"},"400":{"$ref":"#/components/responses/ValidationError"},"401":{"$ref":"#/components/responses/Unauthorized"}},"summary":"List optional review queue","tags":["Review Queue"]}},"/api/v1/status/{job_id}":{"get":{"description":"Retrieve status, timestamps, and extracted results for a submitted job.","parameters":[{"description":"UUID job identifier returned by a processing endpoint","in":"path","name":"job_id","required":true,"schema":{"example":"12345678-90ab-cdef-1234-567890abcdef","format":"uuid","type":"string"}}],"responses":{"200":{"content":{"application/json":{"examples":{"completed":{"value":{"approval_status":"pending_review","approved_at":null,"attempts":1,"completed_at":"2026-05-02T09:00:07Z","created_at":"2026-05-02T09:00:00Z","extracted_data":{"currency":"IDR","document_date":"2026-05-02","document_number":"INV-2026-00124","total_amount":"1250000.00","vendor_name":"PT Maju Jaya"},"job_id":"12345678-90ab-cdef-1234-567890abcdef","processing_time_ms":5040,"progress":100,"started_at":"2026-05-02T09:00:02Z","status":"completed","validator_name":null}},"failed":{"value":{"approval_status":"pending_review","approved_at":null,"attempts":3,"completed_at":"2026-05-02T09:00:03Z","created_at":"2026-05-02T09:00:00Z","error":"OCR backend unavailable for this job.","job_id":"12345678-90ab-cdef-1234-567890abcdef","processing_time_ms":null,"progress":5,"started_at":"2026-05-02T09:00:02Z","status":"failed","validator_name":null}},"pending":{"value":{"approval_status":"pending_review","approved_at":null,"attempts":0,"completed_at":null,"created_at":"2026-05-02T09:00:00Z","job_id":"12345678-90ab-cdef-1234-567890abcdef","processing_time_ms":null,"progress":0,"started_at":null,"status":"pending","validator_name":null}},"processing":{"value":{"approval_status":"pending_review","approved_at":null,"attempts":1,"completed_at":null,"created_at":"2026-05-02T09:00:00Z","job_id":"12345678-90ab-cdef-1234-567890abcdef","processing_time_ms":null,"progress":25,"started_at":"2026-05-02T09:00:02Z","status":"processing","validator_name":null}}},"schema":{"$ref":"#/components/schemas/JobStatusResponse"}}},"description":"Job status retrieved"},"400":{"$ref":"#/components/responses/ValidationError"},"401":{"$ref":"#/components/responses/Unauthorized"},"404":{"$ref":"#/components/responses/NotFound"},"500":{"$ref":"#/components/responses/ProcessingError"}},"summary":"Get job processing status","tags":["Job Management"]}},"/health":{"get":{"description":"Check whether the API service is responding normally.","responses":{"200":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/HealthStatus"}}},"description":"Service is healthy"}},"security":[],"summary":"Service health check","tags":["Health"]}},"/health/live":{"get":{"description":"Kubernetes-style liveness probe.","responses":{"200":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/LivenessStatus"}}},"description":"Service process is alive"}},"security":[],"summary":"Liveness probe","tags":["Health"]}},"/health/ready":{"get":{"description":"Kubernetes-style readiness probe.","responses":{"200":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ReadinessStatus"}}},"description":"Service is ready to accept traffic"}},"security":[],"summary":"Readiness probe","tags":["Health"]}}},"security":[{"bearerAuth":[]}],"servers":[{"description":"Production API","url":"https://api.immenzo.com"}],"tags":[{"description":"Unauthenticated health and probe endpoints","name":"Health"},{"description":"Primary asynchronous upload entrypoints. Start here to submit one or more documents, receive job IDs, and enter the status -> review -> autofill workflow.","name":"Upload & Submission"},{"description":"Poll submitted jobs, read extracted_data, and track processing plus review metadata through completion or failure.","name":"Job Management"},{"description":"Review completed jobs, approve or reject them, and record review-state history before downstream handoff.","name":"Review Queue"},{"description":"Submit approved fields into IngestX by Immenzo autofill intake for connector pickup, managed writeback workflows, or audit history.","name":"ERP Handoff"}]}
