Skip to main content
A registration is an account at one app, keyed by that app’s URL origin. POST /v1/registrations starts a browser run that fills the app’s own signup form and completes email verification from the account’s own inbox; when it finishes you have a durable account you can re-login, hand to a browser, or export as a session. The same endpoints serve both kinds of account: created (Sente signed it up) and connected (you own it and supplied the credentials — see Connections). Sessions, re-login, credential writes, and session export all live here and take either id.
Register only at apps whose terms permit automated account creation — see Acceptable use. Pass confirmBeforeSubmit: true to keep a person on the final click. CAPTCHAs and SMS verification are not automated: the run stops, pages a human with an interactive live view, and waits. Nothing is worked around.

The registration object

One registration exists per (identity, app origin). https://app.example.com/signup and https://app.example.com/ are the same registration; example.com and app.example.com are different ones.

Register at an app

POST /v1/registrations Returns 201 with the registration and the run driving it.
Poll GET /v1/runs/:id or subscribe to the run.* webhooks for the outcome.

Idempotency

The call converges instead of erroring. Re-posting the same (identity, app origin):

Errors

When identityId is omitted and the registration itself then fails, the auto-provisioned identity is deleted again — a failed call doesn’t quietly consume your identity cap.

List registrations

GET /v1/registrations Each row embeds latestRun (a full run object, or null) so a dashboard can render status without a second call. Newest first.
The list includes both kinds. Filter client-side on kind, or use GET /v1/connections for connected accounts only. Passing an identityId that isn’t your org’s returns 404 {"error": "identity not found"}.

Get a registration

GET /v1/registrations/:id
Response 200: the registration object (no latestRun). 404 {"error": "not found"} otherwise.

Log in again

POST /v1/registrations/:id/login Queues a login run that re-authenticates with the vaulted credentials, completing email verification from the account’s own inbox if the app sends a code, and injecting a TOTP code server-side if a seed is vaulted. Works for created and connected accounts. No body.
Response 201: { "registration": { … }, "run": { …, "type": "login", "status": "queued" } }. If a run is already in flight for that identity, you get that run back instead of a second one.

Open a logged-in browser session

POST /v1/registrations/:id/session Opens a browser on the identity’s persistent profile — already signed in to this app — and returns a CDP URL for chromium.connectOverCDP (Playwright) or puppeteer.connect. Conceptual walkthrough: Sessions. The login is verified by recency, not by inspecting the page: if the last confirmed login is within the freshness window (10 minutes by default), the session opens immediately; if it is older, Sente queues a re-login run and answers 409 SESSION_STALE with the runId to poll before retrying.
Response 201:
verified and healed are present only on the default (verified) path — with verify: false the response carries sessionId, cdpUrl, liveViewUrl, and expiresAt alone. The cdpUrl is returned once and never stored; a new session mints a new one. One live session per identity, and it is mutually exclusive with runs — both drive the same browser profile.
The SDK method registrations.getSession(id) (get_session in Python) already implements the 409-poll-retry loop: it waits out the re-login run and returns the session, with healed: true when a re-login happened. Use it instead of writing the loop yourself.

Close the session

DELETE /v1/registrations/:id/session Stops the identity’s open browser session and frees the slot. Idempotent — closing when nothing is open still returns 204. Sessions bill per minute while open, so close them.
Response: 204 with no body.

Export session state

POST /v1/registrations/:id/session/export Returns a portable Playwright storageState (cookies + localStorage) for the logged-in account, loadable into your own Playwright, Puppeteer, or browser-use — no Sente browser needed afterwards. Takes the same verify / maxStaleSec body and the same 409 SESSION_STALE / SESSION_PENDING contract as /session. If a session is already open, Sente exports from it and leaves it open. Otherwise it opens one, exports, and closes it again.
Response 200:
The export is a bearer credential for a logged-in account — anyone holding it is signed in as that account, and Sente cannot revoke it. Store it like a password. Every export writes a session.export audit event.

Get credentials

GET /v1/registrations/:id/credentials For Sente-created accounts: returns the vaulted username and password in plaintext, because the password is one Sente generated and you have no other copy. Every read writes a credentials.read audit event.
Response 200:
origin is generated (Sente made the password) or supplied (you provided it). Any field may be null if it was never set.

Update credentials

PUT /v1/registrations/:id/credentials
This overwrites the vault only. It does not change the password at the app. Use it after you rotate the password at the app yourself — otherwise the vault and the app desync and the next login run fails.
Response: 204 with no body. Writes a credentials.write audit event. Returns 409 {"code": "REVOKED"} if the account is disabled (a revoked connection).

Register an account

The guide, with the human-in-the-loop path.

Sessions

CDP handoff, freshness, and storageState.

Runs

Watch, resume, or abort what this started.