API Reference

Complete reference for the Moonlit Legal Intelligence API. Search Dutch and European legal documents, retrieve full texts, and interact with Luna, our AI research assistant.

Base URL

https://api.moonlit.ai/v1.1

Authentication

Ocp-Apim-Subscription-Key

Rate Limit

50,000 requests / month

Response Format

JSON

Authentication

All API requests must include your subscription key in the Ocp-Apim-Subscription-Key header. Get in touch with our team to get your API key.

Keep your API key secret. Do not expose it in client-side code or public repositories. If your key is compromised, contact our team immediately.

curl -X POST "https://api.moonlit.ai/v1.1/search/keyword_search" \
  -H "Content-Type: application/json" \
  -H "Ocp-Apim-Subscription-Key: YOUR_API_KEY" \
  -d '{"query": "huurrecht opzegging", "jurisdictions": ["Netherlands"]}'

Base URL

All API endpoints are relative to the following base URL:

https://api.moonlit.ai/v1.1

For example, the keyword search endpoint is available at https://api.moonlit.ai/v1.1/search/keyword_search.

Errors

The API uses standard HTTP status codes to indicate the success or failure of a request. Codes in the 2xx range indicate success, 4xx range indicate a client error, and 5xx range indicate a server error.

Status CodeMeaningDescription
400Bad RequestThe request body is malformed or missing required parameters.
401UnauthorizedThe API key is missing or invalid.
403ForbiddenYour API key does not have permission to access this resource.
422Validation ErrorThe request body failed validation. Check required fields and parameter types.
429Rate LimitedYou have exceeded your monthly request quota. Contact our team to discuss your plan.
500Server ErrorAn unexpected error occurred on our end. Try again or contact support if the issue persists.
504Gateway TimeoutThe search timed out. This can happen with complex hybrid or semantic queries. Try narrowing your filters or reducing num_results.

Error Response Format

{
  "error": {
    "code": 401,
    "message": "Invalid or missing API key."
  }
}

Which search should you use?

"I have a natural language question"

Hybrid Search (best default)

Need max precision? Add reranking

"I need exact terms, case numbers, Boolean logic"

Keyword Search

Sort by date or citations with sort_type

"I want concept-based discovery"

Semantic Search

Need max precision? Add reranking

"I just want answers, not document lists"

Luna API (streaming research assistant)

POST/v1.1/search/semantic_search_reranked

Semantic Search with Reranking

Same as semantic search but applies a reranker to the results for improved relevance. Uses Google Vertex AI reranking.

Parameters

ParameterTypeRequiredDescription
documentTypesstring[]NoFilter by document type. Only accepts IDs returned by GET /v1.1/search/filters/documenttypes. Example IDs: '18fead608f1a4dcb5671b9fc8aeab4d1' (Laws and regulations), '04b42e5bf858a66de2229227deaa21e3' (Decisions).
jurisdictionsstring[]NoFilter by jurisdiction. Only accepts names returned by GET /v1.1/search/filters/jurisdictions_portals.
portalsstring[]NoFilter by portal. Use the `value` field returned by GET /v1.1/search/filters/jurisdictions_portals. Can be combined with jurisdictions — e.g. pairing 'Netherlands' in jurisdictions with '1|eur-lex.europa.eu' in portals searches all documents from the Netherlands and documents from eur-lex.europa.eu.
fieldsOfLawstring[]NoFilter by field of law. Only accepts IDs returned by GET /v1.1/search/filters/trees.
from_datestringNoInclusive lower date bound (YYYY-MM-DD). Requires until_date when set.
until_datestringNoInclusive upper date bound (YYYY-MM-DD). Requires from_date when set.
sourcesstring[]NoFilter by source (issuing entity such as a court or legislative body). Only accepts the `value` field from items returned by GET /v1.1/search/filters/sources. For example, if the filter endpoint returns `{"name": "Hof van Cassatie", "value": "c1f4502e43dc2c11969f4f201194fc07", ...}`, pass `"c1f4502e43dc2c11969f4f201194fc07"` in this array.
reference_identifierstringNoDocument identifier to find references for. When set, results are restricted to documents that reference or are referenced by this document (depending on reference_direction).
reference_directionintegerNoDirection of the reference relationship. 0 = to (documents that reference/cite reference_identifier), 1 = made_by (documents referenced by reference_identifier), 2 = both directions combined. Only used when reference_identifier is set. Possible values: 0, 1, 2.
article_reference_idstringNoArticle-level identifier to narrow reference results to a specific article within the referenced document. Use GET /v1.1/document/articles to discover available article identifiers for a document. Only used when reference_identifier is set.
querystringYesNatural-language semantic query text.
pageintegerNo1-based result page. Default: 1. Min: 1. Max: 1000.
num_resultsintegerNoResults per page. Default: 20. Min: 1. Max: 100.
rerankerTypeintegerNo1 = GoogleVertexAiRerank (default). Possible values: 1, 2.

