Skip to main content
  • ABOUT
  • CASELAW
  • GALLERY
  • LOG IN
  • FOR COURTS
  • CONTACT
Documentation / Learning Tracks / API Learning Track / CAP API Tutorial
    • For Researchers
        • How do you want to access caselaw data?
          • Bulk Downloads
          • API
        • What level of access do you need?
        • How do I register?
        • How do I apply for researcher access?
          • Important Caveats
          • Eligibility
          • Where do I apply?
            • Harvard
            • Other Institutions
            • Others
    • For Courts
        • Digital-First Guidelines
            • Introduction
            • Digital-first publishing guidelines
              • Essential characteristics
                • Online
                • Free & Open
                • Comprehensive
                • Official
                • Citable
                • Machine Readable
              • Desirable characteristics
                • Digitally Signed
                • Versioning
                • Structured Data
                • Medium-Neutral
                • Archives
                • Search
                • Bulk
                • API
        • Case Studies
            • Case study: Arkansas
            • Case study: Canada
            • Case study: New Mexico
    • For Libraries
    • Registration
    • Search
        • Overview
        • What's included?
        • Searching in CAP is simple
          • First: Choose What To Search
          • Second: Select Your Search Criteria
          • Third: Execute the Search
        • Full-Text Case Search
          • Phrase Search
          • Exclusion
        • Tips
        • Getting Legal Help
    • API
        • API Learning Track
        • Authentication
          • Get an API Key
          • Modify The Request Headers
          • Example
          • Failure: error_auth_required
          • Browsable API
          • Sitewide Token Authentication
        • Case Text Formats
        • Pagination and Counts
          • Example
        • Endpoints
          • API Base
          • Cases Endpoint
            • Endpoint Parameters
            • Single Case Endpoint
            • Search Syntax
            • Examples
          • Reporters Endpoint
            • Endpoint Parameters
            • Examples
          • Jurisdictions Endpoint
            • Endpoint Parameters
          • Courts
            • Endpoint Parameters
          • Volumes
            • Endpoint Parameters
          • Ngrams
            • Endpoint Parameters
            • Examples
          • Citations
            • Endpoint Parameters
    • Bulk Data
        • Access Limits
        • Downloading
        • API Equivalence
        • Data Format
        • Using Bulk Data
        • Other repositories
    • Historical Trends
        • Start Here
        • Reading Results
          • Key
          • Horizontal axis
          • Vertical axis
        • Customize
          • Percentage Count/Instance Count/Scaling
          • Smoothing
        • Table view
        • Keyboard navigation
        • Download
        • Wildcard search
        • Jurisdiction search
        • Jurisdiction codes
        • Citation feature
    • API Learning Track
        • Intro to APIs
        • CAP API Tutorial
            • Intro: Browsable API
            • Intro to JSON
            • curl
            • Overview of the endpoints
            • Dig-in With Real Queries
            • Next Steps
            • Wrap-up
        • CAP API In Depth
            • Getting Started
              • Making Basic Queries
              • Filtering
              • Search
                • Full-text Search
                • Filtering by Groups or Ranges
              • Sorting
              • Types of Data You Can Query
            • Getting Full Case Text
            • Authentication
              • Find your API Key
              • Modify Your Headers
                • curl
                • python requests library
                • Other Environments
              • Doesn't work?
                • error_auth_required
                • error_limit_exceeded
            • Data Formats
              • Structured Casebody Text
            • Other Endpoints
    • Access Limits
        • Exceptions
        • Open Jurisditions
        • Research Access
        • Commercial Licensing
        • User Types and Permissions
          • Unregistered Users
          • Registered Users
          • Researchers
          • Commercial Users
    • Stability and Changes
    • Reporting Problems
        • Misspelled Words
        • Website Errors
        • Metadata Errors
    • Documentation Glossary
        • API
        • Character
        • Special Character
        • Command Line
        • curl
        • Endpoint
        • Jurisdiction
        • OCR
        • RESTful
        • Reporter
        • Server
        • Slug
        • String
        • Top-Level Domain
        • URL
        • URL Parameter
        • URL Path
        • Open Jurisdiction
        • Restricted Jurisdiction
        • Cursor
    • Data Specifications
        • Bulk
          • Structure
          • Data Format
        • API
          • Individual Records
          • Query Results
        • Individual Objects
          • Case
            • Casebody
            • Analysis Fields
          • Jurisdiction
          • Court
          • Volume
          • Reporter
          • Citation
          • Ngrams
    • Changelog
        • August 28 2020
        • August 2020
        • June 2020
        • April 2020
        • March 2020
        • February 2020
        • January 24, 2020
        • January 19, 2020
        • January 16, 2020
        • January 9, 2020
        • December 6, 2019
        • October 1, 2019
        • July 31, 2019
        • June 19, 2019

