@onplo/sdk 0.0.0-stage → 0.0.1

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.
@@ -0,0 +1,2492 @@
1
+ export interface paths {
2
+ "/.well-known/openid-configuration": {
3
+ parameters: {
4
+ query?: never;
5
+ header?: never;
6
+ path?: never;
7
+ cookie?: never;
8
+ };
9
+ /**
10
+ * Read where the sign-in provider is and what it supports
11
+ * @description THE DISCOVERY DOCUMENT (OpenID Connect Discovery 1.0). Every Onplo app — web, desktop, phone,
12
+ * the command line and the agent connector — signs in through identity as an OpenID Connect client
13
+ * (architecture decision record 037), and reads this first: where to send a person to sign in,
14
+ * where to trade the answer for tokens, and where the keys are that check them.
15
+ *
16
+ * IT NAMES ONLY WHAT IS SUPPORTED: the authorization code with PKCE (`S256`), public clients that
17
+ * hold no secret, the `openid` scope, and ID tokens signed ES256. No implicit flow, no password
18
+ * grant and no device code (record 037, rule One).
19
+ *
20
+ * SIGNED OUT, because nobody is signed in yet when it is read, and LIMITED by how often it is
21
+ * called, never by who calls (decision 0732). It may be kept for five minutes.
22
+ */
23
+ get: operations["readProviderDiscovery"];
24
+ put?: never;
25
+ post?: never;
26
+ delete?: never;
27
+ options?: never;
28
+ head?: never;
29
+ patch?: never;
30
+ trace?: never;
31
+ };
32
+ "/.well-known/jwks.json": {
33
+ parameters: {
34
+ query?: never;
35
+ header?: never;
36
+ path?: never;
37
+ cookie?: never;
38
+ };
39
+ /**
40
+ * Read the public keys that check the provider's tokens
41
+ * @description THE KEY SET (RFC 7517): the public half of every key whose ID tokens may still be in a client's
42
+ * hands. A client checks an ID token's signature with the key its header names by `kid`.
43
+ *
44
+ * THE PRIVATE HALF NEVER LEAVES ONPLO'S KEY SERVICE: identity asks it to sign, and reads only the
45
+ * public half to publish here.
46
+ *
47
+ * ACROSS A ROTATION THERE ARE TWO: the key signing now, and the one before it, kept for at least a
48
+ * day after the change, so a token signed just before it is still checked. A `kid` is the key's own
49
+ * thumbprint (RFC 7638), so one id never names two keys.
50
+ *
51
+ * SIGNED OUT AND LIMITED, as the discovery document is. It may be kept for five minutes; a client
52
+ * that meets a `kid` it does not know reads it again.
53
+ */
54
+ get: operations["readProviderKeySet"];
55
+ put?: never;
56
+ post?: never;
57
+ delete?: never;
58
+ options?: never;
59
+ head?: never;
60
+ patch?: never;
61
+ trace?: never;
62
+ };
63
+ "/authorize": {
64
+ parameters: {
65
+ query?: never;
66
+ header?: never;
67
+ path?: never;
68
+ cookie?: never;
69
+ };
70
+ /**
71
+ * Send a person from an app to sign in
72
+ * @description THE AUTHORIZATION ENDPOINT (OpenID Connect Core §3.1.2, architecture decision record 037). An
73
+ * app sends the browser here with its request, and Onplo answers one of three ways:
74
+ *
75
+ * - TO THE SIGN-IN SCREEN, carrying the request, when the app, its return address and every
76
+ * field are ones Onplo takes. The screen asks for the passkey, then
77
+ * `grantAuthorizationCode` sends the browser back to the app with its code.
78
+ * - BACK TO THE APP'S REGISTERED ADDRESS WITH AN OAUTH `error` (RFC 6749 §4.1.2.1), and its
79
+ * `state`, when the app and its address are Onplo's but another field is not.
80
+ * - NOWHERE, AS A 400 `not_registered`, when the app or its return address is not one Onplo
81
+ * lists. A code or an error sent to an address nobody registered is how a sign-in is stolen.
82
+ *
83
+ * THE FIELDS ARE READ BY THE RULES OF `AuthorizationRequest`, not by the parameters' own bounds:
84
+ * each is optional here so that a wrong one is answered as OAuth answers it, never as a 422.
85
+ *
86
+ * SIGNED OUT, because nobody is signed in yet, and LIMITED by how often it is called (decision
87
+ * 0732). It writes nothing.
88
+ */
89
+ get: operations["authorizeSignIn"];
90
+ put?: never;
91
+ post?: never;
92
+ delete?: never;
93
+ options?: never;
94
+ head?: never;
95
+ patch?: never;
96
+ trace?: never;
97
+ };
98
+ "/passkey-proofs": {
99
+ parameters: {
100
+ query?: never;
101
+ header?: never;
102
+ path?: never;
103
+ cookie?: never;
104
+ };
105
+ get?: never;
106
+ put?: never;
107
+ /**
108
+ * Ask for the question a passkey answers
109
+ * @description THE FIRST HALF OF PROVING IT IS YOU. Onplo mints a ceremony and answers
110
+ * `request_options`: hand it to the browser's passkey API untouched, and the browser asks
111
+ * the person for their fingerprint, face or PIN.
112
+ *
113
+ * USER VERIFICATION IS REQUIRED, ALWAYS. A touch with no fingerprint and no PIN proves a
114
+ * device is present, not that the person is.
115
+ *
116
+ * BOUND TO THE SESSION THAT ASKED. The ceremony can be completed only with the same
117
+ * credential, so an answer lifted from one session proves nothing in another.
118
+ *
119
+ * SHORT-LIVED AND SINGLE USE. A person who walks away starts again; nothing has to be
120
+ * cancelled.
121
+ *
122
+ * A `POST` because every call mints a new ceremony. It takes no body: everything it needs is
123
+ * the credential.
124
+ *
125
+ * Not gated: proving it is you is not something a company grants or withholds.
126
+ */
127
+ post: operations["startPasskeyProof"];
128
+ delete?: never;
129
+ options?: never;
130
+ head?: never;
131
+ patch?: never;
132
+ trace?: never;
133
+ };
134
+ "/passkey-proofs/{passkey_proof_id}/completion": {
135
+ parameters: {
136
+ query?: never;
137
+ header?: never;
138
+ path: {
139
+ passkey_proof_id: components["parameters"]["PasskeyProofId"];
140
+ };
141
+ cookie?: never;
142
+ };
143
+ get?: never;
144
+ put?: never;
145
+ /**
146
+ * Bring the passkey's answer back
147
+ * @description THE SECOND HALF. Send what the browser's passkey API returned, untouched. Onplo checks
148
+ * that it answers the question this ceremony asked, on this site, signed by a passkey or
149
+ * security key this person holds, with the person verified.
150
+ *
151
+ * WHAT CHANGES IS ONE MOMENT. The session's `proved_at` becomes now — the moment every
152
+ * service holds against its own freshness window. The session itself is the same session:
153
+ * same credential, same reach, and whatever was on screen is still there.
154
+ *
155
+ * IT WIDENS NOTHING. A fresh proof is what reaching for more demands; it is never the
156
+ * reaching itself.
157
+ *
158
+ * ONE ANSWER PER CEREMONY. Completed, refused or expired, a ceremony is spent, and its id
159
+ * answers `not_found` from then on — as it does from any other session. The cases are not
160
+ * told apart, so nothing is learned by trying ids.
161
+ *
162
+ * A REFUSED ANSWER SAYS ONLY THAT IT WAS REFUSED — `passkey_not_verified`. A wrong
163
+ * signature, another site, no user verification, a passkey that is not this person's: saying
164
+ * which would teach somebody what to fix. Start a new ceremony.
165
+ *
166
+ * Not gated: proving it is you is not something a company grants or withholds.
167
+ */
168
+ post: operations["completePasskeyProof"];
169
+ delete?: never;
170
+ options?: never;
171
+ head?: never;
172
+ patch?: never;
173
+ trace?: never;
174
+ };
175
+ "/device-tokens": {
176
+ parameters: {
177
+ query?: never;
178
+ header?: never;
179
+ path?: never;
180
+ cookie?: never;
181
+ };
182
+ get?: never;
183
+ put?: never;
184
+ /**
185
+ * Trade a statement a device signed for a short-lived token
186
+ * @description HOW AN ENROLLED DEVICE GETS A CREDENTIAL. At enrolment a device was issued a certificate;
187
+ * its private half never leaves the device. Here the device proves it holds that half: it
188
+ * signs a short statement and is answered a token, which it then sends as
189
+ * `Authorization: Bearer` on its own calls like any other credential.
190
+ *
191
+ * THE STATEMENT IS A STANDARD ONE (decision 0647): a signed JSON Web Token as RFC 7523
192
+ * describes a client proving itself with its own key. `iss` and `sub` are both the device
193
+ * record's id; `aud` is the full address of this operation; `exp` is when it stops being
194
+ * good; `jti` is a value used once. Its header names the certificate by its SHA-256
195
+ * thumbprint (`x5t#S256`, RFC 7515). The device never sends the certificate itself: Onplo
196
+ * issued it and finds it by that thumbprint.
197
+ *
198
+ * GOOD FOR AT MOST FIVE MINUTES, AND FOR ONE USE. `exp` may be no more than five minutes
199
+ * ahead of Onplo's clock, and a `jti` is refused the second time. So a device signs a new
200
+ * statement at the moment it sends one — after a week asleep as well — and nothing signed
201
+ * earlier is worth keeping.
202
+ *
203
+ * WHAT THE TOKEN IS. It says which device record is calling, in which account environment,
204
+ * and nothing else. It lives at most an hour. It ends AT ONCE when the device's certificate
205
+ * ends — a retired or un-enrolled device is refused on its next call, not when the hour is
206
+ * up. It signs no person in and carries no permission: what a device may call is marked in
207
+ * each contract as an operation a device makes about itself.
208
+ *
209
+ * ONE KIND OF KEY IS CERTIFIED: an elliptic-curve key on the P-256 curve (decision 0963). So a
210
+ * statement is signed ES256, and one whose header names any other `alg` is not verified. A
211
+ * Mac's Secure Enclave and a TPM both make such a key, and it never leaves them.
212
+ *
213
+ * A CERTIFICATE IS VALID FOR 90 DAYS, AND IT IS RENEWED HERE. Every token answers when the
214
+ * certificate that signed its statement stops being valid. When 30 days or fewer are left,
215
+ * the device makes a NEW key pair and sends a certificate request for it beside its next
216
+ * statement; the answer carries the new certificate as well as the token. The old certificate
217
+ * stays in force until the first statement the new key signs is traded, and ends then. A
218
+ * device that lost that answer sends the same request again and is answered the same
219
+ * certificate. A device whose certificate ran out can no longer prove itself here: it is
220
+ * enrolled again.
221
+ *
222
+ * TWO REFUSALS, AND ONLY ONE SAYS WHY. `statement_not_verified` covers everything about WHO
223
+ * signed it — a certificate Onplo does not know, one that has ended, a signature that does
224
+ * not match, another audience, a `jti` already used. They are never told apart, so nothing
225
+ * is learned by trying, and a device cannot learn here that it was un-enrolled.
226
+ * `statement_outside_its_time` is told apart on purpose: a device with a wrong clock can do
227
+ * nothing with "not verified", and every answer's `Date` header carries Onplo's own time to
228
+ * set a statement by.
229
+ *
230
+ * A RENEWAL'S REFUSALS ARE TOLD APART, because the statement is judged first and has already
231
+ * proved the device by then. `certificate_request_unreadable`: no PKCS #10 request can be
232
+ * read from it. `certificate_request_not_signed_by_its_key`: its signature was not made by
233
+ * the key inside it. `key_not_certified`: the key is not a P-256 one. `key_ended`: a
234
+ * certificate for that key was ended, and such a key is never certified again.
235
+ * `key_already_certified`: the key signed this statement, or another device's certificate
236
+ * holds it.
237
+ *
238
+ * NO 401, NO 403 AND NO 503: it never asks who is calling, because the statement is the
239
+ * whole of the answer to that, so it refuses nobody for a credential and the service that
240
+ * would judge one is never asked. An `Authorization` header sent anyway is not read.
241
+ *
242
+ * A `POST` because every call mints a new token.
243
+ */
244
+ post: operations["tradeDeviceStatement"];
245
+ delete?: never;
246
+ options?: never;
247
+ head?: never;
248
+ patch?: never;
249
+ trace?: never;
250
+ };
251
+ "/environment-switches": {
252
+ parameters: {
253
+ query?: never;
254
+ header?: never;
255
+ path?: never;
256
+ cookie?: never;
257
+ };
258
+ get?: never;
259
+ put?: never;
260
+ /**
261
+ * Open a session in another environment you are a member of
262
+ * @description HOW A SIGNED-IN PERSON STEPS INTO ANOTHER COMPANY. A session acts in one environment, so a
263
+ * switch opens a NEW session in the one named, and answers its token once. The session that
264
+ * asked is not changed and not ended: switching back uses it while it lasts.
265
+ *
266
+ * ONLY A MEMBER, NOW. The person must be a member of that environment at the moment of
267
+ * asking, and not suspended there. An environment that does not exist and one the person is
268
+ * not a member of are refused alike, `not_a_member`, so nothing is learned by trying ids.
269
+ *
270
+ * A PASSKEY TOUCH FIRST, WHEN ONE IS NEEDED — `passkey_proof_needed`. Reaching an environment
271
+ * the sign-in left off needs a touch made in the last five minutes; an environment it chose
272
+ * needs only what the company's entering gate asks. Prove it is you on the session you have,
273
+ * with `startPasskeyProof` and `completePasskeyProof`, and send the switch again. Signing in
274
+ * does not record its chosen environments yet, so today every switch needs the touch.
275
+ *
276
+ * THE NEW SESSION carries the moment of the touch that opened it as its `proved_at`, and it
277
+ * ends no later than the session that asked.
278
+ *
279
+ * `503 authorization_unavailable` also when the company's entering gate could not be read:
280
+ * whether the switch may proceed is unknown, so it is refused, never let through.
281
+ *
282
+ * A `POST` because every call opens a new session.
283
+ *
284
+ * Not gated: stepping into a company you belong to is not something a role grants.
285
+ */
286
+ post: operations["switchEnvironment"];
287
+ delete?: never;
288
+ options?: never;
289
+ head?: never;
290
+ patch?: never;
291
+ trace?: never;
292
+ };
293
+ "/sign-ins": {
294
+ parameters: {
295
+ query?: never;
296
+ header?: never;
297
+ path?: never;
298
+ cookie?: never;
299
+ };
300
+ get?: never;
301
+ put?: never;
302
+ /**
303
+ * Ask for the question a passkey answers to sign in
304
+ * @description THE FIRST OF THREE CALLS THAT SIGN A PERSON IN. Onplo mints a sign-in and answers
305
+ * `request_options`: hand it to the browser's passkey API untouched, and the device shows the
306
+ * Onplo accounts it holds a passkey for. The person picks one and is verified by fingerprint,
307
+ * face or PIN.
308
+ *
309
+ * NOBODY IS NAMED, AND NO KEY IS LISTED. The call takes no body, so it cannot be asked about
310
+ * a username, and `allowCredentials` is always empty: every sign-in is put the same question,
311
+ * whoever is asking and whether or not an account exists (decision 0529). Nothing is learned
312
+ * by trying. A passkey and a security key alike are made to be found this way when they are
313
+ * registered (`startPasskeyRegistration`).
314
+ *
315
+ * A PERSON WHO TYPED A USERNAME sends it with the answer, and an answer from another
316
+ * person's passkey is refused exactly as a wrong passkey is.
317
+ *
318
+ * SHORT-LIVED AND SINGLE USE. A person who walks away starts again; nothing has to be
319
+ * cancelled.
320
+ *
321
+ * A `POST` because every call mints a new sign-in.
322
+ */
323
+ post: operations["startSignIn"];
324
+ delete?: never;
325
+ options?: never;
326
+ head?: never;
327
+ patch?: never;
328
+ trace?: never;
329
+ };
330
+ "/sign-ins/{sign_in_id}/completion": {
331
+ parameters: {
332
+ query?: never;
333
+ header?: never;
334
+ path: {
335
+ sign_in_id: components["parameters"]["SignInId"];
336
+ };
337
+ cookie?: never;
338
+ };
339
+ get?: never;
340
+ put?: never;
341
+ /**
342
+ * Bring the passkey's answer back, and see where you may go
343
+ * @description THE SECOND CALL. Send what the browser's passkey API returned, untouched. Onplo checks
344
+ * that it answers the question this sign-in asked, on this site, signed by a passkey or
345
+ * security key Onplo holds, with the person verified. Which person it is, is read from the
346
+ * answer's `userHandle`.
347
+ *
348
+ * WHAT IT ANSWERS IS A CHOICE, NOT A SESSION. The person has proved who they are and has not
349
+ * chosen where they go (Account → Sign in, step 4): the answer lists the environments they may
350
+ * choose (decision 0562) and a `sign_in_token`, good once and for minutes, that opens the
351
+ * session they choose (`openSignedInSession`). Nothing is signed in until then.
352
+ *
353
+ * WITH THE DEVICE'S OWN TOKEN, WHEN THE CLIENT HAS ONE. An enrolled device shows the token it
354
+ * traded for (`tradeDeviceStatement`) beside the answer, and the session this sign-in opens
355
+ * keeps that device (decision 0886): the passkey says who, the device says where. A token that
356
+ * is not a live device's is refused `device_token_not_verified`; send the answer again in a new
357
+ * sign-in without it, or with a fresh one.
358
+ *
359
+ * A REFUSED ANSWER SAYS ONLY THAT IT WAS REFUSED — `passkey_not_verified`. A wrong signature,
360
+ * another site, no user verification, an answer without a `userHandle`, a passkey Onplo does
361
+ * not hold, and a username that is not the passkey's are never told apart. The person sees
362
+ * "That did not work", whichever it was.
363
+ *
364
+ * ONE ANSWER PER SIGN-IN. Completed, refused or expired, a sign-in is spent, and its id
365
+ * answers `not_found` from then on. The cases are not told apart.
366
+ *
367
+ * `503` when the list of environments could not be read: nothing is answered, and the person
368
+ * starts again.
369
+ */
370
+ post: operations["completeSignIn"];
371
+ delete?: never;
372
+ options?: never;
373
+ head?: never;
374
+ patch?: never;
375
+ trace?: never;
376
+ };
377
+ "/sign-ins/{sign_in_id}/sessions": {
378
+ parameters: {
379
+ query?: never;
380
+ header?: never;
381
+ path: {
382
+ sign_in_id: components["parameters"]["SignInId"];
383
+ };
384
+ cookie?: never;
385
+ };
386
+ get?: never;
387
+ put?: never;
388
+ /**
389
+ * Open the session you chose
390
+ * @description THE THIRD CALL. Send the `sign_in_token` the completion answered, the environments the
391
+ * person chose, and the one they land in. Onplo opens ONE session, in that environment, and
392
+ * answers its token once.
393
+ *
394
+ * ONE SESSION, IN ONE ENVIRONMENT (decision 0798, rule 3). The other environments chosen are
395
+ * recorded on it: switching into one of them later (`switchEnvironment`) asks only the
396
+ * company's entering gate, while one left off asks a passkey touch first (decision 0873). So
397
+ * "Full access" is every choice sent here, and a session is still opened in only one.
398
+ *
399
+ * WHERE TO LAND is the client's to propose, from the sign-in page's rule: the Personal
400
+ * environment, or the most recently used Business one when Personal is off. It must be one of
401
+ * the environments chosen.
402
+ *
403
+ * THE SIGN-IN TOKEN IS GOOD ONCE. Used, expired, or not this sign-in's, it answers
404
+ * `not_found`, and the cases are not told apart.
405
+ *
406
+ * THE SESSION carries the moment of this sign-in's passkey touch as its `proved_at`, and the
407
+ * device shown at completion, if one was.
408
+ *
409
+ * A `POST` because it opens a session.
410
+ */
411
+ post: operations["openSignedInSession"];
412
+ delete?: never;
413
+ options?: never;
414
+ head?: never;
415
+ patch?: never;
416
+ trace?: never;
417
+ };
418
+ "/sign-ins/{sign_in_id}/authorization-codes": {
419
+ parameters: {
420
+ query?: never;
421
+ header?: never;
422
+ path: {
423
+ sign_in_id: components["parameters"]["SignInId"];
424
+ };
425
+ cookie?: never;
426
+ };
427
+ get?: never;
428
+ put?: never;
429
+ /**
430
+ * Send the person back to the app they came from, with its one code
431
+ * @description THE THIRD CALL, FOR AN APP SIGNING IN THROUGH SINGLE SIGN-ON (architecture decision record
432
+ * 037). It takes the place `openSignedInSession` has when the sign-in screen signs itself in:
433
+ * where that opens a session and hands its token to the screen, this keeps a one-time code for
434
+ * the app the person was sent from, and answers the address to send the browser to, back to
435
+ * that app with the code.
436
+ *
437
+ * SEND what `openSignedInSession` takes, the `sign_in_token`, the environments chosen and the
438
+ * one to land in, and beside them the app's request exactly as it arrived at the
439
+ * authorization endpoint. Onplo reads the request again by the same rules, because the screen
440
+ * carried it and nothing it carries is trusted.
441
+ *
442
+ * THE CODE is good once, for one minute, and only for the app it names, at the exact return
443
+ * address it names, with the PKCE verifier that matches its challenge. The app trades it for
444
+ * the session at the token endpoint. Only its hash is kept.
445
+ *
446
+ * THE SIGN-IN TOKEN IS GOOD ONCE. Used, expired, or not this sign-in's, it answers
447
+ * `not_found`, and the cases are not told apart. One sign-in token hands out one code.
448
+ *
449
+ * A `POST` because it keeps a code.
450
+ */
451
+ post: operations["grantAuthorizationCode"];
452
+ delete?: never;
453
+ options?: never;
454
+ head?: never;
455
+ patch?: never;
456
+ trace?: never;
457
+ };
458
+ "/passkey-registrations": {
459
+ parameters: {
460
+ query?: never;
461
+ header?: never;
462
+ path?: never;
463
+ cookie?: never;
464
+ };
465
+ get?: never;
466
+ put?: never;
467
+ /**
468
+ * Ask for the question a new passkey answers
469
+ * @description THE FIRST HALF OF ADDING A PASSKEY OR A SECURITY KEY, for a person already signed in
470
+ * (Account → Settings → Security → Sign-in methods). Onplo mints a registration and answers
471
+ * `creation_options`: hand it to the browser's passkey API untouched, and the device makes a
472
+ * new key for this person on `onplo.com`.
473
+ *
474
+ * A PASSKEY TOUCH FIRST: ONE MADE IN THE LAST FIVE MINUTES — `passkey_proof_needed`. A new way
475
+ * in is the most sensitive thing a session can add, so the person proves it is them on the
476
+ * session they have (`startPasskeyProof`, `completePasskeyProof`) and asks again. Right after
477
+ * signing in, that proof is already fresh.
478
+ *
479
+ * EVERY KEY IS MADE TO BE FOUND WITHOUT A USERNAME (`residentKey: required`), so signing in
480
+ * never has to list anyone's keys (`startSignIn`). The keys this person already holds are
481
+ * listed in `excludeCredentials`, so the same key is not added twice.
482
+ *
483
+ * BOUND TO THE SESSION THAT ASKED, SHORT-LIVED AND SINGLE USE, as a proof is.
484
+ *
485
+ * A `POST` because every call mints a new registration. It takes no body: everything it needs
486
+ * is the credential.
487
+ *
488
+ * GATED BY `account:sign-in-method.create`, the catalogue's act of adding a passkey or a security
489
+ * key (ring 1, a personal environment's): a key or an agent never holds it.
490
+ */
491
+ post: operations["startPasskeyRegistration"];
492
+ delete?: never;
493
+ options?: never;
494
+ head?: never;
495
+ patch?: never;
496
+ trace?: never;
497
+ };
498
+ "/passkey-registrations/{passkey_registration_id}/completion": {
499
+ parameters: {
500
+ query?: never;
501
+ header?: never;
502
+ path: {
503
+ passkey_registration_id: components["parameters"]["PasskeyRegistrationId"];
504
+ };
505
+ cookie?: never;
506
+ };
507
+ get?: never;
508
+ put?: never;
509
+ /**
510
+ * Bring the new key back, and keep it
511
+ * @description THE SECOND HALF. Send what the browser's passkey API returned, untouched, and the name the
512
+ * person gives the key. Onplo checks that it answers the question this registration asked, on
513
+ * this site, from a key that verified the person and can be found without a username, and
514
+ * keeps it as one of the person's sign-in methods.
515
+ *
516
+ * WHAT IS KEPT is the key's public half and how to reach it; its private half never leaves the
517
+ * device. The key is listed in Account → Settings → Security → Sign-in methods from then on,
518
+ * where it can be renamed, made Primary or removed.
519
+ *
520
+ * NO ATTESTATION IS ASKED FOR (`attestation: none`). Onplo does not judge which maker built a
521
+ * key, only that the person holds it and was verified by it.
522
+ *
523
+ * ONE ANSWER PER REGISTRATION. Completed, refused or expired, it is spent, and its id answers
524
+ * `not_found` from then on — as it does from any other session.
525
+ *
526
+ * A REFUSED KEY SAYS ONLY THAT IT WAS REFUSED — `passkey_not_verified`, as a proof's refusal
527
+ * does. `already_registered` is told apart: the person already holds this very key, and a
528
+ * client says so rather than "try again".
529
+ *
530
+ * A `POST` because it adds a sign-in method, which has its own id.
531
+ *
532
+ * GATED BY `account:sign-in-method.create`, the catalogue's act of adding a passkey or a security
533
+ * key (ring 1, a personal environment's): a key or an agent never holds it.
534
+ */
535
+ post: operations["completePasskeyRegistration"];
536
+ delete?: never;
537
+ options?: never;
538
+ head?: never;
539
+ patch?: never;
540
+ trace?: never;
541
+ };
542
+ "/username-checks": {
543
+ parameters: {
544
+ query?: never;
545
+ header?: never;
546
+ path?: never;
547
+ cookie?: never;
548
+ };
549
+ get?: never;
550
+ put?: never;
551
+ /**
552
+ * Ask whether a username may be chosen
553
+ * @description THE CHECK AS YOU TYPE, on the first screen of signing up (Account → Sign up, step 1). Send the
554
+ * username being typed; Onplo answers whether it may be chosen now.
555
+ *
556
+ * ONE ANSWER FOR EVERY NAME THAT MAY NOT BE CHOSEN: somebody holds it, or somebody gave it up
557
+ * less than 90 days ago, or it is reserved. Which of them is never said, because it says
558
+ * something about a person the one signing up has never met (Account's `RegisterPerson`).
559
+ *
560
+ * WHY THIS DOES NOT UNDO SIGN-IN'S RULE. Signing in never says whether a username exists
561
+ * (decision 0529). Signing up must, at the moment a name is chosen, and says only "may be chosen"
562
+ * or "may not", from the same list `RegisterPerson` judges. It is limited per address by the
563
+ * gate, as every signed-out call is.
564
+ *
565
+ * ADVICE, NEVER A HOLD. Nothing is reserved by asking: the name is judged again when the sign-up
566
+ * finishes, and another person may have taken it in between.
567
+ *
568
+ * A `POST` so the name travels in the body and never in a URL a log keeps.
569
+ *
570
+ * `503` when Account, which knows the list, could not be asked: nothing was judged, and the check
571
+ * may be tried again.
572
+ */
573
+ post: operations["checkUsername"];
574
+ delete?: never;
575
+ options?: never;
576
+ head?: never;
577
+ patch?: never;
578
+ trace?: never;
579
+ };
580
+ "/sign-ups": {
581
+ parameters: {
582
+ query?: never;
583
+ header?: never;
584
+ path?: never;
585
+ cookie?: never;
586
+ };
587
+ get?: never;
588
+ put?: never;
589
+ /**
590
+ * Start signing up, and get the question the first passkey answers
591
+ * @description THE FIRST OF TWO CALLS THAT MAKE AN ONPLO ACCOUNT (Account → Sign up). Send the username and
592
+ * the facts Account records about the person; Onplo mints a sign-up and answers
593
+ * `creation_options`: hand it to the browser's passkey API untouched, and the device makes the
594
+ * person's first passkey, or a security key does.
595
+ *
596
+ * THE USERNAME IS JUDGED HERE, as `checkUsername` judges it, and again when the sign-up finishes.
597
+ * `username_not_available` here means pick another.
598
+ *
599
+ * THE EMAIL ADDRESS IS ASKED, NOT REQUIRED, AND IS NEVER A WAY IN (decisions 0198 and 0935). When
600
+ * sent it is recorded as the person's own and mailed its confirmation link; it may be left out.
601
+ * Nothing signs in by it.
602
+ *
603
+ * AN INVITED GUEST SIGNS UP THE SAME WAY. An invitation is accepted afterwards, from the
604
+ * person's own Companies → Requests, by somebody who holds the invited address confirmed
605
+ * (Account's rule, ONPLO-1694). A sign-up carries no invitation, so a forwarded mail lets nobody
606
+ * in.
607
+ *
608
+ * SHORT-LIVED AND SINGLE USE, as a sign-in is. Nothing is recorded anywhere until the sign-up
609
+ * finishes: a person who walks away leaves no account behind.
610
+ *
611
+ * `503` when Account, which judges the username, could not be asked: no sign-up was minted, and
612
+ * the call may be tried again.
613
+ */
614
+ post: operations["startSignUp"];
615
+ delete?: never;
616
+ options?: never;
617
+ head?: never;
618
+ patch?: never;
619
+ trace?: never;
620
+ };
621
+ "/sign-ups/{sign_up_id}/completion": {
622
+ parameters: {
623
+ query?: never;
624
+ header?: never;
625
+ path: {
626
+ sign_up_id: components["parameters"]["SignUpId"];
627
+ };
628
+ cookie?: never;
629
+ };
630
+ get?: never;
631
+ put?: never;
632
+ /**
633
+ * Bring the first passkey back, and get the recovery codes and the first session
634
+ * @description THE SECOND CALL. Send what the browser's passkey API returned, untouched, and the name the
635
+ * person gives the key. Onplo checks it as `completePasskeyRegistration` checks a new key, and
636
+ * then, in one act: keeps the key, has Account record the person, their personal environment
637
+ * and its one membership (`RegisterPerson`), mints the person's recovery codes, and opens their
638
+ * first session there.
639
+ *
640
+ * THE RECOVERY CODES ARE SHOWN ONCE, HERE, AND NEVER AGAIN. They are the only way back for a
641
+ * person who loses every passkey (Account → Sign up, step 3). Onplo keeps none of them in the
642
+ * clear, so nobody can show them a second time. They are not yet counted as a way in: the
643
+ * person says they kept them, on Settings → Security (decision 0614).
644
+ *
645
+ * THE SESSION LANDS IN THE PERSONAL ENVIRONMENT, the only one the person has (step 5). Its
646
+ * `proved_at` is the moment of this passkey touch.
647
+ *
648
+ * ONE ANSWER PER SIGN-UP. Completed, refused or expired, a sign-up is spent, and its id answers
649
+ * `not_found` from then on.
650
+ *
651
+ * `username_not_available` when somebody took the name since the sign-up started: nothing was
652
+ * recorded, and the person starts again with another.
653
+ *
654
+ * `503` when Account could not be asked to record the person: the sign-up is not spent, no codes
655
+ * were minted, and the same answer may be sent again until the sign-up expires.
656
+ */
657
+ post: operations["completeSignUp"];
658
+ delete?: never;
659
+ options?: never;
660
+ head?: never;
661
+ patch?: never;
662
+ trace?: never;
663
+ };
664
+ "/recoveries": {
665
+ parameters: {
666
+ query?: never;
667
+ header?: never;
668
+ path?: never;
669
+ cookie?: never;
670
+ };
671
+ get?: never;
672
+ put?: never;
673
+ /**
674
+ * Use a recovery code, and get the question a new passkey answers
675
+ * @description THE EMERGENCY DOOR, for a person who lost every passkey (Account → Sign in → Choose another
676
+ * sign-in method → Recovery code). Send the username and one recovery code. Onplo spends the code
677
+ * and answers `creation_options` for a new passkey: using a code requires registering a new
678
+ * passkey, which becomes the Primary one (Account → Settings → Security).
679
+ *
680
+ * A REFUSED CODE SAYS ONLY THAT IT WAS REFUSED — `recovery_not_verified`. An unknown username, a
681
+ * wrong code and a code already used are never told apart, so trying says nothing about whether
682
+ * an account exists (decision 0529).
683
+ *
684
+ * A CODE IS SPENT WHEN IT IS ACCEPTED HERE, whether or not the new passkey is then made. A person
685
+ * who walks away uses another code next time. The person's other codes stay good.
686
+ *
687
+ * USING A CODE RAISES A SECURITY ALERT to the person, so somebody who used a stolen code is seen
688
+ * (Account, "Recovery codes & sessions").
689
+ *
690
+ * SHORT-LIVED AND SINGLE USE, as a sign-in is.
691
+ */
692
+ post: operations["startRecovery"];
693
+ delete?: never;
694
+ options?: never;
695
+ head?: never;
696
+ patch?: never;
697
+ trace?: never;
698
+ };
699
+ "/recoveries/{recovery_id}/completion": {
700
+ parameters: {
701
+ query?: never;
702
+ header?: never;
703
+ path: {
704
+ recovery_id: components["parameters"]["RecoveryId"];
705
+ };
706
+ cookie?: never;
707
+ };
708
+ get?: never;
709
+ put?: never;
710
+ /**
711
+ * Bring the new passkey back, and see where you may go
712
+ * @description THE SECOND CALL. Send what the browser's passkey API returned, untouched, and the name the
713
+ * person gives the key. Onplo checks it as `completePasskeyRegistration` checks a new key, keeps
714
+ * it as the person's Primary passkey, and answers as `completeSignIn` does: the environments the
715
+ * person may choose and a `sign_in_token` that opens one session. A RECOVERY IS A SIGN-IN THAT
716
+ * BEGAN WITH A CODE: open the session with `openSignedInSession`, naming this recovery's id as
717
+ * its `sign_in_id`.
718
+ *
719
+ * ONE ANSWER PER RECOVERY. Completed, refused or expired, a recovery is spent, and its id answers
720
+ * `not_found` from then on.
721
+ *
722
+ * `503` when the list of environments could not be read: the key is kept, and the person signs in
723
+ * with it.
724
+ */
725
+ post: operations["completeRecovery"];
726
+ delete?: never;
727
+ options?: never;
728
+ head?: never;
729
+ patch?: never;
730
+ trace?: never;
731
+ };
732
+ }
733
+ export type webhooks = Record<string, never>;
734
+ export interface components {
735
+ schemas: {
736
+ /**
737
+ * Format: uuid
738
+ * @description A UUID version 7 (RFC 9562) — sortable by creation, and never a counter.
739
+ * @example 019250e1-8f3c-7c21-9a4d-3a2f7b6c1d90
740
+ */
741
+ Id: string;
742
+ /**
743
+ * @description ONE CEREMONY: the question to put to a passkey, and until when an answer is taken. Single
744
+ * use, and only the session that asked can complete it.
745
+ */
746
+ PasskeyProof: {
747
+ /** @description What the completion names. */
748
+ id: components["schemas"]["Id"];
749
+ request_options: components["schemas"]["PasskeyRequestOptions"];
750
+ /** @description When the ceremony dies. Seconds to minutes; after it, start again. */
751
+ expires_at: components["schemas"]["Timestamp"];
752
+ };
753
+ /**
754
+ * @description WHAT THE BROWSER HANDS THE PASSKEY — the JSON form of the standard's request options, in the
755
+ * standard's own field names (see the note at the top of this document). Pass it to the
756
+ * browser's passkey API untouched.
757
+ */
758
+ PasskeyRequestOptions: {
759
+ /** @description Random bytes minted for this ceremony. The passkey signs them, so an old answer cannot be replayed. */
760
+ challenge: string;
761
+ /** @description A hint, in milliseconds, for how long the browser waits for the person. `expires_at` is what binds. */
762
+ timeout?: number;
763
+ /**
764
+ * @description The site the passkey belongs to, always `onplo.com` (decision 0728): the registrable
765
+ * domain and never the host the product is served from, so a passkey made once answers on every
766
+ * Onplo site and none outside them. It never changes, because a new one strands every passkey
767
+ * made under the old. A passkey made for another site cannot answer.
768
+ */
769
+ rpId: string;
770
+ /**
771
+ * @description The passkeys and security keys this person holds, so the browser offers theirs and no
772
+ * one else's.
773
+ */
774
+ allowCredentials: {
775
+ id: string;
776
+ /** @enum {string} */
777
+ type: "public-key";
778
+ /** @description How that key was last reached — a hint the browser uses to look in the right place. */
779
+ transports?: string[];
780
+ }[];
781
+ /**
782
+ * @description Always `required`. The person is verified, not merely present.
783
+ * @enum {string}
784
+ */
785
+ userVerification: "required";
786
+ };
787
+ PasskeyProofCompletion: {
788
+ answer: components["schemas"]["PasskeyAnswer"];
789
+ };
790
+ /**
791
+ * @description WHAT THE BROWSER'S PASSKEY API RETURNED — the JSON form of the standard's authentication
792
+ * response, in the standard's own field names. Send it untouched.
793
+ */
794
+ PasskeyAnswer: {
795
+ /** @description Which passkey or security key answered. */
796
+ id: string;
797
+ /** @description The same, as the standard repeats it. */
798
+ rawId: string;
799
+ /** @enum {string} */
800
+ type: "public-key";
801
+ /**
802
+ * @description Whether the key is part of this device or was reached from another.
803
+ * @enum {string}
804
+ */
805
+ authenticatorAttachment?: "platform" | "cross-platform";
806
+ response: {
807
+ /**
808
+ * @description What the browser says it asked — the challenge and the page it asked from. The page's
809
+ * origin must be one identity lists, `https://app.onplo.com` at launch, or the answer is
810
+ * refused, whatever the passkey signed: any page under `onplo.com` may ask a passkey, and the
811
+ * list is what keeps a page that is not ours from completing a sign-in (decision 0728).
812
+ */
813
+ clientDataJSON: string;
814
+ /** @description What the key says about itself — the site it is for, and that the person was verified. */
815
+ authenticatorData: string;
816
+ signature: string;
817
+ /** @description Whose passkey this is, as the key recorded it. Left out by a key that does not keep one. */
818
+ userHandle?: string;
819
+ };
820
+ /**
821
+ * @description Always present in the standard's form, and always empty here: this API asks for no
822
+ * extension, so an answer carrying one is not an answer to its question.
823
+ */
824
+ clientExtensionResults: Record<string, never>;
825
+ };
826
+ /** @description What a completed proof leaves behind. */
827
+ SessionProof: {
828
+ /**
829
+ * @description When this session last proved itself — now. The same moment every service holds
830
+ * against its own freshness window.
831
+ */
832
+ proved_at: components["schemas"]["Timestamp"];
833
+ };
834
+ /**
835
+ * @description WHAT A DEVICE SENDS AS ITS CREDENTIAL, and until when. Opaque: a device stores it, sends
836
+ * it, and never reads it.
837
+ */
838
+ DeviceToken: {
839
+ /**
840
+ * @description The credential. Sent as `Authorization: Bearer` on the device's own calls. Never a
841
+ * token a client can decode: what it means is asked of Onplo on every call.
842
+ */
843
+ token: string;
844
+ /**
845
+ * @description When the token stops being good by itself — at most an hour from now. It may stop
846
+ * sooner: it ends with the device's certificate, at once.
847
+ */
848
+ expires_at: components["schemas"]["Timestamp"];
849
+ /**
850
+ * @description When the certificate that signed this statement stops being valid by itself, 90 days
851
+ * after it was issued. With 30 days or fewer left, the device sends a renewal.
852
+ */
853
+ certificate_expires_at: components["schemas"]["Timestamp"];
854
+ /**
855
+ * @description Only on an answer to a renewal: the certificate for the new key. It comes into force
856
+ * when the first statement the new key signs is traded.
857
+ */
858
+ renewed_certificate?: components["schemas"]["RenewedDeviceCertificate"];
859
+ };
860
+ /**
861
+ * @description A DEVICE'S NEXT CERTIFICATE, and what signed it. Public, every part of it: a certificate
862
+ * authority's key never leaves a managed KMS (architecture decision record 030).
863
+ */
864
+ RenewedDeviceCertificate: {
865
+ /**
866
+ * @description The certificate, X.509 in DER, written base64url with no padding. It names the device
867
+ * record and its environment, as the one it follows did.
868
+ */
869
+ certificate: string;
870
+ /**
871
+ * @description What signed it, the certificate's own issuer first — each X.509 in DER, written
872
+ * base64url with no padding.
873
+ */
874
+ authority_certificates: string[];
875
+ /** @description When the new certificate stops being valid by itself, 90 days after it was issued. */
876
+ expires_at: components["schemas"]["Timestamp"];
877
+ };
878
+ /**
879
+ * @description THE SESSION A SWITCH OPENED. Opaque, like every token here: a client stores it, sends it,
880
+ * and never reads it.
881
+ */
882
+ SwitchedSession: {
883
+ /**
884
+ * @description The new session's credential, shown this once. Sent as `Authorization: Bearer` on every
885
+ * call made in the environment switched into.
886
+ */
887
+ token: string;
888
+ /** @description The account environment this session acts in — the one the switch named. */
889
+ environment_id: components["schemas"]["Id"];
890
+ /**
891
+ * @description When this session stops being good by itself: never later than the session that asked
892
+ * for it.
893
+ */
894
+ expires_at: components["schemas"]["Timestamp"];
895
+ /**
896
+ * @description The moment of the passkey touch that opened this session — the one the asking session
897
+ * carried.
898
+ */
899
+ proved_at: components["schemas"]["Timestamp"];
900
+ };
901
+ /** @description ONE SIGN-IN: the question to put to a passkey, and until when an answer is taken. Single use. */
902
+ SignIn: {
903
+ /** @description What the completion and the session's opening name. */
904
+ id: components["schemas"]["Id"];
905
+ /**
906
+ * @description With `allowCredentials` always empty: the person is not known yet, and the device offers
907
+ * every Onplo key it holds.
908
+ */
909
+ request_options: components["schemas"]["PasskeyRequestOptions"];
910
+ /** @description When the sign-in dies. Seconds to minutes; after it, start again. */
911
+ expires_at: components["schemas"]["Timestamp"];
912
+ };
913
+ SignInCompletion: {
914
+ answer: components["schemas"]["PasskeyAnswer"];
915
+ /**
916
+ * @description The username the person typed, when they typed one — Account's `Username`, lower case
917
+ * (decision 0561). The answer must come from that person's key, or it is refused as a
918
+ * wrong passkey is. Left out when the person picked their account on the device.
919
+ */
920
+ username?: string;
921
+ /**
922
+ * @description The token this device traded for (`DeviceToken.token`), when the client runs on an
923
+ * enrolled device. It proves which device the person is on, never who they are (decisions
924
+ * 0644 and 0886).
925
+ */
926
+ device_token?: string;
927
+ };
928
+ /**
929
+ * @description WHERE A PERSON WHO HAS JUST PROVED THEMSELVES MAY GO, and the token that opens one session.
930
+ * The list is the person's own (decision 0562): which environments they belong to, each one's
931
+ * kind and name, and their state there — never anything inside one.
932
+ */
933
+ SignInChoices: {
934
+ /**
935
+ * @description Good once, and until `expires_at`, for opening this sign-in's session
936
+ * (`openSignedInSession`). It is not a session and opens nothing else.
937
+ */
938
+ sign_in_token: string;
939
+ /** @description When the sign-in token dies. Minutes; after it, sign in again. */
940
+ expires_at: components["schemas"]["Timestamp"];
941
+ /** @description The moment of the passkey touch — the `proved_at` the session will carry. */
942
+ proved_at: components["schemas"]["Timestamp"];
943
+ /**
944
+ * @description EVERY ENVIRONMENT THE PERSON MAY CHOOSE, WHOLE — never a page, because the chooser shows
945
+ * them all on one screen with one "Full access" toggle. Personal first, then Business, then
946
+ * the Onplo team, and oldest first within a kind. A membership the person left is never
947
+ * here; a suspended one is, so the chooser can say access is paused.
948
+ */
949
+ choices: components["schemas"]["SignInChoice"][];
950
+ };
951
+ SignInChoice: {
952
+ /** @description The account environment. */
953
+ environment_id: components["schemas"]["Id"];
954
+ /**
955
+ * @description Which kind of environment it is.
956
+ * @enum {string}
957
+ */
958
+ kind: "personal" | "business" | "onplo";
959
+ /**
960
+ * @description A company's name. Absent exactly when `kind` is `personal`: the client names a personal
961
+ * environment from its kind, in the reader's language.
962
+ */
963
+ name?: string;
964
+ /**
965
+ * @description The person's state there. A suspended membership can be seen and not landed in.
966
+ * @enum {string}
967
+ */
968
+ membership_state: "active" | "suspended";
969
+ };
970
+ SignedInSessionOpening: {
971
+ /** @description The token the completion answered. */
972
+ sign_in_token: string;
973
+ /**
974
+ * @description THE ENVIRONMENTS THE PERSON CHOSE for this sign-in, each one of the completion's
975
+ * choices, each named once. "Full access" sends them all. Switching into one of these later asks no passkey
976
+ * touch; one left out does.
977
+ */
978
+ environment_ids: components["schemas"]["Id"][];
979
+ /** @description The one of them the session acts in. */
980
+ land_in: components["schemas"]["Id"];
981
+ };
982
+ AuthorizationCodeGrant: {
983
+ /** @description The token the completion answered. */
984
+ sign_in_token: string;
985
+ /** @description The environments the person chose, each one of the completion's choices, each named once. */
986
+ environment_ids: components["schemas"]["Id"][];
987
+ /** @description The one of them the app's session will act in. */
988
+ land_in: components["schemas"]["Id"];
989
+ authorization_request: components["schemas"]["AuthorizationRequest"];
990
+ };
991
+ /**
992
+ * @description THE APP'S REQUEST, field for field as it arrived at the authorization endpoint (RFC 6749
993
+ * §4.1.1, RFC 7636 §4.3, OpenID Connect Core §3.1.2.1).
994
+ */
995
+ AuthorizationRequest: {
996
+ /** @description The app, by the id Onplo lists it under. */
997
+ client_id: string;
998
+ /** @description Where the app is sent back to, exactly as it registered it. */
999
+ redirect_uri: string;
1000
+ /**
1001
+ * @description Always `code`, the authorization code.
1002
+ * @enum {string}
1003
+ */
1004
+ response_type: "code";
1005
+ /** @description The scopes asked, space-separated. `openid` is always one of them. */
1006
+ scope: string;
1007
+ /** @description The app's own value, sent back to it beside the code. */
1008
+ state: string;
1009
+ /** @description The PKCE challenge, the SHA-256 of the app's verifier in base64url. */
1010
+ code_challenge: string;
1011
+ /**
1012
+ * @description Always `S256`.
1013
+ * @enum {string}
1014
+ */
1015
+ code_challenge_method: "S256";
1016
+ /** @description The app's value the ID token echoes, when it sent one. */
1017
+ nonce?: string;
1018
+ };
1019
+ AuthorizationCodeGranted: {
1020
+ /**
1021
+ * Format: uri
1022
+ * @description The app's return address with `code` and `state` added. The screen sends the browser
1023
+ * there at once; the code in it is good for one minute.
1024
+ */
1025
+ redirect_to: string;
1026
+ };
1027
+ /**
1028
+ * @description THE SESSION A SIGN-IN OPENED. Opaque, like every token here: a client stores it, sends it,
1029
+ * and never reads it.
1030
+ */
1031
+ SignedInSession: {
1032
+ /**
1033
+ * @description The session's credential, shown this once. Sent as `Authorization: Bearer` on every call
1034
+ * made in the environment it acts in.
1035
+ */
1036
+ token: string;
1037
+ /** @description The account environment this session acts in — `land_in`. */
1038
+ environment_id: components["schemas"]["Id"];
1039
+ /** @description When this session stops being good by itself. */
1040
+ expires_at: components["schemas"]["Timestamp"];
1041
+ /** @description The moment of the passkey touch that signed the person in. */
1042
+ proved_at: components["schemas"]["Timestamp"];
1043
+ };
1044
+ /**
1045
+ * @description ONE REGISTRATION: the question a new key answers, and until when an answer is taken. Single
1046
+ * use, and only the session that asked can complete it.
1047
+ */
1048
+ PasskeyRegistration: {
1049
+ /** @description What the completion names. */
1050
+ id: components["schemas"]["Id"];
1051
+ creation_options: components["schemas"]["PasskeyCreationOptions"];
1052
+ /** @description When the registration dies. Seconds to minutes; after it, start again. */
1053
+ expires_at: components["schemas"]["Timestamp"];
1054
+ };
1055
+ /**
1056
+ * @description WHAT THE BROWSER HANDS THE DEVICE TO MAKE A NEW KEY — the JSON form of the standard's
1057
+ * creation options, in the standard's own field names (see the note at the top of this
1058
+ * document). Pass it to the browser's passkey API untouched.
1059
+ */
1060
+ PasskeyCreationOptions: {
1061
+ rp: {
1062
+ /** @description Always `onplo.com` (decision 0728), as `PasskeyRequestOptions.rpId` is. */
1063
+ id: string;
1064
+ /** @description What the device shows the key as being for — `Onplo`. */
1065
+ name: string;
1066
+ };
1067
+ user: {
1068
+ /**
1069
+ * @description The person, as the key records them and hands back as `userHandle` at every sign-in.
1070
+ * Opaque bytes that name nobody outside Onplo.
1071
+ */
1072
+ id: string;
1073
+ /** @description The person's username, so the device can tell their keys apart. */
1074
+ name: string;
1075
+ /** @description The person's name, as the device shows it. */
1076
+ displayName: string;
1077
+ };
1078
+ /** @description Random bytes minted for this registration. The new key signs them. */
1079
+ challenge: string;
1080
+ /** @description The signature kinds Onplo accepts, most preferred first. */
1081
+ pubKeyCredParams: {
1082
+ /** @enum {string} */
1083
+ type: "public-key";
1084
+ /** @description A COSE algorithm number — `-8` EdDSA, `-7` ES256, `-257` RS256. */
1085
+ alg: number;
1086
+ }[];
1087
+ /** @description A hint, in milliseconds, for how long the browser waits for the person. `expires_at` is what binds. */
1088
+ timeout?: number;
1089
+ /** @description The keys this person already holds, so the device does not add one twice. */
1090
+ excludeCredentials: {
1091
+ id: string;
1092
+ /** @enum {string} */
1093
+ type: "public-key";
1094
+ transports?: string[];
1095
+ }[];
1096
+ authenticatorSelection: {
1097
+ /**
1098
+ * @description Always `required`: the key keeps who it is for, so signing in finds it without a
1099
+ * username and never lists anyone's keys.
1100
+ * @enum {string}
1101
+ */
1102
+ residentKey: "required";
1103
+ /**
1104
+ * @description Always `required`. The person is verified, not merely present.
1105
+ * @enum {string}
1106
+ */
1107
+ userVerification: "required";
1108
+ };
1109
+ /**
1110
+ * @description Always `none`. Onplo does not judge which maker built a key.
1111
+ * @enum {string}
1112
+ */
1113
+ attestation: "none";
1114
+ };
1115
+ PasskeyRegistrationCompletion: {
1116
+ attestation: components["schemas"]["PasskeyAttestation"];
1117
+ /**
1118
+ * @description What the person calls this key in their list of sign-in methods — Account's
1119
+ * `SignInMethod.name`, renamed there later.
1120
+ */
1121
+ name: string;
1122
+ };
1123
+ /**
1124
+ * @description WHAT THE BROWSER'S PASSKEY API RETURNED WHEN IT MADE THE KEY — the JSON form of the
1125
+ * standard's registration response, in the standard's own field names. Send it untouched.
1126
+ */
1127
+ PasskeyAttestation: {
1128
+ /** @description The new key's id. */
1129
+ id: string;
1130
+ /** @description The same, as the standard repeats it. */
1131
+ rawId: string;
1132
+ /** @enum {string} */
1133
+ type: "public-key";
1134
+ /**
1135
+ * @description Whether the key is part of this device or was reached from another.
1136
+ * @enum {string}
1137
+ */
1138
+ authenticatorAttachment?: "platform" | "cross-platform";
1139
+ response: {
1140
+ /**
1141
+ * @description What the browser says it asked — the challenge and the page it asked from, which must
1142
+ * be one identity lists, as for a sign-in (decision 0728).
1143
+ */
1144
+ clientDataJSON: string;
1145
+ /** @description The new key's public half and what the key says about itself. */
1146
+ attestationObject: string;
1147
+ /** @description How the key can be reached, kept so the browser looks in the right place. */
1148
+ transports?: string[];
1149
+ };
1150
+ /** @description Always empty, because this API asks for no extension. */
1151
+ clientExtensionResults: Record<string, never>;
1152
+ };
1153
+ /** @description THE KEY JUST KEPT, by the id Account's list of sign-in methods names it with. */
1154
+ AddedSignInMethod: {
1155
+ /** @description The sign-in method's id — `SignInMethod.id` in Account's list. */
1156
+ id: components["schemas"]["Id"];
1157
+ /** @description The name it was given. */
1158
+ name: string;
1159
+ /** @description When it was kept. */
1160
+ added_at: components["schemas"]["Timestamp"];
1161
+ };
1162
+ /**
1163
+ * @description A person's one identifier, lower case — Account's `Username` (decision 0561). The client lowers
1164
+ * what the person types before sending it.
1165
+ */
1166
+ Username: string;
1167
+ UsernameCheck: {
1168
+ username: components["schemas"]["Username"];
1169
+ };
1170
+ UsernameAvailability: {
1171
+ /**
1172
+ * @description Whether the name may be chosen now. False for a name somebody holds, gave up less than 90
1173
+ * days ago, or that is reserved — never which. Advice, never a hold.
1174
+ */
1175
+ available: boolean;
1176
+ };
1177
+ /**
1178
+ * @description WHAT ACCOUNT RECORDS ABOUT A NEW PERSON (`RegisterPerson`), asked on the sign-up screens and
1179
+ * held by identity until the sign-up finishes.
1180
+ *
1181
+ * A FIRST NAME, AND A LAST NAME IF THEY HAVE ONE (Account → Sign in, "How signing up works",
1182
+ * step 1; ONPLO-4080). There is no middle name, and where one name divides is never guessed.
1183
+ */
1184
+ SignUpStart: {
1185
+ username: components["schemas"]["Username"];
1186
+ /**
1187
+ * @description The person's first name, as typed, by the rule Account's `ProfileUpdate` holds: something a
1188
+ * person can see, on one line.
1189
+ */
1190
+ first_name: string;
1191
+ /** @description The person's last name, as typed, by the same rule. Left out by a person who has one name. */
1192
+ last_name?: string;
1193
+ /**
1194
+ * Format: email
1195
+ * @description The person's own address, OR LEFT OUT: it is asked, and is not required to get in (step 4,
1196
+ * decision 0935). When sent it is recorded as theirs and mailed its confirmation link, and it is
1197
+ * never a way in (decision 0198). Left out, no address is written and no mail is sent.
1198
+ */
1199
+ email_address?: string;
1200
+ /**
1201
+ * @description The language Onplo speaks to them in, a BCP 47 tag, from the browser and confirmed once. The same rule as Account's `Preferences.language`.
1202
+ * @example nl-BE
1203
+ */
1204
+ language: string;
1205
+ /** @description The zone times are shown in for them, an IANA name, from the device and confirmed once. */
1206
+ time_zone: string;
1207
+ /**
1208
+ * @description The country they are in, ISO 3166-1 alpha-2, which their working calendar counts public
1209
+ * holidays by. Left out when the client does not know it.
1210
+ */
1211
+ country?: string;
1212
+ };
1213
+ /**
1214
+ * @description ONE SIGN-UP: the question the first passkey answers, and until when an answer is taken. Single
1215
+ * use.
1216
+ */
1217
+ SignUp: {
1218
+ /** @description What the completion names. */
1219
+ id: components["schemas"]["Id"];
1220
+ /** @description With `excludeCredentials` always empty, since the person holds no key yet. */
1221
+ creation_options: components["schemas"]["PasskeyCreationOptions"];
1222
+ /** @description When the sign-up dies. Minutes; after it, start again. */
1223
+ expires_at: components["schemas"]["Timestamp"];
1224
+ };
1225
+ SignUpCompletion: {
1226
+ attestation: components["schemas"]["PasskeyAttestation"];
1227
+ /** @description What the person calls their first key in their list of sign-in methods. */
1228
+ name: string;
1229
+ };
1230
+ /**
1231
+ * @description AN ACCOUNT MADE: the recovery codes, shown this once, and the first session, in the person's
1232
+ * personal environment.
1233
+ */
1234
+ SignedUp: {
1235
+ /**
1236
+ * @description TEN ONE-TIME CODES, each good once, the only way back for a person who loses every passkey.
1237
+ * Shown here and never again: Onplo keeps none of them in the clear.
1238
+ */
1239
+ recovery_codes: string[];
1240
+ session: components["schemas"]["SignedInSession"];
1241
+ };
1242
+ RecoveryStart: {
1243
+ username: components["schemas"]["Username"];
1244
+ /**
1245
+ * @description One of the person's recovery codes, as it was shown, lower case.
1246
+ * @example abcde-12345
1247
+ */
1248
+ recovery_code: string;
1249
+ };
1250
+ /**
1251
+ * @description ONE RECOVERY: the question the new passkey answers, and until when an answer is taken. Single
1252
+ * use. Its id is the `sign_in_id` that opens the session afterwards.
1253
+ */
1254
+ Recovery: {
1255
+ /** @description What the completion, and then `openSignedInSession`, name. */
1256
+ id: components["schemas"]["Id"];
1257
+ creation_options: components["schemas"]["PasskeyCreationOptions"];
1258
+ /** @description When the recovery dies. Minutes; after it, use another code. */
1259
+ expires_at: components["schemas"]["Timestamp"];
1260
+ };
1261
+ RecoveryCompletion: {
1262
+ attestation: components["schemas"]["PasskeyAttestation"];
1263
+ /** @description What the person calls the new key. It becomes their Primary passkey. */
1264
+ name: string;
1265
+ };
1266
+ /**
1267
+ * Format: date-time
1268
+ * @description RFC 3339, always UTC, always with the offset written out.
1269
+ * @example 2026-09-13T06:06:00Z
1270
+ */
1271
+ Timestamp: string;
1272
+ /**
1273
+ * @description RFC 9457. Served as `application/problem+json`, on every failure, from every operation —
1274
+ * one shape to handle rather than one per endpoint. CLOSED, like every other object here:
1275
+ * the server validates its own answers against this schema, and an open object is the one
1276
+ * shape that check cannot see through.
1277
+ */
1278
+ Problem: {
1279
+ /**
1280
+ * Format: uri
1281
+ * @description A stable URI naming the kind of problem. Dereferenceable; documentation lives there.
1282
+ * @example https://onplo.com/problems/passkey_not_verified
1283
+ */
1284
+ type: string;
1285
+ /** @example The passkey did not verify */
1286
+ title: string;
1287
+ status: number;
1288
+ /** @description What went wrong THIS time, in a sentence a person could be shown. */
1289
+ detail?: string;
1290
+ /**
1291
+ * Format: uri-reference
1292
+ * @description The request path this happened on.
1293
+ */
1294
+ instance?: string;
1295
+ /**
1296
+ * @description The machine name, stable across wording changes. `type` is the URI a human opens; this
1297
+ * is what a client branches on.
1298
+ * @example passkey_not_verified
1299
+ */
1300
+ code: string;
1301
+ /**
1302
+ * Format: uuid
1303
+ * @description Quote it in a support request and the exact call can be found. It is also on the
1304
+ * `Onplo-Request-Id` response header of every response, failed or not.
1305
+ */
1306
+ request_id: string;
1307
+ /** @description One entry per field that is wrong. REQUIRED on a 422. */
1308
+ errors?: {
1309
+ /**
1310
+ * @description A JSON Pointer (RFC 6901) at the wrong value, rooted at the REQUEST: `/body/...`
1311
+ * for a body field, `/path/...` for a path segment.
1312
+ * @example /body/answer/response/signature
1313
+ */
1314
+ pointer: string;
1315
+ code: string;
1316
+ detail: string;
1317
+ }[];
1318
+ };
1319
+ /**
1320
+ * @description The provider's metadata, under the names OpenID Connect Discovery 1.0 gives them, so any
1321
+ * standard client reads it unchanged. Every list holds only what identity supports.
1322
+ */
1323
+ ProviderDiscovery: {
1324
+ /**
1325
+ * Format: uri
1326
+ * @description The provider's address. Every ID token's `iss` is exactly this.
1327
+ */
1328
+ issuer: string;
1329
+ /**
1330
+ * Format: uri
1331
+ * @description Where a person is sent to sign in.
1332
+ */
1333
+ authorization_endpoint: string;
1334
+ /**
1335
+ * Format: uri
1336
+ * @description Where the answer is traded for tokens.
1337
+ */
1338
+ token_endpoint: string;
1339
+ /**
1340
+ * Format: uri
1341
+ * @description Where the key set is, `readProviderKeySet`.
1342
+ */
1343
+ jwks_uri: string;
1344
+ scopes_supported: "openid"[];
1345
+ response_types_supported: "code"[];
1346
+ response_modes_supported: "query"[];
1347
+ grant_types_supported: ("authorization_code" | "refresh_token")[];
1348
+ subject_types_supported: "public"[];
1349
+ id_token_signing_alg_values_supported: "ES256"[];
1350
+ /** @description `none`: every Onplo app is a public client and holds no secret. */
1351
+ token_endpoint_auth_methods_supported: "none"[];
1352
+ code_challenge_methods_supported: "S256"[];
1353
+ claims_supported: ("iss" | "sub" | "aud" | "exp" | "iat" | "auth_time" | "amr")[];
1354
+ };
1355
+ /** @description A JSON Web Key Set (RFC 7517). */
1356
+ ProviderKeySet: {
1357
+ keys: components["schemas"]["ProviderKey"][];
1358
+ };
1359
+ /**
1360
+ * @description One public key, an elliptic-curve key on P-256 as RFC 7518 writes it. The private half is never
1361
+ * anywhere this API reaches.
1362
+ */
1363
+ ProviderKey: {
1364
+ /**
1365
+ * @description The key type.
1366
+ * @enum {string}
1367
+ */
1368
+ kty: "EC";
1369
+ /**
1370
+ * @description The curve.
1371
+ * @enum {string}
1372
+ */
1373
+ crv: "P-256";
1374
+ /** @description The point's x coordinate, 32 bytes in base64url. */
1375
+ x: string;
1376
+ /** @description The point's y coordinate, 32 bytes in base64url. */
1377
+ y: string;
1378
+ /** @description The key's id, its RFC 7638 thumbprint. An ID token's header names its key by it. */
1379
+ kid: string;
1380
+ /**
1381
+ * @description The key signs; it encrypts nothing.
1382
+ * @enum {string}
1383
+ */
1384
+ use: "sig";
1385
+ /**
1386
+ * @description The one algorithm it signs with.
1387
+ * @enum {string}
1388
+ */
1389
+ alg: "ES256";
1390
+ };
1391
+ };
1392
+ responses: {
1393
+ /**
1394
+ * @description The request could not be read, so nothing in it was looked at — `malformed_request`. Its body
1395
+ * is not valid JSON, or its address carries a broken `%`-escape. No field is named, because
1396
+ * none was read. Declared on every operation, the ones that take no body included: a body is
1397
+ * read before the server knows which operation it was sent to.
1398
+ */
1399
+ BadRequest: {
1400
+ headers: {
1401
+ "Onplo-Request-Id": components["headers"]["OnploRequestId"];
1402
+ [name: string]: unknown;
1403
+ };
1404
+ content: {
1405
+ "application/problem+json": components["schemas"]["Problem"] & {
1406
+ /** @enum {unknown} */
1407
+ code?: "malformed_request";
1408
+ };
1409
+ };
1410
+ };
1411
+ /**
1412
+ * @description There is no usable credential on this call — it is missing, malformed, unknown, expired, or
1413
+ * it has been REVOKED. A revoked credential fails HERE and not with 403, because it is no
1414
+ * longer a credential.
1415
+ */
1416
+ Unauthorized: {
1417
+ headers: {
1418
+ "Onplo-Request-Id": components["headers"]["OnploRequestId"];
1419
+ "WWW-Authenticate": components["headers"]["WwwAuthenticate"];
1420
+ [name: string]: unknown;
1421
+ };
1422
+ content: {
1423
+ "application/problem+json": components["schemas"]["Problem"] & {
1424
+ /** @enum {unknown} */
1425
+ code?: "credential_missing" | "credential_malformed" | "credential_unknown" | "credential_expired" | "credential_revoked";
1426
+ };
1427
+ };
1428
+ };
1429
+ /**
1430
+ * @description The credential is good and this call is refused anyway. `permission_missing`: the
1431
+ * credential does not carry the permission this operation needs. `ring_requires_person`: a
1432
+ * ring-1 act attempted by a raw key, refused regardless of scopes. `outside_session_scope`:
1433
+ * allowed to this subject and not within the scope this session declared at sign-in.
1434
+ *
1435
+ * ONE COMPONENT ON EVERY OPERATION, the ungated ones included, because the three reasons are
1436
+ * the same on every contract and a client writes one branch for them.
1437
+ */
1438
+ Forbidden: {
1439
+ headers: {
1440
+ "Onplo-Request-Id": components["headers"]["OnploRequestId"];
1441
+ [name: string]: unknown;
1442
+ };
1443
+ content: {
1444
+ "application/problem+json": components["schemas"]["Problem"] & {
1445
+ /** @enum {unknown} */
1446
+ code?: "permission_missing" | "ring_requires_person" | "outside_session_scope";
1447
+ };
1448
+ };
1449
+ };
1450
+ /**
1451
+ * @description No such ceremony, or not one this session started. The two are never told apart, and
1452
+ * neither is one that expired or was already answered: saying which would let somebody learn
1453
+ * about a ceremony by trying its id.
1454
+ */
1455
+ NotFound: {
1456
+ headers: {
1457
+ "Onplo-Request-Id": components["headers"]["OnploRequestId"];
1458
+ "Cache-Control": components["headers"]["CacheControl"];
1459
+ [name: string]: unknown;
1460
+ };
1461
+ content: {
1462
+ "application/problem+json": components["schemas"]["Problem"] & {
1463
+ /** @enum {unknown} */
1464
+ code?: "not_found";
1465
+ };
1466
+ };
1467
+ };
1468
+ /**
1469
+ * @description The request body is larger than this API reads — `request_too_large`. `detail` names the
1470
+ * limit in bytes. Declared on every operation, for the reason `BadRequest` gives.
1471
+ */
1472
+ ContentTooLarge: {
1473
+ headers: {
1474
+ "Onplo-Request-Id": components["headers"]["OnploRequestId"];
1475
+ [name: string]: unknown;
1476
+ };
1477
+ content: {
1478
+ "application/problem+json": components["schemas"]["Problem"] & {
1479
+ /** @enum {unknown} */
1480
+ code?: "request_too_large";
1481
+ };
1482
+ };
1483
+ };
1484
+ /**
1485
+ * @description The request body is in a form this API does not read — `unsupported_media_type`. This API
1486
+ * reads JSON, sent uncompressed as `application/json`, and nothing else.
1487
+ */
1488
+ UnsupportedMediaType: {
1489
+ headers: {
1490
+ "Onplo-Request-Id": components["headers"]["OnploRequestId"];
1491
+ [name: string]: unknown;
1492
+ };
1493
+ content: {
1494
+ "application/problem+json": components["schemas"]["Problem"] & {
1495
+ /** @enum {unknown} */
1496
+ code?: "unsupported_media_type";
1497
+ };
1498
+ };
1499
+ };
1500
+ /**
1501
+ * @description The request parsed and something in it is wrong. `errors` says what, one entry per field,
1502
+ * each with a JSON Pointer at it. ONE `code`, because the detail is in `errors`. This is
1503
+ * about the SHAPE of what was sent; an answer of the right shape that does not verify is the
1504
+ * 409 on that operation.
1505
+ */
1506
+ Unprocessable: {
1507
+ headers: {
1508
+ "Onplo-Request-Id": components["headers"]["OnploRequestId"];
1509
+ [name: string]: unknown;
1510
+ };
1511
+ content: {
1512
+ "application/problem+json": components["schemas"]["Problem"] & {
1513
+ /** @enum {unknown} */
1514
+ code?: "unprocessable_request";
1515
+ };
1516
+ };
1517
+ };
1518
+ /**
1519
+ * @description This door was called too often in the last minute, from this address or from everyone
1520
+ * together — `too_many_requests`. Nothing was read and no token was issued. `Retry-After`
1521
+ * says how many whole seconds to wait; the same call is then answered as usual.
1522
+ *
1523
+ * Only a door that answers with no credential is limited this way, because nobody is charged
1524
+ * for the call (decision 0732). How many calls a minute it takes is not part of this contract.
1525
+ */
1526
+ TooManyCalls: {
1527
+ headers: {
1528
+ "Onplo-Request-Id": components["headers"]["OnploRequestId"];
1529
+ "Retry-After": components["headers"]["RetryAfter"];
1530
+ [name: string]: unknown;
1531
+ };
1532
+ content: {
1533
+ "application/problem+json": components["schemas"]["Problem"] & {
1534
+ /** @enum {unknown} */
1535
+ code?: "too_many_requests";
1536
+ };
1537
+ };
1538
+ };
1539
+ /**
1540
+ * @description Something failed that this contract cannot describe — including an answer this API produced
1541
+ * and then refused to send, because the contract does not describe that answer either
1542
+ * (`response_not_in_contract`). Response validation stays on in production (decision 0551).
1543
+ * `request_id` is what finds the call.
1544
+ */
1545
+ ServerError: {
1546
+ headers: {
1547
+ "Onplo-Request-Id": components["headers"]["OnploRequestId"];
1548
+ [name: string]: unknown;
1549
+ };
1550
+ content: {
1551
+ "application/problem+json": components["schemas"]["Problem"] & {
1552
+ /** @enum {unknown} */
1553
+ code?: "internal_error" | "response_not_in_contract";
1554
+ };
1555
+ };
1556
+ };
1557
+ /**
1558
+ * @description The authorization service could not be asked, so whether this call may proceed is UNKNOWN —
1559
+ * `authorization_unavailable`. Never a 403, which would claim a refusal when all that is
1560
+ * known is that we could not ask.
1561
+ */
1562
+ ServiceUnavailable: {
1563
+ headers: {
1564
+ "Onplo-Request-Id": components["headers"]["OnploRequestId"];
1565
+ [name: string]: unknown;
1566
+ };
1567
+ content: {
1568
+ "application/problem+json": components["schemas"]["Problem"] & {
1569
+ /** @enum {unknown} */
1570
+ code?: "authorization_unavailable";
1571
+ };
1572
+ };
1573
+ };
1574
+ /**
1575
+ * @description **Onplo has not built this operation yet** — `not_implemented` (decision 0580). It is
1576
+ * declared here because the contract is written before the code; it is not a 404, because the
1577
+ * address is right, and not a 503, because there is nothing to retry. Treat the operation as
1578
+ * absent for now. Nothing about your credential or your request caused this.
1579
+ */
1580
+ NotImplemented: {
1581
+ headers: {
1582
+ "Onplo-Request-Id": components["headers"]["OnploRequestId"];
1583
+ "Cache-Control": components["headers"]["CacheControl"];
1584
+ [name: string]: unknown;
1585
+ };
1586
+ content: {
1587
+ "application/problem+json": components["schemas"]["Problem"] & {
1588
+ /** @enum {unknown} */
1589
+ code?: "not_implemented";
1590
+ };
1591
+ };
1592
+ };
1593
+ };
1594
+ parameters: {
1595
+ PasskeyProofId: components["schemas"]["Id"];
1596
+ SignInId: components["schemas"]["Id"];
1597
+ PasskeyRegistrationId: components["schemas"]["Id"];
1598
+ SignUpId: components["schemas"]["Id"];
1599
+ RecoveryId: components["schemas"]["Id"];
1600
+ };
1601
+ requestBodies: never;
1602
+ headers: {
1603
+ /**
1604
+ * @description The id of this call. Minted by the server as a UUID version 7 and **never taken from a
1605
+ * request header** (decision 0553). It rides EVERY response, and it is the same value as the
1606
+ * problem document's `request_id` when there is one. Quote it in a support request and the
1607
+ * exact call can be found.
1608
+ */
1609
+ OnploRequestId: string;
1610
+ /**
1611
+ * @description The challenge RFC 9110 §11.6.1 and RFC 6750 §3 require on a 401 under a bearer scheme
1612
+ * (decision 0569). `Bearer realm="onplo"` alone when no credential was sent; otherwise
1613
+ * `Bearer realm="onplo", error="invalid_token"`. It never carries `error_description` and never
1614
+ * `scope`. A 403 carries no challenge at all.
1615
+ */
1616
+ WwwAuthenticate: string;
1617
+ /**
1618
+ * @description `no-store`, in two places. On the statuses RFC 9110 §15.1 makes cacheable by default — a
1619
+ * 404 and a 501 (decision 0580): a cached "not built yet" would outlive the day the operation
1620
+ * is built. And on every answer that carries a credential — `tradeDeviceStatement`'s,
1621
+ * `switchEnvironment`'s, `completeSignIn`'s, `openSignedInSession`'s, `completeSignUp`'s and
1622
+ * `completeRecovery`'s — each marked `x-carries-secret` so the server sends it.
1623
+ */
1624
+ CacheControl: "no-store";
1625
+ /**
1626
+ * @description Whole seconds until a limited caller may call this door again (decision 0732). It rides a
1627
+ * 429 and no other status.
1628
+ */
1629
+ RetryAfter: number;
1630
+ /**
1631
+ * @description Where the browser is sent (decision 1027): identity's sign-in screen, or the app's registered
1632
+ * return address with an OAuth `error`. It rides a redirect and no other answer.
1633
+ */
1634
+ Location: string;
1635
+ };
1636
+ pathItems: never;
1637
+ }
1638
+ export type $defs = Record<string, never>;
1639
+ export interface operations {
1640
+ readProviderDiscovery: {
1641
+ parameters: {
1642
+ query?: never;
1643
+ header?: never;
1644
+ path?: never;
1645
+ cookie?: never;
1646
+ };
1647
+ requestBody?: never;
1648
+ responses: {
1649
+ /** @description The discovery document. */
1650
+ 200: {
1651
+ headers: {
1652
+ "Onplo-Request-Id": components["headers"]["OnploRequestId"];
1653
+ [name: string]: unknown;
1654
+ };
1655
+ content: {
1656
+ "application/json": components["schemas"]["ProviderDiscovery"];
1657
+ };
1658
+ };
1659
+ 400: components["responses"]["BadRequest"];
1660
+ 413: components["responses"]["ContentTooLarge"];
1661
+ 415: components["responses"]["UnsupportedMediaType"];
1662
+ 429: components["responses"]["TooManyCalls"];
1663
+ 500: components["responses"]["ServerError"];
1664
+ 501: components["responses"]["NotImplemented"];
1665
+ };
1666
+ };
1667
+ readProviderKeySet: {
1668
+ parameters: {
1669
+ query?: never;
1670
+ header?: never;
1671
+ path?: never;
1672
+ cookie?: never;
1673
+ };
1674
+ requestBody?: never;
1675
+ responses: {
1676
+ /** @description The key set. */
1677
+ 200: {
1678
+ headers: {
1679
+ "Onplo-Request-Id": components["headers"]["OnploRequestId"];
1680
+ [name: string]: unknown;
1681
+ };
1682
+ content: {
1683
+ "application/json": components["schemas"]["ProviderKeySet"];
1684
+ };
1685
+ };
1686
+ 400: components["responses"]["BadRequest"];
1687
+ 413: components["responses"]["ContentTooLarge"];
1688
+ 415: components["responses"]["UnsupportedMediaType"];
1689
+ 429: components["responses"]["TooManyCalls"];
1690
+ 500: components["responses"]["ServerError"];
1691
+ 501: components["responses"]["NotImplemented"];
1692
+ };
1693
+ };
1694
+ authorizeSignIn: {
1695
+ parameters: {
1696
+ query?: {
1697
+ /** @description The app, by the id Onplo lists it under. */
1698
+ client_id?: string;
1699
+ /** @description Where the app is sent back to, exactly as it registered it. */
1700
+ redirect_uri?: string;
1701
+ /** @description Always `code`. */
1702
+ response_type?: string;
1703
+ /** @description The scopes asked, space-separated. `openid` is always one of them. */
1704
+ scope?: string;
1705
+ /** @description The app's own value, sent back to it. */
1706
+ state?: string;
1707
+ /** @description The PKCE challenge, the SHA-256 of the app's verifier in base64url. */
1708
+ code_challenge?: string;
1709
+ /** @description Always `S256`. */
1710
+ code_challenge_method?: string;
1711
+ /** @description The app's value the ID token echoes. */
1712
+ nonce?: string;
1713
+ };
1714
+ header?: never;
1715
+ path?: never;
1716
+ cookie?: never;
1717
+ };
1718
+ requestBody?: never;
1719
+ responses: {
1720
+ /** @description The browser is sent to the sign-in screen, or back to the app with an error. */
1721
+ 302: {
1722
+ headers: {
1723
+ "Onplo-Request-Id": components["headers"]["OnploRequestId"];
1724
+ Location: components["headers"]["Location"];
1725
+ [name: string]: unknown;
1726
+ };
1727
+ content?: never;
1728
+ };
1729
+ /**
1730
+ * @description Nothing is redirected. `not_registered`: the app, or its return address, is not one Onplo
1731
+ * lists. `malformed_request`: the address could not be read.
1732
+ */
1733
+ 400: {
1734
+ headers: {
1735
+ "Onplo-Request-Id": components["headers"]["OnploRequestId"];
1736
+ [name: string]: unknown;
1737
+ };
1738
+ content: {
1739
+ "application/problem+json": components["schemas"]["Problem"] & {
1740
+ /** @enum {unknown} */
1741
+ code?: "malformed_request" | "not_registered";
1742
+ };
1743
+ };
1744
+ };
1745
+ 413: components["responses"]["ContentTooLarge"];
1746
+ 415: components["responses"]["UnsupportedMediaType"];
1747
+ 422: components["responses"]["Unprocessable"];
1748
+ 429: components["responses"]["TooManyCalls"];
1749
+ 500: components["responses"]["ServerError"];
1750
+ };
1751
+ };
1752
+ startPasskeyProof: {
1753
+ parameters: {
1754
+ query?: never;
1755
+ header?: never;
1756
+ path?: never;
1757
+ cookie?: never;
1758
+ };
1759
+ requestBody?: never;
1760
+ responses: {
1761
+ /** @description The ceremony, and the question to put to the passkey. */
1762
+ 201: {
1763
+ headers: {
1764
+ "Onplo-Request-Id": components["headers"]["OnploRequestId"];
1765
+ [name: string]: unknown;
1766
+ };
1767
+ content: {
1768
+ "application/json": components["schemas"]["PasskeyProof"];
1769
+ };
1770
+ };
1771
+ 400: components["responses"]["BadRequest"];
1772
+ 401: components["responses"]["Unauthorized"];
1773
+ 403: components["responses"]["Forbidden"];
1774
+ /**
1775
+ * @description Refused: the credential is not a person's signed-in session (`not_a_person_session`).
1776
+ * A key, a grant and an AI agent have no passkey to ask.
1777
+ */
1778
+ 409: {
1779
+ headers: {
1780
+ "Onplo-Request-Id": components["headers"]["OnploRequestId"];
1781
+ [name: string]: unknown;
1782
+ };
1783
+ content: {
1784
+ "application/problem+json": components["schemas"]["Problem"] & {
1785
+ /** @enum {unknown} */
1786
+ code?: "not_a_person_session";
1787
+ };
1788
+ };
1789
+ };
1790
+ 413: components["responses"]["ContentTooLarge"];
1791
+ 415: components["responses"]["UnsupportedMediaType"];
1792
+ 500: components["responses"]["ServerError"];
1793
+ 503: components["responses"]["ServiceUnavailable"];
1794
+ };
1795
+ };
1796
+ completePasskeyProof: {
1797
+ parameters: {
1798
+ query?: never;
1799
+ header?: never;
1800
+ path: {
1801
+ passkey_proof_id: components["parameters"]["PasskeyProofId"];
1802
+ };
1803
+ cookie?: never;
1804
+ };
1805
+ requestBody: {
1806
+ content: {
1807
+ "application/json": components["schemas"]["PasskeyProofCompletion"];
1808
+ };
1809
+ };
1810
+ responses: {
1811
+ /** @description Proved. The moment this session now carries. */
1812
+ 200: {
1813
+ headers: {
1814
+ "Onplo-Request-Id": components["headers"]["OnploRequestId"];
1815
+ [name: string]: unknown;
1816
+ };
1817
+ content: {
1818
+ "application/json": components["schemas"]["SessionProof"];
1819
+ };
1820
+ };
1821
+ 400: components["responses"]["BadRequest"];
1822
+ 401: components["responses"]["Unauthorized"];
1823
+ 403: components["responses"]["Forbidden"];
1824
+ 404: components["responses"]["NotFound"];
1825
+ /**
1826
+ * @description Refused: the passkey's answer did not verify (`passkey_not_verified`). The ceremony is
1827
+ * spent.
1828
+ */
1829
+ 409: {
1830
+ headers: {
1831
+ "Onplo-Request-Id": components["headers"]["OnploRequestId"];
1832
+ [name: string]: unknown;
1833
+ };
1834
+ content: {
1835
+ "application/problem+json": components["schemas"]["Problem"] & {
1836
+ /** @enum {unknown} */
1837
+ code?: "passkey_not_verified";
1838
+ };
1839
+ };
1840
+ };
1841
+ 413: components["responses"]["ContentTooLarge"];
1842
+ 415: components["responses"]["UnsupportedMediaType"];
1843
+ 422: components["responses"]["Unprocessable"];
1844
+ 500: components["responses"]["ServerError"];
1845
+ 503: components["responses"]["ServiceUnavailable"];
1846
+ };
1847
+ };
1848
+ tradeDeviceStatement: {
1849
+ parameters: {
1850
+ query?: never;
1851
+ header?: never;
1852
+ path?: never;
1853
+ cookie?: never;
1854
+ };
1855
+ requestBody: {
1856
+ content: {
1857
+ "application/json": {
1858
+ /**
1859
+ * @description The signed statement, in the compact form: three base64url parts joined by
1860
+ * dots. Bounded, because an unbounded string in a body makes the body limit
1861
+ * unprovable. The example shows the SHAPE and is no statement at all: its three
1862
+ * parts are the words header, claims and signature.
1863
+ * @example aGVhZGVy.Y2xhaW1z.c2lnbmF0dXJl
1864
+ */
1865
+ statement: string;
1866
+ /**
1867
+ * @description A RENEWAL, sent only when the device wants its next certificate: a PKCS #10
1868
+ * certificate request (RFC 2986) for a NEW P-256 key, signed by that key, in DER
1869
+ * and written base64url with no padding. One for P-256 is a few hundred bytes;
1870
+ * the ceiling leaves room for the names it carries.
1871
+ */
1872
+ certificate_request?: string;
1873
+ };
1874
+ };
1875
+ };
1876
+ responses: {
1877
+ /**
1878
+ * @description The token, and when it stops being good, and when the certificate behind it does. With
1879
+ * a renewal, the new certificate too. Sent with `no-store`.
1880
+ */
1881
+ 201: {
1882
+ headers: {
1883
+ "Onplo-Request-Id": components["headers"]["OnploRequestId"];
1884
+ "Cache-Control": components["headers"]["CacheControl"];
1885
+ [name: string]: unknown;
1886
+ };
1887
+ content: {
1888
+ "application/json": components["schemas"]["DeviceToken"];
1889
+ };
1890
+ };
1891
+ 400: components["responses"]["BadRequest"];
1892
+ /**
1893
+ * @description Refused. `statement_not_verified`: the statement does not prove a device Onplo will
1894
+ * answer — which check failed is never said. `statement_outside_its_time`: its `exp` is
1895
+ * past, or more than five minutes ahead; set the clock by this answer's `Date` header
1896
+ * and sign a new one. The five others refuse a renewal's certificate request, and the
1897
+ * operation's description says each. No token is issued, and no certificate, either way.
1898
+ */
1899
+ 409: {
1900
+ headers: {
1901
+ "Onplo-Request-Id": components["headers"]["OnploRequestId"];
1902
+ [name: string]: unknown;
1903
+ };
1904
+ content: {
1905
+ "application/problem+json": components["schemas"]["Problem"] & {
1906
+ /** @enum {unknown} */
1907
+ code?: "statement_not_verified" | "statement_outside_its_time" | "certificate_request_unreadable" | "certificate_request_not_signed_by_its_key" | "key_not_certified" | "key_ended" | "key_already_certified";
1908
+ };
1909
+ };
1910
+ };
1911
+ 413: components["responses"]["ContentTooLarge"];
1912
+ 415: components["responses"]["UnsupportedMediaType"];
1913
+ 422: components["responses"]["Unprocessable"];
1914
+ 429: components["responses"]["TooManyCalls"];
1915
+ 500: components["responses"]["ServerError"];
1916
+ 501: components["responses"]["NotImplemented"];
1917
+ };
1918
+ };
1919
+ switchEnvironment: {
1920
+ parameters: {
1921
+ query?: never;
1922
+ header?: never;
1923
+ path?: never;
1924
+ cookie?: never;
1925
+ };
1926
+ requestBody: {
1927
+ content: {
1928
+ "application/json": {
1929
+ /** @description The account environment to open a session in. */
1930
+ environment_id: components["schemas"]["Id"];
1931
+ };
1932
+ };
1933
+ };
1934
+ responses: {
1935
+ /** @description The new session's token, where it acts, and until when. Sent with `no-store`. */
1936
+ 201: {
1937
+ headers: {
1938
+ "Onplo-Request-Id": components["headers"]["OnploRequestId"];
1939
+ "Cache-Control": components["headers"]["CacheControl"];
1940
+ [name: string]: unknown;
1941
+ };
1942
+ content: {
1943
+ "application/json": components["schemas"]["SwitchedSession"];
1944
+ };
1945
+ };
1946
+ 400: components["responses"]["BadRequest"];
1947
+ 401: components["responses"]["Unauthorized"];
1948
+ 403: components["responses"]["Forbidden"];
1949
+ /**
1950
+ * @description Refused, and no session is opened. `not_a_person_session`: the credential is not a
1951
+ * person's signed-in session. `not_a_member`: the person is not a member of that
1952
+ * environment now, or it does not exist. `membership_suspended`: they are a member and
1953
+ * suspended there. `passkey_proof_needed`: prove it is you on this session, then send the
1954
+ * switch again. `already_in_that_environment`: the session that asked already acts there.
1955
+ */
1956
+ 409: {
1957
+ headers: {
1958
+ "Onplo-Request-Id": components["headers"]["OnploRequestId"];
1959
+ [name: string]: unknown;
1960
+ };
1961
+ content: {
1962
+ "application/problem+json": components["schemas"]["Problem"] & {
1963
+ /** @enum {unknown} */
1964
+ code?: "not_a_person_session" | "not_a_member" | "membership_suspended" | "passkey_proof_needed" | "already_in_that_environment";
1965
+ };
1966
+ };
1967
+ };
1968
+ 413: components["responses"]["ContentTooLarge"];
1969
+ 415: components["responses"]["UnsupportedMediaType"];
1970
+ 422: components["responses"]["Unprocessable"];
1971
+ 500: components["responses"]["ServerError"];
1972
+ 503: components["responses"]["ServiceUnavailable"];
1973
+ };
1974
+ };
1975
+ startSignIn: {
1976
+ parameters: {
1977
+ query?: never;
1978
+ header?: never;
1979
+ path?: never;
1980
+ cookie?: never;
1981
+ };
1982
+ requestBody?: never;
1983
+ responses: {
1984
+ /** @description The sign-in, and the question to put to the passkey. */
1985
+ 201: {
1986
+ headers: {
1987
+ "Onplo-Request-Id": components["headers"]["OnploRequestId"];
1988
+ [name: string]: unknown;
1989
+ };
1990
+ content: {
1991
+ "application/json": components["schemas"]["SignIn"];
1992
+ };
1993
+ };
1994
+ 400: components["responses"]["BadRequest"];
1995
+ 413: components["responses"]["ContentTooLarge"];
1996
+ 415: components["responses"]["UnsupportedMediaType"];
1997
+ 429: components["responses"]["TooManyCalls"];
1998
+ 500: components["responses"]["ServerError"];
1999
+ };
2000
+ };
2001
+ completeSignIn: {
2002
+ parameters: {
2003
+ query?: never;
2004
+ header?: never;
2005
+ path: {
2006
+ sign_in_id: components["parameters"]["SignInId"];
2007
+ };
2008
+ cookie?: never;
2009
+ };
2010
+ requestBody: {
2011
+ content: {
2012
+ "application/json": components["schemas"]["SignInCompletion"];
2013
+ };
2014
+ };
2015
+ responses: {
2016
+ /** @description Proved. Where the person may go, and the token that opens one session. Sent with `no-store`. */
2017
+ 200: {
2018
+ headers: {
2019
+ "Onplo-Request-Id": components["headers"]["OnploRequestId"];
2020
+ "Cache-Control": components["headers"]["CacheControl"];
2021
+ [name: string]: unknown;
2022
+ };
2023
+ content: {
2024
+ "application/json": components["schemas"]["SignInChoices"];
2025
+ };
2026
+ };
2027
+ 400: components["responses"]["BadRequest"];
2028
+ 404: components["responses"]["NotFound"];
2029
+ /**
2030
+ * @description Refused, and the sign-in is spent. `passkey_not_verified`: the answer did not prove a
2031
+ * person Onplo will sign in, and which check failed is never said.
2032
+ * `device_token_not_verified`: the device token shown beside it is not a live device's.
2033
+ */
2034
+ 409: {
2035
+ headers: {
2036
+ "Onplo-Request-Id": components["headers"]["OnploRequestId"];
2037
+ [name: string]: unknown;
2038
+ };
2039
+ content: {
2040
+ "application/problem+json": components["schemas"]["Problem"] & {
2041
+ /** @enum {unknown} */
2042
+ code?: "passkey_not_verified" | "device_token_not_verified";
2043
+ };
2044
+ };
2045
+ };
2046
+ 413: components["responses"]["ContentTooLarge"];
2047
+ 415: components["responses"]["UnsupportedMediaType"];
2048
+ 422: components["responses"]["Unprocessable"];
2049
+ 429: components["responses"]["TooManyCalls"];
2050
+ 500: components["responses"]["ServerError"];
2051
+ 503: components["responses"]["ServiceUnavailable"];
2052
+ };
2053
+ };
2054
+ openSignedInSession: {
2055
+ parameters: {
2056
+ query?: never;
2057
+ header?: never;
2058
+ path: {
2059
+ sign_in_id: components["parameters"]["SignInId"];
2060
+ };
2061
+ cookie?: never;
2062
+ };
2063
+ requestBody: {
2064
+ content: {
2065
+ "application/json": components["schemas"]["SignedInSessionOpening"];
2066
+ };
2067
+ };
2068
+ responses: {
2069
+ /** @description The session's token, where it acts, and until when. Sent with `no-store`. */
2070
+ 201: {
2071
+ headers: {
2072
+ "Onplo-Request-Id": components["headers"]["OnploRequestId"];
2073
+ "Cache-Control": components["headers"]["CacheControl"];
2074
+ [name: string]: unknown;
2075
+ };
2076
+ content: {
2077
+ "application/json": components["schemas"]["SignedInSession"];
2078
+ };
2079
+ };
2080
+ 400: components["responses"]["BadRequest"];
2081
+ 404: components["responses"]["NotFound"];
2082
+ /**
2083
+ * @description Refused, and no session is opened; the sign-in token is still good until it expires.
2084
+ * `not_a_choice`: an environment sent is not one the completion listed, or the one to land
2085
+ * in is not among those chosen. `membership_suspended`: the person is suspended in the
2086
+ * environment they would land in; choose another.
2087
+ */
2088
+ 409: {
2089
+ headers: {
2090
+ "Onplo-Request-Id": components["headers"]["OnploRequestId"];
2091
+ [name: string]: unknown;
2092
+ };
2093
+ content: {
2094
+ "application/problem+json": components["schemas"]["Problem"] & {
2095
+ /** @enum {unknown} */
2096
+ code?: "not_a_choice" | "membership_suspended";
2097
+ };
2098
+ };
2099
+ };
2100
+ 413: components["responses"]["ContentTooLarge"];
2101
+ 415: components["responses"]["UnsupportedMediaType"];
2102
+ 422: components["responses"]["Unprocessable"];
2103
+ 429: components["responses"]["TooManyCalls"];
2104
+ 500: components["responses"]["ServerError"];
2105
+ };
2106
+ };
2107
+ grantAuthorizationCode: {
2108
+ parameters: {
2109
+ query?: never;
2110
+ header?: never;
2111
+ path: {
2112
+ sign_in_id: components["parameters"]["SignInId"];
2113
+ };
2114
+ cookie?: never;
2115
+ };
2116
+ requestBody: {
2117
+ content: {
2118
+ "application/json": components["schemas"]["AuthorizationCodeGrant"];
2119
+ };
2120
+ };
2121
+ responses: {
2122
+ /** @description Where to send the browser, back to the app with its code. Sent with `no-store`. */
2123
+ 201: {
2124
+ headers: {
2125
+ "Onplo-Request-Id": components["headers"]["OnploRequestId"];
2126
+ "Cache-Control": components["headers"]["CacheControl"];
2127
+ [name: string]: unknown;
2128
+ };
2129
+ content: {
2130
+ "application/json": components["schemas"]["AuthorizationCodeGranted"];
2131
+ };
2132
+ };
2133
+ 400: components["responses"]["BadRequest"];
2134
+ 404: components["responses"]["NotFound"];
2135
+ /**
2136
+ * @description Refused, and no code is kept; the sign-in token is still good until it expires.
2137
+ * `not_a_choice` and `membership_suspended` are what `openSignedInSession` answers.
2138
+ * `not_registered`: the app, or its return address, is not one Onplo lists. The browser is
2139
+ * never sent there. `authorization_request_refused`: the request is not one the
2140
+ * authorization endpoint takes.
2141
+ */
2142
+ 409: {
2143
+ headers: {
2144
+ "Onplo-Request-Id": components["headers"]["OnploRequestId"];
2145
+ [name: string]: unknown;
2146
+ };
2147
+ content: {
2148
+ "application/problem+json": components["schemas"]["Problem"] & {
2149
+ /** @enum {unknown} */
2150
+ code?: "not_a_choice" | "membership_suspended" | "not_registered" | "authorization_request_refused";
2151
+ };
2152
+ };
2153
+ };
2154
+ 413: components["responses"]["ContentTooLarge"];
2155
+ 415: components["responses"]["UnsupportedMediaType"];
2156
+ 422: components["responses"]["Unprocessable"];
2157
+ 429: components["responses"]["TooManyCalls"];
2158
+ 500: components["responses"]["ServerError"];
2159
+ };
2160
+ };
2161
+ startPasskeyRegistration: {
2162
+ parameters: {
2163
+ query?: never;
2164
+ header?: never;
2165
+ path?: never;
2166
+ cookie?: never;
2167
+ };
2168
+ requestBody?: never;
2169
+ responses: {
2170
+ /** @description The registration, and the question to put to the new key. */
2171
+ 201: {
2172
+ headers: {
2173
+ "Onplo-Request-Id": components["headers"]["OnploRequestId"];
2174
+ [name: string]: unknown;
2175
+ };
2176
+ content: {
2177
+ "application/json": components["schemas"]["PasskeyRegistration"];
2178
+ };
2179
+ };
2180
+ 400: components["responses"]["BadRequest"];
2181
+ 401: components["responses"]["Unauthorized"];
2182
+ 403: components["responses"]["Forbidden"];
2183
+ /**
2184
+ * @description Refused. `not_a_person_session`: the credential is not a person's signed-in session.
2185
+ * `passkey_proof_needed`: prove it is you on this session, then ask again.
2186
+ */
2187
+ 409: {
2188
+ headers: {
2189
+ "Onplo-Request-Id": components["headers"]["OnploRequestId"];
2190
+ [name: string]: unknown;
2191
+ };
2192
+ content: {
2193
+ "application/problem+json": components["schemas"]["Problem"] & {
2194
+ /** @enum {unknown} */
2195
+ code?: "not_a_person_session" | "passkey_proof_needed";
2196
+ };
2197
+ };
2198
+ };
2199
+ 413: components["responses"]["ContentTooLarge"];
2200
+ 415: components["responses"]["UnsupportedMediaType"];
2201
+ 500: components["responses"]["ServerError"];
2202
+ 503: components["responses"]["ServiceUnavailable"];
2203
+ };
2204
+ };
2205
+ completePasskeyRegistration: {
2206
+ parameters: {
2207
+ query?: never;
2208
+ header?: never;
2209
+ path: {
2210
+ passkey_registration_id: components["parameters"]["PasskeyRegistrationId"];
2211
+ };
2212
+ cookie?: never;
2213
+ };
2214
+ requestBody: {
2215
+ content: {
2216
+ "application/json": components["schemas"]["PasskeyRegistrationCompletion"];
2217
+ };
2218
+ };
2219
+ responses: {
2220
+ /** @description Kept. The new sign-in method, as Account lists it. */
2221
+ 201: {
2222
+ headers: {
2223
+ "Onplo-Request-Id": components["headers"]["OnploRequestId"];
2224
+ [name: string]: unknown;
2225
+ };
2226
+ content: {
2227
+ "application/json": components["schemas"]["AddedSignInMethod"];
2228
+ };
2229
+ };
2230
+ 400: components["responses"]["BadRequest"];
2231
+ 401: components["responses"]["Unauthorized"];
2232
+ 403: components["responses"]["Forbidden"];
2233
+ 404: components["responses"]["NotFound"];
2234
+ /**
2235
+ * @description Refused, and nothing is kept. `passkey_not_verified`: the new key did not prove what it
2236
+ * must, and which check failed is never said. `already_registered`: this person already
2237
+ * holds this key.
2238
+ */
2239
+ 409: {
2240
+ headers: {
2241
+ "Onplo-Request-Id": components["headers"]["OnploRequestId"];
2242
+ [name: string]: unknown;
2243
+ };
2244
+ content: {
2245
+ "application/problem+json": components["schemas"]["Problem"] & {
2246
+ /** @enum {unknown} */
2247
+ code?: "passkey_not_verified" | "already_registered";
2248
+ };
2249
+ };
2250
+ };
2251
+ 413: components["responses"]["ContentTooLarge"];
2252
+ 415: components["responses"]["UnsupportedMediaType"];
2253
+ 422: components["responses"]["Unprocessable"];
2254
+ 500: components["responses"]["ServerError"];
2255
+ 503: components["responses"]["ServiceUnavailable"];
2256
+ };
2257
+ };
2258
+ checkUsername: {
2259
+ parameters: {
2260
+ query?: never;
2261
+ header?: never;
2262
+ path?: never;
2263
+ cookie?: never;
2264
+ };
2265
+ requestBody: {
2266
+ content: {
2267
+ "application/json": components["schemas"]["UsernameCheck"];
2268
+ };
2269
+ };
2270
+ responses: {
2271
+ /** @description Whether the name may be chosen now. */
2272
+ 200: {
2273
+ headers: {
2274
+ "Onplo-Request-Id": components["headers"]["OnploRequestId"];
2275
+ [name: string]: unknown;
2276
+ };
2277
+ content: {
2278
+ "application/json": components["schemas"]["UsernameAvailability"];
2279
+ };
2280
+ };
2281
+ 400: components["responses"]["BadRequest"];
2282
+ 413: components["responses"]["ContentTooLarge"];
2283
+ 415: components["responses"]["UnsupportedMediaType"];
2284
+ 422: components["responses"]["Unprocessable"];
2285
+ 429: components["responses"]["TooManyCalls"];
2286
+ 500: components["responses"]["ServerError"];
2287
+ 503: components["responses"]["ServiceUnavailable"];
2288
+ };
2289
+ };
2290
+ startSignUp: {
2291
+ parameters: {
2292
+ query?: never;
2293
+ header?: never;
2294
+ path?: never;
2295
+ cookie?: never;
2296
+ };
2297
+ requestBody: {
2298
+ content: {
2299
+ "application/json": components["schemas"]["SignUpStart"];
2300
+ };
2301
+ };
2302
+ responses: {
2303
+ /** @description The sign-up, and the question to put to the first passkey. */
2304
+ 201: {
2305
+ headers: {
2306
+ "Onplo-Request-Id": components["headers"]["OnploRequestId"];
2307
+ [name: string]: unknown;
2308
+ };
2309
+ content: {
2310
+ "application/json": components["schemas"]["SignUp"];
2311
+ };
2312
+ };
2313
+ 400: components["responses"]["BadRequest"];
2314
+ /**
2315
+ * @description Refused. `username_not_available`: somebody holds the name, gave it up recently, or it is
2316
+ * reserved — never which.
2317
+ */
2318
+ 409: {
2319
+ headers: {
2320
+ "Onplo-Request-Id": components["headers"]["OnploRequestId"];
2321
+ [name: string]: unknown;
2322
+ };
2323
+ content: {
2324
+ "application/problem+json": components["schemas"]["Problem"] & {
2325
+ /** @enum {unknown} */
2326
+ code?: "username_not_available";
2327
+ };
2328
+ };
2329
+ };
2330
+ 413: components["responses"]["ContentTooLarge"];
2331
+ 415: components["responses"]["UnsupportedMediaType"];
2332
+ 422: components["responses"]["Unprocessable"];
2333
+ 429: components["responses"]["TooManyCalls"];
2334
+ 500: components["responses"]["ServerError"];
2335
+ 503: components["responses"]["ServiceUnavailable"];
2336
+ };
2337
+ };
2338
+ completeSignUp: {
2339
+ parameters: {
2340
+ query?: never;
2341
+ header?: never;
2342
+ path: {
2343
+ sign_up_id: components["parameters"]["SignUpId"];
2344
+ };
2345
+ cookie?: never;
2346
+ };
2347
+ requestBody: {
2348
+ content: {
2349
+ "application/json": components["schemas"]["SignUpCompletion"];
2350
+ };
2351
+ };
2352
+ responses: {
2353
+ /** @description Signed up. The recovery codes, shown this once, and the first session. Sent with `no-store`. */
2354
+ 201: {
2355
+ headers: {
2356
+ "Onplo-Request-Id": components["headers"]["OnploRequestId"];
2357
+ "Cache-Control": components["headers"]["CacheControl"];
2358
+ [name: string]: unknown;
2359
+ };
2360
+ content: {
2361
+ "application/json": components["schemas"]["SignedUp"];
2362
+ };
2363
+ };
2364
+ 400: components["responses"]["BadRequest"];
2365
+ 404: components["responses"]["NotFound"];
2366
+ /**
2367
+ * @description Refused, and the sign-up is spent. `passkey_not_verified`: the answer did not prove a new
2368
+ * key Onplo will keep, and which check failed is never said. `username_not_available`:
2369
+ * somebody took the name since the sign-up started.
2370
+ */
2371
+ 409: {
2372
+ headers: {
2373
+ "Onplo-Request-Id": components["headers"]["OnploRequestId"];
2374
+ [name: string]: unknown;
2375
+ };
2376
+ content: {
2377
+ "application/problem+json": components["schemas"]["Problem"] & {
2378
+ /** @enum {unknown} */
2379
+ code?: "passkey_not_verified" | "username_not_available";
2380
+ };
2381
+ };
2382
+ };
2383
+ 413: components["responses"]["ContentTooLarge"];
2384
+ 415: components["responses"]["UnsupportedMediaType"];
2385
+ 422: components["responses"]["Unprocessable"];
2386
+ 429: components["responses"]["TooManyCalls"];
2387
+ 500: components["responses"]["ServerError"];
2388
+ 503: components["responses"]["ServiceUnavailable"];
2389
+ };
2390
+ };
2391
+ startRecovery: {
2392
+ parameters: {
2393
+ query?: never;
2394
+ header?: never;
2395
+ path?: never;
2396
+ cookie?: never;
2397
+ };
2398
+ requestBody: {
2399
+ content: {
2400
+ "application/json": components["schemas"]["RecoveryStart"];
2401
+ };
2402
+ };
2403
+ responses: {
2404
+ /** @description The recovery, and the question to put to the new passkey. */
2405
+ 201: {
2406
+ headers: {
2407
+ "Onplo-Request-Id": components["headers"]["OnploRequestId"];
2408
+ [name: string]: unknown;
2409
+ };
2410
+ content: {
2411
+ "application/json": components["schemas"]["Recovery"];
2412
+ };
2413
+ };
2414
+ 400: components["responses"]["BadRequest"];
2415
+ /**
2416
+ * @description Refused. `recovery_not_verified`: the username and code did not prove a person, and why is
2417
+ * never said.
2418
+ */
2419
+ 409: {
2420
+ headers: {
2421
+ "Onplo-Request-Id": components["headers"]["OnploRequestId"];
2422
+ [name: string]: unknown;
2423
+ };
2424
+ content: {
2425
+ "application/problem+json": components["schemas"]["Problem"] & {
2426
+ /** @enum {unknown} */
2427
+ code?: "recovery_not_verified";
2428
+ };
2429
+ };
2430
+ };
2431
+ 413: components["responses"]["ContentTooLarge"];
2432
+ 415: components["responses"]["UnsupportedMediaType"];
2433
+ 422: components["responses"]["Unprocessable"];
2434
+ 429: components["responses"]["TooManyCalls"];
2435
+ 500: components["responses"]["ServerError"];
2436
+ 501: components["responses"]["NotImplemented"];
2437
+ };
2438
+ };
2439
+ completeRecovery: {
2440
+ parameters: {
2441
+ query?: never;
2442
+ header?: never;
2443
+ path: {
2444
+ recovery_id: components["parameters"]["RecoveryId"];
2445
+ };
2446
+ cookie?: never;
2447
+ };
2448
+ requestBody: {
2449
+ content: {
2450
+ "application/json": components["schemas"]["RecoveryCompletion"];
2451
+ };
2452
+ };
2453
+ responses: {
2454
+ /** @description Back in. Where the person may go, and the token that opens one session. Sent with `no-store`. */
2455
+ 200: {
2456
+ headers: {
2457
+ "Onplo-Request-Id": components["headers"]["OnploRequestId"];
2458
+ "Cache-Control": components["headers"]["CacheControl"];
2459
+ [name: string]: unknown;
2460
+ };
2461
+ content: {
2462
+ "application/json": components["schemas"]["SignInChoices"];
2463
+ };
2464
+ };
2465
+ 400: components["responses"]["BadRequest"];
2466
+ 404: components["responses"]["NotFound"];
2467
+ /**
2468
+ * @description Refused, and the recovery is spent. `passkey_not_verified`: the answer did not prove a new
2469
+ * key Onplo will keep. `already_registered`: that key is kept already.
2470
+ */
2471
+ 409: {
2472
+ headers: {
2473
+ "Onplo-Request-Id": components["headers"]["OnploRequestId"];
2474
+ [name: string]: unknown;
2475
+ };
2476
+ content: {
2477
+ "application/problem+json": components["schemas"]["Problem"] & {
2478
+ /** @enum {unknown} */
2479
+ code?: "passkey_not_verified" | "already_registered";
2480
+ };
2481
+ };
2482
+ };
2483
+ 413: components["responses"]["ContentTooLarge"];
2484
+ 415: components["responses"]["UnsupportedMediaType"];
2485
+ 422: components["responses"]["Unprocessable"];
2486
+ 429: components["responses"]["TooManyCalls"];
2487
+ 500: components["responses"]["ServerError"];
2488
+ 501: components["responses"]["NotImplemented"];
2489
+ 503: components["responses"]["ServiceUnavailable"];
2490
+ };
2491
+ };
2492
+ }