Example Request

curl -X POST "https://api.moonlit.ai/v1.1/search/semantic_search_reranked" \
  -H "Ocp-Apim-Subscription-Key: YOUR_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{
  "jurisdictions": [
    "European Union",
    "Netherlands"
  ],
  "query": "data transfer safeguards",
  "num_results": 10
}'

Example Response

{
  "result": {
    "count": 405,
    "skip": 0,
    "top": 10,
    "results": [
      {
        "identifier": "62018CJ0311",
        "secondaryIdentifier": "ECLI:EU:C:2020:559",
        "tertiaryIdentifier": "C-311/18",
        "portal": "eur-lex.europa.eu",
        "startDate": "2018-05-09T00:00:00+00:00",
        "endDate": "2020-07-16T00:00:00+00:00",
        "highlights": [
          "...<span class='bold'>data</span> <span class='bold'>privacy</span>..."
        ],
        "title": "Data Protection Commissioner/Facebook Ireland Limited and Maximillian Schrems (European Court of Justice 16 July 2020, C-311/18, ECLI:EU:C:2020:559)",
        "court": "European Court of Justice",
        "year": 2020,
        "sources": [
          {
            "id": "02045a9e2de3f3bd6c520ad0317efd0d",
            "parentId": "f7875ac0576a21c24937d480f6fde4f1",
            "shortName": "European Court of Justice",
            "name": "European Court of Justice"
          }
        ],
        "fieldsOfLaw": [
          {
            "id": "6c1022289490f6fca4adcf0e082d2524",
            "shortName": "European data protection law",
            "name": "European data protection law"
          }
        ],
        "documentTypes": [
          {
            "id": "04b42e5bf858a66de2229227deaa21e3",
            "shortName": "Decisions",
            "name": "Decisions"
          }
        ],
        "language": "EN",
        "dataSource": 0,
        "referenced": 165,
        "literatureReferenced": 103,
        "score": 24.674826,
        "sourceUrl": "https://eur-lex.europa.eu/legal-content/EN/TXT/?uri=CELEX:62018CJ0311"
      }
    ],
    "facets": {
      "DataSources": [
        {
          "shortName": "EU",
          "name": "European Union",
          "value": "0",
          "count": 128,
          "portals": [
            {
              "name": "eur-lex.europa.eu",
              "value": "0|eur-lex.europa.eu",
              "count": 59
            }
          ]
        }
      ],
      "Portals": [
        {
          "shortName": "eur-lex.europa.eu",
          "name": "eur-lex.europa.eu",
          "value": "eur-lex.europa.eu",
          "count": 59
        }
      ],
      "FieldsOfLaw": [
        {
          "shortName": "Public law",
          "name": "Public law",
          "value": "2f6b898befaa9e641cd8ee258cd8f22e",
          "count": 1,
          "tooltip": "Public law",
          "children": []
        }
      ],
      "DocumentTypes": [
        {
          "shortName": "Decisions",
          "name": "Decisions",
          "value": "04b42e5bf858a66de2229227deaa21e3",
          "count": 33,
          "tooltip": "Decisions",
          "children": []
        }
      ],
      "sources": [
        {
          "shortName": "International courts",
          "name": "International courts",
          "value": "f7875ac0576a21c24937d480f6fde4f1",
          "count": 30,
          "tooltip": "International courts",
          "children": []
        }
      ]
    }
  },
  "success": true
}
POST/v1.1/search/hybrid_search_reranked

Hybrid Search with Reranking

Same as hybrid search but applies a reranker to the fused results for improved relevance. Uses Google Vertex AI reranking. The reranker re-scores results after RRF fusion, giving higher-quality ranking at the cost of slightly higher latency. Filter values are validated server-side. Retrieve accepted values from the filter endpoints before applying them: - GET /v1.1/search/filters/documenttypes — accepted documentTypes IDs - GET /v1.1/search/filters/jurisdictions_portals — accepted jurisdiction names and portal values - GET /v1.1/search/filters/trees — accepted fieldsOfLaw IDs

Parameters

