{"openapi":"3.1.0","info":{"title":"Harmwise Guardrail API","version":"1.1.0","description":"Safety instructions for your prompt (versioned, and kept up to date as usage changes), grading after the reply has been sent, ranked referrals and the sealed record. Harmwise Guardrail never blocks, edits or delays a reply. Every response carries `X-Request-Id` and the `RateLimit-*` headers; every error is an RFC 9457 problem with a page under /problems. Within v1, changes only add fields and endpoints (see /changelog)."},"servers":[{"url":"https://harmwise.digitalsafeguard.org/api"}],"security":[{"bearer":[]}],"components":{"securitySchemes":{"bearer":{"type":"http","scheme":"bearer","description":"hr_live_… (production) or hr_test_… (test) key from the console."}},"headers":{"RequestId":{"description":"Yours, if you sent a valid `X-Request-Id`; otherwise one we made. Quote it to support.","schema":{"type":"string"}},"RateLimitLimit":{"description":"Requests allowed in the current window","schema":{"type":"integer"}},"RateLimitRemaining":{"description":"Requests left in the current window","schema":{"type":"integer"}},"RateLimitReset":{"description":"Seconds until the window resets","schema":{"type":"integer"}}},"responses":{"Problem":{"description":"RFC 9457 problem details. `type` links to a page explaining the problem and what to do.","headers":{"X-Request-Id":{"$ref":"#/components/headers/RequestId"},"RateLimit-Limit":{"$ref":"#/components/headers/RateLimitLimit"},"RateLimit-Remaining":{"$ref":"#/components/headers/RateLimitRemaining"},"RateLimit-Reset":{"$ref":"#/components/headers/RateLimitReset"}},"content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"}}}}},"schemas":{"Problem":{"type":"object","properties":{"type":{"type":"string","format":"uri"},"title":{"type":"string"},"status":{"type":"integer"},"detail":{"type":"string"}},"required":["type","title","status","detail"],"unevaluatedProperties":false},"Turn":{"type":"object","properties":{"role":{"enum":["user","assistant","system"]},"content":{"type":"string","maxLength":20000}},"required":["role","content"],"unevaluatedProperties":false},"Seal":{"type":"object","properties":{"seq":{"type":"integer"},"prev":{"type":"string"},"self":{"type":"string"}},"required":["seq","prev","self"],"unevaluatedProperties":false},"Signature":{"type":"object","properties":{"alg":{"const":"Ed25519"},"kid":{"type":"string"},"value":{"type":"string","description":"base64url"}},"required":["alg","kid","value"],"unevaluatedProperties":false},"Receipt":{"oneOf":[{"type":"null"},{"description":"Ed25519 over `harmwise-receipt-v1\\n<record_id>\\n<system_id>\\n<seq>\\n<self>\\n<occurred_at>`, with a key published at /.well-known/harmwise-keys.json. Null where signing is not configured.","type":"object","properties":{"version":{"const":"harmwise-receipt-v1"},"alg":{"const":"Ed25519"},"kid":{"type":"string"},"value":{"type":"string"}},"required":["version","alg","kid","value"],"unevaluatedProperties":false}]},"Instance":{"type":"object","properties":{"id":{"type":"string","description":"`<record_id>.<index>`; dispute it at /v1/instances/{id}/dispute"},"severity":{"enum":["S0","S1","S2"]},"principles":{"type":"array","items":{"type":"string"}},"source":{"type":"string","description":"The rule that raised it"},"detail":{"type":"string"},"quote":{"type":["string","null"],"description":"Only where the organisation retains quoted spans"}},"required":["id","severity","principles","source","detail","quote"],"unevaluatedProperties":false},"ReferralRecord":{"oneOf":[{"type":"null"},{"type":"object","properties":{"tier":{"enum":["verified_local","national","emergency_only"]},"offered":{"type":"array","items":{"type":"string"},"description":"Directory ids of the services the reply offered"},"kinds":{"type":"array","items":{"type":"string"}},"likelyOpen":{"type":["boolean","null"]},"alternativeGiven":{"type":"boolean"},"ownedOffered":{"type":"boolean"},"independentAlternativeGiven":{"type":"boolean"},"hoursVerified":{"type":["string","null"]}},"required":["tier","offered","kinds","likelyOpen","alternativeGiven","ownedOffered","independentAlternativeGiven","hoursVerified"],"unevaluatedProperties":false}]},"Record":{"type":"object","description":"A sealed record. The conversation itself is never kept: only a keyed hash of it (see /v1/records/{id}/match).","properties":{"record_id":{"type":"string"},"system_id":{"type":"string"},"occurred_at":{"type":"string","format":"date-time"},"verdict":{"enum":["clean","flagged","error"],"description":"`clean` means no finding: the reply passed the safety floor, not a full review"},"outcome":{"enum":["scored","unavailable","instrument_error","not_applicable"]},"coverage":{"enum":["full","safety_only"]},"in_domain":{"type":"boolean"},"gap_cause":{"enum":["deadline","degraded","not_applied","not_enabled","platform_unavailable","post_hoc","language_unsupported","policy_mismatch",null]},"instances":{"type":"array","items":{"$ref":"#/components/schemas/Instance"}},"referral":{"$ref":"#/components/schemas/ReferralRecord"},"seal":{"$ref":"#/components/schemas/Seal"},"receipt":{"$ref":"#/components/schemas/Receipt"},"environment":{"enum":["production","test"]}},"required":["record_id","system_id","occurred_at","verdict","outcome","coverage","in_domain","gap_cause","instances","referral","seal","receipt","environment"]},"RankedService":{"type":"object","properties":{"id":{"type":"string"},"name":{"type":"string"},"kind":{"type":"string"},"contact":{"type":"string"},"url":{"type":"string"},"what":{"type":"string"},"hours":{"type":"string"},"likelyOpen":{"type":["boolean","null"]},"languageFit":{"type":"boolean"},"verification":{"type":"string","description":"`verified YYYY-MM-DD`, or `published hours, not yet verified`"},"operatedByUs":{"type":"boolean"},"score":{"type":"number","description":"Fitness only; who operates a service is never an input"}},"required":["id","name","kind","contact","url","what","hours","likelyOpen","languageFit","verification","operatedByUs","score"],"unevaluatedProperties":false},"PolicyResponse":{"type":"object","properties":{"modules":{"type":"array","items":{"type":"object","properties":{"id":{"type":"string"},"version":{"type":"string"},"hash":{"type":"string"}},"required":["id","version","hash"],"unevaluatedProperties":false}},"hash":{"type":"string","description":"Identifies this version of the block. Send it as `policy_hash` when grading"},"block":{"type":"string","description":"The current version, byte-stable within that version: cache it inside your system prompt and revalidate with the ETag to stay current"},"session_block":{"type":"string","description":"Place after your last cache checkpoint"},"referral":{"oneOf":[{"type":"null"},{"type":"object","properties":{"tier":{"enum":["verified_local","national","emergency_only"]},"emergency":{"type":"string"},"services":{"type":"array","items":{"$ref":"#/components/schemas/RankedService"}}},"required":["tier","emergency","services"],"unevaluatedProperties":false}]},"cache":{"type":"object","properties":{"max_age":{"type":"integer"},"note":{"type":"string"}},"required":["max_age","note"],"unevaluatedProperties":false}},"required":["modules","hash","block","session_block","referral","cache"],"unevaluatedProperties":false},"GradeResult":{"allOf":[{"$ref":"#/components/schemas/Record"}],"properties":{"missing":{"type":"array","items":{"enum":["emergency_guidance","referral","out_of_hours_alternative"]},"description":"What the reply should have carried and did not"},"route":{"type":"object","properties":{"modules":{"type":"array","items":{"type":"object","properties":{"id":{"type":"string"},"confidence":{"type":"number"},"signals":{"type":"array","items":{"type":"string"}}},"required":["id","confidence","signals"],"unevaluatedProperties":false}},"crisis":{"type":"boolean"},"precedence":{"type":"array","items":{"type":"string"}},"router":{"type":"string"}},"required":["modules","crisis","precedence","router"],"unevaluatedProperties":false},"signals":{"type":"object","description":"What the validators observed, for example `emergency_present`"},"error":{"type":"string","description":"Why the instrument failed, when `outcome` is `instrument_error`"},"versions":{"type":"object","properties":{"validators":{"type":["string","null"]},"policy_expected":{"type":["string","null"]},"policy_applied":{"type":["string","null"]}},"required":["validators","policy_expected","policy_applied"],"unevaluatedProperties":false},"latency_ms":{"type":"integer"},"replayed":{"const":true,"description":"Present on an Idempotency-Key replay, which returns the first request's record"}},"unevaluatedProperties":false},"JobQueued":{"type":"object","properties":{"job_id":{"type":"string"},"status":{"enum":["queued","running","done"]},"status_url":{"type":"string"},"record_id":{"type":["string","null"]},"replayed":{"type":"boolean"}},"required":["job_id","status","status_url","record_id","replayed"],"unevaluatedProperties":false},"Job":{"oneOf":[{"title":"Waiting","type":"object","properties":{"job_id":{"type":"string"},"status":{"enum":["queued","running","done"]},"attempts":{"type":"integer"},"queued_at":{"type":"string"},"next_attempt_at":{"type":["string","null"]},"last_error":{"type":["string","null"]}},"required":["job_id","status","attempts","queued_at","next_attempt_at","last_error"],"unevaluatedProperties":false},{"title":"Failed","type":"object","properties":{"job_id":{"type":"string"},"status":{"const":"failed"},"attempts":{"type":"integer"},"queued_at":{"type":"string"},"record_id":{"type":"null"},"error":{"type":"string"}},"required":["job_id","status","attempts","queued_at","record_id","error"],"unevaluatedProperties":false},{"title":"Done, record not visible to this key","type":"object","properties":{"job_id":{"type":"string"},"status":{"const":"done"},"attempts":{"type":"integer"},"queued_at":{"type":"string"},"record_id":{"type":"string"}},"required":["job_id","status","attempts","queued_at","record_id"],"unevaluatedProperties":false},{"title":"Done","allOf":[{"$ref":"#/components/schemas/Record"}],"properties":{"job_id":{"type":"string"},"status":{"const":"done"},"attempts":{"type":"integer"},"queued_at":{"type":"string"}},"required":["job_id","status","attempts","queued_at"],"unevaluatedProperties":false}]},"Verification":{"type":"object","properties":{"system_id":{"type":"string"},"ok":{"type":"boolean"},"records":{"type":"integer"},"head":{"type":["string","null"]},"broken_at":{"type":["integer","null"]},"reason":{"type":["string","null"]},"verified_from_seq":{"type":"integer"},"verified_records":{"type":"integer"},"checkpoint_verified_at":{"type":["string","null"]},"archived_through_seq":{"type":"integer","description":"The last record moved to the archive (0 if none). Records up to it are in downloadable archive files, checked offline; verification of the database starts no earlier."},"systemId":{"type":"string","deprecated":true},"brokenAt":{"type":["integer","null"],"deprecated":true}},"required":["system_id","ok","records","head","broken_at","reason","verified_from_seq","verified_records","checkpoint_verified_at","archived_through_seq","systemId","brokenAt"],"unevaluatedProperties":false},"Archive":{"type":"object","properties":{"archive_id":{"type":"string"},"system_id":{"type":"string"},"from_seq":{"type":"integer"},"to_seq":{"type":"integer"},"prev_hash":{"type":"string","description":"The hash the first archived record follows: genesis (64 zeros) or the previous run's `last_hash`"},"last_hash":{"type":"string","description":"The last archived record's own hash"},"records":{"type":"integer"},"reviews":{"type":"integer","description":"Findings decisions archived with the records"},"first_at":{"type":"string","format":"date-time"},"last_at":{"type":"string","format":"date-time"},"bytes":{"type":"integer"},"sha256":{"type":"string","description":"Of the file as downloaded (compressed)"},"created_at":{"type":"string","format":"date-time"},"delete_after":{"type":"string","format":"date-time","description":"When the file is deleted: seven years after `last_at`"},"retired_at":{"type":["string","null"],"description":"When the file was deleted; the run's hashes stay, so the chain still verifies"},"download_url":{"type":["string","null"],"description":"Works for 15 minutes; null once the file is deleted"}},"required":["archive_id","system_id","from_seq","to_seq","prev_hash","last_hash","records","reviews","first_at","last_at","bytes","sha256","created_at","delete_after","retired_at","download_url"],"unevaluatedProperties":false},"Finding":{"type":"object","properties":{"id":{"type":"string"},"record_id":{"type":"string"},"seal_seq":{"type":"integer"},"occurred_at":{"type":"string"},"call_site":{"type":"string"},"jurisdiction":{"type":"string"},"severity":{"enum":["S0","S1","S2"]},"rule":{"type":"string"},"principles":{"type":"array","items":{"type":"string"}},"detail":{"type":"string"},"quote":{"type":["string","null"]},"status":{"enum":["open","disputed","resolved","upheld"]},"owner":{"type":["string","null"]},"status_note":{"type":["string","null"]},"status_at":{"type":["string","null"]}},"required":["id","record_id","seal_seq","occurred_at","call_site","jurisdiction","severity","rule","principles","detail","quote","status","owner","status_note","status_at"],"unevaluatedProperties":false},"BoardRow":{"type":"object","properties":{"criterion":{"type":"string"},"principle":{"type":"string"},"verdict":{"enum":["pass","fail","ne","unhealthy","hard"],"description":"`ne`: not established"},"value":{"type":"string"},"n":{"type":"integer"},"note":{"type":"string"}},"required":["criterion","principle","verdict","value","n","note"],"unevaluatedProperties":false},"Module":{"type":"object","properties":{"id":{"type":"string"},"version":{"type":"string"},"kind":{"enum":["core","domain","context"]},"name":{"type":"string"},"status":{"enum":["released","candidate","draft"]},"hash":{"type":"string"},"released_at":{"type":["string","null"]},"in_force":{"type":"boolean"},"measurement":{"type":"object","properties":{"alpha":{"type":["number","null"]},"false_positive_rate":{"type":["number","null"]},"router_recall":{"type":["number","null"]},"router_precision":{"type":["number","null"]},"efficacy_delta":{"type":["number","null"]}},"required":["alpha","false_positive_rate","router_recall","router_precision","efficacy_delta"],"unevaluatedProperties":false},"release_gate":{"type":"object","properties":{"releasable":{"type":"boolean"},"missing":{"type":"array","items":{"type":"string"}}},"required":["releasable","missing"],"unevaluatedProperties":false}},"required":["id","version","kind","name","status","hash","released_at","in_force","measurement","release_gate"],"unevaluatedProperties":false},"Resource":{"type":"object","properties":{"id":{"type":"string"},"name":{"type":"string"},"kind":{"type":"string"},"kind_label":{"type":"string"},"what":{"type":"string"},"contact":{"type":"string"},"url":{"type":"string"},"regions":{"type":"array","items":{"type":"string"}},"languages":{"type":"array","items":{"type":"string"}},"interpreting":{"type":"boolean"},"self_referral":{"type":"boolean"},"hours":{"type":"string"},"likely_open":{"type":["boolean","null"]},"operated_by_us":{"type":"boolean"},"verification":{"enum":["fresh","due","unverified"]},"verified_at":{"type":["string","null"]},"source":{"type":"string"}},"required":["id","name","kind","kind_label","what","contact","url","regions","languages","interpreting","self_referral","hours","likely_open","operated_by_us","verification","verified_at","source"],"unevaluatedProperties":false}}},"paths":{"/v1/policy/block":{"get":{"summary":"The current safety instructions for your system prompt","description":"Versioned, and always up to date: new versions are released as what people say to AI, and how they use it, changes, and this endpoint always returns the version currently in force. `block` is byte-stable within a version and identified by `hash`, so cache it inside your prompt. Revalidate with `If-None-Match` at least every `cache.max_age` seconds (the SDKs do this on every call): a 304 means you already hold the current version, a 200 brings the new one. Send `hash` as `policy_hash` when grading, so the record shows which version shaped each reply; a reply built on an out-of-date version is recorded with the gap `policy_mismatch`. Place `session_block` after your last cache checkpoint. Never capped, on any plan.","parameters":[{"name":"jurisdiction","in":"query","schema":{"type":"string","example":"AU-VIC"}},{"name":"language","in":"query","schema":{"type":"string","default":"en"}},{"name":"turn","in":"query","deprecated":true,"description":"Deprecated: a query string is written to request logs along the way. POST the turn to /v1/policy/session instead.","schema":{"type":"string"}}],"responses":{"200":{"description":"The block","headers":{"X-Request-Id":{"$ref":"#/components/headers/RequestId"},"RateLimit-Limit":{"$ref":"#/components/headers/RateLimitLimit"},"RateLimit-Remaining":{"$ref":"#/components/headers/RateLimitRemaining"},"RateLimit-Reset":{"$ref":"#/components/headers/RateLimitReset"},"ETag":{"schema":{"type":"string"}}},"content":{"application/json":{"schema":{"$ref":"#/components/schemas/PolicyResponse"}}}},"304":{"description":"Not modified"},"401":{"$ref":"#/components/responses/Problem"},"429":{"$ref":"#/components/responses/Problem"}}}},"/v1/policy/session":{"post":{"summary":"The policy response, with the person's turn in the body","description":"Same response as GET /v1/policy/block. The turn is used only to choose referral kinds, and is never stored or logged.","requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","properties":{"jurisdiction":{"type":"string","example":"AU-VIC"},"language":{"type":"string","default":"en"},"turn":{"type":"string","maxLength":20000}}}}}},"responses":{"200":{"description":"The block","headers":{"X-Request-Id":{"$ref":"#/components/headers/RequestId"},"RateLimit-Limit":{"$ref":"#/components/headers/RateLimitLimit"},"RateLimit-Remaining":{"$ref":"#/components/headers/RateLimitRemaining"},"RateLimit-Reset":{"$ref":"#/components/headers/RateLimitReset"},"ETag":{"schema":{"type":"string"}}},"content":{"application/json":{"schema":{"$ref":"#/components/schemas/PolicyResponse"}}}},"304":{"description":"Not modified"},"401":{"$ref":"#/components/responses/Problem"},"422":{"$ref":"#/components/responses/Problem"},"429":{"$ref":"#/components/responses/Problem"}}}},"/v1/grade":{"post":{"summary":"Grade a reply after it has been sent","description":"Writes a sealed record. Send it off the response path. With `Idempotency-Key`, a retry returns the first request's record and never seals twice. With `mode: \"async\"` (or `Prefer: respond-async`) the request is queued and answered with 202 and a job to poll; the queue retries a failing grader for up to 24 hours before it records an instrument error.","parameters":[{"name":"Idempotency-Key","in":"header","schema":{"type":"string","pattern":"^[A-Za-z0-9_.:-]{1,100}$"}},{"name":"Prefer","in":"header","schema":{"type":"string","example":"respond-async"}}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","required":["candidate"],"properties":{"candidate":{"type":"string","maxLength":20000,"description":"The reply that was sent."},"turns":{"type":"array","maxItems":200,"items":{"$ref":"#/components/schemas/Turn"}},"jurisdiction":{"type":"string","default":"AU"},"language":{"type":"string","default":"en"},"session":{"type":"string"},"call_site":{"type":"string","default":"default"},"policy_hash":{"type":"string","description":"The hash of the block you applied."},"mode":{"enum":["fast","async"],"default":"fast"}}}}}},"responses":{"200":{"description":"The grade and its seal. Header `Idempotent-Replayed: true` on a replay.","headers":{"X-Request-Id":{"$ref":"#/components/headers/RequestId"},"RateLimit-Limit":{"$ref":"#/components/headers/RateLimitLimit"},"RateLimit-Remaining":{"$ref":"#/components/headers/RateLimitRemaining"},"RateLimit-Reset":{"$ref":"#/components/headers/RateLimitReset"}},"content":{"application/json":{"schema":{"$ref":"#/components/schemas/GradeResult"}}}},"202":{"description":"Queued (async mode). Poll `status_url`.","headers":{"X-Request-Id":{"$ref":"#/components/headers/RequestId"},"RateLimit-Limit":{"$ref":"#/components/headers/RateLimitLimit"},"RateLimit-Remaining":{"$ref":"#/components/headers/RateLimitRemaining"},"RateLimit-Reset":{"$ref":"#/components/headers/RateLimitReset"},"Location":{"schema":{"type":"string"}}},"content":{"application/json":{"schema":{"$ref":"#/components/schemas/JobQueued"}}}},"401":{"$ref":"#/components/responses/Problem"},"422":{"$ref":"#/components/responses/Problem"},"429":{"description":"`rate_limited`, or `quota_exceeded` when the plan's monthly grades are used and there is no prepaid credit left; wait for `Retry-After` (a minute when an automatic top-up is being charged). Do not retry quota_exceeded before then.","headers":{"X-Request-Id":{"$ref":"#/components/headers/RequestId"},"RateLimit-Limit":{"$ref":"#/components/headers/RateLimitLimit"},"RateLimit-Remaining":{"$ref":"#/components/headers/RateLimitRemaining"},"RateLimit-Reset":{"$ref":"#/components/headers/RateLimitReset"}},"content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"}}}}}}},"/v1/grade/jobs/{id}":{"get":{"summary":"A queued grading request","description":"`queued` or `running` until sealed, then `done` with the record. `failed` means it was not graded and not recorded: send it again.","parameters":[{"name":"id","in":"path","required":true,"schema":{"type":"string"}}],"responses":{"200":{"description":"The job","headers":{"X-Request-Id":{"$ref":"#/components/headers/RequestId"},"RateLimit-Limit":{"$ref":"#/components/headers/RateLimitLimit"},"RateLimit-Remaining":{"$ref":"#/components/headers/RateLimitRemaining"},"RateLimit-Reset":{"$ref":"#/components/headers/RateLimitReset"}},"content":{"application/json":{"schema":{"$ref":"#/components/schemas/Job"}}}},"401":{"$ref":"#/components/responses/Problem"},"404":{"$ref":"#/components/responses/Problem"},"429":{"$ref":"#/components/responses/Problem"}}}},"/v1/grade/batch":{"post":{"summary":"Queue up to 100 replies for grading","description":"For a Baseline or a backfill. Each reply is graded and sealed as POST /v1/grade would, through the queue. Answers 202 at once; read progress and records from `status_url`. With `Idempotency-Key`, a retry returns the batch already queued. Every reply counts towards the plan's monthly grades, and a batch that would pass the allowance is refused whole. Not for the public playground key.","parameters":[{"name":"Idempotency-Key","in":"header","schema":{"type":"string","pattern":"^[A-Za-z0-9_.:-]{1,90}$"}}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","required":["items"],"properties":{"items":{"type":"array","minItems":1,"maxItems":100,"description":"Each as the body of POST /v1/grade; at most 2,000,000 characters in all","items":{"type":"object","required":["candidate"]}}}}}}},"responses":{"202":{"description":"Queued","headers":{"X-Request-Id":{"$ref":"#/components/headers/RequestId"},"RateLimit-Limit":{"$ref":"#/components/headers/RateLimitLimit"},"RateLimit-Remaining":{"$ref":"#/components/headers/RateLimitRemaining"},"RateLimit-Reset":{"$ref":"#/components/headers/RateLimitReset"},"Location":{"schema":{"type":"string"}}},"content":{"application/json":{"schema":{"type":"object","properties":{"batch_id":{"type":"string"},"status_url":{"type":"string"},"total":{"type":"integer"},"replayed":{"type":"boolean"},"jobs":{"type":"array","items":{"type":"object","properties":{"index":{"type":"integer"},"job_id":{"type":"string"}},"required":["index","job_id"],"unevaluatedProperties":false}}},"required":["batch_id","status_url","total","replayed","jobs"],"unevaluatedProperties":false}}}},"401":{"$ref":"#/components/responses/Problem"},"403":{"$ref":"#/components/responses/Problem"},"422":{"$ref":"#/components/responses/Problem"},"429":{"description":"`rate_limited`, or `quota_exceeded` when the batch would pass the plan's monthly grades and the prepaid credit left","headers":{"X-Request-Id":{"$ref":"#/components/headers/RequestId"},"RateLimit-Limit":{"$ref":"#/components/headers/RateLimitLimit"},"RateLimit-Remaining":{"$ref":"#/components/headers/RateLimitRemaining"},"RateLimit-Reset":{"$ref":"#/components/headers/RateLimitReset"}},"content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"}}}},"503":{"$ref":"#/components/responses/Problem"}}}},"/v1/grade/batch/{id}":{"get":{"summary":"A batch's progress, and each record once sealed","description":"Poll until `pending` is 0 (`Retry-After` says how long to wait). Readable for seven days after it finishes.","parameters":[{"name":"id","in":"path","required":true,"schema":{"type":"string"}}],"responses":{"200":{"description":"The batch","headers":{"X-Request-Id":{"$ref":"#/components/headers/RequestId"},"RateLimit-Limit":{"$ref":"#/components/headers/RateLimitLimit"},"RateLimit-Remaining":{"$ref":"#/components/headers/RateLimitRemaining"},"RateLimit-Reset":{"$ref":"#/components/headers/RateLimitReset"}},"content":{"application/json":{"schema":{"type":"object","properties":{"batch_id":{"type":"string"},"total":{"type":"integer"},"done":{"type":"integer"},"failed":{"type":"integer"},"pending":{"type":"integer"},"jobs":{"type":"array","items":{"type":"object","properties":{"index":{"type":"integer"},"job_id":{"type":"string"},"status":{"enum":["queued","running","done","failed"]},"attempts":{"type":"integer"},"record":{"oneOf":[{"type":"null"},{"$ref":"#/components/schemas/Record","unevaluatedProperties":false}]},"error":{"type":"string"}},"required":["index","job_id","status","attempts","record"],"unevaluatedProperties":false}}},"required":["batch_id","total","done","failed","pending","jobs"],"unevaluatedProperties":false}}}},"401":{"$ref":"#/components/responses/Problem"},"403":{"$ref":"#/components/responses/Problem"},"404":{"$ref":"#/components/responses/Problem"},"429":{"$ref":"#/components/responses/Problem"}}}},"/v1/referrals/rank":{"post":{"summary":"Fitness-ranked services and composed referral text","description":"Ranking never considers who operates a service.","requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","required":["jurisdiction"],"properties":{"jurisdiction":{"type":"string"},"language":{"type":"string"},"turn":{"type":"string"},"kinds":{"type":"array","items":{"type":"string"}}}}}}},"responses":{"200":{"description":"Ranked services","headers":{"X-Request-Id":{"$ref":"#/components/headers/RequestId"},"RateLimit-Limit":{"$ref":"#/components/headers/RateLimitLimit"},"RateLimit-Remaining":{"$ref":"#/components/headers/RateLimitRemaining"},"RateLimit-Reset":{"$ref":"#/components/headers/RateLimitReset"}},"content":{"application/json":{"schema":{"type":"object","properties":{"tier":{"enum":["verified_local","national","emergency_only"]},"jurisdiction":{"type":"string"},"emergency":{"type":"string"},"services":{"type":"array","items":{"$ref":"#/components/schemas/RankedService"}},"text":{"type":"string"}},"required":["tier","jurisdiction","emergency","services","text"],"unevaluatedProperties":false}}}},"401":{"$ref":"#/components/responses/Problem"},"422":{"$ref":"#/components/responses/Problem"},"429":{"$ref":"#/components/responses/Problem"}}}},"/v1/records":{"get":{"summary":"This key's system's sealed records, newest first","description":"Pass `next_cursor` back as `cursor` for the next page, with the same filters. A page can hold fewer than `limit` records when a filter skips many: continue while `next_cursor` is set.","parameters":[{"name":"from","in":"query","description":"A date (whole UTC days) or an ISO 8601 time. Default: 30 days before `to`.","schema":{"type":"string","example":"2026-10-01"}},{"name":"to","in":"query","description":"A date (inclusive) or an ISO 8601 time. Default: now. At most 400 days after `from`.","schema":{"type":"string"}},{"name":"verdict","in":"query","schema":{"enum":["clean","flagged","error"]}},{"name":"limit","in":"query","schema":{"type":"integer","minimum":1,"maximum":500,"default":100}},{"name":"cursor","in":"query","schema":{"type":"string"}}],"responses":{"200":{"description":"A page of records","headers":{"X-Request-Id":{"$ref":"#/components/headers/RequestId"},"RateLimit-Limit":{"$ref":"#/components/headers/RateLimitLimit"},"RateLimit-Remaining":{"$ref":"#/components/headers/RateLimitRemaining"},"RateLimit-Reset":{"$ref":"#/components/headers/RateLimitReset"}},"content":{"application/json":{"schema":{"type":"object","properties":{"records":{"type":"array","items":{"$ref":"#/components/schemas/Record","unevaluatedProperties":false}},"next_cursor":{"type":["string","null"]}},"required":["records","next_cursor"],"unevaluatedProperties":false}}}},"401":{"$ref":"#/components/responses/Problem"},"403":{"$ref":"#/components/responses/Problem"},"422":{"$ref":"#/components/responses/Problem"},"429":{"$ref":"#/components/responses/Problem"}}}},"/v1/records/{id}":{"get":{"summary":"One sealed record","parameters":[{"name":"id","in":"path","required":true,"schema":{"type":"string"}}],"responses":{"200":{"description":"The record","headers":{"X-Request-Id":{"$ref":"#/components/headers/RequestId"},"RateLimit-Limit":{"$ref":"#/components/headers/RateLimitLimit"},"RateLimit-Remaining":{"$ref":"#/components/headers/RateLimitRemaining"},"RateLimit-Reset":{"$ref":"#/components/headers/RateLimitReset"}},"content":{"application/json":{"schema":{"$ref":"#/components/schemas/Record","unevaluatedProperties":false}}}},"401":{"$ref":"#/components/responses/Problem"},"403":{"$ref":"#/components/responses/Problem"},"404":{"$ref":"#/components/responses/Problem"},"429":{"$ref":"#/components/responses/Problem"}}}},"/v1/records/{id}/match":{"post":{"summary":"Check your copy of a conversation against a record","description":"Harmwise keeps no conversation text, only a keyed hash of it. Send your copy of the turns and the reply; the answer says whether it is the conversation the record was made from. The text is compared and discarded.","parameters":[{"name":"id","in":"path","required":true,"schema":{"type":"string"}}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","required":["candidate"],"properties":{"candidate":{"type":"string"},"turns":{"type":"array","items":{"$ref":"#/components/schemas/Turn"}}}}}}},"responses":{"200":{"description":"Result","headers":{"X-Request-Id":{"$ref":"#/components/headers/RequestId"},"RateLimit-Limit":{"$ref":"#/components/headers/RateLimitLimit"},"RateLimit-Remaining":{"$ref":"#/components/headers/RateLimitRemaining"},"RateLimit-Reset":{"$ref":"#/components/headers/RateLimitReset"}},"content":{"application/json":{"schema":{"type":"object","properties":{"record_id":{"type":"string"},"match":{"type":"boolean"},"seal":{"$ref":"#/components/schemas/Seal"}},"required":["record_id","match","seal"],"unevaluatedProperties":false}}}},"401":{"$ref":"#/components/responses/Problem"},"404":{"$ref":"#/components/responses/Problem"},"422":{"$ref":"#/components/responses/Problem"},"429":{"$ref":"#/components/responses/Problem"},"503":{"$ref":"#/components/responses/Problem"}}}},"/v1/records/verify":{"get":{"summary":"Verify the key's system chain against its published head","description":"From the last verified checkpoint by default, which costs only what was added since. `from=genesis` re-checks every record from the first; at most twice an hour per system.","parameters":[{"name":"from","in":"query","schema":{"enum":["checkpoint","genesis"],"default":"checkpoint"}}],"responses":{"200":{"description":"Verification result","headers":{"X-Request-Id":{"$ref":"#/components/headers/RequestId"},"RateLimit-Limit":{"$ref":"#/components/headers/RateLimitLimit"},"RateLimit-Remaining":{"$ref":"#/components/headers/RateLimitRemaining"},"RateLimit-Reset":{"$ref":"#/components/headers/RateLimitReset"}},"content":{"application/json":{"schema":{"$ref":"#/components/schemas/Verification"}}}},"401":{"$ref":"#/components/responses/Problem"},"429":{"$ref":"#/components/responses/Problem"}}}},"/v1/records/archives":{"get":{"summary":"This key's system's archived records","description":"Records older than a year (or than your quote retention, if longer) move from the database into archive files: one system's records from one month, contiguous in the chain, gzip-compressed newline-delimited JSON. Each file holds the exact text every seal hashed and the findings decisions on those records, and checks offline (`verifyArchive` in the SDK, or `npx harmwise verify-archive <file>`). Runs link to each other and to genesis by `prev_hash` and `last_hash`. `download_url` works for 15 minutes. A file is deleted at `delete_after`, seven years after its last record, with notice beforehand; save the ones you need.","responses":{"200":{"description":"The archived runs, oldest first","headers":{"X-Request-Id":{"$ref":"#/components/headers/RequestId"},"RateLimit-Limit":{"$ref":"#/components/headers/RateLimitLimit"},"RateLimit-Remaining":{"$ref":"#/components/headers/RateLimitRemaining"},"RateLimit-Reset":{"$ref":"#/components/headers/RateLimitReset"}},"content":{"application/json":{"schema":{"type":"object","properties":{"system_id":{"type":"string"},"archived_through_seq":{"type":"integer"},"archives":{"type":"array","items":{"$ref":"#/components/schemas/Archive"}}},"required":["system_id","archived_through_seq","archives"],"unevaluatedProperties":false}}}},"401":{"$ref":"#/components/responses/Problem"},"403":{"$ref":"#/components/responses/Problem"},"429":{"$ref":"#/components/responses/Problem"}}}},"/v1/records/heads":{"get":{"summary":"Your chain head's inclusion proof in a day's published root","description":"Check it offline against the root at /heads and the key at /.well-known/harmwise-keys.json (`verifyHeadProof` in the SDK). Roots are published daily at 17:00 UTC.","parameters":[{"name":"date","in":"query","schema":{"type":"string","example":"2026-10-22"}}],"responses":{"200":{"description":"The proof","headers":{"X-Request-Id":{"$ref":"#/components/headers/RequestId"},"RateLimit-Limit":{"$ref":"#/components/headers/RateLimitLimit"},"RateLimit-Remaining":{"$ref":"#/components/headers/RateLimitRemaining"},"RateLimit-Reset":{"$ref":"#/components/headers/RateLimitReset"}},"content":{"application/json":{"schema":{"type":"object","properties":{"date":{"type":"string"},"system_id":{"type":"string"},"seq":{"type":"integer"},"hash":{"type":"string"},"leaf":{"type":"string"},"proof":{"type":"array","items":{"type":"object","properties":{"side":{"enum":["left","right"]},"hash":{"type":"string"}},"required":["side","hash"],"unevaluatedProperties":false}},"root":{"type":"string"},"count":{"type":"integer"},"signature":{"oneOf":[{"type":"null"},{"$ref":"#/components/schemas/Signature"}]}},"required":["date","system_id","seq","hash","leaf","proof","root","count","signature"],"unevaluatedProperties":false}}}},"401":{"$ref":"#/components/responses/Problem"},"404":{"$ref":"#/components/responses/Problem"},"422":{"$ref":"#/components/responses/Problem"},"429":{"$ref":"#/components/responses/Problem"}}}},"/v1/findings":{"get":{"summary":"Findings with their workflow status, most severe first","description":"Filtered as in the console. `total` counts every match; `findings` holds the first `limit`.","parameters":[{"name":"from","in":"query","schema":{"type":"string","example":"2026-10-01"}},{"name":"to","in":"query","schema":{"type":"string"}},{"name":"sev","in":"query","schema":{"enum":["S0","S1","S2","all"],"default":"all"}},{"name":"status","in":"query","schema":{"enum":["outstanding","open","disputed","resolved","upheld","all"],"default":"outstanding"}},{"name":"limit","in":"query","schema":{"type":"integer","minimum":1,"maximum":1000,"default":200}}],"responses":{"200":{"description":"Findings","headers":{"X-Request-Id":{"$ref":"#/components/headers/RequestId"},"RateLimit-Limit":{"$ref":"#/components/headers/RateLimitLimit"},"RateLimit-Remaining":{"$ref":"#/components/headers/RateLimitRemaining"},"RateLimit-Reset":{"$ref":"#/components/headers/RateLimitReset"}},"content":{"application/json":{"schema":{"type":"object","properties":{"query":{"type":"object","properties":{"from":{"type":"string"},"to":{"type":"string"},"sev":{"type":"string"},"status":{"type":"string"}},"required":["from","to","sev","status"],"unevaluatedProperties":false},"total":{"type":"integer"},"findings":{"type":"array","items":{"$ref":"#/components/schemas/Finding"}}},"required":["query","total","findings"],"unevaluatedProperties":false}}}},"401":{"$ref":"#/components/responses/Problem"},"403":{"$ref":"#/components/responses/Problem"},"422":{"$ref":"#/components/responses/Problem"},"429":{"$ref":"#/components/responses/Problem"}}}},"/v1/instances/{id}/dispute":{"post":{"summary":"Dispute a finding as a false positive","description":"The record is not changed: the dispute is stored beside it, appears in the console, and DSC staff triage it. Only findings on the key's own system can be disputed.","parameters":[{"name":"id","in":"path","required":true,"schema":{"type":"string","example":"rec_abc123.0"}}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","required":["reason"],"properties":{"reason":{"type":"string","minLength":10,"maxLength":1000},"share_quote":{"type":"boolean","default":false,"description":"Share the retained quoted span with DSC for triage."}}}}}},"responses":{"201":{"description":"Disputed","headers":{"X-Request-Id":{"$ref":"#/components/headers/RequestId"},"RateLimit-Limit":{"$ref":"#/components/headers/RateLimitLimit"},"RateLimit-Remaining":{"$ref":"#/components/headers/RateLimitRemaining"},"RateLimit-Reset":{"$ref":"#/components/headers/RateLimitReset"}},"content":{"application/json":{"schema":{"type":"object","properties":{"finding_id":{"type":"string"},"status":{"const":"disputed"},"disputed_at":{"type":"string"}},"required":["finding_id","status","disputed_at"],"unevaluatedProperties":false}}}},"401":{"$ref":"#/components/responses/Problem"},"403":{"$ref":"#/components/responses/Problem"},"404":{"$ref":"#/components/responses/Problem"},"409":{"$ref":"#/components/responses/Problem"},"422":{"$ref":"#/components/responses/Problem"},"429":{"$ref":"#/components/responses/Problem"},"503":{"$ref":"#/components/responses/Problem"}}}},"/v1/compliance/summary":{"get":{"summary":"The evidence board for this key's system over a period","description":"Computed from the sealed records. It states what was found, and certifies nothing.","parameters":[{"name":"days","in":"query","schema":{"type":"integer","minimum":1,"maximum":90,"default":30}}],"responses":{"200":{"description":"The summary","headers":{"X-Request-Id":{"$ref":"#/components/headers/RequestId"},"RateLimit-Limit":{"$ref":"#/components/headers/RateLimitLimit"},"RateLimit-Remaining":{"$ref":"#/components/headers/RateLimitRemaining"},"RateLimit-Reset":{"$ref":"#/components/headers/RateLimitReset"}},"content":{"application/json":{"schema":{"type":"object","properties":{"system_id":{"type":"string"},"environment":{"enum":["production","test"]},"period":{"type":"object","properties":{"from":{"type":"string"},"to":{"type":"string"},"days":{"type":"integer"}},"required":["from","to","days"],"unevaluatedProperties":false},"in_domain_turns":{"type":"integer"},"scored":{"type":"integer"},"coverage":{"type":"object","properties":{"rate":{"type":"number"},"gaps":{"type":"object","additionalProperties":{"type":"integer"}}},"required":["rate","gaps"],"unevaluatedProperties":false},"findings":{"type":"object","properties":{"clean_rate":{"type":"number"},"s0_total":{"type":"integer"},"s0_open":{"type":"integer"},"s1_open":{"type":"integer"}},"required":["clean_rate","s0_total","s0_open","s1_open"],"unevaluatedProperties":false},"referral":{"type":"object","properties":{"offered":{"type":"integer"},"fitness":{"type":"number"},"alternative_given":{"type":"number"},"owned_offered":{"type":"integer"},"self_preference_rate":{"type":"number"}},"required":["offered","fitness","alternative_given","owned_offered","self_preference_rate"],"unevaluatedProperties":false},"instrument":{"type":"object","properties":{"health":{"type":"number"},"instrument_errors":{"type":"integer"},"router":{"type":"string"},"measured_at":{"type":"string"}},"required":["health","instrument_errors","router","measured_at"],"unevaluatedProperties":false},"board":{"type":"array","items":{"$ref":"#/components/schemas/BoardRow"}},"note":{"type":"string"}},"required":["system_id","environment","period","in_domain_turns","scored","coverage","findings","referral","instrument","board","note"],"unevaluatedProperties":false}}}},"401":{"$ref":"#/components/responses/Problem"},"403":{"$ref":"#/components/responses/Problem"},"422":{"$ref":"#/components/responses/Problem"},"429":{"$ref":"#/components/responses/Problem"}}}},"/v1/attestations":{"get":{"summary":"The organisation's signed 30-day attestation","description":"The same document as the console's export, signed with the platform key over `JSON.stringify(doc, null, 2)` without `signature`. Verify with `verifyAttestation` in the SDK or `npx harmwise verify-attestation`. It certifies nothing. Included from the Pro plan.","responses":{"200":{"description":"The attestation","headers":{"X-Request-Id":{"$ref":"#/components/headers/RequestId"},"RateLimit-Limit":{"$ref":"#/components/headers/RateLimitLimit"},"RateLimit-Remaining":{"$ref":"#/components/headers/RateLimitRemaining"},"RateLimit-Reset":{"$ref":"#/components/headers/RateLimitReset"},"X-Document-Sha256":{"schema":{"type":"string"}}},"content":{"application/json":{"schema":{"type":"object","required":["kind","organisation","period","limitations","signature"],"properties":{"kind":{"const":"harmwise.attestation"},"organisation":{"type":"string"},"period":{"type":"object","properties":{"days":{"type":"integer"},"generated_at":{"type":"string"}},"required":["days","generated_at"],"unevaluatedProperties":false},"limitations":{"type":"array","items":{"type":"string"}},"signature":{"oneOf":[{"type":"object","properties":{"alg":{"const":"Ed25519"},"kid":{"type":"string"},"value":{"type":"string"},"sha256":{"type":"string"}},"required":["alg","kid","value","sha256"],"unevaluatedProperties":false},{"type":"object","properties":{"unsigned":{"type":"string"}},"required":["unsigned"],"unevaluatedProperties":false}]}}}}}},"401":{"$ref":"#/components/responses/Problem"},"403":{"$ref":"#/components/responses/Problem"},"429":{"$ref":"#/components/responses/Problem"}}}},"/v1/modules":{"get":{"summary":"Policy modules, what is in force for you, and release gates","responses":{"200":{"description":"Modules","headers":{"X-Request-Id":{"$ref":"#/components/headers/RequestId"},"RateLimit-Limit":{"$ref":"#/components/headers/RateLimitLimit"},"RateLimit-Remaining":{"$ref":"#/components/headers/RateLimitRemaining"},"RateLimit-Reset":{"$ref":"#/components/headers/RateLimitReset"}},"content":{"application/json":{"schema":{"type":"object","properties":{"modules":{"type":"array","items":{"$ref":"#/components/schemas/Module"}}},"required":["modules"],"unevaluatedProperties":false}}}},"401":{"$ref":"#/components/responses/Problem"},"429":{"$ref":"#/components/responses/Problem"}}}},"/v1/resources":{"get":{"summary":"The referral directory","description":"Listed by name: this is the directory, not a recommendation. To choose services for a person, use POST /v1/referrals/rank. Retired services are left out.","parameters":[{"name":"jurisdiction","in":"query","schema":{"type":"string","example":"AU-VIC"}},{"name":"kind","in":"query","schema":{"type":"string"}},{"name":"language","in":"query","schema":{"type":"string"}}],"responses":{"200":{"description":"Services","headers":{"X-Request-Id":{"$ref":"#/components/headers/RequestId"},"RateLimit-Limit":{"$ref":"#/components/headers/RateLimitLimit"},"RateLimit-Remaining":{"$ref":"#/components/headers/RateLimitRemaining"},"RateLimit-Reset":{"$ref":"#/components/headers/RateLimitReset"}},"content":{"application/json":{"schema":{"type":"object","properties":{"resources":{"type":"array","items":{"$ref":"#/components/schemas/Resource"}},"note":{"type":"string"}},"required":["resources","note"],"unevaluatedProperties":false}}}},"401":{"$ref":"#/components/responses/Problem"},"422":{"$ref":"#/components/responses/Problem"},"429":{"$ref":"#/components/responses/Problem"}}}},"/v1/health":{"get":{"summary":"Liveness and a real grader round trip","security":[],"responses":{"200":{"description":"Healthy","headers":{"X-Request-Id":{"$ref":"#/components/headers/RequestId"},"RateLimit-Limit":{"$ref":"#/components/headers/RateLimitLimit"},"RateLimit-Remaining":{"$ref":"#/components/headers/RateLimitRemaining"},"RateLimit-Reset":{"$ref":"#/components/headers/RateLimitReset"}},"content":{"application/json":{"schema":{"type":"object","properties":{"ok":{"type":"boolean"},"grader":{"type":"string"},"checked_at":{"type":"string"}},"required":["ok","grader","checked_at"],"unevaluatedProperties":false}}}},"503":{"description":"The grader is failing","headers":{"X-Request-Id":{"$ref":"#/components/headers/RequestId"},"RateLimit-Limit":{"$ref":"#/components/headers/RateLimitLimit"},"RateLimit-Remaining":{"$ref":"#/components/headers/RateLimitRemaining"},"RateLimit-Reset":{"$ref":"#/components/headers/RateLimitReset"}},"content":{"application/json":{"schema":{"type":"object","properties":{"ok":{"type":"boolean"},"grader":{"type":"string"},"checked_at":{"type":"string"}},"required":["ok","grader","checked_at"],"unevaluatedProperties":false}}}}}}}},"webhooks":{"event":{"post":{"summary":"An event for your endpoint","description":"Events: finding.s0, finding.s1, quota.warning, quota.exceeded, chain.broken, access.requested, access.approved, access.ended, records.expiring, and test. Signed with `Harmwise-Signature: t=<unix>,v1=<hex HMAC-SHA256 of \"t.body\">`; reject a t more than five minutes old. Delivered at least once: retried for 72 hours until you answer 2xx (a 4xx other than 429 stops it), so drop duplicates by `id` (also in `Harmwise-Delivery`). Never carries conversation content.","parameters":[{"name":"Harmwise-Event","in":"header","schema":{"type":"string"}},{"name":"Harmwise-Delivery","in":"header","schema":{"type":"string"}},{"name":"Harmwise-Signature","in":"header","schema":{"type":"string"}}],"requestBody":{"content":{"application/json":{"schema":{"type":"object","required":["id","type","created","data"],"properties":{"id":{"type":"string","description":"The delivery id; the same on every retry"},"type":{"type":"string"},"created":{"type":"string","format":"date-time"},"data":{"oneOf":[{"title":"finding.s0, finding.s1","type":"object","properties":{"record_id":{"type":"string"},"system_id":{"type":"string"},"environment":{"enum":["production","test"]},"occurred_at":{"type":"string"},"verdict":{"type":"string"},"findings":{"type":"array","items":{"type":"object","properties":{"id":{"type":"string"},"severity":{"type":"string"},"principles":{"type":"array","items":{"type":"string"}},"source":{"type":"string"}}}},"console_url":{"type":"string"}}},{"title":"quota.warning, quota.exceeded","type":"object","properties":{"allowance":{"type":"integer"},"used":{"type":"integer"},"month":{"type":"string"},"resets_at":{"type":"string"}}},{"title":"chain.broken","type":"object","properties":{"system_id":{"type":"string"},"broken_at":{"type":["integer","null"]},"records":{"type":"integer"}}},{"title":"access.requested, access.approved, access.ended","type":"object","properties":{"grant_id":{"type":"string"},"requested_by":{"type":"string"},"reason":{"type":"string"},"approved_by":{"type":["string","null"]},"expires_at":{"type":["string","null"]},"ended_by":{"type":["string","null"]}}},{"title":"records.expiring","description":"Sent 90 and 30 days before archive files reach the end of their seven-year retention. List them with GET /v1/records/archives.","type":"object","properties":{"delete_after":{"type":"string"},"month":{"type":"string"},"days_notice":{"enum":[90,30]},"archives":{"type":"integer"},"records":{"type":"integer"},"systems":{"type":"array","items":{"type":"string"}},"archive_ids":{"type":"array","items":{"type":"string"}},"console_url":{"type":"string"}}}]}}}}}},"responses":{"2XX":{"description":"Received"}}}}}}