Skip to content
cloudhostDocs
API reference

Sign-in and sessions

Passwordless sign-in, sign-up, sessions, second factors, step-up and device login.

GET/v1/auth/profile

The person's profile and preferences#

Credential
A dashboard session only (API keys are refused)
Roles
Any role

Response

200Profile

  • idstring
  • emailstring
  • phonestring | null
  • namestring | null
  • avatarstring | null
  • languagestring | null
  • time_zonestring | null
  • calendarstring | null
  • date_formatstring | null
  • themestring | null
  • updated_atstring (date-time) | null
  • defaultsobject

Errors

StatusDescription
401unauthorized: missing, invalid, expired or revoked credential
403Forbidden: session_only
500internal: an unexpected failure

Example

curl "https://api.ibel.ai/v1/auth/profile" \
  -H "Authorization: Bearer $SESSION"
PATCH/v1/auth/profile

Change the person's profile and preferences#

Any of name, avatar, language, time_zone, calendar, date_format, theme; null puts a field back on its default. Needs a dashboard session.

Credential
A dashboard session only (API keys are refused)
Roles
Any role

Request bodyapplication/json

  • namestring | null
  • avatarstring | null

    a png, jpeg or webp image as a data URL, under 40 KB

  • languagestring | null

    one of fa, en, null

  • time_zonestring | null

    an IANA time zone, for example Asia/Tehran

  • calendarstring | null

    one of jalali, gregorian, null

  • date_formatstring | null

    one of medium, short, long, null

  • themestring | null

    one of system, light, dark, null

Response

200Profile

  • idstring
  • emailstring
  • phonestring | null
  • namestring | null
  • avatarstring | null
  • languagestring | null
  • time_zonestring | null
  • calendarstring | null
  • date_formatstring | null
  • themestring | null
  • updated_atstring (date-time) | null
  • defaultsobject

Errors

StatusDescription
400Bad request: bad_name, bad_avatar, bad_language, bad_time_zone, bad_calendar, bad_date_format, bad_theme, empty
401unauthorized: missing, invalid, expired or revoked credential
403Forbidden: session_only
500internal: an unexpected failure

Example

curl -X PATCH "https://api.ibel.ai/v1/auth/profile" \
  -H "Authorization: Bearer $SESSION" \
  -d '{"name":"my-api","avatar":"…","language":"fa","time_zone":"…","calendar":"jalali","date_format":"medium","theme":"system"}'
POST/v1/auth/contact/start

Begin changing the email address or mobile number#

Sends a code to the new address or number; nothing changes until it is confirmed. Needs a session and a fresh second factor (step_up_required).

Credential
A dashboard session only (API keys are refused)
Roles
Any role
Step-up
With a dashboard session, a second factor confirmed in the last 10 minutes; API keys pass.

Request bodyapplication/json

  • channelstringrequired

    one of email, phone

  • valuestringrequired

Response

200object

  • challengestring
  • channelstring
  • expires_ininteger

Errors

StatusDescription
400Bad request: bad_channel, bad_email, bad_phone
401unauthorized: missing, invalid, expired or revoked credential
403Forbidden: step_up_required, session_only
429Too many requests: rate_limited, resend_wait
500internal: an unexpected failure

Example

curl -X POST "https://api.ibel.ai/v1/auth/contact/start" \
  -H "Authorization: Bearer $SESSION" \
  -d '{"channel":"email","value":"s3cr3t"}'
POST/v1/auth/contact/confirm

Finish changing the email address or mobile number#

With the code sent to the new one. Needs a session and a fresh second factor.

Credential
A dashboard session only (API keys are refused)
Roles
Any role
Step-up
With a dashboard session, a second factor confirmed in the last 10 minutes; API keys pass.

Request bodyapplication/json

  • challengestringrequired
  • codestringrequired

    pattern ^\d{6}$

Response

200Profile

  • idstring
  • emailstring
  • phonestring | null
  • namestring | null
  • avatarstring | null
  • languagestring | null
  • time_zonestring | null
  • calendarstring | null
  • date_formatstring | null
  • themestring | null
  • updated_atstring (date-time) | null
  • defaultsobject