ParameterTypeRequiredDescription
documentTypesstring[]NoFilter by document type. Only accepts IDs returned by GET /v1.1/search/filters/documenttypes. Example IDs: '18fead608f1a4dcb5671b9fc8aeab4d1' (Laws and regulations), '04b42e5bf858a66de2229227deaa21e3' (Decisions).
jurisdictionsstring[]NoFilter by jurisdiction. Only accepts names returned by GET /v1.1/search/filters/jurisdictions_portals.
portalsstring[]NoFilter by portal. Use the `value` field returned by GET /v1.1/search/filters/jurisdictions_portals. Can be combined with jurisdictions — e.g. pairing 'Netherlands' in jurisdictions with '1|eur-lex.europa.eu' in portals searches all documents from the Netherlands and documents from eur-lex.europa.eu.
fieldsOfLawstring[]NoFilter by field of law. Only accepts IDs returned by GET /v1.1/search/filters/trees.
from_datestringNoInclusive lower date bound (YYYY-MM-DD). Requires until_date when set.
until_datestringNoInclusive upper date bound (YYYY-MM-DD). Requires from_date when set.
sourcesstring[]NoFilter by source (issuing entity such as a court or legislative body). Only accepts the `value` field from items returned by GET /v1.1/search/filters/sources. For example, if the filter endpoint returns `{"name": "Hof van Cassatie", "value": "c1f4502e43dc2c11969f4f201194fc07", ...}`, pass `"c1f4502e43dc2c11969f4f201194fc07"` in this array.
reference_identifierstringNoDocument identifier to find references for. When set, results are restricted to documents that reference or are referenced by this document (depending on reference_direction).
reference_directionintegerNoDirection of the reference relationship. 0 = to (documents that reference/cite reference_identifier), 1 = made_by (documents referenced by reference_identifier), 2 = both directions combined. Only used when reference_identifier is set. Possible values: 0, 1, 2.
article_reference_idstringNoArticle-level identifier to narrow reference results to a specific article within the referenced document. Use GET /v1.1/document/articles to discover available article identifiers for a document. Only used when reference_identifier is set.
querystringYesNatural-language query. The system extracts keyword terms automatically and runs both keyword and semantic searches in parallel, fusing the results.
pageintegerNo1-based result page. Default: 1. Min: 1. Max: 1000.
num_resultsintegerNoResults per page. Default: 10. Min: 1. Max: 100.
semantic_weightnumberNoWeight for semantic search results in RRF fusion (0.0–1.0). Keyword weight is inferred as 1 − semantic_weight. Default: 0.6. Min: 0. Max: 1.
rerankerTypeintegerNo1 = GoogleVertexAiRerank (default). Possible values: 1, 2.

Example Request

curl -X POST "https://api.moonlit.ai/v1.1/search/hybrid_search_reranked" \
  -H "Ocp-Apim-Subscription-Key: YOUR_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{
  "jurisdictions": [
    "European Union",
    "Netherlands"
  ],
  "query": "What are the GDPR requirements for cross-border data transfers?",
  "num_results": 10,
  "semantic_weight": 0.6
}'

Example Response

{
  "result": {
    "count": 405,
    "skip": 0,
    "top": 10,
    "results": [
      {
        "identifier": "62018CJ0311",
        "secondaryIdentifier": "ECLI:EU:C:2020:559",
        "tertiaryIdentifier": "C-311/18",
        "portal": "eur-lex.europa.eu",
        "startDate": "2018-05-09T00:00:00+00:00",
        "endDate": "2020-07-16T00:00:00+00:00",
        "highlights": [
          "...<span class='bold'>data</span> <span class='bold'>privacy</span>..."
        ],
        "title": "Data Protection Commissioner/Facebook Ireland Limited and Maximillian Schrems (European Court of Justice 16 July 2020, C-311/18, ECLI:EU:C:2020:559)",
        "court": "European Court of Justice",
        "year": 2020,
        "sources": [
          {
            "id": "02045a9e2de3f3bd6c520ad0317efd0d",
            "parentId": "f7875ac0576a21c24937d480f6fde4f1",
            "shortName": "European Court of Justice",
            "name": "European Court of Justice"
          }
        ],
        "fieldsOfLaw": [
          {
            "id": "6c1022289490f6fca4adcf0e082d2524",
            "shortName": "European data protection law",
            "name": "European data protection law"
          }
        ],
        "documentTypes": [
          {
            "id": "04b42e5bf858a66de2229227deaa21e3",
            "shortName": "Decisions",
            "name": "Decisions"
          }
        ],
        "language": "EN",
        "dataSource": 0,
        "referenced": 165,
        "literatureReferenced": 103,
        "score": 24.674826,
        "sourceUrl": "https://eur-lex.europa.eu/legal-content/EN/TXT/?uri=CELEX:62018CJ0311"
      }
    ],
    "facets": {
      "DataSources": [
        {
          "shortName": "EU",
          "name": "European Union",
          "value": "0",
          "count": 128,
          "portals": [
            {
              "name": "eur-lex.europa.eu",
              "value": "0|eur-lex.europa.eu",
              "count": 59
            }
          ]
        }
      ],
      "Portals": [
        {
          "shortName": "eur-lex.europa.eu",
          "name": "eur-lex.europa.eu",
          "value": "eur-lex.europa.eu",
          "count": 59
        }
      ],
      "FieldsOfLaw": [
        {
          "shortName": "Public law",
          "name": "Public law",
          "value": "2f6b898befaa9e641cd8ee258cd8f22e",
          "count": 1,
          "tooltip": "Public law",
          "children": []
        }
      ],
      "DocumentTypes": [
        {
          "shortName": "Decisions",
          "name": "Decisions",
          "value": "04b42e5bf858a66de2229227deaa21e3",
          "count": 33,
          "tooltip": "Decisions",
          "children": []
        }
      ],
      "sources": [
        {
          "shortName": "International courts",
          "name": "International courts",
          "value": "f7875ac0576a21c24937d480f6fde4f1",
          "count": 30,
          "tooltip": "International courts",
          "children": []
        }
      ]
    }
  },
  "success": true
}
GET/v1.1/search/filters/documenttypes

