{"openapi":"3.0.0","paths":{"/v1":{"get":{"operationId":"AppController_getHello","parameters":[],"responses":{"200":{"description":""}},"tags":["App"]}},"/v1/health":{"get":{"description":"Returns the current health status of the DANI API service.","operationId":"HealthController_check","parameters":[],"responses":{"200":{"description":"DANI API is running successfully."}},"summary":"Check DANI API health","tags":["Health"]}},"/v1/queues/test/status":{"get":{"description":"Checks whether DANI API can connect to the configured Redis/BullMQ queue.","operationId":"TestQueueController_getQueueStatus","parameters":[],"responses":{"200":{"description":"Queue status returned successfully.","content":{"application/json":{"schema":{"example":{"success":true,"request_id":"req_123","queue":"dani-test-queue","status":"connected","counts":{"waiting":0,"active":0,"completed":1,"failed":0,"delayed":0,"paused":0},"timestamp":"2026-05-25T14:30:00.000Z"}}}}}},"summary":"Check test queue status","tags":["Queues"]}},"/v1/queues/test/jobs":{"post":{"description":"Adds a test job to the DANI API BullMQ queue to confirm Redis queue processing works.","operationId":"TestQueueController_createTestJob","parameters":[],"requestBody":{"required":false,"content":{"application/json":{"schema":{"type":"object","properties":{"message":{"type":"string","maxLength":200,"example":"Test BullMQ job from DANI API using Upstash","description":"Optional message to include in the test queue job."}}}}}},"responses":{"201":{"description":"Test queue job created successfully.","content":{"application/json":{"schema":{"example":{"success":true,"request_id":"req_123","queue":"dani-test-queue","job_id":"1","status":"queued","timestamp":"2026-05-25T14:30:00.000Z"}}}}}},"summary":"Create a test queue job","tags":["Queues"]}},"/v1/auth/test":{"get":{"description":"Validates that the provided DANI API key is active and can authenticate successfully.","operationId":"AuthController_testAuth","parameters":[],"responses":{"200":{"description":"API key is valid."},"429":{"description":"Rate limit exceeded."}},"security":[{"dani-api-key":[]}],"summary":"Test API key authentication","tags":["Authentication"]}},"/v1/auth/ownership/workspaces/{workspace_public_id}":{"get":{"description":"Returns success only when the authenticated API key owns or is scoped to the requested workspace.","operationId":"AuthController_testWorkspaceOwnership","parameters":[{"name":"workspace_public_id","required":true,"in":"path","schema":{"example":"wrk_...","type":"string"}}],"responses":{"200":{"description":"Workspace ownership confirmed."},"404":{"description":"Workspace not found or not owned by the authenticated API key."}},"security":[{"dani-api-key":[]}],"summary":"Test workspace ownership","tags":["Authentication"]}},"/v1/auth/ownership/customers/{customer_public_id}":{"get":{"description":"Returns success only when the authenticated API key owns or is scoped to the requested customer.","operationId":"AuthController_testCustomerOwnership","parameters":[{"name":"customer_public_id","required":true,"in":"path","schema":{"example":"cus_...","type":"string"}}],"responses":{"200":{"description":"Customer ownership confirmed."},"404":{"description":"Customer not found or not owned by the authenticated API key."}},"security":[{"dani-api-key":[]}],"summary":"Test customer ownership","tags":["Authentication"]}},"/v1/auth/ownership/api-keys/{api_key_public_id}":{"get":{"description":"Returns success only when the authenticated API key is allowed to access the requested API key record.","operationId":"AuthController_testApiKeyOwnership","parameters":[{"name":"api_key_public_id","required":true,"in":"path","schema":{"example":"key_...","type":"string"}}],"responses":{"200":{"description":"API key ownership confirmed."},"404":{"description":"API key not found or not owned by the authenticated API key."}},"security":[{"dani-api-key":[]}],"summary":"Test API key ownership","tags":["Authentication"]}},"/v1/auth/audit-logs/latest":{"get":{"description":"Returns latest audit logs created by the authenticated API key. This is a local development verification endpoint.","operationId":"AuthController_getLatestAuditLogs","parameters":[],"responses":{"200":{"description":"Latest audit logs returned successfully."}},"security":[{"dani-api-key":[]}],"summary":"Get latest audit logs for the authenticated API key","tags":["Authentication"]}},"/v1/credits/balance":{"get":{"description":"Returns or creates the current credit balance for the authenticated API key customer context.","operationId":"CreditController_getBalance","parameters":[],"responses":{"200":{"description":"Credit balance returned successfully."}},"security":[{"dani-api-key":[]}],"summary":"Get current credit balance","tags":["Credits"]}},"/v1/credits/transactions/latest":{"get":{"description":"Returns latest credit ledger entries for the authenticated API key customer context.","operationId":"CreditController_getLatestTransactions","parameters":[],"responses":{"200":{"description":"Credit transactions returned successfully."}},"security":[{"dani-api-key":[]}],"summary":"Get latest credit transactions","tags":["Credits"]}},"/v1/credits/test/grant":{"post":{"description":"Local development endpoint for adding credits to the authenticated customer credit balance.","operationId":"CreditController_grantCredits","parameters":[],"requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","required":["credits"],"properties":{"credits":{"type":"number","minimum":0.01,"maximum":10000,"example":25},"description":{"type":"string","example":"Initial local test credits"}}}}}},"responses":{"201":{"description":"Credits granted successfully."}},"security":[{"dani-api-key":[]}],"summary":"Grant test credits","tags":["Credits"]}},"/v1/credits/test/charge":{"post":{"description":"Local development endpoint for deducting credits from the authenticated customer credit balance.","operationId":"CreditController_chargeCredits","parameters":[],"requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","required":["credits"],"properties":{"credits":{"type":"number","minimum":0.01,"maximum":10000,"example":1},"reference_type":{"type":"string","example":"manual_test"},"reference_id":{"type":"string","example":"test-charge-001"},"description":{"type":"string","example":"Test charge 1 credit"}}}}}},"responses":{"201":{"description":"Credits charged successfully."},"402":{"description":"Insufficient credits."}},"security":[{"dani-api-key":[]}],"summary":"Charge test credits","tags":["Credits"]}},"/v1/credits/rules/calculate":{"post":{"description":"Calculates credit cost using DANI API charging rules without deducting credits.","operationId":"CreditController_calculateCharge","parameters":[],"requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","required":["page_count","engine_count"],"properties":{"page_count":{"type":"integer","minimum":1,"maximum":500,"example":5},"engine_count":{"type":"integer","minimum":1,"maximum":4,"example":2},"document_type":{"type":"string","example":"invoice"},"primary_engine":{"type":"string","example":"openai"},"compare_mode":{"type":"boolean","example":true},"fallback_used":{"type":"boolean","example":false},"fallback_engine_count":{"type":"integer","minimum":0,"maximum":3,"example":0},"run_validation":{"type":"boolean","example":true},"check_duplicates":{"type":"boolean","example":true},"export_count":{"type":"integer","minimum":0,"maximum":10,"example":1}}}}}},"responses":{"200":{"description":"Credit charge calculated successfully."}},"security":[{"dani-api-key":[]}],"summary":"Calculate credit charge from rules","tags":["Credits"]}},"/v1/credits/rules/charge":{"post":{"description":"Calculates credit cost using DANI API charging rules and deducts the calculated amount from the customer balance.","operationId":"CreditController_chargeByRules","parameters":[],"requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","required":["page_count","engine_count"],"properties":{"page_count":{"type":"integer","minimum":1,"maximum":500,"example":5},"engine_count":{"type":"integer","minimum":1,"maximum":4,"example":2},"document_type":{"type":"string","example":"invoice"},"primary_engine":{"type":"string","example":"openai"},"compare_mode":{"type":"boolean","example":true},"fallback_used":{"type":"boolean","example":false},"fallback_engine_count":{"type":"integer","minimum":0,"maximum":3,"example":0},"run_validation":{"type":"boolean","example":true},"check_duplicates":{"type":"boolean","example":true},"export_count":{"type":"integer","minimum":0,"maximum":10,"example":1},"reference_type":{"type":"string","example":"document_processing"},"reference_id":{"type":"string","example":"doc_test_001"},"description":{"type":"string","example":"Rule-based document processing charge"}}}}}},"responses":{"201":{"description":"Credits charged using rules successfully."},"402":{"description":"Insufficient credits."}},"security":[{"dani-api-key":[]}],"summary":"Charge credits using charging rules","tags":["Credits"]}},"/v1/usage/test/log":{"post":{"description":"Local development endpoint for creating a usage log entry for the authenticated API key context.","operationId":"UsageController_createTestUsageLog","parameters":[],"requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","required":["event_type"],"properties":{"event_type":{"type":"string","example":"document.extraction.completed"},"endpoint":{"type":"string","example":"/v1/documents/extract"},"method":{"type":"string","example":"POST"},"document_type":{"type":"string","example":"invoice"},"engine":{"type":"string","example":"openai"},"reference_type":{"type":"string","example":"document_processing"},"reference_id":{"type":"string","example":"doc_test_usage_001"},"credits_used":{"type":"number","example":3.7},"pages_processed":{"type":"number","example":5},"request_duration_ms":{"type":"number","example":1250},"status":{"type":"string","example":"success"}}}}}},"responses":{"201":{"description":"Usage log created successfully."}},"security":[{"dani-api-key":[]}],"summary":"Create a test usage log","tags":["Usage"]}},"/v1/usage/latest":{"get":{"description":"Returns latest usage logs for the authenticated API key customer context.","operationId":"UsageController_getLatestUsageLogs","parameters":[],"responses":{"200":{"description":"Usage logs returned successfully."}},"security":[{"dani-api-key":[]}],"summary":"Get latest usage logs","tags":["Usage"]}},"/v1/usage/summary":{"get":{"description":"Returns request, credit, and page usage summary for the authenticated API key customer context.","operationId":"UsageController_getUsageSummary","parameters":[],"responses":{"200":{"description":"Usage summary returned successfully."}},"security":[{"dani-api-key":[]}],"summary":"Get usage summary","tags":["Usage"]}},"/v1/documents/upload":{"post":{"description":"Creates a document intake record from a multipart file upload, validates it, hashes it, and stores the uploaded object.","operationId":"DocumentController_uploadDocument","parameters":[],"requestBody":{"required":true,"content":{"multipart/form-data":{"schema":{"type":"object","required":["file"],"properties":{"file":{"type":"string","format":"binary","description":"Document file to upload."},"document_type":{"type":"string","example":"invoice"},"source_label":{"type":"string","example":"phase_3_upload_test"},"description":{"type":"string","example":"7.3 file upload intake test"}}}}}},"responses":{"201":{"description":"Document upload intake record created successfully."}},"security":[{"dani-api-key":[]}],"summary":"Upload a document file for intake","tags":["Documents"]}},"/v1/documents/ingest-url":{"post":{"description":"Creates a document intake record from a remote file URL, validates the URL extension, hashes the source URL, and stores a local URL reference object.","operationId":"DocumentController_ingestDocumentUrl","parameters":[],"requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","required":["file_url"],"properties":{"file_url":{"type":"string","example":"https://example.com/sample-invoice.pdf"},"original_filename":{"type":"string","example":"sample-invoice.pdf"},"document_type":{"type":"string","example":"invoice"},"source_label":{"type":"string","example":"phase_3_url_test"},"description":{"type":"string","example":"7.3 URL intake test"}}}}}},"responses":{"201":{"description":"Document URL intake record created successfully."}},"security":[{"dani-api-key":[]}],"summary":"Ingest a document from a file URL","tags":["Documents"]}},"/v1/documents/{document_public_id}/extract":{"post":{"description":"Runs the configured extraction engine for an existing ingested document, updates extraction lifecycle status, and persists extraction results.","operationId":"DocumentController_extractDocument","parameters":[{"name":"document_public_id","required":true,"in":"path","schema":{"example":"doc_...","type":"string"}}],"requestBody":{"required":false,"content":{"application/json":{"schema":{"type":"object","properties":{"request_id":{"type":"string","example":"req_manual_test_001"},"correlation_id":{"type":"string","example":"corr_manual_test_001"},"idempotency_key":{"type":"string","example":"idem_manual_test_001"},"engine":{"type":"string","example":"openai","enum":["openai","google_document_ai","aws_textract","azure_document_intelligence","auto","fallback","compare"]},"processing_mode":{"type":"string","example":"sync","enum":["sync","async","batch","fallback","compare"]},"requested_fields":{"type":"array","items":{"type":"string"},"example":["invoice_number","vendor","total","line_items"]},"timeout_ms":{"type":"number","example":60000},"metadata":{"type":"object","example":{"source":"manual_phase_5_test"}}}}}}},"responses":{"201":{"description":"Document extraction executed successfully."},"404":{"description":"Document not found."}},"security":[{"dani-api-key":[]}],"summary":"Run document extraction","tags":["Documents"]}},"/v1/documents/{document_public_id}":{"get":{"description":"Returns document status, intake metadata, validation info, storage info, and extraction result placeholder for the authenticated API key context.","operationId":"DocumentController_getDocumentStatus","parameters":[{"name":"document_public_id","required":true,"in":"path","schema":{"example":"doc_...","type":"string"}}],"responses":{"200":{"description":"Document status returned successfully."},"404":{"description":"Document not found."}},"security":[{"dani-api-key":[]}],"summary":"Get document status and result","tags":["Documents"]}},"/v1/workflows/duplicates/check":{"post":{"description":"Runs deterministic duplicate detection using checksum, source URL, filename, file size, and document type signals.","operationId":"WorkflowController_checkDuplicates","parameters":[],"requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/WorkflowDuplicateCheckDto"}}}},"responses":{"201":{"description":"Duplicate detection completed successfully."}},"security":[{"dani-api-key":[]}],"summary":"Check duplicate documents or extracted records","tags":["Workflow APIs"]}},"/v1/workflows/expenses/categorize":{"post":{"description":"Runs deterministic expense categorization using merchant, description, amount, category hint, and allowed category constraints.","operationId":"WorkflowController_categorizeExpense","parameters":[],"requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/WorkflowExpenseCategorizationDto"}}}},"responses":{"201":{"description":"Expense categorization completed successfully."}},"security":[{"dani-api-key":[]}],"summary":"Categorize expense data","tags":["Workflow APIs"]}},"/v1/workflows/exports":{"post":{"description":"Creates a document export payload in JSON, CSV, or XLSX-ready format. Phase 12.4 uses in-memory export status caching only.","operationId":"WorkflowController_createExport","parameters":[],"requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/CreateWorkflowExportDto"}}}},"responses":{"201":{"description":"Export workflow completed successfully."}},"security":[{"dani-api-key":[]}],"summary":"Create an export workflow","tags":["Workflow APIs"]}},"/v1/workflows/exports/{export_public_id}":{"get":{"description":"Returns an export workflow from the in-memory Phase 12.4 export cache while the API process is running.","operationId":"WorkflowController_getExport","parameters":[{"name":"export_public_id","required":true,"in":"path","schema":{"example":"exp_...","type":"string"}}],"responses":{"200":{"description":"Export workflow status returned successfully."}},"security":[{"dani-api-key":[]}],"summary":"Get export workflow status","tags":["Workflow APIs"]}},"/v1/workflows/batches":{"post":{"description":"Creates an in-memory batch workflow plan after validating document ownership and item limits.","operationId":"WorkflowController_createBatch","parameters":[],"requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/CreateWorkflowBatchDto"}}}},"responses":{"201":{"description":"Batch workflow accepted successfully."}},"security":[{"dani-api-key":[]}],"summary":"Create a workflow batch","tags":["Workflow APIs"]}},"/v1/workflows/batches/{batch_public_id}":{"get":{"description":"Returns a batch workflow from the in-memory Phase 12.5 batch cache while the API process is running.","operationId":"WorkflowController_getBatch","parameters":[{"name":"batch_public_id","required":true,"in":"path","schema":{"example":"bat_...","type":"string"}}],"responses":{"200":{"description":"Batch workflow status returned successfully."}},"security":[{"dani-api-key":[]}],"summary":"Get batch workflow status","tags":["Workflow APIs"]}},"/v1/workflows/webhooks":{"post":{"description":"Creates an in-memory webhook registration with URL validation, event type validation, and secret redaction.","operationId":"WorkflowController_createWebhook","parameters":[],"requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/CreateWorkflowWebhookDto"}}}},"responses":{"201":{"description":"Webhook created successfully."}},"security":[{"dani-api-key":[]}],"summary":"Create a workflow webhook","tags":["Workflow APIs"]},"get":{"description":"Lists in-memory webhook registrations for the authenticated customer context.","operationId":"WorkflowController_listWebhooks","parameters":[],"responses":{"200":{"description":"Webhook list returned successfully."}},"security":[{"dani-api-key":[]}],"summary":"List workflow webhooks","tags":["Workflow APIs"]}},"/v1/workflows/webhooks/{webhook_public_id}":{"patch":{"description":"Updates an in-memory webhook registration for the authenticated customer context.","operationId":"WorkflowController_updateWebhook","parameters":[{"name":"webhook_public_id","required":true,"in":"path","schema":{"example":"whk_...","type":"string"}}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/UpdateWorkflowWebhookDto"}}}},"responses":{"200":{"description":"Webhook updated successfully."}},"security":[{"dani-api-key":[]}],"summary":"Update a workflow webhook","tags":["Workflow APIs"]},"delete":{"description":"Disables an in-memory webhook registration. Phase 12.6 uses soft-delete behavior by setting status to disabled.","operationId":"WorkflowController_deleteWebhook","parameters":[{"name":"webhook_public_id","required":true,"in":"path","schema":{"example":"whk_...","type":"string"}}],"responses":{"200":{"description":"Webhook disabled successfully."}},"security":[{"dani-api-key":[]}],"summary":"Delete or disable a workflow webhook","tags":["Workflow APIs"]}},"/v1/admin/auth/test":{"get":{"description":"Validates that the supplied API key is authenticated and has admin access.","operationId":"AdminController_getAdminAuthTest","parameters":[],"responses":{"200":{"description":"Admin API key authenticated successfully."}},"security":[{"dani-api-key":[]}],"summary":"Test admin authentication","tags":["Admin"]}},"/v1/admin/engines/monitoring":{"get":{"description":"Returns extraction engine result monitoring data, including provider, model, status, duration, related document, and extraction job references.","operationId":"AdminController_getEngineMonitoring","parameters":[],"responses":{"200":{"description":"Engine monitoring records returned successfully."}},"security":[{"dani-api-key":[]}],"summary":"Get extraction engine monitoring records","tags":["Admin"]}},"/v1/admin/engines/health":{"get":{"description":"Returns registered extraction providers, required configuration status, routing order, retry settings, and provider availability for admin monitoring.","operationId":"AdminController_getProviderHealth","parameters":[],"responses":{"200":{"description":"Provider health and engine availability returned successfully."}},"security":[{"dani-api-key":[]}],"summary":"Get extraction provider health and availability","tags":["Admin"]}},"/v1/admin/documents/monitoring":{"get":{"description":"Returns admin document monitoring data, including document status, ownership context, latest extraction job, latest extraction result, latest validation result, and latest engine result.","operationId":"AdminController_getDocumentMonitoring","parameters":[],"responses":{"200":{"description":"Document monitoring records returned successfully."}},"security":[{"dani-api-key":[]}],"summary":"Get document monitoring records","tags":["Admin"]}},"/v1/admin/usage/monitoring":{"get":{"description":"Returns admin usage monitoring data, including request usage, status, cost, billing, ownership context, related document, related extraction job, and credit transactions.","operationId":"AdminController_getUsageMonitoring","parameters":[],"responses":{"200":{"description":"Usage monitoring records returned successfully."}},"security":[{"dani-api-key":[]}],"summary":"Get usage monitoring records","tags":["Admin"]}}},"info":{"title":"DANI API","description":"Business automation API platform for document processing, invoice extraction, receipt extraction, validation, usage tracking, and future workflow automation.","version":"1.0.0","contact":{}},"tags":[{"name":"Health","description":"System health and service status"},{"name":"Queues","description":"Queue and background job testing"},{"name":"Authentication","description":"API key authentication testing"},{"name":"Credits","description":"Credit balance and credit transaction ledger"},{"name":"Usage","description":"Usage log and usage summary tracking"},{"name":"Documents","description":"Document intake, validation, storage, and status"}],"servers":[{"url":"http://localhost:5000","description":"Local development"},{"url":"https://dani-api-staging.onrender.com","description":"Staging"},{"url":"https://api.sjappliedtech.com","description":"Production"}],"components":{"securitySchemes":{"dani-api-key":{"scheme":"bearer","bearerFormat":"DANI API Key","type":"http","description":"Use your DANI API key. Example: Authorization: Bearer dani_live_sk_xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx"}},"schemas":{"WorkflowDuplicateCheckDto":{"type":"object","properties":{}},"WorkflowExpenseCategorizationDto":{"type":"object","properties":{}},"CreateWorkflowExportDto":{"type":"object","properties":{}},"CreateWorkflowBatchDto":{"type":"object","properties":{}},"CreateWorkflowWebhookDto":{"type":"object","properties":{}},"UpdateWorkflowWebhookDto":{"type":"object","properties":{}}}}}