Errors

StatusDescription
400Bad request: bad_code
401unauthorized: missing, invalid, expired or revoked credential
403Forbidden: step_up_required, session_only
409Conflict: taken
500internal: an unexpected failure

Example

curl -X POST "https://api.ibel.ai/v1/auth/contact/confirm" \
  -H "Authorization: Bearer $SESSION" \
  -d '{"challenge":"…","code":"123456"}'
POST/v1/auth/signin

Send a sign-in code#

Same answer whether or not an account exists.

Credential
None

Request bodyapplication/json

  • identifierstringrequired

    an email or an Iranian mobile

  • browserstringrequired

    a random value of 16+ characters the client keeps

    at least 16 characters

Response

200Challenge

  • challengestring (uuid)required
  • channelstringrequired

    one of email, sms

  • expires_ininteger

    seconds

  • resend_afterinteger

    seconds

Errors

StatusDescription
400Bad request: bad_browser, bad_identifier, bad_json
429Too many requests: resend_wait, rate_limited
500internal: an unexpected failure

Example

curl -X POST "https://api.ibel.ai/v1/auth/signin" \
  -d '{"identifier":"you@example.com","browser":"b3f1c9a27d4e4c0e9a1f"}'
POST/v1/auth/verify

Exchange a sign-in code for a session#

Credential
None

Request bodyapplication/json

  • challengestring (uuid)required
  • codestringrequired

    pattern ^\d{6}$

Response

200Session

  • sessionstringrequired

    chs_ bearer token

  • expires_atstring (date-time)required

Errors

StatusDescription
400Bad request: bad_code, bad_json
403Not allowed: no_team
429Too many requests: rate_limited
500internal: an unexpected failure

Example

curl -X POST "https://api.ibel.ai/v1/auth/verify" \
  -d '{"challenge":"8c1e0c55-1f2a-4d3b-9e8f-0a1b2c3d4e5f","code":"123456"}'
GET/v1/auth/registration

Whether sign-up is open#

CORS for the marketing site's origins (CH_SITE_ORIGINS), with the OPTIONS preflight.

Credential
None

Response

200object

  • registrationstringrequired

    one of open, invite, closed

Errors

StatusDescription
500internal: an unexpected failure

Example

curl "https://api.ibel.ai/v1/auth/registration"
POST/v1/auth/signup

Start a sign-up#

Credential
None

Request bodyapplication/json

  • emailstringrequired
  • phonestringrequired

    Iranian mobile

  • browserstringrequired

    a random value of 16+ characters the client keeps

    at least 16 characters

  • invitestring
  • team_invitestring

Response

200object

  • email_challengestring (uuid)required
  • phone_challengestring (uuid)required
  • expires_ininteger

    both codes work this long (300)

  • email_expires_ininteger

    600

  • phone_expires_ininteger

    300

  • resend_afterinteger

Errors

StatusDescription
400Bad request: bad_email, bad_phone, bad_browser, bad_json
403Not allowed: registration_closed, bad_invite
429Too many requests: resend_wait, rate_limited
500internal: an unexpected failure

Example

curl -X POST "https://api.ibel.ai/v1/auth/signup" \
  -d '{"email":"you@example.com","phone":"09121234567","browser":"b3f1c9a27d4e4c0e9a1f"}'
POST/v1/auth/signup/verify

Finish a sign-up#

Creates the person, their personal team and a session that is already stepped up.

Credential
None

Request bodyapplication/json

  • email_challengestring (uuid)required
  • email_codestringrequired
  • phone_challengestring (uuid)required
  • phone_codestringrequired
  • invitestring
  • team_invitestring

Response

200Session

  • sessionstringrequired

    chs_ bearer token

  • expires_atstring (date-time)required

Errors

StatusDescription
400Bad request: bad_code, bad_invite, bad_json
403Not allowed: bad_invite, registration_closed
409Conflict: exists
429Too many requests: rate_limited
500internal: an unexpected failure

Example

