One call before you add the dependency
The Package & Dependency Trust API scores open-source packages and repositories as clean JSON.
4 active endpoints, on 2, 3 and 5 credit tiers.
- POST/enrich-package/v1/package_trust
- POST/enrich-package/v1/repo_trust
- POST/enrich-package/v1/lockfile_scan
- POST/enrich-package/v1/batch
What Package & Dependency Trust endpoints does ReefAPI ship?
4 live read endpoints. Read-only data API: no writes, no account actions, no dashboard access on the target site.
Package & Dependency Trust API
3 of 4 endpoints, ready to run
Registry metadata, download volume, the linked repository's health, known vulnerabilities, community signal and a scored breakdown — popularity, maintenance, security, licence, dependency risk.
{ "ok": true, "meta": { "api": "enrich-package", "endpoint": "package_trust", "mode": "rich", "latency_ms": 3686.6, "record_count": 1, "cache_hit": false, "completeness_pct": 80 }, "data": { "provenance": { "registry": { "status": "matched", "engine": "packages" }, "downloads": { "status": "matched", "engine": "packages" }, "repo": { "status": "matched", "engine": "registry-metadata" }, "vulnerabilities": { "status": "matched", "engine": "vuln-intel" }, "repo_health": { "status": "matched", "engine": "github" }, "community": { "status": "matched", "engine": "stackoverflow" } }, "generated_at": "2026-08-29T14:12:38Z", "honesty": "trust score is a RISK SIGNAL, not a security guarantee; scores degrade to 'unknown' rather than show a clean-looking default when a source is missing or a repo match is low-confidence", "package": { "name": "lodash", "ecosystem": "npm", "version": "4.18.1", "latest_version": "4.18.1", "description": "Lodash modular utilities.", "homepage": "https://lodash.com/" }, "metadata": { "license": { "value": "MIT", "raw": "MIT" }, "keywords": [ "modules", "stdlib", "util" ], "version_count": 117, "latest": "4.18.1", "maintainers": [ { "name": "mathias" }, { "name": "jdalton" }, { "name": "bnjmnt4n" } ] }, "downloads": { "registry": "npm", "period": "last-month", "downloads": 711046689, "start": "2026-07-30", "end": "2026-08-28" }, "repo": { "found": true, "repo": "lodash", "repo_url": "https://github.com/lodash/lodash", "match": { "confidence": 0.95, "class": "declared-exact", "source_field": "repository", "name_similarity": 1, "evidence": [ "github owner/repo parsed from package `repository` field → lodash/lodash", "repo↔package name similarity = 1.00" ], "reason": null }, "health": { "stars": 61282, "forks": 7196, "watchers": 811, "open_issues": 106, "archived": false, "license": "NOASSERTION", "pushed_at": "2026-07-03T19:48:01Z", "created_at": "2012-04-07T04:11:46Z", "default_branch": "main", "top_languages": [ "JavaScript", "HTML", "EJS" ], "release_count_listed": 4, "last_release": "2026-04-01T21:01:28Z", "releases_12mo": 2, "contributors_listed": 30, "bus_factor": 30, "top_contributors": [ { "contributions": 6569 }, { "contributions": 423 }, { "contributions": 46 } ] } }, "vulnerabilities": { "count": 10, "highest_severity": "critical", "by_severity": { "critical": 1, "high": 4, "moderate": 5, "low": 0, "unknown": 0 }, "items": [ { "id": "GHSA-29mw-wpgm-hmr9", "cve_ids": [ "CVE-2020-28500" ], "summary": "Regular Expression Denial of Service (ReDoS) in lodash", "severity": "MODERATE", "cvss_base_score": null, "fixed_versions": [ "4.17.21" ] }, { "id": "GHSA-35jh-r3h4-6jhm", "cve_ids": [ "CVE-2021-23337", "CVE-2026-4800" ], "summary": "Command Injection in lodash", "severity": "HIGH", "cvss_base_score": null, "fixed_versions": [ "4.17.21" ] }, { "id": "GHSA-4xc9-xhrj-v574", "cve_ids": [ "CVE-2018-16487" ], "summary": "Prototype Pollution in lodash", "severity": "HIGH", "cvss_base_score": null, "fixed_versions": [ "4.17.11" ] } ] }, "community": { "stackoverflow": { "questions_found": 5, "top": [ { "title": "Differences between Lodash and Underscore.js", "score": 1729, "is_answered": true, "link": "https://stackoverflow.com/questions/13789618/differences-between-lodash-and-underscore-js" }, { "title": "Lodash - difference between .extend() / .assign() and .merge()", "score": 533, "is_answered": true, "link": "https://stackoverflow.com/questions/19965844/lodash-difference-between-extend-assign-and-merge" }, { "title": "How to do a deep comparison between 2 objects with lodash?", "score": 516, "is_answered": true, "link": "https://stackoverflow.com/questions/31683075/how-to-do-a-deep-comparison-between-2-objects-with-lodash" } ] } }, "score": { "popularity": { "score": 98, "inputs": { "monthly_downloads": 711046689, "stars": 61282 }, "method": "mean of log-scaled monthly-downloads (full≈50M) and github stars (full≈100k)" }, "maintenance": { "score": 65, "inputs": { "days_since_last_release": 149, "days_since_last_repo_push": 56, "releases_last_12mo": 2, "archived": false, "contributors": 30 }, "method": "exp-decay release/push recency + release cadence + contributor bus-factor (equal-weighted over available signals)" }, "security": { "score": 43, "inputs": { "vuln_query_ok": true, "vuln_count": 10, "severity_summary": { "by_severity": { "critical": 1, "high": 4, "moderate": 5, "low": 0, "unknown": 0 }, "highest_severity": "critical", "total": 10 }, "version_pinned": false, "repo_match_trusted": true, "known_exploited_count": null }, "note": "security score is a risk SIGNAL, not a guarantee of safety; pin a version for an exact affected/not-affected read", "method": "severity-floor (highest sev present) − saturating count term for the UNPINNED historical advisory set; KEV known-exploited floors the score to ≤10", "flags": [ "historical_vulns_across_all_versions_pin_a_version_for_precise_read", "has_historical_critical_vuln" ] }, "license": { "score": "unknown", "inputs": { "license": "MIT", "spdx_id": "NOASSERTION" }, "tier": "unknown", "method": "SPDX tier: permissive→90, weak-copyleft→55, strong-copyleft/SSPL→25, none/unknown→unknown", "missing_reason": "no license declared in registry/repo metadata", "note": "license tier reflects integration friction for an API/SaaS consumer, not legal advice" }, "dependency_risk": { "score": 100, "inputs": { "direct_dependencies": 0, "vulnerable_dependencies": null, "dependencies_scanned": null }, "method": "exp-decay fan-out penalty (direct deps) + clean-dependency ratio when deps were vuln-scanned" }, "overall": { "trust_score": 71, "grade": "B", "scored_components": [ "dependency_risk", "maintenance", "popularity" ], "unknown_components": [ "license" ], "confidence": 0.85, "method": "weighted mean of resolved sub-scores (security0.30/pop0.20/maint0.20/license0.15/dep0.15), renormalized over available components — unknowns excluded, not treated as 0 or 100" } } } }
How the Package & Dependency Trust API works
Package & Dependency Trust is a normal ReefAPI surface — the same four rules that hold for every other engine on the key.
No OAuth app, no request signing, no per-site account. One key covers all 184 engines.
Every route is a POST with a JSON body. Parameters are validated against the published schema before anything is charged.
Credits, not seats. Failed and blocked calls are never charged, and cache hits cost nothing.
One envelope everywhere. meta carries latency_ms, record_count and the endpoint that answered.
Reviewing a pull request that adds four dependencies
The reviewer's real question is not whether the code compiles. It is whether these packages are maintained, whether the repository they claim is really theirs, and what they drag in.
{"content": "…", "filename": "requirements.txt"}Assesses everything the lockfile pins, which is what actually gets installed — not what the manifest asks for.
{"ecosystem": "npm", "package": "lodash"}For the one that looks wrong. Returns the scored breakdown with the repository match confidence beside it.
The repository-match confidence is the field worth reading first: a registry package claiming a repository it does not own is the shape a supply-chain attack takes, and it is reported as a match class rather than assumed.
curl -X POST https://api.reefapi.com/enrich-package/v1/package_trust \
-H "x-api-key: $REEF_KEY" \
-H "content-type: application/json" \
-d '{"ecosystem":"npm","package":"lodash","version":"4.17.15","mode":"rich"}'{
"ok": true,
"data": { … },
"meta": {
"api": "enrich-package",
"endpoint": "package_trust",
"mode": "live",
"latency_ms": …,
"record_count": …
},
"error": null
}The five sub-scores, their weights, and why one goes 'unknown'
The overall trust_score is a weighted mean of five sub-scores, and the response prints the weights itself. Any sub-score that cannot be resolved returns the string "unknown" rather than a number, and is dropped from the mean instead of being counted as 0 or 100. The confidence field is what is left over: the summed weight of the sub-scores that did resolve. Every figure below is from live calls on lodash, requests, gin and facebook/react.
| Sub-score | Weight | What it needs | Measured |
|---|---|---|---|
| security | 0.30 | an OSV advisory lookup for the ecosystem | lodash pinned at 4.17.15 scored 0 (3 high, 3 moderate); requests unpinned scored 55 over 16 historical advisories |
| popularity | 0.20 | registry download counts or GitHub stars | lodash 98 from 711,291,373 monthly downloads and 61,283 stars; gin "unknown" with neither available |
| maintenance | 0.20 | release dates, push dates, cadence, contributor count | lodash 65 in rich mode and 90 in basic mode, on the same version |
| license | 0.15 | an SPDX id, read from the resolved repo license field | requests 90 permissive; lodash "unknown" even though metadata.license.value is "MIT" |
| dependency_risk | 0.15 | the direct dependency list | lodash 100 with zero runtime deps; requests 93 with 6 direct deps |
| overall.confidence | sum of resolved weights | nothing, it is arithmetic on the rows above | 1.0 for requests, 0.85 for lodash with license missing, 0.55 for a repo_trust call, 0.30 for gin |
| overall.grade | A / B / C / D / F | at least 3 of the 5 sub-scores resolved | gin returned grade "insufficient-data" with confidence 0.30 and a low_confidence_note explaining it |
meta.completeness_pct tracks the same idea from the source side rather than the score side: 100.0 for a PyPI lookup where every group matched, 80.0 for lodash, 20.0 for a Go module where only the vulnerability and Stack Overflow groups resolved. The provenance object names the reason per group, for example registry status "unsupported" with detail "packages engine serves npm/pypi only; Go gets vuln + declared-repo health".
What the score is made of, and what it explicitly is not
Measured on well-known packages and their repositories. The first and last rows are the engine's own words.
Every answer carries an honesty note stating that the trust score is a risk signal and not a security guarantee. That is in the payload rather than in documentation, because the consumer of this endpoint is frequently an automated gate that never reads documentation.
A provenance block names every contributing source — registry metadata, download counts, repository health, vulnerabilities, community signal — with a matched or skipped status on each. A low score because a section is missing is a different thing from a low score because a section came back bad, and you can tell which you have.
The repository a package claims is resolved and returned with a match confidence and a match class. Trusting a registry's repository field without checking it is precisely the gap that dependency-confusion and typosquat attacks live in.
A package can be enormously popular and unmaintained, or freshly maintained with an incompatible licence. Separate sub-scores make those cases visible, where a single number hides them behind an average.
A full package assessment calls the registry, the download stats, the repository, the advisory database and the community source, and waits for all of them. Expect a couple of seconds rather than a couple of hundred milliseconds. This belongs in CI or a review step, not in an interactive path.
What people build with Package & Dependency Trust
The jobs this data is most often used for.
endpoints
credits per call
Security teams call lockfile_scan to trust-score every dependency in a project at once.
License-compliance tools use package_trust to catch copyleft or risky licenses before adoption.
Engineering teams use repo_trust to vet a library's maintenance and health before depending on it.
What Package & Dependency Trust data costs
The cheapest call here is 2 credits, so $15/mo (Pro) buys 5,000 of them — $1.50 per 1,000 credits. Credits roll over and never expire, and failed or blocked calls are not charged.
Full pricing →- 1,000 free credits on signup, no card
- One key, all 184 APIs, one credit pool
- Failed and blocked calls are never charged
- Credits roll over and never expire
Call it in two lines
Sign up, get 1,000 credits and one key that works on every engine. Then this is the whole protocol.
curl -X POST https://api.reefapi.com/enrich-package/v1/package_trust \
-H "x-api-key: $REEF_KEY" \
-H "content-type: application/json" \
-d '{"ecosystem":"npm","package":"lodash","version":"4.17.15","mode":"rich"}'import requests
r = requests.post(
"https://api.reefapi.com/enrich-package/v1/package_trust",
headers={"x-api-key": REEF_KEY},
json={
"ecosystem": "npm",
"package": "lodash",
"version": "4.17.15",
"mode": "rich"
},
)
print(r.json()["data"])Have a question? We got answers.
The questions people actually ask before wiring up Package & Dependency Trust.
Get a free key →metadata.license says MIT, so why is the license sub-score "unknown"?▾
Because the sub-score reads the SPDX id from the resolved GitHub repository, not the string the registry prints. A measured lodash call returned metadata.license.value "MIT" alongside repo.health.license "NOASSERTION", which is what GitHub reports when its licence detector cannot classify the LICENSE file. The score block then carried spdx_id "NOASSERTION", tier "unknown" and missing_reason "no license declared in registry/repo metadata". Read metadata.license.value for what the publisher declared, and read score.license.tier only when spdx_id is a real identifier.
Why did the same package and version score differently in two calls?▾
Because mode changes which inputs exist. lodash 4.17.15 came back with trust_score 56 under mode "rich" and 62 through the batch action, which runs at basic depth. The whole difference is maintenance: rich resolved days_since_last_release 147, releases_last_12mo 2 and contributors 30 and scored 65, while basic had all three as null and scored 90 on push recency alone. The method line says it plainly, "equal-weighted over available signals", so fewer signals can produce a higher number. Only compare packages scored at the same mode.
Does passing a version actually change the security score?▾
It changes the method, not just the number. With a version pinned the response scores only the advisories affecting that exact release: lodash 4.17.15 got 100 minus a weighted severity penalty and landed on 0. Without a version it scores the historical advisory set for the whole package using a severity floor and a saturating count term, and adds the flag historical_vulns_across_all_versions_pin_a_version_for_precise_read. Measured, requests unpinned scored 55 across 16 advisories. If you are auditing what you actually ship, pass the installed version.
What comes back for a package that does not exist?▾
An error, not an empty success. A measured call for npm package zzz-this-package-does-not-exist-9q8x7 returned ok:false with error.code NOT_FOUND, retryable false, the message "package 'zzz-this-package-does-not-exist-9q8x7' not found in npm" and meta.record_count 0. A bad ecosystem is rejected earlier and differently: ecosystem "cocoapods" returned INVALID_PARAM in under 2 ms with error.detail.allowed listing the six accepted values. Neither path substitutes a similarly named package.
Why does a Go or Maven package come back so thin?▾
Because full registry metadata and download counts exist only for npm and PyPI. A measured lookup on github.com/gin-gonic/gin returned meta.completeness_pct 20.0, provenance.registry status "unsupported", repo found false with reason "no_repo_field", and four of the five sub-scores as "unknown". You still get a real vulnerability scan: 8 advisories, one critical, each with fixed_versions. The overall grade was withheld as "insufficient-data" rather than dressed up as a letter.
vulnerabilities.count is 16 but items[] is empty. Is that a bug?▾
No, that is mode "basic". The count, highest_severity and the by_severity breakdown are always populated; the per-advisory list with ids, CVEs, summaries and fixed_versions ships only under mode "rich", which is the default on package_trust and is not available through batch. A measured rich lodash call returned 6 items including GHSA-35jh-r3h4-6jhm with cve_ids CVE-2021-23337 and CVE-2026-4800 and fixed_versions ["4.17.21"]. Note that cvss_base_score came back null on every advisory row we measured, so severity is the field to key on.
Does lockfile_scan give me severities?▾
Not reliably today. A measured requirements.txt scan reported total_vulns 20 with by_severity {critical:0, high:0, moderate:0, low:0, unknown:20} and highest_severity null on the summary and on every dependency row, while package_trust on one of those same packages classified its advisories as 1 high and 7 moderate. Use lockfile_scan to find which dependencies carry advisories and how many, then re-run the interesting ones through package_trust for the severity read. The scan is also bounded: direct plus lockfile-pinned dependencies, maximum 100, with manifest.truncated telling you when the cap bit.
What does repo.match.confidence mean, and when should I distrust the repo health?▾
It scores how the GitHub repository was tied to the package. Measured values: 1.0 with class "explicit-input" when you called repo_trust with owner and repo yourself, 0.95 with class "declared-exact" when the package's own repository field pointed at a repo whose name matched, with evidence strings spelling out the parse and a name_similarity of 1.00, and 0.0 with class "none" and reason "no_repo_field" for the Go module. A weak match also surfaces in the security flags as repo_unverified_health_half_excluded, so the score already discounts it.
What is the Package & Dependency Trust API?▾
Package & Dependency Trust API is a ReefAPI endpoint group for package & dependency trust It returns live JSON through POST requests under /enrich-package/v1.
Is the Package & Dependency Trust API free to try?▾
Yes. ReefAPI starts with 1,000 free credits, no card required. Package & Dependency Trust calls use the same shared credit balance as every other ReefAPI engine.
Do I need a Package & Dependency Trust login or account?▾
No login to Package & Dependency Trust is needed for the API response. You call ReefAPI with your x-api-key header, and the playground can run live examples before you create a production key.
How fresh is the Package & Dependency Trust data?▾
The page example is captured from a live package_trust call, and production requests fetch live data through ReefAPI rather than a static sample.
How many credits does the Package & Dependency Trust API use?▾
Package & Dependency Trust actions currently cost 2-5 credits per successful call. Failed or blocked calls are free, and all APIs draw from one credit pool.
Can I call Package & Dependency Trust from an AI assistant or MCP client?▾
Yes. Connect ReefAPI once through MCP and your assistant can call enrich-package actions with the same key, credit pool and JSON envelope used by normal REST requests.
18 Developer Tools APIs on the same key
One key, one credit pool, one response envelope. If you are pulling Package & Dependency Trust, you are one call away from the rest of the category — no second contract, no second integration.
Need something this API does not do?
Name the endpoint, the field, or a source we do not carry yet. We ship new APIs every week and you would be first to get the key. Real people read every message and reply the same day.
Try it on your own data before you pay anything
The call above is the real endpoint, not a recording. A free key gives you 1,000 credits, the other 183 APIs, and the same envelope everywhere.
Endpoints, parameters and credit costs on this page are read from the live catalog and cannot drift from what the API accepts. Field notes were captured on 2026-08-30.