CleanLibrary API Key Onboarding
Audience: Early-access customers
1. Quick start
CleanLibrary's customer-verdict endpoint at https://cleanapp.clnstrt.dev authenticates requests with a Bearer token issued to your organization by CleanStart. Set it as an environment variable and pass it on each request:
curl -sH "Authorization: Bearer $CLEANLIB_API_KEY" \
https://cleanapp.clnstrt.dev/v1/customer/verdicts/npm/cors/2.8.4 | jq
To request an early-access token, contact CleanStart at cto.office@cleanstart.com.
1.5 Install the tooling
The customer surfaces are published to standard registries — no sideload or git-clone required.
| Surface | Install |
|---|---|
| VS Code extension | Search "CleanLibrary" in the VS Code Extensions view (Cmd+Shift+X / Ctrl+Shift+X) → Install. Or CLI: code --install-extension cleanstart.cleanlibrary |
| MCP server (Claude Desktop / Cursor / Windsurf / Cline) | pip install cleanlib-mcp-server (LIVE on PyPI). Then point your MCP client config at the installed entry point + set CLEANLIB_ENDPOINT + CLEANLIB_API_KEY env vars |
| Python SDK | pip install cleanlib-sdk |
| Go SDK | go get pkg.clnstrt.dev/cleanlib-sdk-go |
| JS/TS SDK | npm install @cleanstart/cleanlib-sdk |
CLI cleanlib | Distributed as a statically-linked binary (Rust); install path per release artifacts |
After installing, configure each surface with your Bearer token per the matrix below.
1.6 Batch scanning — POST /v1/scan
Resolve verdicts for many coordinates in a single request. POST a packages
array, each entry {ecosystem, package, version}:
curl -sH "Authorization: Bearer $CLEANLIB_API_KEY" \
-H "Content-Type: application/json" \
-X POST https://cleanapp.clnstrt.dev/v1/scan \
-d '{
"packages": [
{"ecosystem": "npm", "package": "cors", "version": "2.8.4"},
{"ecosystem": "pypi", "package": "requests", "version": "2.31.0"}
]
}' | jq
The response is a results array (one entry per requested package, order
preserved) plus a coverage summary. Each result echoes its ecosystem /
package / version and carries the same customer-verdict fields as the
single-package endpoint — customer_state, state, source_state,
reason_class, and (when applicable) remediation:
{
"results": [
{
"ecosystem": "npm", "package": "cors", "version": "2.8.4",
"customer_state": "clean", "state": "ALLOWED", "source_state": "ALLOWED_NO_FINDINGS"
},
{
"ecosystem": "pypi", "package": "requests", "version": "2.31.0",
"error": "…"
}
],
"coverage": { "…": "per-scan coverage summary" }
}
Partial success: one bad coordinate never fails the batch. A package that
cannot be resolved carries an error string on its own result entry while every
other package still returns its verdict. A well-formed request returns HTTP
200; inspect each entry for its per-package outcome.
Attestation: batch results carry an attestation_status field but no
per-package signed cosign object — call the single-package endpoint
(/v1/customer/verdicts/{ecosystem}/{package}/{version}) when you need the full
signed attestation.
Rate limits (§1.7) apply to the /v1/scan request as a whole, not per package.
1.7 Rate limits & 429 responses
Requests are rate-limited per (organization-tier, route). Every response carries
X-RateLimit-Limit (the sustained per-minute ceiling) and X-RateLimit-Reset
(the 60-second window). X-RateLimit-Remaining is intentionally not sent —
the limiter keeps no faithful remaining-token count, and an approximate value
would mislead a self-throttling client.
When you exceed the quota the response is HTTP 429 with a Retry-After: <seconds>
header and the body below. Note that error is a nested object (matching the
401 shape), with retry_after_seconds and tier as siblings — not a flat
string:
{
"error": {
"code": "rate_limited",
"message": "Rate limit exceeded for tier <Tier>; retry after <n> seconds",
"request_id": "…"
},
"retry_after_seconds": <n>,
"tier": "<Tier>"
}
Back off using Retry-After (or the equivalent retry_after_seconds) rather
than retrying immediately; both carry the same window.
2. Configuration matrix
| Surface | How to configure | Notes |
|---|---|---|
| VS Code extension | Run CleanLibrary: Set API Key from the Command Palette (Cmd+Shift+P) — stored in OS keychain via VS Code SecretStorage (v0.1.3+). Set cleanlib.endpoint: https://cleanapp.clnstrt.dev in Settings | The cleanlib.apiKey setting is DEPRECATED (auto-migrated to keychain on activation). 4-state status bar shows connection mode (cyan LIVE_CONNECTED / amber LIVE_WITH_FALLBACK / red ERROR / gray NOT_CONFIGURED); falls back to local fixtures if no key set |
| Python SDK | CleanlibClient(endpoint="https://cleanapp.clnstrt.dev", api_key="clk_poc_...") | See sdk-py README |
| Go SDK | cleanlibsdk.NewClient("https://cleanapp.clnstrt.dev", cleanlibsdk.WithAPIKey("clk_poc_...")) | See sdk-go README |
| JS/TS SDK | new CleanlibClient("https://cleanapp.clnstrt.dev", { apiKey: "clk_poc_..." }) | See sdk-js README |
| MCP server (Claude Desktop / Cursor / Windsurf / Cline) | Set CLEANLIB_ENDPOINT + CLEANLIB_API_KEY env vars in your MCP client config | See cleanlib-mcp-server README |
CLI cleanlib | ~/.config/cleanlib/config.toml with endpoint = "..." + api_key = "..." | Or CLEANLIB_ENDPOINT + CLEANLIB_API_KEY env |
| Raw curl | -H "Authorization: Bearer <key>" | Examples throughout POC walkthroughs |
3. Phase 1 (GA) production key provisioning — forthcoming
At Phase 1 General Availability, CleanLibrary will provision per-customer-organization API keys via CDP (Customer Data Platform) admin UI. Each customer organization gets:
- A unique
organization_id(UUID; one per customer) - One or more API keys scoped to that
organization_id - Per-org rate limits (Phase 1 baseline: 100/min, 1000/h, 10000/d — scales per commercial tier)
- Per-org policy assignment + verdict-API access
During early-access evaluation, CleanStart issues your organization a token directly; the self-service CDP provisioning flow above arrives at General Availability.
4. Key rotation + security
- Treat your API token as a secret: store it in a secret manager, never commit it
- To rotate or revoke a token during early-access, contact CleanStart
For Phase 1 GA + commercial deployment:
- Keys rotated via CDP admin UI (forthcoming)
- Recommend storing in your environment's secret manager (GCP Secret Manager, AWS Secrets Manager, HashiCorp Vault, etc.) — never inline in source or commits
- API keys must be fetched at runtime — never baked into images or committed to source
5. Cosign attestation chain (read-only)
Every artifact CleanLibrary serves carries a cosign attestation signed with CleanStart's current cosign attestation signing key. The attestation binds verdict_id, policy_decision, risk_acceptance_status, app_version, and served_at, so your compliance team can verify provenance and extract it as SBOM material.
Verify against the published key CleanStart provides — do not assume a key identity. Contact CleanStart at cto.office@cleanstart.com for the current published verification key and cosign verify instructions.
6. Troubleshooting
| Symptom | Likely cause | Resolution |
|---|---|---|
401 Unauthorized from /v1/customer/verdicts/... | Missing Authorization header | Add -H "Authorization: Bearer ..." |
404 Not Found with JSON body {"error":"verdict_not_found",...} | Package version not in the current evaluation set | Try one of the 4 anchor packages (cors/helmet/dotenv/oracledb) with documented versions |
404 Not Found with HTML body | Cloud Run reachability issue | Check https://cleanapp.clnstrt.dev/health returns 200 + JSON |
| Connection refused / TLS error | Cert provisioning or DNS issue (rare) | Contact onboarding |
| SDK / extension stuck loading | Endpoint mis-configured (typo or http vs https) | Verify endpoint is https://cleanapp.clnstrt.dev exactly |
7. Support
- Evaluation + API questions: cto.office@cleanstart.com
- Security disclosure: cto.office@cleanstart.com
8. What's next (post Phase 1 GA)
- Per-customer-organization key provisioning via CDP admin UI
- Self-service key rotation
- Tiered rate limits by plan
- API key scopes (read-only verdict vs write-policy vs admin)
- OAuth flow for IDE extensions