If you're generally familiar with RESTful APIs but would like a gentler introduction to our API than our documentation affords, you're in the right place. If you're not comfortable with RESTful APIs and would like a generalized introduction to them, try our Beginner's Introduction to APIs. If you've had enough and would prefer just to access the cases using a human-centric interface, please check out our search tool.

Intro: Browsable API

Let's query the CAP API using a web browser.

In a separate tab, navigate to https://api.case.law/

{
    "cases": "https://api.case.law/v1/cases/",
    "jurisdictions": "https://api.case.law/v1/jurisdictions/",
    "courts": "https://api.case.law/v1/courts/",
    "volumes": "https://api.case.law/v1/volumes/",
    "reporters": "https://api.case.law/v1/reporters/",
    "ngrams": "https://api.case.law/v1/ngrams/",
    "user_history": "https://api.case.law/user_history/",
    "citations": "https://api.case.law/v1/citations/"
}

Congratulations! You just executed your first query to the CAP API! While the results might not be incredibly exciting, it's the first step towards doing fantastic work.

You might first notice the unusual, code-ish-looking format of this data. It's called JSON, or JavaScript Object Notation, and we'll look into that soon. You probably also recognized some of the terms on the left, such as cases, jurisdictions, courts, etc. Each is the name of an API endpoint, through which you receive one type of data. For example, to find a court, you might use the /courts endpoint. Click on the URL to the right of "courts."

