# Drupal Code Query API

Read-only HTTP API over a daily static analysis of Drupal core and every
contributed project on drupal.org. No authentication; per-IP rate limits
apply. Responses are JSON unless a route says otherwise.

[/v1/](/v1/) documents every endpoint below: parameters, response shapes and
cache lifetimes.

| Method | Path | Description |
|--------|------|-------------|
| GET | [/](/) | This index: every public endpoint, grouped by what it answers |
| GET | [/v1/](/v1/) | Reference for every v1 endpoint: parameters, response shapes, cache lifetimes |

## Upgrading a site

| Method | Path | Description |
|--------|------|-------------|
| GET | [/v1/composer/scan](/v1/composer/scan) | The reference page for the scan: body fields, the four row verdicts, the patch half and the caps |
| POST | [/v1/composer/scan](/v1/composer/scan) | One POST with a site's composer files reports, for every drupal/* package, whether a release supports a target core. Body {composer_json, composer_lock, target_core}; the lock is required; a slim form with name, version and the sub-module fields (type, require, extra.drupal.datestamp) works. Add patches:true and every composer patch is judged against the release it installs, under plan |
| POST | [/v1/patch/check](/v1/patch/check) | Every composer patch gets a verdict against the release the site installed: whether it still applies, and whether its fix is already in it. Body {items:[…]} (at most 50) or the site's {composer_json, composer_lock, patch_files}; reroll:true adds a re-rolled diff for the ones that no longer apply |
| GET | [/v1/patch/check](/v1/patch/check) | The reference for the POST route. This service downloads nothing, so a patch is sent as diff text rather than named by URL |

## Change records

| Method | Path | Description |
|--------|------|-------------|
| GET | [/v1/change-record](/v1/change-record) | Every published core change record, most recently fixed first: nid, title, target version, flavor, linked issues. ?project=<machine_name> switches to that project's impacted records, ?matches=1 adds the matching files |
| GET | /v1/change-record/{nid} | One change record: its flavor, the core symbols it lists, and every impacted contrib project with per-branch adoption counts and the files that match |

## Core symbols

| Method | Path | Description |
|--------|------|-------------|
| GET | [/v1/symbol/search](/v1/symbol/search) | Find a core symbol by part of its name: ?q=… + ?limit=20 (max 50). Returns identity_id, fqn, kind, subsystem; ?format=html returns the autocomplete fragment |
| GET | /v1/symbol/{id} | One core symbol by identity_id: lifecycle stamps, the contrib projects calling it on development branches, and the change records that list it. ?all=1 lifts the project cap |

## Contrib projects

| Method | Path | Description |
|--------|------|-------------|
| GET | [/v1/project](/v1/project) | Every contrib project with an install base or a published release: type, security coverage, installs, releases, supported branches, and its membership roots. Paged with ?limit=100 (max 1000) and ?offset; ?all=1 for every project. ?member_of=<root> narrows the list to that root's members; ?max_depth=<n> keeps only members at most n requires from the root |
| GET | /v1/project/{machine_name} | One contrib project by machine name (webform): the same facts, unpaged |

## Core issues

| Method | Path | Description |
|--------|------|-------------|
| GET | [/v1/issue](/v1/issue) | Open Drupal core issues, most recently changed first. ?status=all adds closed ones, and ?status=<code> keeps one status. Add ?at=<RFC 3339 time> for the issues in that status at that moment. ?follower=<username> keeps the ones that user subscribes to, ?limit=500 (max 5000) + ?offset, ?all=1 |
| GET | /v1/issue/{nid} | One core issue: its status history, the core subsystems its merge requests touch, and the CI co-failure couplings from those subsystems. It also lists the linked change records |

## Code search

| Method | Path | Description |
|--------|------|-------------|
| GET | [/v1/search](/v1/search) | Regex code search across every indexed contrib project and core. ?q=<query> runs it; without q the page is the query-syntax reference |
| GET | [/v1/search/code](/v1/search/code) | The same search under an explicit path: ?q= plus ?num= (files), ?context= (lines around a match), ?maxmatches=, ?chunks=false |
| GET | [/v1/search/repo](/v1/search/repo) | The indexed repositories and their metadata: per-branch core constraint, installs, security coverage. ?q=r:^(webform\|token)$ narrows to some |

## AI detection

| Method | Path | Description |
|--------|------|-------------|
| GET | [/v1/meta/](/v1/meta/) | What these routes report, the twelve style signals behind a rating, and the rate limit they share |
| GET | /v1/meta/comment/{cid} | AI detection for one drupal.org issue comment, by comment id |
| GET | /v1/meta/issue/{nid} | AI detection for one issue summary, by drupal.org node id: self-disclosure, or a rating with the signals that fired |
| GET | /v1/meta/note/{gid} | AI detection for one merge-request note, by GitLab note id |

The dataset behind these routes, and how to query it directly, is on the
[about page](/data/about/).
