Registry HTTP API
The npm-compatible routes and the /-/apm/v1/* API of registry.apmjs.dev, with methods, parameters, auth and errors.
The registry at https://registry.apmjs.dev/ speaks the npm registry protocol, so stock clients work unchanged, and adds its own API under /-/apm/v1/. This page lists every public route. Routes used only by the website (sign-in, approvals, second factors) and by the AI reviewer are listed at the end without detail.
Conventions
- Auth. Send
Authorization: Bearer <token>with the token fromapm login. Routes marked “token” need one; the rest are public. - Second factor. Routes marked “factor” also need
otp(a six-digit authenticator code) in the JSON body, or a website approval of that exact command made in the last 10 minutes. - Errors. A failure answers JSON with an
errormessage and the matching status:400bad input,401no token,403not allowed,404not found,405wrong method,409conflict,410revoked or expired,413too large,422refused by a check,429over a quota,503an upstream check could not run. - Per-user answers (account, staged uploads, tokens, login, and any
/-/answer to a request carrying credentials) are sent withCache-Control: private, no-storeandVary: Authorization, Cookie. - Package names in paths are URL-encoded the npm way:
@scope%2fname. - Size limits. Publish bodies 32 MB, JSON API bodies 5 MB, a tarball’s
package.json1 MB.
The ~safe view
Prefix any path with /~safe to read through the safe view: https://registry.apmjs.dev/~safe/<package>. Package documents, versions and tarballs then leave out versions that are revoked, pending revocation, yanked, younger than 24 hours, unscored, or scoring under 40, and latest points at the newest version that passes. A hidden version answers 404 with the reason. See The ~safe view.
npm protocol routes
| Method and path | Auth | Answers |
|---|---|---|
GET /-/ping |
none | {} |
GET /<package> |
none | The package document (packument). Supports the abbreviated form (Accept: application/vnd.npm.install-v1+json) and ETag. Each version carries apm’s score as _apmScore. |
GET /<package>/<version or tag> |
none | One version’s document. Revoked versions answer 404. |
GET /<package>/-/<file>.tgz |
none | The tarball, checked against its published sha512 before it is sent. A revoked version answers 410 with the reason. |
PUT /<package> |
token | Publish one version. With a login token it is staged and answers 202 with approvalUrl, expiresAt and an npm-notice header holding the link. npm deprecate uses this route too; with a login token it needs a code in npm-otp. |
GET /-/package/<package>/dist-tags |
none | The dist-tags. |
PUT /-/package/<package>/dist-tags/<tag> |
token, factor | Move a tag. A login token needs a code (npm sends it as npm-otp). |
DELETE /-/package/<package>/dist-tags/<tag> |
token, factor | Remove a tag. |
PUT /<package>/-rev/<rev> |
token, factor | npm owner add and npm owner rm. Needs a code in npm-otp. |
DELETE /<package>/-rev/<rev> |
Always 405. apm does not unpublish; use yank or revoke. |
|
GET /-/v1/search?text=&size=&from= |
none | Search across apm and npm. size at most 250. |
POST /-/npm/v1/security/advisories/bulk |
none | Advisories for bun audit and npm audit. Revoked versions are critical advisories. |
GET /-/whoami |
token | { "username": "..." } |
DELETE /-/user/token/<token> |
token | Revoke the token that made the request. |
PUT /-/user/org.couchdb.user:<name> |
none | npm password login. Only on self-hosted registries with APM_LEGACY_AUTH=1. |
Packages that are not on apm are fetched from https://registry.npmjs.org/, checked against npm’s checksum, and scored on first request.
apm API
GET /-/apm/v1/resolve
What apm add installs. Query: name, range (default latest), cooldown (24h, 90m, 2d, 0; a bare number is hours; default 24h), floor (default 40). A lower floor applies to the named package only; its dependencies are checked at 40 or the stricter floor.
200:{ name, version, report, skipped, source, tree }.tree.packageslists every package the registry walked;tree.uncheckedDepslists those it could not score (git and URL specs, missing packages, past the 300-package walk limit).422: no version passes.{ error, name, version: null, skipped, newest, tree }, whereskippedgives each version’s reason.404: no such package.
GET /-/apm/v1/score/<package>[/<version or tag>]
One version’s score. Without a version, latest.
{
"name": "zod", "version": "4.6.7", "status": "active",
"score": 90, "grade": "A",
"signals": [{ "id": "eval", "label": "Evaluates code built at runtime (eval, Function, vm)", "points": -10, "confidence": "confirmed", "evidence": ["v4/core/compile.js:184: const factory = new F(...constantNames, factoryCode);"] }],
"notChecked": ["runtime behavior: code that downloads, decrypts or builds a second stage while running"],
"publishedAt": "2026-10-12T16:29:37.778Z", "publishedBy": "GitHub Actions",
"previous": { "version": "4.6.6", "score": 90, "grade": "A" },
"changes": []
}
GET /-/apm/v1/names?q=<name>
Name check, as apm name shows it: { query, valid, taken, available, owners, latest, conflicts, similar, suggestions }. Optional user says whose scope to check against; it defaults to the caller.
POST /-/apm/v1/scan
The Bun scanner’s check. Body: { "packages": [{ "name": "zod", "version": "4.6.7" }] }. At most 200 packages without a token, 2,000 with one; the rest come back as unchecked.
200:{ advisories: [{ package, version, level, description, url }], unchecked: [{ package, version, reason }] }. A revoked version (or one pending revocation), or one scoring under 40, comes back withlevel: "fatal", which makes Bun cancel the install. A version not scored yet is listed as unchecked.
POST /-/apm/v1/audit
Body: { "<package>": ["<version>", ...] }. Answers { advisories, unavailable }: npm-style advisories per package, and the packages whose upstream advisories could not be fetched.
GET /-/apm/v1/packages/<package>
The package as the website shows it: versions with status, scores and dist-tags. GET /-/apm/v1/packages/<package>/events is its public log: publishes, yanks, revokes, restores, owner changes and evidence dismissals, with who and why.
GET /-/apm/v1/recent?limit=<n>
Recent events across the registry, newest first. limit 1 to 50, default 12.
GET /-/apm/v1/file/<package>/<version>?path=<path>
One file of a version, as text, from the same verified tarball the install routes serve. Up to 1 MB whole. Add &line=<n>&context=<k> (k at most 100) for lines n-k to n+k of a file of any size. A file that is not UTF-8 answers its size and no text; a line past the end answers 416; a revoked version answers 410.
GET /-/apm/v1/readme/<package>/<version>
The README in the version’s tarball, picked the way npm picks one.
GET /-/apm/v1/review/<package>/<version>
The AI review result for a version, when the registry runs the review. POST .../request asks for one (signed-in users, 5 an hour).
Version state
All take a JSON body and a token, and need the caller to own the package.
| Method and path | Body | Factor |
|---|---|---|
POST /-/apm/v1/yank |
{ name, version, reason? , otp? } |
A login token needs otp. |
POST /-/apm/v1/unyank |
{ name, version, otp? } |
A login token needs otp. |
POST /-/apm/v1/revoke |
{ name, version, reason, otp } |
Required. |
POST /-/apm/v1/restore |
{ name, version, reason?, otp } |
Required. |
POST /-/apm/v1/incident |
{ since, reason?, dryRun?, otp } |
Required. since is ISO, at most 30 days back. |
POST /-/apm/v1/owners |
{ name, user, otp } |
Required. Adds an owner. |
DELETE /-/apm/v1/owners |
{ name, user, otp } |
Required. Removes an owner. |
Revoke answers { ok, name, version, status, finalAt?, note? }; status is revoked, or revoke-pending with finalAt 24 hours later. Incident answers { ok, revoked, tokensRevoked, dryRun? }.
Routes for the website and the reviewer
These exist for apmjs.dev and the AI reviewer process. They need a website session with the website’s Origin, or the reviewer’s service token, and are not a stable API:
- sign-in:
/api/auth/*,GET /-/apm/v1/auth/config,POST /-/apm/v1/login/deviceand/login/device/token(the device flowapm loginuses); - account:
GET /-/apm/v1/account,POST /-/apm/v1/account/tokens/revoke; - second factors:
POST /-/apm/v1/factor/passkey-challenge,POST /-/apm/v1/factor/confirm,POST /-/apm/v1/verify; - staged uploads:
GET /-/apm/v1/staged,GET /-/apm/v1/staged/<id>,GET .../file,POST .../approve,POST .../reject; - evidence review:
/-/apm/v1/evidence-admin/*; - AI review queue:
/-/apm/v1/review-jobs*,/-/apm/v1/review-admin/*.