API
The OLDP API is based on Django REST Framework and provides programmatic access to legal data including cases, laws, courts, and law books.
Base URL
All API requests should be made to:
https://de.openlegaldata.io/api/
Authentication
The API supports two authentication methods:
1. API Tokens (Recommended)
API tokens provide secure, fine-grained access control to API resources. You can create and manage multiple tokens with different permission levels in your account settings.
How to get your API token:
Log in to your account
Navigate to your profile settings
Go to the “API Access” section
Create a new token with a descriptive name
Copy the token (it will only be shown once!)
Using your token in requests:
Add the token to the Authorization header using the Token prefix:
curl -X GET "https://de.openlegaldata.io/api/cases/" \
-H "Authorization: Token YOUR_API_TOKEN_HERE" \
-H "Accept: application/json"
2. Session Authentication
For web-based clients, you can use standard Django session authentication with your username and password.
Permission System
API tokens use a fine-grained permission system that controls access to specific resources and actions.
Permission Levels
Permissions are defined by resource and action:
Resources:
cases,laws,courts,lawbooks,references,annotationsActions:
read,write,delete
Default Permissions
By default, new API tokens are assigned to the “default” permission group which provides:
✅ cases:read - Read access to cases
✅ laws:read - Read access to laws
✅ courts:read - Read access to courts
✅ lawbooks:read - Read access to law books
This ensures secure, read-only access by default. Write and delete permissions must be explicitly granted by administrators.
Permission Groups
Administrators can create custom permission groups with specific combinations of permissions. Tokens are assigned to permission groups, making it easy to manage access for different use cases:
default: Read-only access to core resources
read_write: Read and write access to specific resources
full_access: Complete access including delete operations
Contact the administrators if you need elevated permissions for your API token.
Throttle Rates
To ensure fair usage and maintain service quality, the API implements rate limiting:
Anonymous users: 100 requests per day
Authenticated users: 5,000 requests per hour
If you need higher limits, please contact us or consider using our data dumps for bulk access.
API Endpoints
Cases
List all cases:
curl -X GET "https://de.openlegaldata.io/api/cases/" \
-H "Authorization: Token YOUR_API_TOKEN_HERE" \
-H "Accept: application/json"
Filter cases by court:
curl -X GET "https://de.openlegaldata.io/api/cases/?court_id=3" \
-H "Authorization: Token YOUR_API_TOKEN_HERE" \
-H "Accept: application/json"
Get a specific case:
curl -X GET "https://de.openlegaldata.io/api/cases/12345/" \
-H "Authorization: Token YOUR_API_TOKEN_HERE" \
-H "Accept: application/json"
Filter by date range:
curl -X GET "https://de.openlegaldata.io/api/cases/?date_after=2020-01-01&date_before=2023-12-31" \
-H "Authorization: Token YOUR_API_TOKEN_HERE" \
-H "Accept: application/json"
Laws
Field availability: the list endpoint (
/api/laws/) returns summary records without thecontentfield, mirroring how/api/cases/behaves. Use the detail endpoint (/api/laws/<id>/) to retrieve a law section’s full HTML body. This keeps bulk pagination cheap on bandwidth and origin CPU; for whole-dataset access prefer the data dumps.
List all laws (no content):
curl -X GET "https://de.openlegaldata.io/api/laws/" \
-H "Authorization: Token YOUR_API_TOKEN_HERE" \
-H "Accept: application/json"
Filter laws by book:
curl -X GET "https://de.openlegaldata.io/api/laws/?book_id=5" \
-H "Authorization: Token YOUR_API_TOKEN_HERE" \
-H "Accept: application/json"
Get a specific law (includes content):
curl -X GET "https://de.openlegaldata.io/api/laws/123/" \
-H "Authorization: Token YOUR_API_TOKEN_HERE" \
-H "Accept: application/json"
Law Books
List all law books:
curl -X GET "https://de.openlegaldata.io/api/lawbooks/" \
-H "Authorization: Token YOUR_API_TOKEN_HERE" \
-H "Accept: application/json"
Get a specific law book:
curl -X GET "https://de.openlegaldata.io/api/lawbooks/bgb/" \
-H "Authorization: Token YOUR_API_TOKEN_HERE" \
-H "Accept: application/json"
Filter by code:
curl -X GET "https://de.openlegaldata.io/api/lawbooks/?code=BGB" \
-H "Authorization: Token YOUR_API_TOKEN_HERE" \
-H "Accept: application/json"
Courts
List all courts:
curl -X GET "https://de.openlegaldata.io/api/courts/" \
-H "Authorization: Token YOUR_API_TOKEN_HERE" \
-H "Accept: application/json"
Filter courts by type:
curl -X GET "https://de.openlegaldata.io/api/courts/?court_type=AG" \
-H "Authorization: Token YOUR_API_TOKEN_HERE" \
-H "Accept: application/json"
Get a specific court:
curl -X GET "https://de.openlegaldata.io/api/courts/ag-berlin/" \
-H "Authorization: Token YOUR_API_TOKEN_HERE" \
-H "Accept: application/json"
Pagination
API responses are paginated. Use the limit and offset parameters to navigate through results:
# Get first 50 results
curl -X GET "https://de.openlegaldata.io/api/cases/?limit=50&offset=0" \
-H "Authorization: Token YOUR_API_TOKEN_HERE" \
-H "Accept: application/json"
# Get next 50 results
curl -X GET "https://de.openlegaldata.io/api/cases/?limit=50&offset=50" \
-H "Authorization: Token YOUR_API_TOKEN_HERE" \
-H "Accept: application/json"
The response includes pagination metadata:
{
"count": 1234,
"next": "https://de.openlegaldata.io/api/cases/?limit=50&offset=50",
"previous": null,
"results": [...]
}
Search
Search cases by text:
curl -X GET "https://de.openlegaldata.io/api/cases/search/?text=urheberrecht" \
-H "Authorization: Token YOUR_API_TOKEN_HERE" \
-H "Accept: application/json"
Search laws:
curl -X GET "https://de.openlegaldata.io/api/laws/search/?text=vertragsrecht" \
-H "Authorization: Token YOUR_API_TOKEN_HERE" \
-H "Accept: application/json"
Search supports Lucene syntax for complex queries:
curl -X GET "https://de.openlegaldata.io/api/cases/search/?text=urheberrecht+AND+software" \
-H "Authorization: Token YOUR_API_TOKEN_HERE" \
-H "Accept: application/json"
text is required. Optional filters that compose with the keyword
query (logical AND):
Param |
Notes |
|---|---|
|
|
|
Restrict to cases citing a specific section (case search only — silently ignored on |
|
Restrict to cases citing the case with this id |
|
Include the full |
# Cases citing § 823 BGB that mention "Mietrecht"
curl -G "https://de.openlegaldata.io/api/cases/search/" \
--data-urlencode 'text=Mietrecht' \
--data-urlencode 'cited_law_book=bgb' \
--data-urlencode 'cited_law_section=823' \
-H "Authorization: Token $OLDP_API_TOKEN"
See Search for the full filter matrix across the web, REST, and MCP surfaces.
Citations & Cross-References
The citation graph is queryable in three complementary ways. The same
data is also available via the MCP server — the REST
nested actions and the MCP tools share a single service layer, so
payload shapes match across the two agent-facing surfaces. The
human-facing web search at /search/?cited_law_book=…&cited_law_section=…
(or ?cited_case=<id>) renders the same Elasticsearch-backed result
set with facets and pagination.
Nested actions on cases & laws
Map 1:1 to the natural questions about a single case or law section.
Endpoint |
Returns |
Backend |
|---|---|---|
|
Forward refs emitted by this case (laws + cases it cites) |
SQL |
|
Cases whose body cites this case |
Elasticsearch |
|
Laws whose body cites this case |
SQL |
|
Forward refs emitted by this law |
SQL |
|
Cases whose body cites this law section |
Elasticsearch |
|
Laws whose body cites this law section |
SQL |
The references/ endpoints return a single dict
(total_law_references, total_case_references,
law_references[], case_references[],
references_extracted_at). The citing_* endpoints return a
paginated list of summary records — content is omitted on these
list-style responses for both cases and laws; fetch the detail endpoint
when the body HTML is actually needed.
For laws, the citing-cases lookup is keyed by (book_slug, section_slug) against the CaseIndex.cited_laws field. The slug
pair is stable across book revisions, so older citation rows pinned
to non-latest revisions still surface — no (book_code, section)
sibling expansion needed at query time.
Elasticsearch dependency on citing-cases endpoints
/api/cases/<id>/citing_cases/ and /api/laws/<id>/citing_cases/
read from Elasticsearch (CaseIndex.cited_cases and
CaseIndex.cited_laws respectively). When ES is unavailable these
endpoints return 503 with a structured body so clients can
differentiate transient warm-up from a hard outage:
// 503 — transient timeout, agent should retry
{
"detail": "Search timed out while warming caches. Retry the same query in a few seconds.",
"code": "search_backend_timeout",
"retryable": true,
"hint": "First-touch queries on large result sets read ES segments from disk; the same query is sub-100ms on the next attempt."
}
// 503 — hard outage
{
"detail": "Search backend is currently unavailable. Please try again later.",
"code": "search_backend_unavailable"
}
See docs/elasticsearch.md for the underlying index fields and the reindex command an operator must run after upgrading a release that changes either field’s shape.
# What does case 12345 cite?
curl -X GET "https://de.openlegaldata.io/api/cases/12345/references/" \
-H "Authorization: Token $OLDP_API_TOKEN"
# Which cases cite § 823 BGB?
curl -X GET "https://de.openlegaldata.io/api/laws/<law-id>/citing_cases/" \
-H "Authorization: Token $OLDP_API_TOKEN"
Flat /api/references/
For cross-cutting queries the nested actions can’t express. Filter by either numeric IDs or slugs (no id round-trip required):
Filter |
Field |
|---|---|
|
the source case whose body emitted the cite |
|
same, by slug |
|
source law (id) |
|
source law section slug |
|
source law book slug |
|
target case (id) |
|
target case (slug) |
|
target law (id) |
|
target law section slug |
|
target law book slug |
`assigned=true |
false` |
Filters compose. Examples:
# Every reference involving § 823 BGB as the target, by slug
curl -X GET "https://de.openlegaldata.io/api/references/?cites_law__book__slug=bgb&cites_law__slug=823" \
-H "Authorization: Token $OLDP_API_TOKEN"
# Refs emitted by laws within the BGB book pointing at any law
curl -X GET "https://de.openlegaldata.io/api/references/?cited_by_law__book__slug=bgb&cites_law__isnull=False" \
-H "Authorization: Token $OLDP_API_TOKEN"
# Refs from a specific case (slug) to assigned targets only
curl -X GET "https://de.openlegaldata.io/api/references/?cited_by_case__slug=bgh-vi-zr-123-22&assigned=true" \
-H "Authorization: Token $OLDP_API_TOKEN"
Each row carries the source (cited_by), the target (case or law),
the marker text (the literal citation as it appeared in the source),
and the unresolved free-form to field used during extraction.
Citation validation
GET /api/citations/validate/?citation=...&type=... checks whether a
free-form German legal citation (Aktenzeichen, ECLI, or paragraph
reference) exists in the local DB.
curl -G "https://de.openlegaldata.io/api/citations/validate/" \
--data-urlencode 'citation=§ 823 BGB' \
-H "Authorization: Token $OLDP_API_TOKEN"
# {"found": true, "type": "law", "matches": [...]}
curl -G "https://de.openlegaldata.io/api/citations/validate/" \
--data-urlencode 'citation=VI ZR 123/22' \
-H "Authorization: Token $OLDP_API_TOKEN"
# {"found": true, "type": "case", "matches": [...]}
type defaults to auto (sniff from the input shape). Force a
specific parse with type=file_number, type=ecli, or
type=law_reference.
My Resources (/me/)
The /me/ endpoints let you view resources you have created with your API token.
This is useful for tracking submissions and checking their review status.
For detailed documentation, see My Resources API.
List your cases:
curl -X GET "https://de.openlegaldata.io/api/me/cases/" \
-H "Authorization: Token YOUR_API_TOKEN_HERE" \
-H "Accept: application/json"
List your law books:
curl -X GET "https://de.openlegaldata.io/api/me/law_books/" \
-H "Authorization: Token YOUR_API_TOKEN_HERE"
User profile and token info:
curl -X GET "https://de.openlegaldata.io/api/me/" \
-H "Authorization: Token YOUR_API_TOKEN_HERE"
Creating and Updating Resources
Note: Write operations require a token with appropriate write permissions.
Case Creation API
For detailed documentation on creating cases programmatically, including automatic court resolution, duplicate handling, and reference extraction, see the Case Creation API Documentation.
Create a new case (requires cases:write permission):
curl -X POST "https://de.openlegaldata.io/api/cases/?extract_refs=true" \
-H "Authorization: Token YOUR_API_TOKEN_HERE" \
-H "Content-Type: application/json" \
-H "Accept: application/json" \
-d '{
"court_name": "Bundesgerichtshof",
"file_number": "I ZR 123/21",
"date": "2021-05-15",
"content": "<p>Full case content in HTML...</p>",
"type": "Urteil"
}'
The API automatically resolves the court from the court_name field. Use ?extract_refs=true (default) to extract legal references from the content, or ?extract_refs=false to disable.
Update an existing case (requires cases:write permission):
curl -X PATCH "https://de.openlegaldata.io/api/cases/12345/" \
-H "Authorization: Token YOUR_API_TOKEN_HERE" \
-H "Content-Type: application/json" \
-H "Accept: application/json" \
-d '{
"title": "Updated Case Title"
}'
Court Creation API
For detailed documentation on creating courts programmatically, including automatic state/city resolution, duplicate handling, and review workflow, see the Court Creation API Documentation.
Create a new court (requires courts:write permission):
curl -X POST "https://de.openlegaldata.io/api/courts/" \
-H "Authorization: Token YOUR_API_TOKEN_HERE" \
-H "Content-Type: application/json" \
-H "Accept: application/json" \
-d '{
"name": "Amtsgericht Berlin-Mitte",
"code": "AGBERLINMITTE",
"state_name": "Berlin",
"court_type": "AG",
"city_name": "Berlin"
}'
The API automatically resolves the state and city from their names. Courts created via API are set to review_status="pending" until approved by an administrator.
Delete a resource (requires appropriate delete permission):
curl -X DELETE "https://de.openlegaldata.io/api/cases/12345/" \
-H "Authorization: Token YOUR_API_TOKEN_HERE" \
-H "Accept: application/json"
Error Handling
The API uses standard HTTP status codes:
200 OK: Request successful
201 Created: Resource created successfully
400 Bad Request: Invalid request parameters
401 Unauthorized: Missing or invalid authentication
403 Forbidden: Insufficient permissions
404 Not Found: Resource not found
429 Too Many Requests: Rate limit exceeded
500 Internal Server Error: Server error
Example error response:
{
"detail": "Authentication credentials were not provided."
}
Permission denied response:
{
"detail": "You do not have permission to perform this action."
}
Response Formats
The API supports multiple response formats via the Accept header:
JSON (default):
Accept: application/jsonXML:
Accept: application/xmlBrowsable API:
Accept: text/html(for web browsers)
Best Practices
Use HTTPS: Always use HTTPS to protect your API token
Store tokens securely: Never commit tokens to version control
Use environment variables: Store your token in environment variables:
export OLDP_API_TOKEN="your_token_here" curl -H "Authorization: Token $OLDP_API_TOKEN" ...
Handle rate limits: Implement exponential backoff when you receive 429 responses
Use pagination: Don’t fetch all results at once; use pagination for large datasets
Monitor token usage: Check your token’s last used timestamp in your account settings
Rotate tokens regularly: Create new tokens periodically and revoke old ones
Use specific permissions: Request only the permissions you need for your use case
Examples
Complete Example: Fetching Cases from a Specific Court
#!/bin/bash
# Set your API token
export OLDP_API_TOKEN="your_token_here"
export BASE_URL="https://de.openlegaldata.io/api"
# 1. Find the court ID
echo "Finding court..."
COURT_ID=$(curl -s -X GET "$BASE_URL/courts/?code=BGH" \
-H "Authorization: Token $OLDP_API_TOKEN" \
-H "Accept: application/json" | jq -r '.results[0].id')
echo "Court ID: $COURT_ID"
# 2. Fetch cases from this court
echo "Fetching cases..."
curl -s -X GET "$BASE_URL/cases/?court_id=$COURT_ID&limit=10" \
-H "Authorization: Token $OLDP_API_TOKEN" \
-H "Accept: application/json" | jq '.results[] | {title, date, file_number}'
Example: Exporting Data to CSV
#!/bin/bash
export OLDP_API_TOKEN="your_token_here"
export BASE_URL="https://de.openlegaldata.io/api"
# Fetch and convert to CSV
curl -s -X GET "$BASE_URL/cases/?limit=100" \
-H "Authorization: Token $OLDP_API_TOKEN" \
-H "Accept: application/json" | \
jq -r '.results[] | [.id, .title, .date, .court.name] | @csv' > cases.csv
echo "Exported to cases.csv"
Data Dumps and Bulk Downloads
For bulk access, prefer the dump_api_data management command over making
thousands of API requests. It produces gzipped JSONL files plus a snapshot
manifest. See Data Dumps & Bulk Downloads for full
details.