The Syphon registry API. Base URL: https://syphon-api.vercel.app (env: NEXT_PUBLIC_API_URL)
All endpoints return JSON. Successful responses use HTTP 200/201. Errors use 4xx/5xx with a consistent error body. Paginated endpoints accept limit (max 100) and offset query params.
Pass a bearer token in the Authorization header:
curl https://syphon-api.vercel.app/v1/users/me \
-H "Authorization: Bearer syph_xxxxxxxx..."Tokens start with syph_. Create them with syphon token create. Supabase JWTs (from web login) are also accepted.
{
"error": {
"code": "NOT_FOUND",
"message": "Package not found: github-tools",
"retry_after": null
}
}| Status | Meaning |
|---|---|
| 400 | Bad request — validation error |
| 401 | Missing or invalid auth token |
| 403 | Forbidden — valid token but insufficient permissions |
| 404 | Resource not found |
| 409 | Conflict — e.g. version already published |
| 422 | Unprocessable — e.g. failed signature verification |
| 429 | Rate limit exceeded — see Retry-After header |
| 500 | Internal server error |
/v1/auth/devicedevice-poll rateStart a device-code OAuth flow. Returns a user_code to display to the user and a device_code for polling.
{ "device_code": "...", "user_code": "ABCD-1234", "verification_uri": "https://syphon-web.vercel.app/activate", "expires_in": 900, "interval": 5 }/v1/auth/device/pollPoll for device-code flow completion. Call every interval seconds until you get a token or an error.
{ "device_code": "..." }{ "token": "syph_...", "user": { "username": "...", "email": "..." } }/v1/auth/activateauth requiredApprove a pending device-code request. Called by the web UI when the user clicks 'Approve'. Requires auth (token:write scope).
{ "user_code": "ABCD-1234" }/v1/auth/signupCreate a new account.
{ "email": "...", "password": "...", "username": "..." }{ "user": { "id": "...", "username": "..." } }/v1/auth/signinSign in with email/password and receive a session token.
{ "email": "...", "password": "..." }{ "token": "syph_...", "user": { "username": "..." } }/v1/packagesSearch the registry. Query params: search, category, verified, sort, limit (max 100), offset.
{ "packages": [...], "total": 42 }/v1/packagesauth requiredpublish ratePublish a new version. Multipart/form-data: tarball (file), meta (JSON string). Meta includes manifest, signature (base64), checksum (SHA-256), pubkey (hex), tag, access.
{ "name": "github-tools", "version": "1.0.0", "created_at": "..." }/v1/packages/:nameGet full package details: metadata, all versions, download count, star count, author info.
{ "id": "...", "name": "...", "description": "...", "latest_version": "1.0.0", "downloads": 2400, "stars": 12, "author": { "username": "...", "pubkey": "..." }, "versions": [...] }/v1/packages/:nameauth requiredDelete the entire package (all versions). Only available within 72 hours of first publish, or to org owners.
/v1/packages/:name/readmeGet the package README as plain text. Cached — updates after each publish.
{ "content": "# github-tools
..." }/v1/packages/:name/downloadsGet download counts by day for the last 30 days.
{ "total": 2400, "daily": [{ "date": "2026-05-01", "count": 80 }, ...] }/v1/packages/:name/starauth requiredToggle a star on a package.
{ "starred": true }/v1/packages/:name/transferauth requiredTransfer package ownership to another user or org.
{ "to": "new-owner" }/v1/packages/:name/accessauth requiredChange package visibility.
{ "access": "public" | "private" }/v1/packages/:name/deprecateauth requiredMark a package as deprecated with an optional message.
{ "message": "Use my-new-package instead" }/v1/packages/:name/versions/:versionGet version metadata and a signed download URL for the tarball.
{ "version": "1.0.0", "tarball_url": "https://...", "checksum_sha256": "...", "signature_ed25519": "...", "author_pubkey": "...", "published_at": "..." }/v1/packages/:name/versions/:versionauth requiredUnpublish a specific version. Only within 72 hours of publish.
/v1/packages/:name/filesList files in the latest version tarball.
{ "files": [{ "name": "dist/index.js", "size": 24300 }, ...] }/v1/users/meauth requiredGet the authenticated user's profile, package count, total downloads, and org memberships.
{ "user": { "username": "...", "email": "...", "display_name": "...", "created_at": "..." }, "package_count": 7, "total_downloads": 12400, "orgs": ["my-org"] }/v1/users/meauth requiredUpdate profile fields. All fields optional.
{ "display_name": "Misbah", "bio": "...", "website": "https://...", "github_url": "https://github.com/...", "avatar_url": "https://...", "location": "London", "twitter": "@handle" }/v1/users/me/pubkeyauth requiredRegister or rotate your ed25519 public key (hex).
{ "pubkey": "a3f8b2c1..." }/v1/users/:usernameGet a user's public profile and package list.
{ "username": "...", "packages": [...], "total_downloads": 12400 }/v1/orgsauth requiredCreate a new organisation.
{ "name": "my-org" }/v1/orgs/:orgauth requiredGet org details and member list.
/v1/orgs/:org/invitesauth requiredInvite a user to the org.
{ "username": "alice", "role": "member" | "admin" }/v1/orgs/:org/members/:usernameauth requiredRemove a member from the org.
/v1/tokensauth requiredCreate a new API token. Named tokens default to read-only; request scopes explicitly. The plain-text token is only returned once.
{ "name": "ci-deploy", "expires_in_days": 90, "scopes": ["publish"] }{ "id": "...", "plaintext": "syph_...", "name": "ci-deploy", "scopes": ["publish"], "expires_at": "..." }/v1/tokensauth requiredList all tokens (without the plain-text value).
{ "tokens": [{ "id": "...", "name": "ci-deploy", "prefix": "syph_ab", "scopes": ["publish"], "created_at": "...", "expires_at": "...", "last_used_at": "..." }] }/v1/tokens/:idauth requiredRevoke a token immediately.
Sync API — persists your per-machine install state to the cloud so syphon sync can restore it on a new machine.
/v1/installedauth requiredGet all installed packages for the authenticated user. Query param: profile (optional label).
{ "installed": [{ "name": "github-tools", "version": "1.0.0", "checksum_sha256": "...", "linked_frameworks": ["claude-code"], "profile": null }] }/v1/installed/:nameauth requiredUpsert one installed package record.
{ "version": "1.0.0", "checksum_sha256": "...", "signature_ed25519": "...", "author_pubkey": "...", "linked_frameworks": ["claude-code"], "profile": null }{ "ok": true, "id": "..." }/v1/installed/:nameauth requiredRemove an installed package record. Query param: profile.
/v1/installed/bulk-replaceauth requiredstrict rateReplace the entire install list for the authenticated user + profile in one atomic operation.
{ "packages": [...], "profile": null }{ "replaced": 7 }/v1/advisoriesList all active advisories. Query params: package, severity (low|medium|high|critical).
{ "advisories": [{ "id": "...", "package": "...", "affected_versions": "^1.0.0", "severity": "high", "description": "...", "published_at": "..." }] }/v1/advisories/checkCheck a list of packages against the advisory database. Returns only the packages with known vulnerabilities.
{ "packages": [{ "name": "github-tools", "version": "1.0.0" }] }{ "advisories": [{ "id": "...", "package": "github-tools", "vulnerable_versions": "^1.0.0", "patched_versions": ">=1.1.0", "severity": "high", "summary": "...", "url": "...", "published_at": "..." }] }/v1/webhooksauth requiredList webhooks for the authenticated user.
{ "webhooks": [{ "id": "...", "url": "https://...", "events": ["package.published"], "created_at": "..." }] }/v1/webhooksauth requiredCreate a webhook. Supported events: package.published, package.yanked, package.deprecated.
{ "url": "https://your-server.example.com/hook", "events": ["package.published", "package.yanked"] }{ "id": "...", "url": "...", "events": [...], "created_at": "..." }/v1/packages/trendingGet trending packages (most downloaded in the last 7 days). Query param: limit (max 50).
{ "packages": [...] }/v1/packages/categoriesGet all categories with package counts.
{ "categories": [{ "name": "devtools", "count": 42 }] }/v1/packages/tagsGet all tags. Query param: search.
/v1/healthRegistry health check. Returns 200 if the API is up.
{ "status": "ok", "timestamp": "..." }