{"components":{"parameters":{"IdempotencyKey":{"description":"Bound to project, operation and canonical body. Scan retries replay the original result.","example":"example-request-1","in":"header","name":"Idempotency-Key","required":true,"schema":{"maxLength":256,"minLength":1,"type":"string"}},"OrgId":{"example":"00000000-0000-4000-8000-000000000001","in":"path","name":"org_id","required":true,"schema":{"format":"uuid","type":"string"}},"ProjectId":{"example":"00000000-0000-4000-8000-000000000002","in":"path","name":"id","required":true,"schema":{"format":"uuid","type":"string"}}},"responses":{"Error":{"content":{"application/json":{"example":{"error":{"code":"invalid_request","message":"The request does not match the operation schema.","request_uuid":"00000000-0000-4000-8000-000000000001"}},"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}},"description":"Error envelope; HTTP status and stable code are listed in docs/limits.md.\nThe request UUID also appears in X-Request-Id. This is a support correlation\nID and does not promise a retrievable result when persistence failed.\nRate-limit denials include Retry-After rounded up to seconds and\nX-RateLimit-Remaining. Dependency capacity errors use Retry-After: 2.\n","headers":{"Retry-After":{"description":"Seconds before retrying a rate or capacity denial.","schema":{"minimum":1,"type":"integer"}},"X-RateLimit-Remaining":{"description":"Minimum whole tokens remaining across the applicable key, project and org buckets; present on rate denials.","schema":{"minimum":0,"type":"integer"}}}},"NotImplemented":{"content":{"application/json":{"example":{"error":{"code":"operation_not_implemented","message":"not implemented in this build","request_uuid":"00000000-0000-4000-8000-000000000001"}},"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}},"description":"This build does not implement this operation."},"Organization":{"content":{"application/json":{"example":{"created_at":"2026-09-16T00:00:00Z","description":"","enabled":true,"id":"00000000-0000-4000-8000-000000000001","name":"Example customer"},"schema":{"$ref":"#/components/schemas/Organization"}}},"description":"Organization metadata; identity is immutable."},"Project":{"content":{"application/json":{"example":{"active_config_version":1,"created_at":"2026-09-16T00:00:00Z","description":"","enabled":true,"id":"00000000-0000-4000-8000-000000000002","name":"Example app","org_id":"00000000-0000-4000-8000-000000000001"},"schema":{"$ref":"#/components/schemas/Project"}}},"description":"Project metadata; organization ownership is immutable."},"ProjectConfig":{"content":{"application/json":{"example":{"body":{"context_prompt":"","result_ttl_days":30,"retain_input_days":0,"rules":[],"taxonomy":"mitre_atlas_tactic"},"version":1},"schema":{"properties":{"body":{"$ref":"#/components/schemas/Policy"},"version":{"minimum":1,"type":"integer"}},"required":["version","body"],"type":"object"}}},"description":"Published configuration and immutable version; ETag is the version for If-Match.","headers":{"ETag":{"example":"\"1\"","schema":{"type":"string"}}}},"Result":{"content":{"application/json":{"examples":{"complete":{"summary":"Complete prompt with classifier agreement","value":{"completed_at":"2026-09-16T00:00:02Z","confidence":0.97,"confidence_basis":"t2_agreement_v1","config_version":1,"coverage":{"chunks":1,"messages_assessed":1,"messages_total":1},"created_at":"2026-09-16T00:00:00Z","expires_at":"2026-10-16T00:00:00Z","findings":[],"latency_ms":{"embed":38,"search":9,"t2":1200,"total":1261},"recommendation":null,"request_uuid":"00000000-0000-4000-8000-000000000002","revisions":{"confidence_basis":"knn_heuristic_v1","corpus":"configured-corpus","model":"configured-revision"},"scan_type":"complete","signals":{"adverse_share":0,"knn":{"confidence":0.9,"verdict":"benign"},"margin":1,"max_similarity":0.98,"neighbor_count":20,"path":"close_benign","support":0.9},"stages":{"embed":"ok","knn":"ok","t2":"ok"},"status":"completed","taxonomy":"mitre_atlas_tactic","technique":null,"usage":[{"input_tokens":620,"model":"configured-t2-model","output_tokens":12,"stage":"t2"}],"verdict":"benign","violation":false}},"document":{"summary":"One-page text document with complete assessment","value":{"completed_at":"2026-09-16T00:00:04Z","confidence":0.97,"confidence_basis":"t2_agreement_v1","config_version":1,"coverage":{"chunks":1,"empty_pages":[],"extraction":"complete","extraction_source":"document_model","messages_assessed":1,"messages_total":1,"pages_extracted":1},"created_at":"2026-09-16T00:00:00Z","expires_at":"2026-10-16T00:00:00Z","findings":[],"latency_ms":{"document_model":2000,"embed":38,"search":9,"t2":1200,"total":3261},"per_chunk":[{"confidence":0.97,"evidence":{"chunk_index":0,"offset":0,"page":1},"index":0,"offsets":{"end":24,"start":0},"stages":{"embed":"ok","knn":"ok","t2":"ok"},"verdict":"benign"}],"recommendation":null,"request_uuid":"00000000-0000-4000-8000-000000000003","revisions":{"confidence_basis":"knn_heuristic_v1","corpus":"configured-corpus","model":"configured-revision"},"scan_type":"complete","signals":{"adverse_share":0,"document_model":{"partial":false,"verdict":"benign"},"knn":{"confidence":0.9,"verdict":"benign"},"margin":1,"max_similarity":0.98,"neighbor_count":20,"path":"close_benign","support":0.9},"stages":{"document_model":"ok","embed":"ok","knn":"ok","t2":"ok"},"status":"completed","taxonomy":"mitre_atlas_tactic","technique":null,"usage":[{"input_tokens":180,"model":"configured-document-model","output_tokens":60,"stage":"document_model"},{"input_tokens":620,"model":"configured-t2-model","output_tokens":12,"stage":"t2"}],"verdict":"benign","violation":false}},"fast":{"summary":"Fast prompt with strong benign reference support","value":{"completed_at":"2026-09-16T00:00:01Z","confidence":0.9,"confidence_basis":"knn_heuristic_v1","config_version":1,"coverage":{"chunks":1,"messages_assessed":1,"messages_total":1},"created_at":"2026-09-16T00:00:00Z","expires_at":"2026-10-16T00:00:00Z","findings":[],"latency_ms":{"embed":38,"search":9,"t2":null,"total":61},"recommendation":null,"request_uuid":"00000000-0000-4000-8000-000000000001","revisions":{"confidence_basis":"knn_heuristic_v1","corpus":"configured-corpus","model":"configured-revision"},"scan_type":"fast","signals":{"adverse_share":0,"margin":1,"max_similarity":0.98,"neighbor_count":20,"path":"close_benign","support":0.9},"stages":{"embed":"ok","knn":"ok","t2":"skipped"},"status":"completed","taxonomy":"mitre_atlas_tactic","technique":null,"usage":[],"verdict":"benign","violation":false}}},"schema":{"$ref":"#/components/schemas/ScanResult"}}},"description":"Persisted assessment, including inconclusive or failed stage outcomes."}},"schemas":{"BatchInput":{"additionalProperties":false,"allOf":[{"if":{"properties":{"scan_type":{"const":"complete"}}},"then":{"properties":{"items":{"maxItems":25}}}}],"properties":{"items":{"description":"Unique item_id values. At most 25 items when scan_type is complete.","items":{"additionalProperties":false,"properties":{"item_id":{"minLength":1,"type":"string"},"messages":{"items":{"$ref":"#/components/schemas/Message"},"maxItems":64,"minItems":1,"type":"array"},"metadata":{"$ref":"#/components/schemas/Metadata"},"session_uuid":{"format":"uuid","type":"string"},"target":{"default":"all","enum":["all","last_user"],"type":"string"}},"required":["item_id","messages"],"type":"object"},"maxItems":100,"minItems":1,"type":"array"},"scan_type":{"$ref":"#/components/schemas/ScanType"}},"required":["scan_type","items"],"type":"object"},"BatchResult":{"properties":{"items":{"items":{"oneOf":[{"required":["result"]},{"required":["error"]}],"properties":{"error":{"$ref":"#/components/schemas/ErrorBody"},"item_id":{"type":"string"},"request_uuid":{"format":"uuid","type":"string"},"result":{"$ref":"#/components/schemas/ScanResult"}},"required":["item_id","request_uuid"],"type":"object"},"type":"array"},"summary":{"properties":{"completed":{"minimum":0,"type":"integer"},"failed":{"minimum":0,"type":"integer"},"inconclusive":{"minimum":0,"type":"integer"}},"required":["completed","inconclusive","failed"],"type":"object"}},"required":["items","summary"],"type":"object"},"Confidence":{"description":"Confidence in the reported verdict, not P(violation), not cosine similarity. Null for unknown; uncalibrated in v1. Fast caps at 0.99; the exact After T2 formula can reach 0.997.","maximum":0.997,"minimum":0,"type":["number","null"]},"ConfidenceBasis":{"description":"Heuristic support for the verdict: knn_heuristic_v1 uses reference evidence; t2_agreement_v1 combines agreeing evidence; t2_disagreement_v1 gives T2 precedence at 0.60; t2_only uses a model verdict at 0.65; t2_null means unknown with null confidence. Scores are not calibrated probabilities.","enum":["knn_heuristic_v1","t2_agreement_v1","t2_disagreement_v1","t2_only","t2_null"],"type":"string"},"ConfigRevisions":{"additionalProperties":false,"properties":{"confidence_basis":{"const":"knn_heuristic_v1","type":"string"},"corpus":{"minLength":1,"type":"string"},"model":{"minLength":1,"type":"string"}},"required":["model","corpus","confidence_basis"],"type":"object"},"Coverage":{"description":"Assessed message or document chunk counts and model-reported extraction coverage. Page counts are not independently verified; truncated extraction or failed chunks cannot establish benign.","properties":{"chunks":{"minimum":0,"type":"integer"},"empty_pages":{"items":{"minimum":1,"type":"integer"},"type":"array"},"extraction":{"enum":["complete","truncated","failed"],"type":"string"},"extraction_source":{"const":"document_model","type":"string"},"messages_assessed":{"minimum":0,"type":"integer"},"messages_total":{"minimum":0,"type":"integer"},"pages_extracted":{"description":"Last complete model-reported page marker; no independent page count.","minimum":0,"type":"integer"}},"required":["messages_assessed","messages_total","chunks"],"type":"object"},"CreateMetadata":{"additionalProperties":false,"properties":{"description":{"default":"","type":"string"},"name":{"minLength":1,"type":"string"}},"required":["name"],"type":"object"},"CreateProject":{"additionalProperties":false,"properties":{"config":{"$ref":"#/components/schemas/Policy"},"description":{"default":"","type":"string"},"name":{"minLength":1,"type":"string"}},"required":["name"],"type":"object"},"ErrorBody":{"properties":{"code":{"enum":["invalid_request","unsupported_content","input_too_long","idempotency_conflict","request_in_progress","not_found","result_expired","capacity","model_unavailable","embedder_unavailable","vector_search_unavailable","embedding_invalid","result_not_persisted","document_unreadable","no_text_extracted","deadline_exceeded","unauthorized","rate_limited","operation_not_implemented","database_unavailable","payload_too_large","unsupported_media_type","reference_not_ready","key_already_created","forbidden","precondition_failed","method_not_allowed","management_disabled","disabled"],"type":"string"},"key":{"$ref":"#/components/schemas/KeyMetadata","description":"Metadata returned on key_already_created retries; never a secret."},"message":{"type":"string"},"request_uuid":{"format":"uuid","type":"string"}},"required":["code","message","request_uuid"],"type":"object"},"ErrorEnvelope":{"additionalProperties":false,"properties":{"error":{"$ref":"#/components/schemas/ErrorBody"}},"required":["error"],"type":"object"},"Evidence":{"description":"Offsets and indices only; never quoted input text.","properties":{"chunk_index":{"minimum":0,"type":"integer"},"message_index":{"minimum":0,"type":"integer"},"message_indices":{"items":{"minimum":0,"type":"integer"},"type":"array"},"offset":{"minimum":0,"type":"integer"},"page":{"minimum":1,"type":["integer","null"]},"source":{"enum":["knn","t2","document_model"],"type":"string"}},"type":"object"},"Finding":{"properties":{"confidence":{"$ref":"#/components/schemas/Confidence"},"evidence":{"$ref":"#/components/schemas/Evidence"},"id":{"description":"ATLAS tactic label or Risky; never represented as a technique ID.","type":"string"},"kind":{"enum":["tactic","risk"],"type":"string"},"owasp_agentic":{"items":{"type":"string"},"type":"array"},"scheme":{"const":"mitre_atlas","type":"string"},"source":{"enum":["knn","t2","document_model"],"type":"string"},"version":{"const":"4","type":"string"}},"required":["scheme","version","kind","id","owasp_agentic","confidence","evidence"],"type":"object"},"KeyMetadata":{"properties":{"created_at":{"format":"date-time","type":"string"},"display_prefix":{"description":"Display only; mutations always use the full immutable key ID.","type":"string"},"expires_at":{"format":"date-time","type":["string","null"]},"id":{"format":"uuid","type":"string"},"last_used_at":{"format":"date-time","type":["string","null"]},"name":{"type":"string"},"project_id":{"format":"uuid","type":"string"},"revoked_at":{"format":"date-time","type":["string","null"]},"scopes":{"$ref":"#/components/schemas/Scopes"}},"required":["id","project_id","name","display_prefix","scopes","created_at","expires_at","revoked_at","last_used_at"],"type":"object"},"Message":{"additionalProperties":false,"properties":{"content":{"description":"Text only, at most 32768 characters total per message. Empty and whitespace-only assessed input is rejected.","oneOf":[{"maxLength":32768,"type":"string"},{"items":{"additionalProperties":false,"properties":{"text":{"maxLength":32768,"type":"string"},"type":{"const":"text","type":"string"}},"required":["type","text"],"type":"object"},"minItems":1,"type":"array"}]},"name":{"type":"string"},"role":{"enum":["system","developer","user","assistant","tool"],"type":"string"},"tool_call_id":{"type":"string"},"tool_calls":{"items":{"additionalProperties":false,"properties":{"function":{"additionalProperties":false,"properties":{"arguments":{"type":"string"},"name":{"type":"string"}},"required":["name","arguments"],"type":"object"},"id":{"type":"string"},"type":{"const":"function","type":"string"}},"required":["id","type","function"],"type":"object"},"type":"array"}},"required":["role","content"],"type":"object"},"Metadata":{"additionalProperties":true,"description":"Caller-asserted, at most 4096 bytes and depth 2. Reserved keys rejected. Never embedded, sent to T2 or logged raw.","maxProperties":32,"type":"object"},"Organization":{"properties":{"created_at":{"format":"date-time","type":"string"},"description":{"type":"string"},"enabled":{"type":"boolean"},"id":{"format":"uuid","type":"string"},"name":{"type":"string"}},"required":["id","name","description","enabled","created_at"],"type":"object"},"Policy":{"additionalProperties":false,"properties":{"context_prompt":{"default":"","maxLength":4000,"type":"string"},"enabled_modalities":{"items":{"enum":["prompt","document"],"type":"string"},"type":"array","uniqueItems":true},"limits":{"additionalProperties":false,"description":"Bounded by independent organization allowances; key issuance cannot increase them.","properties":{"complete_rps":{"default":5,"exclusiveMinimum":0,"type":"number"},"document_rps":{"default":1,"exclusiveMinimum":0,"type":"number"},"fast_rps":{"default":50,"exclusiveMinimum":0,"type":"number"}},"type":"object"},"result_ttl_days":{"default":30,"maximum":36500,"minimum":1,"type":"integer"},"retain_input_days":{"const":0,"default":0,"description":"Nonzero retention is rejected until the cleanup worker exists.","type":"integer"},"revisions":{"$ref":"#/components/schemas/ConfigRevisions"},"rules":{"items":{"additionalProperties":false,"properties":{"then":{"enum":["alert","block"],"type":"string"},"when":{"additionalProperties":false,"properties":{"min_confidence":{"maximum":1,"minimum":0,"type":"number"},"techniques":{"items":{"type":"string"},"type":"array"},"verdict":{"$ref":"#/components/schemas/Verdict"}},"required":["verdict"],"type":"object"}},"required":["when","then"],"type":"object"},"type":"array"},"taxonomy":{"const":"mitre_atlas_tactic","type":"string"}},"type":"object"},"Project":{"allOf":[{"$ref":"#/components/schemas/Organization"},{"properties":{"active_config_version":{"minimum":1,"type":"integer"},"org_id":{"format":"uuid","type":"string"}},"required":["org_id","active_config_version"],"type":"object"}]},"PromptInput":{"additionalProperties":false,"properties":{"messages":{"items":{"$ref":"#/components/schemas/Message"},"maxItems":64,"minItems":1,"type":"array"},"metadata":{"$ref":"#/components/schemas/Metadata"},"scan_type":{"$ref":"#/components/schemas/ScanType"},"session_uuid":{"description":"Correlation only; no server-side history.","format":"uuid","type":"string"},"target":{"default":"all","enum":["all","last_user"],"type":"string"}},"required":["scan_type","messages"],"type":"object"},"Revisions":{"properties":{"confidence_basis":{"$ref":"#/components/schemas/ConfidenceBasis"},"corpus":{"type":"string"},"model":{"type":"string"}},"required":["model","corpus","confidence_basis"],"type":"object"},"ScanResult":{"properties":{"completed_at":{"format":"date-time","type":"string"},"confidence":{"$ref":"#/components/schemas/Confidence"},"confidence_basis":{"$ref":"#/components/schemas/ConfidenceBasis"},"config_version":{"minimum":1,"type":"integer"},"coverage":{"$ref":"#/components/schemas/Coverage"},"created_at":{"format":"date-time","type":"string"},"error":{"$ref":"#/components/schemas/ErrorBody"},"expires_at":{"format":"date-time","type":"string"},"findings":{"items":{"$ref":"#/components/schemas/Finding"},"type":"array"},"latency_ms":{"properties":{"document_model":{"minimum":0,"type":["number","null"]},"embed":{"minimum":0,"type":["number","null"]},"search":{"minimum":0,"type":["number","null"]},"t2":{"minimum":0,"type":["number","null"]},"total":{"minimum":0,"type":"number"}},"required":["total"],"type":"object"},"per_chunk":{"items":{"properties":{"confidence":{"$ref":"#/components/schemas/Confidence"},"evidence":{"$ref":"#/components/schemas/Evidence"},"index":{"minimum":0,"type":"integer"},"offsets":{"description":"UTF-8 byte offsets into extracted text; end is exclusive.","properties":{"end":{"minimum":0,"type":"integer"},"start":{"minimum":0,"type":"integer"}},"required":["start","end"],"type":"object"},"stages":{"$ref":"#/components/schemas/Stages"},"verdict":{"$ref":"#/components/schemas/Verdict"}},"required":["index","offsets","evidence","verdict","confidence","stages"],"type":"object"},"type":"array"},"recommendation":{"enum":["alert","block",null],"type":["string","null"]},"request_uuid":{"format":"uuid","type":"string"},"revisions":{"$ref":"#/components/schemas/Revisions"},"scan_type":{"$ref":"#/components/schemas/ScanType"},"signals":{"$ref":"#/components/schemas/Signals"},"stages":{"$ref":"#/components/schemas/Stages"},"status":{"enum":["completed","inconclusive","failed"],"type":"string"},"taxonomy":{"const":"mitre_atlas_tactic","type":"string"},"technique":{"description":"Primary finding at tactic level, or Risky.","type":["string","null"]},"usage":{"description":"Empty on fast prompts. Documents include document_model usage even on fast. Embedder cost is recorded in the usage ledger.","items":{"$ref":"#/components/schemas/Usage"},"type":"array"},"verdict":{"$ref":"#/components/schemas/Verdict"},"violation":{"description":"True for violation, false for benign, null for unknown.","type":["boolean","null"]}},"required":["request_uuid","status","scan_type","stages","verdict","violation","technique","taxonomy","findings","recommendation","confidence","confidence_basis","signals","coverage","config_version","revisions","created_at","completed_at","expires_at","latency_ms","usage"],"type":"object"},"ScanType":{"enum":["fast","complete"],"type":"string"},"Scopes":{"default":["scan:write","result:read","result:delete","usage:read"],"items":{"enum":["scan:write","result:read","result:delete","usage:read"],"type":"string"},"type":"array","uniqueItems":true},"Signals":{"properties":{"adverse_share":{"maximum":1,"minimum":0,"type":["number","null"]},"document_model":{"properties":{"partial":{"type":"boolean"},"verdict":{"$ref":"#/components/schemas/Verdict"}},"type":"object"},"knn":{"description":"Supporting kNN evidence; never promoted to a completed complete verdict after T2 failure.","properties":{"confidence":{"$ref":"#/components/schemas/Confidence"},"verdict":{"$ref":"#/components/schemas/Verdict"}},"type":"object"},"margin":{"maximum":1,"minimum":0,"type":["number","null"]},"max_similarity":{"maximum":1,"minimum":-1,"type":["number","null"]},"neighbor_count":{"minimum":0,"type":"integer"},"path":{"type":"string"},"support":{"maximum":1,"minimum":0,"type":["number","null"]}},"type":"object"},"Stages":{"description":"Outcomes of embedding, reference matching, T2 classification, and document extraction. Inspect these alongside status and coverage; skipped and bypassed stages are not successful full assessments.","properties":{"document_model":{"enum":["ok","truncated","timeout","refused","invalid_output","error","failed","skipped"],"type":"string"},"embed":{"enum":["ok","bypassed_oversize","failed","skipped"],"type":"string"},"knn":{"enum":["ok","failed","skipped"],"type":"string"},"t2":{"enum":["ok","timeout","refused","throttled","invalid_output","error","skipped"],"type":"string"}},"required":["embed","knn","t2"],"type":"object"},"UpdateMetadata":{"additionalProperties":false,"minProperties":1,"properties":{"description":{"type":"string"},"enabled":{"type":"boolean"},"name":{"minLength":1,"type":"string"}},"type":"object"},"Usage":{"properties":{"input_tokens":{"minimum":0,"type":"integer"},"model":{"description":"Configured model identifier recorded from the actual call.","type":"string"},"output_tokens":{"minimum":0,"type":"integer"},"stage":{"enum":["embed","t2","document_model"],"type":"string"}},"required":["stage","model","input_tokens","output_tokens"],"type":"object"},"UsageAggregate":{"allOf":[{"$ref":"#/components/schemas/UsageTotals"},{"properties":{"group":{"description":"UTC YYYY-MM-DD date, model identifier or stage selected by group_by.","type":"string"}},"required":["group"],"type":"object"}]},"UsageTotals":{"properties":{"calls":{"format":"int64","minimum":0,"type":"integer"},"input_tokens":{"format":"int64","minimum":0,"type":"integer"},"output_tokens":{"format":"int64","minimum":0,"type":"integer"}},"required":["input_tokens","output_tokens","calls"],"type":"object"},"Verdict":{"enum":["benign","violation","unknown"],"type":"string"}},"securitySchemes":{"adminBearer":{"description":"Separate operator credential loaded from Secrets Manager using SCAN_ADMIN_SECRET_ARN at startup. Missing or unreadable secret returns 503 management_disabled. Active scan credentials receive 403. Rotation requires restarting every replica. Cannot substitute for a scan key.","scheme":"bearer","type":"http"},"scanKey":{"bearerFormat":"zaun_scan_<64 hex>","description":"Project-bound key. PostgreSQL is authoritative on every authorization check.","scheme":"bearer","type":"http"}}},"info":{"description":"Assess prompts and documents synchronously, then use the verdict, findings,\ncoverage, and stages to decide what your application does next. Fast scans\ncompare text with curated reference examples. Complete scans always add a\ncontextual classifier. Confidence describes support for the reported verdict\nand is not a calibrated probability; unknown means evidence is insufficient.\n\nResults and usage belong to your key's project. Recommendations are advisory:\neven block is a successful HTTP 200 assessment, and your application enforces\nthe decision. Prompt and document scans, result read/delete, and usage queries\nare implemented with PostgreSQL authentication and atomic usage persistence.\nToken-bucket admission and trusted client IP recording are implemented. The\nreference corpus belongs to your organization; scan content cannot select\neither scope. Complete prompt and document scans use configured Bedrock models.\nOperator management is implemented with independent adminBearer authentication.\nBatch and proxy remain reserved 501 operations in this build.\n","license":{"identifier":"MIT","name":"MIT"},"title":"Zaun scan API","version":"0.1.0"},"openapi":"3.1.0","paths":{"/healthz":{"get":{"description":"Reports process liveness without authentication. A successful response means the API\nprocess is running; it does not establish that your organization is ready to scan. No\ntenant, credential, or dependency details are returned.\n","operationId":"health","responses":{"200":{"content":{"application/json":{"example":{"status":"ok"},"schema":{"properties":{"status":{"const":"ok","type":"string"}},"required":["status"],"type":"object"}}},"description":"The process is alive."},"default":{"$ref":"#/components/responses/Error"}},"security":[],"summary":"Process liveness","tags":["Service"]}},"/v1/admin/organizations":{"get":{"description":"Lists organization metadata and enabled state so operators can\nselect an immutable organization ID for setup or maintenance. Customer scan keys do not\ngrant organization-listing privileges.\n","operationId":"listOrganizations","responses":{"200":{"content":{"application/json":{"example":[],"schema":{"items":{"$ref":"#/components/schemas/Organization"},"type":"array"}}},"description":"Organizations and enabled state."},"503":{"$ref":"#/components/responses/Error"},"default":{"$ref":"#/components/responses/Error"}},"security":[{"adminBearer":[]}],"summary":"List organizations","tags":["Administration"]},"post":{"description":"Creates an organization from a name and optional description and\nreturns its immutable ID. The operator must seed and verify the organization before\nscanning; until ready, its scans return 503 reference_not_ready. Customer scan keys\ncannot perform this operation.\n","operationId":"createOrganization","requestBody":{"content":{"application/json":{"example":{"description":"Development organization","name":"Example customer"},"schema":{"$ref":"#/components/schemas/CreateMetadata"}}},"required":true},"responses":{"201":{"$ref":"#/components/responses/Organization"},"503":{"$ref":"#/components/responses/Error"},"default":{"$ref":"#/components/responses/Error"}},"security":[{"adminBearer":[]}],"summary":"Create an organization","tags":["Administration"]}},"/v1/admin/organizations/{org_id}":{"get":{"description":"Reads an organization's metadata and enabled state by immutable ID.\nRenaming an organization does not change its identity or the scope of its projects and\nkeys. Use the separate operator credential, not a customer scan key.\n","operationId":"getOrganization","responses":{"200":{"$ref":"#/components/responses/Organization"},"503":{"$ref":"#/components/responses/Error"},"default":{"$ref":"#/components/responses/Error"}},"security":[{"adminBearer":[]}],"summary":"Read organization metadata","tags":["Administration"]},"parameters":[{"$ref":"#/components/parameters/OrgId"}],"patch":{"description":"Updates an organization's name, description, or enabled state\nwithout changing its immutable ID. Disabling it rejects new scans and key issuance while\notherwise active scoped keys retain read/delete access to saved results until expiry.\nOnly the separate operator credential can make this change.\n","operationId":"updateOrganization","requestBody":{"content":{"application/json":{"example":{"enabled":false},"schema":{"$ref":"#/components/schemas/UpdateMetadata"}}},"required":true},"responses":{"200":{"$ref":"#/components/responses/Organization"},"503":{"$ref":"#/components/responses/Error"},"default":{"$ref":"#/components/responses/Error"}},"security":[{"adminBearer":[]}],"summary":"Update organization metadata or enabled state","tags":["Administration"]}},"/v1/admin/organizations/{org_id}/projects":{"get":{"description":"Lists projects belonging to the selected organization so operators\ncan choose an immutable project ID for policy or key management. Customer scan keys\nremain bound to their own project and cannot enumerate this management collection.\n","operationId":"listProjects","responses":{"200":{"content":{"application/json":{"example":[],"schema":{"items":{"$ref":"#/components/schemas/Project"},"type":"array"}}},"description":"Projects in the selected organization."},"503":{"$ref":"#/components/responses/Error"},"default":{"$ref":"#/components/responses/Error"}},"security":[{"adminBearer":[]}],"summary":"List projects in an organization","tags":["Administration"]},"parameters":[{"$ref":"#/components/parameters/OrgId"}],"post":{"description":"Creates a project under the selected organization with an initial\npolicy version. Its keys, results, usage, and idempotent retries are project-scoped;\nprojects share the organization's curated reference set without sharing customer\nresults. Config object fields recursively merge over SCAN_POLICY_JSON defaults;\narrays replace defaults. Only the operator credential can create projects.\n","operationId":"createProject","requestBody":{"content":{"application/json":{"example":{"description":"Uses configured initial policy defaults","name":"Example app"},"schema":{"$ref":"#/components/schemas/CreateProject"}}},"required":true},"responses":{"201":{"$ref":"#/components/responses/Project"},"503":{"$ref":"#/components/responses/Error"},"default":{"$ref":"#/components/responses/Error"}},"security":[{"adminBearer":[]}],"summary":"Create a project and its initial policy version","tags":["Administration"]}},"/v1/admin/projects/{id}":{"get":{"description":"Reads project metadata, organization ownership, enabled state, and\nactive configuration version. Use the immutable project ID and the separate operator\ncredential; customer requests cannot override their project through request content.\n","operationId":"getProject","responses":{"200":{"$ref":"#/components/responses/Project"},"503":{"$ref":"#/components/responses/Error"},"default":{"$ref":"#/components/responses/Error"}},"security":[{"adminBearer":[]}],"summary":"Read project metadata and active configuration version","tags":["Administration"]},"parameters":[{"$ref":"#/components/parameters/ProjectId"}],"patch":{"description":"Updates a project's name, description, or enabled state while\npreserving its identity and organization ownership. Disabling a project rejects new\nscans and key issuance but preserves retained-result read/delete access for otherwise\nactive scoped keys. Project transfers are not supported.\n","operationId":"updateProject","requestBody":{"content":{"application/json":{"example":{"name":"Renamed app"},"schema":{"$ref":"#/components/schemas/UpdateMetadata"}}},"required":true},"responses":{"200":{"$ref":"#/components/responses/Project"},"503":{"$ref":"#/components/responses/Error"},"default":{"$ref":"#/components/responses/Error"}},"security":[{"adminBearer":[]}],"summary":"Update project metadata or enabled state","tags":["Administration"]}},"/v1/admin/projects/{id}/config":{"get":{"description":"Reads the published project policy and version, including\napplication context, rules, and limits. Operators read this version before publishing an\nupdate with If-Match. Each scan uses the configuration version selected at admission,\nrecorded in its result.\n","operationId":"getProjectConfig","responses":{"200":{"$ref":"#/components/responses/ProjectConfig"},"503":{"$ref":"#/components/responses/Error"},"default":{"$ref":"#/components/responses/Error"}},"security":[{"adminBearer":[]}],"summary":"Read published configuration","tags":["Administration"]},"parameters":[{"$ref":"#/components/parameters/ProjectId"}],"put":{"description":"Validates and publishes a new immutable policy version using a quoted numeric\nIf-Match with the current version. Missing or malformed headers return 422\ninvalid_request; a stale version returns 412 precondition_failed. PUT replaces\nthe complete policy.\nSubsequent requests use the newly published policy, while admitted work keeps its pinned\nversion. Rules use known labels and confidence thresholds from zero through one;\napplication context is limited to 4,000 characters.\n","operationId":"publishProjectConfig","parameters":[{"example":"\"1\"","in":"header","name":"If-Match","required":true,"schema":{"type":"string"}}],"requestBody":{"content":{"application/json":{"example":{"context_prompt":"","result_ttl_days":30,"retain_input_days":0,"rules":[],"taxonomy":"mitre_atlas_tactic"},"schema":{"$ref":"#/components/schemas/Policy"}}},"required":true},"responses":{"200":{"$ref":"#/components/responses/ProjectConfig"},"503":{"$ref":"#/components/responses/Error"},"default":{"$ref":"#/components/responses/Error"}},"security":[{"adminBearer":[]}],"summary":"Publish a new immutable configuration version","tags":["Administration"]}},"/v1/admin/projects/{id}/keys":{"get":{"description":"Lists key IDs, display prefixes, scopes, expiry, and revocation\nmetadata for the selected project, including revoked keys. Responses never include\nplaintext secrets or hashes. Use immutable IDs, not display prefixes, to identify keys\nfor rotation or revocation.\n","operationId":"listKeys","responses":{"200":{"content":{"application/json":{"example":[],"schema":{"items":{"$ref":"#/components/schemas/KeyMetadata"},"type":"array"}}},"description":"Project key metadata, including revoked keys."},"503":{"$ref":"#/components/responses/Error"},"default":{"$ref":"#/components/responses/Error"}},"security":[{"adminBearer":[]}],"summary":"List key metadata and status","tags":["Administration"]},"parameters":[{"$ref":"#/components/parameters/ProjectId"}],"post":{"description":"Requires an Idempotency-Key and issues a project-bound secret once\nwith Cache-Control: no-store, storing only its SHA-256 hash and lifecycle metadata. A same-body\nretry after commit returns 409 key_already_created with key metadata, never the secret\nagain; a changed-body retry returns 409 idempotency_conflict. If the secret response was\nlost, revoke that key ID and create a replacement with a new idempotency key. Customer\nscan keys cannot issue keys. Disabled organizations or projects reject new issuance\nwith 409 disabled. Claims last for the lifetime of the issued key, including after\nrevocation or expiry.\n","operationId":"createKey","parameters":[{"$ref":"#/components/parameters/IdempotencyKey"}],"requestBody":{"content":{"application/json":{"example":{"name":"Development reader","scopes":["result:read","usage:read"]},"schema":{"additionalProperties":false,"properties":{"expires_at":{"format":"date-time","type":["string","null"]},"name":{"minLength":1,"type":"string"},"scopes":{"$ref":"#/components/schemas/Scopes"}},"required":["name"],"type":"object"}}},"required":true},"responses":{"201":{"content":{"application/json":{"schema":{"allOf":[{"$ref":"#/components/schemas/KeyMetadata"},{"properties":{"secret":{"description":"Never logged or included in subsequent responses.","pattern":"^zaun_scan_[0-9a-f]{64}$","type":"string"}},"required":["secret"],"type":"object"}]}}},"description":"Plaintext appears once; Cache-Control is no-store.","headers":{"Cache-Control":{"schema":{"const":"no-store","type":"string"}}}},"503":{"$ref":"#/components/responses/Error"},"default":{"$ref":"#/components/responses/Error"}},"security":[{"adminBearer":[]}],"summary":"Issue a project key with one-time secret delivery","tags":["Administration"]}},"/v1/admin/projects/{id}/keys/{key_id}":{"delete":{"description":"Revokes a key by immutable ID within its project; repeated\nrevocation returns 204 and a missing or other-project ID returns 404. Committed\nrevocation rejects later authorization checks on every replica, while already admitted\nwork can finish. Key metadata, project results, and usage history remain available to\nappropriately scoped replacement keys.\n","operationId":"revokeKey","responses":{"204":{"description":"Revoked; metadata and usage history remain."},"503":{"$ref":"#/components/responses/Error"},"default":{"$ref":"#/components/responses/Error"}},"security":[{"adminBearer":[]}],"summary":"Revoke a key by immutable ID","tags":["Administration"]},"parameters":[{"$ref":"#/components/parameters/ProjectId"},{"example":"00000000-0000-4000-8000-000000000003","in":"path","name":"key_id","required":true,"schema":{"format":"uuid","type":"string"}}]},"/v1/batch/scan-prompts":{"post":{"description":"Reserved in this build and currently returns 501 operation_not_implemented. The batch\ncontract accepts up to 100 fast or 25 complete items with unique item_id values and one\nshared configuration version. It preserves input order and returns individual results or\nerrors, including deadline failures, inside an HTTP 200 batch response when execution is\navailable. Items consume their class rate budgets; batches have a separate four-slot\nconcurrency budget and a 60-second deadline. Requires scan:write and an Idempotency-Key.\n","operationId":"batchScanPrompts","parameters":[{"$ref":"#/components/parameters/IdempotencyKey"}],"requestBody":{"content":{"application/json":{"example":{"items":[{"item_id":"example-1","messages":[{"content":"Explain least privilege.","role":"user"}]}],"scan_type":"fast"},"schema":{"$ref":"#/components/schemas/BatchInput"}}},"required":true},"responses":{"200":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/BatchResult"}}},"description":"Ordered per-item results, including errors."},"501":{"$ref":"#/components/responses/NotImplemented"},"default":{"$ref":"#/components/responses/Error"}},"summary":"Assess an ordered batch","tags":["Scans"]}},"/v1/docs":{"get":{"description":"Opens the browsable API reference without authentication. The reference loads its\nspecification from /v1/openapi.json on the same origin and uses a bundled renderer\nwithout a CDN. Operation descriptions identify reserved operations that are unavailable\nin this build.\n","operationId":"docs","responses":{"200":{"content":{"text/html":{"example":"<!doctype html><html lang=\"en\"><title>Zaun scan API</title></html>","schema":{"type":"string"}}},"description":"Vendored Redoc HTML, loading only the same-origin specification."},"default":{"$ref":"#/components/responses/Error"}},"security":[],"summary":"Browse the API reference","tags":["Service"]}},"/v1/openapi.json":{"get":{"description":"Downloads the OpenAPI 3.1 contract as JSON without authentication. Use it to inspect\nrequest shapes, result fields, examples, and error envelopes for this API build. The\nsame contract powers the browsable API reference at /v1/docs.\n","operationId":"openapi","responses":{"200":{"content":{"application/json":{"example":{"info":{"title":"Zaun scan API","version":"0.1.0"},"openapi":"3.1.0","paths":{}},"schema":{"additionalProperties":true,"type":"object"}}},"description":"Checked-in YAML converted to JSON at compile time."},"default":{"$ref":"#/components/responses/Error"}},"security":[],"summary":"Download the OpenAPI contract","tags":["Service"]}},"/v1/result/{uuid}":{"delete":{"description":"Deletes a retained assessment within the key's project and requires result:delete. A\nrepeated deletion in that project returns 204, while an absent or other-project UUID\nreturns 404. Deletion clears result content and the replay link while a retry-window\ntombstone prevents recreation by late work. Historical usage and audit records remain,\nand an already running provider request cannot be undone.\n","operationId":"deleteResult","responses":{"204":{"description":"Deleted, or already deleted in this project."},"default":{"$ref":"#/components/responses/Error"}},"summary":"Delete a project result","tags":["Results"]},"get":{"description":"Reads a saved assessment within the key's project and requires result:read. Any active\nsame-project key with this scope can read the result, including after the original key\nis rotated. A missing, deleted, or other-project UUID returns 404; an expired result\nreturns 410. Read status, verdict, coverage, and stages together to distinguish\ncompleted assessment from incomplete evidence.\n","operationId":"getResult","responses":{"200":{"$ref":"#/components/responses/Result"},"default":{"$ref":"#/components/responses/Error"}},"summary":"Read a retained project result","tags":["Results"]},"parameters":[{"example":"00000000-0000-4000-8000-000000000001","in":"path","name":"uuid","required":true,"schema":{"format":"uuid","type":"string"}}]},"/v1/run/prompt":{"post":{"description":"Reserved for a future prompt proxy and returns 501 operation_not_implemented after\nauthentication and admission. It does not forward prompts, run tools, or produce model\noutput. Use /v1/scan/prompt to assess a conversation; a scan recommendation is advisory\nand your application enforces it.\n","operationId":"runPrompt","requestBody":{"content":{"application/json":{"example":{"messages":[{"content":"Explain least privilege.","role":"user"}],"scan_type":"complete"},"schema":{"$ref":"#/components/schemas/PromptInput"}}},"required":true},"responses":{"501":{"$ref":"#/components/responses/NotImplemented"},"default":{"$ref":"#/components/responses/Error"}},"summary":"Reserved prompt proxy","tags":["Scans"]}},"/v1/scan/document":{"post":{"description":"Uploads one document for synchronous extraction and assessment, requiring scan:write.\nThe Idempotency-Key header is required; omitting it returns the generic 422\ninvalid_request error. Reuse the key with the same body for retries. A freshly\ncreated organization returns 503 reference_not_ready on scan routes until an\noperator has seeded it and verified reference readiness.\nSend at most 4,718,592 file bytes (4.5 MiB) within a 5 MiB multipart\nbody; accepted formats are pdf, csv, doc, docx, xls, xlsx, html, txt, and md, identified\nfrom the bytes. Even fast document scans send bytes to the Bedrock document model.\nExtracted text is assessed in 2,048-token chunks with 256-token overlap; complete adds\nT2 on up to five selected chunks. The extraction call also supplies document-level\nevidence. The deadline is 90 seconds and extraction output is capped at 16,000 tokens.\nCoverage and page counts are model-reported; truncated extraction or failed chunks yield\nan inconclusive result and cannot establish benign. Inspect coverage, stages, and\nper_chunk in the saved result.\n","operationId":"scanDocument","parameters":[{"$ref":"#/components/parameters/IdempotencyKey"}],"requestBody":{"content":{"multipart/form-data":{"example":{"file":"Explain least privilege.","scan_type":"complete"},"schema":{"additionalProperties":false,"properties":{"file":{"description":"Raw file bytes, never a URL.","format":"binary","type":"string"},"metadata":{"$ref":"#/components/schemas/Metadata"},"scan_type":{"default":"complete","enum":["fast","complete"],"type":"string"},"session_uuid":{"format":"uuid","type":"string"}},"required":["file"],"type":"object"}}},"required":true},"responses":{"200":{"$ref":"#/components/responses/Result"},"default":{"$ref":"#/components/responses/Error"}},"summary":"Assess a document","tags":["Scans"]}},"/v1/scan/prompt":{"post":{"description":"Assesses the supplied conversation synchronously and persists the result before\nreturning HTTP 200. Fast compares the selected messages with curated reference examples;\ncomplete always adds a second-stage classifier (T2), whose valid label decides the\nverdict. A failed T2 assessment returns an inconclusive unknown result with its reason\nin stages, retaining fast evidence in signals.knn. Send scan_type explicitly; target\ndefaults to all and session_uuid adds correlation without saved history. Limits are 64\nmessages, 32,768 characters each, a 1 MiB body, and deadlines of 5 seconds fast or 45\nseconds complete. Messages over the embedding window or the 2,000-character head/tail\nelision boundary bypass embedding; complete can still assess the full selected content.\nBoth modes reject full input over 32,000 tokens, including project context, before paid\ncalls. Requires scan:write. The Idempotency-Key header is required; omitting it\nreturns the generic 422 invalid_request error. Reuse the key with the same body for\nretries. A freshly created organization returns 503 reference_not_ready on scan\nroutes until an operator has seeded it and verified reference readiness.\n","operationId":"scanPrompt","parameters":[{"$ref":"#/components/parameters/IdempotencyKey"}],"requestBody":{"content":{"application/json":{"examples":{"complete":{"value":{"messages":[{"content":"Explain least privilege.","role":"user"}],"scan_type":"complete","target":"all"}},"fast":{"value":{"messages":[{"content":"Explain least privilege.","role":"user"}],"scan_type":"fast","target":"all"}}},"schema":{"$ref":"#/components/schemas/PromptInput"}}},"required":true},"responses":{"200":{"$ref":"#/components/responses/Result"},"default":{"$ref":"#/components/responses/Error"}},"summary":"Assess a conversation","tags":["Scans"]}},"/v1/usage":{"get":{"description":"Aggregates the authenticated project's usage and requires usage:read. Supply an RFC 3339\ninterval from inclusive to to exclusive, no longer than 90 days; defaults are to=now,\nfrom=to minus seven days, and group_by=day in UTC. You can also group by model or stage\nand filter by a same-project key_id. Missing or foreign-project key IDs return 404;\ninvalid dates, unknown parameters, and empty, reversed, or oversized intervals return\n422. Rotation and result deletion preserve historical usage; a valid interval with no\nusage returns an empty array and zero totals.\n","operationId":"getUsage","parameters":[{"example":"2026-09-01T00:00:00Z","in":"query","name":"from","schema":{"format":"date-time","type":"string"}},{"example":"2026-09-16T00:00:00Z","in":"query","name":"to","schema":{"format":"date-time","type":"string"}},{"in":"query","name":"group_by","schema":{"default":"day","enum":["day","model","stage"],"type":"string"}},{"in":"query","name":"key_id","schema":{"format":"uuid","type":"string"}}],"responses":{"200":{"content":{"application/json":{"example":{"from":"2026-09-09T00:00:00Z","group_by":"day","to":"2026-09-16T00:00:00Z","totals":{"calls":0,"input_tokens":0,"output_tokens":0},"usage":[]},"schema":{"properties":{"from":{"format":"date-time","type":"string"},"group_by":{"enum":["day","model","stage"],"type":"string"},"to":{"format":"date-time","type":"string"},"totals":{"$ref":"#/components/schemas/UsageTotals"},"usage":{"items":{"$ref":"#/components/schemas/UsageAggregate"},"type":"array"}},"required":["from","to","group_by","usage","totals"],"type":"object"}}},"description":"Aggregated embed and model calls in the requested interval."},"default":{"$ref":"#/components/responses/Error"}},"summary":"Aggregate project usage","tags":["Results"]}}},"security":[{"scanKey":[]}],"servers":[{"description":"Current API origin","url":"/"}],"tags":[{"description":"Fast and complete prompt assessments and multipart document scans; batch is reserved.","name":"Scans"},{"description":"Project-scoped retained results and usage aggregates.","name":"Results"},{"description":"Organizations, projects, immutable policy versions and one-time keys, protected by a separate operator credential.","name":"Administration"},{"description":"Public liveness and reference documentation.","name":"Service"}]}