{"openapi":"3.1.0","info":{"title":"PromptHarbor API","version":"0.1.0","description":"Approved-AI workspace with deterministic pre-submission controls. Synthetic demo data only."},"paths":{"/api/v1/health":{"get":{"summary":"Liveness probe","tags":["ops"],"description":"Allowed: anyone (no auth).","responses":{"200":{"description":"OK"},"4XX":{"description":"Error object: {error: {code, message, correlation_id}}"}}}},"/api/v1/ready":{"get":{"summary":"Readiness: database, policy and detector self-test","tags":["ops"],"description":"Allowed: anyone (no auth).","responses":{"200":{"description":"OK"},"4XX":{"description":"Error object: {error: {code, message, correlation_id}}"}}}},"/api/v1/openapi.json":{"get":{"summary":"This API description (generated from the route table)","tags":["ops"],"description":"Allowed: anyone (no auth).","responses":{"200":{"description":"OK"},"4XX":{"description":"Error object: {error: {code, message, correlation_id}}"}}}},"/metrics":{"get":{"summary":"Prometheus metrics (requires PH_METRICS_TOKEN)","tags":["ops"],"description":"Allowed: anyone (no auth).","responses":{"200":{"description":"OK"},"4XX":{"description":"Error object: {error: {code, message, correlation_id}}"}}}},"/api/v1/demo/session":{"post":{"summary":"Start an isolated synthetic sandbox; returns an Employee session","tags":["demo"],"description":"Allowed: anyone (no auth).","responses":{"200":{"description":"OK"},"4XX":{"description":"Error object: {error: {code, message, correlation_id}}"}}},"delete":{"summary":"End the sandbox and delete all of its data","tags":["demo"],"description":"Allowed: any authenticated user.","responses":{"200":{"description":"OK"},"4XX":{"description":"Error object: {error: {code, message, correlation_id}}"}},"security":[{"bearer":[]}]}},"/api/v1/demo/session/persona":{"post":{"summary":"Switch to another persona in the same sandbox","tags":["demo"],"description":"Allowed: any authenticated user.","responses":{"200":{"description":"OK"},"4XX":{"description":"Error object: {error: {code, message, correlation_id}}"}},"security":[{"bearer":[]}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/PersonaRequest"}}}}}},"/api/v1/me":{"get":{"summary":"Current user, tenant and available personas","tags":["workspace"],"description":"Allowed: any authenticated user.","responses":{"200":{"description":"OK"},"4XX":{"description":"Error object: {error: {code, message, correlation_id}}"}},"security":[{"bearer":[]}]}},"/api/v1/demo/scenarios":{"get":{"summary":"Frozen synthetic scenarios A–H with expected outcomes","tags":["demo"],"description":"Allowed: anyone (no auth).","responses":{"200":{"description":"OK"},"4XX":{"description":"Error object: {error: {code, message, correlation_id}}"}}}},"/api/v1/demo/scenarios/{slug}/run":{"post":{"summary":"Run one frozen scenario end-to-end in your sandbox","tags":["demo"],"description":"Allowed: any authenticated user. Requires an `Idempotency-Key` header.","responses":{"200":{"description":"OK"},"4XX":{"description":"Error object: {error: {code, message, correlation_id}}"}},"security":[{"bearer":[]}],"parameters":[{"name":"slug","in":"path","required":true,"schema":{"type":"string"}},{"name":"Idempotency-Key","in":"header","required":true,"schema":{"type":"string","pattern":"^[A-Za-z0-9_-]{8,128}$"}}]}},"/api/v1/demo/reset":{"post":{"summary":"Wipe this sandbox back to its initial synthetic state (naturally idempotent)","tags":["demo"],"description":"Allowed: any authenticated user.","responses":{"200":{"description":"OK"},"4XX":{"description":"Error object: {error: {code, message, correlation_id}}"}},"security":[{"bearer":[]}]}},"/api/v1/demo/provider-inbox":{"get":{"summary":"What the mock provider actually received","tags":["demo"],"description":"Allowed: any authenticated user.","responses":{"200":{"description":"OK"},"4XX":{"description":"Error object: {error: {code, message, correlation_id}}"}},"security":[{"bearer":[]}]}},"/api/v1/submissions/scan":{"post":{"summary":"Scan a prompt and get the policy decision (nothing is sent)","tags":["workspace"],"description":"Allowed: employee, approver. Requires an `Idempotency-Key` header.","responses":{"200":{"description":"OK"},"4XX":{"description":"Error object: {error: {code, message, correlation_id}}"}},"security":[{"bearer":[]}],"parameters":[{"name":"Idempotency-Key","in":"header","required":true,"schema":{"type":"string","pattern":"^[A-Za-z0-9_-]{8,128}$"}}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ScanRequest"}}}}}},"/api/v1/submissions":{"get":{"summary":"List submissions (scope=mine|tenant)","tags":["workspace"],"description":"Allowed: any authenticated user.","responses":{"200":{"description":"OK"},"4XX":{"description":"Error object: {error: {code, message, correlation_id}}"}},"security":[{"bearer":[]}]}},"/api/v1/submissions/{id}":{"get":{"summary":"Get one submission (preview only for submitter/approver)","tags":["workspace"],"description":"Allowed: any authenticated user.","responses":{"200":{"description":"OK"},"4XX":{"description":"Error object: {error: {code, message, correlation_id}}"}},"security":[{"bearer":[]}],"parameters":[{"name":"id","in":"path","required":true,"schema":{"type":"string"}}]}},"/api/v1/submissions/{id}/receipt":{"get":{"summary":"Evidence receipt: policy version, rules, finding types, digests, audit hashes","tags":["workspace"],"description":"Allowed: any authenticated user.","responses":{"200":{"description":"OK"},"4XX":{"description":"Error object: {error: {code, message, correlation_id}}"}},"security":[{"bearer":[]}],"parameters":[{"name":"id","in":"path","required":true,"schema":{"type":"string"}}]}},"/api/v1/submissions/{id}/confirm":{"post":{"summary":"Explicitly confirm and send the redacted preview to the mock provider","tags":["workspace"],"description":"Allowed: the submitter. Requires an `Idempotency-Key` header.","responses":{"200":{"description":"OK"},"4XX":{"description":"Error object: {error: {code, message, correlation_id}}"}},"security":[{"bearer":[]}],"parameters":[{"name":"id","in":"path","required":true,"schema":{"type":"string"}},{"name":"Idempotency-Key","in":"header","required":true,"schema":{"type":"string","pattern":"^[A-Za-z0-9_-]{8,128}$"}}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ConfirmRequest"}}}}}},"/api/v1/submissions/{id}/request-review":{"post":{"summary":"Ask an approver for an exception to an overridable block","tags":["workspace"],"description":"Allowed: the submitter. Requires an `Idempotency-Key` header.","responses":{"200":{"description":"OK"},"4XX":{"description":"Error object: {error: {code, message, correlation_id}}"}},"security":[{"bearer":[]}],"parameters":[{"name":"id","in":"path","required":true,"schema":{"type":"string"}},{"name":"Idempotency-Key","in":"header","required":true,"schema":{"type":"string","pattern":"^[A-Za-z0-9_-]{8,128}$"}}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ReasonRequest"}}}}}},"/api/v1/submissions/{id}/feedback":{"post":{"summary":"Report a finding as a false positive (does not change the decision)","tags":["workspace"],"description":"Allowed: the submitter. Requires an `Idempotency-Key` header.","responses":{"200":{"description":"OK"},"4XX":{"description":"Error object: {error: {code, message, correlation_id}}"}},"security":[{"bearer":[]}],"parameters":[{"name":"id","in":"path","required":true,"schema":{"type":"string"}},{"name":"Idempotency-Key","in":"header","required":true,"schema":{"type":"string","pattern":"^[A-Za-z0-9_-]{8,128}$"}}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/FeedbackRequest"}}}}}},"/api/v1/reviews":{"get":{"summary":"Review queue (status=PENDING|APPROVED|REJECTED|EXPIRED|ALL)","tags":["workspace"],"description":"Allowed: approver.","responses":{"200":{"description":"OK"},"4XX":{"description":"Error object: {error: {code, message, correlation_id}}"}},"security":[{"bearer":[]}]}},"/api/v1/reviews/{id}/approve":{"post":{"summary":"Approve a pending review","tags":["workspace"],"description":"Allowed: approver (not the submitter). Requires an `Idempotency-Key` header.","responses":{"200":{"description":"OK"},"4XX":{"description":"Error object: {error: {code, message, correlation_id}}"}},"security":[{"bearer":[]}],"parameters":[{"name":"id","in":"path","required":true,"schema":{"type":"string"}},{"name":"Idempotency-Key","in":"header","required":true,"schema":{"type":"string","pattern":"^[A-Za-z0-9_-]{8,128}$"}}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ReasonRequest"}}}}}},"/api/v1/reviews/{id}/reject":{"post":{"summary":"Reject a pending review","tags":["workspace"],"description":"Allowed: approver (not the submitter). Requires an `Idempotency-Key` header.","responses":{"200":{"description":"OK"},"4XX":{"description":"Error object: {error: {code, message, correlation_id}}"}},"security":[{"bearer":[]}],"parameters":[{"name":"id","in":"path","required":true,"schema":{"type":"string"}},{"name":"Idempotency-Key","in":"header","required":true,"schema":{"type":"string","pattern":"^[A-Za-z0-9_-]{8,128}$"}}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ReasonRequest"}}}}}},"/api/v1/policies/current":{"get":{"summary":"Current published policy (YAML, rules, providers, tasks)","tags":["policy"],"description":"Allowed: any authenticated user.","responses":{"200":{"description":"OK"},"4XX":{"description":"Error object: {error: {code, message, correlation_id}}"}},"security":[{"bearer":[]}]}},"/api/v1/policies/history":{"get":{"summary":"Policy version history","tags":["policy"],"description":"Allowed: policy admin, auditor, tenant owner.","responses":{"200":{"description":"OK"},"4XX":{"description":"Error object: {error: {code, message, correlation_id}}"}},"security":[{"bearer":[]}]}},"/api/v1/policies":{"post":{"summary":"Publish a new policy version (validated, versioned, simulated against scenarios)","tags":["policy"],"description":"Allowed: policy admin. Requires an `Idempotency-Key` header.","responses":{"200":{"description":"OK"},"4XX":{"description":"Error object: {error: {code, message, correlation_id}}"}},"security":[{"bearer":[]}],"parameters":[{"name":"Idempotency-Key","in":"header","required":true,"schema":{"type":"string","pattern":"^[A-Za-z0-9_-]{8,128}$"}}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/PolicyPublishRequest"}}}}}},"/api/v1/providers":{"get":{"summary":"Provider registry from the current policy","tags":["policy"],"description":"Allowed: any authenticated user.","responses":{"200":{"description":"OK"},"4XX":{"description":"Error object: {error: {code, message, correlation_id}}"}},"security":[{"bearer":[]}]}},"/api/v1/tenant/explainer":{"post":{"summary":"Turn the optional (mock) AI explainer on or off for this tenant","tags":["policy"],"description":"Allowed: tenant owner. Requires an `Idempotency-Key` header.","responses":{"200":{"description":"OK"},"4XX":{"description":"Error object: {error: {code, message, correlation_id}}"}},"security":[{"bearer":[]}],"parameters":[{"name":"Idempotency-Key","in":"header","required":true,"schema":{"type":"string","pattern":"^[A-Za-z0-9_-]{8,128}$"}}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ExplainerToggle"}}}}}},"/api/v1/audit/events":{"get":{"summary":"Hash-chained audit events (no prompt content)","tags":["oversight"],"description":"Allowed: auditor, security analyst, tenant owner.","responses":{"200":{"description":"OK"},"4XX":{"description":"Error object: {error: {code, message, correlation_id}}"}},"security":[{"bearer":[]}]}},"/api/v1/audit/verify":{"get":{"summary":"Re-walk and verify the tenant's audit hash chain","tags":["oversight"],"description":"Allowed: auditor, tenant owner.","responses":{"200":{"description":"OK"},"4XX":{"description":"Error object: {error: {code, message, correlation_id}}"}},"security":[{"bearer":[]}]}},"/api/v1/metrics/summary":{"get":{"summary":"Tenant workflow metrics (synthetic)","tags":["oversight"],"description":"Allowed: security analyst, policy admin, tenant owner.","responses":{"200":{"description":"OK"},"4XX":{"description":"Error object: {error: {code, message, correlation_id}}"}},"security":[{"bearer":[]}]}}},"components":{"schemas":{"PersonaRequest":{"additionalProperties":false,"properties":{"persona":{"pattern":"^[a-z0-9]{2,20}$","title":"Persona","type":"string"}},"required":["persona"],"title":"PersonaRequest","type":"object"},"ScanRequest":{"additionalProperties":false,"properties":{"prompt":{"description":"Prompt text. Scanned in memory; never stored raw.","maxLength":20000,"minLength":1,"title":"Prompt","type":"string"},"task":{"maxLength":64,"minLength":1,"title":"Task","type":"string"},"provider_id":{"maxLength":64,"minLength":1,"title":"Provider Id","type":"string"},"classification":{"enum":["public","internal","confidential","restricted"],"title":"Classification","type":"string"}},"required":["prompt","task","provider_id","classification"],"title":"ScanRequest","type":"object"},"ConfirmRequest":{"additionalProperties":false,"properties":{"confirm":{"const":true,"title":"Confirm","type":"boolean"},"preview_sha256":{"description":"SHA-256 of the exact redacted preview the user approved.","pattern":"^[0-9a-f]{64}$","title":"Preview Sha256","type":"string"}},"required":["confirm","preview_sha256"],"title":"ConfirmRequest","type":"object"},"ReasonRequest":{"additionalProperties":false,"properties":{"reason":{"maxLength":1000,"minLength":1,"title":"Reason","type":"string"}},"required":["reason"],"title":"ReasonRequest","type":"object"},"FeedbackRequest":{"additionalProperties":false,"properties":{"finding_ordinal":{"maximum":10000,"minimum":0,"title":"Finding Ordinal","type":"integer"},"kind":{"const":"false_positive","default":"false_positive","title":"Kind","type":"string"}},"required":["finding_ordinal"],"title":"FeedbackRequest","type":"object"},"PolicyPublishRequest":{"additionalProperties":false,"properties":{"yaml":{"maxLength":64000,"minLength":10,"title":"Yaml","type":"string"},"change_note":{"maxLength":500,"minLength":1,"title":"Change Note","type":"string"}},"required":["yaml","change_note"],"title":"PolicyPublishRequest","type":"object"},"ExplainerToggle":{"additionalProperties":false,"properties":{"enabled":{"title":"Enabled","type":"boolean"}},"required":["enabled"],"title":"ExplainerToggle","type":"object"}},"securitySchemes":{"bearer":{"type":"http","scheme":"bearer"}}}}