curl -X POST "https://api.ibel.ai/v1/auth/signup/verify" \
  -d '{"email_challenge":"8c1e0c55-1f2a-4d3b-9e8f-0a1b2c3d4e5f","email_code":"…","phone_challenge":"8c1e0c55-1f2a-4d3b-9e8f-0a1b2c3d4e5f","phone_code":"…"}'
POST/v1/auth/waitlist

Join the waitlist#

CORS for the marketing site's origins (CH_SITE_ORIGINS), with the OPTIONS preflight.

Credential
None

Request bodyapplication/json

  • contactstringrequired

    an email or an Iranian mobile

Response

200Ok

  • okbooleanrequired

Errors

StatusDescription
400Bad request: bad_contact, bad_json
429Too many requests: rate_limited
500internal: an unexpected failure

Example

curl -X POST "https://api.ibel.ai/v1/auth/waitlist" \
  -d '{"contact":"you@example.com"}'
GET/v1/auth/sessions

The person's sessions#

Credential
A dashboard session only (API keys are refused)
Roles
Any role

Response

200object

  • sessionsSessionInfo[]required
    • idstringrequired
    • created_atstring (date-time)
    • last_seen_atstring (date-time)
    • expires_atstring (date-time)
    • ipstring | null
    • user_agentstring | null
    • currentbooleanrequired

Errors

StatusDescription
401unauthorized: missing, invalid, expired or revoked credential
403Not allowed: session_only
500internal: an unexpected failure

Example

curl "https://api.ibel.ai/v1/auth/sessions" \
  -H "Authorization: Bearer $SESSION"
DELETE/v1/auth/sessions/{id}

End a session#

Credential
A dashboard session only (API keys are refused)
Roles
Any role

Parameters

  • idstringpathrequired

    session id

    pattern ^[0-9a-f]{16}$

Response

200object

  • revokedstring

Errors

StatusDescription
401unauthorized: missing, invalid, expired or revoked credential
403Not allowed: session_only
404Not found: not_found
500internal: an unexpected failure

Example

curl -X DELETE "https://api.ibel.ai/v1/auth/sessions/88e2fe1d-6d75-4de5-8c8f-27380ec66903" \
  -H "Authorization: Bearer $SESSION"
POST/v1/auth/signout

End this session#

Credential
A dashboard session only (API keys are refused)
Roles
Any role

Response

200Ok

  • okbooleanrequired

Errors

StatusDescription
401unauthorized: missing, invalid, expired or revoked credential
403Not allowed: session_only
500internal: an unexpected failure

Example

curl -X POST "https://api.ibel.ai/v1/auth/signout" \
  -H "Authorization: Bearer $SESSION"
POST/v1/auth/signout-everywhere

End every session of the person#

Credential
A dashboard session only (API keys are refused)
Roles
Any role

Response

200object

  • revokedinteger

Errors

StatusDescription
401unauthorized: missing, invalid, expired or revoked credential
403Not allowed: session_only
500internal: an unexpected failure

Example

curl -X POST "https://api.ibel.ai/v1/auth/signout-everywhere" \
  -H "Authorization: Bearer $SESSION"
GET/v1/auth/factors

Factors and step-up methods#

Credential
A dashboard session only (API keys are refused)
Roles
Any role

Response

200Factors

  • signed_in_withstring
  • totpboolean
  • passkeysinteger
  • emailstring
  • phonestring | null

    masked

  • step_up_methodsstring[]
  • single_factorboolean
  • stepped_up_untilstring (date-time) | null

Errors

StatusDescription
401unauthorized: missing, invalid, expired or revoked credential
403Not allowed: session_only
500internal: an unexpected failure

Example

curl "https://api.ibel.ai/v1/auth/factors" \
  -H "Authorization: Bearer $SESSION"
POST/v1/auth/step-up/start

Send a step-up code#

Credential
A dashboard session only (API keys are refused)
Roles
Any role

Request bodyapplication/json

  • methodstringrequired

    one of email, sms

Response

200Challenge

  • challengestring (uuid)required
  • channelstringrequired

    one of email, sms

  • expires_ininteger

    seconds

  • resend_afterinteger

    seconds

