Combined
2 routes under /api/combined.
POST/api/combined
Federated search across both Rechtspraak and ECHR with a structured query builder. Supports nested boolean logic, per-rule dataset scoping, sorting, and cursor pagination. This endpoint returns search results only (no citation edges). Use `/api/combined/expand` to expand citations for individual nodes.
Request parameters
| Field | Type | Notes |
|---|---|---|
queryBuilder | object | Required. Contains op, rules, and optional groups. |
queryBuilder.op | string | Required. "AND", "OR", or "NOT". |
queryBuilder.rules | array | Required. Array of rule objects (see below). |
queryBuilder.groups | array | Optional. Nested groups (one level). Each has op and rules. |
sort.by | string | Optional. "date" (default) or "citations". |
sort.direction | string | Optional. "ASC" or "DESC" (default). |
pagination.pageSize | int | Optional. 1 to 1000 (default: 20). |
pagination.cursor | string | Optional. Cursor token from a previous response. |
Rule object
| Field | Type | Notes |
|---|---|---|
field | string | The field to query (see field reference below). |
operator | string | "equals", "contains", "not_contains", "not_equals", "after", "before", "lte". |
value | string | The value to match against. |
sourceScope | string | "ANY" (both datasets), "RS", or "ECHR". Only common fields can use "ANY". |
Query builder fields
| Field | Scope | Operators |
|---|---|---|
text | ANY | contains, not_contains |
title | ANY | contains, equals, not_contains |
ecli | ANY | equals, contains, not_contains |
keywords | ANY | contains, not_contains |
year | ANY | equals, after, before |
dateStart | ANY | equals, after |
dateEnd | ANY | equals, before |
source | ANY | equals, not_equals, contains |
document_type | ANY | equals |
instance | RS | equals |
domain | RS | equals |
articles | RS | contains, equals, not_contains |
selectedLaws | RS | equals, contains |
respondent_state | ECHR | equals, not_equals |
importance | ECHR | equals, lte |
article_violated | ECHR | equals, contains, not_contains |
article_applied | ECHR | equals, contains, not_contains |
application_number | ECHR | equals, contains |
language | ECHR | equals, not_equals |
- Note: This endpoint does not return citation edges. Use
/api/combined/expandto expand citations for individual nodes.
Examples
- sourceScope "ANY" only for fields in both datasets - Root op AND excludes datasets missing scoped rules - year: 4-digit, must not be in the future - Dates: YYYY-MM-DD, must not be in the future - respondent_state: ISO-3 (ARM, DEU, TUR) - language: ISO-3 (ENG, FRE, DEU) - document_type RS: DEC, OPI - document_type ECHR: JUD, DEC, COM, CLIN, PR - selectedLaws: "BWBx123|456" format - Cursor must match current sort settings
Unified query with nested group
{ "queryBuilder": { "op": "AND", "rules": [ { "field": "year", "operator": "equals", "value": "2020", "sourceScope": "ANY" }, { "field": "respondent_state", "operator": "equals", "value": "ARM", "sourceScope": "ECHR" }, { "field": "document_type", "operator": "equals", "value": "DEC", "sourceScope": "RS" } ], "groups": [ { "op": "OR", "rules": [ { "field": "keywords", "operator": "contains", "value": "right to life", "sourceScope": "ANY" }, { "field": "domain", "operator": "equals", "value": "Human rights", "sourceScope": "RS" } ] } ] }, "sort": { "by": "date", "direction": "desc" }, "pagination": { "pageSize": 20 } }
Response
{ "nodes": [ { "id": "ECLI:NL:HR:2020:...", "data": { "isResult": "True", "dataset": "RS", "cites_count": 5, "cited_by_count": 12, "languages": ["NLD"], "document_type": "DEC" } }, { "id": "ECLI:CE:ECHR:2020:...", "data": { "isResult": "True", "dataset": "ECHR", "cites_count": 3, "cited_by_count": 8, "languages": ["ENG", "FRE"], "document_type": "JUD" } } ], "pagination": { "pageSize": 20, "nextCursor": "eyJ...", "total": 1234, "rsTotal": 800, "echrTotal": 434 }, "facets": { "rs_document_type": [{"value": "DEC", "count": 750}], "rs_domain": [{"value": "Strafrecht", "count": 200}], "rs_instance": [{"value": "Hoge Raad", "count": 100}], "echr_document_type": [{"value": "JUD", "count": 300}], "echr_respondent_state": [{"value": "TUR", "count": 50}], "echr_importance": [{"value": 1, "count": 40}], "echr_language": [{"value": "ENG", "count": 400}], "echr_article_violated": [{"value": "6", "count": 500}, {"value": "6-1", "count": 480}], "echr_article_applied": [{"value": "41", "count": 1200}, {"value": "35-1", "count": 900}], "echr_article_non_violated": [{"value": "6", "count": 50}] }, "warnings": [] }
Response
- nodes[].data.cites_count / cited_by_count — citation counts per node - pagination.total — combined total hits across both datasets - pagination.rsTotal / echrTotal — per-dataset totals - facets — only returned on the first page (no cursor). Contains filter value counts grouped by rs_* and echr_* prefixes. - sort.by = "citations" sorts by cited_by_count (most cited first)
Response
1. Search — POST /api/combined → returns nodes + totals + facets (first page only) 2. User selects a node to explore 3. Expand — POST /api/combined/expand → returns edges + neighbour nodes
POST/api/combined/expand
Expand a single node's degree-1 citations. Given an ECLI identifier, returns the immediate citation edges (incoming and/or outgoing) and the hydrated neighbour nodes. The dataset (ECHR or RS) is auto-detected from the ECLI format, or can be specified explicitly via `nodeDataset`.
Request parameters
| Field | Type | Notes |
|---|---|---|
nodeId | string | Required. The ECLI identifier of the node to expand. |
degreesSource | int | Optional. 0 or 1 (default: 0). Set to 1 to include cases that cite this node. |
degreesTarget | int | Optional. 0 or 1 (default: 0). Set to 1 to include cases cited by this node. |
nodeDataset | string | Optional. "ECHR" or "RS". Auto-detected from the ECLI if omitted. |
Validation rules - nodeId is required and must be non-empty - At least one of degreesSource or degreesTarget must be 1 (otherwise nothing to expand) - Degrees accept only 0 or 1 (integer, not boolean) - nodeDataset must be "ECHR" or "RS" if provided - Unknown request keys are rejected Edge directionality
| Direction | Controlled by | Meaning |
|---|---|---|
| Incoming | degreesSource: 1 | Cases that cite the seed node (source → seed). |
| Outgoing | degreesTarget: 1 | Cases cited by the seed node (seed → target). |
Response fields
| Field | Description |
|---|---|
nodeId | Echo of the requested ECLI. |
edges | Array of edge objects with id, source, and target. |
expandedNodes | Array of hydrated neighbour nodes (same shape as /api/combined nodes). Each includes a dataset field. |
Examples
- nodeId is required and must be non-empty - At least one of degreesSource or degreesTarget must be 1 (otherwise nothing to expand) - Degrees accept only 0 or 1 (integer, not boolean) - nodeDataset must be "ECHR" or "RS" if provided - Unknown request keys are rejected
Expand ECHR node (both directions)
{ "nodeId": "ECLI:CE:ECHR:1968:0723JUD000147462", "degreesSource": 1, "degreesTarget": 1 }
Expand RS node (outgoing only)
{ "nodeId": "ECLI:NL:HR:2018:1234", "degreesTarget": 1 }
With explicit dataset
{ "nodeId": "ECLI:CE:ECHR:2019:0101JUD001234567", "degreesSource": 1, "nodeDataset": "ECHR" }
Response
{ "nodeId": "ECLI:CE:ECHR:1968:0723JUD000147462", "edges": [ { "id": "ECLI:CE:ECHR:2006:..._ECLI:CE:ECHR:1968:...", "source": "ECLI:CE:ECHR:2006:...", "target": "ECLI:CE:ECHR:1968:..." }, { "id": "ECLI:CE:ECHR:1968:..._ECLI:CE:ECHR:1961:...", "source": "ECLI:CE:ECHR:1968:...", "target": "ECLI:CE:ECHR:1961:..." } ], "expandedNodes": [ { "id": "ECLI:CE:ECHR:2006:...", "data": { "dataset": "ECHR", "ecli": "ECLI:CE:ECHR:2006:...", "date_judgment": "2006-07-11", "respondent_state": "GRC", "document_type": "JUD", "languages": ["ENG", "FRE"] } } ] }