{"openapi":"3.1.0","info":{"title":"proofread.law","description":"Case citations checked against an open register of 10 million opinions. Every response carries the coverage statement. Authenticate with `Authorization: Bearer pl_...` (API keys on the Firm plan; see /account); without a key the free tier of the calling address applies. Errors are `{\"error\": {\"code\", \"message\"}}`. Contract: https://proofread.law/api","version":"v0"},"paths":{"/health":{"get":{"tags":["status"],"summary":"Health","operationId":"health_health_get","responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{"additionalProperties":true,"type":"object","title":"Response Health Health Get"}}}}}}},"/api/coverage":{"get":{"tags":["status"],"summary":"Coverage Json","description":"The statement, the storage notice, and the freshness the /coverage page prints in its \"as of\" cells (no dates in the page's own copy).","operationId":"coverage_json_api_coverage_get","responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{"additionalProperties":true,"type":"object","title":"Response Coverage Json Api Coverage Get"}}}}}}},"/verify":{"post":{"tags":["check"],"summary":"Verify","operationId":"verify_verify_post","parameters":[{"name":"deep","in":"query","required":false,"schema":{"type":"integer","default":0,"title":"Deep"}},{"name":"stream","in":"query","required":false,"schema":{"type":"integer","default":1,"title":"Stream"}},{"name":"shape","in":"query","required":false,"schema":{"type":"string","default":"single_v4","title":"Shape"}},{"name":"doc","in":"query","required":false,"schema":{"type":"integer","default":0,"title":"Doc"}},{"name":"jurisdiction","in":"query","required":false,"schema":{"type":"string","default":"auto","title":"Jurisdiction"}}],"requestBody":{"content":{"multipart/form-data":{"schema":{"$ref":"#/components/schemas/Body_verify_verify_post"}}}},"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}},"/render":{"post":{"tags":["check"],"summary":"Render Report","operationId":"render_report_render_post","parameters":[{"name":"format","in":"query","required":false,"schema":{"type":"string","default":"md","title":"Format"}}],"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}},"/auth/magic":{"post":{"tags":["accounts"],"summary":"Auth Magic","operationId":"auth_magic_auth_magic_post","responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{}}}}}}},"/auth/verify":{"post":{"tags":["accounts"],"summary":"Auth Verify Confirm","description":"The one click on /login?confirm=: JSON {token} from our own page (X-Requested-With + Origin checked).","operationId":"auth_verify_confirm_auth_verify_post","responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{}}}}}}},"/auth/logout":{"post":{"tags":["accounts"],"summary":"Auth Logout","operationId":"auth_logout_auth_logout_post","responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{}}}}}}},"/me":{"get":{"tags":["accounts"],"summary":"Me","operationId":"me_me_get","responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{}}}}}},"delete":{"tags":["accounts"],"summary":"Me Delete","description":"Delete the signed-in account: its saved briefs and their versions, API keys, sessions, sign-in identities and links, then the\naccount itself, in one transaction. Session only, with X-Requested-With (an API key cannot delete the account it belongs to). 409\nactive_subscription while a Stripe subscription runs: cancel it in the billing portal first. Monthly counts stay, tied to no account.","operationId":"me_delete_me_delete","responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{}}}}}}},"/keys":{"post":{"tags":["accounts"],"summary":"Keys Create","operationId":"keys_create_keys_post","responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{}}}}}}},"/keys/{kid}":{"delete":{"tags":["accounts"],"summary":"Keys Revoke","operationId":"keys_revoke_keys__kid__delete","parameters":[{"name":"kid","in":"path","required":true,"schema":{"type":"integer","title":"Kid"}}],"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}},"/auth/providers":{"get":{"tags":["accounts"],"summary":"Auth Providers","operationId":"auth_providers_auth_providers_get","responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{}}}}}}},"/agent/signup":{"post":{"tags":["agents"],"summary":"Agent Signup","description":"{\"email\": owner's real inbox, \"agent_name\": 1-64 chars} -> 201 {api_key (shown once), plan, limits, next}. Same address, still\nunconfirmed and unpaid -> 200 with a rotated key. Confirmed or paying -> 409. The owner is emailed one confirmation link.","operationId":"agent_signup_agent_signup_post","responses":{"201":{"description":"Successful Response","content":{"application/json":{"schema":{}}}}}}},"/agent/checkout-link":{"post":{"tags":["agents"],"summary":"Agent Checkout Link","description":"With the key: {\"plan\": \"payg\" | \"solo\" | \"firm\"} (default payg) -> {\"checkout_url\"}: a Stripe Checkout page for the owner. The\nplan switches on when Stripe confirms; until then the free tier applies.","operationId":"agent_checkout_link_agent_checkout_link_post","responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{}}}}}}},"/billing/checkout":{"post":{"tags":["billing"],"summary":"Billing Checkout","operationId":"billing_checkout_billing_checkout_post","responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{}}}}}}},"/billing/portal":{"post":{"tags":["billing"],"summary":"Billing Portal","operationId":"billing_portal_billing_portal_post","responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{}}}}}}},"/v1/resolve":{"get":{"tags":["register"],"summary":"V1 Resolve","description":"One citation string -> is there a case at this citation, which one, and how complete is the register for that volume.","operationId":"v1_resolve_v1_resolve_get","parameters":[{"name":"cite","in":"query","required":false,"schema":{"type":"string","default":"","title":"Cite"}}],"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}},"post":{"tags":["register"],"summary":"V1 Resolve Batch","description":"{\"cites\": [...]} up to 500 -> the same object per input, in order.","operationId":"v1_resolve_batch_v1_resolve_post","responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{}}}}}}},"/v1/extract":{"post":{"tags":["register"],"summary":"V1 Extract","description":"{\"text\": \"...\"} -> every citation in the prose, resolved, with spans. The text is processed in memory and never stored.","operationId":"v1_extract_v1_extract_post","responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{}}}}}}},"/v1/case/{cid}":{"get":{"tags":["register"],"summary":"V1 Case","description":"One register cluster. ?text=1 returns the opinion text on the Solo and Firm plans.","operationId":"v1_case_v1_case__cid__get","parameters":[{"name":"cid","in":"path","required":true,"schema":{"type":"integer","title":"Cid"}},{"name":"text","in":"query","required":false,"schema":{"type":"integer","default":0,"title":"Text"}}],"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}},"/v1/coverage":{"get":{"tags":["register"],"summary":"V1 Coverage","description":"The coverage statement, freshness, and per-reporter counts and max volumes (us); per-court counts and the share of the live index held (ch).","operationId":"v1_coverage_v1_coverage_get","parameters":[{"name":"jurisdiction","in":"query","required":false,"schema":{"type":"string","pattern":"^(us|ch)$","default":"us","title":"Jurisdiction"}}],"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}},"/v1/suggest":{"get":{"tags":["register"],"summary":"V1 Suggest","description":"Case suggestions. `jurisdiction` = auto (default: a Swiss statute article, or German, French or Italian text, is Swiss; anything\nelse is a US proposition) | ch | us.\nSwitzerland: statute article -> the leading cases (BGE) the Federal Supreme Court cites with it, one list in the measured order, each\nrow labelled with its field. `q` is an article (\"Art. 41 OR\", \"art. 41 CO\", \"art 41 or\") or a paragraph that cites one (federal acts\nonly); domain = all | civil | criminal | public | social keeps the order within that field; lang = de | fr | it | en (default: the\nquery's language); k = rows, 1 to 50. One resolve per answered query.\nUnited States, BETA: `q` is a legal proposition (a sentence or a short paragraph) -> up to 3 register cases whose own text states it,\neach with the passage the judgment model matched and its neighbouring paragraphs, binding cases first for `court` (a court of appeals\nsuch as 9th Cir., a district court such as N.D. Cal., or a state for a federal court there; empty = the Supreme Court first). The answer\ncarries `beta: true` and the measured line. One deep-class unit per answer that ran the model; the daily model budget applies.\nPaid plans and trials while the practitioner's read is pending.","operationId":"v1_suggest_v1_suggest_get","parameters":[{"name":"q","in":"query","required":false,"schema":{"type":"string","default":"","title":"Q"}},{"name":"domain","in":"query","required":false,"schema":{"type":"string","default":"all","title":"Domain"}},{"name":"lang","in":"query","required":false,"schema":{"type":"string","default":"","title":"Lang"}},{"name":"k","in":"query","required":false,"schema":{"type":"integer","default":10,"title":"K"}},{"name":"court","in":"query","required":false,"schema":{"type":"string","default":"","title":"Court"}},{"name":"jurisdiction","in":"query","required":false,"schema":{"type":"string","default":"auto","title":"Jurisdiction"}}],"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}},"post":{"tags":["register"],"summary":"V1 Suggest Post","description":"The same as GET, for a pasted paragraph: {\"q\": \"...\", \"court\"?, \"jurisdiction\"?, \"domain\"?, \"lang\"?, \"k\"?}. Nothing is stored.","operationId":"v1_suggest_post_v1_suggest_post","responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{}}}}}}},"/v1/briefs":{"get":{"tags":["briefs"],"summary":"Briefs List","description":"The account's saved briefs, newest first: {briefs: [{id, title, created_at, updated_at, last_checked_at, n_citations, summary,\nversions}], limit}. No text.","operationId":"briefs_list_v1_briefs_get","responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{}}}}}},"post":{"tags":["briefs"],"summary":"Briefs Create","description":"Save a brief: {\"text\", \"title\"?}. Runs the default check exactly as POST /verify does, keeps the text and the report encrypted with\nthe account's key, and returns {id, title, created_at, updated_at, summary, report}. It counts as one check, unless this account\nchecked exactly this text with POST /verify in the last 30 minutes (that check paid for it, once). The title defaults to the first\nline of the text (80 characters). Signed-in only; nothing is stored by /verify.","operationId":"briefs_create_v1_briefs_post","responses":{"201":{"description":"Successful Response","content":{"application/json":{"schema":{}}}}}}},"/v1/briefs/{bid}":{"get":{"tags":["briefs"],"summary":"Briefs Get","description":"One brief: {id, title, text, report, summary, created_at, updated_at, last_checked_at, versions: [{v, created_at, summary}]}.","operationId":"briefs_get_v1_briefs__bid__get","parameters":[{"name":"bid","in":"path","required":true,"schema":{"type":"integer","minimum":1,"exclusiveMaximum":9223372036854775808,"title":"Bid"}}],"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}},"put":{"tags":["briefs"],"summary":"Briefs Update","description":"{\"text\"?, \"title\"?, \"recheck\"?}. Changed text (or recheck: true, for a register that moved on) runs the default check (one check),\nstores a new version (the last 20 are kept) and returns the brief plus `changes`: {resolved, new, unchanged} over the flagged rows (red\nand orange) of the previous report against the new one, keyed by the normalised citation and the headline. A title alone costs nothing;\n`changes` is then null.","operationId":"briefs_update_v1_briefs__bid__put","parameters":[{"name":"bid","in":"path","required":true,"schema":{"type":"integer","minimum":1,"exclusiveMaximum":9223372036854775808,"title":"Bid"}}],"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}},"delete":{"tags":["briefs"],"summary":"Briefs Delete","description":"Hard delete of the brief and every version (the freed pages are overwritten). 204; 404 for an id that is not this account's.","operationId":"briefs_delete_v1_briefs__bid__delete","parameters":[{"name":"bid","in":"path","required":true,"schema":{"type":"integer","minimum":1,"exclusiveMaximum":9223372036854775808,"title":"Bid"}}],"responses":{"204":{"description":"Successful Response"},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}},"/v1/briefs/{bid}/versions/{v}":{"get":{"tags":["briefs"],"summary":"Briefs Version","description":"One saved state, read-only: {v, created_at, text, summary, report}.","operationId":"briefs_version_v1_briefs__bid__versions__v__get","parameters":[{"name":"bid","in":"path","required":true,"schema":{"type":"integer","minimum":1,"exclusiveMaximum":9223372036854775808,"title":"Bid"}},{"name":"v","in":"path","required":true,"schema":{"type":"integer","minimum":1,"exclusiveMaximum":9223372036854775808,"title":"V"}}],"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}}},"components":{"schemas":{"Body_verify_verify_post":{"properties":{"file":{"anyOf":[{"type":"string","contentMediaType":"application/octet-stream"},{"type":"null"}],"title":"File"},"text":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Text"}},"type":"object","title":"Body_verify_verify_post"},"HTTPValidationError":{"properties":{"detail":{"items":{"$ref":"#/components/schemas/ValidationError"},"type":"array","title":"Detail"}},"type":"object","title":"HTTPValidationError"},"ValidationError":{"properties":{"loc":{"items":{"anyOf":[{"type":"string"},{"type":"integer"}]},"type":"array","title":"Location"},"msg":{"type":"string","title":"Message"},"type":{"type":"string","title":"Error Type"},"input":{"title":"Input"},"ctx":{"type":"object","title":"Context"}},"type":"object","required":["loc","msg","type"],"title":"ValidationError"}}},"tags":[{"name":"check","description":"Verify citations and render the report"},{"name":"agents","description":"An account, a key and a billing link without a browser (/agent/onboarding.md)"},{"name":"register","description":"The register itself: resolve a citation, extract citations from text, a case, coverage (app/APIFORLAW.md)"},{"name":"accounts","description":"Sign-in, the account, API keys"},{"name":"briefs","description":"Saved briefs, opt-in: the text and its report kept encrypted in the signed-in account, edited and re-checked. /verify stores nothing"},{"name":"billing","description":"Stripe checkout and portal"},{"name":"status","description":"Health and coverage"}]}