{
    "count": 3117,
    "next": "https://api.case.law/v1/courts/?cursor=cD1BdWJ1cm4rQ2l0eStDb3VydA%3D%3D",
    "previous": null,
    "results": [
        {
            "id": 25221,
            "url": "https://api.case.law/v1/courts/sc-2/",
            "name": "",
            "name_abbreviation": "S.C.",
            "jurisdiction": "S.C.",
            "jurisdiction_url": "https://api.case.law/v1/jurisdictions/sc/",
            "slug": "sc-2"
        },
        {
            "id": 15658,
            "url": "https://api.case.law/v1/courts/accomack-cty-cir-ct/",
            "name": "Accomack County Circuit Court",
            "name_abbreviation": "Accomack Cty. Cir. Ct.",
            "jurisdiction": "Va.",
            "jurisdiction_url": "https://api.case.law/v1/jurisdictions/va/",
            "slug": "accomack-cty-cir-ct"
        },
    […]

Whoa! That's a lot more data! Before we continue, let's take a look at the JSON format.

Intro to JSON

JSON, or JavaScript Object Notation, is a simple but flexible way to represent data in text. What people do with this format can be quite complex, but we won't need to dive too deep to understand the API contents.

Let's start with a bit of simple example data in the form of a shopping list to get us started.

  • Grocery Store:
    • 3 apples
    • 1 galangal knob
    • 7 cans of SPAM
    • 1 gallon apple cider
  • Hardware Store:
    • 1 finishing nail
    • 1 small bag of 20oz hammers

JSON has several ways to store individual pieces of data:

  • a string, e.g. "apple" (which is always in double-quotes)
  • a number, e.g. 7
  • true/false
  • null (essentially an explicit way of saying "there is no value.")

JSON has several ways to store multiple pieces of data:

  • an array, a simple list of any of these things, e.g. ["apple", "can of spam", "apple cider"]
  • an object, a type of list in which each thing in the list has a label, e.g. {"name": "CAP'n Crunch", "rank": "Admiral"}

This is all simpler than it might initially sound. For example, one of the more straightforward ways we could store our grocery list above is by using an array.

[ "apple",
 "apple",
 "apple",
 "galangal knob",
 "can of SPAM",
 "can of SPAM",
 "can of SPAM",
 "can of SPAM",
 "pouch of SPAM",
 "pouch of SPAM",
 "pouch of SPAM",
 "gallon apple cider",
 "small bag of 20oz hammers",
 "finishing nail" ]

Pretty simple but pretty inefficient. We can make it more efficient by using objects. We'll make the name of each grocery item the label of the item element, and then we'll make the value of each element the quantity.

{
  "apple": 3,
  "galangal knob": 1,
  "can of SPAM": 4,
  "pouch of SPAM": 3,
  "gallon apple cider": 1,
  "small bag of 20oz hammers": 1,
  "finishing nail": 1 
}

Wow, that's a lot more efficient, but it sure would be nice to see the store to locate each item.

{
      "apple": {
        "store": "grocery",
        "quantity": 3
      },
      "galangal knob": {
        "store": "grocery",
        "quantity": 1
      },
      "can of SPAM": {
        "store": "grocery",
        "quantity": 4
      },
      "pouch of SPAM":{
        "store": "grocery",
        "quantity": 3
      },
      "gallon apple cider":{
        "store": "grocery",
        "quantity": 1
      },
      "small bag of 20oz hammers": {
        "store": "hardware",
        "quantity": 1
      },
      "finishing nail": {
        "store": "hardware",
        "quantity": 1
      },
    }
}

Oof, that's even bulkier than the list. Let's add some hierarchy. Within the base JSON object, we'll have two objects — one for each store. Then, within each store, we'll have each of the items we want to purchase at that store.

{
  "grocery": {
    "apple": {
      "quantity": 3
    },
    "galangal knob": {
      "quantity": 1
    },
    "can of SPAM": {
      "quantity": 4
    },
    "pouch of SPAM":{
      "quantity": 3
    },
    "gallon apple cider":{
      "quantity": 1
    }
  },
  "hardware": {
    "small bag of 20oz hammers": {
      "quantity": 1
    },
    "finishing nail": {
      "quantity": 1
    },
  }
}

It is getting better! We could optimize that SPAM entry, though--- let's change our structure so it can handle variety.

{
  "grocery": {
    "apple": {
      "quantity": 3
    },
    "galangal knob": {
      "quantity": 1
    },
    "SPAM":{
      "pouch": 3,
      "can": 4
    },
    "gallon apple cider":{
      "quantity": 1
    }
  },
  "hardware": {
    "small bag of 20oz hammers": {
      "quantity": 1
    },
    "finishing nail": {
      "quantity": 1
    },
  }
}

Great. We've converted our human-readable grocery list into a data structure easily usable by both humans and computers. So how can you use this data in your environment? Almost all modern programming languages and data tools support ingesting data in JSON. Consult your environment's documentation for info on how to ingest and access JSON data.

curl

In practice, people rarely use web browsers to perform this work. Copying and pasting all of that data is hugely inefficient and doesn't allow a computer program to take in data, process it, and request new, dynamic data as a result. Let's look at the most commonly used option, which doesn't require any programming knowledge: curl.

From your computer's command line or terminal, curl can download the data from any URL and display it on a screen or save it to a file. Help to install curl on your system is a quick google search away. Many systems, such as Linux and macOS, have curl preinstalled.

$ curl https://api.case.law/
{"cases":"https://api.case.law/","jurisdictions":"https://api.case.law/v1/jurisdictions/","courts":"https://api.case.law/v1/courts/","volumes":"https://api.case.law/v1/volumes/","reporters":"https://api.case.law/v1/reporters/","ngrams":"https://api.case.law/v1/ngrams/","user_history":"https://api.case.law/user_history/","citations":"https://api.case.law/v1/citations/"}

Browsable API Link

Hmm... that's not very readable. On macOS and Linux, we can format the output using the json_pp utility:

curl https://api.case.law/ | json_pp
{
   "reporters" : "https://api.case.law/v1/reporters/",
   "courts" : "https://api.case.law/v1/courts/",
   "jurisdictions" : "https://api.case.law/v1/jurisdictions/",
   "ngrams" : "https://api.case.law/v1/ngrams/",
   "user_history" : "https://api.case.law/user_history/",
   "citations" : "https://api.case.law/v1/citations/",
   "volumes" : "https://api.case.law/v1/volumes/",
   "cases" : "https://api.case.law/v1/cases/"
}

Browsable API Link

Now that's more like it. We can also save the output to a JSON file:

curl https://api.case.law/ | json_pp > test_output.json

Now we have a file called test_output.json, which contains the JSON of our query. The Windows process is similar, but not all of the utilities come preinstalled, and a walkthrough of that process is out of this tutorial's scope. Fortunately, querying and saving JSON data is a fairly common task, and you should be able to find a fair amount of information about doing so on the internet.

Overview of the endpoints

Let's take a look at the output of our example command:

curl https://api.case.law/ | json_pp
{
    "cases": "https://api.case.law/v1/cases/",
    "jurisdictions": "https://api.case.law/v1/jurisdictions/",
    "courts": "https://api.case.law/v1/courts/",
    "volumes": "https://api.case.law/v1/volumes/",
    "reporters": "https://api.case.law/v1/reporters/",
    "ngrams": "https://api.case.law/v1/ngrams/",
    "user_history": "https://api.case.law/user_history/",
    "citations": "https://api.case.law/v1/citations/"
}

Browsable API Link

We see a JSON object with cases, jurisdictions, courts, volumes, reporters, ngrams, user_history, and citations. If you're familiar with legal texts, most of those terms probably look familiar to you. Other names, such as ngrams and user_history, aren't standard legal terms. You can get a description of endpoints, their arguments, and their output in the API Reference. Let's start with a simple query to the base courts endpoint.

curl https://api.case.law/v1/courts/
{
   "previous" : null,
   "next" : "https://api.case.law/v1/courts/?cursor=cD1BdWJ1cm4rQ2l0eStDb3VydA%3D%3D",
   "count" : 3117,
   "results" : [
      {
         "jurisdiction_url" : "https://api.case.law/v1/jurisdictions/sc/",
         "id" : 25221,
         "jurisdiction" : "S.C.",
         "slug" : "sc-2",
         "name_abbreviation" : "S.C.",
         "name" : "",
         "url" : "https://api.case.law/v1/courts/sc-2/"
      },
      {
         "url" : "https://api.case.law/v1/courts/accomack-cty-cir-ct/",
         "jurisdiction" : "Va.",
         "slug" : "accomack-cty-cir-ct",
         "name_abbreviation" : "Accomack Cty. Cir. Ct.",
         "jurisdiction_url" : "https://api.case.law/v1/jurisdictions/va/",
         "id" : 15658,
         "name" : "Accomack County Circuit Court"
      },
      [...]

Browsable API Link

Wow, that's a lot of stuff! Scroll up to the top of the output, and let's take a look at the first three arguments, but in reverse order:

Count: 3117

This shows the number of results returned by your query. Since we didn't add any filters or other parameters to our query, this number tells us that our API contains 3,117 court entries.

Next: (a URL)

Since any given query could return thousands of results, for the sake of server performance, we can serve 100 per request, maximum. This URL is where we would go to fetch the next 100 results. Breaking it down a bit further, we can see that the base URL is the same, but now there's the cursor parameter, which is generated by the server, and specific to your results set.

Previous: null

Previous does the same thing as Next but helps us find our way back instead of forward. Since we're on the first "page" of results here, this value is null.

Let's see how this looks with some live queries.

Dig-in With Real Queries

This is a simple query to the jurisdictions endpoint. There are no parameters to this query, which is where we would have submitted any query filters, so it should return all jurisdictions.

Either execute it with curl or visit the URL in your browser to see the output.

curl https://api.case.law/v1/jurisdictions/

{
    "count": 63,
    "next": null,
    "previous": null,
    "results": [
        {
            "url": "<https://api.case.law/v1/jurisdictions/ala/>",
            "id": 23,
    [...]

Browsable API Link

This returns a complete list of jurisdictions in our data set. While having a list of all jurisdictions could be useful in some circumstances, let's refine the query to see which of these jurisdictions is open. We can accomplish this by adding a filter argument saying the "whitelisted" field should be true. (again, you can get a full list of arguments and their possible values in the API Reference.)

curl <https://api.case.law/v1/jurisdictions/?whitelisted=true>

{
    "count": 4,
    "next": null,
    "previous": null,
    "results": [
        {
            "url": "https://api.case.law/v1/jurisdictions/ark/",
            "id": 34,
            "slug": "ark",
            "name": "Ark.",
            "name_long": "Arkansas",
            "whitelisted": true
        },
        {
            "url": "https://api.case.law/v1/jurisdictions/ill/",
            "id": 29,
            "slug": "ill",
            "name": "Ill.",
            "name_long": "Illinois",
            "whitelisted": true
        },
        {
            "url": "https://api.case.law/v1/jurisdictions/nc/",
            "id": 5,
            "slug": "nc",
            "name": "N.C.",
            "name_long": "North Carolina",
            "whitelisted": true
        },
        {
            "url": "https://api.case.law/v1/jurisdictions/nm/",
            "id": 52,
            "slug": "nm",
            "name": "N.M.",
            "name_long": "New Mexico",
            "whitelisted": true
        }
    ]
}

Browsable API Link

Well, that narrowed it down a bit. While this is certainly a manageable list, let's refine it again using an additional filter parameter for the heck of it.

curl https://api.case.law/v1/jurisdictions/?name=N.C.&whitelisted=true

{
    "count": 1,
    "next": null,
    "previous": null,
    "results": [
        {
            "url": "https://api.case.law/v1/jurisdictions/nc/",
            "id": 5,
            "slug": "nc",
            "name": "N.C.",
            "name_long": "North Carolina",
            "whitelisted": true
        }
    ]
}

Browsable API Link

Ok, well now we've got one result. What can we do with it? Let's see which reporter series are available for that jurisdiction by heading on over to the reporters endpoint, and using this jurisdiction slug as a filter:

curl https://api.case.law/v1/reporters/?jurisdictions=nc

{
    "count": 2,
    "next": null,
    "previous": null,
    "results": [
        {
            "id": 365,
            "url": "https://api.case.law/v1/reporters/365/",
            "full_name": "North Carolina Court of Appeals Reports",
            "short_name": "N.C. App.",
            "start_year": 1963,
            "end_year": 2014,
            "jurisdictions": [
                {
                    "url": "https://api.case.law/v1/jurisdictions/nc/",
                    "id": 5,
                    "slug": "nc",
                    "name": "N.C.",
                    "name_long": "North Carolina",
                    "whitelisted": true
                }
            ],
            "frontend_url": "https://cite.case.law/nc-app/"
        },
        {
            "id": 549,
            "url": "https://api.case.law/v1/reporters/549/",
            "full_name": "North Carolina Reports",
            "short_name": "N.C.",
            "start_year": 1778,
            "end_year": 2017,
            "jurisdictions": [
                {
                    "url": "https://api.case.law/v1/jurisdictions/nc/",
                    "id": 5,
                    "slug": "nc",
                    "name": "N.C.",
                    "name_long": "North Carolina",
                    "whitelisted": true
                }
            ],
            "frontend_url": "https://cite.case.law/nc/"
        }
    ]
}

Browsable API Link

Ok, great — 2 reporters. Let's choose one, "N.C. App.", and head over to the cases endpoint. If we look at the cases endpoint in the API Reference, we can see that the reporter filter parameter takes a reporter id as the argument.

curl https://api.case.law/v1/cases/?reporter=365

{
    "count": 26755,
    "next": "https://api.case.law/v1/cases/?cursor=eyJwIjogWzAuMCwgIjE5NjgtMDYtMTIiLCA4NTUzMzgyXX0%3D&reporter=365",
    "previous": null,
    "results": [
        {
            "id": 8555137,
    [...]

Browsable API Link

Let's refine those cases to get only cases decided in 2000. We can use the decision_date__gte and decision_date__lte parameters for that!

curl https://api.case.law/v1/cases/?reporter=365&decision_date__gte=2000&decision_date__lte=2001

{
    "count": 514,
    "next": "https://api.case.law/v1/cases/?cursor=eyJwIjogWzAuMCwgIjIwMDAtMDMtMjEiLCAxMTA5MjQyNV19&decision_date__gte=2000&decision_date__lte=2001&reporter=365",
    "previous": null,
    "results": [
        {
            "id": 11239345,
    [...]

Browsable API Link

And now let's find cases that only mention fraud in their text.

curl https://api.case.law/v1/cases/?search=fraud&reporter=365&decision_date__gte=2000&decision_date__lte=2001

{
    "count": 50,
    "next": null,
    "previous": null,
    "results": [
        {
            "id": 9497365,
    [...]

Browsable API Link

Great. Now let's get all of the case texts associated with each of those cases, using the full_case parameter.

curl https://api.case.law/v1/cases/?search=fraud&reporter=365&decision_date__gte=2000&decision_date__lte=2001&full_case=true

{
    "count": 50,
    "next": null,
    "previous": null,
    "results": [
        {
            "id": 9497365,
            [...]
             "casebody": {
                    "status": "ok",
                    "data": {
                        "head_matter": "THE JAY GROUP, LTD.[...]

Browsable API Link

There you have it. We've walked through different endpoints in the API to narrow down our search to get a pretty specific set of cases, with their full case text.

Next Steps

Would you like to see how this works in a real application? Head over to our search tool, construct a query, and click on the 'SHOW API CALL' link below the search button. The URL box below the search form will update as you change your search terms. You can hover over each field in the URL to highlight its counterpart in the search form or hover over each input box in the search form to highlight its counterpart in the URL. When you've constructed the query, click on the API URL to head over to the API, or click on the search button to use our search feature.

Also, check out our gallery to see how researchers, developers, and other folks have used CAP data. We're continually amazed by the ways people put this data to work.

If you'd like to dig in and get your hands dirty, the API user guide is where you want to go. It gives you everything you need to make the most out of our data. If you think your use case might be better served by downloading large amounts of data and working with it locally, check out our Bulk Data.

Wrap-up

OK! That about does it for our beginner's introduction to web-based APIs. If you want more, head on to our In-Depth Tutorial.

Thanks, and good luck!

  • Find what you were looking for?

    If you have suggestions for improving this documentation, let us know!

CAP API Tutorial

Learn how to query the CAP API using different types of data.

©2021 The President and Fellows of Harvard University. Site text is licensed CC BY-SA 4.0. Source code is MIT licensed. Harvard asserts no copyright in caselaw retrieved from this site.

  • TERMS
  • PRIVACY
  • ACCESSIBILITY