@faable/auth-sdk 2.7.20 → 2.7.21

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -3665,7 +3665,11 @@ export interface paths {
3665
3665
  delete?: never;
3666
3666
  options?: never;
3667
3667
  head?: never;
3668
- patch?: never;
3668
+ /**
3669
+ * Update current User profile
3670
+ * @description Updates the profile of the User behind the current session or bearer token. Only `name`, `company_name` and `country_iso` can be changed; `company_name` is merged into `user_metadata` without touching its other keys. A Bearer token must belong to this Account.
3671
+ */
3672
+ patch: operations["session/me_update"];
3669
3673
  trace?: never;
3670
3674
  };
3671
3675
  "/logout": {
@@ -24069,6 +24073,237 @@ export interface operations {
24069
24073
  };
24070
24074
  };
24071
24075
  };
24076
+ "session/me_update": {
24077
+ parameters: {
24078
+ query?: never;
24079
+ header?: never;
24080
+ path?: never;
24081
+ cookie?: never;
24082
+ };
24083
+ /** @description Profile fields the current User may edit on themselves. `company_name` is stored in `user_metadata`, merged with whatever else is there. */
24084
+ requestBody: {
24085
+ content: {
24086
+ "application/json": {
24087
+ name?: string;
24088
+ company_name?: string;
24089
+ country_iso?: string;
24090
+ };
24091
+ };
24092
+ };
24093
+ responses: {
24094
+ /** @description The current User. With a Bearer access token the response also carries the token's custom claims (e.g. `ciapol.com/station_id`) as top-level properties; profile fields always win over a same-named claim. */
24095
+ 200: {
24096
+ headers: {
24097
+ [name: string]: unknown;
24098
+ };
24099
+ content: {
24100
+ "application/json": {
24101
+ /** @description User ID */
24102
+ id: string;
24103
+ /** @description User name */
24104
+ name?: string | null;
24105
+ /** @description unique username for this user */
24106
+ username?: string | null;
24107
+ /** @description Given name */
24108
+ given_name?: string | null;
24109
+ /** @description Family name */
24110
+ family_name?: string | null;
24111
+ /** @description Middle name (OIDC §5.1) */
24112
+ middle_name?: string | null;
24113
+ /** @description Casual name. Distinct from given_name (e.g. "Mike" vs "Michael"). OIDC §5.1 */
24114
+ nickname?: string | null;
24115
+ /** @description User email */
24116
+ email?: string | null;
24117
+ /**
24118
+ * @description true if email is verified
24119
+ * @default false
24120
+ */
24121
+ email_verified: boolean;
24122
+ /** @description How `email_verified` was last set. `manual` — admin flipped the flag via `POST /user/:id`. `verification_flow` — user clicked the verification link. `passwordless_otp` — user completed passwordless OTP login. `team_invite` — user clicked a team invitation link. `email_change` — user confirmed a self-service email change. `federated` — verified by the external IdP on OAuth callback. `password_reset` — user completed the recovery link that was emailed to them (the `email` channel only). `null` — the field was cleared (admin un-verified the email). */
24123
+ email_verified_method?: "manual" | "verification_flow" | "passwordless_otp" | "team_invite" | "email_change" | "federated" | "sms_otp" | "password_reset" | null;
24124
+ /** @description ISO 8601 timestamp of when `email_verified` was last flipped to true. */
24125
+ email_verified_at?: string | null;
24126
+ /** @description ISO 8601 timestamp of the user's last verified email change. When set, OAuth callbacks will not overwrite `email`/`email_verified` from the federated provider — the manually-chosen email wins. */
24127
+ email_change_locked_at?: string | null;
24128
+ /** @description ISO 8601 timestamp of the last Postmark hard bounce / spam complaint for this address. When set, the email is treated as undeliverable and no further emails are sent to the user until the address changes. */
24129
+ email_bounced_at?: string | null;
24130
+ /** @description ISO 8601 timestamp of the built-in welcome email send. Set once by the platform; guarantees at most one welcome per user. */
24131
+ welcome_sent_at?: string | null;
24132
+ /** @description ISO 8601 timestamp of the last time the hosted "create a passkey" offer was shown to this user after a login. Drives the snooze in `login_methods.passkey_promotion_snooze_days`. */
24133
+ passkey_prompted_at?: string | null;
24134
+ /** @description How many times the passkey offer has been shown to this user. Capped by `login_methods.passkey_promotion_max_prompts`; reset by an administrator through `POST /user/:id/passkey-prompt/reset`. */
24135
+ passkey_prompt_count?: number;
24136
+ /** @description ISO 8601 timestamp of the last time the user chose "Not now" on the passkey offer, as opposed to closing the tab. */
24137
+ passkey_prompt_dismissed_at?: string | null;
24138
+ /** @description contact phone number */
24139
+ phone?: string | null;
24140
+ /** @description Whether `phone` is a valid E.164 number. Calculated on read, never stored: new writes are rejected unless they normalise, so a `false` here is a legacy row that no SMS can reach — fix the number, or set the account default country and write it again. */
24141
+ phone_e164?: boolean;
24142
+ /** @description phone is verified */
24143
+ phone_verified: boolean;
24144
+ /** @description How `phone_verified` was last set. Same enum as `email_verified_method`, plus `sms_otp` — the user typed a code sent by SMS (`POST /user/:id/verify-phone/start`). */
24145
+ phone_verified_method?: "manual" | "verification_flow" | "passwordless_otp" | "team_invite" | "email_change" | "federated" | "sms_otp" | "password_reset" | null;
24146
+ /** @description ISO 8601 timestamp of when `phone_verified` was last flipped to true. */
24147
+ phone_verified_at?: string | null;
24148
+ /** @description country iso code */
24149
+ country_iso?: string | null;
24150
+ /** @description user birth_date */
24151
+ birth_date?: string | null;
24152
+ /** @description User gender (free-form, OIDC §5.1) */
24153
+ gender?: string | null;
24154
+ /** @description IANA time-zone name (e.g. "Europe/Madrid"). OIDC §5.1 — used for the `zoneinfo` claim. */
24155
+ zoneinfo?: string | null;
24156
+ /** @description user main language */
24157
+ locale?: string | null;
24158
+ /** @description customer region */
24159
+ region?: string | null;
24160
+ /** @description URL of the User's personal Web page or blog (OIDC §5.1) */
24161
+ website?: string | null;
24162
+ address?: {
24163
+ /** @description Full mailing address, formatted for display (may contain newlines) */
24164
+ formatted?: string | null;
24165
+ street_address?: string | null;
24166
+ /** @description City or locality */
24167
+ locality?: string | null;
24168
+ /** @description State, province, or region */
24169
+ region?: string | null;
24170
+ postal_code?: string | null;
24171
+ /** @description Country name */
24172
+ country?: string | null;
24173
+ } | null;
24174
+ /** @description User picture url */
24175
+ picture?: string | null;
24176
+ /** @description Total number of logins this user has performed. */
24177
+ logins_count: number;
24178
+ /** @description Last IP address from which this user logged in */
24179
+ last_ip?: string | null;
24180
+ /** @description Last date and time this user logged in (ISO_8601 format) */
24181
+ last_login?: string | null;
24182
+ /** @description Primary Accept-Language subtag seen at this user's FIRST login (e.g. "zh"). Written once and never updated, so a later login whose language differs is visible as `event.stats.language_changed` in actions — a cross-session signal no single request can produce. */
24183
+ first_language?: string | null;
24184
+ /**
24185
+ * @description true while the user is suspended. A suspended user is rejected at every login flow, token grant, session use and management-API call.
24186
+ * @default false
24187
+ */
24188
+ suspended: boolean;
24189
+ /** @description ISO 8601 timestamp of when `suspended` was last flipped to true. */
24190
+ suspended_at?: string | null;
24191
+ /** @description Free-form reason recorded when the user was suspended (e.g. "abuse: RCE payload"). */
24192
+ suspended_reason?: string | null;
24193
+ /**
24194
+ * @description User Metadata
24195
+ * @default {}
24196
+ */
24197
+ user_metadata: {
24198
+ [key: string]: unknown;
24199
+ };
24200
+ /**
24201
+ * @description App Metadata
24202
+ * @default {}
24203
+ */
24204
+ app_metadata: {
24205
+ [key: string]: unknown;
24206
+ };
24207
+ /** @description Object is related with this account */
24208
+ account: string;
24209
+ /**
24210
+ * @description UserMetadata
24211
+ * @default {}
24212
+ */
24213
+ metadata: {
24214
+ [key: string]: unknown;
24215
+ };
24216
+ /** @description User creation date */
24217
+ createdAt: string;
24218
+ /** @description User updated date */
24219
+ updatedAt?: string;
24220
+ } & {
24221
+ [key: string]: unknown;
24222
+ };
24223
+ };
24224
+ };
24225
+ /**
24226
+ * @description `bad_request` — The request is malformed. `message` says what is wrong.
24227
+ *
24228
+ * `validation_error` — The body, query or path failed schema validation. `details.issues` lists each failing field.
24229
+ */
24230
+ 400: {
24231
+ headers: {
24232
+ [name: string]: unknown;
24233
+ };
24234
+ content: {
24235
+ "application/json": components["schemas"]["ErrorResponse"] & {
24236
+ /** @enum {string} */
24237
+ error_code?: "bad_request" | "validation_error";
24238
+ };
24239
+ };
24240
+ };
24241
+ /**
24242
+ * @description `mfa_pending` — A second-factor challenge is pending; answer it before continuing.
24243
+ *
24244
+ * `not_logged_in` — There is no signed-in session for this request.
24245
+ */
24246
+ 401: {
24247
+ headers: {
24248
+ [name: string]: unknown;
24249
+ };
24250
+ content: {
24251
+ "application/json": components["schemas"]["ErrorResponse"] & {
24252
+ /** @enum {string} */
24253
+ error_code?: "mfa_pending" | "not_logged_in";
24254
+ };
24255
+ };
24256
+ };
24257
+ /** @description `forbidden` — The credentials are valid but do not allow this operation. */
24258
+ 403: {
24259
+ headers: {
24260
+ [name: string]: unknown;
24261
+ };
24262
+ content: {
24263
+ "application/json": components["schemas"]["ErrorResponse"] & {
24264
+ /** @enum {string} */
24265
+ error_code?: "forbidden";
24266
+ };
24267
+ };
24268
+ };
24269
+ /** @description `account_not_found` — No Auth Account matches the request (domain, header or token). */
24270
+ 404: {
24271
+ headers: {
24272
+ [name: string]: unknown;
24273
+ };
24274
+ content: {
24275
+ "application/json": components["schemas"]["ErrorResponse"] & {
24276
+ /** @enum {string} */
24277
+ error_code?: "account_not_found";
24278
+ };
24279
+ };
24280
+ };
24281
+ /** @description `too_many_requests` — Rate limit exceeded. Honour the `Retry-After` header. */
24282
+ 429: {
24283
+ headers: {
24284
+ [name: string]: unknown;
24285
+ };
24286
+ content: {
24287
+ "application/json": components["schemas"]["ErrorResponse"] & {
24288
+ /** @enum {string} */
24289
+ error_code?: "too_many_requests";
24290
+ };
24291
+ };
24292
+ };
24293
+ /** @description `internal_error` — Unexpected server error. Retry later; the request id is logged. */
24294
+ 500: {
24295
+ headers: {
24296
+ [name: string]: unknown;
24297
+ };
24298
+ content: {
24299
+ "application/json": components["schemas"]["ErrorResponse"] & {
24300
+ /** @enum {string} */
24301
+ error_code?: "internal_error";
24302
+ };
24303
+ };
24304
+ };
24305
+ };
24306
+ };
24072
24307
  "session/logout": {
24073
24308
  parameters: {
24074
24309
  query?: {
package/dist/version.js CHANGED
@@ -9,13 +9,13 @@
9
9
  // login pages could not import the SDK at all. Same pattern as auth-js.
10
10
  //
11
11
  // The sentinels MUST stay byte-identical to the `from` values in `.releaserc`.
12
- export const version = "2.7.20";
12
+ export const version = "2.7.21";
13
13
  // Short git SHA of the released commit. The version dates a build; this names
14
14
  // the exact tree, so a canonical log line or an audit entry leads straight to
15
15
  // `git show <sha>`. Deliberately NOT hex: an unreleased build (dev, a local
16
16
  // link) cannot be mistaken for a real commit — auth only records values that
17
17
  // look like a SHA, and this one never will.
18
- export const commit = "d9f28a7";
18
+ export const commit = "eda9c4d";
19
19
  // What this SDK writes in `x-faable-client`. Exported for a consumer that
20
20
  // builds a strategy on its own (outside `FaableAuthApi`) and still wants the
21
21
  // token request attributed — a bare `authClientCredentials` stamps only what
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@faable/auth-sdk",
3
- "version": "2.7.20",
3
+ "version": "2.7.21",
4
4
  "author": "Marc Pomar <marc@faable.com>",
5
5
  "main": "dist/index.js",
6
6
  "types": "dist/index.d.ts",
package/spec/openapi.json CHANGED
@@ -3,7 +3,7 @@
3
3
  "info": {
4
4
  "title": "@faablecloud/auth",
5
5
  "description": "Auth Platform made by Faable. Manage Users and Roles",
6
- "version": "2.30.0",
6
+ "version": "2.31.0",
7
7
  "license": {
8
8
  "name": "private",
9
9
  "url": "https://faable.com/docs/platform/privacy-policy"
@@ -53073,6 +53073,570 @@
53073
53073
  }
53074
53074
  }
53075
53075
  }
53076
+ },
53077
+ "patch": {
53078
+ "operationId": "session/me_update",
53079
+ "summary": "Update current User profile",
53080
+ "tags": [
53081
+ "session"
53082
+ ],
53083
+ "description": "Updates the profile of the User behind the current session or bearer token. Only `name`, `company_name` and `country_iso` can be changed; `company_name` is merged into `user_metadata` without touching its other keys. A Bearer token must belong to this Account.",
53084
+ "requestBody": {
53085
+ "required": true,
53086
+ "content": {
53087
+ "application/json": {
53088
+ "schema": {
53089
+ "type": "object",
53090
+ "properties": {
53091
+ "name": {
53092
+ "type": "string",
53093
+ "minLength": 1,
53094
+ "maxLength": 100
53095
+ },
53096
+ "company_name": {
53097
+ "type": "string",
53098
+ "maxLength": 100
53099
+ },
53100
+ "country_iso": {
53101
+ "type": "string",
53102
+ "maxLength": 3
53103
+ }
53104
+ },
53105
+ "additionalProperties": false,
53106
+ "description": "Profile fields the current User may edit on themselves. `company_name` is stored in `user_metadata`, merged with whatever else is there."
53107
+ }
53108
+ }
53109
+ },
53110
+ "description": "Profile fields the current User may edit on themselves. `company_name` is stored in `user_metadata`, merged with whatever else is there."
53111
+ },
53112
+ "responses": {
53113
+ "200": {
53114
+ "description": "The current User. With a Bearer access token the response also carries the token's custom claims (e.g. `ciapol.com/station_id`) as top-level properties; profile fields always win over a same-named claim.",
53115
+ "content": {
53116
+ "application/json": {
53117
+ "schema": {
53118
+ "type": "object",
53119
+ "required": [
53120
+ "id",
53121
+ "email_verified",
53122
+ "phone_verified",
53123
+ "logins_count",
53124
+ "user_metadata",
53125
+ "app_metadata",
53126
+ "account",
53127
+ "createdAt"
53128
+ ],
53129
+ "properties": {
53130
+ "id": {
53131
+ "type": "string",
53132
+ "description": "User ID"
53133
+ },
53134
+ "name": {
53135
+ "type": "string",
53136
+ "description": "User name",
53137
+ "nullable": true
53138
+ },
53139
+ "username": {
53140
+ "type": "string",
53141
+ "description": "unique username for this user",
53142
+ "nullable": true
53143
+ },
53144
+ "given_name": {
53145
+ "type": "string",
53146
+ "description": "Given name",
53147
+ "nullable": true
53148
+ },
53149
+ "family_name": {
53150
+ "type": "string",
53151
+ "description": "Family name",
53152
+ "nullable": true
53153
+ },
53154
+ "middle_name": {
53155
+ "type": "string",
53156
+ "description": "Middle name (OIDC §5.1)",
53157
+ "nullable": true
53158
+ },
53159
+ "nickname": {
53160
+ "type": "string",
53161
+ "description": "Casual name. Distinct from given_name (e.g. \"Mike\" vs \"Michael\"). OIDC §5.1",
53162
+ "nullable": true
53163
+ },
53164
+ "email": {
53165
+ "type": "string",
53166
+ "description": "User email",
53167
+ "nullable": true
53168
+ },
53169
+ "email_verified": {
53170
+ "type": "boolean",
53171
+ "description": "true if email is verified",
53172
+ "default": false
53173
+ },
53174
+ "email_verified_method": {
53175
+ "anyOf": [
53176
+ {
53177
+ "type": "string",
53178
+ "enum": [
53179
+ "manual"
53180
+ ]
53181
+ },
53182
+ {
53183
+ "type": "string",
53184
+ "enum": [
53185
+ "verification_flow"
53186
+ ]
53187
+ },
53188
+ {
53189
+ "type": "string",
53190
+ "enum": [
53191
+ "passwordless_otp"
53192
+ ]
53193
+ },
53194
+ {
53195
+ "type": "string",
53196
+ "enum": [
53197
+ "team_invite"
53198
+ ]
53199
+ },
53200
+ {
53201
+ "type": "string",
53202
+ "enum": [
53203
+ "email_change"
53204
+ ]
53205
+ },
53206
+ {
53207
+ "type": "string",
53208
+ "enum": [
53209
+ "federated"
53210
+ ]
53211
+ },
53212
+ {
53213
+ "type": "string",
53214
+ "enum": [
53215
+ "sms_otp"
53216
+ ]
53217
+ },
53218
+ {
53219
+ "type": "string",
53220
+ "enum": [
53221
+ "password_reset"
53222
+ ]
53223
+ },
53224
+ {
53225
+ "type": "null"
53226
+ }
53227
+ ],
53228
+ "description": "How `email_verified` was last set. `manual` — admin flipped the flag via `POST /user/:id`. `verification_flow` — user clicked the verification link. `passwordless_otp` — user completed passwordless OTP login. `team_invite` — user clicked a team invitation link. `email_change` — user confirmed a self-service email change. `federated` — verified by the external IdP on OAuth callback. `password_reset` — user completed the recovery link that was emailed to them (the `email` channel only). `null` — the field was cleared (admin un-verified the email)."
53229
+ },
53230
+ "email_verified_at": {
53231
+ "type": "string",
53232
+ "description": "ISO 8601 timestamp of when `email_verified` was last flipped to true.",
53233
+ "nullable": true
53234
+ },
53235
+ "email_change_locked_at": {
53236
+ "type": "string",
53237
+ "description": "ISO 8601 timestamp of the user's last verified email change. When set, OAuth callbacks will not overwrite `email`/`email_verified` from the federated provider — the manually-chosen email wins.",
53238
+ "nullable": true
53239
+ },
53240
+ "email_bounced_at": {
53241
+ "type": "string",
53242
+ "description": "ISO 8601 timestamp of the last Postmark hard bounce / spam complaint for this address. When set, the email is treated as undeliverable and no further emails are sent to the user until the address changes.",
53243
+ "nullable": true
53244
+ },
53245
+ "welcome_sent_at": {
53246
+ "type": "string",
53247
+ "description": "ISO 8601 timestamp of the built-in welcome email send. Set once by the platform; guarantees at most one welcome per user.",
53248
+ "nullable": true
53249
+ },
53250
+ "passkey_prompted_at": {
53251
+ "type": "string",
53252
+ "description": "ISO 8601 timestamp of the last time the hosted \"create a passkey\" offer was shown to this user after a login. Drives the snooze in `login_methods.passkey_promotion_snooze_days`.",
53253
+ "nullable": true
53254
+ },
53255
+ "passkey_prompt_count": {
53256
+ "type": "integer",
53257
+ "description": "How many times the passkey offer has been shown to this user. Capped by `login_methods.passkey_promotion_max_prompts`; reset by an administrator through `POST /user/:id/passkey-prompt/reset`."
53258
+ },
53259
+ "passkey_prompt_dismissed_at": {
53260
+ "type": "string",
53261
+ "description": "ISO 8601 timestamp of the last time the user chose \"Not now\" on the passkey offer, as opposed to closing the tab.",
53262
+ "nullable": true
53263
+ },
53264
+ "phone": {
53265
+ "type": "string",
53266
+ "description": "contact phone number",
53267
+ "nullable": true
53268
+ },
53269
+ "phone_e164": {
53270
+ "type": "boolean",
53271
+ "description": "Whether `phone` is a valid E.164 number. Calculated on read, never stored: new writes are rejected unless they normalise, so a `false` here is a legacy row that no SMS can reach — fix the number, or set the account default country and write it again."
53272
+ },
53273
+ "phone_verified": {
53274
+ "type": "boolean",
53275
+ "description": "phone is verified"
53276
+ },
53277
+ "phone_verified_method": {
53278
+ "anyOf": [
53279
+ {
53280
+ "type": "string",
53281
+ "enum": [
53282
+ "manual"
53283
+ ]
53284
+ },
53285
+ {
53286
+ "type": "string",
53287
+ "enum": [
53288
+ "verification_flow"
53289
+ ]
53290
+ },
53291
+ {
53292
+ "type": "string",
53293
+ "enum": [
53294
+ "passwordless_otp"
53295
+ ]
53296
+ },
53297
+ {
53298
+ "type": "string",
53299
+ "enum": [
53300
+ "team_invite"
53301
+ ]
53302
+ },
53303
+ {
53304
+ "type": "string",
53305
+ "enum": [
53306
+ "email_change"
53307
+ ]
53308
+ },
53309
+ {
53310
+ "type": "string",
53311
+ "enum": [
53312
+ "federated"
53313
+ ]
53314
+ },
53315
+ {
53316
+ "type": "string",
53317
+ "enum": [
53318
+ "sms_otp"
53319
+ ]
53320
+ },
53321
+ {
53322
+ "type": "string",
53323
+ "enum": [
53324
+ "password_reset"
53325
+ ]
53326
+ },
53327
+ {
53328
+ "type": "null"
53329
+ }
53330
+ ],
53331
+ "description": "How `phone_verified` was last set. Same enum as `email_verified_method`, plus `sms_otp` — the user typed a code sent by SMS (`POST /user/:id/verify-phone/start`)."
53332
+ },
53333
+ "phone_verified_at": {
53334
+ "type": "string",
53335
+ "description": "ISO 8601 timestamp of when `phone_verified` was last flipped to true.",
53336
+ "nullable": true
53337
+ },
53338
+ "country_iso": {
53339
+ "type": "string",
53340
+ "description": "country iso code",
53341
+ "nullable": true
53342
+ },
53343
+ "birth_date": {
53344
+ "type": "string",
53345
+ "description": "user birth_date",
53346
+ "nullable": true
53347
+ },
53348
+ "gender": {
53349
+ "type": "string",
53350
+ "description": "User gender (free-form, OIDC §5.1)",
53351
+ "nullable": true
53352
+ },
53353
+ "zoneinfo": {
53354
+ "type": "string",
53355
+ "description": "IANA time-zone name (e.g. \"Europe/Madrid\"). OIDC §5.1 — used for the `zoneinfo` claim.",
53356
+ "nullable": true
53357
+ },
53358
+ "locale": {
53359
+ "type": "string",
53360
+ "description": "user main language",
53361
+ "nullable": true
53362
+ },
53363
+ "region": {
53364
+ "type": "string",
53365
+ "description": "customer region",
53366
+ "nullable": true
53367
+ },
53368
+ "website": {
53369
+ "type": "string",
53370
+ "description": "URL of the User's personal Web page or blog (OIDC §5.1)",
53371
+ "nullable": true
53372
+ },
53373
+ "address": {
53374
+ "type": "object",
53375
+ "properties": {
53376
+ "formatted": {
53377
+ "type": "string",
53378
+ "description": "Full mailing address, formatted for display (may contain newlines)",
53379
+ "nullable": true
53380
+ },
53381
+ "street_address": {
53382
+ "type": "string",
53383
+ "nullable": true
53384
+ },
53385
+ "locality": {
53386
+ "type": "string",
53387
+ "description": "City or locality",
53388
+ "nullable": true
53389
+ },
53390
+ "region": {
53391
+ "type": "string",
53392
+ "description": "State, province, or region",
53393
+ "nullable": true
53394
+ },
53395
+ "postal_code": {
53396
+ "type": "string",
53397
+ "nullable": true
53398
+ },
53399
+ "country": {
53400
+ "type": "string",
53401
+ "description": "Country name",
53402
+ "nullable": true
53403
+ }
53404
+ },
53405
+ "additionalProperties": false,
53406
+ "nullable": true
53407
+ },
53408
+ "picture": {
53409
+ "type": "string",
53410
+ "description": "User picture url",
53411
+ "nullable": true
53412
+ },
53413
+ "logins_count": {
53414
+ "type": "number",
53415
+ "description": "Total number of logins this user has performed."
53416
+ },
53417
+ "last_ip": {
53418
+ "type": "string",
53419
+ "description": "Last IP address from which this user logged in",
53420
+ "nullable": true
53421
+ },
53422
+ "last_login": {
53423
+ "type": "string",
53424
+ "description": "Last date and time this user logged in (ISO_8601 format)",
53425
+ "nullable": true
53426
+ },
53427
+ "first_language": {
53428
+ "type": "string",
53429
+ "description": "Primary Accept-Language subtag seen at this user's FIRST login (e.g. \"zh\"). Written once and never updated, so a later login whose language differs is visible as `event.stats.language_changed` in actions — a cross-session signal no single request can produce.",
53430
+ "nullable": true
53431
+ },
53432
+ "suspended": {
53433
+ "type": "boolean",
53434
+ "description": "true while the user is suspended. A suspended user is rejected at every login flow, token grant, session use and management-API call.",
53435
+ "default": false
53436
+ },
53437
+ "suspended_at": {
53438
+ "type": "string",
53439
+ "description": "ISO 8601 timestamp of when `suspended` was last flipped to true.",
53440
+ "nullable": true
53441
+ },
53442
+ "suspended_reason": {
53443
+ "type": "string",
53444
+ "description": "Free-form reason recorded when the user was suspended (e.g. \"abuse: RCE payload\").",
53445
+ "nullable": true
53446
+ },
53447
+ "user_metadata": {
53448
+ "type": "object",
53449
+ "properties": {},
53450
+ "additionalProperties": true,
53451
+ "description": "User Metadata",
53452
+ "default": {}
53453
+ },
53454
+ "app_metadata": {
53455
+ "type": "object",
53456
+ "properties": {},
53457
+ "additionalProperties": true,
53458
+ "description": "App Metadata",
53459
+ "default": {}
53460
+ },
53461
+ "account": {
53462
+ "type": "string",
53463
+ "description": "Object is related with this account"
53464
+ },
53465
+ "metadata": {
53466
+ "type": "object",
53467
+ "properties": {},
53468
+ "additionalProperties": true,
53469
+ "description": "UserMetadata",
53470
+ "default": {}
53471
+ },
53472
+ "createdAt": {
53473
+ "type": "string",
53474
+ "description": "User creation date"
53475
+ },
53476
+ "updatedAt": {
53477
+ "type": "string",
53478
+ "description": "User updated date"
53479
+ }
53480
+ },
53481
+ "additionalProperties": true,
53482
+ "description": "The current User. With a Bearer access token the response also carries the token's custom claims (e.g. `ciapol.com/station_id`) as top-level properties; profile fields always win over a same-named claim."
53483
+ }
53484
+ }
53485
+ }
53486
+ },
53487
+ "400": {
53488
+ "description": "`bad_request` — The request is malformed. `message` says what is wrong.\n\n`validation_error` — The body, query or path failed schema validation. `details.issues` lists each failing field.",
53489
+ "content": {
53490
+ "application/json": {
53491
+ "schema": {
53492
+ "allOf": [
53493
+ {
53494
+ "$ref": "#/components/schemas/ErrorResponse"
53495
+ },
53496
+ {
53497
+ "type": "object",
53498
+ "properties": {
53499
+ "error_code": {
53500
+ "type": "string",
53501
+ "enum": [
53502
+ "bad_request",
53503
+ "validation_error"
53504
+ ]
53505
+ }
53506
+ }
53507
+ }
53508
+ ]
53509
+ }
53510
+ }
53511
+ }
53512
+ },
53513
+ "401": {
53514
+ "description": "`mfa_pending` — A second-factor challenge is pending; answer it before continuing.\n\n`not_logged_in` — There is no signed-in session for this request.",
53515
+ "content": {
53516
+ "application/json": {
53517
+ "schema": {
53518
+ "allOf": [
53519
+ {
53520
+ "$ref": "#/components/schemas/ErrorResponse"
53521
+ },
53522
+ {
53523
+ "type": "object",
53524
+ "properties": {
53525
+ "error_code": {
53526
+ "type": "string",
53527
+ "enum": [
53528
+ "mfa_pending",
53529
+ "not_logged_in"
53530
+ ]
53531
+ }
53532
+ }
53533
+ }
53534
+ ]
53535
+ }
53536
+ }
53537
+ }
53538
+ },
53539
+ "403": {
53540
+ "description": "`forbidden` — The credentials are valid but do not allow this operation.",
53541
+ "content": {
53542
+ "application/json": {
53543
+ "schema": {
53544
+ "allOf": [
53545
+ {
53546
+ "$ref": "#/components/schemas/ErrorResponse"
53547
+ },
53548
+ {
53549
+ "type": "object",
53550
+ "properties": {
53551
+ "error_code": {
53552
+ "type": "string",
53553
+ "enum": [
53554
+ "forbidden"
53555
+ ]
53556
+ }
53557
+ }
53558
+ }
53559
+ ]
53560
+ }
53561
+ }
53562
+ }
53563
+ },
53564
+ "404": {
53565
+ "description": "`account_not_found` — No Auth Account matches the request (domain, header or token).",
53566
+ "content": {
53567
+ "application/json": {
53568
+ "schema": {
53569
+ "allOf": [
53570
+ {
53571
+ "$ref": "#/components/schemas/ErrorResponse"
53572
+ },
53573
+ {
53574
+ "type": "object",
53575
+ "properties": {
53576
+ "error_code": {
53577
+ "type": "string",
53578
+ "enum": [
53579
+ "account_not_found"
53580
+ ]
53581
+ }
53582
+ }
53583
+ }
53584
+ ]
53585
+ }
53586
+ }
53587
+ }
53588
+ },
53589
+ "429": {
53590
+ "description": "`too_many_requests` — Rate limit exceeded. Honour the `Retry-After` header.",
53591
+ "content": {
53592
+ "application/json": {
53593
+ "schema": {
53594
+ "allOf": [
53595
+ {
53596
+ "$ref": "#/components/schemas/ErrorResponse"
53597
+ },
53598
+ {
53599
+ "type": "object",
53600
+ "properties": {
53601
+ "error_code": {
53602
+ "type": "string",
53603
+ "enum": [
53604
+ "too_many_requests"
53605
+ ]
53606
+ }
53607
+ }
53608
+ }
53609
+ ]
53610
+ }
53611
+ }
53612
+ }
53613
+ },
53614
+ "500": {
53615
+ "description": "`internal_error` — Unexpected server error. Retry later; the request id is logged.",
53616
+ "content": {
53617
+ "application/json": {
53618
+ "schema": {
53619
+ "allOf": [
53620
+ {
53621
+ "$ref": "#/components/schemas/ErrorResponse"
53622
+ },
53623
+ {
53624
+ "type": "object",
53625
+ "properties": {
53626
+ "error_code": {
53627
+ "type": "string",
53628
+ "enum": [
53629
+ "internal_error"
53630
+ ]
53631
+ }
53632
+ }
53633
+ }
53634
+ ]
53635
+ }
53636
+ }
53637
+ }
53638
+ }
53639
+ }
53076
53640
  }
53077
53641
  },
53078
53642
  "/logout": {