List Document Types

Returns document type IDs structured as a hierarchical tree with nested child categories for filtering search endpoints.

Example Request

curl "https://api.moonlit.ai/v1.1/search/filters/documenttypes" \
  -H "Ocp-Apim-Subscription-Key: YOUR_API_KEY"

Example Response

{
  "DocumentTypes": [
    {
      "name": "value",
      "id": "value",
      "children": [
        "..."
      ]
    }
  ]
}
GET/v1.1/search/filters/jurisdictions_portals

List Jurisdictions and Portals

Returns jurisdiction names and their portals. Use each portal's `value` field as the canonical `portals` filter input for search endpoints.

Example Request

curl "https://api.moonlit.ai/v1.1/search/filters/jurisdictions_portals" \
  -H "Ocp-Apim-Subscription-Key: YOUR_API_KEY"

Example Response

[
  {
    "name": "value",
    "count": 0,
    "portals": [
      {
        "name": "value",
        "value": "value",
        "count": 0
      }
    ]
  }
]
GET/v1.1/search/filters/trees

List Fields-of-Law Tree

Returns hierarchical fields-of-law for use in search filters.

Example Request

curl "https://api.moonlit.ai/v1.1/search/filters/trees" \
  -H "Ocp-Apim-Subscription-Key: YOUR_API_KEY"

Example Response

{
  "FieldsOfLaw": [
    {
      "name": "value",
      "id": "value",
      "children": [
        "..."
      ]
    }
  ]
}
GET/v1.1/search/filters/sources

List Sources

Returns the hierarchical list of sources available for filtering search endpoints. Sources are issuing entities such as Supreme Courts, Courts of Appeal, and Legislative bodies. Each item contains a `value` field — pass that value in the `sources` array of keyword or semantic search requests to filter results by source. Optionally narrow the returned sources by providing `jurisdictions` and/or `portals` as query parameters.

Parameters

ParameterTypeRequiredDescription
jurisdictionsstringNoComma-separated jurisdiction names from /v1.1/search/filters/jurisdictions_portals.
portalsstringNoComma-separated portal values from /v1.1/search/filters/jurisdictions_portals.

Example Request

curl "https://api.moonlit.ai/v1.1/search/filters/sources" \
  -H "Ocp-Apim-Subscription-Key: YOUR_API_KEY"

Example Response

{
  "Sources": [
    {
      "name": "value",
      "value": "value",
      "count": 0,
      "children": [
        "..."
      ],
      "parentId": "value"
    }
  ]
}
GET/v1.1/search/semantic_portals

List Semantic Portals

Returns the list of portals currently enabled as semantic-search sources.

Example Request

curl "https://api.moonlit.ai/v1.1/search/semantic_portals" \
  -H "Ocp-Apim-Subscription-Key: YOUR_API_KEY"

Example Response

[
  {
    "name": "value",
    "value": "value"
  }
]
GET/v1.1/document/retrieve_document

Retrieve Document

Retrieve full document content and metadata by identifier.

Parameters

