Skip to main content
Both surfaces are on https://dash.square1.dev and accept either the ws-session cookie or a Bearer API key.

Change your password

POST /api/user/me/password5 requests/minute.
camelCase body. The new password must be at least 8 characters; there is no other composition rule.
Success revokes every session on the account — including this one — and then immediately issues a replacement, returned as a fresh ws-session cookie on the same response. Half the point of changing a password is cutting off a stolen session, so nothing else survives.If you called this with a Bearer key rather than a cookie, you are logged out of every browser and receive a session cookie you probably don’t want.
Your API keys are untouched. They are a separate credential, and quietly revoking them would kill every hardcoded client at once. Rotate them explicitly from API keys if that’s what you want.

Errors

The 409 fires after the current-password check has already run against a dummy hash, so the response time doesn’t reveal whether a password exists. Both success and failure are written to the account’s audit trail.

Passkeys

Four endpoints under /api/user/me/passkeys, holding up to 5 WebAuthn credentials per account.
Passkeys are behind an operator switch. When it’s off, all four endpoints answer 404 with code feature_disabled — the surface reports itself as nonexistent rather than as forbidden:
Check passkeyCount on GET /api/user/me — it reads 0 whenever the feature is off — before assuming a 404 means “no passkeys”.

List — GET /api/user/me/passkeys

camelCase. Oldest first, revoked credentials excluded. id is the WebAuthn credential id. When you didn’t name a passkey, label falls back to a recognized device name for its authenticator. deviceType is the authenticator’s WebAuthn device type (singleDevice or multiDevice), and is an empty string when the authenticator didn’t report one.

Register — two steps

Registration is the standard WebAuthn ceremony split across two calls. 1. POST /api/user/me/passkeys/options
Pass optionsJSON straight to navigator.credentials.create(). The response also sets a ws-pk cookie — a browser-session key, separate from ws-session, that binds the challenge to this tab. It lives 10 minutes; the challenge behind it expires after 5. A 409 (no code) means the challenge could not be started — most often because you already hold max passkeys. The cap is enforced here, at the start of the ceremony, not at the finish. 2. POST /api/user/me/passkeys
label is optional. Both a missing response and a missing/expired ws-pk cookie return 400 passkey_challenge_invalid, as does a response that fails verification.
Because the challenge is keyed to the ws-pk cookie rather than to your account, two browser tabs can register independently without one overwriting the other’s challenge. It also means the two calls must come from the same cookie jar — this ceremony is not scriptable with a Bearer key alone.

Revoke — DELETE /api/user/me/passkeys/:id

:id is the credential id from the list. 404 if it isn’t yours or is already revoked. Revocations are audited.
Nothing stops you from revoking your last passkey. Make sure you still have a working password or API key first.