Errors

StatusDescription
400Bad request: bad_method, bad_json
401unauthorized: missing, invalid, expired or revoked credential
403Not allowed: session_only
429Too many requests: resend_wait, rate_limited
500internal: an unexpected failure

Example

curl -X POST "https://api.ibel.ai/v1/auth/step-up/start" \
  -H "Authorization: Bearer $SESSION" \
  -d '{"method":"email"}'
POST/v1/auth/step-up/verify

Confirm the second factor#

Sensitive actions are then allowed for 10 minutes.

Credential
A dashboard session only (API keys are refused)
Roles
Any role

Request bodyapplication/json

  • methodstring

    one of totp

  • challengestring (uuid)
  • codestringrequired

Response

200object

  • stepped_up_untilstring (date-time)

Errors

StatusDescription
400Bad request: bad_code, bad_json
401unauthorized: missing, invalid, expired or revoked credential
403Not allowed: session_only
429Too many requests: rate_limited
500internal: an unexpected failure

Example

curl -X POST "https://api.ibel.ai/v1/auth/step-up/verify" \
  -H "Authorization: Bearer $SESSION" \
  -d '{"code":"123456"}'
GET/v1/auth/passkeys

List your passkeys#

Credential
A dashboard session only (API keys are refused)
Roles
Any role

Response

200object

  • passkeysPasskey[]
  • availableboolean
  • rp_idstring

Errors

StatusDescription
401unauthorized: missing, invalid, expired or revoked credential
403Not allowed: session_only
500internal: an unexpected failure

Example

curl "https://api.ibel.ai/v1/auth/passkeys" \
  -H "Authorization: Bearer $SESSION"
POST/v1/auth/passkeys/register/options

Start adding a passkey#

Needs a fresh step-up.

Credential
A dashboard session only (API keys are refused)
Roles
Any role

Response

200object

  • challenge_idstring (uuid)
  • optionsobject

    the browser's credential options, binary values in base64url

Errors

StatusDescription
401unauthorized: missing, invalid, expired or revoked credential
403Not allowed: session_only, step_up_required
409Conflict: passkey_limit
500internal: an unexpected failure
503Not offered on this site: passkeys_unavailable

Example

curl -X POST "https://api.ibel.ai/v1/auth/passkeys/register/options" \
  -H "Authorization: Bearer $SESSION"
POST/v1/auth/passkeys/register/verify

Finish adding a passkey#

Needs a fresh step-up.

Credential
A dashboard session only (API keys are refused)
Roles
Any role

Request bodyapplication/json

  • challenge_idstring (uuid)required
  • credentialobjectrequired

    what PublicKeyCredential.toJSON() returns: id, rawId, type, response

  • namestring

    up to 60 characters

Response

201PasskeyCreated

  • idstring (uuid)
  • namestring
  • created_atstring (date-time)
  • last_used_atstring (date-time) | null
  • syncedboolean

    syncs across devices (phone, password manager)

  • transportsstring[]

Errors

StatusDescription
400Bad request: passkey_refused, passkey_expired, bad_json
401unauthorized: missing, invalid, expired or revoked credential
403Not allowed: session_only, step_up_required
409Conflict: passkey_exists, passkey_limit
500internal: an unexpected failure
503Not offered on this site: passkeys_unavailable

Example

curl -X POST "https://api.ibel.ai/v1/auth/passkeys/register/verify" \
  -H "Authorization: Bearer $SESSION" \
  -d '{"challenge_id":"8c1e0c55-1f2a-4d3b-9e8f-0a1b2c3d4e5f","credential":{}}'
DELETE/v1/auth/passkeys/{id}

Remove a passkey#

Needs a fresh step-up.

Credential
A dashboard session only (API keys are refused)
Roles
Any role

Parameters

  • idstring (uuid)pathrequired

Response

200object

  • removedstring (uuid)

Errors

StatusDescription
401unauthorized: missing, invalid, expired or revoked credential
403Not allowed: session_only, step_up_required
404Not found: not_found
500internal: an unexpected failure