ParameterTypeRequiredDescription
DocumentIdentifierstringYesUnique identifier of the document to retrieve.

Example Request

curl "https://api.moonlit.ai/v1.1/document/retrieve_document?DocumentIdentifier=32019L0001" \
  -H "Ocp-Apim-Subscription-Key: YOUR_API_KEY"

Example Response

{
  "identifier": "32019L0001",
  "language": "EN",
  "date": "2018-12-11",
  "source": "European Parliament",
  "jurisdiction": "European Union",
  "portal": "eur-lex.europa.eu",
  "sourceUrl": "https://eur-lex.europa.eu/legal-content/EN/TXT/?uri=CELEX:32019L0001",
  "sourcePdf": "https://eur-lex.europa.eu/legal-content/EN/TXT/PDF/?uri=32019L0001",
  "sources": [
    {
      "id": "b49c23adeaa6a345aa815e401c6d194b",
      "name": "Legislative bodies"
    },
    {
      "id": "c9aca61be7de06a023b67cc6ab78bf72",
      "parentId": "b49c23adeaa6a345aa815e401c6d194b",
      "name": "European Parliament"
    }
  ],
  "documentTypes": [
    {
      "id": "87a86c141d2c0649a699745ba63e4c6b",
      "parentId": "18fead608f1a4dcb5671b9fc8aeab4d1",
      "name": "European law"
    },
    {
      "id": "18fead608f1a4dcb5671b9fc8aeab4d1",
      "name": "Laws and regulations"
    },
    {
      "id": "f01159d4ed0dc13c024b743d514e1401",
      "parentId": "8dba0d10dfdf2460a34ddf4eeb7b6584",
      "name": "EU directives"
    },
    {
      "id": "8dba0d10dfdf2460a34ddf4eeb7b6584",
      "parentId": "87a86c141d2c0649a699745ba63e4c6b",
      "name": "EU secondary law"
    }
  ],
  "text": "14.1.2019 EN Official Journal of the European Union...",
  "html": "<h1>DIRECTIVE (EU) 2019/1 OF THE EUROPEAN PARLIAMENT...",
  "year": 2019,
  "inForce": true,
  "summary": "This directive establishes common rules for the internal market..."
}
GET/v1.1/document/articles

List Document Articles

Returns the list of articles/elements within a composite document (e.g. a law or regulation). Each article includes its identifier, title, hierarchy level, and the number of documents that reference it. Use the `elementIdentifier` from the response as the `article_reference_id` parameter in reference search to narrow results to a specific article.

Parameters

ParameterTypeRequiredDescription
DocumentIdentifierstringYesUnique identifier of the document to list articles for.

Example Request

curl "https://api.moonlit.ai/v1.1/document/articles?DocumentIdentifier=32016R0679" \
  -H "Ocp-Apim-Subscription-Key: YOUR_API_KEY"

Example Response

[
  {
    "elementIdentifier": "value",
    "elementTitle": "value",
    "elementSubTitle": "value",
    "referenceCount": 0,
    "level": 0,
    "globalOrder": 0
  }
]
POST/v1.1/luna/initialize_chat

Initialize a Luna research chat session

Creates a new research chat session and returns a chat_id for subsequent questions.

Example Request

curl -X POST "https://api.moonlit.ai/v1.1/luna/initialize_chat" \
  -H "Ocp-Apim-Subscription-Key: YOUR_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{}'

Example Response

{
  "chat_id": "value"
}
POST/v1.1/luna/ask_question

Ask a research question (SSE stream)

Sends a question to an existing Luna research chat session and streams the answer back as Server-Sent Events (SSE).

Parameters

ParameterTypeRequiredDescription
chat_idstringYesChat session ID returned by initialize_chat
inputstringYesThe research question to ask
jurisdictionsstring[]NoJurisdiction names to scope the research. Only accepts names returned by GET /v1.1/search/filters/jurisdictions_portals.

Example Request

curl -N -X POST "https://api.moonlit.ai/v1.1/luna/ask_question" \
  -H "Ocp-Apim-Subscription-Key: YOUR_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{
  "chat_id": "f47ac10b-58cc-4372-a567-0e02b2c3d479",
  "input": "What are the key requirements for valid consent under GDPR?",
  "jurisdictions": [
    "European Union",
    "Netherlands"
  ]
}'

Example Response

event: message
data: Based on the relevant case law and legislation...

event: message
data:  the key requirements include...

event: sources
data: {"sources": [{"id": "62018CJ0311", "title": "Schrems II", "relevance": 0.96}]}

event: done
data: [DONE]