OpenCase API v1
The OpenCase API checks legal citations, answers legal questions and reviews contracts. It is organized around REST. Requests and responses are JSON, errors use standard HTTP status codes, and every request is authenticated with a bearer token.
Paid endpoints draw from a prepaid balance. Short requests return results directly. A long document returns a job that you poll.
| /citations/verify | $0.015 / citation |
| /citations/resolve | $0.015 / citation |
| /answers | $0.125 / answer |
| /documents/review | $0.10 / review |
Quickstart
- 1
Create a key
In OpenCase Settings, open API and choose New key. Export it as
OC_API_KEY. - 2
Add funds
A new account starts at a zero balance, and a request made at zero or less returns
402 payment_required. On the same API page, choose Add funds. - 3
Send a request
The example sends a two-citation passage to
/citations/verify. - 4
Read the response
Results are in
data, next to arequestId. Here, the first citation is real and the second was invented.
curl https://public-api.opencase.com/v1/citations/verify \
-H "Authorization: Bearer $OC_API_KEY" \
-H "Content-Type: application/json" \
-d '{
"text": "See Brown v. Board of Education, 347 U.S. 483 (1954); Varghese v. China Southern Airlines Co., 925 F.3d 1339 (11th Cir. 2019).",
"country": "US"
}'{ "data": { "citations": [ { "citation": "Brown v. Board of Education, 347 U.S. 483 (1954)", "status": "verified", "bluebookCitation": "Brown v. Bd. of Educ., 347 U.S. 483 (1954)", "sourceUrl": "https://www.courtlistener.com/opinion/..." }, { "citation": "Varghese v. China Southern Airlines Co., 925 F.3d 1339 (11th Cir. 2019)", "status": "unverified", "sourceUrl": null } ], "stats": { "total": 2, "verified": 1, "unverified": 1, "unavailable": 0 }, "extractedCount": 2, "truncated": false }, "requestId": "8c1f0e2a-5b7d-4e19-9a64-2d3f7b0c91e5"}Authentication
Send your key as a bearer token on every request. Keys go on your server, never in browser or mobile code. A missing or invalid key returns 401 unauthorized.
| Authorizationstring | Bearer $OC_API_KEYRequired |
|---|---|
| Content-Typestring | application/json |
| X-Request-Idstring | Your own ID for the request, echoed back as requestId. Without one we assign a UUID. Send a new one per request: an ID already billed on that endpoint returns 409. |
{ "data": { … }, "requestId": "8c1f0e2a-5b7d-4e19-9a64-2d3f7b0c91e5" } { "error": { "code": "payment_required", "message": "Insufficient balance", "requestId": "8c1f0e2a-5b7d-4e19-9a64-2d3f7b0c91e5" } }Pricing
Charges come out of a prepaid balance. A rate-limited request is never charged. A request that starts with a balance of zero or less returns 402 payment_required.
| Endpoint | Billed per | Price |
|---|---|---|
| /citations/verify | Unique citation checked. A citation repeated in one document counts once. At most 50 per request. | $0.015 |
| /citations/resolve | Unique citation in the list, at most 50 per request. | $0.015 |
| /answers | Answer. | $0.125 |
| /documents/review | Review. A contract type we don't support is not billed. | $0.10 |
| /jobs/{jobId} | Checking on a queued verify. | Free |
Errors and rate limits
Errors carry a stable code. Match on it, not on the message. A 429 carries a Retry-After header in seconds. Back off with jitter, and never retry a 4xx other than 429 unchanged.
| Status | Code | Meaning | What to do |
|---|---|---|---|
| 400 | bad_request | The body failed validation, or the answer model refused the question | Check the body against the field table |
| 400 | unsupported_jurisdiction | Verify cannot extract citations for the requested country (US only) | Send the citation strings to /citations/resolve instead |
| 400 | invalid_document_url | The url is not public https, or points at a non-public address | Host the document at a publicly reachable https URL |
| 400 | document_unreadable | The document was fetched but cannot be read: an unsupported format, too many pages, or a scan with no text layer | Send a PDF or DOCX with a text layer, or post the text |
| 400 | invalid_request_id | X-Request-Id starts with job:, a prefix reserved for internal use | Send any other X-Request-Id |
| 401 | unauthorized | Missing or invalid API key | Send a valid bearer token |
| 402 | payment_required | The balance is zero or less | Add funds |
| 409 | request_id_reused | This X-Request-Id was already billed on this endpoint | Retry with a new X-Request-Id |
| 413 | document_too_large | The document is over 500,000 characters, or the request body is over 1 MB | Split the document and send each part |
| 429 | rate_limited | Too many requests | Wait for Retry-After, then retry with backoff |
| 502 | review_failed | The model answered, but not with a usable review | Retry the request |
| 503 | async_unavailable | A url or long text was sent while the job queue is off | Send text of 100,000 characters or fewer |
| 503 | document_service_unavailable | The document service could not be reached while fetching a url | Retry. A queued job retries this on its own |
| 504 | gateway_timeout | The model did not finish in time (answers, review) | Retry once, or shorten the question or document |
Verify a document
Finds every citation in a document and checks each one. Text up to 100,000 characters returns 200 with results. A url, or longer text, returns 202 with a job.
| textstring | The document text, up to 500,000 characters.One of text or url |
|---|---|
| urlstring | A public https link to a PDF or DOCX. Always queued. |
| countrystring | Defaults to US, the only country Verify reads. For others, use Resolve. |
| citations[].statusenum | See the statuses below. |
|---|---|
| citations[].citationstring | As written in your document. |
| citations[].bluebookCitationstring | null | Bluebook form. Null when it would mean guessing a court, year or page. |
| citations[].titlestring | null | If the name doesn't match the case at that page, the case actually there. |
| citations[].caseStatusobject | null | Whether the case is still good law. |
| extractedCountinteger | Citations found. Zero means none found, not a clean document. |
| truncatedboolean | True when more than 50 were found and only 50 were checked. |
verifiedThe cited case, statute, regulation or rule was found. For a case, the case at that page is the one named.unverifiedNo match. The authority may not exist, or, for a case, the page holds a different case.unavailableCould not be checked. Tells you nothing either way.Queued requests
A 202 carries a jobId. Poll /v1/jobs/{jobId} every 2 seconds for the first 30 seconds, then every 10. Status moves from queued to running to completed or failed. A completed job's result is the same body a direct request returns. Polling is free, and has its own limit of 600 requests a minute.
curl https://public-api.opencase.com/v1/citations/verify \
-H "Authorization: Bearer $OC_API_KEY" \
-H "Content-Type: application/json" \
-d '{
"url": "https://example.com/brief.pdf",
"country": "US"
}'{ "data": { "jobId": "b7e4c2d0-1f3a-4c8e-9d52-6a0f8e3b1c47", "status": "queued" } }curl https://public-api.opencase.com/v1/jobs/b7e4c2d0-1f3a-4c8e-9d52-6a0f8e3b1c47 \
-H "Authorization: Bearer $OC_API_KEY"{ "data": { "status": "completed", "result": { "citations": [ … ] } } }Resolve citations
Checks citations you already have as a list. Covers cases, statutes, regulations and court rules, and countries beyond the US.
| citationsstring[] | 1 to 50 citations, each up to 2,000 characters.Required |
|---|---|
| countrystring | Where the citations come from. Defaults to US. |
| statusenum | Same values as Verify. |
|---|---|
| contentTypestring | null | case, statute, regulation or rule. |
| caseStatusobject | null | Whether the case is still good law. |
curl https://public-api.opencase.com/v1/citations/resolve \
-H "Authorization: Bearer $OC_API_KEY" \
-H "Content-Type: application/json" \
-d '{
"citations": [
"Brown v. Board of Education, 347 U.S. 483 (1954)",
"42 U.S.C. § 1983"
]
}'{ "data": { "citations": [ { "citation": "42 U.S.C. § 1983", "status": "verified", "contentType": "statute", … } ] } }Answer a question
Researches a legal question and returns a Markdown answer. Every citation in the answer is checked, and web sources are numbered to match the answer's [1] markers.
| questionstring | Up to 8,000 characters.Required |
|---|---|
| countryenum | Jurisdiction for the answer: US, UK, CA, AU, ZA, IE, PH or IN. Omit it to search all of them. |
| statesstring[] | Narrow a US answer to states, such as California. |
| circuitsstring[] | Narrow a US answer to federal circuits, such as 9th Circuit. |
| subdivisionsstring[] | Narrow an answer outside the US to states or provinces, such as New South Wales. |
curl https://public-api.opencase.com/v1/answers \
-H "Authorization: Bearer $OC_API_KEY" \
-H "Content-Type: application/json" \
-d '{
"question": "What is the standard for a preliminary injunction?",
"country": "US"
}'{ "data": { "answer": "Under Winter v. NRDC, a plaintiff…", "citations": [ { "status": "verified", … } ], "sources": [ … ], "stats": { "total": 3, "verified": 3, "unverified": 0 } } }Review a contract
Detects the contract type, checks the contract against our playbook for that type, and returns a finding per rule. A type we don't support returns reviewed: false and is not billed.
| textstring | Up to 500,000 characters. The first 200,000 are analyzed.Required |
|---|
| reviewedboolean | False when the document is not a contract type we review. reason says why. |
|---|---|
| contractTypestring | The detected type, e.g. nda, or none. |
| findings[]object[] | One per rule: status (pass or fail), where in the contract it was decided, and why. A failure adds the clause and suggested language. |
| answers[]object[] | Key terms read from the contract, such as the parties. |
| analyzedCharsinteger | Characters reviewed. Less than totalChars means only that much was read. |
curl https://public-api.opencase.com/v1/documents/review \
-H "Authorization: Bearer $OC_API_KEY" \
-H "Content-Type: application/json" \
-d '{
"text": "MUTUAL NONDISCLOSURE AGREEMENT…"
}'{ "data": { "reviewed": true, "contractType": "nda", "checksPassed": 5, "checksTotal": 6, "findings": [ { "ruleName": "Mutual confidentiality obligations", "status": "pass", "citation": "Section 2", … } ] } }