Example

curl -X DELETE "https://api.ibel.ai/v1/auth/passkeys/88e2fe1d-6d75-4de5-8c8f-27380ec66903" \
  -H "Authorization: Bearer $SESSION"
PATCH/v1/auth/passkeys/{id}

Rename a passkey#

Credential
A dashboard session only (API keys are refused)
Roles
Any role

Parameters

  • idstring (uuid)pathrequired

Request bodyapplication/json

  • namestringrequired

    1–60 characters

Response

200Passkey

  • idstring (uuid)
  • namestring
  • created_atstring (date-time)
  • last_used_atstring (date-time) | null
  • syncedboolean

    syncs across devices (phone, password manager)

  • transportsstring[]

Errors

StatusDescription
400Bad request: bad_name, bad_json
401unauthorized: missing, invalid, expired or revoked credential
403Not allowed: session_only
404Not found: not_found
500internal: an unexpected failure

Example

curl -X PATCH "https://api.ibel.ai/v1/auth/passkeys/88e2fe1d-6d75-4de5-8c8f-27380ec66903" \
  -H "Authorization: Bearer $SESSION" \
  -d '{"name":"my-api"}'
POST/v1/auth/passkeys/signin/options

Start a passkey sign-in#

Credential
None

Response

200object

  • challenge_idstring (uuid)
  • optionsobject

    the browser's credential options, binary values in base64url

Errors

StatusDescription
429Too many requests: rate_limited
500internal: an unexpected failure
503Not offered on this site: passkeys_unavailable

Example

curl -X POST "https://api.ibel.ai/v1/auth/passkeys/signin/options"
POST/v1/auth/passkeys/signin/verify

Sign in with a passkey#

The session starts stepped up (a passkey is user-verified).

Credential
None

Request bodyapplication/json

  • challenge_idstring (uuid)required
  • credentialobjectrequired

    what PublicKeyCredential.toJSON() returns: id, rawId, type, response

  • teamstring (uuid)

Response

200Session

  • sessionstringrequired

    chs_ bearer token

  • expires_atstring (date-time)required
  • passkeyobject

Errors

StatusDescription
400Bad request: passkey_refused, passkey_expired, passkey_unknown, bad_json
403Not allowed: no_team
429Too many requests: rate_limited
500internal: an unexpected failure
503Not offered on this site: passkeys_unavailable

Example

curl -X POST "https://api.ibel.ai/v1/auth/passkeys/signin/verify" \
  -d '{"challenge_id":"8c1e0c55-1f2a-4d3b-9e8f-0a1b2c3d4e5f","credential":{}}'
POST/v1/auth/step-up/passkey/options

Start a step-up with a passkey#

Credential
A dashboard session only (API keys are refused)
Roles
Any role

Response

200object

  • challenge_idstring (uuid)
  • optionsobject

    the browser's credential options, binary values in base64url

Errors

StatusDescription
400Bad request: bad_method
401unauthorized: missing, invalid, expired or revoked credential
403Not allowed: session_only
500internal: an unexpected failure
503Not offered on this site: passkeys_unavailable

Example

curl -X POST "https://api.ibel.ai/v1/auth/step-up/passkey/options" \
  -H "Authorization: Bearer $SESSION"
POST/v1/auth/step-up/passkey/verify

Confirm a step-up with a passkey#

Credential
A dashboard session only (API keys are refused)
Roles
Any role

Request bodyapplication/json

  • challenge_idstring (uuid)required
  • credentialobjectrequired

    what PublicKeyCredential.toJSON() returns: id, rawId, type, response

Response

200object

  • stepped_up_untilstring (date-time)

Errors

StatusDescription
400Bad request: passkey_refused, passkey_expired, passkey_unknown, bad_json
401unauthorized: missing, invalid, expired or revoked credential
403Not allowed: session_only
429Too many requests: rate_limited
500internal: an unexpected failure
503Not offered on this site: passkeys_unavailable

Example

