OpenCaseAPIAPI keys

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.

Endpoints
/citations/verify$0.015 / citation
/citations/resolve$0.015 / citation
/answers$0.125 / answer
/documents/review$0.10 / review

Quickstart

  1. 1

    Create a key

    In OpenCase Settings, open API and choose New key. Export it as OC_API_KEY.

  2. 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. 3

    Send a request

    The example sends a two-citation passage to /citations/verify.

  4. 4

    Read the response

    Results are in data, next to a requestId. 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"
  }'
Response · trimmed200 OK
{  "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.

Request headers
AuthorizationstringBearer $OC_API_KEYRequired
Content-Typestringapplication/json
X-Request-IdstringYour 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.
Every response
{ "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.

EndpointBilled perPrice
/citations/verifyUnique citation checked. A citation repeated in one document counts once. At most 50 per request.$0.015
/citations/resolveUnique citation in the list, at most 50 per request.$0.015
/answersAnswer.$0.125
/documents/reviewReview. 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.

StatusCodeMeaningWhat to do
400bad_requestThe body failed validation, or the answer model refused the questionCheck the body against the field table
400unsupported_jurisdictionVerify cannot extract citations for the requested country (US only)Send the citation strings to /citations/resolve instead
400invalid_document_urlThe url is not public https, or points at a non-public addressHost the document at a publicly reachable https URL
400document_unreadableThe document was fetched but cannot be read: an unsupported format, too many pages, or a scan with no text layerSend a PDF or DOCX with a text layer, or post the text
400invalid_request_idX-Request-Id starts with job:, a prefix reserved for internal useSend any other X-Request-Id
401unauthorizedMissing or invalid API keySend a valid bearer token
402payment_requiredThe balance is zero or lessAdd funds
409request_id_reusedThis X-Request-Id was already billed on this endpointRetry with a new X-Request-Id
413document_too_largeThe document is over 500,000 characters, or the request body is over 1 MBSplit the document and send each part
429rate_limitedToo many requestsWait for Retry-After, then retry with backoff
502review_failedThe model answered, but not with a usable reviewRetry the request
503async_unavailableA url or long text was sent while the job queue is offSend text of 100,000 characters or fewer
503document_service_unavailableThe document service could not be reached while fetching a urlRetry. A queued job retries this on its own
504gateway_timeoutThe model did not finish in time (answers, review)Retry once, or shorten the question or document
Citations

Verify a document

POST/v1/citations/verify$0.015 per citation

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.

Body
textstringThe document text, up to 500,000 characters.One of text or url
urlstringA public https link to a PDF or DOCX. Always queued.
countrystringDefaults to US, the only country Verify reads. For others, use Resolve.
Response: data
citations[].statusenumSee the statuses below.
citations[].citationstringAs written in your document.
citations[].bluebookCitationstring | nullBluebook form. Null when it would mean guessing a court, year or page.
citations[].titlestring | nullIf the name doesn't match the case at that page, the case actually there.
citations[].caseStatusobject | nullWhether the case is still good law.
extractedCountintegerCitations found. Zero means none found, not a clean document.
truncatedbooleanTrue 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.

400unsupported_jurisdiction400invalid_document_url400document_unreadable402payment_required413document_too_large429rate_limited
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"
  }'
Response · trimmed202 Accepted
{ "data": {    "jobId": "b7e4c2d0-1f3a-4c8e-9d52-6a0f8e3b1c47",    "status": "queued" } }
Then poll the job
curl https://public-api.opencase.com/v1/jobs/b7e4c2d0-1f3a-4c8e-9d52-6a0f8e3b1c47 \
  -H "Authorization: Bearer $OC_API_KEY"
Response · trimmed200 OK
{ "data": { "status": "completed",    "result": { "citations": [ … ] } } }
Citations

Resolve citations

POST/v1/citations/resolve$0.015 per citation

Checks citations you already have as a list. Covers cases, statutes, regulations and court rules, and countries beyond the US.

Body
citationsstring[]1 to 50 citations, each up to 2,000 characters.Required
countrystringWhere the citations come from. Defaults to US.
Response: data.citations[]
statusenumSame values as Verify.
contentTypestring | nullcase, statute, regulation or rule.
caseStatusobject | nullWhether the case is still good law.
400bad_request402payment_required429rate_limited
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"
    ]
  }'
Response · trimmed200 OK
{ "data": { "citations": [  { "citation": "42 U.S.C. § 1983",    "status": "verified",    "contentType": "statute", … } ] } }
Research

Answer a question

POST/v1/answers$0.125 per answer

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.

Body
questionstringUp to 8,000 characters.Required
countryenumJurisdiction 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.
400bad_request402payment_required429rate_limited504gateway_timeout
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"
  }'
Response · trimmed200 OK
{ "data": {    "answer": "Under Winter v. NRDC, a plaintiff…",    "citations": [ { "status": "verified", … } ],    "sources": [ … ],    "stats": { "total": 3, "verified": 3, "unverified": 0 } } }
Documents

Review a contract

POST/v1/documents/review$0.10 per review

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.

Body
textstringUp to 500,000 characters. The first 200,000 are analyzed.Required
Response: data
reviewedbooleanFalse when the document is not a contract type we review. reason says why.
contractTypestringThe 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.
analyzedCharsintegerCharacters reviewed. Less than totalChars means only that much was read.
402payment_required413document_too_large429rate_limited502review_failed504gateway_timeout
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…"
  }'
Response · trimmed200 OK
{ "data": {    "reviewed": true,    "contractType": "nda",    "checksPassed": 5,    "checksTotal": 6,    "findings": [      { "ruleName": "Mutual confidentiality obligations",        "status": "pass",        "citation": "Section 2", … } ] } }