AperioFlow Start free

Docs API reference

API: your account and sessions

59 endpoints. Send your API key as Authorization: Bearer <key> on each request; see The API and AI assistants for keys, errors, idempotency and the conventions every endpoint shares.

GET /api/health

Liveness check

Responses:

StatusMeaning
200Server is up

GET /api/me

The signed-in user, the organisation this session acts in, and every organisation they belong to

user is null for an API key or the shared password.

Responses:

StatusMeaning
200The user and organisations

PATCH /api/me

Change your name

Request body (application/json, required).

FieldTypeRequiredDescription
namestringYesUp to 200 characters.

Responses:

StatusMeaning
200Updated
403Not a user session

POST /api/me/email

Start a change of sign-in address; a link goes to the new address

The current password is checked. The account keeps its current address until the link sent to the new one is used (/auth/confirm-email-change). The answer is the same whether or not the new address belongs to another account; an address that bounced for good or complained is refused.

Request body (application/json, required).

FieldTypeRequiredDescription
emailstringYes
current_passwordstringYes

Responses:

StatusMeaning
202If the address can be used
400Current password wrong
403Not a user session

POST /api/me/export

Download your own data as a JSON file

Account details, memberships, passkey names, API key labels, sessions, invitations sent, what you own and what you did. Passwords, authenticator secrets, recovery codes, keys and session ids are never included. The current password is required again; ten attempts per hour.

Request body (application/json, required).

FieldTypeRequiredDescription
current_passwordstringYes

Responses:

StatusMeaning
200The file
400Current password wrong
403Not a user session
429Too many attempts

POST /api/me/confirm-age

Confirm you are 18 or over (accounts that have not yet)

Records, once, the time the person confirmed it, in the same column as at sign-up. Until it is given, a browser session can only read /api/me, confirm, export its data or start deleting the account; everything else answers 403 with code age_confirmation_required. Only true is accepted.

Request body (application/json, required).

FieldTypeRequiredDescription
over_18booleanYes

Responses:

StatusMeaning
200The user
400over_18 was not true
403Not a user session

GET /api/me/policies

Updated terms and notices waiting for you (the group's policy versions feed)

Only when the server has the policy check (policy_check in /auth/options; 404 otherwise). Reads the Tweed Tyne Technologies legal site's versions.json (cached; a feed that cannot be read gives available: false and nothing is asked). agreements are the changed agreements you are asked to accept (the Terms of Service once for the organisation, asked of an owner; the End User Licence Agreement for each person); notices are shown for information (a member sees the organisation's Terms as a notice). Each document has slug, title, version, effective_date, url, what_changed, line and read_link, already worded. show is true once per sign-in while something is outstanding (false after I do not accept in this session). versions is what to send back. text and decline hold the approved wording; limited is true when, from the feed's enforcement date, you declined an agreement that has taken effect: every other /api call then answers 403 with code policy_acceptance_required and the api_blocked_message, except /api/me, the data export, billing and these routes. Works from the website and the app (X-Client: app); released app builds are never limited for not answering.

Responses:

StatusMeaning
200The outstanding documents and the wording
403Not a user session
404The policy check is not configured

POST /api/me/policies/accept

I accept - records accepted for the outstanding agreements and seen for the notices

Request body (application/json, required).

FieldTypeRequiredDescription
versionsobjectYesThe { slug: version } that GET /api/me/policies returned in versions

Responses:

StatusMeaning
200The new state
400versions missing
409code policy_versions_changed: the documents changed since they were shown (nothing recorded; policies is the new state)
503code policy_feed_unavailable: the feed cannot be read just now

POST /api/me/policies/seen

Got it - records seen for the outstanding notices (only when no agreement is waiting)

Request body (application/json, required).

FieldTypeRequiredDescription
versionsobjectYes

Responses:

StatusMeaning
200The new state
409code agreement_answer_required (an agreement is waiting) or policy_versions_changed

POST /api/me/policies/decline

I do not accept - records declined for the outstanding agreements and seen for the notices

Nothing is deleted or cancelled and the session is not ended. The answer has declined true and the decline wording. Before the feed's enforcement date the person carries on; from it they have limited access until they accept.

Request body (application/json, required).

FieldTypeRequiredDescription
versionsobjectYes

Responses:

StatusMeaning
200The new state and the decline wording
409code nothing_to_decline or policy_versions_changed

GET /api/me/deletion-blockers

The organisations that stop you deleting your account

The organisations in which you are the only owner, with how many other members each has. Empty when you may delete your account.