curl -X POST "https://api.ibel.ai/v1/auth/step-up/passkey/verify" \
  -H "Authorization: Bearer $SESSION" \
  -d '{"challenge_id":"8c1e0c55-1f2a-4d3b-9e8f-0a1b2c3d4e5f","credential":{}}'
POST/v1/auth/totp/setup

Start adding an authenticator app#

Credential
A dashboard session only (API keys are refused)
Roles
Any role
Step-up
With a dashboard session, a second factor confirmed in the last 10 minutes; API keys pass.

Response

200object

  • secretstringrequired
  • otpauth_uristringrequired
  • confirmstring

Errors

StatusDescription
401unauthorized: missing, invalid, expired or revoked credential
403Not allowed: step_up_required, session_only
500internal: an unexpected failure

Example

curl -X POST "https://api.ibel.ai/v1/auth/totp/setup" \
  -H "Authorization: Bearer $SESSION"
POST/v1/auth/totp/confirm

Turn the authenticator app on#

Credential
A dashboard session only (API keys are refused)
Roles
Any role

Request bodyapplication/json

  • codestringrequired

    pattern ^\d{6}$

Response

200object

  • enabledboolean

Errors

StatusDescription
400Bad request: bad_code, bad_json
401unauthorized: missing, invalid, expired or revoked credential
403Not allowed: session_only
429Too many requests: rate_limited
500internal: an unexpected failure

Example

curl -X POST "https://api.ibel.ai/v1/auth/totp/confirm" \
  -H "Authorization: Bearer $SESSION" \
  -d '{"code":"123456"}'
DELETE/v1/auth/totp

Remove the authenticator app#

Credential
A dashboard session only (API keys are refused)
Roles
Any role
Step-up
With a dashboard session, a second factor confirmed in the last 10 minutes; API keys pass.

Response

200object

  • removedboolean

Errors

StatusDescription
401unauthorized: missing, invalid, expired or revoked credential
403Not allowed: step_up_required, session_only
500internal: an unexpected failure

Example

curl -X DELETE "https://api.ibel.ai/v1/auth/totp" \
  -H "Authorization: Bearer $SESSION"
POST/v1/auth/device

Start a device login (CLI)#

Credential
None

Request bodyapplication/json

  • namestring

    up to 80 characters

Response

200DeviceStart

  • device_codestringrequired
  • user_codestringrequired

    pattern ^[A-Z0-9]{4}-[A-Z0-9]{4}$

  • verification_urlstringrequired
  • verification_url_completestring
  • intervalintegerrequired
  • expires_inintegerrequired

Errors

StatusDescription
400Bad request: bad_json
429Too many requests: rate_limited
500internal: an unexpected failure

Example

curl -X POST "https://api.ibel.ai/v1/auth/device" \
  -d '{"name":"my-api"}'
POST/v1/auth/device/approve

Approve or deny a device code#

Step-up is needed to approve, not to deny.

Credential
A dashboard session only (API keys are refused)
Roles
Any role
Step-up
With a dashboard session, a second factor confirmed in the last 10 minutes; API keys pass.

Request bodyapplication/json

  • user_codestringrequired
  • denyboolean

Response

200object

  • approvedboolean
  • namestring

Errors

StatusDescription
400Bad request: bad_json
401unauthorized: missing, invalid, expired or revoked credential
403Not allowed: step_up_required, session_only
404Not found: bad_code
500internal: an unexpected failure

Example

curl -X POST "https://api.ibel.ai/v1/auth/device/approve" \
  -H "Authorization: Bearer $SESSION" \
  -d '{"user_code":"WDJB-MJHT"}'
POST/v1/auth/device/token

Poll for the device's API key#

RFC 8628: every polling error is a 400, authorization_pending included.

Credential
None

Request bodyapplication/json

  • device_codestringrequired

Response

200DeviceToken

  • api_keystringrequired
  • key_idstringrequired
  • expires_in_daysinteger

Errors

StatusDescription
400Bad request: authorization_pending, access_denied, expired_token, bad_json
500internal: an unexpected failure

Example

curl -X POST "https://api.ibel.ai/v1/auth/device/token" \
  -d '{"device_code":"…"}'