@productcraft/auth 1.0.0 → 1.1.0
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.
- package/README.md +33 -2
- package/api.md +547 -230
- package/dist/index.cjs +868 -231
- package/dist/index.cjs.map +1 -1
- package/dist/index.d.cts +37246 -0
- package/dist/index.d.ts +1058 -263
- package/dist/index.js +868 -231
- package/dist/index.js.map +1 -1
- package/dist/testing.d.cts +32 -0
- package/manifest.json +210 -210
- package/package.json +25 -8
package/api.md
CHANGED
|
@@ -15,8 +15,11 @@ Create a new app owned by the caller.
|
|
|
15
15
|
|
|
16
16
|
The new app starts with emails to its users turned on: they go out from the workspace default sender chosen in Mail, and the default verification, welcome, password-reset, invite and sign-in code templates are created in the workspace's Mail templates (an existing template with the same name is reused). Change or turn this off with `PATCH /v1/apps/{appId}/notification-settings`.
|
|
17
17
|
|
|
18
|
+
**Sign-up starts off.** A new app has `signup_enabled: false`, so `POST /{app_slug}/v1/auth/signup` answers 403 `FORBIDDEN` ("Signup is disabled for this app") until you turn it on with `PATCH /v1/apps/{app_id}/auth-config` and `{ "signup_enabled": true }`. Sign-in, invites and admin-created users work either way.
|
|
19
|
+
|
|
18
20
|
- Params: `Auth.AppCreateParams`
|
|
19
21
|
- Idempotent: an `Idempotency-Key` is sent automatically and reused on retries
|
|
22
|
+
- Credential: [`workspace_key`](#workspace_key)
|
|
20
23
|
|
|
21
24
|
| Status | Error class | Codes | When |
|
|
22
25
|
|---|---|---|---|
|
|
@@ -42,6 +45,8 @@ const app = await auth.apps.create({
|
|
|
42
45
|
|
|
43
46
|
Delete an app permanently.
|
|
44
47
|
|
|
48
|
+
- Credential: [`workspace_key`](#workspace_key)
|
|
49
|
+
|
|
45
50
|
| Status | Error class | Codes | When |
|
|
46
51
|
|---|---|---|---|
|
|
47
52
|
| 401 | `AuthenticationError` | `UNAUTHORIZED` | Missing, invalid or expired bearer token. |
|
|
@@ -50,7 +55,7 @@ Delete an app permanently.
|
|
|
50
55
|
| 429 | `RateLimitError` | `RATE_LIMITED` | Rate limited: too many requests from this client IP in the last 60 seconds (`RATE_LIMITED`); wait `Retry-After` seconds. |
|
|
51
56
|
|
|
52
57
|
```ts
|
|
53
|
-
await auth.apps.delete("
|
|
58
|
+
await auth.apps.delete("3f0c3c1e-8a2b-4c55-9d3f-0a1b2c3d4e5f");
|
|
54
59
|
```
|
|
55
60
|
|
|
56
61
|
[HTTP reference](https://productcraft.co/docs/auth/api-reference#delete-v1-apps-app-id)
|
|
@@ -63,6 +68,7 @@ List apps in workspaces the caller is a member of. Pass `workspace_id` to scope
|
|
|
63
68
|
|
|
64
69
|
- Params: `Auth.AppListParams`
|
|
65
70
|
- Paginated: `for await` iterates every item; `await` gives one page
|
|
71
|
+
- Credential: [`workspace_key`](#workspace_key)
|
|
66
72
|
|
|
67
73
|
| Status | Error class | Codes | When |
|
|
68
74
|
|---|---|---|---|
|
|
@@ -85,6 +91,8 @@ const page = await auth.apps.list({}, { timeout: 5_000 });
|
|
|
85
91
|
|
|
86
92
|
Get app details.
|
|
87
93
|
|
|
94
|
+
- Credential: [`workspace_key`](#workspace_key)
|
|
95
|
+
|
|
88
96
|
| Status | Error class | Codes | When |
|
|
89
97
|
|---|---|---|---|
|
|
90
98
|
| 401 | `AuthenticationError` | `UNAUTHORIZED` | Missing or invalid bearer token. |
|
|
@@ -93,7 +101,7 @@ Get app details.
|
|
|
93
101
|
| 429 | `RateLimitError` | `RATE_LIMITED` | Rate limited: too many requests from this client IP in the last 60 seconds (`RATE_LIMITED`); wait `Retry-After` seconds. |
|
|
94
102
|
|
|
95
103
|
```ts
|
|
96
|
-
const app = await auth.apps.retrieve("
|
|
104
|
+
const app = await auth.apps.retrieve("3f0c3c1e-8a2b-4c55-9d3f-0a1b2c3d4e5f");
|
|
97
105
|
```
|
|
98
106
|
|
|
99
107
|
[HTTP reference](https://productcraft.co/docs/auth/api-reference#get-v1-apps-app-id)
|
|
@@ -105,6 +113,7 @@ const app = await auth.apps.retrieve("app");
|
|
|
105
113
|
Update app display name, slug, metadata, and retention settings.
|
|
106
114
|
|
|
107
115
|
- Params: `Auth.AppUpdateParams`
|
|
116
|
+
- Credential: [`workspace_key`](#workspace_key)
|
|
108
117
|
|
|
109
118
|
| Status | Error class | Codes | When |
|
|
110
119
|
|---|---|---|---|
|
|
@@ -113,7 +122,7 @@ Update app display name, slug, metadata, and retention settings.
|
|
|
113
122
|
| 429 | `RateLimitError` | `RATE_LIMITED` | Rate limited: too many requests from this client IP in the last 60 seconds (`RATE_LIMITED`); wait `Retry-After` seconds. |
|
|
114
123
|
|
|
115
124
|
```ts
|
|
116
|
-
const app = await auth.apps.update("
|
|
125
|
+
const app = await auth.apps.update("3f0c3c1e-8a2b-4c55-9d3f-0a1b2c3d4e5f", { audit_retention_days: 365 });
|
|
117
126
|
```
|
|
118
127
|
|
|
119
128
|
[HTTP reference](https://productcraft.co/docs/auth/api-reference#patch-v1-apps-app-id)
|
|
@@ -129,6 +138,7 @@ Aggregate counts for the signed-in PlatformUser.
|
|
|
129
138
|
Returns total Auth apps owned by workspaces the caller is a member of, end-users across those apps, and active API keys across those apps. Pass `workspace_id` to scope the counts to a single workspace — required from the dashboard so cross-tenant data does not bleed into the totals.
|
|
130
139
|
|
|
131
140
|
- Params: `Auth.StatsMeParams`
|
|
141
|
+
- Credential: [`workspace_key`](#workspace_key)
|
|
132
142
|
|
|
133
143
|
| Status | Error class | Codes | When |
|
|
134
144
|
|---|---|---|---|
|
|
@@ -154,6 +164,7 @@ Active end users over 1, 7 and 30 days, total and new end users, production app
|
|
|
154
164
|
Days are UTC. Counts only: no end-user identifiers. Cached for up to 60 seconds (`generated_at`).
|
|
155
165
|
|
|
156
166
|
- Params: `Auth.StatsRetrieveParams`
|
|
167
|
+
- Credential: [`workspace_key`](#workspace_key)
|
|
157
168
|
|
|
158
169
|
| Status | Error class | Codes | When |
|
|
159
170
|
|---|---|---|---|
|
|
@@ -175,6 +186,10 @@ const authWorkspaceStats = await auth.stats.retrieve();
|
|
|
175
186
|
|
|
176
187
|
Verifies the signature and returns `Auth.UnwrapWebhookEvent`. Events: `app.slug_changed`, `tenant.created`, `tenant.deleted`, `tenant.invite.accepted`, `tenant.invite.created`, `tenant.invite.revoked`, `tenant.member.added`, `tenant.member.removed`, `tenant.member.role_changed`, `tenant.updated`, `user.contact_verified`, `user.deactivated`, `user.deleted`, `user.email_verified`, `user.mfa.enrollment_required`, `user.mfa.factor_disabled`, `user.mfa.factor_enrolled`, `user.mfa.recovery_code_used`, `user.mfa.reenrollment_required`, `user.mfa.step_up_locked`, `user.mfa.step_up_succeeded`, `user.password_reset.completed`, `user.password_reset.requested`, `user.reinstated`, `user.role_changed`, `user.signin`, `user.signup`, `user.suspended`, plus `UnknownWebhookEvent` for types added later.
|
|
177
188
|
|
|
189
|
+
### `auth.webhooks.sign({ payload, secret?, id?, timestamp? })`
|
|
190
|
+
|
|
191
|
+
Signs a test event exactly as ProductCraft signs deliveries (Standard Webhooks) and returns `{ payload, headers }`, ready for `unwrap` or a request to your handler. For tests; real deliveries come signed.
|
|
192
|
+
|
|
178
193
|
## admin.app(…)
|
|
179
194
|
|
|
180
195
|
### `auth.admin.app(…).clone(params, options?)`
|
|
@@ -185,6 +200,7 @@ Create a second app in the same workspace whose configuration matches this one
|
|
|
185
200
|
|
|
186
201
|
- Params: `Auth.CloneParams`
|
|
187
202
|
- Idempotent: an `Idempotency-Key` is sent automatically and reused on retries
|
|
203
|
+
- Credential: [`workspace_key`](#workspace_key)
|
|
188
204
|
|
|
189
205
|
| Status | Error class | Codes | When |
|
|
190
206
|
|---|---|---|---|
|
|
@@ -196,7 +212,7 @@ Create a second app in the same workspace whose configuration matches this one
|
|
|
196
212
|
| 429 | `RateLimitError` | `RATE_LIMITED` | Rate limited: too many requests from this client IP in the last 60 seconds (`RATE_LIMITED`); wait `Retry-After` seconds. |
|
|
197
213
|
|
|
198
214
|
```ts
|
|
199
|
-
const cloneApp = await auth.admin.app("
|
|
215
|
+
const cloneApp = await auth.admin.app("3f0c3c1e-8a2b-4c55-9d3f-0a1b2c3d4e5f").clone({ environment: "staging", slug: "acme-app-staging" });
|
|
200
216
|
```
|
|
201
217
|
|
|
202
218
|
[HTTP reference](https://productcraft.co/docs/auth/api-reference#post-v1-apps-app-id-clone)
|
|
@@ -208,6 +224,7 @@ const cloneApp = await auth.admin.app("app").clone({ environment: "staging", slu
|
|
|
208
224
|
Update app status (active, suspended, archived).
|
|
209
225
|
|
|
210
226
|
- Params: `Auth.UpdateStatusParams`
|
|
227
|
+
- Credential: [`workspace_key`](#workspace_key)
|
|
211
228
|
|
|
212
229
|
| Status | Error class | Codes | When |
|
|
213
230
|
|---|---|---|---|
|
|
@@ -218,7 +235,7 @@ Update app status (active, suspended, archived).
|
|
|
218
235
|
| 429 | `RateLimitError` | `RATE_LIMITED` | Rate limited: too many requests from this client IP in the last 60 seconds (`RATE_LIMITED`); wait `Retry-After` seconds. |
|
|
219
236
|
|
|
220
237
|
```ts
|
|
221
|
-
const app = await auth.admin.app("
|
|
238
|
+
const app = await auth.admin.app("3f0c3c1e-8a2b-4c55-9d3f-0a1b2c3d4e5f").updateStatus({ status: "suspended" });
|
|
222
239
|
```
|
|
223
240
|
|
|
224
241
|
[HTTP reference](https://productcraft.co/docs/auth/api-reference#patch-v1-apps-app-id-status)
|
|
@@ -233,6 +250,7 @@ Mint a new hdk_live_* API key with an explicit permission scope. The raw key is
|
|
|
233
250
|
|
|
234
251
|
- Params: `Auth.ApiKeyCreateParams`
|
|
235
252
|
- Idempotent: an `Idempotency-Key` is sent automatically and reused on retries
|
|
253
|
+
- Credential: [`workspace_key`](#workspace_key)
|
|
236
254
|
|
|
237
255
|
| Status | Error class | Codes | When |
|
|
238
256
|
|---|---|---|---|
|
|
@@ -244,7 +262,7 @@ Mint a new hdk_live_* API key with an explicit permission scope. The raw key is
|
|
|
244
262
|
| 429 | `RateLimitError` | `RATE_LIMITED` | Rate limited: too many requests from this client IP in the last 60 seconds (`RATE_LIMITED`); wait `Retry-After` seconds. |
|
|
245
263
|
|
|
246
264
|
```ts
|
|
247
|
-
const createApiKey = await auth.admin.app("
|
|
265
|
+
const createApiKey = await auth.admin.app("3f0c3c1e-8a2b-4c55-9d3f-0a1b2c3d4e5f").apiKeys.create({ name: "CI deploy bot", permissions: ["user.read", "user.list"] });
|
|
248
266
|
```
|
|
249
267
|
|
|
250
268
|
[HTTP reference](https://productcraft.co/docs/auth/api-reference#post-v1-apps-app-id-api-keys)
|
|
@@ -255,6 +273,8 @@ const createApiKey = await auth.admin.app("app").apiKeys.create({ name: "CI depl
|
|
|
255
273
|
|
|
256
274
|
Revoke an API key. The key stops authenticating immediately; the row is kept (soft delete) so the list and the audit trail can still answer who revoked it and when.
|
|
257
275
|
|
|
276
|
+
- Credential: [`workspace_key`](#workspace_key)
|
|
277
|
+
|
|
258
278
|
| Status | Error class | Codes | When |
|
|
259
279
|
|---|---|---|---|
|
|
260
280
|
| 401 | `AuthenticationError` | `UNAUTHORIZED` | Missing, invalid or expired bearer token. |
|
|
@@ -262,7 +282,7 @@ Revoke an API key. The key stops authenticating immediately; the row is kept (so
|
|
|
262
282
|
| 429 | `RateLimitError` | `RATE_LIMITED` | Rate limited: too many requests from this client IP in the last 60 seconds (`RATE_LIMITED`); wait `Retry-After` seconds. |
|
|
263
283
|
|
|
264
284
|
```ts
|
|
265
|
-
await auth.admin.app("
|
|
285
|
+
await auth.admin.app("3f0c3c1e-8a2b-4c55-9d3f-0a1b2c3d4e5f").apiKeys.delete("3f0c3c1e-8a2b-4c55-9d3f-0a1b2c3d4e5f");
|
|
266
286
|
```
|
|
267
287
|
|
|
268
288
|
[HTTP reference](https://productcraft.co/docs/auth/api-reference#delete-v1-apps-app-id-api-keys-key-id)
|
|
@@ -275,6 +295,7 @@ List API keys for an app (no raw secret), newest first. Cursor-paginated: 20/pag
|
|
|
275
295
|
|
|
276
296
|
- Params: `Auth.ApiKeyListParams`
|
|
277
297
|
- Paginated: `for await` iterates every item; `await` gives one page
|
|
298
|
+
- Credential: [`workspace_key`](#workspace_key)
|
|
278
299
|
|
|
279
300
|
| Status | Error class | Codes | When |
|
|
280
301
|
|---|---|---|---|
|
|
@@ -283,10 +304,10 @@ List API keys for an app (no raw secret), newest first. Cursor-paginated: 20/pag
|
|
|
283
304
|
| 429 | `RateLimitError` | `RATE_LIMITED` | Rate limited: too many requests from this client IP in the last 60 seconds (`RATE_LIMITED`); wait `Retry-After` seconds. |
|
|
284
305
|
|
|
285
306
|
```ts
|
|
286
|
-
for await (const apiKey of auth.admin.app("
|
|
307
|
+
for await (const apiKey of auth.admin.app("3f0c3c1e-8a2b-4c55-9d3f-0a1b2c3d4e5f").apiKeys.list()) {
|
|
287
308
|
console.log(apiKey);
|
|
288
309
|
}
|
|
289
|
-
const page = await auth.admin.app("
|
|
310
|
+
const page = await auth.admin.app("3f0c3c1e-8a2b-4c55-9d3f-0a1b2c3d4e5f").apiKeys.list({}, { timeout: 5_000 });
|
|
290
311
|
```
|
|
291
312
|
|
|
292
313
|
[HTTP reference](https://productcraft.co/docs/auth/api-reference#get-v1-apps-app-id-api-keys)
|
|
@@ -299,6 +320,7 @@ Mint a replacement for an existing key, carrying its name and permissions over.
|
|
|
299
320
|
|
|
300
321
|
- Params: `Auth.ApiKeyRotateParams`
|
|
301
322
|
- Idempotent: an `Idempotency-Key` is sent automatically and reused on retries
|
|
323
|
+
- Credential: [`workspace_key`](#workspace_key)
|
|
302
324
|
|
|
303
325
|
| Status | Error class | Codes | When |
|
|
304
326
|
|---|---|---|---|
|
|
@@ -308,7 +330,7 @@ Mint a replacement for an existing key, carrying its name and permissions over.
|
|
|
308
330
|
| 429 | `RateLimitError` | `RATE_LIMITED` | Rate limited: too many requests from this client IP in the last 60 seconds (`RATE_LIMITED`); wait `Retry-After` seconds. |
|
|
309
331
|
|
|
310
332
|
```ts
|
|
311
|
-
const rotateApiKey = await auth.admin.app("
|
|
333
|
+
const rotateApiKey = await auth.admin.app("3f0c3c1e-8a2b-4c55-9d3f-0a1b2c3d4e5f").apiKeys.rotate("3f0c3c1e-8a2b-4c55-9d3f-0a1b2c3d4e5f", { grace_hours: 24 });
|
|
312
334
|
```
|
|
313
335
|
|
|
314
336
|
[HTTP reference](https://productcraft.co/docs/auth/api-reference#post-v1-apps-app-id-api-keys-key-id-rotate)
|
|
@@ -324,6 +346,7 @@ Stream this app's audit log as NDJSON or CSV, applying the same `?action=` / `?a
|
|
|
324
346
|
The response is streamed: rows are walked in keyset batches and written as they are read, so neither the service nor the client has to hold the whole result set. Works on both lanes — a platform bearer token and a `pcft_live_*` Platform API Key with `auth.audit.read` hit the same route. Hard cap of 1,000,000 rows per call; a wider request is refused with 413 before any body is written, so a truncated file can never masquerade as a complete one.
|
|
325
347
|
|
|
326
348
|
- Params: `Auth.AuditLogExportParams`
|
|
349
|
+
- Credential: [`workspace_key`](#workspace_key)
|
|
327
350
|
|
|
328
351
|
| Status | Error class | Codes | When |
|
|
329
352
|
|---|---|---|---|
|
|
@@ -335,7 +358,7 @@ The response is streamed: rows are walked in keyset batches and written as they
|
|
|
335
358
|
| 429 | `RateLimitError` | `RATE_LIMITED` | Rate limited: too many requests from this client IP in the last 60 seconds (`RATE_LIMITED`); wait `Retry-After` seconds. |
|
|
336
359
|
|
|
337
360
|
```ts
|
|
338
|
-
const response = await auth.admin.app("
|
|
361
|
+
const response = await auth.admin.app("3f0c3c1e-8a2b-4c55-9d3f-0a1b2c3d4e5f").auditLogs.export();
|
|
339
362
|
const text = await response.text();
|
|
340
363
|
```
|
|
341
364
|
|
|
@@ -349,6 +372,7 @@ Append-only audit log for this app, newest first. Filter by `?action=`, `?actor_
|
|
|
349
372
|
|
|
350
373
|
- Params: `Auth.AuditLogListParams`
|
|
351
374
|
- Paginated: `for await` iterates every item; `await` gives one page
|
|
375
|
+
- Credential: [`workspace_key`](#workspace_key)
|
|
352
376
|
|
|
353
377
|
| Status | Error class | Codes | When |
|
|
354
378
|
|---|---|---|---|
|
|
@@ -359,10 +383,10 @@ Append-only audit log for this app, newest first. Filter by `?action=`, `?actor_
|
|
|
359
383
|
| 429 | `RateLimitError` | `RATE_LIMITED` | Rate limited: too many requests from this client IP in the last 60 seconds (`RATE_LIMITED`); wait `Retry-After` seconds. |
|
|
360
384
|
|
|
361
385
|
```ts
|
|
362
|
-
for await (const auditLog of auth.admin.app("
|
|
386
|
+
for await (const auditLog of auth.admin.app("3f0c3c1e-8a2b-4c55-9d3f-0a1b2c3d4e5f").auditLogs.list()) {
|
|
363
387
|
console.log(auditLog);
|
|
364
388
|
}
|
|
365
|
-
const page = await auth.admin.app("
|
|
389
|
+
const page = await auth.admin.app("3f0c3c1e-8a2b-4c55-9d3f-0a1b2c3d4e5f").auditLogs.list({}, { timeout: 5_000 });
|
|
366
390
|
```
|
|
367
391
|
|
|
368
392
|
[HTTP reference](https://productcraft.co/docs/auth/api-reference#get-v1-apps-app-id-audit-logs)
|
|
@@ -375,6 +399,8 @@ const page = await auth.admin.app("app").auditLogs.list({}, { timeout: 5_000 });
|
|
|
375
399
|
|
|
376
400
|
Remove the audit sink. Shipping stops immediately; the audit log itself is untouched.
|
|
377
401
|
|
|
402
|
+
- Credential: [`workspace_key`](#workspace_key)
|
|
403
|
+
|
|
378
404
|
| Status | Error class | Codes | When |
|
|
379
405
|
|---|---|---|---|
|
|
380
406
|
| 401 | `AuthenticationError` | `UNAUTHORIZED` | Missing, invalid or expired bearer token. |
|
|
@@ -383,7 +409,7 @@ Remove the audit sink. Shipping stops immediately; the audit log itself is untou
|
|
|
383
409
|
| 429 | `RateLimitError` | `RATE_LIMITED` | Rate limited: too many requests from this client IP in the last 60 seconds (`RATE_LIMITED`); wait `Retry-After` seconds. |
|
|
384
410
|
|
|
385
411
|
```ts
|
|
386
|
-
await auth.admin.app("
|
|
412
|
+
await auth.admin.app("3f0c3c1e-8a2b-4c55-9d3f-0a1b2c3d4e5f").auditSink.disconnect();
|
|
387
413
|
```
|
|
388
414
|
|
|
389
415
|
[HTTP reference](https://productcraft.co/docs/auth/api-reference#delete-v1-apps-app-id-audit-sink)
|
|
@@ -397,6 +423,7 @@ Create or replace the audit sink. Returns a freshly generated signing secret exa
|
|
|
397
423
|
Audit rows are POSTed in batches of up to 100, signed with the same `X-Auth-Signature: t=<unix>,v1=<hex>` HMAC header as the outbound webhooks. Delivery is at-least-once: the cursor advances only after a 2xx, so a batch that times out after the receiver processed it is re-sent. Every record carries its immutable `audit_log` id, so dedupe on that. A new sink starts from the moment it is created — configuring one does not replay the existing history into your SIEM. Replacing an existing sink clears the auto-disabled state (the same "I fixed my receiver" signal a webhook PUT carries) but does NOT rewind the cursor.
|
|
398
424
|
|
|
399
425
|
- Params: `Auth.AuditSinkReplaceParams`
|
|
426
|
+
- Credential: [`workspace_key`](#workspace_key)
|
|
400
427
|
|
|
401
428
|
| Status | Error class | Codes | When |
|
|
402
429
|
|---|---|---|---|
|
|
@@ -407,7 +434,7 @@ Audit rows are POSTed in batches of up to 100, signed with the same `X-Auth-Sign
|
|
|
407
434
|
| 429 | `RateLimitError` | `RATE_LIMITED` | Rate limited: too many requests from this client IP in the last 60 seconds (`RATE_LIMITED`); wait `Retry-After` seconds. |
|
|
408
435
|
|
|
409
436
|
```ts
|
|
410
|
-
const auditSinkWithSecret = await auth.admin.app("
|
|
437
|
+
const auditSinkWithSecret = await auth.admin.app("3f0c3c1e-8a2b-4c55-9d3f-0a1b2c3d4e5f").auditSink.replace({ url: "https://siem.customer.example.com/ingest/productcraft-auth" });
|
|
411
438
|
```
|
|
412
439
|
|
|
413
440
|
[HTTP reference](https://productcraft.co/docs/auth/api-reference#put-v1-apps-app-id-audit-sink)
|
|
@@ -418,6 +445,8 @@ const auditSinkWithSecret = await auth.admin.app("app").auditSink.replace({ url:
|
|
|
418
445
|
|
|
419
446
|
Current audit sink for this app, or 404 when none is configured. Never returns the signing secret — only its last-4 hint.
|
|
420
447
|
|
|
448
|
+
- Credential: [`workspace_key`](#workspace_key)
|
|
449
|
+
|
|
421
450
|
| Status | Error class | Codes | When |
|
|
422
451
|
|---|---|---|---|
|
|
423
452
|
| 401 | `AuthenticationError` | `UNAUTHORIZED` | Missing, invalid or expired bearer token. |
|
|
@@ -426,7 +455,7 @@ Current audit sink for this app, or 404 when none is configured. Never returns t
|
|
|
426
455
|
| 429 | `RateLimitError` | `RATE_LIMITED` | Rate limited: too many requests from this client IP in the last 60 seconds (`RATE_LIMITED`); wait `Retry-After` seconds. |
|
|
427
456
|
|
|
428
457
|
```ts
|
|
429
|
-
const auditSink = await auth.admin.app("
|
|
458
|
+
const auditSink = await auth.admin.app("3f0c3c1e-8a2b-4c55-9d3f-0a1b2c3d4e5f").auditSink.retrieve();
|
|
430
459
|
```
|
|
431
460
|
|
|
432
461
|
[HTTP reference](https://productcraft.co/docs/auth/api-reference#get-v1-apps-app-id-audit-sink)
|
|
@@ -439,6 +468,8 @@ Issue a new signing secret, returned exactly once.
|
|
|
439
468
|
|
|
440
469
|
The new secret signs every batch from now on; the old one stops at once. Update your receiver right away: batches it rejects in between are retried every minute (the position only moves after a 2xx), so nothing is lost, but export stops after 20 failures in a row. Clears the receiver-test proof.
|
|
441
470
|
|
|
471
|
+
- Credential: [`workspace_key`](#workspace_key)
|
|
472
|
+
|
|
442
473
|
| Status | Error class | Codes | When |
|
|
443
474
|
|---|---|---|---|
|
|
444
475
|
| 401 | `AuthenticationError` | `UNAUTHORIZED` | Missing, invalid or expired bearer token. |
|
|
@@ -447,7 +478,7 @@ The new secret signs every batch from now on; the old one stops at once. Update
|
|
|
447
478
|
| 429 | `RateLimitError` | `RATE_LIMITED` | Rate limited: too many requests from this client IP in the last 60 seconds (`RATE_LIMITED`); wait `Retry-After` seconds. |
|
|
448
479
|
|
|
449
480
|
```ts
|
|
450
|
-
const auditSinkWithSecret = await auth.admin.app("
|
|
481
|
+
const auditSinkWithSecret = await auth.admin.app("3f0c3c1e-8a2b-4c55-9d3f-0a1b2c3d4e5f").auditSink.rotateSecret();
|
|
451
482
|
```
|
|
452
483
|
|
|
453
484
|
[HTTP reference](https://productcraft.co/docs/auth/api-reference#post-v1-apps-app-id-audit-sink-rotate-secret)
|
|
@@ -460,6 +491,8 @@ Get the audit export checklist: destination, receiver test and delivery.
|
|
|
460
491
|
|
|
461
492
|
Rows, in order: `destination` (not_set until a sink exists), `test_batch` (pass once the receiver accepted a test batch with the current address and secret; blocked when the last test was refused; carries `test.action: audit_sink.test`, run with `POST /v1/apps/{appId}/audit-sink/test`), and `delivery` (blocked when export stopped after repeated failures, attention while paused or while recent batches fail). Computed from the stored sink on every request; answers 200 whether or not a sink exists.
|
|
462
493
|
|
|
494
|
+
- Credential: [`workspace_key`](#workspace_key)
|
|
495
|
+
|
|
463
496
|
| Status | Error class | Codes | When |
|
|
464
497
|
|---|---|---|---|
|
|
465
498
|
| 401 | `AuthenticationError` | `UNAUTHORIZED` | Missing, invalid or expired bearer token. |
|
|
@@ -468,7 +501,7 @@ Rows, in order: `destination` (not_set until a sink exists), `test_batch` (pass
|
|
|
468
501
|
| 429 | `RateLimitError` | `RATE_LIMITED` | Rate limited: too many requests from this client IP in the last 60 seconds (`RATE_LIMITED`); wait `Retry-After` seconds. |
|
|
469
502
|
|
|
470
503
|
```ts
|
|
471
|
-
const setupStatus = await auth.admin.app("
|
|
504
|
+
const setupStatus = await auth.admin.app("3f0c3c1e-8a2b-4c55-9d3f-0a1b2c3d4e5f").auditSink.setupStatus();
|
|
472
505
|
```
|
|
473
506
|
|
|
474
507
|
[HTTP reference](https://productcraft.co/docs/auth/api-reference#get-v1-apps-app-id-audit-sink-setup-status)
|
|
@@ -482,6 +515,7 @@ Send a test batch to the receiver now and report what it answered.
|
|
|
482
515
|
POSTs one signed batch, shaped exactly like a real one (`type: audit.batch`, same headers and signature), with `test: true` and a single synthetic record whose `id` starts with `test_`. Works while export is paused or stopped, so a fix can be proven before export is turned back on. The outcome is recorded on the sink (`last_attempt_*`, `last_test_succeeded_at`) but never moves the position in the audit log or counts toward the automatic stop. A refused test is still a 200 with `delivered: false`. At most 20 tests per app per hour.
|
|
483
516
|
|
|
484
517
|
- Idempotent: an `Idempotency-Key` is sent automatically and reused on retries
|
|
518
|
+
- Credential: [`workspace_key`](#workspace_key)
|
|
485
519
|
|
|
486
520
|
| Status | Error class | Codes | When |
|
|
487
521
|
|---|---|---|---|
|
|
@@ -492,7 +526,7 @@ POSTs one signed batch, shaped exactly like a real one (`type: audit.batch`, sam
|
|
|
492
526
|
| 429 | `RateLimitError` | `RATE_LIMITED` | More than 20 tests for this app in the last hour (`RATE_LIMITED`). |
|
|
493
527
|
|
|
494
528
|
```ts
|
|
495
|
-
const auditSinkTestResult = await auth.admin.app("
|
|
529
|
+
const auditSinkTestResult = await auth.admin.app("3f0c3c1e-8a2b-4c55-9d3f-0a1b2c3d4e5f").auditSink.test();
|
|
496
530
|
```
|
|
497
531
|
|
|
498
532
|
[HTTP reference](https://productcraft.co/docs/auth/api-reference#post-v1-apps-app-id-audit-sink-test)
|
|
@@ -506,6 +540,7 @@ Change the address or switch export on or off, keeping the signing secret.
|
|
|
506
540
|
Send `url`, `enabled` or both. `enabled: false` pauses export; `enabled: true` resumes it and clears a stop after repeated failures and the failure count. The position in the audit log is never moved: nothing is skipped and nothing is replayed twice on purpose. A new `url` is checked by the same address guard as `PUT`.
|
|
507
541
|
|
|
508
542
|
- Params: `Auth.AuditSinkUpdateParams`
|
|
543
|
+
- Credential: [`workspace_key`](#workspace_key)
|
|
509
544
|
|
|
510
545
|
| Status | Error class | Codes | When |
|
|
511
546
|
|---|---|---|---|
|
|
@@ -516,7 +551,7 @@ Send `url`, `enabled` or both. `enabled: false` pauses export; `enabled: true` r
|
|
|
516
551
|
| 429 | `RateLimitError` | `RATE_LIMITED` | Rate limited: too many requests from this client IP in the last 60 seconds (`RATE_LIMITED`); wait `Retry-After` seconds. |
|
|
517
552
|
|
|
518
553
|
```ts
|
|
519
|
-
const auditSink = await auth.admin.app("
|
|
554
|
+
const auditSink = await auth.admin.app("3f0c3c1e-8a2b-4c55-9d3f-0a1b2c3d4e5f").auditSink.update({ enabled: true });
|
|
520
555
|
```
|
|
521
556
|
|
|
522
557
|
[HTTP reference](https://productcraft.co/docs/auth/api-reference#patch-v1-apps-app-id-audit-sink)
|
|
@@ -529,6 +564,8 @@ const auditSink = await auth.admin.app("app").auditSink.update({ enabled: true }
|
|
|
529
564
|
|
|
530
565
|
Get the per-app auth config (signup, signin, password policy, sessions).
|
|
531
566
|
|
|
567
|
+
- Credential: [`workspace_key`](#workspace_key)
|
|
568
|
+
|
|
532
569
|
| Status | Error class | Codes | When |
|
|
533
570
|
|---|---|---|---|
|
|
534
571
|
| 401 | `AuthenticationError` | `UNAUTHORIZED` | Missing or invalid bearer token. |
|
|
@@ -537,7 +574,7 @@ Get the per-app auth config (signup, signin, password policy, sessions).
|
|
|
537
574
|
| 429 | `RateLimitError` | `RATE_LIMITED` | Rate limited: too many requests from this client IP in the last 60 seconds (`RATE_LIMITED`); wait `Retry-After` seconds. |
|
|
538
575
|
|
|
539
576
|
```ts
|
|
540
|
-
const authConfig = await auth.admin.app("
|
|
577
|
+
const authConfig = await auth.admin.app("3f0c3c1e-8a2b-4c55-9d3f-0a1b2c3d4e5f").authConfig.retrieve();
|
|
541
578
|
```
|
|
542
579
|
|
|
543
580
|
[HTTP reference](https://productcraft.co/docs/auth/api-reference#get-v1-apps-app-id-auth-config)
|
|
@@ -549,6 +586,7 @@ const authConfig = await auth.admin.app("app").authConfig.retrieve();
|
|
|
549
586
|
Update the per-app auth config. Only fields you pass are changed.
|
|
550
587
|
|
|
551
588
|
- Params: `Auth.AuthConfigUpdateParams`
|
|
589
|
+
- Credential: [`workspace_key`](#workspace_key)
|
|
552
590
|
|
|
553
591
|
| Status | Error class | Codes | When |
|
|
554
592
|
|---|---|---|---|
|
|
@@ -560,7 +598,7 @@ Update the per-app auth config. Only fields you pass are changed.
|
|
|
560
598
|
| 429 | `RateLimitError` | `RATE_LIMITED` | Rate limited: too many requests from this client IP in the last 60 seconds (`RATE_LIMITED`); wait `Retry-After` seconds. |
|
|
561
599
|
|
|
562
600
|
```ts
|
|
563
|
-
const authConfig = await auth.admin.app("
|
|
601
|
+
const authConfig = await auth.admin.app("3f0c3c1e-8a2b-4c55-9d3f-0a1b2c3d4e5f").authConfig.update({ access_token_minutes: 60 });
|
|
564
602
|
```
|
|
565
603
|
|
|
566
604
|
[HTTP reference](https://productcraft.co/docs/auth/api-reference#patch-v1-apps-app-id-auth-config)
|
|
@@ -575,6 +613,8 @@ Check the saved provider credentials with the provider.
|
|
|
575
613
|
|
|
576
614
|
Calls the provider's token endpoint with a dummy sign-in code. If the provider refuses the client (`invalid_client`, GitHub `incorrect_client_credentials` or `unknown_client`), the result is `credentials_rejected` and the provider shows as `blocked` with reason `credentials_rejected` until the credentials are fixed. If it only refuses the code (`invalid_grant`, `bad_verification_code`), the credentials are valid. Nobody is signed in. The result is saved on the provider (`last_check_*`). The same check runs automatically whenever the credentials are saved. Works for a provider that is saved but not switched on yet.
|
|
577
615
|
|
|
616
|
+
- Credential: [`workspace_key`](#workspace_key)
|
|
617
|
+
|
|
578
618
|
| Status | Error class | Codes | When |
|
|
579
619
|
|---|---|---|---|
|
|
580
620
|
| 400 | `BadRequestError` | `BAD_REQUEST`, `VALIDATION_ERROR` | Unknown provider id, or the saved config can no longer be read. |
|
|
@@ -584,7 +624,7 @@ Calls the provider's token endpoint with a dummy sign-in code. If the provider r
|
|
|
584
624
|
| 429 | `RateLimitError` | `RATE_LIMITED` | Rate limited: too many requests from this client IP in the last 60 seconds (`RATE_LIMITED`); wait `Retry-After` seconds. |
|
|
585
625
|
|
|
586
626
|
```ts
|
|
587
|
-
const providerCheck = await auth.admin.app("
|
|
627
|
+
const providerCheck = await auth.admin.app("3f0c3c1e-8a2b-4c55-9d3f-0a1b2c3d4e5f").authConfig.providers.check("google");
|
|
588
628
|
```
|
|
589
629
|
|
|
590
630
|
[HTTP reference](https://productcraft.co/docs/auth/api-reference#post-v1-apps-app-id-auth-config-providers-provider-check)
|
|
@@ -595,6 +635,8 @@ const providerCheck = await auth.admin.app("app").authConfig.providers.check("pr
|
|
|
595
635
|
|
|
596
636
|
Remove the config for an (app, provider). Existing identity rows (people who already signed in with this provider) stay; they just lose the ability to sign in again until config is re-uploaded.
|
|
597
637
|
|
|
638
|
+
- Credential: [`workspace_key`](#workspace_key)
|
|
639
|
+
|
|
598
640
|
| Status | Error class | Codes | When |
|
|
599
641
|
|---|---|---|---|
|
|
600
642
|
| 400 | `BadRequestError` | `BAD_REQUEST`, `VALIDATION_ERROR` | Unknown provider id. |
|
|
@@ -602,7 +644,7 @@ Remove the config for an (app, provider). Existing identity rows (people who alr
|
|
|
602
644
|
| 429 | `RateLimitError` | `RATE_LIMITED` | Rate limited: too many requests from this client IP in the last 60 seconds (`RATE_LIMITED`); wait `Retry-After` seconds. |
|
|
603
645
|
|
|
604
646
|
```ts
|
|
605
|
-
await auth.admin.app("
|
|
647
|
+
await auth.admin.app("3f0c3c1e-8a2b-4c55-9d3f-0a1b2c3d4e5f").authConfig.providers.delete("google");
|
|
606
648
|
```
|
|
607
649
|
|
|
608
650
|
[HTTP reference](https://productcraft.co/docs/auth/api-reference#delete-v1-apps-app-id-auth-config-providers-provider)
|
|
@@ -615,6 +657,8 @@ List federated sign-in providers Auth supports, with their setup status for this
|
|
|
615
657
|
|
|
616
658
|
Each entry carries `status` (`ready` | `blocked` | `disabled` | `not_configured`) and `blocked_reasons`, computed on the server with the same rule the web sign-in flow enforces, so a provider shown as `ready` is one people can actually sign in with.
|
|
617
659
|
|
|
660
|
+
- Credential: [`workspace_key`](#workspace_key)
|
|
661
|
+
|
|
618
662
|
| Status | Error class | Codes | When |
|
|
619
663
|
|---|---|---|---|
|
|
620
664
|
| 401 | `AuthenticationError` | `UNAUTHORIZED` | Missing or invalid bearer token. |
|
|
@@ -623,7 +667,7 @@ Each entry carries `status` (`ready` | `blocked` | `disabled` | `not_configured`
|
|
|
623
667
|
| 429 | `RateLimitError` | `RATE_LIMITED` | Rate limited: too many requests from this client IP in the last 60 seconds (`RATE_LIMITED`); wait `Retry-After` seconds. |
|
|
624
668
|
|
|
625
669
|
```ts
|
|
626
|
-
const result = await auth.admin.app("
|
|
670
|
+
const result = await auth.admin.app("3f0c3c1e-8a2b-4c55-9d3f-0a1b2c3d4e5f").authConfig.providers.list();
|
|
627
671
|
```
|
|
628
672
|
|
|
629
673
|
[HTTP reference](https://productcraft.co/docs/auth/api-reference#get-v1-apps-app-id-auth-config-providers)
|
|
@@ -635,6 +679,7 @@ const result = await auth.admin.app("app").authConfig.providers.list();
|
|
|
635
679
|
Write or replace the config for an (app, provider). Validates the body via the provider impl's `parseConfig` before encrypting; malformed config 400s. Default `enabled=false`.
|
|
636
680
|
|
|
637
681
|
- Params: `Auth.AuthConfigProviderReplaceParams`
|
|
682
|
+
- Credential: [`workspace_key`](#workspace_key)
|
|
638
683
|
|
|
639
684
|
| Status | Error class | Codes | When |
|
|
640
685
|
|---|---|---|---|
|
|
@@ -643,7 +688,7 @@ Write or replace the config for an (app, provider). Validates the body via the p
|
|
|
643
688
|
| 429 | `RateLimitError` | `RATE_LIMITED` | Rate limited: too many requests from this client IP in the last 60 seconds (`RATE_LIMITED`); wait `Retry-After` seconds. |
|
|
644
689
|
|
|
645
690
|
```ts
|
|
646
|
-
const providerDetail = await auth.admin.app("
|
|
691
|
+
const providerDetail = await auth.admin.app("3f0c3c1e-8a2b-4c55-9d3f-0a1b2c3d4e5f").authConfig.providers.replace("google", { config: {} });
|
|
647
692
|
```
|
|
648
693
|
|
|
649
694
|
[HTTP reference](https://productcraft.co/docs/auth/api-reference#put-v1-apps-app-id-auth-config-providers-provider)
|
|
@@ -654,6 +699,8 @@ const providerDetail = await auth.admin.app("app").authConfig.providers.replace(
|
|
|
654
699
|
|
|
655
700
|
Get the config for one (app, provider). Secrets are redacted — `private_key_present: true` is the only acknowledgement that a private key is on file.
|
|
656
701
|
|
|
702
|
+
- Credential: [`workspace_key`](#workspace_key)
|
|
703
|
+
|
|
657
704
|
| Status | Error class | Codes | When |
|
|
658
705
|
|---|---|---|---|
|
|
659
706
|
| 400 | `BadRequestError` | `BAD_REQUEST`, `VALIDATION_ERROR` | Unknown provider id. |
|
|
@@ -662,7 +709,7 @@ Get the config for one (app, provider). Secrets are redacted — `private_key_pr
|
|
|
662
709
|
| 429 | `RateLimitError` | `RATE_LIMITED` | Rate limited: too many requests from this client IP in the last 60 seconds (`RATE_LIMITED`); wait `Retry-After` seconds. |
|
|
663
710
|
|
|
664
711
|
```ts
|
|
665
|
-
const providerDetail = await auth.admin.app("
|
|
712
|
+
const providerDetail = await auth.admin.app("3f0c3c1e-8a2b-4c55-9d3f-0a1b2c3d4e5f").authConfig.providers.retrieve("google");
|
|
666
713
|
```
|
|
667
714
|
|
|
668
715
|
[HTTP reference](https://productcraft.co/docs/auth/api-reference#get-v1-apps-app-id-auth-config-providers-provider)
|
|
@@ -674,6 +721,7 @@ const providerDetail = await auth.admin.app("app").authConfig.providers.retrieve
|
|
|
674
721
|
Partially update the config for an (app, provider). Only top-level keys present in `config` are changed; omitted keys — secrets included — keep their stored values. The merged config is validated by the provider impl's `parseConfig`; 404 if the provider is not configured yet (create it with PUT).
|
|
675
722
|
|
|
676
723
|
- Params: `Auth.AuthConfigProviderUpdateParams`
|
|
724
|
+
- Credential: [`workspace_key`](#workspace_key)
|
|
677
725
|
|
|
678
726
|
| Status | Error class | Codes | When |
|
|
679
727
|
|---|---|---|---|
|
|
@@ -683,7 +731,7 @@ Partially update the config for an (app, provider). Only top-level keys present
|
|
|
683
731
|
| 429 | `RateLimitError` | `RATE_LIMITED` | Rate limited: too many requests from this client IP in the last 60 seconds (`RATE_LIMITED`); wait `Retry-After` seconds. |
|
|
684
732
|
|
|
685
733
|
```ts
|
|
686
|
-
const providerDetail = await auth.admin.app("
|
|
734
|
+
const providerDetail = await auth.admin.app("3f0c3c1e-8a2b-4c55-9d3f-0a1b2c3d4e5f").authConfig.providers.update("google", { config: {} });
|
|
687
735
|
```
|
|
688
736
|
|
|
689
737
|
[HTTP reference](https://productcraft.co/docs/auth/api-reference#patch-v1-apps-app-id-auth-config-providers-provider)
|
|
@@ -698,6 +746,7 @@ Create a new M2M client.
|
|
|
698
746
|
|
|
699
747
|
- Params: `Auth.CredentialCreateParams`
|
|
700
748
|
- Idempotent: an `Idempotency-Key` is sent automatically and reused on retries
|
|
749
|
+
- Credential: [`workspace_key`](#workspace_key)
|
|
701
750
|
|
|
702
751
|
| Status | Error class | Codes | When |
|
|
703
752
|
|---|---|---|---|
|
|
@@ -709,7 +758,7 @@ Create a new M2M client.
|
|
|
709
758
|
| 429 | `RateLimitError` | `RATE_LIMITED` | Rate limited: too many requests from this client IP in the last 60 seconds (`RATE_LIMITED`); wait `Retry-After` seconds. |
|
|
710
759
|
|
|
711
760
|
```ts
|
|
712
|
-
const m2mClientCreate = await auth.admin.app("
|
|
761
|
+
const m2mClientCreate = await auth.admin.app("3f0c3c1e-8a2b-4c55-9d3f-0a1b2c3d4e5f").credentials.create({ name: "CI Pipeline" });
|
|
713
762
|
```
|
|
714
763
|
|
|
715
764
|
[HTTP reference](https://productcraft.co/docs/auth/api-reference#post-v1-apps-app-id-credentials)
|
|
@@ -720,6 +769,8 @@ const m2mClientCreate = await auth.admin.app("app").credentials.create({ name: "
|
|
|
720
769
|
|
|
721
770
|
Delete an M2M client.
|
|
722
771
|
|
|
772
|
+
- Credential: [`workspace_key`](#workspace_key)
|
|
773
|
+
|
|
723
774
|
| Status | Error class | Codes | When |
|
|
724
775
|
|---|---|---|---|
|
|
725
776
|
| 401 | `AuthenticationError` | `UNAUTHORIZED` | Missing, invalid or expired bearer token. |
|
|
@@ -728,7 +779,7 @@ Delete an M2M client.
|
|
|
728
779
|
| 429 | `RateLimitError` | `RATE_LIMITED` | Rate limited: too many requests from this client IP in the last 60 seconds (`RATE_LIMITED`); wait `Retry-After` seconds. |
|
|
729
780
|
|
|
730
781
|
```ts
|
|
731
|
-
await auth.admin.app("
|
|
782
|
+
await auth.admin.app("3f0c3c1e-8a2b-4c55-9d3f-0a1b2c3d4e5f").credentials.delete("m2m_a1b2c3d4e5f6");
|
|
732
783
|
```
|
|
733
784
|
|
|
734
785
|
[HTTP reference](https://productcraft.co/docs/auth/api-reference#delete-v1-apps-app-id-credentials-client-id)
|
|
@@ -741,6 +792,7 @@ List M2M clients.
|
|
|
741
792
|
|
|
742
793
|
- Params: `Auth.CredentialListParams`
|
|
743
794
|
- Paginated: `for await` iterates every item; `await` gives one page
|
|
795
|
+
- Credential: [`workspace_key`](#workspace_key)
|
|
744
796
|
|
|
745
797
|
| Status | Error class | Codes | When |
|
|
746
798
|
|---|---|---|---|
|
|
@@ -750,10 +802,10 @@ List M2M clients.
|
|
|
750
802
|
| 429 | `RateLimitError` | `RATE_LIMITED` | Rate limited: too many requests from this client IP in the last 60 seconds (`RATE_LIMITED`); wait `Retry-After` seconds. |
|
|
751
803
|
|
|
752
804
|
```ts
|
|
753
|
-
for await (const credential of auth.admin.app("
|
|
805
|
+
for await (const credential of auth.admin.app("3f0c3c1e-8a2b-4c55-9d3f-0a1b2c3d4e5f").credentials.list()) {
|
|
754
806
|
console.log(credential);
|
|
755
807
|
}
|
|
756
|
-
const page = await auth.admin.app("
|
|
808
|
+
const page = await auth.admin.app("3f0c3c1e-8a2b-4c55-9d3f-0a1b2c3d4e5f").credentials.list({}, { timeout: 5_000 });
|
|
757
809
|
```
|
|
758
810
|
|
|
759
811
|
[HTTP reference](https://productcraft.co/docs/auth/api-reference#get-v1-apps-app-id-credentials)
|
|
@@ -764,6 +816,8 @@ const page = await auth.admin.app("app").credentials.list({}, { timeout: 5_000 }
|
|
|
764
816
|
|
|
765
817
|
Get M2M client details.
|
|
766
818
|
|
|
819
|
+
- Credential: [`workspace_key`](#workspace_key)
|
|
820
|
+
|
|
767
821
|
| Status | Error class | Codes | When |
|
|
768
822
|
|---|---|---|---|
|
|
769
823
|
| 401 | `AuthenticationError` | `UNAUTHORIZED` | Missing or invalid bearer token. |
|
|
@@ -772,7 +826,7 @@ Get M2M client details.
|
|
|
772
826
|
| 429 | `RateLimitError` | `RATE_LIMITED` | Rate limited: too many requests from this client IP in the last 60 seconds (`RATE_LIMITED`); wait `Retry-After` seconds. |
|
|
773
827
|
|
|
774
828
|
```ts
|
|
775
|
-
const m2mClientDetail = await auth.admin.app("
|
|
829
|
+
const m2mClientDetail = await auth.admin.app("3f0c3c1e-8a2b-4c55-9d3f-0a1b2c3d4e5f").credentials.retrieve("m2m_a1b2c3d4e5f6");
|
|
776
830
|
```
|
|
777
831
|
|
|
778
832
|
[HTTP reference](https://productcraft.co/docs/auth/api-reference#get-v1-apps-app-id-credentials-client-id)
|
|
@@ -783,6 +837,8 @@ const m2mClientDetail = await auth.admin.app("app").credentials.retrieve("client
|
|
|
783
837
|
|
|
784
838
|
Rotate M2M client secret.
|
|
785
839
|
|
|
840
|
+
- Credential: [`workspace_key`](#workspace_key)
|
|
841
|
+
|
|
786
842
|
| Status | Error class | Codes | When |
|
|
787
843
|
|---|---|---|---|
|
|
788
844
|
| 401 | `AuthenticationError` | `UNAUTHORIZED` | Missing, invalid or expired bearer token. |
|
|
@@ -791,7 +847,7 @@ Rotate M2M client secret.
|
|
|
791
847
|
| 429 | `RateLimitError` | `RATE_LIMITED` | Rate limited: too many requests from this client IP in the last 60 seconds (`RATE_LIMITED`); wait `Retry-After` seconds. |
|
|
792
848
|
|
|
793
849
|
```ts
|
|
794
|
-
const m2mRotateSecret = await auth.admin.app("
|
|
850
|
+
const m2mRotateSecret = await auth.admin.app("3f0c3c1e-8a2b-4c55-9d3f-0a1b2c3d4e5f").credentials.rotate("m2m_a1b2c3d4e5f6");
|
|
795
851
|
```
|
|
796
852
|
|
|
797
853
|
[HTTP reference](https://productcraft.co/docs/auth/api-reference#post-v1-apps-app-id-credentials-client-id-rotate)
|
|
@@ -803,6 +859,7 @@ const m2mRotateSecret = await auth.admin.app("app").credentials.rotate("client")
|
|
|
803
859
|
Update M2M client status.
|
|
804
860
|
|
|
805
861
|
- Params: `Auth.CredentialUpdateParams`
|
|
862
|
+
- Credential: [`workspace_key`](#workspace_key)
|
|
806
863
|
|
|
807
864
|
| Status | Error class | Codes | When |
|
|
808
865
|
|---|---|---|---|
|
|
@@ -813,7 +870,7 @@ Update M2M client status.
|
|
|
813
870
|
| 429 | `RateLimitError` | `RATE_LIMITED` | Rate limited: too many requests from this client IP in the last 60 seconds (`RATE_LIMITED`); wait `Retry-After` seconds. |
|
|
814
871
|
|
|
815
872
|
```ts
|
|
816
|
-
const m2mClientDetail = await auth.admin.app("
|
|
873
|
+
const m2mClientDetail = await auth.admin.app("3f0c3c1e-8a2b-4c55-9d3f-0a1b2c3d4e5f").credentials.update("m2m_a1b2c3d4e5f6", { is_active: true });
|
|
817
874
|
```
|
|
818
875
|
|
|
819
876
|
[HTTP reference](https://productcraft.co/docs/auth/api-reference#patch-v1-apps-app-id-credentials-client-id)
|
|
@@ -825,6 +882,7 @@ const m2mClientDetail = await auth.admin.app("app").credentials.update("client",
|
|
|
825
882
|
Set scopes for an M2M client.
|
|
826
883
|
|
|
827
884
|
- Params: `Auth.CredentialUpdateScopesParams`
|
|
885
|
+
- Credential: [`workspace_key`](#workspace_key)
|
|
828
886
|
|
|
829
887
|
| Status | Error class | Codes | When |
|
|
830
888
|
|---|---|---|---|
|
|
@@ -835,7 +893,7 @@ Set scopes for an M2M client.
|
|
|
835
893
|
| 429 | `RateLimitError` | `RATE_LIMITED` | Rate limited: too many requests from this client IP in the last 60 seconds (`RATE_LIMITED`); wait `Retry-After` seconds. |
|
|
836
894
|
|
|
837
895
|
```ts
|
|
838
|
-
const result = await auth.admin.app("
|
|
896
|
+
const result = await auth.admin.app("3f0c3c1e-8a2b-4c55-9d3f-0a1b2c3d4e5f").credentials.updateScopes("m2m_a1b2c3d4e5f6", { permissions: ["user.read", "app.read"] });
|
|
839
897
|
```
|
|
840
898
|
|
|
841
899
|
[HTTP reference](https://productcraft.co/docs/auth/api-reference#put-v1-apps-app-id-credentials-client-id-scopes)
|
|
@@ -852,6 +910,7 @@ Reads the zone through the provider's API and plans both records: `create`, or `
|
|
|
852
910
|
|
|
853
911
|
- Params: `Auth.CustomDomainApplyParams`
|
|
854
912
|
- Idempotent: an `Idempotency-Key` is sent automatically and reused on retries
|
|
913
|
+
- Credential: [`workspace_key`](#workspace_key)
|
|
855
914
|
|
|
856
915
|
| Status | Error class | Codes | When |
|
|
857
916
|
|---|---|---|---|
|
|
@@ -864,7 +923,7 @@ Reads the zone through the provider's API and plans both records: `create`, or `
|
|
|
864
923
|
| 502 | `InternalServerError` | `BAD_GATEWAY`, `PROVIDER_UNAVAILABLE`, `PROVIDER_ERROR` | The provider failed or did not answer (`PROVIDER_UNAVAILABLE`, `PROVIDER_ERROR`). Nothing was written unless the plan items say so. |
|
|
865
924
|
|
|
866
925
|
```ts
|
|
867
|
-
const customDomainApplyResult = await auth.admin.app("
|
|
926
|
+
const customDomainApplyResult = await auth.admin.app("3f0c3c1e-8a2b-4c55-9d3f-0a1b2c3d4e5f").customDomains.apply("3f0c3c1e-8a2b-4c55-9d3f-0a1b2c3d4e5f", { dry_run: true, provider: "cloudflare", token: "cf-token-from-your-dashboard" });
|
|
868
927
|
```
|
|
869
928
|
|
|
870
929
|
[HTTP reference](https://productcraft.co/docs/auth/api-reference#post-v1-apps-app-id-custom-domains-domain-id-apply)
|
|
@@ -877,6 +936,8 @@ Check the custom domain's DNS records now.
|
|
|
877
936
|
|
|
878
937
|
Asks the zone's own nameservers and a public resolver for both records, stores each record's state and conflicts, and moves the status: `active` once both are verified; an active domain turns `failing` only when a record is definitely gone or blocked (a DNS outage never takes a working domain down). Safe to repeat.
|
|
879
938
|
|
|
939
|
+
- Credential: [`workspace_key`](#workspace_key)
|
|
940
|
+
|
|
880
941
|
| Status | Error class | Codes | When |
|
|
881
942
|
|---|---|---|---|
|
|
882
943
|
| 400 | `BadRequestError` | `BAD_REQUEST`, `VALIDATION_ERROR` | `domainId` is not a UUID. |
|
|
@@ -886,7 +947,7 @@ Asks the zone's own nameservers and a public resolver for both records, stores e
|
|
|
886
947
|
| 429 | `RateLimitError` | `RATE_LIMITED` | Rate limited: too many requests from this client IP in the last 60 seconds (`RATE_LIMITED`); wait `Retry-After` seconds. |
|
|
887
948
|
|
|
888
949
|
```ts
|
|
889
|
-
const customDomain = await auth.admin.app("
|
|
950
|
+
const customDomain = await auth.admin.app("3f0c3c1e-8a2b-4c55-9d3f-0a1b2c3d4e5f").customDomains.check("3f0c3c1e-8a2b-4c55-9d3f-0a1b2c3d4e5f");
|
|
890
951
|
```
|
|
891
952
|
|
|
892
953
|
[HTTP reference](https://productcraft.co/docs/auth/api-reference#post-v1-apps-app-id-custom-domains-domain-id-check)
|
|
@@ -901,6 +962,7 @@ Returns the two records to publish: a CNAME from the host to `edge_target`, and
|
|
|
901
962
|
|
|
902
963
|
- Params: `Auth.CustomDomainCreateParams`
|
|
903
964
|
- Idempotent: an `Idempotency-Key` is sent automatically and reused on retries
|
|
965
|
+
- Credential: [`workspace_key`](#workspace_key)
|
|
904
966
|
|
|
905
967
|
| Status | Error class | Codes | When |
|
|
906
968
|
|---|---|---|---|
|
|
@@ -912,7 +974,7 @@ Returns the two records to publish: a CNAME from the host to `edge_target`, and
|
|
|
912
974
|
| 429 | `RateLimitError` | `RATE_LIMITED` | Rate limited: too many requests from this client IP in the last 60 seconds (`RATE_LIMITED`); wait `Retry-After` seconds. |
|
|
913
975
|
|
|
914
976
|
```ts
|
|
915
|
-
const customDomain = await auth.admin.app("
|
|
977
|
+
const customDomain = await auth.admin.app("3f0c3c1e-8a2b-4c55-9d3f-0a1b2c3d4e5f").customDomains.create({ hostname: "auth.acme.com" });
|
|
916
978
|
```
|
|
917
979
|
|
|
918
980
|
[HTTP reference](https://productcraft.co/docs/auth/api-reference#post-v1-apps-app-id-custom-domains)
|
|
@@ -925,6 +987,8 @@ Remove the custom domain.
|
|
|
925
987
|
|
|
926
988
|
The host stops serving this app at once and its certificate is no longer renewed. Your DNS records are not touched: delete the CNAME and the `_productcraft-auth` TXT record at your DNS provider. Sign-ins on the canonical host are unaffected.
|
|
927
989
|
|
|
990
|
+
- Credential: [`workspace_key`](#workspace_key)
|
|
991
|
+
|
|
928
992
|
| Status | Error class | Codes | When |
|
|
929
993
|
|---|---|---|---|
|
|
930
994
|
| 400 | `BadRequestError` | `BAD_REQUEST`, `VALIDATION_ERROR` | `domainId` is not a UUID. |
|
|
@@ -934,7 +998,7 @@ The host stops serving this app at once and its certificate is no longer renewed
|
|
|
934
998
|
| 429 | `RateLimitError` | `RATE_LIMITED` | Rate limited: too many requests from this client IP in the last 60 seconds (`RATE_LIMITED`); wait `Retry-After` seconds. |
|
|
935
999
|
|
|
936
1000
|
```ts
|
|
937
|
-
await auth.admin.app("
|
|
1001
|
+
await auth.admin.app("3f0c3c1e-8a2b-4c55-9d3f-0a1b2c3d4e5f").customDomains.delete("3f0c3c1e-8a2b-4c55-9d3f-0a1b2c3d4e5f");
|
|
938
1002
|
```
|
|
939
1003
|
|
|
940
1004
|
[HTTP reference](https://productcraft.co/docs/auth/api-reference#delete-v1-apps-app-id-custom-domains-domain-id)
|
|
@@ -948,6 +1012,7 @@ Download the custom domain's DNS records as a BIND zone fragment or a CSV.
|
|
|
948
1012
|
`format=bind`: a zone-file fragment (`$ORIGIN <zone>.`, `$TTL 3600`, names relative to the zone, a comment per record with its purpose and any conflict) that Cloudflare and Route 53 import directly. `format=csv`: `type,name,value,priority,ttl,purpose,required`, fully qualified names. By default only records not verified yet; `all=true` for both. Served as an attachment.
|
|
949
1013
|
|
|
950
1014
|
- Params: `Auth.CustomDomainExportParams`
|
|
1015
|
+
- Credential: [`workspace_key`](#workspace_key)
|
|
951
1016
|
|
|
952
1017
|
| Status | Error class | Codes | When |
|
|
953
1018
|
|---|---|---|---|
|
|
@@ -958,7 +1023,7 @@ Download the custom domain's DNS records as a BIND zone fragment or a CSV.
|
|
|
958
1023
|
| 429 | `RateLimitError` | `RATE_LIMITED` | Rate limited: too many requests from this client IP in the last 60 seconds (`RATE_LIMITED`); wait `Retry-After` seconds. |
|
|
959
1024
|
|
|
960
1025
|
```ts
|
|
961
|
-
const response = await auth.admin.app("
|
|
1026
|
+
const response = await auth.admin.app("3f0c3c1e-8a2b-4c55-9d3f-0a1b2c3d4e5f").customDomains.export("3f0c3c1e-8a2b-4c55-9d3f-0a1b2c3d4e5f", { format: "bind" });
|
|
962
1027
|
const text = await response.text();
|
|
963
1028
|
```
|
|
964
1029
|
|
|
@@ -973,6 +1038,7 @@ List the app's custom domains (at most one).
|
|
|
973
1038
|
Each with its status and the last check of its records, plus `available`: whether custom domains are switched on for the workspace. Always a single page.
|
|
974
1039
|
|
|
975
1040
|
- Paginated: `for await` iterates every item; `await` gives one page
|
|
1041
|
+
- Credential: [`workspace_key`](#workspace_key)
|
|
976
1042
|
|
|
977
1043
|
| Status | Error class | Codes | When |
|
|
978
1044
|
|---|---|---|---|
|
|
@@ -982,7 +1048,7 @@ Each with its status and the last check of its records, plus `available`: whethe
|
|
|
982
1048
|
| 429 | `RateLimitError` | `RATE_LIMITED` | Rate limited: too many requests from this client IP in the last 60 seconds (`RATE_LIMITED`); wait `Retry-After` seconds. |
|
|
983
1049
|
|
|
984
1050
|
```ts
|
|
985
|
-
for await (const customDomain of auth.admin.app("
|
|
1051
|
+
for await (const customDomain of auth.admin.app("3f0c3c1e-8a2b-4c55-9d3f-0a1b2c3d4e5f").customDomains.list()) {
|
|
986
1052
|
console.log(customDomain);
|
|
987
1053
|
}
|
|
988
1054
|
```
|
|
@@ -997,6 +1063,8 @@ Get a custom domain and the last check of its records.
|
|
|
997
1063
|
|
|
998
1064
|
Reads stored state only; `POST …/check` runs a new DNS check.
|
|
999
1065
|
|
|
1066
|
+
- Credential: [`workspace_key`](#workspace_key)
|
|
1067
|
+
|
|
1000
1068
|
| Status | Error class | Codes | When |
|
|
1001
1069
|
|---|---|---|---|
|
|
1002
1070
|
| 400 | `BadRequestError` | `BAD_REQUEST`, `VALIDATION_ERROR` | `domainId` is not a UUID. |
|
|
@@ -1006,7 +1074,7 @@ Reads stored state only; `POST …/check` runs a new DNS check.
|
|
|
1006
1074
|
| 429 | `RateLimitError` | `RATE_LIMITED` | Rate limited: too many requests from this client IP in the last 60 seconds (`RATE_LIMITED`); wait `Retry-After` seconds. |
|
|
1007
1075
|
|
|
1008
1076
|
```ts
|
|
1009
|
-
const customDomain = await auth.admin.app("
|
|
1077
|
+
const customDomain = await auth.admin.app("3f0c3c1e-8a2b-4c55-9d3f-0a1b2c3d4e5f").customDomains.retrieve("3f0c3c1e-8a2b-4c55-9d3f-0a1b2c3d4e5f");
|
|
1010
1078
|
```
|
|
1011
1079
|
|
|
1012
1080
|
[HTTP reference](https://productcraft.co/docs/auth/api-reference#get-v1-apps-app-id-custom-domains-domain-id)
|
|
@@ -1019,6 +1087,8 @@ const customDomain = await auth.admin.app("app").customDomains.retrieve("3f0c1a2
|
|
|
1019
1087
|
|
|
1020
1088
|
Auth health for this app over the last 30 days: verification completion, sign-in failure rate, MFA adoption, password-reset follow-through, and session counts. Rates are null when there is nothing to divide by.
|
|
1021
1089
|
|
|
1090
|
+
- Credential: [`workspace_key`](#workspace_key)
|
|
1091
|
+
|
|
1022
1092
|
| Status | Error class | Codes | When |
|
|
1023
1093
|
|---|---|---|---|
|
|
1024
1094
|
| 400 | `BadRequestError` | `BAD_REQUEST`, `VALIDATION_ERROR` | `appId` is not a UUID. |
|
|
@@ -1027,7 +1097,7 @@ Auth health for this app over the last 30 days: verification completion, sign-in
|
|
|
1027
1097
|
| 429 | `RateLimitError` | `RATE_LIMITED` | Rate limited: too many requests from this client IP in the last 60 seconds (`RATE_LIMITED`); wait `Retry-After` seconds. |
|
|
1028
1098
|
|
|
1029
1099
|
```ts
|
|
1030
|
-
const endUserInsights = await auth.admin.app("
|
|
1100
|
+
const endUserInsights = await auth.admin.app("3f0c3c1e-8a2b-4c55-9d3f-0a1b2c3d4e5f").endUserInsights.retrieve();
|
|
1031
1101
|
```
|
|
1032
1102
|
|
|
1033
1103
|
[HTTP reference](https://productcraft.co/docs/auth/api-reference#get-v1-apps-app-id-end-user-insights)
|
|
@@ -1040,6 +1110,8 @@ const endUserInsights = await auth.admin.app("3f0c1a2b-4c5d-4e6f-8a9b-0c1d2e3f4a
|
|
|
1040
1110
|
|
|
1041
1111
|
One end-user's recorded activity: their audit trail, their sessions with device/IP, and their enrolled factors. `noActivityRecorded` distinguishes "nothing happened" from "no data".
|
|
1042
1112
|
|
|
1113
|
+
- Credential: [`workspace_key`](#workspace_key)
|
|
1114
|
+
|
|
1043
1115
|
| Status | Error class | Codes | When |
|
|
1044
1116
|
|---|---|---|---|
|
|
1045
1117
|
| 400 | `BadRequestError` | `BAD_REQUEST`, `VALIDATION_ERROR` | `appId` or `userId` is not a UUID. |
|
|
@@ -1049,7 +1121,7 @@ One end-user's recorded activity: their audit trail, their sessions with device/
|
|
|
1049
1121
|
| 429 | `RateLimitError` | `RATE_LIMITED` | Rate limited: too many requests from this client IP in the last 60 seconds (`RATE_LIMITED`); wait `Retry-After` seconds. |
|
|
1050
1122
|
|
|
1051
1123
|
```ts
|
|
1052
|
-
const endUserDetailInsights = await auth.admin.app("
|
|
1124
|
+
const endUserDetailInsights = await auth.admin.app("3f0c3c1e-8a2b-4c55-9d3f-0a1b2c3d4e5f").endUserInsights.users.retrieve("3f0c3c1e-8a2b-4c55-9d3f-0a1b2c3d4e5f");
|
|
1053
1125
|
```
|
|
1054
1126
|
|
|
1055
1127
|
[HTTP reference](https://productcraft.co/docs/auth/api-reference#get-v1-apps-app-id-end-user-insights-users-user-id)
|
|
@@ -1065,6 +1137,7 @@ Bulk-delete accounts across a selection.
|
|
|
1065
1137
|
Deletes every matched account in one transaction. Each deleted account gets an `auth.account.deleted` audit row (`via: platform_bulk`) whose metadata carries the `selection` (`{ mode: "ids" }`, or `{ mode: "filter", filter }`), so a filter sweep reads as one. The workspace audit log gets one `auth.end_users.deleted` row with the count. `user.deleted` (`via: "platform_bulk"`) fires per account only when 100 or fewer were deleted.
|
|
1066
1138
|
|
|
1067
1139
|
- Params: `Auth.EndUserBulkDeleteParams`
|
|
1140
|
+
- Credential: [`workspace_key`](#workspace_key)
|
|
1068
1141
|
|
|
1069
1142
|
| Status | Error class | Codes | When |
|
|
1070
1143
|
|---|---|---|---|
|
|
@@ -1075,7 +1148,7 @@ Deletes every matched account in one transaction. Each deleted account gets an `
|
|
|
1075
1148
|
| 429 | `RateLimitError` | `RATE_LIMITED` | Rate limited: too many requests from this client IP in the last 60 seconds (`RATE_LIMITED`); wait `Retry-After` seconds. |
|
|
1076
1149
|
|
|
1077
1150
|
```ts
|
|
1078
|
-
const bulkAffectedUsers = await auth.admin.app("
|
|
1151
|
+
const bulkAffectedUsers = await auth.admin.app("3f0c3c1e-8a2b-4c55-9d3f-0a1b2c3d4e5f").endUsers.bulkDelete({ selection: { mode: "ids" } });
|
|
1079
1152
|
```
|
|
1080
1153
|
|
|
1081
1154
|
[HTTP reference](https://productcraft.co/docs/auth/api-reference#post-v1-apps-app-id-end-users-bulk-delete)
|
|
@@ -1087,6 +1160,7 @@ const bulkAffectedUsers = await auth.admin.app("app").endUsers.bulkDelete({ sele
|
|
|
1087
1160
|
Bulk-revoke sessions across a selection.
|
|
1088
1161
|
|
|
1089
1162
|
- Params: `Auth.EndUserBulkRevokeSessionsParams`
|
|
1163
|
+
- Credential: [`workspace_key`](#workspace_key)
|
|
1090
1164
|
|
|
1091
1165
|
| Status | Error class | Codes | When |
|
|
1092
1166
|
|---|---|---|---|
|
|
@@ -1097,7 +1171,7 @@ Bulk-revoke sessions across a selection.
|
|
|
1097
1171
|
| 429 | `RateLimitError` | `RATE_LIMITED` | Rate limited: too many requests from this client IP in the last 60 seconds (`RATE_LIMITED`); wait `Retry-After` seconds. |
|
|
1098
1172
|
|
|
1099
1173
|
```ts
|
|
1100
|
-
const bulkAffectedUsers = await auth.admin.app("
|
|
1174
|
+
const bulkAffectedUsers = await auth.admin.app("3f0c3c1e-8a2b-4c55-9d3f-0a1b2c3d4e5f").endUsers.bulkRevokeSessions({ selection: { mode: "ids" } });
|
|
1101
1175
|
```
|
|
1102
1176
|
|
|
1103
1177
|
[HTTP reference](https://productcraft.co/docs/auth/api-reference#post-v1-apps-app-id-end-users-bulk-revoke-sessions)
|
|
@@ -1109,6 +1183,7 @@ const bulkAffectedUsers = await auth.admin.app("app").endUsers.bulkRevokeSession
|
|
|
1109
1183
|
Bulk-assign a role across a selection.
|
|
1110
1184
|
|
|
1111
1185
|
- Params: `Auth.EndUserBulkUpdateRoleParams`
|
|
1186
|
+
- Credential: [`workspace_key`](#workspace_key)
|
|
1112
1187
|
|
|
1113
1188
|
| Status | Error class | Codes | When |
|
|
1114
1189
|
|---|---|---|---|
|
|
@@ -1119,7 +1194,7 @@ Bulk-assign a role across a selection.
|
|
|
1119
1194
|
| 429 | `RateLimitError` | `RATE_LIMITED` | Rate limited: too many requests from this client IP in the last 60 seconds (`RATE_LIMITED`); wait `Retry-After` seconds. |
|
|
1120
1195
|
|
|
1121
1196
|
```ts
|
|
1122
|
-
const bulkAffectedUsers = await auth.admin.app("
|
|
1197
|
+
const bulkAffectedUsers = await auth.admin.app("3f0c3c1e-8a2b-4c55-9d3f-0a1b2c3d4e5f").endUsers.bulkUpdateRole({ role_name: "member", selection: { mode: "ids" } });
|
|
1123
1198
|
```
|
|
1124
1199
|
|
|
1125
1200
|
[HTTP reference](https://productcraft.co/docs/auth/api-reference#post-v1-apps-app-id-end-users-bulk-update-role)
|
|
@@ -1131,6 +1206,7 @@ const bulkAffectedUsers = await auth.admin.app("app").endUsers.bulkUpdateRole({
|
|
|
1131
1206
|
Bulk-update status across a selection.
|
|
1132
1207
|
|
|
1133
1208
|
- Params: `Auth.EndUserBulkUpdateStatusParams`
|
|
1209
|
+
- Credential: [`workspace_key`](#workspace_key)
|
|
1134
1210
|
|
|
1135
1211
|
| Status | Error class | Codes | When |
|
|
1136
1212
|
|---|---|---|---|
|
|
@@ -1141,7 +1217,7 @@ Bulk-update status across a selection.
|
|
|
1141
1217
|
| 429 | `RateLimitError` | `RATE_LIMITED` | Rate limited: too many requests from this client IP in the last 60 seconds (`RATE_LIMITED`); wait `Retry-After` seconds. |
|
|
1142
1218
|
|
|
1143
1219
|
```ts
|
|
1144
|
-
const bulkAffectedUsers = await auth.admin.app("
|
|
1220
|
+
const bulkAffectedUsers = await auth.admin.app("3f0c3c1e-8a2b-4c55-9d3f-0a1b2c3d4e5f").endUsers.bulkUpdateStatus({ selection: { mode: "ids" }, status: "suspended" });
|
|
1145
1221
|
```
|
|
1146
1222
|
|
|
1147
1223
|
[HTTP reference](https://productcraft.co/docs/auth/api-reference#post-v1-apps-app-id-end-users-bulk-update-status)
|
|
@@ -1154,6 +1230,8 @@ Delete an end-user permanently.
|
|
|
1154
1230
|
|
|
1155
1231
|
Removes the account with its contacts, sessions and tenant memberships. Writes one `auth.account.deleted` audit row (`via: platform`) in the same transaction, mirrors the deletion into the workspace audit log as `auth.end_users.deleted`, and fires `user.deleted` with `via: "platform"`.
|
|
1156
1232
|
|
|
1233
|
+
- Credential: [`workspace_key`](#workspace_key)
|
|
1234
|
+
|
|
1157
1235
|
| Status | Error class | Codes | When |
|
|
1158
1236
|
|---|---|---|---|
|
|
1159
1237
|
| 401 | `AuthenticationError` | `UNAUTHORIZED` | Missing or invalid bearer token. |
|
|
@@ -1162,7 +1240,7 @@ Removes the account with its contacts, sessions and tenant memberships. Writes o
|
|
|
1162
1240
|
| 429 | `RateLimitError` | `RATE_LIMITED` | Rate limited: too many requests from this client IP in the last 60 seconds (`RATE_LIMITED`); wait `Retry-After` seconds. |
|
|
1163
1241
|
|
|
1164
1242
|
```ts
|
|
1165
|
-
await auth.admin.app("
|
|
1243
|
+
await auth.admin.app("3f0c3c1e-8a2b-4c55-9d3f-0a1b2c3d4e5f").endUsers.delete("3f0c3c1e-8a2b-4c55-9d3f-0a1b2c3d4e5f");
|
|
1166
1244
|
```
|
|
1167
1245
|
|
|
1168
1246
|
[HTTP reference](https://productcraft.co/docs/auth/api-reference#delete-v1-apps-app-id-end-users-user-id)
|
|
@@ -1176,6 +1254,7 @@ Stream this app's end-user directory as NDJSON or CSV, applying the list's `?sta
|
|
|
1176
1254
|
Streamed in keyset batches — neither the service nor the client holds the whole directory. Ordered oldest-first by `(created_at, id)` so a re-run is stable. Gated on `auth.user.export`, which is escalation class: this hands over every address in the directory in one call, where `auth.list` pages it. Hard cap of 1,000,000 rows; a wider request is refused with 413 before any body is written.
|
|
1177
1255
|
|
|
1178
1256
|
- Params: `Auth.EndUserExportParams`
|
|
1257
|
+
- Credential: [`workspace_key`](#workspace_key)
|
|
1179
1258
|
|
|
1180
1259
|
| Status | Error class | Codes | When |
|
|
1181
1260
|
|---|---|---|---|
|
|
@@ -1187,7 +1266,7 @@ Streamed in keyset batches — neither the service nor the client holds the whol
|
|
|
1187
1266
|
| 429 | `RateLimitError` | `RATE_LIMITED` | Rate limited: too many requests from this client IP in the last 60 seconds (`RATE_LIMITED`); wait `Retry-After` seconds. |
|
|
1188
1267
|
|
|
1189
1268
|
```ts
|
|
1190
|
-
const response = await auth.admin.app("
|
|
1269
|
+
const response = await auth.admin.app("3f0c3c1e-8a2b-4c55-9d3f-0a1b2c3d4e5f").endUsers.export();
|
|
1191
1270
|
const text = await response.text();
|
|
1192
1271
|
```
|
|
1193
1272
|
|
|
@@ -1201,6 +1280,7 @@ List end-users in this app (cursor-paginated).
|
|
|
1201
1280
|
|
|
1202
1281
|
- Params: `Auth.EndUserListParams`
|
|
1203
1282
|
- Paginated: `for await` iterates every item; `await` gives one page
|
|
1283
|
+
- Credential: [`workspace_key`](#workspace_key)
|
|
1204
1284
|
|
|
1205
1285
|
| Status | Error class | Codes | When |
|
|
1206
1286
|
|---|---|---|---|
|
|
@@ -1209,10 +1289,10 @@ List end-users in this app (cursor-paginated).
|
|
|
1209
1289
|
| 429 | `RateLimitError` | `RATE_LIMITED` | Rate limited: too many requests from this client IP in the last 60 seconds (`RATE_LIMITED`); wait `Retry-After` seconds. |
|
|
1210
1290
|
|
|
1211
1291
|
```ts
|
|
1212
|
-
for await (const endUser of auth.admin.app("
|
|
1292
|
+
for await (const endUser of auth.admin.app("3f0c3c1e-8a2b-4c55-9d3f-0a1b2c3d4e5f").endUsers.list()) {
|
|
1213
1293
|
console.log(endUser);
|
|
1214
1294
|
}
|
|
1215
|
-
const page = await auth.admin.app("
|
|
1295
|
+
const page = await auth.admin.app("3f0c3c1e-8a2b-4c55-9d3f-0a1b2c3d4e5f").endUsers.list({}, { timeout: 5_000 });
|
|
1216
1296
|
```
|
|
1217
1297
|
|
|
1218
1298
|
[HTTP reference](https://productcraft.co/docs/auth/api-reference#get-v1-apps-app-id-end-users)
|
|
@@ -1223,6 +1303,8 @@ const page = await auth.admin.app("app").endUsers.list({}, { timeout: 5_000 });
|
|
|
1223
1303
|
|
|
1224
1304
|
Resend verification to the primary email contact.
|
|
1225
1305
|
|
|
1306
|
+
- Credential: [`workspace_key`](#workspace_key)
|
|
1307
|
+
|
|
1226
1308
|
| Status | Error class | Codes | When |
|
|
1227
1309
|
|---|---|---|---|
|
|
1228
1310
|
| 401 | `AuthenticationError` | `UNAUTHORIZED` | Missing or invalid bearer token. |
|
|
@@ -1232,7 +1314,7 @@ Resend verification to the primary email contact.
|
|
|
1232
1314
|
| 429 | `RateLimitError` | `RATE_LIMITED` | Rate limited: too many requests from this client IP in the last 60 seconds (`RATE_LIMITED`); wait `Retry-After` seconds. |
|
|
1233
1315
|
|
|
1234
1316
|
```ts
|
|
1235
|
-
const issuedVerificationCode = await auth.admin.app("
|
|
1317
|
+
const issuedVerificationCode = await auth.admin.app("3f0c3c1e-8a2b-4c55-9d3f-0a1b2c3d4e5f").endUsers.resendVerification("3f0c3c1e-8a2b-4c55-9d3f-0a1b2c3d4e5f");
|
|
1236
1318
|
```
|
|
1237
1319
|
|
|
1238
1320
|
[HTTP reference](https://productcraft.co/docs/auth/api-reference#post-v1-apps-app-id-end-users-user-id-resend-verification)
|
|
@@ -1243,6 +1325,8 @@ const issuedVerificationCode = await auth.admin.app("app").endUsers.resendVerifi
|
|
|
1243
1325
|
|
|
1244
1326
|
Get one end-user.
|
|
1245
1327
|
|
|
1328
|
+
- Credential: [`workspace_key`](#workspace_key)
|
|
1329
|
+
|
|
1246
1330
|
| Status | Error class | Codes | When |
|
|
1247
1331
|
|---|---|---|---|
|
|
1248
1332
|
| 401 | `AuthenticationError` | `UNAUTHORIZED` | Missing or invalid bearer token. |
|
|
@@ -1251,7 +1335,7 @@ Get one end-user.
|
|
|
1251
1335
|
| 429 | `RateLimitError` | `RATE_LIMITED` | Rate limited: too many requests from this client IP in the last 60 seconds (`RATE_LIMITED`); wait `Retry-After` seconds. |
|
|
1252
1336
|
|
|
1253
1337
|
```ts
|
|
1254
|
-
const endUserSummary = await auth.admin.app("
|
|
1338
|
+
const endUserSummary = await auth.admin.app("3f0c3c1e-8a2b-4c55-9d3f-0a1b2c3d4e5f").endUsers.retrieve("3f0c3c1e-8a2b-4c55-9d3f-0a1b2c3d4e5f");
|
|
1255
1339
|
```
|
|
1256
1340
|
|
|
1257
1341
|
[HTTP reference](https://productcraft.co/docs/auth/api-reference#get-v1-apps-app-id-end-users-user-id)
|
|
@@ -1263,6 +1347,7 @@ const endUserSummary = await auth.admin.app("app").endUsers.retrieve("user");
|
|
|
1263
1347
|
Update end-user display name, primary email, or metadata keys (merged).
|
|
1264
1348
|
|
|
1265
1349
|
- Params: `Auth.EndUserUpdateParams`
|
|
1350
|
+
- Credential: [`workspace_key`](#workspace_key)
|
|
1266
1351
|
|
|
1267
1352
|
| Status | Error class | Codes | When |
|
|
1268
1353
|
|---|---|---|---|
|
|
@@ -1273,7 +1358,7 @@ Update end-user display name, primary email, or metadata keys (merged).
|
|
|
1273
1358
|
| 429 | `RateLimitError` | `RATE_LIMITED` | Rate limited: too many requests from this client IP in the last 60 seconds (`RATE_LIMITED`); wait `Retry-After` seconds. |
|
|
1274
1359
|
|
|
1275
1360
|
```ts
|
|
1276
|
-
const endUserSummary = await auth.admin.app("
|
|
1361
|
+
const endUserSummary = await auth.admin.app("3f0c3c1e-8a2b-4c55-9d3f-0a1b2c3d4e5f").endUsers.update("3f0c3c1e-8a2b-4c55-9d3f-0a1b2c3d4e5f", { display_name: "Ada Lovelace" });
|
|
1277
1362
|
```
|
|
1278
1363
|
|
|
1279
1364
|
[HTTP reference](https://productcraft.co/docs/auth/api-reference#patch-v1-apps-app-id-end-users-user-id)
|
|
@@ -1285,6 +1370,7 @@ const endUserSummary = await auth.admin.app("app").endUsers.update("user", { dis
|
|
|
1285
1370
|
Assign an end-user a role.
|
|
1286
1371
|
|
|
1287
1372
|
- Params: `Auth.EndUserUpdateRoleParams`
|
|
1373
|
+
- Credential: [`workspace_key`](#workspace_key)
|
|
1288
1374
|
|
|
1289
1375
|
| Status | Error class | Codes | When |
|
|
1290
1376
|
|---|---|---|---|
|
|
@@ -1295,7 +1381,7 @@ Assign an end-user a role.
|
|
|
1295
1381
|
| 429 | `RateLimitError` | `RATE_LIMITED` | Rate limited: too many requests from this client IP in the last 60 seconds (`RATE_LIMITED`); wait `Retry-After` seconds. |
|
|
1296
1382
|
|
|
1297
1383
|
```ts
|
|
1298
|
-
const endUserRoleAssignment = await auth.admin.app("
|
|
1384
|
+
const endUserRoleAssignment = await auth.admin.app("3f0c3c1e-8a2b-4c55-9d3f-0a1b2c3d4e5f").endUsers.updateRole("3f0c3c1e-8a2b-4c55-9d3f-0a1b2c3d4e5f", { role_name: "admin" });
|
|
1299
1385
|
```
|
|
1300
1386
|
|
|
1301
1387
|
[HTTP reference](https://productcraft.co/docs/auth/api-reference#patch-v1-apps-app-id-end-users-user-id-role)
|
|
@@ -1307,6 +1393,7 @@ const endUserRoleAssignment = await auth.admin.app("app").endUsers.updateRole("u
|
|
|
1307
1393
|
Change end-user status (active / suspended / deactivated).
|
|
1308
1394
|
|
|
1309
1395
|
- Params: `Auth.EndUserUpdateStatusParams`
|
|
1396
|
+
- Credential: [`workspace_key`](#workspace_key)
|
|
1310
1397
|
|
|
1311
1398
|
| Status | Error class | Codes | When |
|
|
1312
1399
|
|---|---|---|---|
|
|
@@ -1317,7 +1404,7 @@ Change end-user status (active / suspended / deactivated).
|
|
|
1317
1404
|
| 429 | `RateLimitError` | `RATE_LIMITED` | Rate limited: too many requests from this client IP in the last 60 seconds (`RATE_LIMITED`); wait `Retry-After` seconds. |
|
|
1318
1405
|
|
|
1319
1406
|
```ts
|
|
1320
|
-
const endUserSummary = await auth.admin.app("
|
|
1407
|
+
const endUserSummary = await auth.admin.app("3f0c3c1e-8a2b-4c55-9d3f-0a1b2c3d4e5f").endUsers.updateStatus("3f0c3c1e-8a2b-4c55-9d3f-0a1b2c3d4e5f", { status: "suspended" });
|
|
1321
1408
|
```
|
|
1322
1409
|
|
|
1323
1410
|
[HTTP reference](https://productcraft.co/docs/auth/api-reference#patch-v1-apps-app-id-end-users-user-id-status)
|
|
@@ -1332,6 +1419,7 @@ Add a contact for an end-user (unverified).
|
|
|
1332
1419
|
|
|
1333
1420
|
- Params: `Auth.EndUserContactCreateParams`
|
|
1334
1421
|
- Idempotent: an `Idempotency-Key` is sent automatically and reused on retries
|
|
1422
|
+
- Credential: [`workspace_key`](#workspace_key)
|
|
1335
1423
|
|
|
1336
1424
|
| Status | Error class | Codes | When |
|
|
1337
1425
|
|---|---|---|---|
|
|
@@ -1343,7 +1431,7 @@ Add a contact for an end-user (unverified).
|
|
|
1343
1431
|
| 429 | `RateLimitError` | `RATE_LIMITED` | Rate limited: too many requests from this client IP in the last 60 seconds (`RATE_LIMITED`); wait `Retry-After` seconds. |
|
|
1344
1432
|
|
|
1345
1433
|
```ts
|
|
1346
|
-
const accountContact = await auth.admin.app("
|
|
1434
|
+
const accountContact = await auth.admin.app("3f0c3c1e-8a2b-4c55-9d3f-0a1b2c3d4e5f").endUsers.contacts.create("3f0c3c1e-8a2b-4c55-9d3f-0a1b2c3d4e5f", { type: "email", value: "ada@example.com" });
|
|
1347
1435
|
```
|
|
1348
1436
|
|
|
1349
1437
|
[HTTP reference](https://productcraft.co/docs/auth/api-reference#post-v1-apps-app-id-end-users-user-id-contacts)
|
|
@@ -1354,6 +1442,8 @@ const accountContact = await auth.admin.app("app").endUsers.contacts.create("use
|
|
|
1354
1442
|
|
|
1355
1443
|
Delete a contact from an end-user.
|
|
1356
1444
|
|
|
1445
|
+
- Credential: [`workspace_key`](#workspace_key)
|
|
1446
|
+
|
|
1357
1447
|
| Status | Error class | Codes | When |
|
|
1358
1448
|
|---|---|---|---|
|
|
1359
1449
|
| 401 | `AuthenticationError` | `UNAUTHORIZED` | Missing or invalid bearer token. |
|
|
@@ -1363,7 +1453,7 @@ Delete a contact from an end-user.
|
|
|
1363
1453
|
| 429 | `RateLimitError` | `RATE_LIMITED` | Rate limited: too many requests from this client IP in the last 60 seconds (`RATE_LIMITED`); wait `Retry-After` seconds. |
|
|
1364
1454
|
|
|
1365
1455
|
```ts
|
|
1366
|
-
await auth.admin.app("
|
|
1456
|
+
await auth.admin.app("3f0c3c1e-8a2b-4c55-9d3f-0a1b2c3d4e5f").endUsers.contacts.delete("3f0c3c1e-8a2b-4c55-9d3f-0a1b2c3d4e5f", "3f0c3c1e-8a2b-4c55-9d3f-0a1b2c3d4e5f");
|
|
1367
1457
|
```
|
|
1368
1458
|
|
|
1369
1459
|
[HTTP reference](https://productcraft.co/docs/auth/api-reference#delete-v1-apps-app-id-end-users-user-id-contacts-contact-id)
|
|
@@ -1374,6 +1464,8 @@ await auth.admin.app("app").endUsers.contacts.delete("user", "contact");
|
|
|
1374
1464
|
|
|
1375
1465
|
List an end-user's contacts.
|
|
1376
1466
|
|
|
1467
|
+
- Credential: [`workspace_key`](#workspace_key)
|
|
1468
|
+
|
|
1377
1469
|
| Status | Error class | Codes | When |
|
|
1378
1470
|
|---|---|---|---|
|
|
1379
1471
|
| 401 | `AuthenticationError` | `UNAUTHORIZED` | Missing or invalid bearer token. |
|
|
@@ -1382,7 +1474,7 @@ List an end-user's contacts.
|
|
|
1382
1474
|
| 429 | `RateLimitError` | `RATE_LIMITED` | Rate limited: too many requests from this client IP in the last 60 seconds (`RATE_LIMITED`); wait `Retry-After` seconds. |
|
|
1383
1475
|
|
|
1384
1476
|
```ts
|
|
1385
|
-
const accountContactList = await auth.admin.app("
|
|
1477
|
+
const accountContactList = await auth.admin.app("3f0c3c1e-8a2b-4c55-9d3f-0a1b2c3d4e5f").endUsers.contacts.list("3f0c3c1e-8a2b-4c55-9d3f-0a1b2c3d4e5f");
|
|
1386
1478
|
```
|
|
1387
1479
|
|
|
1388
1480
|
[HTTP reference](https://productcraft.co/docs/auth/api-reference#get-v1-apps-app-id-end-users-user-id-contacts)
|
|
@@ -1393,6 +1485,8 @@ const accountContactList = await auth.admin.app("app").endUsers.contacts.list("u
|
|
|
1393
1485
|
|
|
1394
1486
|
Promote a verified contact to primary.
|
|
1395
1487
|
|
|
1488
|
+
- Credential: [`workspace_key`](#workspace_key)
|
|
1489
|
+
|
|
1396
1490
|
| Status | Error class | Codes | When |
|
|
1397
1491
|
|---|---|---|---|
|
|
1398
1492
|
| 401 | `AuthenticationError` | `UNAUTHORIZED` | Missing or invalid bearer token. |
|
|
@@ -1402,7 +1496,7 @@ Promote a verified contact to primary.
|
|
|
1402
1496
|
| 429 | `RateLimitError` | `RATE_LIMITED` | Rate limited: too many requests from this client IP in the last 60 seconds (`RATE_LIMITED`); wait `Retry-After` seconds. |
|
|
1403
1497
|
|
|
1404
1498
|
```ts
|
|
1405
|
-
await auth.admin.app("
|
|
1499
|
+
await auth.admin.app("3f0c3c1e-8a2b-4c55-9d3f-0a1b2c3d4e5f").endUsers.contacts.promote("3f0c3c1e-8a2b-4c55-9d3f-0a1b2c3d4e5f", "3f0c3c1e-8a2b-4c55-9d3f-0a1b2c3d4e5f");
|
|
1406
1500
|
```
|
|
1407
1501
|
|
|
1408
1502
|
[HTTP reference](https://productcraft.co/docs/auth/api-reference#post-v1-apps-app-id-end-users-user-id-contacts-contact-id-promote)
|
|
@@ -1413,6 +1507,8 @@ await auth.admin.app("app").endUsers.contacts.promote("user", "contact");
|
|
|
1413
1507
|
|
|
1414
1508
|
Reissue a verification code for a contact.
|
|
1415
1509
|
|
|
1510
|
+
- Credential: [`workspace_key`](#workspace_key)
|
|
1511
|
+
|
|
1416
1512
|
| Status | Error class | Codes | When |
|
|
1417
1513
|
|---|---|---|---|
|
|
1418
1514
|
| 401 | `AuthenticationError` | `UNAUTHORIZED` | Missing or invalid bearer token. |
|
|
@@ -1422,7 +1518,7 @@ Reissue a verification code for a contact.
|
|
|
1422
1518
|
| 429 | `RateLimitError` | `RATE_LIMITED` | Rate limited: too many requests from this client IP in the last 60 seconds (`RATE_LIMITED`); wait `Retry-After` seconds. |
|
|
1423
1519
|
|
|
1424
1520
|
```ts
|
|
1425
|
-
const issuedVerificationCode = await auth.admin.app("
|
|
1521
|
+
const issuedVerificationCode = await auth.admin.app("3f0c3c1e-8a2b-4c55-9d3f-0a1b2c3d4e5f").endUsers.contacts.resendVerification("3f0c3c1e-8a2b-4c55-9d3f-0a1b2c3d4e5f", "3f0c3c1e-8a2b-4c55-9d3f-0a1b2c3d4e5f");
|
|
1426
1522
|
```
|
|
1427
1523
|
|
|
1428
1524
|
[HTTP reference](https://productcraft.co/docs/auth/api-reference#post-v1-apps-app-id-end-users-user-id-contacts-contact-id-resend-verification)
|
|
@@ -1438,6 +1534,7 @@ Queue a bulk end-user import. Body is NDJSON — one JSON object per line. Retur
|
|
|
1438
1534
|
Row fields: `email` (required), `username`, `display_name`, `role`, `tenant_slugs` (array), `external_id`, `metadata`, `email_verified`, and `password_hash` + `password_hash_algorithm`. `password_hash_algorithm` is `argon2id` or `bcrypt`. **argon2id** hashes are accepted at any parameters. **bcrypt** hashes (`$2a$`, `$2b$`, `$2y$` — Auth0, PHP `password_hash`, Spring, node `bcrypt`, Devise / Rails, Laravel, Django) are accepted at any valid cost (4-31), verified on the user's first signin and replaced by an argon2id hash of the same password in that request, so the user keeps their password and never notices. Signin pads a bcrypt verify up to the argon2id floor, so at cost 10 and below an imported account cannot be told apart by timing; at cost 11 and above the verify is slower than the floor and answers when it finishes — a small timing difference on migrated accounts only, gone after each one's first signin. A re-run is idempotent: rows match on `external_id` first, then the primary email, and update rather than duplicate. An existing password, an already-verified address and an existing member's role are never overwritten — see the module docs for why each one.
|
|
1439
1535
|
|
|
1440
1536
|
- Idempotent: an `Idempotency-Key` is sent automatically and reused on retries
|
|
1537
|
+
- Credential: [`workspace_key`](#workspace_key)
|
|
1441
1538
|
|
|
1442
1539
|
| Status | Error class | Codes | When |
|
|
1443
1540
|
|---|---|---|---|
|
|
@@ -1449,7 +1546,7 @@ Row fields: `email` (required), `username`, `display_name`, `role`, `tenant_slug
|
|
|
1449
1546
|
| 429 | `RateLimitError` | `RATE_LIMITED` | Rate limited: too many requests from this client IP in the last 60 seconds (`RATE_LIMITED`); wait `Retry-After` seconds. |
|
|
1450
1547
|
|
|
1451
1548
|
```ts
|
|
1452
|
-
const importJob = await auth.admin.app("
|
|
1549
|
+
const importJob = await auth.admin.app("3f0c3c1e-8a2b-4c55-9d3f-0a1b2c3d4e5f").endUsers.imports.create();
|
|
1453
1550
|
```
|
|
1454
1551
|
|
|
1455
1552
|
[HTTP reference](https://productcraft.co/docs/auth/api-reference#post-v1-apps-app-id-end-users-import)
|
|
@@ -1462,6 +1559,8 @@ Import job status and per-row error report. Never returns the uploaded file.
|
|
|
1462
1559
|
|
|
1463
1560
|
`status: succeeded` means the job RAN TO COMPLETION, not that every row landed — read `failed_count` and `errors` for that. `errors` is capped at the first 500 entries; the counts stay exact.
|
|
1464
1561
|
|
|
1562
|
+
- Credential: [`workspace_key`](#workspace_key)
|
|
1563
|
+
|
|
1465
1564
|
| Status | Error class | Codes | When |
|
|
1466
1565
|
|---|---|---|---|
|
|
1467
1566
|
| 401 | `AuthenticationError` | `UNAUTHORIZED` | Missing, invalid or expired bearer token. |
|
|
@@ -1470,7 +1569,7 @@ Import job status and per-row error report. Never returns the uploaded file.
|
|
|
1470
1569
|
| 429 | `RateLimitError` | `RATE_LIMITED` | Rate limited: too many requests from this client IP in the last 60 seconds (`RATE_LIMITED`); wait `Retry-After` seconds. |
|
|
1471
1570
|
|
|
1472
1571
|
```ts
|
|
1473
|
-
const importJob = await auth.admin.app("
|
|
1572
|
+
const importJob = await auth.admin.app("3f0c3c1e-8a2b-4c55-9d3f-0a1b2c3d4e5f").endUsers.imports.retrieve("3f0c3c1e-8a2b-4c55-9d3f-0a1b2c3d4e5f");
|
|
1474
1573
|
```
|
|
1475
1574
|
|
|
1476
1575
|
[HTTP reference](https://productcraft.co/docs/auth/api-reference#get-v1-apps-app-id-end-users-import-job-id)
|
|
@@ -1485,6 +1584,7 @@ Pre-allocate an EndUser invite. Dispatches an invitation email via the workspace
|
|
|
1485
1584
|
|
|
1486
1585
|
- Params: `Auth.EndUserInviteCreateParams`
|
|
1487
1586
|
- Idempotent: an `Idempotency-Key` is sent automatically and reused on retries
|
|
1587
|
+
- Credential: [`workspace_key`](#workspace_key)
|
|
1488
1588
|
|
|
1489
1589
|
| Status | Error class | Codes | When |
|
|
1490
1590
|
|---|---|---|---|
|
|
@@ -1494,7 +1594,7 @@ Pre-allocate an EndUser invite. Dispatches an invitation email via the workspace
|
|
|
1494
1594
|
| 429 | `RateLimitError` | `RATE_LIMITED` | Rate limited: too many requests from this client IP in the last 60 seconds (`RATE_LIMITED`); wait `Retry-After` seconds. |
|
|
1495
1595
|
|
|
1496
1596
|
```ts
|
|
1497
|
-
const endUserInvite = await auth.admin.app("
|
|
1597
|
+
const endUserInvite = await auth.admin.app("3f0c3c1e-8a2b-4c55-9d3f-0a1b2c3d4e5f").endUsers.invites.create({ email: "alice@example.com" });
|
|
1498
1598
|
```
|
|
1499
1599
|
|
|
1500
1600
|
[HTTP reference](https://productcraft.co/docs/auth/api-reference#post-v1-apps-app-id-end-users-invites)
|
|
@@ -1505,6 +1605,8 @@ const endUserInvite = await auth.admin.app("app").endUsers.invites.create({ emai
|
|
|
1505
1605
|
|
|
1506
1606
|
Revoke an EndUser invite (soft-delete).
|
|
1507
1607
|
|
|
1608
|
+
- Credential: [`workspace_key`](#workspace_key)
|
|
1609
|
+
|
|
1508
1610
|
| Status | Error class | Codes | When |
|
|
1509
1611
|
|---|---|---|---|
|
|
1510
1612
|
| 401 | `AuthenticationError` | `UNAUTHORIZED` | Missing or invalid bearer token. |
|
|
@@ -1513,7 +1615,7 @@ Revoke an EndUser invite (soft-delete).
|
|
|
1513
1615
|
| 429 | `RateLimitError` | `RATE_LIMITED` | Rate limited: too many requests from this client IP in the last 60 seconds (`RATE_LIMITED`); wait `Retry-After` seconds. |
|
|
1514
1616
|
|
|
1515
1617
|
```ts
|
|
1516
|
-
await auth.admin.app("
|
|
1618
|
+
await auth.admin.app("3f0c3c1e-8a2b-4c55-9d3f-0a1b2c3d4e5f").endUsers.invites.delete("3f0c3c1e-8a2b-4c55-9d3f-0a1b2c3d4e5f");
|
|
1517
1619
|
```
|
|
1518
1620
|
|
|
1519
1621
|
[HTTP reference](https://productcraft.co/docs/auth/api-reference#delete-v1-apps-app-id-end-users-invites-invite-id)
|
|
@@ -1526,6 +1628,7 @@ List EndUser invites for this app, newest first. Filter by `?status=`.
|
|
|
1526
1628
|
|
|
1527
1629
|
- Params: `Auth.EndUserInviteListParams`
|
|
1528
1630
|
- Paginated: `for await` iterates every item; `await` gives one page
|
|
1631
|
+
- Credential: [`workspace_key`](#workspace_key)
|
|
1529
1632
|
|
|
1530
1633
|
| Status | Error class | Codes | When |
|
|
1531
1634
|
|---|---|---|---|
|
|
@@ -1534,10 +1637,10 @@ List EndUser invites for this app, newest first. Filter by `?status=`.
|
|
|
1534
1637
|
| 429 | `RateLimitError` | `RATE_LIMITED` | Rate limited: too many requests from this client IP in the last 60 seconds (`RATE_LIMITED`); wait `Retry-After` seconds. |
|
|
1535
1638
|
|
|
1536
1639
|
```ts
|
|
1537
|
-
for await (const invite of auth.admin.app("
|
|
1640
|
+
for await (const invite of auth.admin.app("3f0c3c1e-8a2b-4c55-9d3f-0a1b2c3d4e5f").endUsers.invites.list()) {
|
|
1538
1641
|
console.log(invite);
|
|
1539
1642
|
}
|
|
1540
|
-
const page = await auth.admin.app("
|
|
1643
|
+
const page = await auth.admin.app("3f0c3c1e-8a2b-4c55-9d3f-0a1b2c3d4e5f").endUsers.invites.list({}, { timeout: 5_000 });
|
|
1541
1644
|
```
|
|
1542
1645
|
|
|
1543
1646
|
[HTTP reference](https://productcraft.co/docs/auth/api-reference#get-v1-apps-app-id-end-users-invites)
|
|
@@ -1552,6 +1655,8 @@ Force an end-user back through MFA enrolment.
|
|
|
1552
1655
|
|
|
1553
1656
|
Disables every enabled factor on the account, destroys its recovery codes, and revokes every live session. The next sign-in on an app running `auth_config.mfa: "required"` returns `mfa_enrollment_required` and the user must enrol a new factor before a session is minted. On an app running `mfa: "optional"` the user simply ends up with no MFA, which is the pre-existing meaning of deleting their factors. All three steps matter: leaving the recovery codes alive would let whoever holds the old printout complete `/auth/mfa/recover` and skip enrolment entirely. Audited, and emits `user.mfa.factor_disabled` per factor plus one `user.mfa.reenrollment_required`. Idempotent.
|
|
1554
1657
|
|
|
1658
|
+
- Credential: [`workspace_key`](#workspace_key)
|
|
1659
|
+
|
|
1555
1660
|
| Status | Error class | Codes | When |
|
|
1556
1661
|
|---|---|---|---|
|
|
1557
1662
|
| 401 | `AuthenticationError` | `UNAUTHORIZED` | Missing, invalid or expired bearer token. |
|
|
@@ -1560,7 +1665,7 @@ Disables every enabled factor on the account, destroys its recovery codes, and r
|
|
|
1560
1665
|
| 429 | `RateLimitError` | `RATE_LIMITED` | Rate limited: too many requests from this client IP in the last 60 seconds (`RATE_LIMITED`); wait `Retry-After` seconds. |
|
|
1561
1666
|
|
|
1562
1667
|
```ts
|
|
1563
|
-
const requireMfaReenrollment = await auth.admin.app("
|
|
1668
|
+
const requireMfaReenrollment = await auth.admin.app("3f0c3c1e-8a2b-4c55-9d3f-0a1b2c3d4e5f").endUsers.mfa.requireReenrollment("3f0c3c1e-8a2b-4c55-9d3f-0a1b2c3d4e5f");
|
|
1564
1669
|
```
|
|
1565
1670
|
|
|
1566
1671
|
[HTTP reference](https://productcraft.co/docs/auth/api-reference#post-v1-apps-app-id-end-users-user-id-mfa-require-reenrollment)
|
|
@@ -1573,6 +1678,8 @@ const requireMfaReenrollment = await auth.admin.app("app").endUsers.mfa.requireR
|
|
|
1573
1678
|
|
|
1574
1679
|
Revoke every active session for an end-user.
|
|
1575
1680
|
|
|
1681
|
+
- Credential: [`workspace_key`](#workspace_key)
|
|
1682
|
+
|
|
1576
1683
|
| Status | Error class | Codes | When |
|
|
1577
1684
|
|---|---|---|---|
|
|
1578
1685
|
| 401 | `AuthenticationError` | `UNAUTHORIZED` | Missing or invalid bearer token. |
|
|
@@ -1581,7 +1688,7 @@ Revoke every active session for an end-user.
|
|
|
1581
1688
|
| 429 | `RateLimitError` | `RATE_LIMITED` | Rate limited: too many requests from this client IP in the last 60 seconds (`RATE_LIMITED`); wait `Retry-After` seconds. |
|
|
1582
1689
|
|
|
1583
1690
|
```ts
|
|
1584
|
-
await auth.admin.app("
|
|
1691
|
+
await auth.admin.app("3f0c3c1e-8a2b-4c55-9d3f-0a1b2c3d4e5f").endUsers.sessions.revokeAll("3f0c3c1e-8a2b-4c55-9d3f-0a1b2c3d4e5f");
|
|
1585
1692
|
```
|
|
1586
1693
|
|
|
1587
1694
|
[HTTP reference](https://productcraft.co/docs/auth/api-reference#post-v1-apps-app-id-end-users-user-id-sessions-revoke-all)
|
|
@@ -1594,6 +1701,8 @@ await auth.admin.app("app").endUsers.sessions.revokeAll("user");
|
|
|
1594
1701
|
|
|
1595
1702
|
Remove a member from the app.
|
|
1596
1703
|
|
|
1704
|
+
- Credential: [`workspace_key`](#workspace_key)
|
|
1705
|
+
|
|
1597
1706
|
| Status | Error class | Codes | When |
|
|
1598
1707
|
|---|---|---|---|
|
|
1599
1708
|
| 401 | `AuthenticationError` | `UNAUTHORIZED` | Missing or invalid bearer token. |
|
|
@@ -1602,7 +1711,7 @@ Remove a member from the app.
|
|
|
1602
1711
|
| 429 | `RateLimitError` | `RATE_LIMITED` | Rate limited: too many requests from this client IP in the last 60 seconds (`RATE_LIMITED`); wait `Retry-After` seconds. |
|
|
1603
1712
|
|
|
1604
1713
|
```ts
|
|
1605
|
-
await auth.admin.app("
|
|
1714
|
+
await auth.admin.app("3f0c3c1e-8a2b-4c55-9d3f-0a1b2c3d4e5f").members.delete("3f0c3c1e-8a2b-4c55-9d3f-0a1b2c3d4e5f");
|
|
1606
1715
|
```
|
|
1607
1716
|
|
|
1608
1717
|
[HTTP reference](https://productcraft.co/docs/auth/api-reference#delete-v1-apps-app-id-members-account-id)
|
|
@@ -1615,6 +1724,7 @@ List app members (PlatformUser view of EndUser memberships).
|
|
|
1615
1724
|
|
|
1616
1725
|
- Params: `Auth.MemberListParams`
|
|
1617
1726
|
- Paginated: `for await` iterates every item; `await` gives one page
|
|
1727
|
+
- Credential: [`workspace_key`](#workspace_key)
|
|
1618
1728
|
|
|
1619
1729
|
| Status | Error class | Codes | When |
|
|
1620
1730
|
|---|---|---|---|
|
|
@@ -1625,10 +1735,10 @@ List app members (PlatformUser view of EndUser memberships).
|
|
|
1625
1735
|
| 429 | `RateLimitError` | `RATE_LIMITED` | Rate limited: too many requests from this client IP in the last 60 seconds (`RATE_LIMITED`); wait `Retry-After` seconds. |
|
|
1626
1736
|
|
|
1627
1737
|
```ts
|
|
1628
|
-
for await (const member of auth.admin.app("
|
|
1738
|
+
for await (const member of auth.admin.app("3f0c3c1e-8a2b-4c55-9d3f-0a1b2c3d4e5f").members.list()) {
|
|
1629
1739
|
console.log(member);
|
|
1630
1740
|
}
|
|
1631
|
-
const page = await auth.admin.app("
|
|
1741
|
+
const page = await auth.admin.app("3f0c3c1e-8a2b-4c55-9d3f-0a1b2c3d4e5f").members.list({}, { timeout: 5_000 });
|
|
1632
1742
|
```
|
|
1633
1743
|
|
|
1634
1744
|
[HTTP reference](https://productcraft.co/docs/auth/api-reference#get-v1-apps-app-id-members)
|
|
@@ -1643,6 +1753,8 @@ Read the per-app notification settings. Absent row reads as defaults (notificati
|
|
|
1643
1753
|
|
|
1644
1754
|
`effective_sender` is the sender emails actually go out from, checked live in Mail with your own access (the workspace default sender, or the app's custom address).
|
|
1645
1755
|
|
|
1756
|
+
- Credential: [`workspace_key`](#workspace_key)
|
|
1757
|
+
|
|
1646
1758
|
| Status | Error class | Codes | When |
|
|
1647
1759
|
|---|---|---|---|
|
|
1648
1760
|
| 401 | `AuthenticationError` | `UNAUTHORIZED` | Missing or invalid bearer token. |
|
|
@@ -1651,7 +1763,7 @@ Read the per-app notification settings. Absent row reads as defaults (notificati
|
|
|
1651
1763
|
| 429 | `RateLimitError` | `RATE_LIMITED` | Rate limited: too many requests from this client IP in the last 60 seconds (`RATE_LIMITED`); wait `Retry-After` seconds. |
|
|
1652
1764
|
|
|
1653
1765
|
```ts
|
|
1654
|
-
const appNotificationSettings = await auth.admin.app("
|
|
1766
|
+
const appNotificationSettings = await auth.admin.app("3f0c3c1e-8a2b-4c55-9d3f-0a1b2c3d4e5f").notificationSettings.retrieve();
|
|
1655
1767
|
```
|
|
1656
1768
|
|
|
1657
1769
|
[HTTP reference](https://productcraft.co/docs/auth/api-reference#get-v1-apps-app-id-notification-settings)
|
|
@@ -1665,6 +1777,7 @@ Update the per-app notification settings. Each field is independently optional;
|
|
|
1665
1777
|
Turning `notifications_via_envoi` on (from off) creates the default template of every empty slot in the workspace's Mail templates (`auth-verification`, `auth-welcome`, `auth-password-reset`, `auth-invite`, `auth-mfa-code`), reusing a template that already has that name, and fills the slot. Templates are created with your own Mail access; a slot that could not be created stays empty. A slot you clear later is not refilled until emails are switched off and on again.
|
|
1666
1778
|
|
|
1667
1779
|
- Params: `Auth.NotificationSettingUpdateParams`
|
|
1780
|
+
- Credential: [`workspace_key`](#workspace_key)
|
|
1668
1781
|
|
|
1669
1782
|
| Status | Error class | Codes | When |
|
|
1670
1783
|
|---|---|---|---|
|
|
@@ -1676,7 +1789,7 @@ Turning `notifications_via_envoi` on (from off) creates the default template of
|
|
|
1676
1789
|
| 429 | `RateLimitError` | `RATE_LIMITED` | Rate limited: too many requests from this client IP in the last 60 seconds (`RATE_LIMITED`); wait `Retry-After` seconds. |
|
|
1677
1790
|
|
|
1678
1791
|
```ts
|
|
1679
|
-
const appNotificationSettings = await auth.admin.app("
|
|
1792
|
+
const appNotificationSettings = await auth.admin.app("3f0c3c1e-8a2b-4c55-9d3f-0a1b2c3d4e5f").notificationSettings.update({ default_sender_address: "ada@example.com" });
|
|
1680
1793
|
```
|
|
1681
1794
|
|
|
1682
1795
|
[HTTP reference](https://productcraft.co/docs/auth/api-reference#patch-v1-apps-app-id-notification-settings)
|
|
@@ -1692,6 +1805,7 @@ Send me a test of one email.
|
|
|
1692
1805
|
Sends the slot's real Mail template, with this app's real sender (the workspace default or the custom address) and example values for every variable, to your own verified account address. It cannot be sent anywhere else. It uses your own Mail access, goes through the same send path as real emails, and shows up in Mail > Emails. At most 10 tests per person per hour. Not available to API keys (a key has no inbox).
|
|
1693
1806
|
|
|
1694
1807
|
- Idempotent: an `Idempotency-Key` is sent automatically and reused on retries
|
|
1808
|
+
- Credential: [`workspace_key`](#workspace_key)
|
|
1695
1809
|
|
|
1696
1810
|
| Status | Error class | Codes | When |
|
|
1697
1811
|
|---|---|---|---|
|
|
@@ -1706,7 +1820,7 @@ Sends the slot's real Mail template, with this app's real sender (the workspace
|
|
|
1706
1820
|
| 503 | `InternalServerError` | `SERVICE_UNAVAILABLE`, `MAIL_UNREACHABLE` | `MAIL_UNREACHABLE`: Mail did not answer. |
|
|
1707
1821
|
|
|
1708
1822
|
```ts
|
|
1709
|
-
const notificationTest = await auth.admin.app("
|
|
1823
|
+
const notificationTest = await auth.admin.app("3f0c3c1e-8a2b-4c55-9d3f-0a1b2c3d4e5f").notifications.test("verification");
|
|
1710
1824
|
```
|
|
1711
1825
|
|
|
1712
1826
|
[HTTP reference](https://productcraft.co/docs/auth/api-reference#post-v1-apps-app-id-notifications-slot-test)
|
|
@@ -1721,6 +1835,7 @@ Create a custom permission.
|
|
|
1721
1835
|
|
|
1722
1836
|
- Params: `Auth.AppScopedPermissionCreateParams`
|
|
1723
1837
|
- Idempotent: an `Idempotency-Key` is sent automatically and reused on retries
|
|
1838
|
+
- Credential: [`workspace_key`](#workspace_key)
|
|
1724
1839
|
|
|
1725
1840
|
| Status | Error class | Codes | When |
|
|
1726
1841
|
|---|---|---|---|
|
|
@@ -1732,7 +1847,7 @@ Create a custom permission.
|
|
|
1732
1847
|
| 429 | `RateLimitError` | `RATE_LIMITED` | Rate limited: too many requests from this client IP in the last 60 seconds (`RATE_LIMITED`); wait `Retry-After` seconds. |
|
|
1733
1848
|
|
|
1734
1849
|
```ts
|
|
1735
|
-
const permission = await auth.admin.app("
|
|
1850
|
+
const permission = await auth.admin.app("3f0c3c1e-8a2b-4c55-9d3f-0a1b2c3d4e5f").permissions.create({ action: "read", resource: "project" });
|
|
1736
1851
|
```
|
|
1737
1852
|
|
|
1738
1853
|
[HTTP reference](https://productcraft.co/docs/auth/api-reference#post-v1-apps-app-id-permissions)
|
|
@@ -1743,6 +1858,8 @@ const permission = await auth.admin.app("app").permissions.create({ action: "rea
|
|
|
1743
1858
|
|
|
1744
1859
|
Delete a custom permission.
|
|
1745
1860
|
|
|
1861
|
+
- Credential: [`workspace_key`](#workspace_key)
|
|
1862
|
+
|
|
1746
1863
|
| Status | Error class | Codes | When |
|
|
1747
1864
|
|---|---|---|---|
|
|
1748
1865
|
| 400 | `BadRequestError` | `BAD_REQUEST`, `VALIDATION_ERROR` | `permissionKey` is not in `resource.action` format. |
|
|
@@ -1752,7 +1869,7 @@ Delete a custom permission.
|
|
|
1752
1869
|
| 429 | `RateLimitError` | `RATE_LIMITED` | Rate limited: too many requests from this client IP in the last 60 seconds (`RATE_LIMITED`); wait `Retry-After` seconds. |
|
|
1753
1870
|
|
|
1754
1871
|
```ts
|
|
1755
|
-
await auth.admin.app("
|
|
1872
|
+
await auth.admin.app("3f0c3c1e-8a2b-4c55-9d3f-0a1b2c3d4e5f").permissions.delete("invoice.read");
|
|
1756
1873
|
```
|
|
1757
1874
|
|
|
1758
1875
|
[HTTP reference](https://productcraft.co/docs/auth/api-reference#delete-v1-apps-app-id-permissions-permission-key)
|
|
@@ -1763,6 +1880,8 @@ await auth.admin.app("app").permissions.delete("permission_key");
|
|
|
1763
1880
|
|
|
1764
1881
|
List all permissions (system + custom).
|
|
1765
1882
|
|
|
1883
|
+
- Credential: [`workspace_key`](#workspace_key)
|
|
1884
|
+
|
|
1766
1885
|
| Status | Error class | Codes | When |
|
|
1767
1886
|
|---|---|---|---|
|
|
1768
1887
|
| 401 | `AuthenticationError` | `UNAUTHORIZED` | Missing or invalid bearer token. |
|
|
@@ -1771,7 +1890,7 @@ List all permissions (system + custom).
|
|
|
1771
1890
|
| 429 | `RateLimitError` | `RATE_LIMITED` | Rate limited: too many requests from this client IP in the last 60 seconds (`RATE_LIMITED`); wait `Retry-After` seconds. |
|
|
1772
1891
|
|
|
1773
1892
|
```ts
|
|
1774
|
-
const result = await auth.admin.app("
|
|
1893
|
+
const result = await auth.admin.app("3f0c3c1e-8a2b-4c55-9d3f-0a1b2c3d4e5f").permissions.list();
|
|
1775
1894
|
```
|
|
1776
1895
|
|
|
1777
1896
|
[HTTP reference](https://productcraft.co/docs/auth/api-reference#get-v1-apps-app-id-permissions)
|
|
@@ -1786,6 +1905,8 @@ List permissions that at least one Consumer-API route enforces.
|
|
|
1786
1905
|
|
|
1787
1906
|
Returns the deduplicated set of permission strings that any handler in this users-api build gates via `@RequireAppPermission`. Drives the console "Enforced" badge — a customer who binds `user.delete` to a role can see whether any route in this deploy actually checks for it. App-agnostic in shape; the path parameter is included for URN symmetry with the rest of the per-app surface, not to narrow the response.
|
|
1788
1907
|
|
|
1908
|
+
- Credential: [`workspace_key`](#workspace_key)
|
|
1909
|
+
|
|
1789
1910
|
| Status | Error class | Codes | When |
|
|
1790
1911
|
|---|---|---|---|
|
|
1791
1912
|
| 401 | `AuthenticationError` | `UNAUTHORIZED` | Missing or invalid bearer token. |
|
|
@@ -1794,7 +1915,7 @@ Returns the deduplicated set of permission strings that any handler in this user
|
|
|
1794
1915
|
| 429 | `RateLimitError` | `RATE_LIMITED` | Rate limited: too many requests from this client IP in the last 60 seconds (`RATE_LIMITED`); wait `Retry-After` seconds. |
|
|
1795
1916
|
|
|
1796
1917
|
```ts
|
|
1797
|
-
const enforcedPermissions = await auth.admin.app("
|
|
1918
|
+
const enforcedPermissions = await auth.admin.app("3f0c3c1e-8a2b-4c55-9d3f-0a1b2c3d4e5f").permissions.enforcement.list();
|
|
1798
1919
|
```
|
|
1799
1920
|
|
|
1800
1921
|
[HTTP reference](https://productcraft.co/docs/auth/api-reference#get-v1-apps-app-id-permissions-enforcement)
|
|
@@ -1808,6 +1929,7 @@ const enforcedPermissions = await auth.admin.app("app").permissions.enforcement.
|
|
|
1808
1929
|
Assign a role to a user.
|
|
1809
1930
|
|
|
1810
1931
|
- Params: `Auth.RoleAssignParams`
|
|
1932
|
+
- Credential: [`workspace_key`](#workspace_key)
|
|
1811
1933
|
|
|
1812
1934
|
| Status | Error class | Codes | When |
|
|
1813
1935
|
|---|---|---|---|
|
|
@@ -1818,7 +1940,7 @@ Assign a role to a user.
|
|
|
1818
1940
|
| 429 | `RateLimitError` | `RATE_LIMITED` | Rate limited: too many requests from this client IP in the last 60 seconds (`RATE_LIMITED`); wait `Retry-After` seconds. |
|
|
1819
1941
|
|
|
1820
1942
|
```ts
|
|
1821
|
-
const appMembership = await auth.admin.app("
|
|
1943
|
+
const appMembership = await auth.admin.app("3f0c3c1e-8a2b-4c55-9d3f-0a1b2c3d4e5f").roles.assign({ account_id: "3f0c3c1e-8a2b-4c55-9d3f-0a1b2c3d4e5f", role: "admin" });
|
|
1822
1944
|
```
|
|
1823
1945
|
|
|
1824
1946
|
[HTTP reference](https://productcraft.co/docs/auth/api-reference#post-v1-apps-app-id-roles-assign)
|
|
@@ -1831,6 +1953,7 @@ Create a new role (no permissions yet — set them via PUT /:roleName/permission
|
|
|
1831
1953
|
|
|
1832
1954
|
- Params: `Auth.AppScopedRoleCreateParams`
|
|
1833
1955
|
- Idempotent: an `Idempotency-Key` is sent automatically and reused on retries
|
|
1956
|
+
- Credential: [`workspace_key`](#workspace_key)
|
|
1834
1957
|
|
|
1835
1958
|
| Status | Error class | Codes | When |
|
|
1836
1959
|
|---|---|---|---|
|
|
@@ -1842,7 +1965,7 @@ Create a new role (no permissions yet — set them via PUT /:roleName/permission
|
|
|
1842
1965
|
| 429 | `RateLimitError` | `RATE_LIMITED` | Rate limited: too many requests from this client IP in the last 60 seconds (`RATE_LIMITED`); wait `Retry-After` seconds. |
|
|
1843
1966
|
|
|
1844
1967
|
```ts
|
|
1845
|
-
const role = await auth.admin.app("
|
|
1968
|
+
const role = await auth.admin.app("3f0c3c1e-8a2b-4c55-9d3f-0a1b2c3d4e5f").roles.create({ name: "editor" });
|
|
1846
1969
|
```
|
|
1847
1970
|
|
|
1848
1971
|
[HTTP reference](https://productcraft.co/docs/auth/api-reference#post-v1-apps-app-id-roles)
|
|
@@ -1853,6 +1976,8 @@ const role = await auth.admin.app("app").roles.create({ name: "editor" });
|
|
|
1853
1976
|
|
|
1854
1977
|
Delete a custom role.
|
|
1855
1978
|
|
|
1979
|
+
- Credential: [`workspace_key`](#workspace_key)
|
|
1980
|
+
|
|
1856
1981
|
| Status | Error class | Codes | When |
|
|
1857
1982
|
|---|---|---|---|
|
|
1858
1983
|
| 401 | `AuthenticationError` | `UNAUTHORIZED` | Missing or invalid bearer token. |
|
|
@@ -1862,7 +1987,7 @@ Delete a custom role.
|
|
|
1862
1987
|
| 429 | `RateLimitError` | `RATE_LIMITED` | Rate limited: too many requests from this client IP in the last 60 seconds (`RATE_LIMITED`); wait `Retry-After` seconds. |
|
|
1863
1988
|
|
|
1864
1989
|
```ts
|
|
1865
|
-
await auth.admin.app("
|
|
1990
|
+
await auth.admin.app("3f0c3c1e-8a2b-4c55-9d3f-0a1b2c3d4e5f").roles.delete("admin");
|
|
1866
1991
|
```
|
|
1867
1992
|
|
|
1868
1993
|
[HTTP reference](https://productcraft.co/docs/auth/api-reference#delete-v1-apps-app-id-roles-role-name)
|
|
@@ -1875,6 +2000,7 @@ List all roles in an app. Filter by `?search=` on the role name.
|
|
|
1875
2000
|
|
|
1876
2001
|
- Params: `Auth.AppScopedRoleListParams`
|
|
1877
2002
|
- Paginated: `for await` iterates every item; `await` gives one page
|
|
2003
|
+
- Credential: [`workspace_key`](#workspace_key)
|
|
1878
2004
|
|
|
1879
2005
|
| Status | Error class | Codes | When |
|
|
1880
2006
|
|---|---|---|---|
|
|
@@ -1885,10 +2011,10 @@ List all roles in an app. Filter by `?search=` on the role name.
|
|
|
1885
2011
|
| 429 | `RateLimitError` | `RATE_LIMITED` | Rate limited: too many requests from this client IP in the last 60 seconds (`RATE_LIMITED`); wait `Retry-After` seconds. |
|
|
1886
2012
|
|
|
1887
2013
|
```ts
|
|
1888
|
-
for await (const role of auth.admin.app("
|
|
2014
|
+
for await (const role of auth.admin.app("3f0c3c1e-8a2b-4c55-9d3f-0a1b2c3d4e5f").roles.list()) {
|
|
1889
2015
|
console.log(role);
|
|
1890
2016
|
}
|
|
1891
|
-
const page = await auth.admin.app("
|
|
2017
|
+
const page = await auth.admin.app("3f0c3c1e-8a2b-4c55-9d3f-0a1b2c3d4e5f").roles.list({}, { timeout: 5_000 });
|
|
1892
2018
|
```
|
|
1893
2019
|
|
|
1894
2020
|
[HTTP reference](https://productcraft.co/docs/auth/api-reference#get-v1-apps-app-id-roles)
|
|
@@ -1899,6 +2025,8 @@ const page = await auth.admin.app("app").roles.list({}, { timeout: 5_000 });
|
|
|
1899
2025
|
|
|
1900
2026
|
Get role details with permissions.
|
|
1901
2027
|
|
|
2028
|
+
- Credential: [`workspace_key`](#workspace_key)
|
|
2029
|
+
|
|
1902
2030
|
| Status | Error class | Codes | When |
|
|
1903
2031
|
|---|---|---|---|
|
|
1904
2032
|
| 401 | `AuthenticationError` | `UNAUTHORIZED` | Missing or invalid bearer token. |
|
|
@@ -1907,7 +2035,7 @@ Get role details with permissions.
|
|
|
1907
2035
|
| 429 | `RateLimitError` | `RATE_LIMITED` | Rate limited: too many requests from this client IP in the last 60 seconds (`RATE_LIMITED`); wait `Retry-After` seconds. |
|
|
1908
2036
|
|
|
1909
2037
|
```ts
|
|
1910
|
-
const roleWithPermissions = await auth.admin.app("
|
|
2038
|
+
const roleWithPermissions = await auth.admin.app("3f0c3c1e-8a2b-4c55-9d3f-0a1b2c3d4e5f").roles.retrieve("admin");
|
|
1911
2039
|
```
|
|
1912
2040
|
|
|
1913
2041
|
[HTTP reference](https://productcraft.co/docs/auth/api-reference#get-v1-apps-app-id-roles-role-name)
|
|
@@ -1919,6 +2047,7 @@ const roleWithPermissions = await auth.admin.app("app").roles.retrieve("role_nam
|
|
|
1919
2047
|
Update role name or description.
|
|
1920
2048
|
|
|
1921
2049
|
- Params: `Auth.AppScopedRoleUpdateParams`
|
|
2050
|
+
- Credential: [`workspace_key`](#workspace_key)
|
|
1922
2051
|
|
|
1923
2052
|
| Status | Error class | Codes | When |
|
|
1924
2053
|
|---|---|---|---|
|
|
@@ -1929,7 +2058,7 @@ Update role name or description.
|
|
|
1929
2058
|
| 429 | `RateLimitError` | `RATE_LIMITED` | Rate limited: too many requests from this client IP in the last 60 seconds (`RATE_LIMITED`); wait `Retry-After` seconds. |
|
|
1930
2059
|
|
|
1931
2060
|
```ts
|
|
1932
|
-
const role = await auth.admin.app("
|
|
2061
|
+
const role = await auth.admin.app("3f0c3c1e-8a2b-4c55-9d3f-0a1b2c3d4e5f").roles.update("admin", { description: "Updated description" });
|
|
1933
2062
|
```
|
|
1934
2063
|
|
|
1935
2064
|
[HTTP reference](https://productcraft.co/docs/auth/api-reference#patch-v1-apps-app-id-roles-role-name)
|
|
@@ -1941,6 +2070,7 @@ const role = await auth.admin.app("app").roles.update("role_name", { description
|
|
|
1941
2070
|
Set permissions for a role (caller-narrowed: caller must hold every requested permission).
|
|
1942
2071
|
|
|
1943
2072
|
- Params: `Auth.AppScopedRoleUpdatePermissionsParams`
|
|
2073
|
+
- Credential: [`workspace_key`](#workspace_key)
|
|
1944
2074
|
|
|
1945
2075
|
| Status | Error class | Codes | When |
|
|
1946
2076
|
|---|---|---|---|
|
|
@@ -1951,7 +2081,7 @@ Set permissions for a role (caller-narrowed: caller must hold every requested pe
|
|
|
1951
2081
|
| 429 | `RateLimitError` | `RATE_LIMITED` | Rate limited: too many requests from this client IP in the last 60 seconds (`RATE_LIMITED`); wait `Retry-After` seconds. |
|
|
1952
2082
|
|
|
1953
2083
|
```ts
|
|
1954
|
-
const result = await auth.admin.app("
|
|
2084
|
+
const result = await auth.admin.app("3f0c3c1e-8a2b-4c55-9d3f-0a1b2c3d4e5f").roles.updatePermissions("admin", { permissions: ["user.read", "role.create"] });
|
|
1955
2085
|
```
|
|
1956
2086
|
|
|
1957
2087
|
[HTTP reference](https://productcraft.co/docs/auth/api-reference#put-v1-apps-app-id-roles-role-name-permissions)
|
|
@@ -1964,6 +2094,8 @@ const result = await auth.admin.app("app").roles.updatePermissions("role_name",
|
|
|
1964
2094
|
|
|
1965
2095
|
List all available permissions.
|
|
1966
2096
|
|
|
2097
|
+
- Credential: [`workspace_key`](#workspace_key)
|
|
2098
|
+
|
|
1967
2099
|
| Status | Error class | Codes | When |
|
|
1968
2100
|
|---|---|---|---|
|
|
1969
2101
|
| 401 | `AuthenticationError` | `UNAUTHORIZED` | Missing or invalid bearer token. |
|
|
@@ -1972,7 +2104,7 @@ List all available permissions.
|
|
|
1972
2104
|
| 429 | `RateLimitError` | `RATE_LIMITED` | Rate limited: too many requests from this client IP in the last 60 seconds (`RATE_LIMITED`); wait `Retry-After` seconds. |
|
|
1973
2105
|
|
|
1974
2106
|
```ts
|
|
1975
|
-
const result = await auth.admin.app("
|
|
2107
|
+
const result = await auth.admin.app("3f0c3c1e-8a2b-4c55-9d3f-0a1b2c3d4e5f").roles.permissions.list();
|
|
1976
2108
|
```
|
|
1977
2109
|
|
|
1978
2110
|
[HTTP reference](https://productcraft.co/docs/auth/api-reference#get-v1-apps-app-id-roles-permissions)
|
|
@@ -1987,6 +2119,8 @@ Get the setup checklist for an app: what works, what is missing, and where to fi
|
|
|
1987
2119
|
|
|
1988
2120
|
Rows, in order: `signups` (attention while sign-ups are off), `redirect_origins` (blocked until at least one site may start sign-in), one `provider_<id>` row per switched-on sign-in provider (blocked while its status is blocked), `email` (sender chosen and a template for every email; attention while emails are off), `api_key` (attention until an active app key exists), `webhook` (attention until an endpoint has accepted a delivery), and `passkeys` (only while passkeys are on; blocked when no allowed redirect origin is on the passkey site). `complete` is true once no row is `not_set` or `blocked`. Each `fix.href` is a console path to the exact setting. Computed on every request from stored settings, plus the workspace default sender read from Mail with your own access when emails use it: nothing here calls DNS or a sign-in provider (a provider whose last credential check was rejected shows as blocked). A ready provider row carries `test.action: sign_in.try`: run it with `POST /v1/apps/{appId}/sign-in-tests` `{ method: "oauth", provider }`.
|
|
1989
2121
|
|
|
2122
|
+
- Credential: [`workspace_key`](#workspace_key)
|
|
2123
|
+
|
|
1990
2124
|
| Status | Error class | Codes | When |
|
|
1991
2125
|
|---|---|---|---|
|
|
1992
2126
|
| 401 | `AuthenticationError` | `UNAUTHORIZED` | Missing or invalid bearer token. |
|
|
@@ -1995,7 +2129,7 @@ Rows, in order: `signups` (attention while sign-ups are off), `redirect_origins`
|
|
|
1995
2129
|
| 429 | `RateLimitError` | `RATE_LIMITED` | Rate limited: too many requests from this client IP in the last 60 seconds (`RATE_LIMITED`); wait `Retry-After` seconds. |
|
|
1996
2130
|
|
|
1997
2131
|
```ts
|
|
1998
|
-
const setupStatus = await auth.admin.app("
|
|
2132
|
+
const setupStatus = await auth.admin.app("3f0c3c1e-8a2b-4c55-9d3f-0a1b2c3d4e5f").setupStatus.retrieve();
|
|
1999
2133
|
```
|
|
2000
2134
|
|
|
2001
2135
|
[HTTP reference](https://productcraft.co/docs/auth/api-reference#get-v1-apps-app-id-setup-status)
|
|
@@ -2012,6 +2146,7 @@ For `oauth`, the server first checks what it can on its own (an allowed redirect
|
|
|
2012
2146
|
|
|
2013
2147
|
- Params: `Auth.SignInTestCreateParams`
|
|
2014
2148
|
- Idempotent: an `Idempotency-Key` is sent automatically and reused on retries
|
|
2149
|
+
- Credential: [`workspace_key`](#workspace_key)
|
|
2015
2150
|
|
|
2016
2151
|
| Status | Error class | Codes | When |
|
|
2017
2152
|
|---|---|---|---|
|
|
@@ -2023,7 +2158,7 @@ For `oauth`, the server first checks what it can on its own (an allowed redirect
|
|
|
2023
2158
|
| 429 | `RateLimitError` | `RATE_LIMITED` | More than 20 tests for this app in the last hour (`RATE_LIMITED`). |
|
|
2024
2159
|
|
|
2025
2160
|
```ts
|
|
2026
|
-
const signInTest = await auth.admin.app("
|
|
2161
|
+
const signInTest = await auth.admin.app("3f0c3c1e-8a2b-4c55-9d3f-0a1b2c3d4e5f").signInTests.create({ method: "oauth" });
|
|
2027
2162
|
```
|
|
2028
2163
|
|
|
2029
2164
|
[HTTP reference](https://productcraft.co/docs/auth/api-reference#post-v1-apps-app-id-sign-in-tests)
|
|
@@ -2036,6 +2171,8 @@ Get a sign-in test and its result.
|
|
|
2036
2171
|
|
|
2037
2172
|
Poll this after opening `start_url`. `state` turns `succeeded` (with `outcome` and `identity`) or `failed` (with `error.fix`). A test that is never finished turns `failed` with code `expired` 15 minutes after it was created.
|
|
2038
2173
|
|
|
2174
|
+
- Credential: [`workspace_key`](#workspace_key)
|
|
2175
|
+
|
|
2039
2176
|
| Status | Error class | Codes | When |
|
|
2040
2177
|
|---|---|---|---|
|
|
2041
2178
|
| 400 | `BadRequestError` | `BAD_REQUEST`, `VALIDATION_ERROR` | `testId` is not a UUID. |
|
|
@@ -2045,7 +2182,7 @@ Poll this after opening `start_url`. `state` turns `succeeded` (with `outcome` a
|
|
|
2045
2182
|
| 429 | `RateLimitError` | `RATE_LIMITED` | Rate limited: too many requests from this client IP in the last 60 seconds (`RATE_LIMITED`); wait `Retry-After` seconds. |
|
|
2046
2183
|
|
|
2047
2184
|
```ts
|
|
2048
|
-
const signInTest = await auth.admin.app("
|
|
2185
|
+
const signInTest = await auth.admin.app("3f0c3c1e-8a2b-4c55-9d3f-0a1b2c3d4e5f").signInTests.retrieve("3f0c3c1e-8a2b-4c55-9d3f-0a1b2c3d4e5f");
|
|
2049
2186
|
```
|
|
2050
2187
|
|
|
2051
2188
|
[HTTP reference](https://productcraft.co/docs/auth/api-reference#get-v1-apps-app-id-sign-in-tests-test-id)
|
|
@@ -2060,6 +2197,8 @@ Revoke a tenant's API key.
|
|
|
2060
2197
|
|
|
2061
2198
|
Immediate and final; recorded as revoked by you (`revoked_by_type: platform_user`) in the key and in the audit log. Idempotent: revoking a revoked key is a 204 that changes nothing. Requires `auth.revoke` on the app.
|
|
2062
2199
|
|
|
2200
|
+
- Credential: [`workspace_key`](#workspace_key)
|
|
2201
|
+
|
|
2063
2202
|
| Status | Error class | Codes | When |
|
|
2064
2203
|
|---|---|---|---|
|
|
2065
2204
|
| 401 | `AuthenticationError` | `UNAUTHORIZED` | Missing or invalid bearer token. |
|
|
@@ -2068,7 +2207,7 @@ Immediate and final; recorded as revoked by you (`revoked_by_type: platform_user
|
|
|
2068
2207
|
| 429 | `RateLimitError` | `RATE_LIMITED` | Rate limited: too many requests from this client IP in the last 60 seconds (`RATE_LIMITED`); wait `Retry-After` seconds. |
|
|
2069
2208
|
|
|
2070
2209
|
```ts
|
|
2071
|
-
await auth.admin.app("
|
|
2210
|
+
await auth.admin.app("3f0c3c1e-8a2b-4c55-9d3f-0a1b2c3d4e5f").tenantApiKeys.delete("3f0c3c1e-8a2b-4c55-9d3f-0a1b2c3d4e5f");
|
|
2072
2211
|
```
|
|
2073
2212
|
|
|
2074
2213
|
[HTTP reference](https://productcraft.co/docs/auth/api-reference#delete-v1-apps-app-id-tenant-api-keys-key-id)
|
|
@@ -2083,6 +2222,7 @@ Every tenant of the app, newest first, cursor-paginated (20 per page, max 100).
|
|
|
2083
2222
|
|
|
2084
2223
|
- Params: `Auth.AppScopedTenantApiKeyListParams`
|
|
2085
2224
|
- Paginated: `for await` iterates every item; `await` gives one page
|
|
2225
|
+
- Credential: [`workspace_key`](#workspace_key)
|
|
2086
2226
|
|
|
2087
2227
|
| Status | Error class | Codes | When |
|
|
2088
2228
|
|---|---|---|---|
|
|
@@ -2093,10 +2233,10 @@ Every tenant of the app, newest first, cursor-paginated (20 per page, max 100).
|
|
|
2093
2233
|
| 429 | `RateLimitError` | `RATE_LIMITED` | Rate limited: too many requests from this client IP in the last 60 seconds (`RATE_LIMITED`); wait `Retry-After` seconds. |
|
|
2094
2234
|
|
|
2095
2235
|
```ts
|
|
2096
|
-
for await (const tenantApiKey of auth.admin.app("
|
|
2236
|
+
for await (const tenantApiKey of auth.admin.app("3f0c3c1e-8a2b-4c55-9d3f-0a1b2c3d4e5f").tenantApiKeys.list()) {
|
|
2097
2237
|
console.log(tenantApiKey);
|
|
2098
2238
|
}
|
|
2099
|
-
const page = await auth.admin.app("
|
|
2239
|
+
const page = await auth.admin.app("3f0c3c1e-8a2b-4c55-9d3f-0a1b2c3d4e5f").tenantApiKeys.list({}, { timeout: 5_000 });
|
|
2100
2240
|
```
|
|
2101
2241
|
|
|
2102
2242
|
[HTTP reference](https://productcraft.co/docs/auth/api-reference#get-v1-apps-app-id-tenant-api-keys)
|
|
@@ -2111,6 +2251,8 @@ Read the app's tenant API key settings.
|
|
|
2111
2251
|
|
|
2112
2252
|
Includes the platform kill switch `suspended`. Requires `auth.read` on the app.
|
|
2113
2253
|
|
|
2254
|
+
- Credential: [`workspace_key`](#workspace_key)
|
|
2255
|
+
|
|
2114
2256
|
| Status | Error class | Codes | When |
|
|
2115
2257
|
|---|---|---|---|
|
|
2116
2258
|
| 401 | `AuthenticationError` | `UNAUTHORIZED` | Missing or invalid bearer token. |
|
|
@@ -2119,7 +2261,7 @@ Includes the platform kill switch `suspended`. Requires `auth.read` on the app.
|
|
|
2119
2261
|
| 429 | `RateLimitError` | `RATE_LIMITED` | Rate limited: too many requests from this client IP in the last 60 seconds (`RATE_LIMITED`); wait `Retry-After` seconds. |
|
|
2120
2262
|
|
|
2121
2263
|
```ts
|
|
2122
|
-
const tenantApiKeysConfig = await auth.admin.app("
|
|
2264
|
+
const tenantApiKeysConfig = await auth.admin.app("3f0c3c1e-8a2b-4c55-9d3f-0a1b2c3d4e5f").tenantApiKeys.config.retrieve();
|
|
2123
2265
|
```
|
|
2124
2266
|
|
|
2125
2267
|
[HTTP reference](https://productcraft.co/docs/auth/api-reference#get-v1-apps-app-id-tenant-api-keys-config)
|
|
@@ -2134,6 +2276,7 @@ Fields you leave out keep their stored value. `suspended: true` is the kill swit
|
|
|
2134
2276
|
|
|
2135
2277
|
- Params: `Auth.AppScopedTenantApiKeyConfigUpdateParams`
|
|
2136
2278
|
- Idempotent: an `Idempotency-Key` is sent automatically and reused on retries
|
|
2279
|
+
- Credential: [`workspace_key`](#workspace_key)
|
|
2137
2280
|
|
|
2138
2281
|
| Status | Error class | Codes | When |
|
|
2139
2282
|
|---|---|---|---|
|
|
@@ -2145,7 +2288,7 @@ Fields you leave out keep their stored value. `suspended: true` is the kill swit
|
|
|
2145
2288
|
| 429 | `RateLimitError` | `RATE_LIMITED` | Rate limited: too many requests from this client IP in the last 60 seconds (`RATE_LIMITED`); wait `Retry-After` seconds. |
|
|
2146
2289
|
|
|
2147
2290
|
```ts
|
|
2148
|
-
const tenantApiKeysConfig = await auth.admin.app("
|
|
2291
|
+
const tenantApiKeysConfig = await auth.admin.app("3f0c3c1e-8a2b-4c55-9d3f-0a1b2c3d4e5f").tenantApiKeys.config.update({ default_expiry_days: 7 });
|
|
2149
2292
|
```
|
|
2150
2293
|
|
|
2151
2294
|
[HTTP reference](https://productcraft.co/docs/auth/api-reference#put-v1-apps-app-id-tenant-api-keys-config)
|
|
@@ -2160,6 +2303,7 @@ Create a tenant in this app. Auth-admin lane; requires auth.tenant.create on the
|
|
|
2160
2303
|
|
|
2161
2304
|
- Params: `Auth.AppScopedTenantCreateParams`
|
|
2162
2305
|
- Idempotent: an `Idempotency-Key` is sent automatically and reused on retries
|
|
2306
|
+
- Credential: [`workspace_key`](#workspace_key)
|
|
2163
2307
|
|
|
2164
2308
|
| Status | Error class | Codes | When |
|
|
2165
2309
|
|---|---|---|---|
|
|
@@ -2171,7 +2315,7 @@ Create a tenant in this app. Auth-admin lane; requires auth.tenant.create on the
|
|
|
2171
2315
|
| 429 | `RateLimitError` | `RATE_LIMITED` | Rate limited: too many requests from this client IP in the last 60 seconds (`RATE_LIMITED`); wait `Retry-After` seconds. |
|
|
2172
2316
|
|
|
2173
2317
|
```ts
|
|
2174
|
-
const tenant = await auth.admin.app("
|
|
2318
|
+
const tenant = await auth.admin.app("3f0c3c1e-8a2b-4c55-9d3f-0a1b2c3d4e5f").tenants.create({ display_name: "Acme Co" });
|
|
2175
2319
|
```
|
|
2176
2320
|
|
|
2177
2321
|
[HTTP reference](https://productcraft.co/docs/auth/api-reference#post-v1-apps-app-id-tenants)
|
|
@@ -2182,6 +2326,8 @@ const tenant = await auth.admin.app("app").tenants.create({ display_name: "Acme
|
|
|
2182
2326
|
|
|
2183
2327
|
Delete a tenant.
|
|
2184
2328
|
|
|
2329
|
+
- Credential: [`workspace_key`](#workspace_key)
|
|
2330
|
+
|
|
2185
2331
|
| Status | Error class | Codes | When |
|
|
2186
2332
|
|---|---|---|---|
|
|
2187
2333
|
| 401 | `AuthenticationError` | `UNAUTHORIZED` | Missing or invalid bearer token. |
|
|
@@ -2190,7 +2336,7 @@ Delete a tenant.
|
|
|
2190
2336
|
| 429 | `RateLimitError` | `RATE_LIMITED` | Rate limited: too many requests from this client IP in the last 60 seconds (`RATE_LIMITED`); wait `Retry-After` seconds. |
|
|
2191
2337
|
|
|
2192
2338
|
```ts
|
|
2193
|
-
await auth.admin.app("
|
|
2339
|
+
await auth.admin.app("3f0c3c1e-8a2b-4c55-9d3f-0a1b2c3d4e5f").tenants.delete("3f0c3c1e-8a2b-4c55-9d3f-0a1b2c3d4e5f");
|
|
2194
2340
|
```
|
|
2195
2341
|
|
|
2196
2342
|
[HTTP reference](https://productcraft.co/docs/auth/api-reference#delete-v1-apps-app-id-tenants-tenant-id)
|
|
@@ -2203,6 +2349,7 @@ List tenants in this app, paginated by created_at desc.
|
|
|
2203
2349
|
|
|
2204
2350
|
- Params: `Auth.AppScopedTenantListParams`
|
|
2205
2351
|
- Paginated: `for await` iterates every item; `await` gives one page
|
|
2352
|
+
- Credential: [`workspace_key`](#workspace_key)
|
|
2206
2353
|
|
|
2207
2354
|
| Status | Error class | Codes | When |
|
|
2208
2355
|
|---|---|---|---|
|
|
@@ -2213,10 +2360,10 @@ List tenants in this app, paginated by created_at desc.
|
|
|
2213
2360
|
| 429 | `RateLimitError` | `RATE_LIMITED` | Rate limited: too many requests from this client IP in the last 60 seconds (`RATE_LIMITED`); wait `Retry-After` seconds. |
|
|
2214
2361
|
|
|
2215
2362
|
```ts
|
|
2216
|
-
for await (const tenant of auth.admin.app("
|
|
2363
|
+
for await (const tenant of auth.admin.app("3f0c3c1e-8a2b-4c55-9d3f-0a1b2c3d4e5f").tenants.list()) {
|
|
2217
2364
|
console.log(tenant);
|
|
2218
2365
|
}
|
|
2219
|
-
const page = await auth.admin.app("
|
|
2366
|
+
const page = await auth.admin.app("3f0c3c1e-8a2b-4c55-9d3f-0a1b2c3d4e5f").tenants.list({}, { timeout: 5_000 });
|
|
2220
2367
|
```
|
|
2221
2368
|
|
|
2222
2369
|
[HTTP reference](https://productcraft.co/docs/auth/api-reference#get-v1-apps-app-id-tenants)
|
|
@@ -2227,6 +2374,8 @@ const page = await auth.admin.app("app").tenants.list({}, { timeout: 5_000 });
|
|
|
2227
2374
|
|
|
2228
2375
|
Get a single tenant by id or display id.
|
|
2229
2376
|
|
|
2377
|
+
- Credential: [`workspace_key`](#workspace_key)
|
|
2378
|
+
|
|
2230
2379
|
| Status | Error class | Codes | When |
|
|
2231
2380
|
|---|---|---|---|
|
|
2232
2381
|
| 401 | `AuthenticationError` | `UNAUTHORIZED` | Missing or invalid bearer token. |
|
|
@@ -2235,7 +2384,7 @@ Get a single tenant by id or display id.
|
|
|
2235
2384
|
| 429 | `RateLimitError` | `RATE_LIMITED` | Rate limited: too many requests from this client IP in the last 60 seconds (`RATE_LIMITED`); wait `Retry-After` seconds. |
|
|
2236
2385
|
|
|
2237
2386
|
```ts
|
|
2238
|
-
const tenant = await auth.admin.app("
|
|
2387
|
+
const tenant = await auth.admin.app("3f0c3c1e-8a2b-4c55-9d3f-0a1b2c3d4e5f").tenants.retrieve("3f0c3c1e-8a2b-4c55-9d3f-0a1b2c3d4e5f");
|
|
2239
2388
|
```
|
|
2240
2389
|
|
|
2241
2390
|
[HTTP reference](https://productcraft.co/docs/auth/api-reference#get-v1-apps-app-id-tenants-tenant-id)
|
|
@@ -2247,6 +2396,7 @@ const tenant = await auth.admin.app("app").tenants.retrieve("tenant");
|
|
|
2247
2396
|
Update a tenant (display_name, slug, status, metadata).
|
|
2248
2397
|
|
|
2249
2398
|
- Params: `Auth.AppScopedTenantUpdateParams`
|
|
2399
|
+
- Credential: [`workspace_key`](#workspace_key)
|
|
2250
2400
|
|
|
2251
2401
|
| Status | Error class | Codes | When |
|
|
2252
2402
|
|---|---|---|---|
|
|
@@ -2258,7 +2408,7 @@ Update a tenant (display_name, slug, status, metadata).
|
|
|
2258
2408
|
| 429 | `RateLimitError` | `RATE_LIMITED` | Rate limited: too many requests from this client IP in the last 60 seconds (`RATE_LIMITED`); wait `Retry-After` seconds. |
|
|
2259
2409
|
|
|
2260
2410
|
```ts
|
|
2261
|
-
const tenant = await auth.admin.app("
|
|
2411
|
+
const tenant = await auth.admin.app("3f0c3c1e-8a2b-4c55-9d3f-0a1b2c3d4e5f").tenants.update("3f0c3c1e-8a2b-4c55-9d3f-0a1b2c3d4e5f", { display_name: "Acme Inc" });
|
|
2262
2412
|
```
|
|
2263
2413
|
|
|
2264
2414
|
[HTTP reference](https://productcraft.co/docs/auth/api-reference#patch-v1-apps-app-id-tenants-tenant-id)
|
|
@@ -2273,6 +2423,7 @@ Invite an email address into a tenant. Returns the plaintext code once; only its
|
|
|
2273
2423
|
|
|
2274
2424
|
- Params: `Auth.AppScopedTenantInviteCreateParams`
|
|
2275
2425
|
- Idempotent: an `Idempotency-Key` is sent automatically and reused on retries
|
|
2426
|
+
- Credential: [`workspace_key`](#workspace_key)
|
|
2276
2427
|
|
|
2277
2428
|
| Status | Error class | Codes | When |
|
|
2278
2429
|
|---|---|---|---|
|
|
@@ -2283,7 +2434,7 @@ Invite an email address into a tenant. Returns the plaintext code once; only its
|
|
|
2283
2434
|
| 429 | `RateLimitError` | `RATE_LIMITED` | Rate limited: too many requests from this client IP in the last 60 seconds (`RATE_LIMITED`); wait `Retry-After` seconds. |
|
|
2284
2435
|
|
|
2285
2436
|
```ts
|
|
2286
|
-
const createTenantInvite = await auth.admin.app("
|
|
2437
|
+
const createTenantInvite = await auth.admin.app("3f0c3c1e-8a2b-4c55-9d3f-0a1b2c3d4e5f").tenants.invites.create("3f0c3c1e-8a2b-4c55-9d3f-0a1b2c3d4e5f", { email: "alice@example.com", role_name: "member" });
|
|
2287
2438
|
```
|
|
2288
2439
|
|
|
2289
2440
|
[HTTP reference](https://productcraft.co/docs/auth/api-reference#post-v1-apps-app-id-tenants-tenant-id-invites)
|
|
@@ -2294,6 +2445,8 @@ const createTenantInvite = await auth.admin.app("app").tenants.invites.create("t
|
|
|
2294
2445
|
|
|
2295
2446
|
Revoke a pending invite. Idempotent — a second revoke is a 204 no-op and fires no second webhook.
|
|
2296
2447
|
|
|
2448
|
+
- Credential: [`workspace_key`](#workspace_key)
|
|
2449
|
+
|
|
2297
2450
|
| Status | Error class | Codes | When |
|
|
2298
2451
|
|---|---|---|---|
|
|
2299
2452
|
| 401 | `AuthenticationError` | `UNAUTHORIZED` | Missing, invalid or expired bearer token. |
|
|
@@ -2301,7 +2454,7 @@ Revoke a pending invite. Idempotent — a second revoke is a 204 no-op and fires
|
|
|
2301
2454
|
| 429 | `RateLimitError` | `RATE_LIMITED` | Rate limited: too many requests from this client IP in the last 60 seconds (`RATE_LIMITED`); wait `Retry-After` seconds. |
|
|
2302
2455
|
|
|
2303
2456
|
```ts
|
|
2304
|
-
await auth.admin.app("
|
|
2457
|
+
await auth.admin.app("3f0c3c1e-8a2b-4c55-9d3f-0a1b2c3d4e5f").tenants.invites.delete("3f0c3c1e-8a2b-4c55-9d3f-0a1b2c3d4e5f", "3f0c3c1e-8a2b-4c55-9d3f-0a1b2c3d4e5f");
|
|
2305
2458
|
```
|
|
2306
2459
|
|
|
2307
2460
|
[HTTP reference](https://productcraft.co/docs/auth/api-reference#delete-v1-apps-app-id-tenants-tenant-id-invites-invite-id)
|
|
@@ -2314,6 +2467,7 @@ List a tenant's invites, newest first. Optional `?status=pending|revoked|expired
|
|
|
2314
2467
|
|
|
2315
2468
|
- Params: `Auth.AppScopedTenantInviteListParams`
|
|
2316
2469
|
- Paginated: `for await` iterates every item; `await` gives one page
|
|
2470
|
+
- Credential: [`workspace_key`](#workspace_key)
|
|
2317
2471
|
|
|
2318
2472
|
| Status | Error class | Codes | When |
|
|
2319
2473
|
|---|---|---|---|
|
|
@@ -2323,10 +2477,10 @@ List a tenant's invites, newest first. Optional `?status=pending|revoked|expired
|
|
|
2323
2477
|
| 429 | `RateLimitError` | `RATE_LIMITED` | Rate limited: too many requests from this client IP in the last 60 seconds (`RATE_LIMITED`); wait `Retry-After` seconds. |
|
|
2324
2478
|
|
|
2325
2479
|
```ts
|
|
2326
|
-
for await (const invite of auth.admin.app("
|
|
2480
|
+
for await (const invite of auth.admin.app("3f0c3c1e-8a2b-4c55-9d3f-0a1b2c3d4e5f").tenants.invites.list("3f0c3c1e-8a2b-4c55-9d3f-0a1b2c3d4e5f")) {
|
|
2327
2481
|
console.log(invite);
|
|
2328
2482
|
}
|
|
2329
|
-
const page = await auth.admin.app("
|
|
2483
|
+
const page = await auth.admin.app("3f0c3c1e-8a2b-4c55-9d3f-0a1b2c3d4e5f").tenants.invites.list("3f0c3c1e-8a2b-4c55-9d3f-0a1b2c3d4e5f", {}, { timeout: 5_000 });
|
|
2330
2484
|
```
|
|
2331
2485
|
|
|
2332
2486
|
[HTTP reference](https://productcraft.co/docs/auth/api-reference#get-v1-apps-app-id-tenants-tenant-id-invites)
|
|
@@ -2341,6 +2495,7 @@ Add a member to a tenant.
|
|
|
2341
2495
|
|
|
2342
2496
|
- Params: `Auth.AppScopedTenantMemberCreateParams`
|
|
2343
2497
|
- Idempotent: an `Idempotency-Key` is sent automatically and reused on retries
|
|
2498
|
+
- Credential: [`workspace_key`](#workspace_key)
|
|
2344
2499
|
|
|
2345
2500
|
| Status | Error class | Codes | When |
|
|
2346
2501
|
|---|---|---|---|
|
|
@@ -2352,7 +2507,7 @@ Add a member to a tenant.
|
|
|
2352
2507
|
| 429 | `RateLimitError` | `RATE_LIMITED` | Rate limited: too many requests from this client IP in the last 60 seconds (`RATE_LIMITED`); wait `Retry-After` seconds. |
|
|
2353
2508
|
|
|
2354
2509
|
```ts
|
|
2355
|
-
const addMember = await auth.admin.app("
|
|
2510
|
+
const addMember = await auth.admin.app("3f0c3c1e-8a2b-4c55-9d3f-0a1b2c3d4e5f").tenants.members.create("3f0c3c1e-8a2b-4c55-9d3f-0a1b2c3d4e5f", { role_name: "member" });
|
|
2356
2511
|
```
|
|
2357
2512
|
|
|
2358
2513
|
[HTTP reference](https://productcraft.co/docs/auth/api-reference#post-v1-apps-app-id-tenants-tenant-id-members)
|
|
@@ -2363,6 +2518,8 @@ const addMember = await auth.admin.app("app").tenants.members.create("tenant", {
|
|
|
2363
2518
|
|
|
2364
2519
|
Remove a member from a tenant.
|
|
2365
2520
|
|
|
2521
|
+
- Credential: [`workspace_key`](#workspace_key)
|
|
2522
|
+
|
|
2366
2523
|
| Status | Error class | Codes | When |
|
|
2367
2524
|
|---|---|---|---|
|
|
2368
2525
|
| 401 | `AuthenticationError` | `UNAUTHORIZED` | Missing or invalid bearer token. |
|
|
@@ -2371,7 +2528,7 @@ Remove a member from a tenant.
|
|
|
2371
2528
|
| 429 | `RateLimitError` | `RATE_LIMITED` | Rate limited: too many requests from this client IP in the last 60 seconds (`RATE_LIMITED`); wait `Retry-After` seconds. |
|
|
2372
2529
|
|
|
2373
2530
|
```ts
|
|
2374
|
-
await auth.admin.app("
|
|
2531
|
+
await auth.admin.app("3f0c3c1e-8a2b-4c55-9d3f-0a1b2c3d4e5f").tenants.members.delete("3f0c3c1e-8a2b-4c55-9d3f-0a1b2c3d4e5f", "3f0c3c1e-8a2b-4c55-9d3f-0a1b2c3d4e5f");
|
|
2375
2532
|
```
|
|
2376
2533
|
|
|
2377
2534
|
[HTTP reference](https://productcraft.co/docs/auth/api-reference#delete-v1-apps-app-id-tenants-tenant-id-members-account-id)
|
|
@@ -2384,6 +2541,7 @@ List members of a tenant, newest membership first. Filter by `?search=` and/or `
|
|
|
2384
2541
|
|
|
2385
2542
|
- Params: `Auth.AppScopedTenantMemberListParams`
|
|
2386
2543
|
- Paginated: `for await` iterates every item; `await` gives one page
|
|
2544
|
+
- Credential: [`workspace_key`](#workspace_key)
|
|
2387
2545
|
|
|
2388
2546
|
| Status | Error class | Codes | When |
|
|
2389
2547
|
|---|---|---|---|
|
|
@@ -2394,10 +2552,10 @@ List members of a tenant, newest membership first. Filter by `?search=` and/or `
|
|
|
2394
2552
|
| 429 | `RateLimitError` | `RATE_LIMITED` | Rate limited: too many requests from this client IP in the last 60 seconds (`RATE_LIMITED`); wait `Retry-After` seconds. |
|
|
2395
2553
|
|
|
2396
2554
|
```ts
|
|
2397
|
-
for await (const member of auth.admin.app("
|
|
2555
|
+
for await (const member of auth.admin.app("3f0c3c1e-8a2b-4c55-9d3f-0a1b2c3d4e5f").tenants.members.list("3f0c3c1e-8a2b-4c55-9d3f-0a1b2c3d4e5f")) {
|
|
2398
2556
|
console.log(member);
|
|
2399
2557
|
}
|
|
2400
|
-
const page = await auth.admin.app("
|
|
2558
|
+
const page = await auth.admin.app("3f0c3c1e-8a2b-4c55-9d3f-0a1b2c3d4e5f").tenants.members.list("3f0c3c1e-8a2b-4c55-9d3f-0a1b2c3d4e5f", {}, { timeout: 5_000 });
|
|
2401
2559
|
```
|
|
2402
2560
|
|
|
2403
2561
|
[HTTP reference](https://productcraft.co/docs/auth/api-reference#get-v1-apps-app-id-tenants-tenant-id-members)
|
|
@@ -2409,6 +2567,7 @@ const page = await auth.admin.app("app").tenants.members.list("tenant", {}, { ti
|
|
|
2409
2567
|
Change a member's role inside a tenant.
|
|
2410
2568
|
|
|
2411
2569
|
- Params: `Auth.AppScopedTenantMemberUpdateParams`
|
|
2570
|
+
- Credential: [`workspace_key`](#workspace_key)
|
|
2412
2571
|
|
|
2413
2572
|
| Status | Error class | Codes | When |
|
|
2414
2573
|
|---|---|---|---|
|
|
@@ -2419,7 +2578,7 @@ Change a member's role inside a tenant.
|
|
|
2419
2578
|
| 429 | `RateLimitError` | `RATE_LIMITED` | Rate limited: too many requests from this client IP in the last 60 seconds (`RATE_LIMITED`); wait `Retry-After` seconds. |
|
|
2420
2579
|
|
|
2421
2580
|
```ts
|
|
2422
|
-
const tenantMembership = await auth.admin.app("
|
|
2581
|
+
const tenantMembership = await auth.admin.app("3f0c3c1e-8a2b-4c55-9d3f-0a1b2c3d4e5f").tenants.members.update("3f0c3c1e-8a2b-4c55-9d3f-0a1b2c3d4e5f", "3f0c3c1e-8a2b-4c55-9d3f-0a1b2c3d4e5f", { role_name: "admin" });
|
|
2423
2582
|
```
|
|
2424
2583
|
|
|
2425
2584
|
[HTTP reference](https://productcraft.co/docs/auth/api-reference#patch-v1-apps-app-id-tenants-tenant-id-members-account-id)
|
|
@@ -2432,6 +2591,8 @@ const tenantMembership = await auth.admin.app("app").tenants.members.update("ten
|
|
|
2432
2591
|
|
|
2433
2592
|
Get the unverified-account expiry setting and how many accounts it deleted in the last 30 days.
|
|
2434
2593
|
|
|
2594
|
+
- Credential: [`workspace_key`](#workspace_key)
|
|
2595
|
+
|
|
2435
2596
|
| Status | Error class | Codes | When |
|
|
2436
2597
|
|---|---|---|---|
|
|
2437
2598
|
| 401 | `AuthenticationError` | `UNAUTHORIZED` | Missing or invalid bearer token. |
|
|
@@ -2440,7 +2601,7 @@ Get the unverified-account expiry setting and how many accounts it deleted in th
|
|
|
2440
2601
|
| 429 | `RateLimitError` | `RATE_LIMITED` | Rate limited: too many requests from this client IP in the last 60 seconds (`RATE_LIMITED`); wait `Retry-After` seconds. |
|
|
2441
2602
|
|
|
2442
2603
|
```ts
|
|
2443
|
-
const unverifiedAccountExpiryStatus = await auth.admin.app("
|
|
2604
|
+
const unverifiedAccountExpiryStatus = await auth.admin.app("3f0c3c1e-8a2b-4c55-9d3f-0a1b2c3d4e5f").unverifiedAccountExpiry.retrieve();
|
|
2444
2605
|
```
|
|
2445
2606
|
|
|
2446
2607
|
[HTTP reference](https://productcraft.co/docs/auth/api-reference#get-v1-apps-app-id-unverified-account-expiry)
|
|
@@ -2455,6 +2616,7 @@ Permanently deletes every account that qualifies under the app's `unverified_acc
|
|
|
2455
2616
|
|
|
2456
2617
|
- Params: `Auth.UnverifiedAccountExpiryRunParams`
|
|
2457
2618
|
- Idempotent: an `Idempotency-Key` is sent automatically and reused on retries
|
|
2619
|
+
- Credential: [`workspace_key`](#workspace_key)
|
|
2458
2620
|
|
|
2459
2621
|
| Status | Error class | Codes | When |
|
|
2460
2622
|
|---|---|---|---|
|
|
@@ -2467,7 +2629,7 @@ Permanently deletes every account that qualifies under the app's `unverified_acc
|
|
|
2467
2629
|
| 429 | `RateLimitError` | `RATE_LIMITED` | Rate limited: too many requests from this client IP in the last 60 seconds (`RATE_LIMITED`); wait `Retry-After` seconds. |
|
|
2468
2630
|
|
|
2469
2631
|
```ts
|
|
2470
|
-
const unverifiedAccountExpiryRun = await auth.admin.app("
|
|
2632
|
+
const unverifiedAccountExpiryRun = await auth.admin.app("3f0c3c1e-8a2b-4c55-9d3f-0a1b2c3d4e5f").unverifiedAccountExpiry.run({ dry_run: false });
|
|
2471
2633
|
```
|
|
2472
2634
|
|
|
2473
2635
|
[HTTP reference](https://productcraft.co/docs/auth/api-reference#post-v1-apps-app-id-unverified-account-expiry-run)
|
|
@@ -2482,6 +2644,8 @@ Get the per-app passkey (WebAuthn) relying-party settings.
|
|
|
2482
2644
|
|
|
2483
2645
|
Returns defaults with `enabled: false` and a null `rp_id` when passkeys have never been configured for the app.
|
|
2484
2646
|
|
|
2647
|
+
- Credential: [`workspace_key`](#workspace_key)
|
|
2648
|
+
|
|
2485
2649
|
| Status | Error class | Codes | When |
|
|
2486
2650
|
|---|---|---|---|
|
|
2487
2651
|
| 401 | `AuthenticationError` | `UNAUTHORIZED` | Missing or invalid bearer token. |
|
|
@@ -2490,7 +2654,7 @@ Returns defaults with `enabled: false` and a null `rp_id` when passkeys have nev
|
|
|
2490
2654
|
| 429 | `RateLimitError` | `RATE_LIMITED` | Rate limited: too many requests from this client IP in the last 60 seconds (`RATE_LIMITED`); wait `Retry-After` seconds. |
|
|
2491
2655
|
|
|
2492
2656
|
```ts
|
|
2493
|
-
const webauthnConfig = await auth.admin.app("
|
|
2657
|
+
const webauthnConfig = await auth.admin.app("3f0c3c1e-8a2b-4c55-9d3f-0a1b2c3d4e5f").webauthnConfig.retrieve();
|
|
2494
2658
|
```
|
|
2495
2659
|
|
|
2496
2660
|
[HTTP reference](https://productcraft.co/docs/auth/api-reference#get-v1-apps-app-id-webauthn-config)
|
|
@@ -2502,6 +2666,7 @@ const webauthnConfig = await auth.admin.app("app").webauthnConfig.retrieve();
|
|
|
2502
2666
|
Set the per-app passkey (WebAuthn) relying-party settings.
|
|
2503
2667
|
|
|
2504
2668
|
- Params: `Auth.WebauthnConfigUpdateParams`
|
|
2669
|
+
- Credential: [`workspace_key`](#workspace_key)
|
|
2505
2670
|
|
|
2506
2671
|
| Status | Error class | Codes | When |
|
|
2507
2672
|
|---|---|---|---|
|
|
@@ -2512,7 +2677,7 @@ Set the per-app passkey (WebAuthn) relying-party settings.
|
|
|
2512
2677
|
| 429 | `RateLimitError` | `RATE_LIMITED` | Rate limited: too many requests from this client IP in the last 60 seconds (`RATE_LIMITED`); wait `Retry-After` seconds. |
|
|
2513
2678
|
|
|
2514
2679
|
```ts
|
|
2515
|
-
const webauthnConfig = await auth.admin.app("
|
|
2680
|
+
const webauthnConfig = await auth.admin.app("3f0c3c1e-8a2b-4c55-9d3f-0a1b2c3d4e5f").webauthnConfig.update({ enabled: true, rp_id: "example.com" });
|
|
2516
2681
|
```
|
|
2517
2682
|
|
|
2518
2683
|
[HTTP reference](https://productcraft.co/docs/auth/api-reference#put-v1-apps-app-id-webauthn-config)
|
|
@@ -2529,6 +2694,7 @@ Deliveries are signed with the Standard Webhooks headers `webhook-id`, `webhook-
|
|
|
2529
2694
|
|
|
2530
2695
|
- Params: `Auth.WebhookEndpointCreateParams`
|
|
2531
2696
|
- Idempotent: an `Idempotency-Key` is sent automatically and reused on retries
|
|
2697
|
+
- Credential: [`workspace_key`](#workspace_key)
|
|
2532
2698
|
|
|
2533
2699
|
| Status | Error class | Codes | When |
|
|
2534
2700
|
|---|---|---|---|
|
|
@@ -2541,7 +2707,7 @@ Deliveries are signed with the Standard Webhooks headers `webhook-id`, `webhook-
|
|
|
2541
2707
|
| 429 | `RateLimitError` | `RATE_LIMITED` | Rate limited: too many requests from this client IP in the last 60 seconds (`RATE_LIMITED`); wait `Retry-After` seconds. |
|
|
2542
2708
|
|
|
2543
2709
|
```ts
|
|
2544
|
-
const webhookEndpointWithSecret = await auth.admin.app("
|
|
2710
|
+
const webhookEndpointWithSecret = await auth.admin.app("3f0c3c1e-8a2b-4c55-9d3f-0a1b2c3d4e5f").webhooks.endpoints.create({ url: "https://api.acme.com/webhooks" });
|
|
2545
2711
|
```
|
|
2546
2712
|
|
|
2547
2713
|
[HTTP reference](https://productcraft.co/docs/auth/api-reference#post-v1-apps-app-id-webhooks-endpoints)
|
|
@@ -2554,6 +2720,8 @@ Delete a webhook endpoint.
|
|
|
2554
2720
|
|
|
2555
2721
|
Queued retries are dropped. Its past attempts stay in the event log until the events expire.
|
|
2556
2722
|
|
|
2723
|
+
- Credential: [`workspace_key`](#workspace_key)
|
|
2724
|
+
|
|
2557
2725
|
| Status | Error class | Codes | When |
|
|
2558
2726
|
|---|---|---|---|
|
|
2559
2727
|
| 400 | `BadRequestError` | `BAD_REQUEST`, `VALIDATION_ERROR` | `endpoint_id` is not a UUID. |
|
|
@@ -2563,7 +2731,7 @@ Queued retries are dropped. Its past attempts stay in the event log until the ev
|
|
|
2563
2731
|
| 429 | `RateLimitError` | `RATE_LIMITED` | Rate limited: too many requests from this client IP in the last 60 seconds (`RATE_LIMITED`); wait `Retry-After` seconds. |
|
|
2564
2732
|
|
|
2565
2733
|
```ts
|
|
2566
|
-
await auth.admin.app("
|
|
2734
|
+
await auth.admin.app("3f0c3c1e-8a2b-4c55-9d3f-0a1b2c3d4e5f").webhooks.endpoints.delete("3f0c3c1e-8a2b-4c55-9d3f-0a1b2c3d4e5f");
|
|
2567
2735
|
```
|
|
2568
2736
|
|
|
2569
2737
|
[HTTP reference](https://productcraft.co/docs/auth/api-reference#delete-v1-apps-app-id-webhooks-endpoints-endpoint-id)
|
|
@@ -2577,6 +2745,7 @@ List webhook endpoints, oldest first.
|
|
|
2577
2745
|
At most 10, so this is always one page. Signing secrets are never returned here, only their last 4 characters.
|
|
2578
2746
|
|
|
2579
2747
|
- Paginated: `for await` iterates every item; `await` gives one page
|
|
2748
|
+
- Credential: [`workspace_key`](#workspace_key)
|
|
2580
2749
|
|
|
2581
2750
|
| Status | Error class | Codes | When |
|
|
2582
2751
|
|---|---|---|---|
|
|
@@ -2587,7 +2756,7 @@ At most 10, so this is always one page. Signing secrets are never returned here,
|
|
|
2587
2756
|
| 429 | `RateLimitError` | `RATE_LIMITED` | Rate limited: too many requests from this client IP in the last 60 seconds (`RATE_LIMITED`); wait `Retry-After` seconds. |
|
|
2588
2757
|
|
|
2589
2758
|
```ts
|
|
2590
|
-
for await (const endpoint of auth.admin.app("
|
|
2759
|
+
for await (const endpoint of auth.admin.app("3f0c3c1e-8a2b-4c55-9d3f-0a1b2c3d4e5f").webhooks.endpoints.list()) {
|
|
2591
2760
|
console.log(endpoint);
|
|
2592
2761
|
}
|
|
2593
2762
|
```
|
|
@@ -2602,6 +2771,8 @@ Get one webhook endpoint (without its secret).
|
|
|
2602
2771
|
|
|
2603
2772
|
The endpoint's URL, subscription, on/off state, failure streak and the last 4 characters of its signing secret. The full secret is only returned when the endpoint is created or its secret is rotated.
|
|
2604
2773
|
|
|
2774
|
+
- Credential: [`workspace_key`](#workspace_key)
|
|
2775
|
+
|
|
2605
2776
|
| Status | Error class | Codes | When |
|
|
2606
2777
|
|---|---|---|---|
|
|
2607
2778
|
| 400 | `BadRequestError` | `BAD_REQUEST`, `VALIDATION_ERROR` | `endpoint_id` is not a UUID. |
|
|
@@ -2611,7 +2782,7 @@ The endpoint's URL, subscription, on/off state, failure streak and the last 4 ch
|
|
|
2611
2782
|
| 429 | `RateLimitError` | `RATE_LIMITED` | Rate limited: too many requests from this client IP in the last 60 seconds (`RATE_LIMITED`); wait `Retry-After` seconds. |
|
|
2612
2783
|
|
|
2613
2784
|
```ts
|
|
2614
|
-
const webhookEndpoint = await auth.admin.app("
|
|
2785
|
+
const webhookEndpoint = await auth.admin.app("3f0c3c1e-8a2b-4c55-9d3f-0a1b2c3d4e5f").webhooks.endpoints.retrieve("3f0c3c1e-8a2b-4c55-9d3f-0a1b2c3d4e5f");
|
|
2615
2786
|
```
|
|
2616
2787
|
|
|
2617
2788
|
[HTTP reference](https://productcraft.co/docs/auth/api-reference#get-v1-apps-app-id-webhooks-endpoints-endpoint-id)
|
|
@@ -2626,6 +2797,7 @@ For `grace_hours` (default 24) the previous secret keeps signing too: `webhook-s
|
|
|
2626
2797
|
|
|
2627
2798
|
- Params: `Auth.WebhookEndpointRotateSecretParams`
|
|
2628
2799
|
- Idempotent: an `Idempotency-Key` is sent automatically and reused on retries
|
|
2800
|
+
- Credential: [`workspace_key`](#workspace_key)
|
|
2629
2801
|
|
|
2630
2802
|
| Status | Error class | Codes | When |
|
|
2631
2803
|
|---|---|---|---|
|
|
@@ -2637,7 +2809,7 @@ For `grace_hours` (default 24) the previous secret keeps signing too: `webhook-s
|
|
|
2637
2809
|
| 429 | `RateLimitError` | `RATE_LIMITED` | Rate limited: too many requests from this client IP in the last 60 seconds (`RATE_LIMITED`); wait `Retry-After` seconds. |
|
|
2638
2810
|
|
|
2639
2811
|
```ts
|
|
2640
|
-
const webhookEndpointWithSecret = await auth.admin.app("
|
|
2812
|
+
const webhookEndpointWithSecret = await auth.admin.app("3f0c3c1e-8a2b-4c55-9d3f-0a1b2c3d4e5f").webhooks.endpoints.rotateSecret("3f0c3c1e-8a2b-4c55-9d3f-0a1b2c3d4e5f", { grace_hours: 24 });
|
|
2641
2813
|
```
|
|
2642
2814
|
|
|
2643
2815
|
[HTTP reference](https://productcraft.co/docs/auth/api-reference#post-v1-apps-app-id-webhooks-endpoints-endpoint-id-rotate-secret)
|
|
@@ -2652,6 +2824,7 @@ Delivers the catalogue example of `event_type`, signed like any delivery, with `
|
|
|
2652
2824
|
|
|
2653
2825
|
- Params: `Auth.WebhookEndpointTestParams`
|
|
2654
2826
|
- Idempotent: an `Idempotency-Key` is sent automatically and reused on retries
|
|
2827
|
+
- Credential: [`workspace_key`](#workspace_key)
|
|
2655
2828
|
|
|
2656
2829
|
| Status | Error class | Codes | When |
|
|
2657
2830
|
|---|---|---|---|
|
|
@@ -2663,7 +2836,7 @@ Delivers the catalogue example of `event_type`, signed like any delivery, with `
|
|
|
2663
2836
|
| 429 | `RateLimitError` | `RATE_LIMITED` | Rate limited: too many requests from this client IP in the last 60 seconds (`RATE_LIMITED`); wait `Retry-After` seconds. |
|
|
2664
2837
|
|
|
2665
2838
|
```ts
|
|
2666
|
-
const webhookDeliveryAttempt = await auth.admin.app("
|
|
2839
|
+
const webhookDeliveryAttempt = await auth.admin.app("3f0c3c1e-8a2b-4c55-9d3f-0a1b2c3d4e5f").webhooks.endpoints.test("3f0c3c1e-8a2b-4c55-9d3f-0a1b2c3d4e5f", { event_type: "user.signup" });
|
|
2667
2840
|
```
|
|
2668
2841
|
|
|
2669
2842
|
[HTTP reference](https://productcraft.co/docs/auth/api-reference#post-v1-apps-app-id-webhooks-endpoints-endpoint-id-test)
|
|
@@ -2678,6 +2851,7 @@ Only the fields sent change. `enabled: true` (or a new URL) also clears an autom
|
|
|
2678
2851
|
|
|
2679
2852
|
- Params: `Auth.WebhookEndpointUpdateParams`
|
|
2680
2853
|
- Idempotent: an `Idempotency-Key` is sent automatically and reused on retries
|
|
2854
|
+
- Credential: [`workspace_key`](#workspace_key)
|
|
2681
2855
|
|
|
2682
2856
|
| Status | Error class | Codes | When |
|
|
2683
2857
|
|---|---|---|---|
|
|
@@ -2690,7 +2864,7 @@ Only the fields sent change. `enabled: true` (or a new URL) also clears an autom
|
|
|
2690
2864
|
| 429 | `RateLimitError` | `RATE_LIMITED` | Rate limited: too many requests from this client IP in the last 60 seconds (`RATE_LIMITED`); wait `Retry-After` seconds. |
|
|
2691
2865
|
|
|
2692
2866
|
```ts
|
|
2693
|
-
const webhookEndpoint = await auth.admin.app("
|
|
2867
|
+
const webhookEndpoint = await auth.admin.app("3f0c3c1e-8a2b-4c55-9d3f-0a1b2c3d4e5f").webhooks.endpoints.update("3f0c3c1e-8a2b-4c55-9d3f-0a1b2c3d4e5f", { description: "Production receiver" });
|
|
2694
2868
|
```
|
|
2695
2869
|
|
|
2696
2870
|
[HTTP reference](https://productcraft.co/docs/auth/api-reference#patch-v1-apps-app-id-webhooks-endpoints-endpoint-id)
|
|
@@ -2705,6 +2879,8 @@ List the events an endpoint can subscribe to.
|
|
|
2705
2879
|
|
|
2706
2880
|
Each type with a plain description, its group and an example `data` object (what "Send test" delivers).
|
|
2707
2881
|
|
|
2882
|
+
- Credential: [`workspace_key`](#workspace_key)
|
|
2883
|
+
|
|
2708
2884
|
| Status | Error class | Codes | When |
|
|
2709
2885
|
|---|---|---|---|
|
|
2710
2886
|
| 401 | `AuthenticationError` | `UNAUTHORIZED` | Missing or invalid bearer token. |
|
|
@@ -2713,7 +2889,7 @@ Each type with a plain description, its group and an example `data` object (what
|
|
|
2713
2889
|
| 429 | `RateLimitError` | `RATE_LIMITED` | Rate limited: too many requests from this client IP in the last 60 seconds (`RATE_LIMITED`); wait `Retry-After` seconds. |
|
|
2714
2890
|
|
|
2715
2891
|
```ts
|
|
2716
|
-
const listWebhookEventTypes = await auth.admin.app("
|
|
2892
|
+
const listWebhookEventTypes = await auth.admin.app("3f0c3c1e-8a2b-4c55-9d3f-0a1b2c3d4e5f").webhooks.eventTypes.list();
|
|
2717
2893
|
```
|
|
2718
2894
|
|
|
2719
2895
|
[HTTP reference](https://productcraft.co/docs/auth/api-reference#get-v1-apps-app-id-webhooks-event-types)
|
|
@@ -2730,6 +2906,7 @@ Every event logged while at least one endpoint existed, with the latest state pe
|
|
|
2730
2906
|
|
|
2731
2907
|
- Params: `Auth.WebhookEventListParams`
|
|
2732
2908
|
- Paginated: `for await` iterates every item; `await` gives one page
|
|
2909
|
+
- Credential: [`workspace_key`](#workspace_key)
|
|
2733
2910
|
|
|
2734
2911
|
| Status | Error class | Codes | When |
|
|
2735
2912
|
|---|---|---|---|
|
|
@@ -2740,10 +2917,10 @@ Every event logged while at least one endpoint existed, with the latest state pe
|
|
|
2740
2917
|
| 429 | `RateLimitError` | `RATE_LIMITED` | Rate limited: too many requests from this client IP in the last 60 seconds (`RATE_LIMITED`); wait `Retry-After` seconds. |
|
|
2741
2918
|
|
|
2742
2919
|
```ts
|
|
2743
|
-
for await (const event of auth.admin.app("
|
|
2920
|
+
for await (const event of auth.admin.app("3f0c3c1e-8a2b-4c55-9d3f-0a1b2c3d4e5f").webhooks.events.list()) {
|
|
2744
2921
|
console.log(event);
|
|
2745
2922
|
}
|
|
2746
|
-
const page = await auth.admin.app("
|
|
2923
|
+
const page = await auth.admin.app("3f0c3c1e-8a2b-4c55-9d3f-0a1b2c3d4e5f").webhooks.events.list({}, { timeout: 5_000 });
|
|
2747
2924
|
```
|
|
2748
2925
|
|
|
2749
2926
|
[HTTP reference](https://productcraft.co/docs/auth/api-reference#get-v1-apps-app-id-webhooks-events)
|
|
@@ -2758,6 +2935,7 @@ Same body and `webhook-id`, freshly signed, to every switched-on endpoint that r
|
|
|
2758
2935
|
|
|
2759
2936
|
- Params: `Auth.WebhookEventReplayParams`
|
|
2760
2937
|
- Idempotent: an `Idempotency-Key` is sent automatically and reused on retries
|
|
2938
|
+
- Credential: [`workspace_key`](#workspace_key)
|
|
2761
2939
|
|
|
2762
2940
|
| Status | Error class | Codes | When |
|
|
2763
2941
|
|---|---|---|---|
|
|
@@ -2769,7 +2947,7 @@ Same body and `webhook-id`, freshly signed, to every switched-on endpoint that r
|
|
|
2769
2947
|
| 429 | `RateLimitError` | `RATE_LIMITED` | Rate limited: too many requests from this client IP in the last 60 seconds (`RATE_LIMITED`); wait `Retry-After` seconds. |
|
|
2770
2948
|
|
|
2771
2949
|
```ts
|
|
2772
|
-
const replayWebhookEvent = await auth.admin.app("
|
|
2950
|
+
const replayWebhookEvent = await auth.admin.app("3f0c3c1e-8a2b-4c55-9d3f-0a1b2c3d4e5f").webhooks.events.replay("evt_3f0c3c1e-8a2b-4c55-9d3f-0a1b2c3d4e5f");
|
|
2773
2951
|
```
|
|
2774
2952
|
|
|
2775
2953
|
[HTTP reference](https://productcraft.co/docs/auth/api-reference#post-v1-apps-app-id-webhooks-events-event-id-replay)
|
|
@@ -2782,6 +2960,8 @@ Get one webhook event with every delivery attempt.
|
|
|
2782
2960
|
|
|
2783
2961
|
The event as it was sent (`type`, `data`) and every delivery attempt to every endpoint, with its trigger, HTTP status, error and the start of the response body. Use it to debug a receiver, then `replay` to send it again.
|
|
2784
2962
|
|
|
2963
|
+
- Credential: [`workspace_key`](#workspace_key)
|
|
2964
|
+
|
|
2785
2965
|
| Status | Error class | Codes | When |
|
|
2786
2966
|
|---|---|---|---|
|
|
2787
2967
|
| 400 | `BadRequestError` | `BAD_REQUEST`, `VALIDATION_ERROR` | `event_id` is not `evt_<uuid>`. |
|
|
@@ -2791,7 +2971,7 @@ The event as it was sent (`type`, `data`) and every delivery attempt to every en
|
|
|
2791
2971
|
| 429 | `RateLimitError` | `RATE_LIMITED` | Rate limited: too many requests from this client IP in the last 60 seconds (`RATE_LIMITED`); wait `Retry-After` seconds. |
|
|
2792
2972
|
|
|
2793
2973
|
```ts
|
|
2794
|
-
const webhookEventDetail = await auth.admin.app("
|
|
2974
|
+
const webhookEventDetail = await auth.admin.app("3f0c3c1e-8a2b-4c55-9d3f-0a1b2c3d4e5f").webhooks.events.retrieve("evt_3f0c3c1e-8a2b-4c55-9d3f-0a1b2c3d4e5f");
|
|
2795
2975
|
```
|
|
2796
2976
|
|
|
2797
2977
|
[HTTP reference](https://productcraft.co/docs/auth/api-reference#get-v1-apps-app-id-webhooks-events-event-id)
|
|
@@ -2821,7 +3001,7 @@ Materialises a pre-allocated invite into a real EndUser: creates account + prima
|
|
|
2821
3001
|
| 503 | `InternalServerError` | `SERVICE_UNAVAILABLE` | The service is momentarily busy (`SERVICE_UNAVAILABLE`): too many password hashes or verifications are already running or queued on the instance that took the request. Nothing was changed and no attempt was counted. Retry after the number of seconds in the `Retry-After` header (also in `details.retry_after_seconds`). Decided by instance load only, never by the identifier or the account, so it reveals nothing about whether an account exists. |
|
|
2822
3002
|
|
|
2823
3003
|
```ts
|
|
2824
|
-
const result = await auth.consumer("app").acceptInvite({ code: "inv_x7H2k3jLqXr", password: "CorrectHorseBatteryStaple" });
|
|
3004
|
+
const result = await auth.consumer("my-app").acceptInvite({ code: "inv_x7H2k3jLqXr", password: "CorrectHorseBatteryStaple" });
|
|
2825
3005
|
```
|
|
2826
3006
|
|
|
2827
3007
|
[HTTP reference](https://productcraft.co/docs/auth/api-reference#post-app-slug-v1-auth-accept-invite)
|
|
@@ -2849,7 +3029,7 @@ Materialises a pending `tenant_invite` into a real EndUser: creates account + ve
|
|
|
2849
3029
|
| 503 | `InternalServerError` | `SERVICE_UNAVAILABLE` | The service is momentarily busy (`SERVICE_UNAVAILABLE`): too many password hashes or verifications are already running or queued on the instance that took the request. Nothing was changed and no attempt was counted. Retry after the number of seconds in the `Retry-After` header (also in `details.retry_after_seconds`). Decided by instance load only, never by the identifier or the account, so it reveals nothing about whether an account exists. |
|
|
2850
3030
|
|
|
2851
3031
|
```ts
|
|
2852
|
-
const consumerToken = await auth.consumer("app").acceptTenantInvite({ code: "tinv_9dK2mQ7pR4vXbN1sT6yZ0hLcJeW3fAgU", password: "CorrectHorseBatteryStaple" });
|
|
3032
|
+
const consumerToken = await auth.consumer("my-app").acceptTenantInvite({ code: "tinv_9dK2mQ7pR4vXbN1sT6yZ0hLcJeW3fAgU", password: "CorrectHorseBatteryStaple" });
|
|
2853
3033
|
```
|
|
2854
3034
|
|
|
2855
3035
|
[HTTP reference](https://productcraft.co/docs/auth/api-reference#post-app-slug-v1-auth-accept-tenant-invite)
|
|
@@ -2870,7 +3050,7 @@ Exchange a `heimdall_code` (received on the web-flow callback redirect) for Auth
|
|
|
2870
3050
|
| 429 | `RateLimitError` | `RATE_LIMITED` | Rate limited: too many requests from this client IP in the last 60 seconds (`RATE_LIMITED`); wait `Retry-After` seconds. |
|
|
2871
3051
|
|
|
2872
3052
|
```ts
|
|
2873
|
-
const exchange = await auth.consumer("app").exchangeProviderCode({ code: "
|
|
3053
|
+
const exchange = await auth.consumer("my-app").exchangeProviderCode({ code: "hc_8f14e45fceea167a5a36dedd4bea2543" });
|
|
2874
3054
|
```
|
|
2875
3055
|
|
|
2876
3056
|
[HTTP reference](https://productcraft.co/docs/auth/api-reference#post-app-slug-v1-auth-oauth-exchange)
|
|
@@ -2896,7 +3076,9 @@ Destroys the session that owns the refresh token. The matching access token cont
|
|
|
2896
3076
|
| 429 | `RateLimitError` | `RATE_LIMITED` | Per-IP rate limit (`RATE_LIMITED`): this path is in the `default` bucket — 60 requests per minute per IP over a sliding 60-second window, shared across pods through Redis. Applied by `RateLimitMiddleware` before the handler runs, so it is reachable whatever the body says, and the response carries `Retry-After` in seconds. |
|
|
2897
3077
|
|
|
2898
3078
|
```ts
|
|
2899
|
-
await auth.consumer("app").logout({
|
|
3079
|
+
await auth.consumer("my-app").logout({
|
|
3080
|
+
refresh_token: "eyJhbGciOiJSUzI1NiIsImtpZCI6ImsxIn0.eyJ0eXAiOiJyZWZyZXNoIn0.c2lnbmF0dXJl",
|
|
3081
|
+
});
|
|
2900
3082
|
```
|
|
2901
3083
|
|
|
2902
3084
|
[HTTP reference](https://productcraft.co/docs/auth/api-reference#post-app-slug-v1-auth-logout)
|
|
@@ -2922,7 +3104,9 @@ Rotates the refresh token on every call — the previous refresh token is revoke
|
|
|
2922
3104
|
| 429 | `RateLimitError` | `RATE_LIMITED` | Per-IP rate limit (`RATE_LIMITED`): this path is in the `auth` bucket — 10 requests per minute per IP over a sliding 60-second window, shared across pods through Redis. Applied by `RateLimitMiddleware` before the handler runs, so it is reachable whatever the body says, and the response carries `Retry-After` in seconds. |
|
|
2923
3105
|
|
|
2924
3106
|
```ts
|
|
2925
|
-
const consumerToken = await auth.consumer("app").refresh({
|
|
3107
|
+
const consumerToken = await auth.consumer("my-app").refresh({
|
|
3108
|
+
refresh_token: "eyJhbGciOiJSUzI1NiIsImtpZCI6ImsxIn0.eyJ0eXAiOiJyZWZyZXNoIn0.c2lnbmF0dXJl",
|
|
3109
|
+
});
|
|
2926
3110
|
```
|
|
2927
3111
|
|
|
2928
3112
|
[HTTP reference](https://productcraft.co/docs/auth/api-reference#post-app-slug-v1-auth-refresh)
|
|
@@ -2940,6 +3124,7 @@ PAK-required: `auth.user.password-reset.create`. Returns `{ code, expires_at }`
|
|
|
2940
3124
|
Renamed from /auth/request-reset.
|
|
2941
3125
|
|
|
2942
3126
|
- Params: `Auth.RequestPasswordResetParams`
|
|
3127
|
+
- Credential: [`workspace_key`](#workspace_key)
|
|
2943
3128
|
|
|
2944
3129
|
| Status | Error class | Codes | When |
|
|
2945
3130
|
|---|---|---|---|
|
|
@@ -2951,7 +3136,7 @@ Renamed from /auth/request-reset.
|
|
|
2951
3136
|
| 429 | `RateLimitError` | `RATE_LIMITED` | Per-IP rate limit (`RATE_LIMITED`): this path is in the `auth` bucket — 10 requests per minute per IP over a sliding 60-second window, shared across pods through Redis. Applied by `RateLimitMiddleware` before the handler runs, so it is reachable whatever the body says, and the response carries `Retry-After` in seconds. |
|
|
2952
3137
|
|
|
2953
3138
|
```ts
|
|
2954
|
-
const consumerCodeIssue = await auth.consumer("app").requestPasswordReset({ email: "jane@example.com" });
|
|
3139
|
+
const consumerCodeIssue = await auth.consumer("my-app").requestPasswordReset({ email: "jane@example.com" });
|
|
2955
3140
|
```
|
|
2956
3141
|
|
|
2957
3142
|
[HTTP reference](https://productcraft.co/docs/auth/api-reference#post-app-slug-v1-auth-request-password-reset)
|
|
@@ -2969,6 +3154,7 @@ Returns `{ code, expires_at }` for delivery via the customer's own SMTP / SMS pr
|
|
|
2969
3154
|
Issuing a code invalidates any previously issued, unconsumed code for the same contact — including the one auto-emailed at signup. Only the most recently minted code is accepted.
|
|
2970
3155
|
|
|
2971
3156
|
- Params: `Auth.RequestVerificationParams`
|
|
3157
|
+
- Credential: [`workspace_key`](#workspace_key)
|
|
2972
3158
|
|
|
2973
3159
|
| Status | Error class | Codes | When |
|
|
2974
3160
|
|---|---|---|---|
|
|
@@ -2980,7 +3166,7 @@ Issuing a code invalidates any previously issued, unconsumed code for the same c
|
|
|
2980
3166
|
| 429 | `RateLimitError` | `RATE_LIMITED` | Per-IP rate limit (`RATE_LIMITED`): this path is in the `auth` bucket — 10 requests per minute per IP over a sliding 60-second window, shared across pods through Redis. Applied by `RateLimitMiddleware` before the handler runs, so it is reachable whatever the body says, and the response carries `Retry-After` in seconds. |
|
|
2981
3167
|
|
|
2982
3168
|
```ts
|
|
2983
|
-
const consumerCodeIssue = await auth.consumer("app").requestVerification({ email: "jane@example.com" });
|
|
3169
|
+
const consumerCodeIssue = await auth.consumer("my-app").requestVerification({ email: "jane@example.com" });
|
|
2984
3170
|
```
|
|
2985
3171
|
|
|
2986
3172
|
[HTTP reference](https://productcraft.co/docs/auth/api-reference#post-app-slug-v1-auth-request-verification)
|
|
@@ -3007,7 +3193,7 @@ Consumes the 6-digit reset code (single-use). On success the password is updated
|
|
|
3007
3193
|
| 503 | `InternalServerError` | `SERVICE_UNAVAILABLE` | The service is momentarily busy (`SERVICE_UNAVAILABLE`): too many password hashes or verifications are already running or queued on the instance that took the request. Nothing was changed and no attempt was counted. Retry after the number of seconds in the `Retry-After` header (also in `details.retry_after_seconds`). Decided by instance load only, never by the identifier or the account, so it reveals nothing about whether an account exists. |
|
|
3008
3194
|
|
|
3009
3195
|
```ts
|
|
3010
|
-
await auth.consumer("app").resetPassword({ code: "123456", new_password: "
|
|
3196
|
+
await auth.consumer("my-app").resetPassword({ code: "123456", new_password: "a new long passphrase 42" });
|
|
3011
3197
|
```
|
|
3012
3198
|
|
|
3013
3199
|
[HTTP reference](https://productcraft.co/docs/auth/api-reference#post-app-slug-v1-auth-reset-password)
|
|
@@ -3021,6 +3207,7 @@ Mint + dispatch a password-reset email via Mail (PAK-required).
|
|
|
3021
3207
|
Same shape as `send-verification-email` but for the reset slot. PAK perm: `auth.user.password-reset.send-email`. Same loud precondition errors. Email-only.
|
|
3022
3208
|
|
|
3023
3209
|
- Params: `Auth.SendPasswordResetEmailParams`
|
|
3210
|
+
- Credential: [`workspace_key`](#workspace_key)
|
|
3024
3211
|
|
|
3025
3212
|
| Status | Error class | Codes | When |
|
|
3026
3213
|
|---|---|---|---|
|
|
@@ -3034,7 +3221,7 @@ Same shape as `send-verification-email` but for the reset slot. PAK perm: `auth.
|
|
|
3034
3221
|
| 503 | `InternalServerError` | `SERVICE_UNAVAILABLE` | Mail dispatch failed or client not wired. |
|
|
3035
3222
|
|
|
3036
3223
|
```ts
|
|
3037
|
-
const consumerCodeDispatch = await auth.consumer("app").sendPasswordResetEmail({ email: "jane@example.com" });
|
|
3224
|
+
const consumerCodeDispatch = await auth.consumer("my-app").sendPasswordResetEmail({ email: "jane@example.com" });
|
|
3038
3225
|
```
|
|
3039
3226
|
|
|
3040
3227
|
[HTTP reference](https://productcraft.co/docs/auth/api-reference#post-app-slug-v1-auth-send-password-reset-email)
|
|
@@ -3061,6 +3248,7 @@ On success returns `{ expires_at }`. The plaintext code is NOT returned. Returns
|
|
|
3061
3248
|
Issuing a code invalidates any previously issued, unconsumed code for the same contact — including the one auto-emailed at signup. Only the most recently minted code is accepted.
|
|
3062
3249
|
|
|
3063
3250
|
- Params: `Auth.SendVerificationEmailParams`
|
|
3251
|
+
- Credential: [`workspace_key`](#workspace_key)
|
|
3064
3252
|
|
|
3065
3253
|
| Status | Error class | Codes | When |
|
|
3066
3254
|
|---|---|---|---|
|
|
@@ -3074,7 +3262,7 @@ Issuing a code invalidates any previously issued, unconsumed code for the same c
|
|
|
3074
3262
|
| 503 | `InternalServerError` | `SERVICE_UNAVAILABLE` | Mail dispatch failed or client not wired. |
|
|
3075
3263
|
|
|
3076
3264
|
```ts
|
|
3077
|
-
const consumerCodeDispatch = await auth.consumer("app").sendVerificationEmail({ email: "jane@example.com" });
|
|
3265
|
+
const consumerCodeDispatch = await auth.consumer("my-app").sendVerificationEmail({ email: "jane@example.com" });
|
|
3078
3266
|
```
|
|
3079
3267
|
|
|
3080
3268
|
[HTTP reference](https://productcraft.co/docs/auth/api-reference#post-app-slug-v1-auth-send-verification-email)
|
|
@@ -3101,7 +3289,7 @@ Authenticate with username or verified primary email + password. When the accoun
|
|
|
3101
3289
|
| 503 | `InternalServerError` | `SERVICE_UNAVAILABLE` | The service is momentarily busy (`SERVICE_UNAVAILABLE`): too many password hashes or verifications are already running or queued on the instance that took the request. Nothing was changed and no attempt was counted. Retry after the number of seconds in the `Retry-After` header (also in `details.retry_after_seconds`). Decided by instance load only, never by the identifier or the account, so it reveals nothing about whether an account exists. |
|
|
3102
3290
|
|
|
3103
3291
|
```ts
|
|
3104
|
-
const result = await auth.consumer("app").signin({ identifier: "jane_doe", password: "
|
|
3292
|
+
const result = await auth.consumer("my-app").signin({ identifier: "jane_doe", password: "correct horse battery staple" });
|
|
3105
3293
|
```
|
|
3106
3294
|
|
|
3107
3295
|
[HTTP reference](https://productcraft.co/docs/auth/api-reference#post-app-slug-v1-auth-signin)
|
|
@@ -3124,7 +3312,10 @@ Submit the provider-issued ID token from a native client (iOS ASAuthorizationCon
|
|
|
3124
3312
|
| 429 | `RateLimitError` | `RATE_LIMITED` | Rate limited: too many requests from this client IP in the last 60 seconds (`RATE_LIMITED`); wait `Retry-After` seconds. |
|
|
3125
3313
|
|
|
3126
3314
|
```ts
|
|
3127
|
-
const result = await auth.consumer("app").signinWithProvider("
|
|
3315
|
+
const result = await auth.consumer("my-app").signinWithProvider("google", {
|
|
3316
|
+
id_token: "eyJhbGciOiJSUzI1NiIsImtpZCI6ImsxIn0.eyJzdWIiOiJ1c3JfMSJ9.c2lnbmF0dXJl",
|
|
3317
|
+
nonce: "n-0S6_WzA2Mj",
|
|
3318
|
+
});
|
|
3128
3319
|
```
|
|
3129
3320
|
|
|
3130
3321
|
[HTTP reference](https://productcraft.co/docs/auth/api-reference#post-app-slug-v1-auth-oauth-provider)
|
|
@@ -3142,12 +3333,13 @@ When the app runs `auth_config.mfa: "required"`, the account is still created bu
|
|
|
3142
3333
|
When the app has bot protection on (`auth_config.bot_protection`, Cloudflare Turnstile or hCaptcha), send the widget response as `bot_protection_token`. Auth verifies it with the provider before it looks at the email, username or password, and refuses the sign-up when the token is missing (400 `BOT_PROTECTION_REQUIRED`), rejected (403 `BOT_PROTECTION_FAILED`) or cannot be checked (503 `BOT_PROTECTION_UNAVAILABLE`; no account is created). This applies to PAK-authenticated calls too: a backend forwards the token its browser received.
|
|
3143
3334
|
|
|
3144
3335
|
- Params: `Auth.SignupParams`
|
|
3336
|
+
- Credential (optional): [`workspace_key`](#workspace_key)
|
|
3145
3337
|
|
|
3146
3338
|
| Status | Error class | Codes | When |
|
|
3147
3339
|
|---|---|---|---|
|
|
3148
3340
|
| 400 | `BadRequestError` | `BAD_REQUEST`, `VALIDATION_ERROR`, `BOT_PROTECTION_REQUIRED` | `BOT_PROTECTION_REQUIRED`: the app has bot protection on and the request carried no `bot_protection_token`. Also: Request validation failed: a required body field is missing, has the wrong type, or fails its format constraint. Produced by the global `ValidationPipe` before the handler runs; the response body lists the offending fields. |
|
|
3149
3341
|
| 401 | `AuthenticationError` | `UNAUTHORIZED` | The app sets `signup_requires_pak` and no Platform API Key was presented on `Authorization: Bearer`. |
|
|
3150
|
-
| 403 | `PermissionDeniedError` | `FORBIDDEN`, `BOT_PROTECTION_FAILED`, `APP_SUSPENDED`, `APP_ARCHIVED` | `BOT_PROTECTION_FAILED`: the bot-protection provider rejected the `bot_protection_token` (bad, expired or already used), or the hostname it reported is not one of the app's `bot_protection.expected_hostnames`; render a fresh widget and retry. Otherwise: signup is disabled for this app, the email domain is not on the app's allow-list, the presented PAK belongs to a different workspace, or its policy denies `auth.signup.create` on this app. Also returned when the app itself is suspended (`APP_SUSPENDED`) or archived (`APP_ARCHIVED`). |
|
|
3342
|
+
| 403 | `PermissionDeniedError` | `FORBIDDEN`, `BOT_PROTECTION_FAILED`, `APP_SUSPENDED`, `APP_ARCHIVED` | `BOT_PROTECTION_FAILED`: the bot-protection provider rejected the `bot_protection_token` (bad, expired or already used), or the hostname it reported is not one of the app's `bot_protection.expected_hostnames`; render a fresh widget and retry. Otherwise: signup is disabled for this app (new apps start with `signup_enabled: false`; turn it on with `PATCH /v1/apps/{app_id}/auth-config`), the email domain is not on the app's allow-list, the presented PAK belongs to a different workspace, or its policy denies `auth.signup.create` on this app. Also returned when the app itself is suspended (`APP_SUSPENDED`) or archived (`APP_ARCHIVED`). |
|
|
3151
3343
|
| 404 | `NotFoundError` | `NOT_FOUND` | The `:appSlug` in the path matches no app (or no live rename alias for one). This is about the **app**, not the account — it is decided before any identifier, code or credential in the body is looked at, so it is never a signal about whether an account or a contact exists. |
|
|
3152
3344
|
| 409 | `ConflictError` | `CONFLICT` | Email or username already in use in this app, or the app has no workspace binding and therefore cannot accept a PAK signup. |
|
|
3153
3345
|
| 415 | `APIError` | `UNSUPPORTED_MEDIA_TYPE` | The request body was sent as `application/x-www-form-urlencoded` (`UNSUPPORTED_MEDIA_TYPE`). This API is JSON-only: a form body is a CORS-simple request that skips preflight, so accepting one would widen the CSRF surface. Send `application/json`. Rejected in `main.ts` before routing, on every non-GET request. |
|
|
@@ -3155,7 +3347,7 @@ When the app has bot protection on (`auth_config.bot_protection`, Cloudflare Tur
|
|
|
3155
3347
|
| 503 | `InternalServerError` | `SERVICE_UNAVAILABLE`, `BOT_PROTECTION_UNAVAILABLE` | `BOT_PROTECTION_UNAVAILABLE`: the app has bot protection on and the token could not be checked (the provider timed out or failed, or the app's bot-protection secret is missing or was refused by the provider). Sign-up fails closed: no account was created. Retry shortly. Otherwise: The service is momentarily busy (`SERVICE_UNAVAILABLE`): too many password hashes or verifications are already running or queued on the instance that took the request. Nothing was changed and no attempt was counted. Retry after the number of seconds in the `Retry-After` header (also in `details.retry_after_seconds`). Decided by instance load only, never by the identifier or the account, so it reveals nothing about whether an account exists. |
|
|
3156
3348
|
|
|
3157
3349
|
```ts
|
|
3158
|
-
const result = await auth.consumer("app").signup({ email: "jane@example.com", password: "CorrectHorseBatteryStaple", username: "john_doe" });
|
|
3350
|
+
const result = await auth.consumer("my-app").signup({ email: "jane@example.com", password: "CorrectHorseBatteryStaple", username: "john_doe" });
|
|
3159
3351
|
```
|
|
3160
3352
|
|
|
3161
3353
|
[HTTP reference](https://productcraft.co/docs/auth/api-reference#post-app-slug-v1-auth-signup)
|
|
@@ -3169,6 +3361,7 @@ Switch the active tenant for this session.
|
|
|
3169
3361
|
Re-issues the EndUser's access + refresh tokens with the new `org_id` + `org_role` claims, after verifying the caller holds a tenant_membership for the target tenant. The session row is updated to the new tenant so subsequent refreshes preserve the context. The new access token keeps the session's `amr` and `mfa_at` (as `/auth/refresh` does), so a sign-in that completed MFA still proves it after a switch. Refresh-token rotation runs as usual; the previous refresh token enters the standard 60-second grace window.
|
|
3170
3362
|
|
|
3171
3363
|
- Params: `Auth.SwitchTenantParams`
|
|
3364
|
+
- Credential: [`end_user_token`](#end_user_token)
|
|
3172
3365
|
|
|
3173
3366
|
| Status | Error class | Codes | When |
|
|
3174
3367
|
|---|---|---|---|
|
|
@@ -3180,7 +3373,7 @@ Re-issues the EndUser's access + refresh tokens with the new `org_id` + `org_rol
|
|
|
3180
3373
|
| 429 | `RateLimitError` | `RATE_LIMITED` | Per-IP rate limit (`RATE_LIMITED`): this path is in the `default` bucket — 60 requests per minute per IP over a sliding 60-second window, shared across pods through Redis. Applied by `RateLimitMiddleware` before the handler runs, so it is reachable whatever the body says, and the response carries `Retry-After` in seconds. |
|
|
3181
3374
|
|
|
3182
3375
|
```ts
|
|
3183
|
-
const consumerToken = await auth.consumer("app").switchTenant({ tenant_id: "
|
|
3376
|
+
const consumerToken = await auth.consumer("my-app").switchTenant({ tenant_id: "3f0c3c1e-8a2b-4c55-9d3f-0a1b2c3d4e5f" });
|
|
3184
3377
|
```
|
|
3185
3378
|
|
|
3186
3379
|
[HTTP reference](https://productcraft.co/docs/auth/api-reference#post-app-slug-v1-auth-switch-tenant)
|
|
@@ -3208,7 +3401,7 @@ Renamed from /verify-email — the same endpoint now serves both email and phone
|
|
|
3208
3401
|
| 429 | `RateLimitError` | `RATE_LIMITED` | Per-IP rate limit (`RATE_LIMITED`): this path is in the `verify_code` bucket — 5 requests per minute per IP over a sliding 60-second window, shared across pods through Redis. Applied by `RateLimitMiddleware` before the handler runs, so it is reachable whatever the body says, and the response carries `Retry-After` in seconds. |
|
|
3209
3402
|
|
|
3210
3403
|
```ts
|
|
3211
|
-
const consumerVerify = await auth.consumer("app").verifyEmail({ code: "123456" });
|
|
3404
|
+
const consumerVerify = await auth.consumer("my-app").verifyEmail({ code: "123456" });
|
|
3212
3405
|
```
|
|
3213
3406
|
|
|
3214
3407
|
[HTTP reference](https://productcraft.co/docs/auth/api-reference#post-app-slug-v1-auth-verify)
|
|
@@ -3224,6 +3417,7 @@ Change the password of the signed-in EndUser.
|
|
|
3224
3417
|
Verifies `current_password`, sets the new hash, and revokes every OTHER active session for the account (the calling session is preserved). 401 if the current password is wrong or the account has no password credential — admin-provisioned accounts without an initial password should use the reset flow instead. The new password is held to exactly the same policy as signup: the app's length + character-class rules, the common-password deny-list, and the breach corpus.
|
|
3225
3418
|
|
|
3226
3419
|
- Params: `Auth.MeChangePasswordParams`
|
|
3420
|
+
- Credential: [`end_user_token`](#end_user_token)
|
|
3227
3421
|
|
|
3228
3422
|
| Status | Error class | Codes | When |
|
|
3229
3423
|
|---|---|---|---|
|
|
@@ -3233,7 +3427,10 @@ Verifies `current_password`, sets the new hash, and revokes every OTHER active s
|
|
|
3233
3427
|
| 503 | `InternalServerError` | `SERVICE_UNAVAILABLE` | The service is momentarily busy (`SERVICE_UNAVAILABLE`): too many password hashes or verifications are already running or queued on the instance that took the request. Nothing was changed and no attempt was counted. Retry after the number of seconds in the `Retry-After` header (also in `details.retry_after_seconds`). Decided by instance load only, never by the identifier or the account, so it reveals nothing about whether an account exists. |
|
|
3234
3428
|
|
|
3235
3429
|
```ts
|
|
3236
|
-
await auth.consumer("app").me.changePassword({
|
|
3430
|
+
await auth.consumer("my-app").me.changePassword({
|
|
3431
|
+
current_password: "correct horse battery staple",
|
|
3432
|
+
new_password: "a new long passphrase 42",
|
|
3433
|
+
});
|
|
3237
3434
|
```
|
|
3238
3435
|
|
|
3239
3436
|
[HTTP reference](https://productcraft.co/docs/auth/api-reference#post-app-slug-v1-me-change-password)
|
|
@@ -3246,13 +3443,15 @@ Permanently delete the signed-in EndUser account.
|
|
|
3246
3443
|
|
|
3247
3444
|
Removes the EndUser, all sessions, and all related records inside this app. Cannot be undone. The app audit log keeps one `auth.account.deleted` row (`via: self`; username and email domain only, never the address), and `user.deleted` fires with `via: "self"`.
|
|
3248
3445
|
|
|
3446
|
+
- Credential: [`end_user_token`](#end_user_token)
|
|
3447
|
+
|
|
3249
3448
|
| Status | Error class | Codes | When |
|
|
3250
3449
|
|---|---|---|---|
|
|
3251
3450
|
| 401 | `AuthenticationError` | `UNAUTHORIZED` | Missing, invalid or expired bearer token, unknown or inactive app, or the account/session is no longer active. |
|
|
3252
3451
|
| 429 | `RateLimitError` | `RATE_LIMITED` | Rate limited: too many requests from this client IP in the last 60 seconds (`RATE_LIMITED`); wait `Retry-After` seconds. |
|
|
3253
3452
|
|
|
3254
3453
|
```ts
|
|
3255
|
-
await auth.consumer("app").me.deleteAccount();
|
|
3454
|
+
await auth.consumer("my-app").me.deleteAccount();
|
|
3256
3455
|
```
|
|
3257
3456
|
|
|
3258
3457
|
[HTTP reference](https://productcraft.co/docs/auth/api-reference#delete-app-slug-v1-me)
|
|
@@ -3265,6 +3464,8 @@ Remove the EndUser avatar.
|
|
|
3265
3464
|
|
|
3266
3465
|
Clears both the uploaded avatar and any provider-captured picture, and deletes the stored object. A later Google/GitHub sign-in re-populates the provider picture — that is "sync from provider" behavior, by design.
|
|
3267
3466
|
|
|
3467
|
+
- Credential: [`end_user_token`](#end_user_token)
|
|
3468
|
+
|
|
3268
3469
|
| Status | Error class | Codes | When |
|
|
3269
3470
|
|---|---|---|---|
|
|
3270
3471
|
| 401 | `AuthenticationError` | `UNAUTHORIZED` | Missing, invalid or expired bearer token, unknown or inactive app, or the account/session is no longer active. |
|
|
@@ -3272,7 +3473,7 @@ Clears both the uploaded avatar and any provider-captured picture, and deletes t
|
|
|
3272
3473
|
| 429 | `RateLimitError` | `RATE_LIMITED` | Rate limited: too many requests from this client IP in the last 60 seconds (`RATE_LIMITED`); wait `Retry-After` seconds. |
|
|
3273
3474
|
|
|
3274
3475
|
```ts
|
|
3275
|
-
await auth.consumer("app").me.deleteAvatar();
|
|
3476
|
+
await auth.consumer("my-app").me.deleteAvatar();
|
|
3276
3477
|
```
|
|
3277
3478
|
|
|
3278
3479
|
[HTTP reference](https://productcraft.co/docs/auth/api-reference#delete-app-slug-v1-me-avatar)
|
|
@@ -3285,13 +3486,15 @@ Resolve the signed-in EndUser's effective permissions.
|
|
|
3285
3486
|
|
|
3286
3487
|
Returns the union of the app-level role permissions and the tenant-level role permissions (when the token carries an `org_id`). Resolved per-request through a 60-second LRU — role-permission edits propagate within ~1 minute. Use this instead of decoding a `permissions[]` claim from the JWT, which is no longer included. M2M tokens cannot call this — use `POST /:appSlug/v1/oauth/introspect` to inspect M2M scopes.
|
|
3287
3488
|
|
|
3489
|
+
- Credential: [`end_user_token`](#end_user_token)
|
|
3490
|
+
|
|
3288
3491
|
| Status | Error class | Codes | When |
|
|
3289
3492
|
|---|---|---|---|
|
|
3290
3493
|
| 401 | `AuthenticationError` | `UNAUTHORIZED` | Missing, invalid or expired bearer token, unknown or inactive app, or the account/session is no longer active. |
|
|
3291
3494
|
| 429 | `RateLimitError` | `RATE_LIMITED` | Rate limited: too many requests from this client IP in the last 60 seconds (`RATE_LIMITED`); wait `Retry-After` seconds. |
|
|
3292
3495
|
|
|
3293
3496
|
```ts
|
|
3294
|
-
const mePermissions = await auth.consumer("app").me.permissions();
|
|
3497
|
+
const mePermissions = await auth.consumer("my-app").me.permissions();
|
|
3295
3498
|
```
|
|
3296
3499
|
|
|
3297
3500
|
[HTTP reference](https://productcraft.co/docs/auth/api-reference#get-app-slug-v1-me-permissions)
|
|
@@ -3304,6 +3507,8 @@ Get the signed-in EndUser profile.
|
|
|
3304
3507
|
|
|
3305
3508
|
Returns the EndUser identity, app membership, and role name. The flat `permissions[]` array is intentionally NOT included — permissions resolve from the role on demand. Call `GET /me/permissions` for the flat list when the client needs it for UI gating.
|
|
3306
3509
|
|
|
3510
|
+
- Credential: [`end_user_token`](#end_user_token)
|
|
3511
|
+
|
|
3307
3512
|
| Status | Error class | Codes | When |
|
|
3308
3513
|
|---|---|---|---|
|
|
3309
3514
|
| 401 | `AuthenticationError` | `UNAUTHORIZED` | Missing, invalid or expired bearer token. |
|
|
@@ -3311,7 +3516,7 @@ Returns the EndUser identity, app membership, and role name. The flat `permissio
|
|
|
3311
3516
|
| 429 | `RateLimitError` | `RATE_LIMITED` | Rate limited: too many requests from this client IP in the last 60 seconds (`RATE_LIMITED`); wait `Retry-After` seconds. |
|
|
3312
3517
|
|
|
3313
3518
|
```ts
|
|
3314
|
-
const meProfile = await auth.consumer("app").me.retrieve();
|
|
3519
|
+
const meProfile = await auth.consumer("my-app").me.retrieve();
|
|
3315
3520
|
```
|
|
3316
3521
|
|
|
3317
3522
|
[HTTP reference](https://productcraft.co/docs/auth/api-reference#get-app-slug-v1-me)
|
|
@@ -3325,6 +3530,7 @@ Update the signed-in EndUser profile.
|
|
|
3325
3530
|
Editable fields: `display_name` and `username`. The username is unique per app (case-insensitive, same rule as signup); sending the current username is a no-op. Usernames cannot be cleared.
|
|
3326
3531
|
|
|
3327
3532
|
- Params: `Auth.MeUpdateParams`
|
|
3533
|
+
- Credential: [`end_user_token`](#end_user_token)
|
|
3328
3534
|
|
|
3329
3535
|
| Status | Error class | Codes | When |
|
|
3330
3536
|
|---|---|---|---|
|
|
@@ -3333,7 +3539,7 @@ Editable fields: `display_name` and `username`. The username is unique per app (
|
|
|
3333
3539
|
| 429 | `RateLimitError` | `RATE_LIMITED` | Rate limited: too many requests from this client IP in the last 60 seconds (`RATE_LIMITED`); wait `Retry-After` seconds. |
|
|
3334
3540
|
|
|
3335
3541
|
```ts
|
|
3336
|
-
const meUpdatedAccount = await auth.consumer("app").me.update({ display_name: "Ada Lovelace" });
|
|
3542
|
+
const meUpdatedAccount = await auth.consumer("my-app").me.update({ display_name: "Ada Lovelace" });
|
|
3337
3543
|
```
|
|
3338
3544
|
|
|
3339
3545
|
[HTTP reference](https://productcraft.co/docs/auth/api-reference#patch-app-slug-v1-me)
|
|
@@ -3347,6 +3553,7 @@ Upload (or replace) the EndUser avatar.
|
|
|
3347
3553
|
PNG/JPEG/WEBP only — SVG is rejected (stored-XSS vector). ≤2 MB. Magic bytes are sniffed; a mislabeled file is rejected. The image is re-encoded server-side (orientation baked in, all metadata incl. EXIF/GPS stripped, bounded to 512×512, webp). An uploaded avatar takes precedence over a provider-captured picture.
|
|
3348
3554
|
|
|
3349
3555
|
- Params: `Auth.MeUploadAvatarParams`
|
|
3556
|
+
- Credential: [`end_user_token`](#end_user_token)
|
|
3350
3557
|
|
|
3351
3558
|
| Status | Error class | Codes | When |
|
|
3352
3559
|
|---|---|---|---|
|
|
@@ -3356,7 +3563,7 @@ PNG/JPEG/WEBP only — SVG is rejected (stored-XSS vector). ≤2 MB. Magic bytes
|
|
|
3356
3563
|
| 429 | `RateLimitError` | `RATE_LIMITED` | Rate limited: too many requests from this client IP in the last 60 seconds (`RATE_LIMITED`); wait `Retry-After` seconds. |
|
|
3357
3564
|
|
|
3358
3565
|
```ts
|
|
3359
|
-
const avatarUrl = await auth.consumer("app").me.uploadAvatar({ file: new File(["…"], "image.png", { type: "image/png" }) });
|
|
3566
|
+
const avatarUrl = await auth.consumer("my-app").me.uploadAvatar({ file: new File(["…"], "image.png", { type: "image/png" }) });
|
|
3360
3567
|
```
|
|
3361
3568
|
|
|
3362
3569
|
[HTTP reference](https://productcraft.co/docs/auth/api-reference#post-app-slug-v1-me-avatar)
|
|
@@ -3372,6 +3579,7 @@ Recent account activity.
|
|
|
3372
3579
|
Login events, password changes, and other security-relevant records, scoped to this EndUser.
|
|
3373
3580
|
|
|
3374
3581
|
- Paginated: `for await` iterates every item; `await` gives one page
|
|
3582
|
+
- Credential: [`end_user_token`](#end_user_token)
|
|
3375
3583
|
|
|
3376
3584
|
| Status | Error class | Codes | When |
|
|
3377
3585
|
|---|---|---|---|
|
|
@@ -3379,7 +3587,7 @@ Login events, password changes, and other security-relevant records, scoped to t
|
|
|
3379
3587
|
| 429 | `RateLimitError` | `RATE_LIMITED` | Rate limited: too many requests from this client IP in the last 60 seconds (`RATE_LIMITED`); wait `Retry-After` seconds. |
|
|
3380
3588
|
|
|
3381
3589
|
```ts
|
|
3382
|
-
for await (const activity of auth.consumer("app").me.activity.list()) {
|
|
3590
|
+
for await (const activity of auth.consumer("my-app").me.activity.list()) {
|
|
3383
3591
|
console.log(activity);
|
|
3384
3592
|
}
|
|
3385
3593
|
```
|
|
@@ -3398,6 +3606,7 @@ Adds an email or phone contact to the EndUser. The contact starts unverified and
|
|
|
3398
3606
|
|
|
3399
3607
|
- Params: `Auth.MeContactCreateParams`
|
|
3400
3608
|
- Idempotent: an `Idempotency-Key` is sent automatically and reused on retries
|
|
3609
|
+
- Credential: [`end_user_token`](#end_user_token)
|
|
3401
3610
|
|
|
3402
3611
|
| Status | Error class | Codes | When |
|
|
3403
3612
|
|---|---|---|---|
|
|
@@ -3407,7 +3616,7 @@ Adds an email or phone contact to the EndUser. The contact starts unverified and
|
|
|
3407
3616
|
| 429 | `RateLimitError` | `RATE_LIMITED` | Per-IP rate limit (`RATE_LIMITED`): `/me/contacts` is in the strict `auth` bucket (10 requests per minute per IP). |
|
|
3408
3617
|
|
|
3409
3618
|
```ts
|
|
3410
|
-
const meContact = await auth.consumer("app").me.contacts.create({ type: "email", value: "
|
|
3619
|
+
const meContact = await auth.consumer("my-app").me.contacts.create({ type: "email", value: "ada@example.com" });
|
|
3411
3620
|
```
|
|
3412
3621
|
|
|
3413
3622
|
[HTTP reference](https://productcraft.co/docs/auth/api-reference#post-app-slug-v1-me-contacts)
|
|
@@ -3418,6 +3627,8 @@ const meContact = await auth.consumer("app").me.contacts.create({ type: "email",
|
|
|
3418
3627
|
|
|
3419
3628
|
Delete a contact.
|
|
3420
3629
|
|
|
3630
|
+
- Credential: [`end_user_token`](#end_user_token)
|
|
3631
|
+
|
|
3421
3632
|
| Status | Error class | Codes | When |
|
|
3422
3633
|
|---|---|---|---|
|
|
3423
3634
|
| 401 | `AuthenticationError` | `UNAUTHORIZED` | Missing, invalid or expired bearer token, unknown or inactive app, or the account/session is no longer active. |
|
|
@@ -3426,7 +3637,7 @@ Delete a contact.
|
|
|
3426
3637
|
| 429 | `RateLimitError` | `RATE_LIMITED` | Per-IP rate limit (`RATE_LIMITED`): `/me/contacts` is in the strict `auth` bucket (10 requests per minute per IP). |
|
|
3427
3638
|
|
|
3428
3639
|
```ts
|
|
3429
|
-
await auth.consumer("app").me.contacts.delete("
|
|
3640
|
+
await auth.consumer("my-app").me.contacts.delete("3f0c3c1e-8a2b-4c55-9d3f-0a1b2c3d4e5f");
|
|
3430
3641
|
```
|
|
3431
3642
|
|
|
3432
3643
|
[HTTP reference](https://productcraft.co/docs/auth/api-reference#delete-app-slug-v1-me-contacts-id)
|
|
@@ -3437,13 +3648,15 @@ await auth.consumer("app").me.contacts.delete("id");
|
|
|
3437
3648
|
|
|
3438
3649
|
List the EndUser's contacts.
|
|
3439
3650
|
|
|
3651
|
+
- Credential: [`end_user_token`](#end_user_token)
|
|
3652
|
+
|
|
3440
3653
|
| Status | Error class | Codes | When |
|
|
3441
3654
|
|---|---|---|---|
|
|
3442
3655
|
| 401 | `AuthenticationError` | `UNAUTHORIZED` | Missing, invalid or expired bearer token, unknown or inactive app, or the account/session is no longer active. |
|
|
3443
3656
|
| 429 | `RateLimitError` | `RATE_LIMITED` | Per-IP rate limit (`RATE_LIMITED`): the general bucket, 60 requests per minute per IP. Adding, verifying or removing a contact is in the strict `auth` bucket (10 per minute). |
|
|
3444
3657
|
|
|
3445
3658
|
```ts
|
|
3446
|
-
const meContacts = await auth.consumer("app").me.contacts.list();
|
|
3659
|
+
const meContacts = await auth.consumer("my-app").me.contacts.list();
|
|
3447
3660
|
```
|
|
3448
3661
|
|
|
3449
3662
|
[HTTP reference](https://productcraft.co/docs/auth/api-reference#get-app-slug-v1-me-contacts)
|
|
@@ -3456,6 +3669,8 @@ Promote a verified contact to primary.
|
|
|
3456
3669
|
|
|
3457
3670
|
Demotes the previous primary of the same type. Refused (409) when the target contact is unverified — promoting an unverified contact would let an attacker who registered the contact bypass verification by routing reset codes through it.
|
|
3458
3671
|
|
|
3672
|
+
- Credential: [`end_user_token`](#end_user_token)
|
|
3673
|
+
|
|
3459
3674
|
| Status | Error class | Codes | When |
|
|
3460
3675
|
|---|---|---|---|
|
|
3461
3676
|
| 401 | `AuthenticationError` | `UNAUTHORIZED` | Missing, invalid or expired bearer token, unknown or inactive app, or the account/session is no longer active. |
|
|
@@ -3464,7 +3679,7 @@ Demotes the previous primary of the same type. Refused (409) when the target con
|
|
|
3464
3679
|
| 429 | `RateLimitError` | `RATE_LIMITED` | Per-IP rate limit (`RATE_LIMITED`): `/me/contacts` is in the strict `auth` bucket (10 requests per minute per IP). |
|
|
3465
3680
|
|
|
3466
3681
|
```ts
|
|
3467
|
-
await auth.consumer("app").me.contacts.promote("
|
|
3682
|
+
await auth.consumer("my-app").me.contacts.promote("3f0c3c1e-8a2b-4c55-9d3f-0a1b2c3d4e5f");
|
|
3468
3683
|
```
|
|
3469
3684
|
|
|
3470
3685
|
[HTTP reference](https://productcraft.co/docs/auth/api-reference#post-app-slug-v1-me-contacts-id-promote)
|
|
@@ -3481,6 +3696,7 @@ Creates a pending factor and returns the type-specific enrollment payload. TOTP:
|
|
|
3481
3696
|
|
|
3482
3697
|
- Params: `Auth.MeMfaFactorCreateParams`
|
|
3483
3698
|
- Idempotent: an `Idempotency-Key` is sent automatically and reused on retries
|
|
3699
|
+
- Credential: [`end_user_token`](#end_user_token)
|
|
3484
3700
|
|
|
3485
3701
|
| Status | Error class | Codes | When |
|
|
3486
3702
|
|---|---|---|---|
|
|
@@ -3492,7 +3708,7 @@ Creates a pending factor and returns the type-specific enrollment payload. TOTP:
|
|
|
3492
3708
|
| 429 | `RateLimitError` | `RATE_LIMITED` | Rate limited: too many requests from this client IP in the last 60 seconds (`RATE_LIMITED`); wait `Retry-After` seconds. |
|
|
3493
3709
|
|
|
3494
3710
|
```ts
|
|
3495
|
-
const startEnrollment = await auth.consumer("app").me.mfa.factors.create({ type: "totp" });
|
|
3711
|
+
const startEnrollment = await auth.consumer("my-app").me.mfa.factors.create({ type: "totp" });
|
|
3496
3712
|
```
|
|
3497
3713
|
|
|
3498
3714
|
[HTTP reference](https://productcraft.co/docs/auth/api-reference#post-app-slug-v1-me-mfa-factors)
|
|
@@ -3505,6 +3721,8 @@ Disable an MFA factor.
|
|
|
3505
3721
|
|
|
3506
3722
|
Soft-disable. The row is preserved (with `disabled_at` set) for audit. Has no effect on existing sessions — their `amr` claim still reflects whatever satisfied sign-in at the time. Disabling the only enabled factor removes the MFA requirement on future sign-ins.
|
|
3507
3723
|
|
|
3724
|
+
- Credential: [`end_user_token`](#end_user_token)
|
|
3725
|
+
|
|
3508
3726
|
| Status | Error class | Codes | When |
|
|
3509
3727
|
|---|---|---|---|
|
|
3510
3728
|
| 401 | `AuthenticationError` | `UNAUTHORIZED` | Missing, invalid or expired bearer token, unknown or inactive app, or the account/session is no longer active. |
|
|
@@ -3512,7 +3730,7 @@ Soft-disable. The row is preserved (with `disabled_at` set) for audit. Has no ef
|
|
|
3512
3730
|
| 429 | `RateLimitError` | `RATE_LIMITED` | Rate limited: too many requests from this client IP in the last 60 seconds (`RATE_LIMITED`); wait `Retry-After` seconds. |
|
|
3513
3731
|
|
|
3514
3732
|
```ts
|
|
3515
|
-
await auth.consumer("app").me.mfa.factors.delete("
|
|
3733
|
+
await auth.consumer("my-app").me.mfa.factors.delete("3f0c3c1e-8a2b-4c55-9d3f-0a1b2c3d4e5f");
|
|
3516
3734
|
```
|
|
3517
3735
|
|
|
3518
3736
|
[HTTP reference](https://productcraft.co/docs/auth/api-reference#delete-app-slug-v1-me-mfa-factors-id)
|
|
@@ -3525,13 +3743,15 @@ List the authenticated EndUser's MFA factors.
|
|
|
3525
3743
|
|
|
3526
3744
|
Includes factors in any state (pending enrollment + enabled). Disabled factors are not listed.
|
|
3527
3745
|
|
|
3746
|
+
- Credential: [`end_user_token`](#end_user_token)
|
|
3747
|
+
|
|
3528
3748
|
| Status | Error class | Codes | When |
|
|
3529
3749
|
|---|---|---|---|
|
|
3530
3750
|
| 401 | `AuthenticationError` | `UNAUTHORIZED` | Missing, invalid or expired bearer token, unknown or inactive app, or the account/session is no longer active. |
|
|
3531
3751
|
| 429 | `RateLimitError` | `RATE_LIMITED` | Rate limited: too many requests from this client IP in the last 60 seconds (`RATE_LIMITED`); wait `Retry-After` seconds. |
|
|
3532
3752
|
|
|
3533
3753
|
```ts
|
|
3534
|
-
const factorList = await auth.consumer("app").me.mfa.factors.list();
|
|
3754
|
+
const factorList = await auth.consumer("my-app").me.mfa.factors.list();
|
|
3535
3755
|
```
|
|
3536
3756
|
|
|
3537
3757
|
[HTTP reference](https://productcraft.co/docs/auth/api-reference#get-app-slug-v1-me-mfa-factors)
|
|
@@ -3545,6 +3765,7 @@ Confirm enrollment of a pending factor.
|
|
|
3545
3765
|
TOTP: submit two `codes` from consecutive 30-second windows. Email: submit the emailed 6-digit `code`. On success the factor flips to enabled, recovery codes are minted (returned once), and prior recovery codes for the account are invalidated. Subsequent calls with the same `:id` fail with 400.
|
|
3546
3766
|
|
|
3547
3767
|
- Params: `Auth.MeMfaFactorVerifyParams`
|
|
3768
|
+
- Credential: [`end_user_token`](#end_user_token)
|
|
3548
3769
|
|
|
3549
3770
|
| Status | Error class | Codes | When |
|
|
3550
3771
|
|---|---|---|---|
|
|
@@ -3553,7 +3774,7 @@ TOTP: submit two `codes` from consecutive 30-second windows. Email: submit the e
|
|
|
3553
3774
|
| 429 | `RateLimitError` | `RATE_LIMITED` | Rate limited: too many requests from this client IP in the last 60 seconds (`RATE_LIMITED`); wait `Retry-After` seconds. |
|
|
3554
3775
|
|
|
3555
3776
|
```ts
|
|
3556
|
-
const confirmEnrollment = await auth.consumer("app").me.mfa.factors.verify("
|
|
3777
|
+
const confirmEnrollment = await auth.consumer("my-app").me.mfa.factors.verify("3f0c3c1e-8a2b-4c55-9d3f-0a1b2c3d4e5f", { code: "123456" });
|
|
3557
3778
|
```
|
|
3558
3779
|
|
|
3559
3780
|
[HTTP reference](https://productcraft.co/docs/auth/api-reference#post-app-slug-v1-me-mfa-factors-id-verify)
|
|
@@ -3568,13 +3789,15 @@ Regenerate the recovery-code set.
|
|
|
3568
3789
|
|
|
3569
3790
|
Mints a fresh set of single-use recovery codes and invalidates every prior code for the account. The new codes are returned once — store them now.
|
|
3570
3791
|
|
|
3792
|
+
- Credential: [`end_user_token`](#end_user_token)
|
|
3793
|
+
|
|
3571
3794
|
| Status | Error class | Codes | When |
|
|
3572
3795
|
|---|---|---|---|
|
|
3573
3796
|
| 401 | `AuthenticationError` | `UNAUTHORIZED` | Missing, invalid or expired bearer token, unknown or inactive app, or the account/session is no longer active. |
|
|
3574
3797
|
| 429 | `RateLimitError` | `RATE_LIMITED` | Rate limited: too many requests from this client IP in the last 60 seconds (`RATE_LIMITED`); wait `Retry-After` seconds. |
|
|
3575
3798
|
|
|
3576
3799
|
```ts
|
|
3577
|
-
const recoveryCodes = await auth.consumer("app").me.mfa.recoveryCodes.regenerate();
|
|
3800
|
+
const recoveryCodes = await auth.consumer("my-app").me.mfa.recoveryCodes.regenerate();
|
|
3578
3801
|
```
|
|
3579
3802
|
|
|
3580
3803
|
[HTTP reference](https://productcraft.co/docs/auth/api-reference#post-app-slug-v1-me-mfa-recovery-codes-regenerate)
|
|
@@ -3590,6 +3813,7 @@ Email a step-up code.
|
|
|
3590
3813
|
Mints a single-use 6-digit code against one of the account's enabled email factors and delivers it to the bound address. Follow with `/step-up` submitting the code. Codes expire after 5 minutes; sends are throttled per contact (30s between sends, shared with the sign-in path). Refused while step-up is locked on this session.
|
|
3591
3814
|
|
|
3592
3815
|
- Params: `Auth.MeMfaStepUpSendCodeParams`
|
|
3816
|
+
- Credential: [`end_user_token`](#end_user_token)
|
|
3593
3817
|
|
|
3594
3818
|
| Status | Error class | Codes | When |
|
|
3595
3819
|
|---|---|---|---|
|
|
@@ -3600,7 +3824,7 @@ Mints a single-use 6-digit code against one of the account's enabled email facto
|
|
|
3600
3824
|
| 429 | `RateLimitError` | `RATE_LIMITED` | Send throttled, or step-up is locked on this session. |
|
|
3601
3825
|
|
|
3602
3826
|
```ts
|
|
3603
|
-
const stepUpSendCode = await auth.consumer("app").me.mfa.stepUp.sendCode({ factor_id: "9b2f6c1e-0d6a-4a63-9a43-2f1c3e4d5a6b" });
|
|
3827
|
+
const stepUpSendCode = await auth.consumer("my-app").me.mfa.stepUp.sendCode({ factor_id: "9b2f6c1e-0d6a-4a63-9a43-2f1c3e4d5a6b" });
|
|
3604
3828
|
```
|
|
3605
3829
|
|
|
3606
3830
|
[HTTP reference](https://productcraft.co/docs/auth/api-reference#post-app-slug-v1-me-mfa-step-up-send-code)
|
|
@@ -3614,6 +3838,7 @@ Bump this session's MFA recency.
|
|
|
3614
3838
|
Verify a fresh code (TOTP, emailed via `/step-up/send-code`, or recovery) against any enabled factor on the account, and update the session's `auth_methods` + `mfa_at`. Call `/auth/refresh` after this to mint a token whose claims reflect the new state. Customers reading `mfa_at` from access tokens to gate sensitive actions should require a `/step-up` + refresh cycle when the timestamp is older than their policy window. 5 consecutive wrong codes lock step-up on this session for 15 minutes.
|
|
3615
3839
|
|
|
3616
3840
|
- Params: `Auth.MeMfaStepUpVerifyParams`
|
|
3841
|
+
- Credential: [`end_user_token`](#end_user_token)
|
|
3617
3842
|
|
|
3618
3843
|
| Status | Error class | Codes | When |
|
|
3619
3844
|
|---|---|---|---|
|
|
@@ -3622,7 +3847,7 @@ Verify a fresh code (TOTP, emailed via `/step-up/send-code`, or recovery) agains
|
|
|
3622
3847
|
| 503 | `InternalServerError` | `SERVICE_UNAVAILABLE` | The service is momentarily busy (`SERVICE_UNAVAILABLE`): too many password hashes or verifications are already running or queued on the instance that took the request. Nothing was changed and no attempt was counted. Retry after the number of seconds in the `Retry-After` header (also in `details.retry_after_seconds`). Decided by instance load only, never by the identifier or the account, so it reveals nothing about whether an account exists. |
|
|
3623
3848
|
|
|
3624
3849
|
```ts
|
|
3625
|
-
const stepUp = await auth.consumer("app").me.mfa.stepUp.verify({ code: "123456" });
|
|
3850
|
+
const stepUp = await auth.consumer("my-app").me.mfa.stepUp.verify({ code: "123456" });
|
|
3626
3851
|
```
|
|
3627
3852
|
|
|
3628
3853
|
[HTTP reference](https://productcraft.co/docs/auth/api-reference#post-app-slug-v1-me-mfa-step-up)
|
|
@@ -3637,6 +3862,8 @@ Get passkey assertion options for step-up.
|
|
|
3637
3862
|
|
|
3638
3863
|
Mints a single-use WebAuthn challenge for the enabled passkeys on this account and returns the `publicKey` member for `navigator.credentials.get()`. Submit the result to `/step-up` as `credential`. Refused while step-up is locked on this session — a locked session must not be able to keep minting challenges.
|
|
3639
3864
|
|
|
3865
|
+
- Credential: [`end_user_token`](#end_user_token)
|
|
3866
|
+
|
|
3640
3867
|
| Status | Error class | Codes | When |
|
|
3641
3868
|
|---|---|---|---|
|
|
3642
3869
|
| 400 | `BadRequestError` | `BAD_REQUEST`, `VALIDATION_ERROR` | No passkey is enrolled on this account. |
|
|
@@ -3645,7 +3872,7 @@ Mints a single-use WebAuthn challenge for the enabled passkeys on this account a
|
|
|
3645
3872
|
| 429 | `RateLimitError` | `RATE_LIMITED` | Step-up is locked on this session. |
|
|
3646
3873
|
|
|
3647
3874
|
```ts
|
|
3648
|
-
const webauthnOptions = await auth.consumer("app").me.mfa.stepUp.webauthn.options();
|
|
3875
|
+
const webauthnOptions = await auth.consumer("my-app").me.mfa.stepUp.webauthn.options();
|
|
3649
3876
|
```
|
|
3650
3877
|
|
|
3651
3878
|
[HTTP reference](https://productcraft.co/docs/auth/api-reference#post-app-slug-v1-me-mfa-step-up-webauthn-options)
|
|
@@ -3660,6 +3887,8 @@ Revoke a session.
|
|
|
3660
3887
|
|
|
3661
3888
|
Sign the EndUser out of one device. The session's refresh token is destroyed; its access token expires on its TTL. Requires the `session.revoke` permission when the app's `enforce_app_permissions` flag is on; otherwise (the default) any valid token can call this. Self-revoke (revoking your own session as a member with no perms) is something to enforce separately if needed; this guard does not exempt the principal from the role check.
|
|
3662
3889
|
|
|
3890
|
+
- Credential: [`end_user_token`](#end_user_token)
|
|
3891
|
+
|
|
3663
3892
|
| Status | Error class | Codes | When |
|
|
3664
3893
|
|---|---|---|---|
|
|
3665
3894
|
| 401 | `AuthenticationError` | `UNAUTHORIZED` | Missing, invalid or expired bearer token, unknown or inactive app, or the account/session is no longer active. |
|
|
@@ -3667,7 +3896,7 @@ Sign the EndUser out of one device. The session's refresh token is destroyed; it
|
|
|
3667
3896
|
| 429 | `RateLimitError` | `RATE_LIMITED` | Rate limited: too many requests from this client IP in the last 60 seconds (`RATE_LIMITED`); wait `Retry-After` seconds. |
|
|
3668
3897
|
|
|
3669
3898
|
```ts
|
|
3670
|
-
await auth.consumer("app").me.sessions.delete("
|
|
3899
|
+
await auth.consumer("my-app").me.sessions.delete("3f0c3c1e-8a2b-4c55-9d3f-0a1b2c3d4e5f");
|
|
3671
3900
|
```
|
|
3672
3901
|
|
|
3673
3902
|
[HTTP reference](https://productcraft.co/docs/auth/api-reference#delete-app-slug-v1-me-sessions-id)
|
|
@@ -3681,6 +3910,7 @@ List all active sessions for the EndUser.
|
|
|
3681
3910
|
Each session includes a `current` flag identifying the one belonging to the bearer token used for this request.
|
|
3682
3911
|
|
|
3683
3912
|
- Paginated: `for await` iterates every item; `await` gives one page
|
|
3913
|
+
- Credential: [`end_user_token`](#end_user_token)
|
|
3684
3914
|
|
|
3685
3915
|
| Status | Error class | Codes | When |
|
|
3686
3916
|
|---|---|---|---|
|
|
@@ -3688,7 +3918,7 @@ Each session includes a `current` flag identifying the one belonging to the bear
|
|
|
3688
3918
|
| 429 | `RateLimitError` | `RATE_LIMITED` | Rate limited: too many requests from this client IP in the last 60 seconds (`RATE_LIMITED`); wait `Retry-After` seconds. |
|
|
3689
3919
|
|
|
3690
3920
|
```ts
|
|
3691
|
-
for await (const session of auth.consumer("app").me.sessions.list()) {
|
|
3921
|
+
for await (const session of auth.consumer("my-app").me.sessions.list()) {
|
|
3692
3922
|
console.log(session);
|
|
3693
3923
|
}
|
|
3694
3924
|
```
|
|
@@ -3706,6 +3936,7 @@ Accept a tenant invite as the signed-in EndUser.
|
|
|
3706
3936
|
Adds the caller to the invited tenant with the role the invite names, and consumes the invite. Requires the invited address to be one of the caller's own VERIFIED email contacts in this app — holding the code is not sufficient, because whoever minted the invite also holds it, and an unverified contact is not proof of owning the address. A refused accept leaves the invite redeemable.
|
|
3707
3937
|
|
|
3708
3938
|
- Params: `Auth.MeTenantInviteAcceptParams`
|
|
3939
|
+
- Credential: [`end_user_token`](#end_user_token)
|
|
3709
3940
|
|
|
3710
3941
|
| Status | Error class | Codes | When |
|
|
3711
3942
|
|---|---|---|---|
|
|
@@ -3717,7 +3948,7 @@ Adds the caller to the invited tenant with the role the invite names, and consum
|
|
|
3717
3948
|
| 429 | `RateLimitError` | `RATE_LIMITED` | Rate limited: too many requests from this client IP in the last 60 seconds (`RATE_LIMITED`); wait `Retry-After` seconds. |
|
|
3718
3949
|
|
|
3719
3950
|
```ts
|
|
3720
|
-
const acceptedTenantInvite = await auth.consumer("app").me.tenantInvites.accept({ code: "tinv_9dK2mQ7pR4vXbN1sT6yZ0hLcJeW3fAgU" });
|
|
3951
|
+
const acceptedTenantInvite = await auth.consumer("my-app").me.tenantInvites.accept({ code: "tinv_9dK2mQ7pR4vXbN1sT6yZ0hLcJeW3fAgU" });
|
|
3721
3952
|
```
|
|
3722
3953
|
|
|
3723
3954
|
[HTTP reference](https://productcraft.co/docs/auth/api-reference#post-app-slug-v1-me-tenant-invites-accept)
|
|
@@ -3732,6 +3963,8 @@ List the EndUser's tenant memberships in this app.
|
|
|
3732
3963
|
|
|
3733
3964
|
Returns each tenant the caller is a member of, including the tenant slug + display name and the member's role. Powers a tenant-switcher UI on the customer's product.
|
|
3734
3965
|
|
|
3966
|
+
- Credential: [`end_user_token`](#end_user_token)
|
|
3967
|
+
|
|
3735
3968
|
| Status | Error class | Codes | When |
|
|
3736
3969
|
|---|---|---|---|
|
|
3737
3970
|
| 401 | `AuthenticationError` | `UNAUTHORIZED` | Missing / invalid bearer, or the session behind the token is revoked, expired or no longer exists. |
|
|
@@ -3740,7 +3973,7 @@ Returns each tenant the caller is a member of, including the tenant slug + displ
|
|
|
3740
3973
|
| 429 | `RateLimitError` | `RATE_LIMITED` | Per-IP rate limit (`RATE_LIMITED`): this path is in the `default` bucket — 60 requests per minute per IP over a sliding 60-second window, shared across pods through Redis. Applied by `RateLimitMiddleware` before the handler runs, so it is reachable whatever the body says, and the response carries `Retry-After` in seconds. |
|
|
3741
3974
|
|
|
3742
3975
|
```ts
|
|
3743
|
-
const myTenants = await auth.consumer("app").me.tenants.list();
|
|
3976
|
+
const myTenants = await auth.consumer("my-app").me.tenants.list();
|
|
3744
3977
|
```
|
|
3745
3978
|
|
|
3746
3979
|
[HTTP reference](https://productcraft.co/docs/auth/api-reference#get-app-slug-v1-auth-me-tenants)
|
|
@@ -3769,7 +4002,7 @@ For apps running `auth_config.mfa: "required"`. When a user proves their passwor
|
|
|
3769
4002
|
| 429 | `RateLimitError` | `RATE_LIMITED` | Per-IP rate limit (`RATE_LIMITED`): this path is in the `default` bucket — 60 requests per minute per IP over a sliding 60-second window, shared across pods through Redis. Applied by `RateLimitMiddleware` before the handler runs, so it is reachable whatever the body says, and the response carries `Retry-After` in seconds. |
|
|
3770
4003
|
|
|
3771
4004
|
```ts
|
|
3772
|
-
const startEnrollment = await auth.consumer("app").mfa.enroll({ mfa_token: "
|
|
4005
|
+
const startEnrollment = await auth.consumer("my-app").mfa.enroll({ mfa_token: "3f0c3c1e-8a2b-4c55-9d3f-0a1b2c3d4e5f", type: "totp" });
|
|
3773
4006
|
```
|
|
3774
4007
|
|
|
3775
4008
|
[HTTP reference](https://productcraft.co/docs/auth/api-reference#post-app-slug-v1-auth-mfa-enroll)
|
|
@@ -3796,7 +4029,10 @@ Same flow as `/auth/mfa/verify` but consumes a single-use recovery code (16 hex
|
|
|
3796
4029
|
| 503 | `InternalServerError` | `SERVICE_UNAVAILABLE` | The service is momentarily busy (`SERVICE_UNAVAILABLE`): too many password hashes or verifications are already running or queued on the instance that took the request. Nothing was changed and no attempt was counted. Retry after the number of seconds in the `Retry-After` header (also in `details.retry_after_seconds`). Decided by instance load only, never by the identifier or the account, so it reveals nothing about whether an account exists. |
|
|
3797
4030
|
|
|
3798
4031
|
```ts
|
|
3799
|
-
const consumerToken = await auth.consumer("app").mfa.recover({
|
|
4032
|
+
const consumerToken = await auth.consumer("my-app").mfa.recover({
|
|
4033
|
+
mfa_token: "3f0c3c1e-8a2b-4c55-9d3f-0a1b2c3d4e5f",
|
|
4034
|
+
recovery_code: "1a2b-3c4d-5e6f-7890",
|
|
4035
|
+
});
|
|
3800
4036
|
```
|
|
3801
4037
|
|
|
3802
4038
|
[HTTP reference](https://productcraft.co/docs/auth/api-reference#post-app-slug-v1-auth-mfa-recover)
|
|
@@ -3824,7 +4060,10 @@ Delivers a single-use 6-digit code to the masked address of an `email` factor li
|
|
|
3824
4060
|
| 429 | `RateLimitError` | `RATE_LIMITED` | Send throttled (max 3 sends per challenge, 30s apart), or too many failed attempts on the challenge. Per-IP rate limit (`RATE_LIMITED`): this path is in the `default` bucket — 60 requests per minute per IP over a sliding 60-second window, shared across pods through Redis. Applied by `RateLimitMiddleware` before the handler runs, so it is reachable whatever the body says, and the response carries `Retry-After` in seconds. |
|
|
3825
4061
|
|
|
3826
4062
|
```ts
|
|
3827
|
-
const consumerMfaSendCode = await auth.consumer("app").mfa.sendCode({
|
|
4063
|
+
const consumerMfaSendCode = await auth.consumer("my-app").mfa.sendCode({
|
|
4064
|
+
factor_id: "9b2f6c1e-0d6a-4a63-9a43-2f1c3e4d5a6b",
|
|
4065
|
+
mfa_token: "3f0c3c1e-8a2b-4c55-9d3f-0a1b2c3d4e5f",
|
|
4066
|
+
});
|
|
3828
4067
|
```
|
|
3829
4068
|
|
|
3830
4069
|
[HTTP reference](https://productcraft.co/docs/auth/api-reference#post-app-slug-v1-auth-mfa-send-code)
|
|
@@ -3850,7 +4089,7 @@ Submit the `mfa_token` from a `mfa_required: true` signin response, plus EITHER
|
|
|
3850
4089
|
| 429 | `RateLimitError` | `RATE_LIMITED` | Too many failed attempts against this challenge (5 locks it). Per-IP rate limit (`RATE_LIMITED`): this path is in the `verify_code` bucket — 5 requests per minute per IP over a sliding 60-second window, shared across pods through Redis. Applied by `RateLimitMiddleware` before the handler runs, so it is reachable whatever the body says, and the response carries `Retry-After` in seconds. |
|
|
3851
4090
|
|
|
3852
4091
|
```ts
|
|
3853
|
-
const consumerToken = await auth.consumer("app").mfa.verify({ mfa_token: "
|
|
4092
|
+
const consumerToken = await auth.consumer("my-app").mfa.verify({ mfa_token: "3f0c3c1e-8a2b-4c55-9d3f-0a1b2c3d4e5f" });
|
|
3854
4093
|
```
|
|
3855
4094
|
|
|
3856
4095
|
[HTTP reference](https://productcraft.co/docs/auth/api-reference#post-app-slug-v1-auth-mfa-verify)
|
|
@@ -3876,7 +4115,10 @@ Completes the flow started by `/auth/mfa/enroll`. TOTP: submit two `codes` from
|
|
|
3876
4115
|
| 429 | `RateLimitError` | `RATE_LIMITED` | Too many failed attempts against this enrolment token (5 locks it). Per-IP rate limit (`RATE_LIMITED`): this path is in the `verify_code` bucket — 5 requests per minute per IP over a sliding 60-second window, shared across pods through Redis. Applied by `RateLimitMiddleware` before the handler runs, so it is reachable whatever the body says, and the response carries `Retry-After` in seconds. |
|
|
3877
4116
|
|
|
3878
4117
|
```ts
|
|
3879
|
-
const consumerMfaEnrollVerify = await auth.consumer("app").mfa.verifyEnrollment({
|
|
4118
|
+
const consumerMfaEnrollVerify = await auth.consumer("my-app").mfa.verifyEnrollment({
|
|
4119
|
+
factor_id: "9b2f6c1e-0d6a-4a63-9a43-2f1c3e4d5a6b",
|
|
4120
|
+
mfa_token: "3f0c3c1e-8a2b-4c55-9d3f-0a1b2c3d4e5f",
|
|
4121
|
+
});
|
|
3880
4122
|
```
|
|
3881
4123
|
|
|
3882
4124
|
[HTTP reference](https://productcraft.co/docs/auth/api-reference#post-app-slug-v1-auth-mfa-enroll-verify)
|
|
@@ -3905,7 +4147,7 @@ Mints a single-use WebAuthn challenge scoped to the account behind `mfa_token` a
|
|
|
3905
4147
|
| 429 | `RateLimitError` | `RATE_LIMITED` | Too many failed attempts on the challenge. Per-IP rate limit (`RATE_LIMITED`): this path is in the `default` bucket — 60 requests per minute per IP over a sliding 60-second window, shared across pods through Redis. Applied by `RateLimitMiddleware` before the handler runs, so it is reachable whatever the body says, and the response carries `Retry-After` in seconds. |
|
|
3906
4148
|
|
|
3907
4149
|
```ts
|
|
3908
|
-
const consumerWebauthnOptions = await auth.consumer("app").mfa.webauthn.options({ mfa_token: "
|
|
4150
|
+
const consumerWebauthnOptions = await auth.consumer("my-app").mfa.webauthn.options({ mfa_token: "3f0c3c1e-8a2b-4c55-9d3f-0a1b2c3d4e5f" });
|
|
3909
4151
|
```
|
|
3910
4152
|
|
|
3911
4153
|
[HTTP reference](https://productcraft.co/docs/auth/api-reference#post-app-slug-v1-auth-mfa-webauthn-options)
|
|
@@ -3921,6 +4163,7 @@ Introspect the bearer access token (RFC 7662).
|
|
|
3921
4163
|
OAuth 2.0 token introspection. Send the access token via `Authorization: Bearer <token>` and receive either `{ active: false }` (invalid / expired / wrong app, or a session that is revoked, past its `expires_at`, or gone because the end user was deleted) or the active claim set including `scopes` (M2M) or `role` (EndUser), `exp`, `iat`, `iss`, `aid`. The body `token` field is optional and, if present, must match the bearer — RFC 7662 allows a separate `token` body field but we deliberately refuse cross-token introspection so a stolen token can't be probed against another active credential. The endpoint accepts both M2M and EndUser tokens — use it as the canonical way for a service to know what its own token can do, instead of decoding the JWT by hand. Returns 401 when the bearer is missing.
|
|
3922
4164
|
|
|
3923
4165
|
- Params: `Auth.OauthIntrospectParams`
|
|
4166
|
+
- Credential: [`m2m_token`](#m2m_token) or [`end_user_token`](#end_user_token)
|
|
3924
4167
|
|
|
3925
4168
|
| Status | Error class | Codes | When |
|
|
3926
4169
|
|---|---|---|---|
|
|
@@ -3932,7 +4175,7 @@ OAuth 2.0 token introspection. Send the access token via `Authorization: Bearer
|
|
|
3932
4175
|
| 429 | `RateLimitError` | `RATE_LIMITED` | Per-IP rate limit (`RATE_LIMITED`): this path is in the `default` bucket — 60 requests per minute per IP over a sliding 60-second window, shared across pods through Redis. Applied by `RateLimitMiddleware` before the handler runs, so it is reachable whatever the body says, and the response carries `Retry-After` in seconds. |
|
|
3933
4176
|
|
|
3934
4177
|
```ts
|
|
3935
|
-
const introspect = await auth.consumer("app").oauth.introspect({ token: "
|
|
4178
|
+
const introspect = await auth.consumer("my-app").oauth.introspect({ token: "eyJhbGciOiJSUzI1NiIsImtpZCI6ImsxIn0.eyJzdWIiOiJ1c3JfMSJ9.c2lnbmF0dXJl" });
|
|
3936
4179
|
```
|
|
3937
4180
|
|
|
3938
4181
|
[HTTP reference](https://productcraft.co/docs/auth/api-reference#post-app-slug-v1-oauth-introspect)
|
|
@@ -3958,9 +4201,9 @@ Standard OAuth 2.0 client_credentials grant. Returns an app-scoped access token
|
|
|
3958
4201
|
| 429 | `RateLimitError` | `RATE_LIMITED` | Per-IP rate limit (`RATE_LIMITED`): this path is in the `token_exchange` bucket — 60 requests per minute per IP over a sliding 60-second window, shared across pods through Redis. Applied by `RateLimitMiddleware` before the handler runs, so it is reachable whatever the body says, and the response carries `Retry-After` in seconds. |
|
|
3959
4202
|
|
|
3960
4203
|
```ts
|
|
3961
|
-
const oAuthToken = await auth.consumer("app").oauth.token({
|
|
4204
|
+
const oAuthToken = await auth.consumer("my-app").oauth.token({
|
|
3962
4205
|
client_id: "m2m_a1b2c3d4e5f6...",
|
|
3963
|
-
client_secret: "
|
|
4206
|
+
client_secret: "the-secret-returned-by-credentials-create",
|
|
3964
4207
|
grant_type: "client_credentials",
|
|
3965
4208
|
});
|
|
3966
4209
|
```
|
|
@@ -3990,7 +4233,7 @@ Returns a single-use WebAuthn challenge for `navigator.credentials.get()`. `allo
|
|
|
3990
4233
|
| 429 | `RateLimitError` | `RATE_LIMITED` | Per-IP burst limit. The endpoint does no credential work — one random challenge and one insert — so the bucket is the whole bound. Per-IP rate limit (`RATE_LIMITED`): this path is in the `auth` bucket — 10 requests per minute per IP over a sliding 60-second window, shared across pods through Redis. Applied by `RateLimitMiddleware` before the handler runs, so it is reachable whatever the body says, and the response carries `Retry-After` in seconds. |
|
|
3991
4234
|
|
|
3992
4235
|
```ts
|
|
3993
|
-
const consumerWebauthnOptions = await auth.consumer("app").passkey.options({ tenant_id: "9b2f6c1e-0d6a-4a63-9a43-2f1c3e4d5a6b" });
|
|
4236
|
+
const consumerWebauthnOptions = await auth.consumer("my-app").passkey.options({ tenant_id: "9b2f6c1e-0d6a-4a63-9a43-2f1c3e4d5a6b" });
|
|
3994
4237
|
```
|
|
3995
4238
|
|
|
3996
4239
|
[HTTP reference](https://productcraft.co/docs/auth/api-reference#post-app-slug-v1-auth-passkey-options)
|
|
@@ -4016,7 +4259,7 @@ Verifies the assertion against the challenge from `/auth/passkey/options` and mi
|
|
|
4016
4259
|
| 429 | `RateLimitError` | `RATE_LIMITED` | Per-IP burst limit on credential consumption. Per-IP rate limit (`RATE_LIMITED`): this path is in the `verify_code` bucket — 5 requests per minute per IP over a sliding 60-second window, shared across pods through Redis. Applied by `RateLimitMiddleware` before the handler runs, so it is reachable whatever the body says, and the response carries `Retry-After` in seconds. |
|
|
4017
4260
|
|
|
4018
4261
|
```ts
|
|
4019
|
-
const consumerToken = await auth.consumer("app").passkey.verify({ credential: {} });
|
|
4262
|
+
const consumerToken = await auth.consumer("my-app").passkey.verify({ credential: {} });
|
|
4020
4263
|
```
|
|
4021
4264
|
|
|
4022
4265
|
[HTTP reference](https://productcraft.co/docs/auth/api-reference#post-app-slug-v1-auth-passkey-verify)
|
|
@@ -4033,6 +4276,7 @@ Inserts a `<resource>.<action>` row in the per-app permission catalogue. The res
|
|
|
4033
4276
|
|
|
4034
4277
|
- Params: `Auth.ConsumerScopedPermissionCreateParams`
|
|
4035
4278
|
- Idempotent: an `Idempotency-Key` is sent automatically and reused on retries
|
|
4279
|
+
- Credential: [`app_api_key`](#app_api_key) or [`m2m_token`](#m2m_token) or [`end_user_token`](#end_user_token)
|
|
4036
4280
|
|
|
4037
4281
|
| Status | Error class | Codes | When |
|
|
4038
4282
|
|---|---|---|---|
|
|
@@ -4041,7 +4285,7 @@ Inserts a `<resource>.<action>` row in the per-app permission catalogue. The res
|
|
|
4041
4285
|
| 429 | `RateLimitError` | `RATE_LIMITED` | Rate limited: too many requests from this client IP in the last 60 seconds (`RATE_LIMITED`); wait `Retry-After` seconds. |
|
|
4042
4286
|
|
|
4043
4287
|
```ts
|
|
4044
|
-
const consumerAdminPermission = await auth.consumer("app").permissions.create({ action: "read", resource: "project" });
|
|
4288
|
+
const consumerAdminPermission = await auth.consumer("my-app").permissions.create({ action: "read", resource: "project" });
|
|
4045
4289
|
```
|
|
4046
4290
|
|
|
4047
4291
|
[HTTP reference](https://productcraft.co/docs/auth/api-reference#post-app-slug-v1-admin-permissions)
|
|
@@ -4054,6 +4298,8 @@ Delete a custom permission.
|
|
|
4054
4298
|
|
|
4055
4299
|
The `permissionKey` path parameter is the literal `<resource>.<action>` string. System permissions cannot be deleted — attempts return 403. Removing a permission also removes every `role_permission` row that bound it (cascade); role lookups dropped of that perm on the next request.
|
|
4056
4300
|
|
|
4301
|
+
- Credential: [`app_api_key`](#app_api_key) or [`m2m_token`](#m2m_token) or [`end_user_token`](#end_user_token)
|
|
4302
|
+
|
|
4057
4303
|
| Status | Error class | Codes | When |
|
|
4058
4304
|
|---|---|---|---|
|
|
4059
4305
|
| 400 | `BadRequestError` | `BAD_REQUEST`, `VALIDATION_ERROR` | permissionKey must be in `resource.action` format. |
|
|
@@ -4063,7 +4309,7 @@ The `permissionKey` path parameter is the literal `<resource>.<action>` string.
|
|
|
4063
4309
|
| 429 | `RateLimitError` | `RATE_LIMITED` | Rate limited: too many requests from this client IP in the last 60 seconds (`RATE_LIMITED`); wait `Retry-After` seconds. |
|
|
4064
4310
|
|
|
4065
4311
|
```ts
|
|
4066
|
-
await auth.consumer("app").permissions.delete("
|
|
4312
|
+
await auth.consumer("my-app").permissions.delete("invoice.read");
|
|
4067
4313
|
```
|
|
4068
4314
|
|
|
4069
4315
|
[HTTP reference](https://productcraft.co/docs/auth/api-reference#delete-app-slug-v1-admin-permissions-permission-key)
|
|
@@ -4076,6 +4322,8 @@ List all permissions visible to this app.
|
|
|
4076
4322
|
|
|
4077
4323
|
Returns the union of system permissions (shared across every app — `is_system: true` in the response) and any custom entries this app has defined (`is_system: false`). Useful for driving a role-editor UI that picks from the full catalogue.
|
|
4078
4324
|
|
|
4325
|
+
- Credential: [`app_api_key`](#app_api_key) or [`m2m_token`](#m2m_token) or [`end_user_token`](#end_user_token)
|
|
4326
|
+
|
|
4079
4327
|
| Status | Error class | Codes | When |
|
|
4080
4328
|
|---|---|---|---|
|
|
4081
4329
|
| 401 | `AuthenticationError` | `UNAUTHORIZED` | Missing, invalid or expired Consumer-API bearer: an EndUser or M2M token, or an app API key (`hdk_live_*` / `hdk_test_*`); or the account, session, M2M client or key is no longer active, or the key belongs to another app. |
|
|
@@ -4084,7 +4332,7 @@ Returns the union of system permissions (shared across every app — `is_system:
|
|
|
4084
4332
|
| 429 | `RateLimitError` | `RATE_LIMITED` | Rate limited: too many requests from this client IP in the last 60 seconds (`RATE_LIMITED`); wait `Retry-After` seconds. |
|
|
4085
4333
|
|
|
4086
4334
|
```ts
|
|
4087
|
-
const result = await auth.consumer("app").permissions.list();
|
|
4335
|
+
const result = await auth.consumer("my-app").permissions.list();
|
|
4088
4336
|
```
|
|
4089
4337
|
|
|
4090
4338
|
[HTTP reference](https://productcraft.co/docs/auth/api-reference#get-app-slug-v1-admin-permissions)
|
|
@@ -4101,6 +4349,7 @@ Creates a role with no permissions bound yet. Use `PUT /:roleName/permissions` t
|
|
|
4101
4349
|
|
|
4102
4350
|
- Params: `Auth.ConsumerScopedRoleCreateParams`
|
|
4103
4351
|
- Idempotent: an `Idempotency-Key` is sent automatically and reused on retries
|
|
4352
|
+
- Credential: [`app_api_key`](#app_api_key) or [`m2m_token`](#m2m_token) or [`end_user_token`](#end_user_token)
|
|
4104
4353
|
|
|
4105
4354
|
| Status | Error class | Codes | When |
|
|
4106
4355
|
|---|---|---|---|
|
|
@@ -4109,7 +4358,7 @@ Creates a role with no permissions bound yet. Use `PUT /:roleName/permissions` t
|
|
|
4109
4358
|
| 429 | `RateLimitError` | `RATE_LIMITED` | Rate limited: too many requests from this client IP in the last 60 seconds (`RATE_LIMITED`); wait `Retry-After` seconds. |
|
|
4110
4359
|
|
|
4111
4360
|
```ts
|
|
4112
|
-
const consumerRole = await auth.consumer("app").roles.create({ name: "editor" });
|
|
4361
|
+
const consumerRole = await auth.consumer("my-app").roles.create({ name: "editor" });
|
|
4113
4362
|
```
|
|
4114
4363
|
|
|
4115
4364
|
[HTTP reference](https://productcraft.co/docs/auth/api-reference#post-app-slug-v1-admin-roles)
|
|
@@ -4122,6 +4371,8 @@ Delete a custom role.
|
|
|
4122
4371
|
|
|
4123
4372
|
System roles (`owner`, `admin`, `member`) cannot be deleted — attempts return 403. Roles currently assigned to any member return 409 `ROLE_IN_USE`; reassign the affected members first.
|
|
4124
4373
|
|
|
4374
|
+
- Credential: [`app_api_key`](#app_api_key) or [`m2m_token`](#m2m_token) or [`end_user_token`](#end_user_token)
|
|
4375
|
+
|
|
4125
4376
|
| Status | Error class | Codes | When |
|
|
4126
4377
|
|---|---|---|---|
|
|
4127
4378
|
| 401 | `AuthenticationError` | `UNAUTHORIZED` | Missing, invalid or expired bearer token. |
|
|
@@ -4130,7 +4381,7 @@ System roles (`owner`, `admin`, `member`) cannot be deleted — attempts return
|
|
|
4130
4381
|
| 429 | `RateLimitError` | `RATE_LIMITED` | Rate limited: too many requests from this client IP in the last 60 seconds (`RATE_LIMITED`); wait `Retry-After` seconds. |
|
|
4131
4382
|
|
|
4132
4383
|
```ts
|
|
4133
|
-
await auth.consumer("app").roles.delete("
|
|
4384
|
+
await auth.consumer("my-app").roles.delete("admin");
|
|
4134
4385
|
```
|
|
4135
4386
|
|
|
4136
4387
|
[HTTP reference](https://productcraft.co/docs/auth/api-reference#delete-app-slug-v1-admin-roles-role-name)
|
|
@@ -4145,6 +4396,7 @@ Cursor-paginated by `created_at`. Use the returned `next_cursor` in subsequent c
|
|
|
4145
4396
|
|
|
4146
4397
|
- Params: `Auth.ConsumerScopedRoleListParams`
|
|
4147
4398
|
- Paginated: `for await` iterates every item; `await` gives one page
|
|
4399
|
+
- Credential: [`app_api_key`](#app_api_key) or [`m2m_token`](#m2m_token) or [`end_user_token`](#end_user_token)
|
|
4148
4400
|
|
|
4149
4401
|
| Status | Error class | Codes | When |
|
|
4150
4402
|
|---|---|---|---|
|
|
@@ -4155,10 +4407,10 @@ Cursor-paginated by `created_at`. Use the returned `next_cursor` in subsequent c
|
|
|
4155
4407
|
| 429 | `RateLimitError` | `RATE_LIMITED` | Rate limited: too many requests from this client IP in the last 60 seconds (`RATE_LIMITED`); wait `Retry-After` seconds. |
|
|
4156
4408
|
|
|
4157
4409
|
```ts
|
|
4158
|
-
for await (const role of auth.consumer("app").roles.list()) {
|
|
4410
|
+
for await (const role of auth.consumer("my-app").roles.list()) {
|
|
4159
4411
|
console.log(role);
|
|
4160
4412
|
}
|
|
4161
|
-
const page = await auth.consumer("app").roles.list({}, { timeout: 5_000 });
|
|
4413
|
+
const page = await auth.consumer("my-app").roles.list({}, { timeout: 5_000 });
|
|
4162
4414
|
```
|
|
4163
4415
|
|
|
4164
4416
|
[HTTP reference](https://productcraft.co/docs/auth/api-reference#get-app-slug-v1-admin-roles)
|
|
@@ -4171,6 +4423,8 @@ Read one role with its permission set.
|
|
|
4171
4423
|
|
|
4172
4424
|
Returns the role plus the flat `permissions[]` array currently bound. Use this to drive a "configure role" UI in the customer product without having to call `/permissions` separately.
|
|
4173
4425
|
|
|
4426
|
+
- Credential: [`app_api_key`](#app_api_key) or [`m2m_token`](#m2m_token) or [`end_user_token`](#end_user_token)
|
|
4427
|
+
|
|
4174
4428
|
| Status | Error class | Codes | When |
|
|
4175
4429
|
|---|---|---|---|
|
|
4176
4430
|
| 401 | `AuthenticationError` | `UNAUTHORIZED` | Missing, invalid or expired bearer token. |
|
|
@@ -4178,7 +4432,7 @@ Returns the role plus the flat `permissions[]` array currently bound. Use this t
|
|
|
4178
4432
|
| 429 | `RateLimitError` | `RATE_LIMITED` | Rate limited: too many requests from this client IP in the last 60 seconds (`RATE_LIMITED`); wait `Retry-After` seconds. |
|
|
4179
4433
|
|
|
4180
4434
|
```ts
|
|
4181
|
-
const consumerRoleWithPermissions = await auth.consumer("app").roles.retrieve("
|
|
4435
|
+
const consumerRoleWithPermissions = await auth.consumer("my-app").roles.retrieve("admin");
|
|
4182
4436
|
```
|
|
4183
4437
|
|
|
4184
4438
|
[HTTP reference](https://productcraft.co/docs/auth/api-reference#get-app-slug-v1-admin-roles-role-name)
|
|
@@ -4192,6 +4446,7 @@ Update a role's description.
|
|
|
4192
4446
|
Renames are intentionally NOT supported — the role name is part of every issued EndUser JWT, so changing it would silently break live sessions. Create a new role and migrate users instead.
|
|
4193
4447
|
|
|
4194
4448
|
- Params: `Auth.ConsumerScopedRoleUpdateParams`
|
|
4449
|
+
- Credential: [`app_api_key`](#app_api_key) or [`m2m_token`](#m2m_token) or [`end_user_token`](#end_user_token)
|
|
4195
4450
|
|
|
4196
4451
|
| Status | Error class | Codes | When |
|
|
4197
4452
|
|---|---|---|---|
|
|
@@ -4200,7 +4455,7 @@ Renames are intentionally NOT supported — the role name is part of every issue
|
|
|
4200
4455
|
| 429 | `RateLimitError` | `RATE_LIMITED` | Rate limited: too many requests from this client IP in the last 60 seconds (`RATE_LIMITED`); wait `Retry-After` seconds. |
|
|
4201
4456
|
|
|
4202
4457
|
```ts
|
|
4203
|
-
const consumerRole = await auth.consumer("app").roles.update("
|
|
4458
|
+
const consumerRole = await auth.consumer("my-app").roles.update("admin", { description: "Updated description" });
|
|
4204
4459
|
```
|
|
4205
4460
|
|
|
4206
4461
|
[HTTP reference](https://productcraft.co/docs/auth/api-reference#patch-app-slug-v1-admin-roles-role-name)
|
|
@@ -4214,6 +4469,7 @@ Replace a role's permission set.
|
|
|
4214
4469
|
Destructive — the role's permission set is replaced wholesale with the supplied array. Caller-narrowed: the caller must hold every permission in the request, otherwise 403 `Cannot grant actions you don't have: ...`. For EndUser callers the caller-held set is their app-membership role's effective permissions. For M2M callers the held set is the token's `scopes[]` claim — the M2M cannot grant a role any verb that wasn't configured on the M2M credential. Unknown permission strings return 400.
|
|
4215
4470
|
|
|
4216
4471
|
- Params: `Auth.ConsumerScopedRoleUpdatePermissionsParams`
|
|
4472
|
+
- Credential: [`app_api_key`](#app_api_key) or [`m2m_token`](#m2m_token) or [`end_user_token`](#end_user_token)
|
|
4217
4473
|
|
|
4218
4474
|
| Status | Error class | Codes | When |
|
|
4219
4475
|
|---|---|---|---|
|
|
@@ -4224,7 +4480,7 @@ Destructive — the role's permission set is replaced wholesale with the supplie
|
|
|
4224
4480
|
| 429 | `RateLimitError` | `RATE_LIMITED` | Rate limited: too many requests from this client IP in the last 60 seconds (`RATE_LIMITED`); wait `Retry-After` seconds. |
|
|
4225
4481
|
|
|
4226
4482
|
```ts
|
|
4227
|
-
const result = await auth.consumer("app").roles.updatePermissions("
|
|
4483
|
+
const result = await auth.consumer("my-app").roles.updatePermissions("admin", { permissions: ["user.read", "role.create"] });
|
|
4228
4484
|
```
|
|
4229
4485
|
|
|
4230
4486
|
[HTTP reference](https://productcraft.co/docs/auth/api-reference#put-app-slug-v1-admin-roles-role-name-permissions)
|
|
@@ -4241,6 +4497,7 @@ Returns the secret ONCE (`key`). Scopes must be grantable by the app and held by
|
|
|
4241
4497
|
|
|
4242
4498
|
- Params: `Auth.TenantApiKeyCreateParams`
|
|
4243
4499
|
- Idempotent: an `Idempotency-Key` is sent automatically and reused on retries
|
|
4500
|
+
- Credential: [`end_user_token`](#end_user_token)
|
|
4244
4501
|
|
|
4245
4502
|
| Status | Error class | Codes | When |
|
|
4246
4503
|
|---|---|---|---|
|
|
@@ -4252,7 +4509,7 @@ Returns the secret ONCE (`key`). Scopes must be grantable by the app and held by
|
|
|
4252
4509
|
| 429 | `RateLimitError` | `RATE_LIMITED` | Rate limited: too many requests from this client IP in the last 60 seconds (`RATE_LIMITED`); wait `Retry-After` seconds. |
|
|
4253
4510
|
|
|
4254
4511
|
```ts
|
|
4255
|
-
const tenantApiKeyWithSecret = await auth.consumer("app").tenantApiKeys.create({ name: "CI e2e", scopes: ["disputes.read", "audit.read"] });
|
|
4512
|
+
const tenantApiKeyWithSecret = await auth.consumer("my-app").tenantApiKeys.create({ name: "CI e2e", scopes: ["disputes.read", "audit.read"] });
|
|
4256
4513
|
```
|
|
4257
4514
|
|
|
4258
4515
|
[HTTP reference](https://productcraft.co/docs/auth/api-reference#post-app-slug-v1-tenant-api-keys)
|
|
@@ -4265,6 +4522,8 @@ Revoke an API key.
|
|
|
4265
4522
|
|
|
4266
4523
|
Immediate and final. Idempotent: revoking a revoked key is a 204 that changes nothing.
|
|
4267
4524
|
|
|
4525
|
+
- Credential: [`end_user_token`](#end_user_token)
|
|
4526
|
+
|
|
4268
4527
|
| Status | Error class | Codes | When |
|
|
4269
4528
|
|---|---|---|---|
|
|
4270
4529
|
| 401 | `AuthenticationError` | `UNAUTHORIZED` | Missing or invalid end-user bearer token (M2M tokens, PAKs and API keys are refused). |
|
|
@@ -4273,7 +4532,7 @@ Immediate and final. Idempotent: revoking a revoked key is a 204 that changes no
|
|
|
4273
4532
|
| 429 | `RateLimitError` | `RATE_LIMITED` | Rate limited: too many requests from this client IP in the last 60 seconds (`RATE_LIMITED`); wait `Retry-After` seconds. |
|
|
4274
4533
|
|
|
4275
4534
|
```ts
|
|
4276
|
-
await auth.consumer("app").tenantApiKeys.delete("
|
|
4535
|
+
await auth.consumer("my-app").tenantApiKeys.delete("3f0c3c1e-8a2b-4c55-9d3f-0a1b2c3d4e5f");
|
|
4277
4536
|
```
|
|
4278
4537
|
|
|
4279
4538
|
[HTTP reference](https://productcraft.co/docs/auth/api-reference#delete-app-slug-v1-tenant-api-keys-key-id)
|
|
@@ -4287,6 +4546,7 @@ Verify a tenant API key (RFC 7662 shape).
|
|
|
4287
4546
|
For your backend: is this `pctk_` key, presented to YOUR API, usable right now, for which tenant and with which scopes? A key of another app is `{"active": false}`. Cache answers by the key's SHA-256: positives up to 30 s (never past `expires_at`), negatives up to 60 s. Intersect `scopes` with the permissions of `created_by.tenant_role` in your app. Requires `auth.tenant.api_keys.introspect` on the app. Not audited per call; `last_used_at` records use (5-minute granularity). This route has its own per-app rate bucket (1200 calls a minute by default), separate from your PAK's other calls; over it the answer is 429 with `Retry-After`, never a false `active: false`, so keep serving keys you hold a fresh positive for.
|
|
4288
4547
|
|
|
4289
4548
|
- Params: `Auth.TenantApiKeyIntrospectParams`
|
|
4549
|
+
- Credential: [`workspace_key`](#workspace_key)
|
|
4290
4550
|
|
|
4291
4551
|
| Status | Error class | Codes | When |
|
|
4292
4552
|
|---|---|---|---|
|
|
@@ -4298,7 +4558,7 @@ For your backend: is this `pctk_` key, presented to YOUR API, usable right now,
|
|
|
4298
4558
|
| 429 | `RateLimitError` | `RATE_LIMITED` | `RATE_LIMITED`: this app's introspect bucket is exhausted for the current minute. `Retry-After` says when it refills. |
|
|
4299
4559
|
|
|
4300
4560
|
```ts
|
|
4301
|
-
const tenantApiKeyIntrospection = await auth.consumer("app").tenantApiKeys.introspect({ key: "pctk_live_4fQ2aZ0000000000000000000000000000000000000_1a2B3c" });
|
|
4561
|
+
const tenantApiKeyIntrospection = await auth.consumer("my-app").tenantApiKeys.introspect({ key: "pctk_live_4fQ2aZ0000000000000000000000000000000000000_1a2B3c" });
|
|
4302
4562
|
```
|
|
4303
4563
|
|
|
4304
4564
|
[HTTP reference](https://productcraft.co/docs/auth/api-reference#post-app-slug-v1-tenant-api-keys-introspect)
|
|
@@ -4313,6 +4573,7 @@ Newest first, cursor-paginated (20 per page, max 100). Secrets are never returne
|
|
|
4313
4573
|
|
|
4314
4574
|
- Params: `Auth.ConsumerScopedTenantApiKeyListParams`
|
|
4315
4575
|
- Paginated: `for await` iterates every item; `await` gives one page
|
|
4576
|
+
- Credential: [`end_user_token`](#end_user_token)
|
|
4316
4577
|
|
|
4317
4578
|
| Status | Error class | Codes | When |
|
|
4318
4579
|
|---|---|---|---|
|
|
@@ -4323,10 +4584,10 @@ Newest first, cursor-paginated (20 per page, max 100). Secrets are never returne
|
|
|
4323
4584
|
| 429 | `RateLimitError` | `RATE_LIMITED` | Rate limited: too many requests from this client IP in the last 60 seconds (`RATE_LIMITED`); wait `Retry-After` seconds. |
|
|
4324
4585
|
|
|
4325
4586
|
```ts
|
|
4326
|
-
for await (const tenantApiKey of auth.consumer("app").tenantApiKeys.list()) {
|
|
4587
|
+
for await (const tenantApiKey of auth.consumer("my-app").tenantApiKeys.list()) {
|
|
4327
4588
|
console.log(tenantApiKey);
|
|
4328
4589
|
}
|
|
4329
|
-
const page = await auth.consumer("app").tenantApiKeys.list({}, { timeout: 5_000 });
|
|
4590
|
+
const page = await auth.consumer("my-app").tenantApiKeys.list({}, { timeout: 5_000 });
|
|
4330
4591
|
```
|
|
4331
4592
|
|
|
4332
4593
|
[HTTP reference](https://productcraft.co/docs/auth/api-reference#get-app-slug-v1-tenant-api-keys)
|
|
@@ -4341,6 +4602,7 @@ Mints a replacement with the same name and scopes and returns its secret ONCE. Y
|
|
|
4341
4602
|
|
|
4342
4603
|
- Params: `Auth.TenantApiKeyRotateParams`
|
|
4343
4604
|
- Idempotent: an `Idempotency-Key` is sent automatically and reused on retries
|
|
4605
|
+
- Credential: [`end_user_token`](#end_user_token)
|
|
4344
4606
|
|
|
4345
4607
|
| Status | Error class | Codes | When |
|
|
4346
4608
|
|---|---|---|---|
|
|
@@ -4352,7 +4614,7 @@ Mints a replacement with the same name and scopes and returns its secret ONCE. Y
|
|
|
4352
4614
|
| 429 | `RateLimitError` | `RATE_LIMITED` | Rate limited: too many requests from this client IP in the last 60 seconds (`RATE_LIMITED`); wait `Retry-After` seconds. |
|
|
4353
4615
|
|
|
4354
4616
|
```ts
|
|
4355
|
-
const tenantApiKeyWithSecret = await auth.consumer("app").tenantApiKeys.rotate("
|
|
4617
|
+
const tenantApiKeyWithSecret = await auth.consumer("my-app").tenantApiKeys.rotate("3f0c3c1e-8a2b-4c55-9d3f-0a1b2c3d4e5f", { expires_in_days: 7 });
|
|
4356
4618
|
```
|
|
4357
4619
|
|
|
4358
4620
|
[HTTP reference](https://productcraft.co/docs/auth/api-reference#post-app-slug-v1-tenant-api-keys-key-id-rotate)
|
|
@@ -4365,6 +4627,8 @@ Why a tenant API key is (in)active.
|
|
|
4365
4627
|
|
|
4366
4628
|
For your own audit trail: record why a key you saw go inactive died (revoked in the console, creator left the tenant, expired, keys suspended). Only keys of this app; another app's key is 404. Requires `auth.tenant.api_keys.introspect` on the app.
|
|
4367
4629
|
|
|
4630
|
+
- Credential: [`workspace_key`](#workspace_key)
|
|
4631
|
+
|
|
4368
4632
|
| Status | Error class | Codes | When |
|
|
4369
4633
|
|---|---|---|---|
|
|
4370
4634
|
| 401 | `AuthenticationError` | `UNAUTHORIZED` | Missing, malformed or revoked Platform API Key (`Authorization: Bearer pcft_live_…`). |
|
|
@@ -4374,7 +4638,7 @@ For your own audit trail: record why a key you saw go inactive died (revoked in
|
|
|
4374
4638
|
| 429 | `RateLimitError` | `RATE_LIMITED` | Rate limited: too many requests from this client IP in the last 60 seconds (`RATE_LIMITED`); wait `Retry-After` seconds. |
|
|
4375
4639
|
|
|
4376
4640
|
```ts
|
|
4377
|
-
const tenantApiKeyStatus = await auth.consumer("app").tenantApiKeys.status("
|
|
4641
|
+
const tenantApiKeyStatus = await auth.consumer("my-app").tenantApiKeys.status("3f0c3c1e-8a2b-4c55-9d3f-0a1b2c3d4e5f");
|
|
4378
4642
|
```
|
|
4379
4643
|
|
|
4380
4644
|
[HTTP reference](https://productcraft.co/docs/auth/api-reference#get-app-slug-v1-tenant-api-keys-key-id-status)
|
|
@@ -4389,6 +4653,8 @@ Read this app's tenant API key settings.
|
|
|
4389
4653
|
|
|
4390
4654
|
Requires `auth.tenant.api_keys.configure` on the app.
|
|
4391
4655
|
|
|
4656
|
+
- Credential: [`workspace_key`](#workspace_key)
|
|
4657
|
+
|
|
4392
4658
|
| Status | Error class | Codes | When |
|
|
4393
4659
|
|---|---|---|---|
|
|
4394
4660
|
| 401 | `AuthenticationError` | `UNAUTHORIZED` | Missing, malformed or revoked Platform API Key (`Authorization: Bearer pcft_live_…`). |
|
|
@@ -4398,7 +4664,7 @@ Requires `auth.tenant.api_keys.configure` on the app.
|
|
|
4398
4664
|
| 429 | `RateLimitError` | `RATE_LIMITED` | Rate limited: too many requests from this client IP in the last 60 seconds (`RATE_LIMITED`); wait `Retry-After` seconds. |
|
|
4399
4665
|
|
|
4400
4666
|
```ts
|
|
4401
|
-
const tenantApiKeysConfig = await auth.consumer("app").tenantApiKeys.config.retrieve();
|
|
4667
|
+
const tenantApiKeysConfig = await auth.consumer("my-app").tenantApiKeys.config.retrieve();
|
|
4402
4668
|
```
|
|
4403
4669
|
|
|
4404
4670
|
[HTTP reference](https://productcraft.co/docs/auth/api-reference#get-app-slug-v1-tenant-api-keys-config)
|
|
@@ -4413,6 +4679,7 @@ Call it on boot: your code is the source of truth for the scopes a key can carry
|
|
|
4413
4679
|
|
|
4414
4680
|
- Params: `Auth.ConsumerScopedTenantApiKeyConfigUpdateParams`
|
|
4415
4681
|
- Idempotent: an `Idempotency-Key` is sent automatically and reused on retries
|
|
4682
|
+
- Credential: [`workspace_key`](#workspace_key)
|
|
4416
4683
|
|
|
4417
4684
|
| Status | Error class | Codes | When |
|
|
4418
4685
|
|---|---|---|---|
|
|
@@ -4424,7 +4691,7 @@ Call it on boot: your code is the source of truth for the scopes a key can carry
|
|
|
4424
4691
|
| 429 | `RateLimitError` | `RATE_LIMITED` | Rate limited: too many requests from this client IP in the last 60 seconds (`RATE_LIMITED`); wait `Retry-After` seconds. |
|
|
4425
4692
|
|
|
4426
4693
|
```ts
|
|
4427
|
-
const tenantApiKeysConfig = await auth.consumer("app").tenantApiKeys.config.update({ default_expiry_days: 7 });
|
|
4694
|
+
const tenantApiKeysConfig = await auth.consumer("my-app").tenantApiKeys.config.update({ default_expiry_days: 7 });
|
|
4428
4695
|
```
|
|
4429
4696
|
|
|
4430
4697
|
[HTTP reference](https://productcraft.co/docs/auth/api-reference#put-app-slug-v1-tenant-api-keys-config)
|
|
@@ -4439,6 +4706,7 @@ Create a tenant inside this app. Returns the new tenant with a `display_id` (`tn
|
|
|
4439
4706
|
|
|
4440
4707
|
- Params: `Auth.ConsumerScopedTenantCreateParams`
|
|
4441
4708
|
- Idempotent: an `Idempotency-Key` is sent automatically and reused on retries
|
|
4709
|
+
- Credential: [`workspace_key`](#workspace_key)
|
|
4442
4710
|
|
|
4443
4711
|
| Status | Error class | Codes | When |
|
|
4444
4712
|
|---|---|---|---|
|
|
@@ -4450,7 +4718,7 @@ Create a tenant inside this app. Returns the new tenant with a `display_id` (`tn
|
|
|
4450
4718
|
| 429 | `RateLimitError` | `RATE_LIMITED` | Rate limited: too many requests from this client IP in the last 60 seconds (`RATE_LIMITED`); wait `Retry-After` seconds. |
|
|
4451
4719
|
|
|
4452
4720
|
```ts
|
|
4453
|
-
const consumerTenant = await auth.consumer("app").tenants.create({ display_name: "Acme Co" });
|
|
4721
|
+
const consumerTenant = await auth.consumer("my-app").tenants.create({ display_name: "Acme Co" });
|
|
4454
4722
|
```
|
|
4455
4723
|
|
|
4456
4724
|
[HTTP reference](https://productcraft.co/docs/auth/api-reference#post-app-slug-v1-tenants)
|
|
@@ -4461,6 +4729,8 @@ const consumerTenant = await auth.consumer("app").tenants.create({ display_name:
|
|
|
4461
4729
|
|
|
4462
4730
|
Delete a tenant. Cascades to tenant_membership rows; account rows are unaffected. PAK must hold auth.tenant.delete.
|
|
4463
4731
|
|
|
4732
|
+
- Credential: [`workspace_key`](#workspace_key)
|
|
4733
|
+
|
|
4464
4734
|
| Status | Error class | Codes | When |
|
|
4465
4735
|
|---|---|---|---|
|
|
4466
4736
|
| 401 | `AuthenticationError` | `UNAUTHORIZED` | Missing, invalid or expired bearer token. |
|
|
@@ -4468,7 +4738,7 @@ Delete a tenant. Cascades to tenant_membership rows; account rows are unaffected
|
|
|
4468
4738
|
| 429 | `RateLimitError` | `RATE_LIMITED` | Rate limited: too many requests from this client IP in the last 60 seconds (`RATE_LIMITED`); wait `Retry-After` seconds. |
|
|
4469
4739
|
|
|
4470
4740
|
```ts
|
|
4471
|
-
await auth.consumer("app").tenants.delete("
|
|
4741
|
+
await auth.consumer("my-app").tenants.delete("3f0c3c1e-8a2b-4c55-9d3f-0a1b2c3d4e5f");
|
|
4472
4742
|
```
|
|
4473
4743
|
|
|
4474
4744
|
[HTTP reference](https://productcraft.co/docs/auth/api-reference#delete-app-slug-v1-tenants-tenant-id)
|
|
@@ -4481,6 +4751,7 @@ List tenants in this app, paginated by created_at desc. PAK must hold auth.tenan
|
|
|
4481
4751
|
|
|
4482
4752
|
- Params: `Auth.ConsumerScopedTenantListParams`
|
|
4483
4753
|
- Paginated: `for await` iterates every item; `await` gives one page
|
|
4754
|
+
- Credential: [`workspace_key`](#workspace_key)
|
|
4484
4755
|
|
|
4485
4756
|
| Status | Error class | Codes | When |
|
|
4486
4757
|
|---|---|---|---|
|
|
@@ -4492,10 +4763,10 @@ List tenants in this app, paginated by created_at desc. PAK must hold auth.tenan
|
|
|
4492
4763
|
| 429 | `RateLimitError` | `RATE_LIMITED` | Rate limited: too many requests from this client IP in the last 60 seconds (`RATE_LIMITED`); wait `Retry-After` seconds. |
|
|
4493
4764
|
|
|
4494
4765
|
```ts
|
|
4495
|
-
for await (const tenant of auth.consumer("app").tenants.list()) {
|
|
4766
|
+
for await (const tenant of auth.consumer("my-app").tenants.list()) {
|
|
4496
4767
|
console.log(tenant);
|
|
4497
4768
|
}
|
|
4498
|
-
const page = await auth.consumer("app").tenants.list({}, { timeout: 5_000 });
|
|
4769
|
+
const page = await auth.consumer("my-app").tenants.list({}, { timeout: 5_000 });
|
|
4499
4770
|
```
|
|
4500
4771
|
|
|
4501
4772
|
[HTTP reference](https://productcraft.co/docs/auth/api-reference#get-app-slug-v1-tenants)
|
|
@@ -4506,6 +4777,8 @@ const page = await auth.consumer("app").tenants.list({}, { timeout: 5_000 });
|
|
|
4506
4777
|
|
|
4507
4778
|
Fetch a single tenant by its UUID or `tnt_<12hex>` display id. PAK must hold auth.tenant.read.
|
|
4508
4779
|
|
|
4780
|
+
- Credential: [`workspace_key`](#workspace_key)
|
|
4781
|
+
|
|
4509
4782
|
| Status | Error class | Codes | When |
|
|
4510
4783
|
|---|---|---|---|
|
|
4511
4784
|
| 401 | `AuthenticationError` | `UNAUTHORIZED` | Missing, invalid or expired bearer token. |
|
|
@@ -4513,7 +4786,7 @@ Fetch a single tenant by its UUID or `tnt_<12hex>` display id. PAK must hold aut
|
|
|
4513
4786
|
| 429 | `RateLimitError` | `RATE_LIMITED` | Rate limited: too many requests from this client IP in the last 60 seconds (`RATE_LIMITED`); wait `Retry-After` seconds. |
|
|
4514
4787
|
|
|
4515
4788
|
```ts
|
|
4516
|
-
const consumerTenant = await auth.consumer("app").tenants.retrieve("
|
|
4789
|
+
const consumerTenant = await auth.consumer("my-app").tenants.retrieve("3f0c3c1e-8a2b-4c55-9d3f-0a1b2c3d4e5f");
|
|
4517
4790
|
```
|
|
4518
4791
|
|
|
4519
4792
|
[HTTP reference](https://productcraft.co/docs/auth/api-reference#get-app-slug-v1-tenants-tenant-id)
|
|
@@ -4525,6 +4798,7 @@ const consumerTenant = await auth.consumer("app").tenants.retrieve("tenant");
|
|
|
4525
4798
|
Patch a tenant. Any subset of {display_name, slug, status, metadata}. PAK must hold auth.tenant.update.
|
|
4526
4799
|
|
|
4527
4800
|
- Params: `Auth.ConsumerScopedTenantUpdateParams`
|
|
4801
|
+
- Credential: [`workspace_key`](#workspace_key)
|
|
4528
4802
|
|
|
4529
4803
|
| Status | Error class | Codes | When |
|
|
4530
4804
|
|---|---|---|---|
|
|
@@ -4535,7 +4809,7 @@ Patch a tenant. Any subset of {display_name, slug, status, metadata}. PAK must h
|
|
|
4535
4809
|
| 429 | `RateLimitError` | `RATE_LIMITED` | Rate limited: too many requests from this client IP in the last 60 seconds (`RATE_LIMITED`); wait `Retry-After` seconds. |
|
|
4536
4810
|
|
|
4537
4811
|
```ts
|
|
4538
|
-
const consumerTenant = await auth.consumer("app").tenants.update("
|
|
4812
|
+
const consumerTenant = await auth.consumer("my-app").tenants.update("3f0c3c1e-8a2b-4c55-9d3f-0a1b2c3d4e5f", { display_name: "Acme Inc" });
|
|
4539
4813
|
```
|
|
4540
4814
|
|
|
4541
4815
|
[HTTP reference](https://productcraft.co/docs/auth/api-reference#patch-app-slug-v1-tenants-tenant-id)
|
|
@@ -4552,6 +4826,7 @@ Unlike `POST /members`, nothing is granted until the invitee accepts at `POST /:
|
|
|
4552
4826
|
|
|
4553
4827
|
- Params: `Auth.ConsumerScopedTenantInviteCreateParams`
|
|
4554
4828
|
- Idempotent: an `Idempotency-Key` is sent automatically and reused on retries
|
|
4829
|
+
- Credential: [`workspace_key`](#workspace_key)
|
|
4555
4830
|
|
|
4556
4831
|
| Status | Error class | Codes | When |
|
|
4557
4832
|
|---|---|---|---|
|
|
@@ -4563,7 +4838,7 @@ Unlike `POST /members`, nothing is granted until the invitee accepts at `POST /:
|
|
|
4563
4838
|
| 429 | `RateLimitError` | `RATE_LIMITED` | Rate limited: too many requests from this client IP in the last 60 seconds (`RATE_LIMITED`); wait `Retry-After` seconds. |
|
|
4564
4839
|
|
|
4565
4840
|
```ts
|
|
4566
|
-
const createTenantInvite = await auth.consumer("app").tenants.invites.create("
|
|
4841
|
+
const createTenantInvite = await auth.consumer("my-app").tenants.invites.create("3f0c3c1e-8a2b-4c55-9d3f-0a1b2c3d4e5f", { email: "alice@example.com", role_name: "member" });
|
|
4567
4842
|
```
|
|
4568
4843
|
|
|
4569
4844
|
[HTTP reference](https://productcraft.co/docs/auth/api-reference#post-app-slug-v1-tenants-tenant-id-invites)
|
|
@@ -4574,6 +4849,8 @@ const createTenantInvite = await auth.consumer("app").tenants.invites.create("te
|
|
|
4574
4849
|
|
|
4575
4850
|
Revoke a pending invite. Idempotent — revoking an already-revoked invite is a 204 no-op and fires no second webhook. PAK must hold auth.tenant.members.remove.
|
|
4576
4851
|
|
|
4852
|
+
- Credential: [`workspace_key`](#workspace_key)
|
|
4853
|
+
|
|
4577
4854
|
| Status | Error class | Codes | When |
|
|
4578
4855
|
|---|---|---|---|
|
|
4579
4856
|
| 401 | `AuthenticationError` | `UNAUTHORIZED` | Missing, invalid or expired bearer token. |
|
|
@@ -4581,7 +4858,7 @@ Revoke a pending invite. Idempotent — revoking an already-revoked invite is a
|
|
|
4581
4858
|
| 429 | `RateLimitError` | `RATE_LIMITED` | Rate limited: too many requests from this client IP in the last 60 seconds (`RATE_LIMITED`); wait `Retry-After` seconds. |
|
|
4582
4859
|
|
|
4583
4860
|
```ts
|
|
4584
|
-
await auth.consumer("app").tenants.invites.delete("
|
|
4861
|
+
await auth.consumer("my-app").tenants.invites.delete("3f0c3c1e-8a2b-4c55-9d3f-0a1b2c3d4e5f", "3f0c3c1e-8a2b-4c55-9d3f-0a1b2c3d4e5f");
|
|
4585
4862
|
```
|
|
4586
4863
|
|
|
4587
4864
|
[HTTP reference](https://productcraft.co/docs/auth/api-reference#delete-app-slug-v1-tenants-tenant-id-invites-invite-id)
|
|
@@ -4596,6 +4873,7 @@ Codes are never returned here — only the digest is stored. Use `status=pending
|
|
|
4596
4873
|
|
|
4597
4874
|
- Params: `Auth.ConsumerScopedTenantInviteListParams`
|
|
4598
4875
|
- Paginated: `for await` iterates every item; `await` gives one page
|
|
4876
|
+
- Credential: [`workspace_key`](#workspace_key)
|
|
4599
4877
|
|
|
4600
4878
|
| Status | Error class | Codes | When |
|
|
4601
4879
|
|---|---|---|---|
|
|
@@ -4605,10 +4883,10 @@ Codes are never returned here — only the digest is stored. Use `status=pending
|
|
|
4605
4883
|
| 429 | `RateLimitError` | `RATE_LIMITED` | Rate limited: too many requests from this client IP in the last 60 seconds (`RATE_LIMITED`); wait `Retry-After` seconds. |
|
|
4606
4884
|
|
|
4607
4885
|
```ts
|
|
4608
|
-
for await (const invite of auth.consumer("app").tenants.invites.list("
|
|
4886
|
+
for await (const invite of auth.consumer("my-app").tenants.invites.list("3f0c3c1e-8a2b-4c55-9d3f-0a1b2c3d4e5f")) {
|
|
4609
4887
|
console.log(invite);
|
|
4610
4888
|
}
|
|
4611
|
-
const page = await auth.consumer("app").tenants.invites.list("
|
|
4889
|
+
const page = await auth.consumer("my-app").tenants.invites.list("3f0c3c1e-8a2b-4c55-9d3f-0a1b2c3d4e5f", {}, { timeout: 5_000 });
|
|
4612
4890
|
```
|
|
4613
4891
|
|
|
4614
4892
|
[HTTP reference](https://productcraft.co/docs/auth/api-reference#get-app-slug-v1-tenants-tenant-id-invites)
|
|
@@ -4623,6 +4901,7 @@ Add a member to a tenant. Pass `accountId` for an existing user, or `email` (+ o
|
|
|
4623
4901
|
|
|
4624
4902
|
- Params: `Auth.ConsumerScopedTenantMemberCreateParams`
|
|
4625
4903
|
- Idempotent: an `Idempotency-Key` is sent automatically and reused on retries
|
|
4904
|
+
- Credential: [`workspace_key`](#workspace_key)
|
|
4626
4905
|
|
|
4627
4906
|
| Status | Error class | Codes | When |
|
|
4628
4907
|
|---|---|---|---|
|
|
@@ -4633,7 +4912,7 @@ Add a member to a tenant. Pass `accountId` for an existing user, or `email` (+ o
|
|
|
4633
4912
|
| 429 | `RateLimitError` | `RATE_LIMITED` | Rate limited: too many requests from this client IP in the last 60 seconds (`RATE_LIMITED`); wait `Retry-After` seconds. |
|
|
4634
4913
|
|
|
4635
4914
|
```ts
|
|
4636
|
-
const consumerAddMember = await auth.consumer("app").tenants.members.create("
|
|
4915
|
+
const consumerAddMember = await auth.consumer("my-app").tenants.members.create("3f0c3c1e-8a2b-4c55-9d3f-0a1b2c3d4e5f", { role_name: "member" });
|
|
4637
4916
|
```
|
|
4638
4917
|
|
|
4639
4918
|
[HTTP reference](https://productcraft.co/docs/auth/api-reference#post-app-slug-v1-tenants-tenant-id-members)
|
|
@@ -4644,6 +4923,8 @@ const consumerAddMember = await auth.consumer("app").tenants.members.create("ten
|
|
|
4644
4923
|
|
|
4645
4924
|
Remove a member from a tenant. The underlying account row stays in the app — only the tenant_membership row is deleted. PAK must hold auth.tenant.members.remove.
|
|
4646
4925
|
|
|
4926
|
+
- Credential: [`workspace_key`](#workspace_key)
|
|
4927
|
+
|
|
4647
4928
|
| Status | Error class | Codes | When |
|
|
4648
4929
|
|---|---|---|---|
|
|
4649
4930
|
| 401 | `AuthenticationError` | `UNAUTHORIZED` | Missing, invalid or expired bearer token. |
|
|
@@ -4651,7 +4932,7 @@ Remove a member from a tenant. The underlying account row stays in the app — o
|
|
|
4651
4932
|
| 429 | `RateLimitError` | `RATE_LIMITED` | Rate limited: too many requests from this client IP in the last 60 seconds (`RATE_LIMITED`); wait `Retry-After` seconds. |
|
|
4652
4933
|
|
|
4653
4934
|
```ts
|
|
4654
|
-
await auth.consumer("app").tenants.members.delete("
|
|
4935
|
+
await auth.consumer("my-app").tenants.members.delete("3f0c3c1e-8a2b-4c55-9d3f-0a1b2c3d4e5f", "3f0c3c1e-8a2b-4c55-9d3f-0a1b2c3d4e5f");
|
|
4655
4936
|
```
|
|
4656
4937
|
|
|
4657
4938
|
[HTTP reference](https://productcraft.co/docs/auth/api-reference#delete-app-slug-v1-tenants-tenant-id-members-account-id)
|
|
@@ -4664,6 +4945,7 @@ List members of a tenant. Cursor-paginated by joined_at desc. Filter by `?search
|
|
|
4664
4945
|
|
|
4665
4946
|
- Params: `Auth.ConsumerScopedTenantMemberListParams`
|
|
4666
4947
|
- Paginated: `for await` iterates every item; `await` gives one page
|
|
4948
|
+
- Credential: [`workspace_key`](#workspace_key)
|
|
4667
4949
|
|
|
4668
4950
|
| Status | Error class | Codes | When |
|
|
4669
4951
|
|---|---|---|---|
|
|
@@ -4675,10 +4957,10 @@ List members of a tenant. Cursor-paginated by joined_at desc. Filter by `?search
|
|
|
4675
4957
|
| 429 | `RateLimitError` | `RATE_LIMITED` | Rate limited: too many requests from this client IP in the last 60 seconds (`RATE_LIMITED`); wait `Retry-After` seconds. |
|
|
4676
4958
|
|
|
4677
4959
|
```ts
|
|
4678
|
-
for await (const member of auth.consumer("app").tenants.members.list("
|
|
4960
|
+
for await (const member of auth.consumer("my-app").tenants.members.list("3f0c3c1e-8a2b-4c55-9d3f-0a1b2c3d4e5f")) {
|
|
4679
4961
|
console.log(member);
|
|
4680
4962
|
}
|
|
4681
|
-
const page = await auth.consumer("app").tenants.members.list("
|
|
4963
|
+
const page = await auth.consumer("my-app").tenants.members.list("3f0c3c1e-8a2b-4c55-9d3f-0a1b2c3d4e5f", {}, { timeout: 5_000 });
|
|
4682
4964
|
```
|
|
4683
4965
|
|
|
4684
4966
|
[HTTP reference](https://productcraft.co/docs/auth/api-reference#get-app-slug-v1-tenants-tenant-id-members)
|
|
@@ -4690,6 +4972,7 @@ const page = await auth.consumer("app").tenants.members.list("tenant", {}, { tim
|
|
|
4690
4972
|
Change a member's role. PAK must hold auth.tenant.members.update-role.
|
|
4691
4973
|
|
|
4692
4974
|
- Params: `Auth.ConsumerScopedTenantMemberUpdateParams`
|
|
4975
|
+
- Credential: [`workspace_key`](#workspace_key)
|
|
4693
4976
|
|
|
4694
4977
|
| Status | Error class | Codes | When |
|
|
4695
4978
|
|---|---|---|---|
|
|
@@ -4699,7 +4982,7 @@ Change a member's role. PAK must hold auth.tenant.members.update-role.
|
|
|
4699
4982
|
| 429 | `RateLimitError` | `RATE_LIMITED` | Rate limited: too many requests from this client IP in the last 60 seconds (`RATE_LIMITED`); wait `Retry-After` seconds. |
|
|
4700
4983
|
|
|
4701
4984
|
```ts
|
|
4702
|
-
const consumerTenantMembership = await auth.consumer("app").tenants.members.update("
|
|
4985
|
+
const consumerTenantMembership = await auth.consumer("my-app").tenants.members.update("3f0c3c1e-8a2b-4c55-9d3f-0a1b2c3d4e5f", "3f0c3c1e-8a2b-4c55-9d3f-0a1b2c3d4e5f", { role_name: "admin" });
|
|
4703
4986
|
```
|
|
4704
4987
|
|
|
4705
4988
|
[HTTP reference](https://productcraft.co/docs/auth/api-reference#patch-app-slug-v1-tenants-tenant-id-members-account-id)
|
|
@@ -4718,6 +5001,7 @@ What is NOT distinct: the password policy. A supplied `password` goes through th
|
|
|
4718
5001
|
|
|
4719
5002
|
- Params: `Auth.UserCreateParams`
|
|
4720
5003
|
- Idempotent: an `Idempotency-Key` is sent automatically and reused on retries
|
|
5004
|
+
- Credential: [`app_api_key`](#app_api_key) or [`m2m_token`](#m2m_token) or [`end_user_token`](#end_user_token)
|
|
4721
5005
|
|
|
4722
5006
|
| Status | Error class | Codes | When |
|
|
4723
5007
|
|---|---|---|---|
|
|
@@ -4728,7 +5012,7 @@ What is NOT distinct: the password policy. A supplied `password` goes through th
|
|
|
4728
5012
|
| 503 | `InternalServerError` | `SERVICE_UNAVAILABLE` | The service is momentarily busy (`SERVICE_UNAVAILABLE`): too many password hashes or verifications are already running or queued on the instance that took the request. Nothing was changed and no attempt was counted. Retry after the number of seconds in the `Retry-After` header (also in `details.retry_after_seconds`). Decided by instance load only, never by the identifier or the account, so it reveals nothing about whether an account exists. |
|
|
4729
5013
|
|
|
4730
5014
|
```ts
|
|
4731
|
-
const consumerAdminCreatedUser = await auth.consumer("app").users.create({ email: "
|
|
5015
|
+
const consumerAdminCreatedUser = await auth.consumer("my-app").users.create({ email: "ada@example.com" });
|
|
4732
5016
|
```
|
|
4733
5017
|
|
|
4734
5018
|
[HTTP reference](https://productcraft.co/docs/auth/api-reference#post-app-slug-v1-admin-users)
|
|
@@ -4741,6 +5025,8 @@ Permanently delete an end-user.
|
|
|
4741
5025
|
|
|
4742
5026
|
Removes the account, its sessions, contacts, and tenant memberships. Audit rows are preserved, and the deletion itself is audited as `auth.account.deleted` with `via: consumer_admin` and the caller as actor. Fires `user.deleted` with `via: "consumer_admin"`.
|
|
4743
5027
|
|
|
5028
|
+
- Credential: [`app_api_key`](#app_api_key) or [`m2m_token`](#m2m_token) or [`end_user_token`](#end_user_token)
|
|
5029
|
+
|
|
4744
5030
|
| Status | Error class | Codes | When |
|
|
4745
5031
|
|---|---|---|---|
|
|
4746
5032
|
| 401 | `AuthenticationError` | `UNAUTHORIZED` | Missing, invalid or expired Consumer-API bearer: an EndUser or M2M token, or an app API key (`hdk_live_*` / `hdk_test_*`); or the account, session, M2M client or key is no longer active, or the key belongs to another app. |
|
|
@@ -4749,7 +5035,7 @@ Removes the account, its sessions, contacts, and tenant memberships. Audit rows
|
|
|
4749
5035
|
| 429 | `RateLimitError` | `RATE_LIMITED` | Rate limited: too many requests from this client IP in the last 60 seconds (`RATE_LIMITED`); wait `Retry-After` seconds. |
|
|
4750
5036
|
|
|
4751
5037
|
```ts
|
|
4752
|
-
await auth.consumer("app").users.delete("
|
|
5038
|
+
await auth.consumer("my-app").users.delete("3f0c3c1e-8a2b-4c55-9d3f-0a1b2c3d4e5f");
|
|
4753
5039
|
```
|
|
4754
5040
|
|
|
4755
5041
|
[HTTP reference](https://productcraft.co/docs/auth/api-reference#delete-app-slug-v1-admin-users-user-id)
|
|
@@ -4764,6 +5050,7 @@ Cursor-paginated. Supports the same `status` and `search` filters as the auth-ad
|
|
|
4764
5050
|
|
|
4765
5051
|
- Params: `Auth.UserListParams`
|
|
4766
5052
|
- Paginated: `for await` iterates every item; `await` gives one page
|
|
5053
|
+
- Credential: [`app_api_key`](#app_api_key) or [`m2m_token`](#m2m_token) or [`end_user_token`](#end_user_token)
|
|
4767
5054
|
|
|
4768
5055
|
| Status | Error class | Codes | When |
|
|
4769
5056
|
|---|---|---|---|
|
|
@@ -4774,10 +5061,10 @@ Cursor-paginated. Supports the same `status` and `search` filters as the auth-ad
|
|
|
4774
5061
|
| 429 | `RateLimitError` | `RATE_LIMITED` | Rate limited: too many requests from this client IP in the last 60 seconds (`RATE_LIMITED`); wait `Retry-After` seconds. |
|
|
4775
5062
|
|
|
4776
5063
|
```ts
|
|
4777
|
-
for await (const user of auth.consumer("app").users.list()) {
|
|
5064
|
+
for await (const user of auth.consumer("my-app").users.list()) {
|
|
4778
5065
|
console.log(user);
|
|
4779
5066
|
}
|
|
4780
|
-
const page = await auth.consumer("app").users.list({}, { timeout: 5_000 });
|
|
5067
|
+
const page = await auth.consumer("my-app").users.list({}, { timeout: 5_000 });
|
|
4781
5068
|
```
|
|
4782
5069
|
|
|
4783
5070
|
[HTTP reference](https://productcraft.co/docs/auth/api-reference#get-app-slug-v1-admin-users)
|
|
@@ -4788,6 +5075,8 @@ const page = await auth.consumer("app").users.list({}, { timeout: 5_000 });
|
|
|
4788
5075
|
|
|
4789
5076
|
Read one end-user.
|
|
4790
5077
|
|
|
5078
|
+
- Credential: [`app_api_key`](#app_api_key) or [`m2m_token`](#m2m_token) or [`end_user_token`](#end_user_token)
|
|
5079
|
+
|
|
4791
5080
|
| Status | Error class | Codes | When |
|
|
4792
5081
|
|---|---|---|---|
|
|
4793
5082
|
| 401 | `AuthenticationError` | `UNAUTHORIZED` | Missing, invalid or expired bearer token. |
|
|
@@ -4795,7 +5084,7 @@ Read one end-user.
|
|
|
4795
5084
|
| 429 | `RateLimitError` | `RATE_LIMITED` | Rate limited: too many requests from this client IP in the last 60 seconds (`RATE_LIMITED`); wait `Retry-After` seconds. |
|
|
4796
5085
|
|
|
4797
5086
|
```ts
|
|
4798
|
-
const consumerAdminEndUser = await auth.consumer("app").users.retrieve("
|
|
5087
|
+
const consumerAdminEndUser = await auth.consumer("my-app").users.retrieve("3f0c3c1e-8a2b-4c55-9d3f-0a1b2c3d4e5f");
|
|
4799
5088
|
```
|
|
4800
5089
|
|
|
4801
5090
|
[HTTP reference](https://productcraft.co/docs/auth/api-reference#get-app-slug-v1-admin-users-user-id)
|
|
@@ -4809,6 +5098,7 @@ Update an end-user's display name or primary email.
|
|
|
4809
5098
|
Email update promotes an existing contact to primary (not for creating new contacts — that goes through the per-contact flow).
|
|
4810
5099
|
|
|
4811
5100
|
- Params: `Auth.UserUpdateParams`
|
|
5101
|
+
- Credential: [`app_api_key`](#app_api_key) or [`m2m_token`](#m2m_token) or [`end_user_token`](#end_user_token)
|
|
4812
5102
|
|
|
4813
5103
|
| Status | Error class | Codes | When |
|
|
4814
5104
|
|---|---|---|---|
|
|
@@ -4819,7 +5109,7 @@ Email update promotes an existing contact to primary (not for creating new conta
|
|
|
4819
5109
|
| 429 | `RateLimitError` | `RATE_LIMITED` | Rate limited: too many requests from this client IP in the last 60 seconds (`RATE_LIMITED`); wait `Retry-After` seconds. |
|
|
4820
5110
|
|
|
4821
5111
|
```ts
|
|
4822
|
-
const consumerAdminEndUser = await auth.consumer("app").users.update("
|
|
5112
|
+
const consumerAdminEndUser = await auth.consumer("my-app").users.update("3f0c3c1e-8a2b-4c55-9d3f-0a1b2c3d4e5f", { display_name: "Ada Lovelace" });
|
|
4823
5113
|
```
|
|
4824
5114
|
|
|
4825
5115
|
[HTTP reference](https://productcraft.co/docs/auth/api-reference#patch-app-slug-v1-admin-users-user-id)
|
|
@@ -4833,6 +5123,7 @@ Assign an end-user a role.
|
|
|
4833
5123
|
Sets `app_membership.role_id` for the target user. For M2M callers the assignable role is bounded by the token's scopes (the guard already enforced `role.assign`); the role's own permission set is NOT additionally narrowed against the M2M scopes because M2M scopes are typically broader than per-user role perms by design (a backend cron with `user.list` + `role.assign` SHOULD be able to promote a user into a role carrying any per-app perm). EndUser admins are bounded by their own role's perms transitively — they couldn't authenticate as an admin without holding the perm.
|
|
4834
5124
|
|
|
4835
5125
|
- Params: `Auth.UserUpdateRoleParams`
|
|
5126
|
+
- Credential: [`app_api_key`](#app_api_key) or [`m2m_token`](#m2m_token) or [`end_user_token`](#end_user_token)
|
|
4836
5127
|
|
|
4837
5128
|
| Status | Error class | Codes | When |
|
|
4838
5129
|
|---|---|---|---|
|
|
@@ -4843,7 +5134,7 @@ Sets `app_membership.role_id` for the target user. For M2M callers the assignabl
|
|
|
4843
5134
|
| 429 | `RateLimitError` | `RATE_LIMITED` | Rate limited: too many requests from this client IP in the last 60 seconds (`RATE_LIMITED`); wait `Retry-After` seconds. |
|
|
4844
5135
|
|
|
4845
5136
|
```ts
|
|
4846
|
-
const consumerAdminRoleAssignment = await auth.consumer("app").users.updateRole("
|
|
5137
|
+
const consumerAdminRoleAssignment = await auth.consumer("my-app").users.updateRole("3f0c3c1e-8a2b-4c55-9d3f-0a1b2c3d4e5f", { role_name: "member" });
|
|
4847
5138
|
```
|
|
4848
5139
|
|
|
4849
5140
|
[HTTP reference](https://productcraft.co/docs/auth/api-reference#patch-app-slug-v1-admin-users-user-id-role)
|
|
@@ -4857,6 +5148,7 @@ Change an end-user status (active / suspended / deactivated).
|
|
|
4857
5148
|
Setting status to `suspended` or `deactivated` also revokes all active sessions for the user (same behaviour as the auth-admin equivalent).
|
|
4858
5149
|
|
|
4859
5150
|
- Params: `Auth.UserUpdateStatusParams`
|
|
5151
|
+
- Credential: [`app_api_key`](#app_api_key) or [`m2m_token`](#m2m_token) or [`end_user_token`](#end_user_token)
|
|
4860
5152
|
|
|
4861
5153
|
| Status | Error class | Codes | When |
|
|
4862
5154
|
|---|---|---|---|
|
|
@@ -4867,7 +5159,7 @@ Setting status to `suspended` or `deactivated` also revokes all active sessions
|
|
|
4867
5159
|
| 429 | `RateLimitError` | `RATE_LIMITED` | Rate limited: too many requests from this client IP in the last 60 seconds (`RATE_LIMITED`); wait `Retry-After` seconds. |
|
|
4868
5160
|
|
|
4869
5161
|
```ts
|
|
4870
|
-
const consumerAdminEndUser = await auth.consumer("app").users.updateStatus("
|
|
5162
|
+
const consumerAdminEndUser = await auth.consumer("my-app").users.updateStatus("3f0c3c1e-8a2b-4c55-9d3f-0a1b2c3d4e5f", { status: "active" });
|
|
4871
5163
|
```
|
|
4872
5164
|
|
|
4873
5165
|
[HTTP reference](https://productcraft.co/docs/auth/api-reference#patch-app-slug-v1-admin-users-user-id-status)
|
|
@@ -4884,6 +5176,7 @@ Creates the factor in the enabled state. TOTP: returns the cleartext secret + ot
|
|
|
4884
5176
|
|
|
4885
5177
|
- Params: `Auth.UserFactorCreateParams`
|
|
4886
5178
|
- Idempotent: an `Idempotency-Key` is sent automatically and reused on retries
|
|
5179
|
+
- Credential: [`workspace_key`](#workspace_key)
|
|
4887
5180
|
|
|
4888
5181
|
| Status | Error class | Codes | When |
|
|
4889
5182
|
|---|---|---|---|
|
|
@@ -4896,7 +5189,7 @@ Creates the factor in the enabled state. TOTP: returns the cleartext secret + ot
|
|
|
4896
5189
|
| 429 | `RateLimitError` | `RATE_LIMITED` | Rate limited: too many requests from this client IP in the last 60 seconds (`RATE_LIMITED`); wait `Retry-After` seconds. |
|
|
4897
5190
|
|
|
4898
5191
|
```ts
|
|
4899
|
-
const adminProvisionFactor = await auth.consumer("app").users.factors.create("
|
|
5192
|
+
const adminProvisionFactor = await auth.consumer("my-app").users.factors.create("3f0c3c1e-8a2b-4c55-9d3f-0a1b2c3d4e5f", { type: "totp" });
|
|
4900
5193
|
```
|
|
4901
5194
|
|
|
4902
5195
|
[HTTP reference](https://productcraft.co/docs/auth/api-reference#post-app-slug-v1-users-user-id-factors)
|
|
@@ -4907,6 +5200,8 @@ const adminProvisionFactor = await auth.consumer("app").users.factors.create("us
|
|
|
4907
5200
|
|
|
4908
5201
|
Disable a user's MFA factor.
|
|
4909
5202
|
|
|
5203
|
+
- Credential: [`workspace_key`](#workspace_key)
|
|
5204
|
+
|
|
4910
5205
|
| Status | Error class | Codes | When |
|
|
4911
5206
|
|---|---|---|---|
|
|
4912
5207
|
| 401 | `AuthenticationError` | `UNAUTHORIZED` | Missing bearer token, or the Platform API Key is malformed, unknown or revoked. |
|
|
@@ -4916,7 +5211,7 @@ Disable a user's MFA factor.
|
|
|
4916
5211
|
| 429 | `RateLimitError` | `RATE_LIMITED` | Rate limited: too many requests from this client IP in the last 60 seconds (`RATE_LIMITED`); wait `Retry-After` seconds. |
|
|
4917
5212
|
|
|
4918
5213
|
```ts
|
|
4919
|
-
await auth.consumer("app").users.factors.delete("
|
|
5214
|
+
await auth.consumer("my-app").users.factors.delete("3f0c3c1e-8a2b-4c55-9d3f-0a1b2c3d4e5f", "3f0c3c1e-8a2b-4c55-9d3f-0a1b2c3d4e5f");
|
|
4920
5215
|
```
|
|
4921
5216
|
|
|
4922
5217
|
[HTTP reference](https://productcraft.co/docs/auth/api-reference#delete-app-slug-v1-users-user-id-factors-factor-id)
|
|
@@ -4927,6 +5222,8 @@ await auth.consumer("app").users.factors.delete("user", "factor");
|
|
|
4927
5222
|
|
|
4928
5223
|
List a user's MFA factors.
|
|
4929
5224
|
|
|
5225
|
+
- Credential: [`workspace_key`](#workspace_key)
|
|
5226
|
+
|
|
4930
5227
|
| Status | Error class | Codes | When |
|
|
4931
5228
|
|---|---|---|---|
|
|
4932
5229
|
| 401 | `AuthenticationError` | `UNAUTHORIZED` | Missing bearer token, or the Platform API Key is malformed, unknown or revoked. |
|
|
@@ -4936,7 +5233,7 @@ List a user's MFA factors.
|
|
|
4936
5233
|
| 429 | `RateLimitError` | `RATE_LIMITED` | Rate limited: too many requests from this client IP in the last 60 seconds (`RATE_LIMITED`); wait `Retry-After` seconds. |
|
|
4937
5234
|
|
|
4938
5235
|
```ts
|
|
4939
|
-
const factorList = await auth.consumer("app").users.factors.list("
|
|
5236
|
+
const factorList = await auth.consumer("my-app").users.factors.list("3f0c3c1e-8a2b-4c55-9d3f-0a1b2c3d4e5f");
|
|
4940
5237
|
```
|
|
4941
5238
|
|
|
4942
5239
|
[HTTP reference](https://productcraft.co/docs/auth/api-reference#get-app-slug-v1-users-user-id-factors)
|
|
@@ -4963,7 +5260,7 @@ Token source: `body.token` if provided, else the `Authorization: Bearer <jwt>` h
|
|
|
4963
5260
|
| 429 | `RateLimitError` | `RATE_LIMITED` | Rate limited: too many requests from this client IP in the last 60 seconds (`RATE_LIMITED`); wait `Retry-After` seconds. |
|
|
4964
5261
|
|
|
4965
5262
|
```ts
|
|
4966
|
-
const authorize = await auth.consumer("app").verify.authorize({ permission: "
|
|
5263
|
+
const authorize = await auth.consumer("my-app").verify.authorize({ permission: "invoice.read" });
|
|
4967
5264
|
```
|
|
4968
5265
|
|
|
4969
5266
|
[HTTP reference](https://productcraft.co/docs/auth/api-reference#post-app-slug-v1-authorize)
|
|
@@ -4988,7 +5285,7 @@ Token source: `body.token` if provided, else the `Authorization: Bearer <jwt>` h
|
|
|
4988
5285
|
| 429 | `RateLimitError` | `RATE_LIMITED` | Rate limited: too many requests from this client IP in the last 60 seconds (`RATE_LIMITED`); wait `Retry-After` seconds. |
|
|
4989
5286
|
|
|
4990
5287
|
```ts
|
|
4991
|
-
const authorizeBatch = await auth.consumer("app").verify.authorizeBatch({ checks: [{}] });
|
|
5288
|
+
const authorizeBatch = await auth.consumer("my-app").verify.authorizeBatch({ checks: [{}] });
|
|
4992
5289
|
```
|
|
4993
5290
|
|
|
4994
5291
|
[HTTP reference](https://productcraft.co/docs/auth/api-reference#post-app-slug-v1-authorize-batch)
|
|
@@ -5013,7 +5310,7 @@ Token source: `body.token` if provided, else the `Authorization: Bearer <jwt>` h
|
|
|
5013
5310
|
| 429 | `RateLimitError` | `RATE_LIMITED` | Rate limited: too many requests from this client IP in the last 60 seconds (`RATE_LIMITED`); wait `Retry-After` seconds. |
|
|
5014
5311
|
|
|
5015
5312
|
```ts
|
|
5016
|
-
const verify = await auth.consumer("app").verify.token({ token: "
|
|
5313
|
+
const verify = await auth.consumer("my-app").verify.token({ token: "eyJhbGciOiJSUzI1NiIsImtpZCI6ImsxIn0.eyJzdWIiOiJ1c3JfMSJ9.c2lnbmF0dXJl" });
|
|
5017
5314
|
```
|
|
5018
5315
|
|
|
5019
5316
|
[HTTP reference](https://productcraft.co/docs/auth/api-reference#post-app-slug-v1-verify)
|
|
@@ -5036,7 +5333,7 @@ Returns the JSON Web Key Set used to sign EndUser and M2M access tokens for this
|
|
|
5036
5333
|
| 429 | `RateLimitError` | `RATE_LIMITED` | Rate limited: too many requests from this client IP in the last 60 seconds (`RATE_LIMITED`); wait `Retry-After` seconds. |
|
|
5037
5334
|
|
|
5038
5335
|
```ts
|
|
5039
|
-
const jwks = await auth.consumer("app").wellKnown.jwks();
|
|
5336
|
+
const jwks = await auth.consumer("my-app").wellKnown.jwks();
|
|
5040
5337
|
```
|
|
5041
5338
|
|
|
5042
5339
|
[HTTP reference](https://productcraft.co/docs/auth/api-reference#get-app-slug-well-known-jwks-json)
|
|
@@ -5057,11 +5354,31 @@ Returns `issuer`, `jwks_uri`, `token_endpoint`, `introspection_endpoint`, `useri
|
|
|
5057
5354
|
| 429 | `RateLimitError` | `RATE_LIMITED` | Rate limited: too many requests from this client IP in the last 60 seconds (`RATE_LIMITED`); wait `Retry-After` seconds. |
|
|
5058
5355
|
|
|
5059
5356
|
```ts
|
|
5060
|
-
const openIdConfiguration = await auth.consumer("app").wellKnown.openidConfiguration();
|
|
5357
|
+
const openIdConfiguration = await auth.consumer("my-app").wellKnown.openidConfiguration();
|
|
5061
5358
|
```
|
|
5062
5359
|
|
|
5063
5360
|
[HTTP reference](https://productcraft.co/docs/auth/api-reference#get-app-slug-well-known-openid-configuration)
|
|
5064
5361
|
|
|
5362
|
+
## Credentials
|
|
5363
|
+
|
|
5364
|
+
Routes take different credentials; each method above says which. Every one is sent as `Authorization: Bearer`. A workspace API key is the client's `apiKey` (or `PRODUCTCRAFT_API_KEY`); pass any other as `new Auth({ auth: { type: "bearer", token } })`. The wrong one answers 401.
|
|
5365
|
+
|
|
5366
|
+
### `app_api_key`
|
|
5367
|
+
|
|
5368
|
+
An app API key (`hdk_live_…` or `hdk_test_…`) minted for this app (`POST /v1/apps/{app_id}/api-keys`). Its permissions are always enforced. A workspace key is refused.
|
|
5369
|
+
|
|
5370
|
+
### `end_user_token`
|
|
5371
|
+
|
|
5372
|
+
An end user's access token for this app, from `signin`, `signup` or `refresh`. Acts as that user.
|
|
5373
|
+
|
|
5374
|
+
### `m2m_token`
|
|
5375
|
+
|
|
5376
|
+
An access token from this app's client-credentials grant (`POST /{app_slug}/v1/oauth/token`).
|
|
5377
|
+
|
|
5378
|
+
### `workspace_key`
|
|
5379
|
+
|
|
5380
|
+
A workspace API key (`pcft_live_…`, what the SDKs read from `PRODUCTCRAFT_API_KEY`) or a signed-in ProductCraft platform session token. Its workspace policy decides what it may do.
|
|
5381
|
+
|
|
5065
5382
|
## Error codes
|
|
5066
5383
|
|
|
5067
5384
|
`err.code` on an `APIError` is one of these (an open set: new codes may appear).
|