Responses:

StatusMeaning
200The list
403Not a user session

POST /api/me/delete-request

Start deleting your account; a one-hour link goes to your address (kept for older pages: new requests use the Tweed Tyne Technologies Privacy Centre)

The account page now links to the Tweed Tyne Technologies Privacy Centre (GET /delete-account redirects there); this call is kept for pages and clients loaded before that change. Needs the current password, the authenticator or recovery code when two-factor is on, and the account's email address typed again. Ten attempts an hour (shared with exports). The account is deleted only when the emailed link is used, at once and for good. 409 when you are the only owner of an organisation (details.organisations lists them).

Request body (application/json, required).

FieldTypeRequiredDescription
current_passwordstringYes
codestringNo
confirm_emailstringYes

Responses:

StatusMeaning
202The link is on its way
400Password
403Not a user session
409You are the only owner of an organisation
429Too many attempts

POST /api/me/password

Change your password; signs out your other sessions

Request body (application/json, required).

FieldTypeRequiredDescription
current_passwordstringYes
passwordstringYesAt least 10 characters.

Responses:

StatusMeaning
200Changed
400Current password wrong or new one invalid

POST /api/me/organisation

Move this session to another organisation you belong to

Request body (application/json, required).

FieldTypeRequiredDescription
org_idintegerYes

Responses:

StatusMeaning
200Switched; the same body as GET /api/me
404Not a member of that organisation

GET /api/me/sessions

Your signed-in sessions (id is a short prefix of the stored hash)

Responses:

StatusMeaning
200Sessions

DELETE /api/me/sessions/{sid}

Sign out one of your sessions

Parameters:

NameInTypeRequiredDescription
sidpathstringYes

Responses:

StatusMeaning
204Signed out
404Not one of your sessions

POST /api/me/sessions/revoke-others

Sign out every session but this one

Responses:

StatusMeaning
200revoked is how many were signed out

POST /api/me/two-factor/setup

Start setting up an authenticator app; returns the secret and an otpauth URL

Responses:

StatusMeaning
200Secret and otpauth_url
409Already on

POST /api/me/two-factor/enable

Turn two-factor sign-in on with a code from the app and your password; returns ten recovery codes, shown once

Request body (application/json, required).

FieldTypeRequiredDescription
codestringYes
passwordstringYesYour current password (not needed for an account with no password)

Responses:

StatusMeaning
200recovery_codes
400Wrong code or password

POST /api/me/two-factor/disable

Turn two-factor sign-in off (needs your password)

Request body (application/json, required).

FieldTypeRequiredDescription
passwordstringYes

Responses:

StatusMeaning
200Off
400Wrong password

GET /api/me/passkeys

Your passkeys (name, whether synced, when added and last used)

Responses:

StatusMeaning
200Array of { id, name, backed_up, created_at, last_used_at }

POST /api/me/passkeys

Save a passkey made from the options of POST /api/me/passkeys/options

Request body (application/json, required).

FieldTypeRequiredDescription
namestringNoDefaults to "Passkey". Up to 100 characters.
responseobjectYesThe credential from navigator.credentials.create(), as WebAuthn JSON (base64url fields)

Responses:

StatusMeaning
201The saved passkey
400Not verified: wrong or used challenge, wrong site, or the person was not verified on the device
409Already registered

POST /api/me/passkeys/options

WebAuthn options for adding a passkey (a one-time challenge valid for 5 minutes); needs your password

Request body (application/json, required).

FieldTypeRequiredDescription
passwordstringYes

Responses:

StatusMeaning
200PublicKeyCredentialCreationOptions as JSON: discoverable, user verification required
400Wrong password
409The account already has 20 passkeys

DELETE /api/me/passkeys/{pid}

Remove a passkey; it stops working at once

Parameters:

NameInTypeRequiredDescription
pidpathintegerYes

Responses:

StatusMeaning
204Removed
404Not one of your passkeys

GET /api/me/identities

Provider accounts (Google, Microsoft, Apple, GitHub, Slack) linked to your account

Responses:

StatusMeaning
200Array of { id, provider, label, created_at, last_used_at }; the label is a masked form of the provider-verified email

POST /api/me/identities/{provider}/start

Start linking a provider account (google, microsoft, apple, github or slack); needs your password

Returns the address to send the browser to. Needs a browser session (not an API key). The browser-binding cookie af_oauth is set and the link is finished by the provider's callback. A provider that is not set up answers 400 provider_off.

Parameters:

NameInTypeRequiredDescription
providerpathstringYesOne of: google, microsoft, apple, github, slack.

Request body (application/json, required).

FieldTypeRequiredDescription
current_passwordstringYes

Responses:

StatusMeaning
200The provider address: { url }
400Wrong password

DELETE /api/me/identities/{id}

Unlink a provider account; needs your password

Parameters:

NameInTypeRequiredDescription
idpathintegerYes

Request body (application/json, required).

FieldTypeRequiredDescription
current_passwordstringYes

Responses:

StatusMeaning
204Unlinked
400Wrong password
404Not one of your linked sign-ins
409It is the account's only way to sign in

GET /api/meta

Allowed enum values and the caller's actor name

Responses:

StatusMeaning
200Metadata
401Missing or invalid API key (Error)

GET /api/me/notices

Your switch for emails about your work

Only when the server has WORK_EMAILS=on; otherwise this route does not exist. The emails are "A task was assigned to you", "A task is due today" and "A task is overdue" (once each per task and due date, by the UTC date; never for done or cancelled tasks or free-text owners): a fixed subject and a link, never any task text, sent only to a current member of the same organisation. A key that is not tied to a person gets a 400.

Responses:

StatusMeaning
200The setting (WorkEmailSetting)
400The request body is invalid or is not valid JSON (Error)
401Missing or invalid API key (Error)

PUT /api/me/notices

Switch emails about your work on or off

Read before every email, so switching off works before the next one.

Request body (application/json, required): WorkEmailSetting.

FieldTypeRequiredDescription
work_emailsbooleanYesOn by default.

Responses:

StatusMeaning
200The setting (WorkEmailSetting)
400The request body is invalid or is not valid JSON (Error)
401Missing or invalid API key (Error)

GET /api/me/devices

Your phones and tablets in the current organisation

Only when the server has MOBILE_PUSH=on; otherwise this route does not exist. Never includes the push tokens. Needs a person's sign-in: a key that is not tied to a person gets a 400.

Responses:

StatusMeaning
200Your devices, newest first (array of Device)
400The request body is invalid or is not valid JSON (Error)
401Missing or invalid API key (Error)

POST /api/me/devices

Register this app install's push token

The label is your own words; by default it says only the kind of device. Every notification choice starts off. The token is deleted when this sign-in ends, when you leave the organisation, when the account or organisation is deleted, when you remove the device, when a push provider reports it invalid, and after 90 days unused. Registering a token last used by someone else moves it to you with every choice off.

Request body (application/json, required).

FieldTypeRequiredDescription
tokenstringYesAt least 8 characters. Up to 4096 characters.
platformstringYesOne of: ios, android, web.
labelstringNoAt least 1 character. Up to 60 characters.

Responses:

StatusMeaning
201The device (Device)
400The request body is invalid or is not valid JSON (Error)
401Missing or invalid API key (Error)

PATCH /api/me/devices/{id}

Change a device's label and notification choices

Parameters:

NameInTypeRequiredDescription
idpathintegerYesFrom 1 to 2147483647.

Request body (application/json, required).

FieldTypeRequiredDescription
labelstringNoAt least 1 character. Up to 60 characters.
notify_downbooleanNo
notify_overduebooleanNo
notify_mentionsbooleanNoA push when someone @mentions you in a comment (generic wording: no names or text).
notify_assignedbooleanNoA push when a task is assigned to you (generic wording).
summary_hourinteger or nullNoThe hour of a morning "due today" summary, or null for none. From 0 to 23.
time_zonestringNoUp to 64 characters.

Responses:

StatusMeaning
200The device (Device)
400The request body is invalid or is not valid JSON (Error)
401Missing or invalid API key (Error)
404Item (or its parent) does not exist (Error)

DELETE /api/me/devices/{id}

Remove a device (its token is deleted at once)

Parameters:

NameInTypeRequiredDescription
idpathintegerYesFrom 1 to 2147483647.

Responses:

StatusMeaning
204Removed
401Missing or invalid API key (Error)
404Item (or its parent) does not exist (Error)

POST /api/me/devices/{id}/test

Send a test notification to one of your phones

Goes through Apple (APNs) or Google (FCM) to the device. At most 5 an hour per person.

Parameters:

NameInTypeRequiredDescription
idpathintegerYesFrom 1 to 2147483647.

Responses:

StatusMeaning
200Sent
401Missing or invalid API key (Error)
404Item (or its parent) does not exist (Error)
429Too many test messages
502The push service did not accept the test
503Phone notifications are not set up on the server

