OSS Protector developer docs
Public REST API, maintainer-authenticated endpoints, rate limits, pagination, repository configuration, and authentication.
What this is
OSS Protector exposes a small public REST API (used by other tools and automations to read the public account directory) and a set of authenticated maintainer endpoints (used by the dashboard at /dashboard). All responses are JSON.
The shape stabilises through schema_version; breaking changes bump the date.
Base URL
https://oss-protector.raedbahri90.workers.devSchema version
Every public response includes "schema_version" (an ISO date). When we bump this, the response shape changed. Pin consumers to a date and re-test before upgrading.
Current: 2026-05-30
Public API
Three public read endpoints. All are throttled per client IP — see Rate limits.
/api/accounts/api/accounts?status=review&reason=external_blocklist&min_score=70&limit=10&offset=0| Query | Values | Meaning |
|---|---|---|
| q | string | Search login or evidence summary. |
| status | all, watch, review, high_risk, block | Filter by published review status. 400 on unknown values. |
| reason | all, fake_bounty, ai_slop, spam_pr, duplicate_pr, low_quality_ai, credential_phishing, malicious_code, impersonation, maintainer_report, honeypot_match, external_blocklist | Filter by stored abuse reason. 400 on unknown values. |
| min_score | integer 0–100 | Only return accounts at or above this score (0–100). |
| limit | integer 1–500 | Page size. Default 50. Larger values rejected with 400. |
| offset | integer 0–50000 | Offset for pagination. Use with limit. Larger values rejected with 400. |
/api/protectors/api/protectors?min_reports=1&min_score=10&limit=10| Query | Values | Meaning |
|---|---|---|
| q | string | Search maintainer login. |
| min_score | integer 0–100 | Only return maintainers at or above this validated score. |
| min_reports | integer 0–500 | Only return maintainers with at least this many review signals. |
| limit | integer 1–500 | Page size. Default 50. |
| offset | integer 0–50000 | Offset for pagination. |
/api/openrouter/free-models/api/openrouter/free-modelsPagination
All filterable endpoints (/api/accounts, /api/protectors) accept the same pagination params and return a page_info block.
limit + offset
| Param | Default | Bounds | Behavior |
|---|---|---|---|
| limit | 50 | 1–500 | Out-of-bounds → 400. |
| offset | 0 | 0–50000 | Out-of-bounds → 400. |
page_info
{
"accounts": [...],
"count": 50,
"page_info": {
"limit": 50,
"offset": 0,
"total": 149,
"hasMore": true
},
"filters": { ... },
"schema_version": "2026-05-30"
}count is this page's row count; total is the full matched set. To iterate, increment offset by limit until hasMore is false.
Maintainer API
Authenticated endpoints used by the dashboard. They require an active Better Auth session cookie — sign in at /login. Not rate-limited by the public 60 req/min bucket. All return 401 when called without a session.
/api/user/preferences/api/openrouter/test/api/maintainer/repo-decision{ repositoryId, targetLogin, decision: 'block' | 'allow', note? }. DELETE clears the override./api/maintainer/repo-decisions/api/maintainer/repo-policy?repositoryId=…enabled, analyzePrivateRepositories, minimumLikelyAbuseConfidence, trustedAuthors, ignoredPaths). The committed .github/oss-protector.json takes precedence per-field.Rate limits & errors
/api/accounts, /api/protectors) are throttled per IP via Cloudflare Rate Limiting. IPv6 clients are bucketed by /64 prefix. Webhooks and maintainer endpoints are not throttled. Over-limit responses return HTTP 429 with Retry-After: 60.400 on invalid filter
Invalid filter values (unknown status/ reason, out-of-range limit/offset/min_score) return HTTP 400 with a structured body so you can correct the request without scraping the message:
{
"error": "Invalid limit \"1000\". Allowed: 1–500.",
"field": "limit",
"value": "1000",
"allowed": ["1–500"]
}Bot commands
Bot-driven endpoints — invoked by mentioning @oss-protector in a PR or issue comment.
Report commands
Anyone can file a report by mentioning the bot. Submitted / needs-review reports are tracked but only validated or corroborated reports affect shared scores.
@oss-protector review this user
@oss-protector flag this user reason: fake bounty
@oss-protector recommend block reason: malicious codeMaintainer corrections
Repo owners and members (author_association of OWNER, MEMBER, or COLLABORATOR) can correct the system from any PR comment. Each correction is applied silently and recorded as an in-app notification — no reply is posted to the PR.
@oss-protector dismiss # false positive: dismiss all open reports
@oss-protector confirm # validate the latest open report
@oss-protector allow # allowlist the PR author (sticky)
@oss-protector reset # clear a prior allowlist; recompute from current signalsConfiguration
Repository policy
Each repo can tune the analyzer with .github/oss-protector.json:
{
"enabled": true,
"analyzePrivateRepositories": false,
"minimumLikelyAbuseConfidence": 80,
"trustedAuthors": ["dependabot[bot]", "renovate[bot]"],
"ignoredPaths": ["docs/", "examples/"]
}Dashboard editor
The same fields can be edited from the Repo policy tab in the dashboard. When both exist, the committed file wins per-field; the dashboard value fills in any field the file doesn't set.
Authentication
OSS Protector uses Better Auth for end-user sign-in and an installation-token model (@octokit/auth-app) for webhook actions.
GitHub OAuth
The default sign-in path. Better Auth handles the OAuth round trip — clicking Continue with GitHub on /login POSTs to /api/auth/sign-in/social, which returns a github.com authorize URL the browser follows. Callback URL: /api/auth/callback/github.
Email OTP
Optional email-only sign-in. Requires RESEND_API_KEY to be set on the Worker. Without it, the send is rejected with a clear error in non-localhost environments (codes log to the server console in local dev).
src/routes/docs.tsx.