# PDS Endpoint Comparison: pds.js vs atproto/packages/pds Comparison of endpoints and parameters between this implementation and the official AT Protocol PDS. --- ## Endpoints Missing from pds.js ### com.atproto.admin.* (entire namespace missing) | Endpoint | Params | |----------|--------| | deleteAccount | did | | disableAccountInvites | account, note | | disableInviteCodes | accounts, codes | | enableAccountInvites | account, note | | getAccountInfo | did | | getAccountInfos | dids | | getInviteCodes | cursor, limit, sort | | getSubjectStatus | blob, did, uri | | searchAccounts | cursor, email, limit | | sendEmail | comment, content, recipientDid, senderDid, subject | | updateAccountEmail | account, email | | updateAccountHandle | did, handle | | updateAccountPassword | did, password | | updateAccountSigningKey | did, signingKey | | updateSubjectStatus | deactivated, subject, takedown | ### com.atproto.identity.* (partially implemented) Still missing: | Endpoint | Params | Notes | |----------|--------|-------| | refreshIdentity | identifier | | | resolveDid | did | | | resolveIdentity | identifier | | *pds.js implements: resolveHandle, updateHandle, getRecommendedDidCredentials, requestPlcOperationSignature, signPlcOperation, submitPlcOperation* `updateHandle` submits a did:plc operation repointing the DID document's `alsoKnownAs` at the new handle, persists it, and emits an `#identity` firehose event so consumers re-resolve. It only accepts a handle that resolves back to the account: the server's own address is taken as-is, a subdomain of it is refused (a single-user PDS answers only at its own host), and any other domain must already resolve to the DID via a `_atproto` DNS TXT record or the HTTPS well-known. `requestPlcOperationSignature` mails a confirmation code when the deployment has a sender and the account has a confirmed address, and `signPlcOperation` then requires it — one code, one operation. Without both, no code is issued and the session remains the only authorization, as before. ### com.atproto.server.* (many missing) | Endpoint | Params | |----------|--------| | confirmEmail | email, token | | createInviteCode | forAccount, useCount | | createInviteCodes | codeCount, forAccounts, useCount | | deleteAccount | did, password, token | | getAccountInviteCodes | createAvailable, includeUsed | | requestAccountDelete | (none) | | requestEmailConfirmation | (none) | | requestEmailUpdate | (none) | | requestPasswordReset | email | | reserveSigningKey | did | | resetPassword | password, token | | updateEmail | email, emailAuthFactor, token | *pds.js implements: createAccount, createSession, getSession, refreshSession, deleteSession, createAppPassword, listAppPasswords, revokeAppPassword, describeServer, activateAccount, deactivateAccount, checkAccountStatus, getServiceAuth* *createAccount supports the account-migration shape only (adopt an existing `did` onto an empty single-tenant server), authorized by a service token from the current PDS or the configured account password. The node and cloudflare packages verify the token's signature against the issuer's atproto key — P-256 in core, secp256k1 (the curve the reference PDS gives every account) via @noble/curves — resolving the issuer's DID document to find the key. A token that cannot be verified is rejected. A core-only deployment with no verifier injected falls back to validating the token's claims alone.* ### com.atproto.sync.* (some missing) | Endpoint | Params | |----------|--------| | getBlocks | cids, did | | getHostStatus | hostname | | listHosts | cursor, limit | | listReposByCollection | collection, cursor, limit | | notifyOfUpdate | hostname | | requestCrawl | hostname | *pds.js implements: listRepos, getLatestCommit, getRepoStatus, getRepo, getRecord, getBlob, listBlobs, subscribeRepos* ### com.atproto.repo.* (complete) *pds.js implements: createRecord, deleteRecord, putRecord, applyWrites, getRecord, describeRepo, listRecords, uploadBlob, importRepo, listMissingBlobs* ### com.atproto.moderation.* | Endpoint | Params | |----------|--------| | createReport | modTool, reason, reasonType, subject | ### com.atproto.temp.* (entire namespace missing) | Endpoint | Params | |----------|--------| | addReservedHandle | handle | | checkHandleAvailability | birthDate, email, handle | | checkSignupQueue | (none) | | dereferenceScope | scope | | fetchLabels | limit, since | | requestPhoneVerification | phoneNumber | | revokeAccountCredentials | account | --- ## Missing Parameters in Shared Endpoints Endpoints that exist in both implementations, but pds.js is missing parameters: | Endpoint | pds.js has | Missing from pds.js | |----------|------------|---------------------| | repo.createRecord | collection, record, rkey, **validate** | **repo**, swapCommit | | repo.deleteRecord | collection, rkey | **repo**, swapCommit, swapRecord | | repo.putRecord | collection, rkey, record, **validate** | **repo**, swapCommit, swapRecord | | repo.applyWrites | writes, **validate** | **repo**, swapCommit | | sync.getRepo | did | since | | sync.listBlobs | did, cursor, limit | since | | sync.listRepos | (none) | cursor, limit | | server.createSession | identifier, password | allowTakendown, authFactorToken | **Bold** = likely important for compatibility --- ## app.bsky.* Coverage Both implementations handle app.bsky.* the same way: | Category | Endpoints | Notes | |----------|-----------|-------| | Native (stored in PDS) | actor.getPreferences, actor.putPreferences | Both implementations | | Proxied to AppView | ~87 endpoints | feed.*, graph.*, notification.*, etc. | --- ## Extra in pds.js (not in atproto spec) Custom endpoints specific to this implementation: | Endpoint | Purpose | |----------|---------| | `POST /init` | Initialize PDS with DID/keys | | `GET /status` | Health check | ### OAuth 2.0 Stack (full implementation) | Endpoint | Purpose | |----------|---------| | `GET /.well-known/oauth-authorization-server` | OAuth server metadata | | `GET /.well-known/oauth-protected-resource` | Protected resource metadata | | `GET /oauth/jwks` | JSON Web Key Set | | `POST /oauth/par` | Pushed Authorization Request | | `GET/POST /oauth/authorize` | Authorization endpoint | | `POST /oauth/authorize/passkey` | Approve a request with a passkey assertion | | `POST /oauth/token` | Token endpoint (with DPoP) | | `POST /oauth/revoke` | Token revocation | ### Account pages Server-rendered, like the consent page; the reference PDS serves the same paths from the React app in `@atproto/oauth-provider-ui`. | Endpoint | Purpose | |----------|---------| | `GET /account` | Account home, or the sign-in form when signed out | | `POST /account/sign-in` | Verify the account password, start a cookie session | | `POST /account/sign-out` | Clear the cookie session | | `GET /account/apps` | Apps holding an OAuth session | | `POST /account/apps/revoke` | End one app's OAuth session | | `GET /account/sessions` | Logins opened with a password | | `POST /account/sessions/revoke` | End one password login | | `GET /account/spaces` | Permissioned-data spaces, when enabled | | `GET /account/spaces/records` | The records in one space collection | | `GET /account/passkeys` | Registered passkeys, and the form to add one | | `POST /account/passkeys/register` | Store a credential the browser created | | `POST /account/passkeys/revoke` | Forget one passkey | | `GET /account/passkey/challenge` | Start a passkey sign-in | | `POST /account/passkey/sign-in` | Open a session from a passkey assertion | | `GET/POST /account/email` | Address and confirmation state; POST sets it | | `POST /account/email/verify` | Exchange the emailed code | | `POST /account/email/cancel` | Drop a pending address change | | `POST /account/email/remove` | Forget the address | | `GET /account/app-passwords` | App password list and creation form | | `POST /account/app-passwords/create` | Create one, shown exactly once | | `POST /account/app-passwords/revoke` | Revoke one by name | | `GET /account/repo` | Record counts by collection, blobs, latest commit | | `GET /account/repo/records` | The records in one repo collection | | `GET /account/identity` | Published identity and account status | | `POST /account/status` | Activate or deactivate the account | --- ## Summary | Category | pds.js | atproto PDS | |----------|--------|-------------| | com.atproto.admin.* | 0 | 15 | | com.atproto.identity.* | 6 | 9 | | com.atproto.moderation.* | 0 | 1 | | com.atproto.repo.* | 10 | 10 | | com.atproto.server.* | 9 | 25 | | com.atproto.sync.* | 8 | 14 | | com.atproto.temp.* | 0 | 7 | | app.bsky.* (native) | 2 | 2 | | app.bsky.* (proxied) | ~87 | ~87 | | **Total XRPC (native)** | **34** | **85** | | Custom endpoints | 2 | 0 | | OAuth endpoints | 8 | 7 (via @atproto/oauth-provider) | | Account pages | 25 | 2 + SPA routes (via @atproto/oauth-provider) |