GET /api/me/digest

Your optional daily summary email

Only when the server has WORK_EMAILS=on; otherwise this route does not exist. The summary is off until you turn it on. It is sent at most once a day, in the hour and time zone you choose, only when you have tasks due today or overdue, and holds counts only (never task names) and a link to My work. Switching off all work emails (/api/me/notices) stops it too. A key that is not tied to a person gets a 400.

Responses:

StatusMeaning
200The setting (DailySummarySetting)
400The request body is invalid or is not valid JSON (Error)
401Missing or invalid API key (Error)

PUT /api/me/digest

Change your daily summary (any of enabled, hour, time_zone)

Request body (application/json, required): DailySummarySetting.

FieldTypeRequiredDescription
enabledbooleanNoDefault false.
hourintegerNoDefault 8. From 0 to 23.
time_zonestringNoAn IANA time zone name. Default "Europe/London". Up to 64 characters.

Responses:

StatusMeaning
200The setting (DailySummarySetting)
400The request body is invalid or is not valid JSON (Error)
401Missing or invalid API key (Error)

POST /auth/login

Sign in to the web UI

With email and password (and code when two-factor sign-in is on), signs in to an account and sets a 30-day HttpOnly af_session cookie for a server-side session in the organisation used last. Without email, accepts the old shared WEB_AUTH password (or an API key) for organisation 1, while WEB_AUTH is set. Cookie-authenticated /api requests must also send X-Client: web. A right password with two-factor on and no code answers 401 with two_factor_required: true; an unverified address answers 403 with email_unverified: true and a new link is emailed. After 10 failed attempts from one IP address, further attempts are refused for 15 minutes.

