@faable/auth-sdk 2.6.20 → 2.6.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.
@@ -105,6 +105,7 @@ export declare class FaableAuthApi extends GeneratedFaableAuthApi {
105
105
  passkey_prompt_count?: number | undefined;
106
106
  passkey_prompt_dismissed_at?: string | null | undefined;
107
107
  phone?: string | null | undefined;
108
+ phone_e164?: boolean | undefined;
108
109
  phone_verified: boolean;
109
110
  phone_verified_method?: "manual" | "verification_flow" | "passwordless_otp" | "team_invite" | "email_change" | "federated" | "sms_otp" | null | undefined;
110
111
  phone_verified_at?: string | null | undefined;
@@ -163,6 +164,7 @@ export declare class FaableAuthApi extends GeneratedFaableAuthApi {
163
164
  passkey_prompt_count?: number | undefined;
164
165
  passkey_prompt_dismissed_at?: string | null | undefined;
165
166
  phone?: string | null | undefined;
167
+ phone_e164?: boolean | undefined;
166
168
  phone_verified: boolean;
167
169
  phone_verified_method?: "manual" | "verification_flow" | "passwordless_otp" | "team_invite" | "email_change" | "federated" | "sms_otp" | null | undefined;
168
170
  phone_verified_at?: string | null | undefined;
@@ -224,6 +226,7 @@ export declare class FaableAuthApi extends GeneratedFaableAuthApi {
224
226
  passkey_prompt_count?: number | undefined;
225
227
  passkey_prompt_dismissed_at?: string | null | undefined;
226
228
  phone?: string | null | undefined;
229
+ phone_e164?: boolean | undefined;
227
230
  phone_verified: boolean;
228
231
  phone_verified_method?: "manual" | "verification_flow" | "passwordless_otp" | "team_invite" | "email_change" | "federated" | "sms_otp" | null | undefined;
229
232
  phone_verified_at?: string | null | undefined;
@@ -284,6 +287,7 @@ export declare class FaableAuthApi extends GeneratedFaableAuthApi {
284
287
  passkey_prompt_count?: number | undefined;
285
288
  passkey_prompt_dismissed_at?: string | null | undefined;
286
289
  phone?: string | null | undefined;
290
+ phone_e164?: boolean | undefined;
287
291
  phone_verified: boolean;
288
292
  phone_verified_method?: "manual" | "verification_flow" | "passwordless_otp" | "team_invite" | "email_change" | "federated" | "sms_otp" | null | undefined;
289
293
  phone_verified_at?: string | null | undefined;
@@ -343,6 +347,7 @@ export declare class FaableAuthApi extends GeneratedFaableAuthApi {
343
347
  passkey_prompt_count?: number | undefined;
344
348
  passkey_prompt_dismissed_at?: string | null | undefined;
345
349
  phone?: string | null | undefined;
350
+ phone_e164?: boolean | undefined;
346
351
  phone_verified: boolean;
347
352
  phone_verified_method?: "manual" | "verification_flow" | "passwordless_otp" | "team_invite" | "email_change" | "federated" | "sms_otp" | null | undefined;
348
353
  phone_verified_at?: string | null | undefined;
@@ -402,6 +407,7 @@ export declare class FaableAuthApi extends GeneratedFaableAuthApi {
402
407
  passkey_prompt_count?: number | undefined;
403
408
  passkey_prompt_dismissed_at?: string | null | undefined;
404
409
  phone?: string | null | undefined;
410
+ phone_e164?: boolean | undefined;
405
411
  phone_verified: boolean;
406
412
  phone_verified_method?: "manual" | "verification_flow" | "passwordless_otp" | "team_invite" | "email_change" | "federated" | "sms_otp" | null | undefined;
407
413
  phone_verified_at?: string | null | undefined;
@@ -3935,6 +3935,7 @@ export declare abstract class GeneratedFaableAuthApi extends FaableApi {
3935
3935
  passkey_prompt_count?: number | undefined;
3936
3936
  passkey_prompt_dismissed_at?: string | null | undefined;
3937
3937
  phone?: string | null | undefined;
3938
+ phone_e164?: boolean | undefined;
3938
3939
  phone_verified: boolean;
3939
3940
  phone_verified_method?: "manual" | "verification_flow" | "passwordless_otp" | "team_invite" | "email_change" | "federated" | "sms_otp" | null | undefined;
3940
3941
  phone_verified_at?: string | null | undefined;
@@ -3998,6 +3999,7 @@ export declare abstract class GeneratedFaableAuthApi extends FaableApi {
3998
3999
  passkey_prompt_count?: number | undefined;
3999
4000
  passkey_prompt_dismissed_at?: string | null | undefined;
4000
4001
  phone?: string | null | undefined;
4002
+ phone_e164?: boolean | undefined;
4001
4003
  phone_verified: boolean;
4002
4004
  phone_verified_method?: "manual" | "verification_flow" | "passwordless_otp" | "team_invite" | "email_change" | "federated" | "sms_otp" | null | undefined;
4003
4005
  phone_verified_at?: string | null | undefined;
@@ -4061,6 +4063,7 @@ export declare abstract class GeneratedFaableAuthApi extends FaableApi {
4061
4063
  passkey_prompt_count?: number | undefined;
4062
4064
  passkey_prompt_dismissed_at?: string | null | undefined;
4063
4065
  phone?: string | null | undefined;
4066
+ phone_e164?: boolean | undefined;
4064
4067
  phone_verified: boolean;
4065
4068
  phone_verified_method?: "manual" | "verification_flow" | "passwordless_otp" | "team_invite" | "email_change" | "federated" | "sms_otp" | null | undefined;
4066
4069
  phone_verified_at?: string | null | undefined;
@@ -4125,6 +4128,7 @@ export declare abstract class GeneratedFaableAuthApi extends FaableApi {
4125
4128
  passkey_prompt_count?: number | undefined;
4126
4129
  passkey_prompt_dismissed_at?: string | null | undefined;
4127
4130
  phone?: string | null | undefined;
4131
+ phone_e164?: boolean | undefined;
4128
4132
  phone_verified: boolean;
4129
4133
  phone_verified_method?: "manual" | "verification_flow" | "passwordless_otp" | "team_invite" | "email_change" | "federated" | "sms_otp" | null | undefined;
4130
4134
  phone_verified_at?: string | null | undefined;
@@ -4183,6 +4187,7 @@ export declare abstract class GeneratedFaableAuthApi extends FaableApi {
4183
4187
  passkey_prompt_count?: number | undefined;
4184
4188
  passkey_prompt_dismissed_at?: string | null | undefined;
4185
4189
  phone?: string | null | undefined;
4190
+ phone_e164?: boolean | undefined;
4186
4191
  phone_verified: boolean;
4187
4192
  phone_verified_method?: "manual" | "verification_flow" | "passwordless_otp" | "team_invite" | "email_change" | "federated" | "sms_otp" | null | undefined;
4188
4193
  phone_verified_at?: string | null | undefined;
@@ -4244,6 +4249,7 @@ export declare abstract class GeneratedFaableAuthApi extends FaableApi {
4244
4249
  passkey_prompt_count?: number | undefined;
4245
4250
  passkey_prompt_dismissed_at?: string | null | undefined;
4246
4251
  phone?: string | null | undefined;
4252
+ phone_e164?: boolean | undefined;
4247
4253
  phone_verified: boolean;
4248
4254
  phone_verified_method?: "manual" | "verification_flow" | "passwordless_otp" | "team_invite" | "email_change" | "federated" | "sms_otp" | null | undefined;
4249
4255
  phone_verified_at?: string | null | undefined;
@@ -4346,6 +4352,7 @@ export declare abstract class GeneratedFaableAuthApi extends FaableApi {
4346
4352
  passkey_prompt_count?: number | undefined;
4347
4353
  passkey_prompt_dismissed_at?: string | null | undefined;
4348
4354
  phone?: string | null | undefined;
4355
+ phone_e164?: boolean | undefined;
4349
4356
  phone_verified: boolean;
4350
4357
  phone_verified_method?: "manual" | "verification_flow" | "passwordless_otp" | "team_invite" | "email_change" | "federated" | "sms_otp" | null | undefined;
4351
4358
  phone_verified_at?: string | null | undefined;
@@ -584,6 +584,46 @@ export interface paths {
584
584
  patch?: never;
585
585
  trace?: never;
586
586
  };
587
+ "/verify-phone/pending": {
588
+ parameters: {
589
+ query?: never;
590
+ header?: never;
591
+ path?: never;
592
+ cookie?: never;
593
+ };
594
+ /**
595
+ * What the verification screen should say
596
+ * @description The masked destination of a pending verification and how long its code is still good for. The screen needs this to say "we sent a code to ···· 628": the `destination_masked` of `start` goes to whoever called it, not to the person typing the code.
597
+ */
598
+ get: operations["user/verifyPhonePending"];
599
+ put?: never;
600
+ post?: never;
601
+ delete?: never;
602
+ options?: never;
603
+ head?: never;
604
+ patch?: never;
605
+ trace?: never;
606
+ };
607
+ "/verify-phone/restart": {
608
+ parameters: {
609
+ query?: never;
610
+ header?: never;
611
+ path?: never;
612
+ cookie?: never;
613
+ };
614
+ get?: never;
615
+ put?: never;
616
+ /**
617
+ * Correct the number and send a new code
618
+ * @description Replaces the phone of a pending verification and sends a fresh code, returning a new `state`; the old one stops working. No session needed — the `state` is the proof — which is why it refuses with 409 `phone_already_verified` once the person has a verified phone: from that point a leaked `state` must not be able to move the number. Counts against the monthly SMS allowance like `start`.
619
+ */
620
+ post: operations["user/verifyPhoneRestart"];
621
+ delete?: never;
622
+ options?: never;
623
+ head?: never;
624
+ patch?: never;
625
+ trace?: never;
626
+ };
587
627
  "/user/{user_id}/factors": {
588
628
  parameters: {
589
629
  query?: never;
@@ -3585,6 +3625,8 @@ export interface components {
3585
3625
  passkey_prompt_dismissed_at?: string | null;
3586
3626
  /** @description contact phone number */
3587
3627
  phone?: string | null;
3628
+ /** @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. */
3629
+ phone_e164?: boolean;
3588
3630
  /** @description phone is verified */
3589
3631
  phone_verified: boolean;
3590
3632
  /** @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`). */
@@ -7356,6 +7398,8 @@ export interface operations {
7356
7398
  passkey_prompt_dismissed_at?: string | null;
7357
7399
  /** @description contact phone number */
7358
7400
  phone?: string | null;
7401
+ /** @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. */
7402
+ phone_e164?: boolean;
7359
7403
  /** @description phone is verified */
7360
7404
  phone_verified: boolean;
7361
7405
  /** @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`). */
@@ -7496,6 +7540,8 @@ export interface operations {
7496
7540
  passkey_prompt_dismissed_at?: string | null;
7497
7541
  /** @description contact phone number */
7498
7542
  phone?: string | null;
7543
+ /** @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. */
7544
+ phone_e164?: boolean;
7499
7545
  /** @description phone is verified */
7500
7546
  phone_verified: boolean;
7501
7547
  /** @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`). */
@@ -7676,6 +7722,8 @@ export interface operations {
7676
7722
  passkey_prompt_dismissed_at?: string | null;
7677
7723
  /** @description contact phone number */
7678
7724
  phone?: string | null;
7725
+ /** @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. */
7726
+ phone_e164?: boolean;
7679
7727
  /** @description phone is verified */
7680
7728
  phone_verified: boolean;
7681
7729
  /** @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`). */
@@ -7816,6 +7864,8 @@ export interface operations {
7816
7864
  passkey_prompt_dismissed_at?: string | null;
7817
7865
  /** @description contact phone number */
7818
7866
  phone?: string | null;
7867
+ /** @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. */
7868
+ phone_e164?: boolean;
7819
7869
  /** @description phone is verified */
7820
7870
  phone_verified: boolean;
7821
7871
  /** @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`). */
@@ -8177,6 +8227,69 @@ export interface operations {
8177
8227
  };
8178
8228
  };
8179
8229
  };
8230
+ "user/verifyPhonePending": {
8231
+ parameters: {
8232
+ query: {
8233
+ state: string;
8234
+ };
8235
+ header?: never;
8236
+ path?: never;
8237
+ cookie?: never;
8238
+ };
8239
+ requestBody?: never;
8240
+ responses: {
8241
+ /** @description Default Response */
8242
+ 200: {
8243
+ headers: {
8244
+ [name: string]: unknown;
8245
+ };
8246
+ content: {
8247
+ "application/json": {
8248
+ destination_masked: string;
8249
+ expires_in: number;
8250
+ /** @description Whether the screen may offer "this is not my number". False once the phone is verified: from then on the `state` must not be able to point it somewhere else. */
8251
+ can_change: boolean;
8252
+ /** @description The account's default country (ISO 3166-1 alpha-2), so the screen can preselect the right dial code when the person corrects their number. */
8253
+ default_country?: string;
8254
+ };
8255
+ };
8256
+ };
8257
+ };
8258
+ };
8259
+ "user/verifyPhoneRestart": {
8260
+ parameters: {
8261
+ query?: never;
8262
+ header?: never;
8263
+ path?: never;
8264
+ cookie?: never;
8265
+ };
8266
+ requestBody: {
8267
+ content: {
8268
+ "application/json": {
8269
+ state: string;
8270
+ phone: string;
8271
+ };
8272
+ };
8273
+ };
8274
+ responses: {
8275
+ /** @description Default Response */
8276
+ 200: {
8277
+ headers: {
8278
+ [name: string]: unknown;
8279
+ };
8280
+ content: {
8281
+ "application/json": {
8282
+ /** @enum {string} */
8283
+ status: "sent";
8284
+ destination_masked: string;
8285
+ /** @description Opaque handle to confirm with. It is what lets a tenant backend start the verification (M2M) and send the person to `/flow/verify-phone?state=…` without a session. */
8286
+ state: string;
8287
+ expires_in: number;
8288
+ };
8289
+ };
8290
+ };
8291
+ };
8292
+ };
8180
8293
  "user/factors": {
8181
8294
  parameters: {
8182
8295
  query?: never;
@@ -12761,6 +12874,8 @@ export interface operations {
12761
12874
  passkey_prompt_dismissed_at?: string | null;
12762
12875
  /** @description contact phone number */
12763
12876
  phone?: string | null;
12877
+ /** @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. */
12878
+ phone_e164?: boolean;
12764
12879
  /** @description phone is verified */
12765
12880
  phone_verified: boolean;
12766
12881
  /** @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`). */
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.6.20";
12
+ export const version = "2.6.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 = "3b53430";
18
+ export const commit = "27ee17f";
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.6.20",
3
+ "version": "2.6.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.21.0",
6
+ "version": "2.22.0",
7
7
  "license": {
8
8
  "name": "private",
9
9
  "url": "https://faable.com/docs/platform/privacy-policy"
@@ -2295,6 +2295,10 @@
2295
2295
  "description": "contact phone number",
2296
2296
  "nullable": true
2297
2297
  },
2298
+ "phone_e164": {
2299
+ "type": "boolean",
2300
+ "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."
2301
+ },
2298
2302
  "phone_verified": {
2299
2303
  "type": "boolean",
2300
2304
  "description": "phone is verified"
@@ -15101,6 +15105,10 @@
15101
15105
  "description": "contact phone number",
15102
15106
  "nullable": true
15103
15107
  },
15108
+ "phone_e164": {
15109
+ "type": "boolean",
15110
+ "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."
15111
+ },
15104
15112
  "phone_verified": {
15105
15113
  "type": "boolean",
15106
15114
  "description": "phone is verified"
@@ -15485,6 +15493,10 @@
15485
15493
  "description": "contact phone number",
15486
15494
  "nullable": true
15487
15495
  },
15496
+ "phone_e164": {
15497
+ "type": "boolean",
15498
+ "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."
15499
+ },
15488
15500
  "phone_verified": {
15489
15501
  "type": "boolean",
15490
15502
  "description": "phone is verified"
@@ -15948,6 +15960,10 @@
15948
15960
  "description": "contact phone number",
15949
15961
  "nullable": true
15950
15962
  },
15963
+ "phone_e164": {
15964
+ "type": "boolean",
15965
+ "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."
15966
+ },
15951
15967
  "phone_verified": {
15952
15968
  "type": "boolean",
15953
15969
  "description": "phone is verified"
@@ -16330,6 +16346,10 @@
16330
16346
  "description": "contact phone number",
16331
16347
  "nullable": true
16332
16348
  },
16349
+ "phone_e164": {
16350
+ "type": "boolean",
16351
+ "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."
16352
+ },
16333
16353
  "phone_verified": {
16334
16354
  "type": "boolean",
16335
16355
  "description": "phone is verified"
@@ -17220,6 +17240,129 @@
17220
17240
  }
17221
17241
  }
17222
17242
  },
17243
+ "/verify-phone/pending": {
17244
+ "get": {
17245
+ "operationId": "user/verifyPhonePending",
17246
+ "summary": "What the verification screen should say",
17247
+ "tags": [
17248
+ "user"
17249
+ ],
17250
+ "description": "The masked destination of a pending verification and how long its code is still good for. The screen needs this to say \"we sent a code to ···· 628\": the `destination_masked` of `start` goes to whoever called it, not to the person typing the code.",
17251
+ "parameters": [
17252
+ {
17253
+ "schema": {
17254
+ "type": "string"
17255
+ },
17256
+ "in": "query",
17257
+ "name": "state",
17258
+ "required": true
17259
+ }
17260
+ ],
17261
+ "responses": {
17262
+ "200": {
17263
+ "description": "Default Response",
17264
+ "content": {
17265
+ "application/json": {
17266
+ "schema": {
17267
+ "type": "object",
17268
+ "required": [
17269
+ "destination_masked",
17270
+ "expires_in",
17271
+ "can_change"
17272
+ ],
17273
+ "properties": {
17274
+ "destination_masked": {
17275
+ "type": "string"
17276
+ },
17277
+ "expires_in": {
17278
+ "type": "integer"
17279
+ },
17280
+ "can_change": {
17281
+ "type": "boolean",
17282
+ "description": "Whether the screen may offer \"this is not my number\". False once the phone is verified: from then on the `state` must not be able to point it somewhere else."
17283
+ },
17284
+ "default_country": {
17285
+ "type": "string",
17286
+ "description": "The account's default country (ISO 3166-1 alpha-2), so the screen can preselect the right dial code when the person corrects their number."
17287
+ }
17288
+ }
17289
+ }
17290
+ }
17291
+ }
17292
+ }
17293
+ }
17294
+ }
17295
+ },
17296
+ "/verify-phone/restart": {
17297
+ "post": {
17298
+ "operationId": "user/verifyPhoneRestart",
17299
+ "summary": "Correct the number and send a new code",
17300
+ "tags": [
17301
+ "user"
17302
+ ],
17303
+ "description": "Replaces the phone of a pending verification and sends a fresh code, returning a new `state`; the old one stops working. No session needed — the `state` is the proof — which is why it refuses with 409 `phone_already_verified` once the person has a verified phone: from that point a leaked `state` must not be able to move the number. Counts against the monthly SMS allowance like `start`.",
17304
+ "requestBody": {
17305
+ "required": true,
17306
+ "content": {
17307
+ "application/json": {
17308
+ "schema": {
17309
+ "type": "object",
17310
+ "required": [
17311
+ "state",
17312
+ "phone"
17313
+ ],
17314
+ "properties": {
17315
+ "state": {
17316
+ "type": "string"
17317
+ },
17318
+ "phone": {
17319
+ "type": "string",
17320
+ "minLength": 4
17321
+ }
17322
+ },
17323
+ "additionalProperties": false
17324
+ }
17325
+ }
17326
+ }
17327
+ },
17328
+ "responses": {
17329
+ "200": {
17330
+ "description": "Default Response",
17331
+ "content": {
17332
+ "application/json": {
17333
+ "schema": {
17334
+ "type": "object",
17335
+ "required": [
17336
+ "status",
17337
+ "destination_masked",
17338
+ "state",
17339
+ "expires_in"
17340
+ ],
17341
+ "properties": {
17342
+ "status": {
17343
+ "type": "string",
17344
+ "enum": [
17345
+ "sent"
17346
+ ]
17347
+ },
17348
+ "destination_masked": {
17349
+ "type": "string"
17350
+ },
17351
+ "state": {
17352
+ "type": "string",
17353
+ "description": "Opaque handle to confirm with. It is what lets a tenant backend start the verification (M2M) and send the person to `/flow/verify-phone?state=…` without a session."
17354
+ },
17355
+ "expires_in": {
17356
+ "type": "integer"
17357
+ }
17358
+ }
17359
+ }
17360
+ }
17361
+ }
17362
+ }
17363
+ }
17364
+ }
17365
+ },
17223
17366
  "/user/{user_id}/factors": {
17224
17367
  "get": {
17225
17368
  "operationId": "user/factors",
@@ -32138,6 +32281,10 @@
32138
32281
  "description": "contact phone number",
32139
32282
  "nullable": true
32140
32283
  },
32284
+ "phone_e164": {
32285
+ "type": "boolean",
32286
+ "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."
32287
+ },
32141
32288
  "phone_verified": {
32142
32289
  "type": "boolean",
32143
32290
  "description": "phone is verified"