A service that checks a password on behalf of its own user (the MCP connector's sign-in page) can send its API key with X-Relayed-Client-IP: <user's IP>, so the lockout applies to that user instead of the service. The header is ignored without a valid API key.

Parameters:

NameInTypeRequiredDescription
X-Relayed-Client-IPheaderstringNoThe end user's IP address. Honoured only with a valid API key.

Request body (application/json, required).

FieldTypeRequiredDescription
emailstring (email)No
passwordstringYes
codestringNo6-digit authenticator code or a recovery code.

Responses:

StatusMeaning
200Signed in
401Incorrect password (Error)
429Too many failed attempts (Error)

POST /auth/app/login

Sign in from the native app (returns the session token instead of a cookie)

For the AperioFlow iOS and Android app (mobile/). The same checks, limits and lockouts as /auth/login with email and password (and code when two-factor sign-in is on), but the 30-day server-side session's token is returned once in token and no cookie is set. The app keeps it in the phone's secure storage and sends it on every /api call as X-Session-Token, together with X-Client: app (a browser cannot add either header to a cross-site request without a CORS preflight, so this is not open to CSRF). Everything a signed-in session can do works the same way, including /api/me/devices. POST /auth/logout with the same two headers ends the session. Failures carry a code: bad (wrong email or password), two_factor (a code is needed, or it was wrong), unverified, locked.

Request body (application/json, required).

FieldTypeRequiredDescription
emailstring (email)Yes
passwordstringYes
codestringNo6-digit authenticator code or a recovery code.

Responses:

StatusMeaning
200Signed in
401Incorrect email or password, or a two-factor code is needed (Error)
403The address is not verified yet (a new link is emailed) (Error)
429Too many failed attempts (Error)

POST /auth/logout

Sign out (ends the server-side session and clears the cookie)

Responses:

StatusMeaning
204Signed out

POST /auth/signup

Create an account and an organisation it owns

Only when the server has SIGNUP_OPEN=true (404 otherwise). The answer is the same whether or not the address has an account; the address gets a confirmation link.

Request body (application/json, required).

FieldTypeRequiredDescription
emailstring (email)Yes
passwordstringYesAt least 10 characters. Up to 200 characters.
namestringYes
organisationstringYes
accept_termsbooleanYesThe Terms tick: I agree to the Terms of Service, including the End User Licence Agreement and the Data Processing Addendum, for myself or for the organisation I represent, and I confirm I am authorised to act for it. Records accepted for those three and seen for the Privacy Policy and Cookie Notice at the current versions. Must be true.
over_18booleanYesMust be true: the person confirms they are 18 or over. The time is stored on the account; no date of birth is asked for.

Responses:

StatusMeaning
202Done
400Invalid fields or link (Error)
429More than 10 of these requests from one IP in 15 minutes

POST /auth/confirm-email-change

Use the link sent to a new address to change the account's sign-in address

The link is valid for 48 hours and works once. The new address becomes the account's address, verified.

Request body (application/json, required).

FieldTypeRequiredDescription
tokenstringYes

Responses:

StatusMeaning
200Done
400Invalid or expired link (Error)
409The address now belongs to another account

POST /auth/confirm-account-deletion

Use the emailed link to delete the account, at once and for good

The link is valid for one hour and works once. Removes the account, its memberships, sessions, passkeys, API keys and sign-in links; the person's work stays with the organisation, shown as "Deleted user". A last-owner check runs again here and a refusal leaves the link unused. Copies in backups are overwritten within 28 days.

Request body (application/json, required).

FieldTypeRequiredDescription
tokenstringYes

Responses:

StatusMeaning
200Deleted
400Invalid or expired link (Error)
409You are now the only owner of an organisation

POST /auth/confirm-organisation-deletion

Use the emailed link to delete the organisation, at once and for good

The link is valid for one hour and works once. The owner and subscription checks run again; a refusal leaves the link unused. Everything under the organisation is removed, every member is emailed, their accounts stay. Copies in backups are overwritten within 28 days.

Request body (application/json, required).

FieldTypeRequiredDescription
tokenstringYes

Responses:

StatusMeaning
200Deleted
400Invalid or expired link (Error)
403The person is no longer an owner
409A subscription is now active

POST /auth/verify-email

Confirm an email address with the emailed token

The link is valid for 48 hours and works once.

Request body (application/json, required).

FieldTypeRequiredDescription
tokenstringYes

Responses:

StatusMeaning
200Done
400Invalid fields or link (Error)
429More than 10 of these requests from one IP in 15 minutes

POST /auth/resend-verification

Send a new confirmation link

Says nothing about whether the address has an account.

Request body (application/json, required).

FieldTypeRequiredDescription
emailstring (email)Yes

Responses:

StatusMeaning
202Done
400Invalid fields or link (Error)
429More than 10 of these requests from one IP in 15 minutes

POST /auth/forgot-password

Email a password reset link

The link is valid for an hour and works once. Says nothing about whether the address has an account.

Request body (application/json, required).

FieldTypeRequiredDescription
emailstring (email)Yes

Responses:

StatusMeaning
202Done
400Invalid fields or link (Error)
429More than 10 of these requests from one IP in 15 minutes

POST /auth/reset-password

Set a new password with the emailed token

Signs out every session of the account and confirms the address.

Request body (application/json, required).

FieldTypeRequiredDescription
tokenstringYes
passwordstringYesAt least 10 characters. Up to 200 characters.

Responses:

StatusMeaning
200Done
400Invalid fields or link (Error)
429More than 10 of these requests from one IP in 15 minutes

POST /auth/passkey/options

WebAuthn options for signing in with a passkey (a one-time challenge valid for 5 minutes)

Responses:

StatusMeaning
200PublicKeyCredentialRequestOptions as JSON; no allowCredentials, so the browser offers the passkeys it holds for this site
429More than 30 of these requests from one IP in 15 minutes

POST /auth/passkey

Sign in with a passkey

Checks the browser's answer to POST /auth/passkey/options and sets the af_session cookie, as /auth/login does. A passkey needs no email, password or authenticator code: the device has checked the person. A failure counts towards the same 10-per-15-minutes lockout.

Request body (application/json, required).

FieldTypeRequiredDescription
responseobjectYesThe credential from navigator.credentials.get(), as WebAuthn JSON.

Responses:

StatusMeaning
200Signed in
401Unknown passkey
403Address not verified (email_unverified: true)
429Locked out after failed sign-ins

GET /auth/provider/{provider}/start

Sign in with Google, Microsoft, Apple, GitHub or Slack (browser navigation)

Redirects the browser to the provider (302) and sets the af_oauth browser-binding cookie. Only the OAuth request is sent to the provider. A provider that is not set up, or any failure, redirects to /#/provider-error/<code>.

Parameters:

NameInTypeRequiredDescription
providerpathstringYesOne of: google, microsoft, apple, github, slack.
clientquerystringNoFrom the iOS or Android app, opened in the phone's secure browser. The flow then ends at aperioflow://provider-sign-in with pending, needs_terms and needs_second_factor, or with error; finish it with POST /auth/app/provider/confirm. One of: app.
challengequerystringNoWith client=app: base64url SHA-256 of a random value only the app holds.

Responses:

StatusMeaning
302To the provider
429Too many requests or recent failures from this IP

POST /auth/app/provider/confirm

Finish a provider sign-in started in the app

The pending sign-in handed back to the app, the value behind the challenge the app sent at the start (verifier), and what the pending sign-in still needs: over_18 and accept_terms on the first sign-in through that identity, code (authenticator or recovery code) when two-factor is on. Returns the session token once, for X-Session-Token with X-Client: app. A pending sign-in started in a browser cannot be finished here, and one started in the app cannot be finished by a browser.

Request body (application/json, required).

FieldTypeRequiredDescription
pendingstringYes
verifierstringYes
over_18booleanNo
accept_termsbooleanNo
codestringNo

Responses:

StatusMeaning
200{ ok: true, token }
400Expired, already used, the wrong verifier (bad_state), or the 18+ and Terms box not ticked
401The authenticator code is missing or wrong (two_factor)
429Too many requests or recent failures from this IP

GET /auth/provider/{provider}/callback

The provider's redirect back (browser navigation); finishes a link or a sign-in

Uses the one-time state (10 minutes, one use, same browser). A link made from a signed-in account redirects to /#/account. A sign-in finds the account by the provider's user id only: an unlinked provider account signs nobody in and creates nothing (/#/provider-error/not_linked). A linked account is signed in at once, or, on its first sign-in through that identity or when two-factor is on, redirected to /#/provider-confirm (cookie af_pending, 5 minutes) for the 18+ and terms box and/or the authenticator code.

Parameters:

NameInTypeRequiredDescription
providerpathstringYesOne of: google, microsoft, apple, github, slack.

Responses:

StatusMeaning
302To / (signed in), /#/account (linked), /#/provider-confirm or /#/provider-error/<code>
429Too many requests or recent failures from this IP

POST /auth/provider/{provider}/callback

Apple's form POST back (browser navigation); carried on as the GET callback

Apple answers with a form POST (response_mode=form_post). Only code, state and error are kept, each a short plain value, and the browser is sent on to the GET callback (303), which does every check. Apple's ID token and user field are dropped unread. Any other provider redirects to /#/provider-error/provider_off.

Parameters:

NameInTypeRequiredDescription
providerpathstringYesOne of: apple.

Request body (application/x-www-form-urlencoded)

Responses:

StatusMeaning
302To /#/provider-error/provider_off
303To the GET callback

GET /auth/provider/{provider}/signup

Create an account with Google, Microsoft, Apple, GitHub or Slack (browser navigation; only while sign-up is open)

Like the sign-in start route, but a provider account that is not yet linked leads to /#/provider-confirm to give a name and an organisation name and confirm 18+ and the Terms. An address that already has an account is never merged: it redirects to /#/provider-error/account_exists. Closed sign-up redirects to /#/provider-error/signup_closed.

Parameters:

NameInTypeRequiredDescription
providerpathstringYesOne of: google, microsoft, apple, github, slack.

Responses:

StatusMeaning
302To the provider
429Too many requests or recent failures from this IP

POST /auth/provider/signup

Finish a provider sign-up

Creates a verified account with no password, owner of a new organisation, linked to the provider, and emails a set-a-password link.

Request body (application/json, required).

FieldTypeRequiredDescription
namestringYes
organisationstringYes
over_18booleanYes
accept_termsbooleanYes

Responses:

StatusMeaning
201Account made and signed in; sets the af_session cookie
400A field is missing or a box was not ticked
429Locked out after failed sign-ins

GET /auth/provider/pending

What a pending provider sign-in or sign-up still needs

Responses:

StatusMeaning
200{ needs_terms, needs_second_factor }, plus sign_up: true and provider for a sign-up
404None

POST /auth/provider/confirm

Finish a pending provider sign-in

Request body (application/json, required).

FieldTypeRequiredDescription
codestringNoAuthenticator or recovery code, when two-factor is on.
over_18booleanNo
accept_termsbooleanNo

Responses:

StatusMeaning
200Signed in; sets the af_session cookie
400The box was not ticked
401Wrong code (two_factor_required: true); five wrong codes end the pending sign-in
429Locked out after failed sign-ins

GET /auth/options

Which ways of signing in the server allows

Responses:

StatusMeaning
200signup is SIGNUP_OPEN; password_only is whether the shared WEB_AUTH password is on; passkeys is whether passkey sign-in is available.

Start free All the docs Video guides

Built for the people who write the code and answer the phone when it breaks.

Run from the UK. Hosted in France.

UK time --:--

Already in?Open the app Start free today
View our policies