torii-backend 0.0.12 → 0.0.13

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.
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: ef8cdd000a9848f1319431c7aba7b66ade0cd4d3e53d8dece0e04242b1f0126e
4
- data.tar.gz: bc18972daa14df1a16a7cd7b91956e269f3dca5e36fa6bc3894b6b027b94545e
3
+ metadata.gz: 990f5b5d3788b63f65c2461ebb1061171d475d61769ea495b2ec71d39ce0db93
4
+ data.tar.gz: 37b546ef8b09f1c10951643f406827684bb9e527fd907cf0924386e8c0d86530
5
5
  SHA512:
6
- metadata.gz: 2778805b73a661672d88d70a20e9cb13501eb42e4cd2f873ee1caf0004d253d4e72b4814166333c1a2562659024ab3b92db3fdd604081cc06157748420dd2638
7
- data.tar.gz: 7ad7011d73b793e75c2cee103370abe111725a365e6bb7a56f6b9ed1902f25376d6565ab5eed9af0e37e28e0b79815ba41dfdc70ddb178d415f32ea73f763ba4
6
+ metadata.gz: 2d62d6abf71614e4bffab5e41f440039e84f022f3c588faa064aef7537d03e009b6851091e8914655513acea133913f1fb4778b5c3e6621b8d4ab75c214612c3
7
+ data.tar.gz: a4e326f06536d3d19f581079896e7a0b82397ebf658d679a8ed4a92cd5d6bc290a8d629254889ce95894ae43223468d31fba6534f68d15149d9956f1e695c906
data/spec/server-v1.json CHANGED
@@ -1 +1 @@
1
- {"openapi":"3.1.0","info":{"title":"Torii Backend API","description":"Server-to-server API (BAPI) for backend SDKs. Authenticated with a secret key (Bearer sk_live_* / sk_test_*).","version":"v1"},"servers":[{"url":"https://api.toriiauth.eu","description":"Production backend API"}],"security":[{"bearerAuth":[]}],"tags":[{"name":"Allowed Origins","description":"Escape-hatch origins for non-web stacks (secret key auth)"},{"name":"Server Impersonation","description":"Secret-key impersonation token minting"},{"name":"Invitations","description":"Invite end-users into the environment (secret key auth)"},{"name":"Server Users","description":"Server user management endpoints (secret key auth)"},{"name":"Server Sessions","description":"Server session management endpoints (secret key auth)"},{"name":"Server Organizations","description":"Server organization + membership metadata endpoints (secret key auth)"}],"paths":{"/api/server/v1/allowed-origins":{"get":{"tags":["Allowed Origins"],"summary":"List escape-hatch origins for this environment","operationId":"list","responses":{"200":{"description":"OK","content":{"application/json":{"schema":{"$ref":"#/components/schemas/AllowedOriginsResponse"}}}}}},"put":{"tags":["Allowed Origins"],"summary":"Replace the escape-hatch origins for this environment","description":"Full origins incl. non-http schemes (e.g. capacitor://localhost). Replaces the list.","operationId":"set","requestBody":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/SetAllowedOriginsRequest"}}},"required":true},"responses":{"200":{"description":"OK","content":{"application/json":{"schema":{"$ref":"#/components/schemas/AllowedOriginsResponse"}}}}}}},"/api/server/v1/users":{"post":{"tags":["Server Users"],"summary":"Create user","description":"Creates an end-user in your environment. All body fields are optional; supply at minimum an email if you want the user to be able to sign in via email + password.","operationId":"createUser","requestBody":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/CreateUserRequest"}}},"required":true},"responses":{"201":{"description":"The created user.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ServerUserResponse"}}}},"400":{"description":"Invalid body (e.g. weak password, malformed email).","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/ProblemDetail"}}}},"401":{"description":"Missing or invalid secret key.","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/ProblemDetail"}}}},"409":{"description":"Another user with this email already exists in the environment.","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/ProblemDetail"}}}}}}},"/api/server/v1/users/{userId}/unban":{"post":{"tags":["Server Users"],"summary":"Unban user","description":"Reverses a previous ban. The user can sign in again on next request.","operationId":"unbanUser","parameters":[{"name":"userId","in":"path","description":"Identifier of the user to unban.","required":true,"schema":{"type":"string","format":"uuid"},"example":"01931a73-8b00-7000-8000-000000000000"}],"responses":{"200":{"description":"The (now active) user.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ServerUserResponse"}}}},"401":{"description":"Missing or invalid secret key.","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/ProblemDetail"}}}},"403":{"description":"User belongs to a different environment.","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/ProblemDetail"}}}},"404":{"description":"No user with this id.","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/ProblemDetail"}}}}}}},"/api/server/v1/users/{userId}/impersonation-token":{"post":{"tags":["Server Impersonation"],"summary":"Mint an impersonation token","description":"Creates a single-use, short-lived impersonation token for the target user, attributed to `actorUserId`. Redeem it programmatically via `POST /_torii/auth/session/impersonate` (access token in the body), or hand the returned `url` to an operator to open in a browser (establishes the session and redirects to the landing URL). Counts against the same per-period impersonation quota and usage ledger as the dashboard.","operationId":"mintImpersonationToken","parameters":[{"name":"userId","in":"path","description":"The user to impersonate.","required":true,"schema":{"type":"string","format":"uuid"},"example":"01931a73-8b00-7000-8000-000000000000"}],"requestBody":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ServerImpersonationTokenRequest"}}},"required":true},"responses":{"200":{"description":"The minted token, its lifetime, and (when a landing URL resolves) a ready-to-use redeem URL.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ServerImpersonationTokenResponse"}}}},"400":{"description":"Deleted target, `expiresInSeconds` out of the 60..600 range, or `redirectUrl` malformed / not in the environment's allowed origins.","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/ProblemDetail"}}}},"401":{"description":"Missing or invalid secret key.","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/ProblemDetail"}}}},"402":{"description":"Plan does not include impersonation, or the per-period quota is exhausted.","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/ProblemDetail"}}}},"403":{"description":"Target or actor is in another environment, or impersonation is disabled for this environment.","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/ProblemDetail"}}}}}}},"/api/server/v1/users/{userId}/ban":{"post":{"tags":["Server Users"],"summary":"Ban user","description":"Marks the user as banned and revokes all their active sessions.","operationId":"banUser","parameters":[{"name":"userId","in":"path","description":"Identifier of the user to ban.","required":true,"schema":{"type":"string","format":"uuid"},"example":"01931a73-8b00-7000-8000-000000000000"}],"responses":{"200":{"description":"The (now banned) user.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ServerUserResponse"}}}},"401":{"description":"Missing or invalid secret key.","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/ProblemDetail"}}}},"403":{"description":"User belongs to a different environment.","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/ProblemDetail"}}}},"404":{"description":"No user with this id.","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/ProblemDetail"}}}}}}},"/api/server/v1/users/search":{"post":{"tags":["Server Users"],"summary":"Search users","description":"Returns a cursor-paginated page of end-users in the environment matching the optional filters. Uses POST so the filter body can be sent without URL-encoding. Three id-selectors resolve users to a set of ids (`userIds`, the explicit batch-by-id lookup; `emailAddresses`, exact and case-insensitive; `email`, a case-insensitive substring); when more than one is supplied they are combined with AND (intersection). The remaining filters (`name`, `statuses`, `createdAfter`/`createdBefore`) apply on top.","operationId":"searchUsers","parameters":[{"name":"limit","in":"query","description":"Maximum number of items in the returned page (default 20).","required":false,"schema":{"type":"integer","format":"int32","default":20},"example":50},{"name":"cursor","in":"query","description":"Opaque cursor returned by the previous page's `nextCursor`. Omit to fetch the first page.","required":false,"schema":{"type":"string","format":"uuid"},"example":"01931a73-8b00-7000-8000-000000000000"}],"requestBody":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ServerUserSearchRequest"}}}},"responses":{"200":{"description":"Page of matching users.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/CursorPageResponseServerUserResponse"}}}},"400":{"description":"An id-selector list exceeds 100 entries.","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/ProblemDetail"}}}},"401":{"description":"Missing or invalid secret key.","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/ProblemDetail"}}}}}}},"/api/server/v1/invitations":{"get":{"tags":["Invitations"],"summary":"List invitations for this environment","operationId":"list_1","parameters":[{"name":"status","in":"query","required":false,"schema":{"type":"array","items":{"type":"string"}}},{"name":"search","in":"query","required":false,"schema":{"type":"string"}},{"name":"limit","in":"query","required":false,"schema":{"type":"integer","format":"int32","default":20}},{"name":"cursor","in":"query","required":false,"schema":{"type":"string","format":"uuid"}}],"responses":{"200":{"description":"OK","content":{"application/json":{"schema":{"$ref":"#/components/schemas/CursorPageResponseEnvironmentInvitationResponse"}}}}}},"post":{"tags":["Invitations"],"summary":"Create an invitation with optional pre-seeded metadata","operationId":"create","requestBody":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/CreateEnvironmentInvitationServerRequest"}}},"required":true},"responses":{"201":{"description":"The created invitation. The email has been sent.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/EnvironmentInvitationResponse"}}}},"400":{"description":"Invalid body, metadata over the 8KB budget, or the environment has no sign-up URL configured.","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/ProblemDetail"}}}},"401":{"description":"Missing or invalid secret key.","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/ProblemDetail"}}}},"409":{"description":"This email already has an account in the environment.","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/ProblemDetail"}}}},"429":{"description":"The environment's invitation rate limit is exhausted.","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/ProblemDetail"}}}}}}},"/api/server/v1/invitations/{invitationId}/resend":{"post":{"tags":["Invitations"],"summary":"Resend a pending invitation with a fresh link","operationId":"resend","parameters":[{"name":"invitationId","in":"path","required":true,"schema":{"type":"string","format":"uuid"}}],"responses":{"200":{"description":"OK","content":{"application/json":{"schema":{"$ref":"#/components/schemas/EnvironmentInvitationResponse"}}}}}}},"/api/server/v1/users/{userId}":{"get":{"tags":["Server Users"],"summary":"Get user","description":"Returns the full profile for one end-user.","operationId":"getUser","parameters":[{"name":"userId","in":"path","description":"Identifier of the user to fetch.","required":true,"schema":{"type":"string","format":"uuid"},"example":"01931a73-8b00-7000-8000-000000000000"}],"responses":{"200":{"description":"The user.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ServerUserResponse"}}}},"401":{"description":"Missing or invalid secret key.","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/ProblemDetail"}}}},"403":{"description":"User belongs to a different environment.","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/ProblemDetail"}}}},"404":{"description":"No user with this id.","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/ProblemDetail"}}}}}},"delete":{"tags":["Server Users"],"summary":"Delete user","description":"Soft-deletes the user. Not idempotent at the HTTP layer: the authorization grant for the user is revoked on the first successful delete, so a subsequent DELETE for the same id returns 403 rather than 204. Treat 403 from a retry as a confirmation that the user is already deleted.","operationId":"deleteUser","parameters":[{"name":"userId","in":"path","description":"Identifier of the user to delete.","required":true,"schema":{"type":"string","format":"uuid"},"example":"01931a73-8b00-7000-8000-000000000000"}],"responses":{"204":{"description":"User deleted."},"401":{"description":"Missing or invalid secret key.","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/ProblemDetail"}}}},"403":{"description":"User belongs to a different environment.","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/ProblemDetail"}}}},"404":{"description":"No user with this id.","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/ProblemDetail"}}}}}},"patch":{"tags":["Server Users"],"summary":"Update user","description":"Partial update with tri-state PATCH semantics. Every field in `UpdateUserRequest` is tri-state: omit the key to leave the field unchanged, send a non-null value to set it, or send JSON null to clear it.","operationId":"updateUser","parameters":[{"name":"userId","in":"path","description":"Identifier of the user to update.","required":true,"schema":{"type":"string","format":"uuid"},"example":"01931a73-8b00-7000-8000-000000000000"}],"requestBody":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/UpdateUserRequest"}}},"required":true},"responses":{"200":{"description":"The updated user.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ServerUserResponse"}}}},"400":{"description":"Invalid body.","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/ProblemDetail"}}}},"401":{"description":"Missing or invalid secret key.","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/ProblemDetail"}}}},"403":{"description":"User belongs to a different environment.","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/ProblemDetail"}}}},"404":{"description":"No user with this id.","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/ProblemDetail"}}}}}}},"/api/server/v1/users/{userId}/metadata":{"patch":{"tags":["Server Users"],"summary":"Update user metadata","description":"Deep-merges into any of the three metadata bags. Each bag is tri-state: omit the key to leave the bag unchanged, or send an object to deep-merge into the existing bag (a key set to null removes it). The merged metadata is capped at 8 KB total across `publicMetadata`, `privateMetadata`, and `unsafeMetadata` combined (no per-bag limit).","operationId":"updateUserMetadata","parameters":[{"name":"userId","in":"path","description":"Identifier of the user to update.","required":true,"schema":{"type":"string","format":"uuid"},"example":"01931a73-8b00-7000-8000-000000000000"}],"requestBody":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/UpdateUserMetadataRequest"}}},"required":true},"responses":{"200":{"description":"The updated user.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ServerUserResponse"}}}},"400":{"description":"A bag exceeds its size limit.","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/ProblemDetail"}}}},"401":{"description":"Missing or invalid secret key.","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/ProblemDetail"}}}},"403":{"description":"User belongs to a different environment.","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/ProblemDetail"}}}},"404":{"description":"No user with this id.","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/ProblemDetail"}}}}}}},"/api/server/v1/organizations/{organizationId}/metadata":{"patch":{"tags":["Server Organizations"],"summary":"Update organization metadata","description":"Deep-merges into either metadata bag. Each bag is tri-state: omit the key to leave the bag unchanged, or send an object to deep-merge into it (a key set to null removes it). Each bag is capped at 8 KB on its own, measured on the merged result rather than on the patch you send. A request naming neither bag is a 400.","operationId":"updateOrganizationMetadata","parameters":[{"name":"organizationId","in":"path","required":true,"schema":{"type":"string","format":"uuid"}}],"requestBody":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/UpdateOrganizationMetadataRequest"}}},"required":true},"responses":{"200":{"description":"The updated organization.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ServerOrganizationResponse"}}}},"400":{"description":"The merged metadata exceeds the size limit.","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/ProblemDetail"}}}},"401":{"description":"Missing or invalid secret key.","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/ProblemDetail"}}}},"404":{"description":"No organization with this id in the key's environment.","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/ProblemDetail"}}}}}}},"/api/server/v1/organizations/{organizationId}/members/{memberUserId}/metadata":{"patch":{"tags":["Server Organizations"],"summary":"Update organization membership metadata","description":"Deep-merges into either bag on one membership, with the same tri-state contract as the organization endpoint. Each bag on the membership has its own 8 KB budget, separate from the organization's bags.","operationId":"updateMemberMetadata","parameters":[{"name":"organizationId","in":"path","required":true,"schema":{"type":"string","format":"uuid"}},{"name":"memberUserId","in":"path","required":true,"schema":{"type":"string","format":"uuid"}}],"requestBody":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/UpdateOrganizationMetadataRequest"}}},"required":true},"responses":{"200":{"description":"The updated membership.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ServerOrganizationMemberResponse"}}}},"400":{"description":"The merged metadata exceeds the size limit.","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/ProblemDetail"}}}},"401":{"description":"Missing or invalid secret key.","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/ProblemDetail"}}}},"404":{"description":"No such organization in the key's environment, or the user is not a member of it.","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/ProblemDetail"}}}}}}},"/api/server/v1/users/{userId}/sessions":{"get":{"tags":["Server Sessions"],"summary":"List user sessions","description":"Returns all active (unexpired, unrevoked) sessions for the user, ordered by most recently used.","operationId":"listSessions","parameters":[{"name":"userId","in":"path","description":"Identifier of the user whose sessions to list.","required":true,"schema":{"type":"string","format":"uuid"},"example":"01931a73-8b00-7000-8000-000000000000"}],"responses":{"200":{"description":"All active sessions for the user.","content":{"application/json":{"schema":{"type":"array","items":{"$ref":"#/components/schemas/UserSessionResponse"}}}}},"401":{"description":"Missing or invalid secret key.","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/ProblemDetail"}}}},"403":{"description":"User belongs to a different environment.","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/ProblemDetail"}}}}}},"delete":{"tags":["Server Sessions"],"summary":"Revoke all sessions","description":"Immediately revokes every active session for the user. Idempotent.","operationId":"revokeAllSessions","parameters":[{"name":"userId","in":"path","description":"Identifier of the user whose sessions to revoke.","required":true,"schema":{"type":"string","format":"uuid"},"example":"01931a73-8b00-7000-8000-000000000000"}],"responses":{"204":{"description":"Sessions revoked."},"401":{"description":"Missing or invalid secret key.","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/ProblemDetail"}}}},"403":{"description":"User belongs to a different environment.","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/ProblemDetail"}}}}}}},"/api/server/v1/users/{userId}/organizations":{"get":{"tags":["Server Users"],"summary":"List a user's organizations","description":"Returns a cursor-paginated page of the organizations this user is a member of, with the user's role in each and that membership's metadata bags. The mirror image of listing an organization's members. Note the bags are the MEMBERSHIP's, not the organization's: read the organization itself for those.","operationId":"listUserOrganizations","parameters":[{"name":"userId","in":"path","description":"Identifier of the user whose organizations to list.","required":true,"schema":{"type":"string","format":"uuid"},"example":"01931a73-8b00-7000-8000-000000000000"},{"name":"limit","in":"query","description":"Maximum number of items in the returned page (default 20).","required":false,"schema":{"type":"integer","format":"int32","default":20},"example":50},{"name":"cursor","in":"query","description":"Opaque cursor returned by the previous page's `nextCursor`. Omit to fetch the first page.","required":false,"schema":{"type":"string","format":"uuid"},"example":"01931a73-8b00-7000-8000-000000000000"}],"responses":{"200":{"description":"Page of memberships (empty when the user belongs to no organization).","content":{"application/json":{"schema":{"$ref":"#/components/schemas/CursorPageResponseServerUserOrganizationResponse"}}}},"401":{"description":"Missing or invalid secret key.","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/ProblemDetail"}}}},"403":{"description":"The user belongs to a different environment, or no user has this id: the two are deliberately indistinguishable so a key cannot probe for foreign user ids.","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/ProblemDetail"}}}}}}},"/api/server/v1/organizations":{"get":{"tags":["Server Organizations"],"summary":"List organizations","description":"Cursor-paginated page of the environment's organizations, with both metadata bags. Optional `name` filter is a case-insensitive substring match.","operationId":"listOrganizations","parameters":[{"name":"name","in":"query","description":"Case-insensitive substring filter on the organization name.","required":false,"schema":{"type":"string"},"example":"acme"},{"name":"limit","in":"query","description":"Maximum number of items in the returned page (default 20; values outside 1-100 are clamped).","required":false,"schema":{"type":"integer","format":"int32","default":20},"example":50},{"name":"cursor","in":"query","description":"Opaque cursor returned by the previous page's `nextCursor`. Omit to fetch the first page.","required":false,"schema":{"type":"string","format":"uuid"},"example":"01931a73-8b00-7000-8000-000000000000"}],"responses":{"200":{"description":"Page of organizations.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/CursorPageResponseServerOrganizationResponse"}}}},"401":{"description":"Missing or invalid secret key.","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/ProblemDetail"}}}}}}},"/api/server/v1/organizations/{organizationId}":{"get":{"tags":["Server Organizations"],"summary":"Get an organization","description":"One organization with both metadata bags.","operationId":"getOrganization","parameters":[{"name":"organizationId","in":"path","required":true,"schema":{"type":"string","format":"uuid"}}],"responses":{"200":{"description":"The organization.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ServerOrganizationResponse"}}}},"401":{"description":"Missing or invalid secret key.","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/ProblemDetail"}}}},"404":{"description":"No organization with this id in the key's environment.","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/ProblemDetail"}}}}}}},"/api/server/v1/organizations/{organizationId}/members":{"get":{"tags":["Server Organizations"],"summary":"List organization members","description":"Cursor-paginated page of the organization's USER memberships, each with both metadata bags. Ordered by member user id ascending (a creation-ordered uuid v7, which is also the seek key), NOT by join time.","operationId":"listMembers","parameters":[{"name":"organizationId","in":"path","required":true,"schema":{"type":"string","format":"uuid"}},{"name":"limit","in":"query","description":"Maximum number of items in the returned page (default 20; values outside 1-100 are clamped).","required":false,"schema":{"type":"integer","format":"int32","default":20},"example":50},{"name":"cursor","in":"query","description":"Opaque cursor returned by the previous page's `nextCursor`. Omit to fetch the first page.","required":false,"schema":{"type":"string","format":"uuid"},"example":"01931a73-8b00-7000-8000-000000000000"}],"responses":{"200":{"description":"Page of the organization's members.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/CursorPageResponseServerOrganizationMemberResponse"}}}},"401":{"description":"Missing or invalid secret key.","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/ProblemDetail"}}}},"404":{"description":"No organization with this id in the key's environment.","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/ProblemDetail"}}}}}}},"/api/server/v1/invitations/{invitationId}":{"get":{"tags":["Invitations"],"summary":"Get an invitation by id","operationId":"get","parameters":[{"name":"invitationId","in":"path","required":true,"schema":{"type":"string","format":"uuid"}}],"responses":{"200":{"description":"OK","content":{"application/json":{"schema":{"$ref":"#/components/schemas/EnvironmentInvitationResponse"}}}}}},"delete":{"tags":["Invitations"],"summary":"Revoke a pending invitation","operationId":"revoke","parameters":[{"name":"invitationId","in":"path","required":true,"schema":{"type":"string","format":"uuid"}}],"responses":{"200":{"description":"OK"}}}},"/api/server/v1/users/{userId}/sessions/{sessionId}":{"delete":{"tags":["Server Sessions"],"summary":"Revoke specific session","description":"Revokes a single session by id. Idempotent: returns 204 even if the session was already revoked or expired.","operationId":"revokeSession","parameters":[{"name":"userId","in":"path","description":"Identifier of the user who owns the session.","required":true,"schema":{"type":"string","format":"uuid"},"example":"01931a73-8b00-7000-8000-000000000000"},{"name":"sessionId","in":"path","description":"Identifier of the session to revoke.","required":true,"schema":{"type":"string","format":"uuid"},"example":"01931a74-1234-7000-8000-000000000000"}],"responses":{"204":{"description":"Session revoked."},"401":{"description":"Missing or invalid secret key.","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/ProblemDetail"}}}},"403":{"description":"User or session belongs to a different environment.","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/ProblemDetail"}}}}}}}},"components":{"schemas":{"SetAllowedOriginsRequest":{"type":"object","properties":{"origins":{"type":"array","items":{"type":"string"}}},"required":["origins"]},"AllowedOriginsResponse":{"type":"object","properties":{"origins":{"type":"array","items":{"type":"string"}}},"required":["origins"]},"CreateUserRequest":{"type":"object","description":"Request body for creating an end-user in your environment. All fields are optional; supply at minimum an email if you want the user to be able to sign in via email + password.","properties":{"email":{"type":["string","null"],"description":"Primary email for the new user. If omitted, the user is created without a sign-in identity.","example":"ada@example.com"},"password":{"type":["string","null"],"description":"Initial password. Subject to the environment's password policy. Omit to create a passwordless user (e.g. social-only).","example":"correct horse battery staple"},"firstName":{"type":["string","null"],"description":"First (given) name to seed on the profile.","example":"Ada"},"lastName":{"type":["string","null"],"description":"Last (family) name to seed on the profile.","example":"Lovelace"},"publicMetadata":{"type":"object","additionalProperties":true,"description":"Initial public metadata (SDK-readable, server-written). Part of the 8 KB combined metadata budget.","example":{"plan":"free"}},"privateMetadata":{"type":"object","additionalProperties":true,"description":"Initial private metadata (server-only). Part of the 8 KB combined metadata budget.","example":{"billingCustomerId":"cus_123"}},"unsafeMetadata":{"type":"object","additionalProperties":true,"description":"Initial unsafe metadata (end-user writable). Part of the 8 KB combined metadata budget.","example":{"onboardingStep":0}}}},"ProblemDetail":{"type":"object","properties":{"type":{"type":"string","format":"uri"},"title":{"type":"string"},"status":{"type":"integer","format":"int32"},"detail":{"type":"string"},"instance":{"type":"string","format":"uri"},"properties":{"type":"object","additionalProperties":{}}}},"ServerUserResponse":{"type":"object","description":"An end-user, including server-only private metadata. Returned only on the secret-key backend API.","properties":{"id":{"type":"string","format":"uuid","description":"Unique identifier for this user.","example":"01931a73-8b00-7000-8000-000000000000"},"environmentId":{"type":"string","format":"uuid","description":"Identifier of the environment this user belongs to.","example":"01931a72-0000-7000-8000-000000000000"},"name":{"type":["string","null"],"description":"Full name on the profile, if any.","example":"Ada Lovelace"},"firstName":{"type":["string","null"],"description":"First (given) name on the profile, if any.","example":"Ada"},"lastName":{"type":["string","null"],"description":"Last (family) name on the profile, if any.","example":"Lovelace"},"locale":{"type":["string","null"],"description":"Preferred locale for emails and UI messages.","enum":["en","da"]},"status":{"type":"string","description":"Lifecycle status of the user (e.g. active, banned).","enum":["active","banned","deleted"]},"createdAt":{"type":"string","format":"date-time","description":"When this user was created (ISO-8601 UTC).","example":"2026-05-16T09:30:00Z"},"updatedAt":{"type":"string","format":"date-time","description":"When this user was last modified (ISO-8601 UTC).","example":"2026-05-16T10:00:00Z"},"email":{"type":["string","null"],"description":"Primary email on the profile, if any.","example":"ada@example.com"},"emailVerifiedAt":{"type":["string","null"],"format":"date-time","description":"When this user's primary email was verified, if it has been verified.","example":"2026-05-16T09:35:00Z"},"deletedAt":{"type":["string","null"],"format":"date-time","description":"When this user was deleted, if soft-deleted. Null for active users.","example":"2026-05-20T12:00:00Z"},"publicMetadata":{"type":"object","additionalProperties":true,"description":"Public metadata: readable by the SDK, writable only server-side.","example":{"plan":"pro"}},"privateMetadata":{"type":"object","additionalProperties":true,"description":"Private metadata: server-only. Never exposed to the SDK or in a JWT.","example":{"billingCustomerId":"cus_123"}},"unsafeMetadata":{"type":"object","additionalProperties":true,"description":"Unsafe metadata: readable and writable by the end-user via the SDK.","example":{"onboardingStep":2}}},"required":["createdAt","environmentId","id","privateMetadata","publicMetadata","status","unsafeMetadata","updatedAt"]},"ServerImpersonationTokenRequest":{"type":"object","description":"Body for minting an impersonation token.","properties":{"actorUserId":{"type":"string","format":"uuid","description":"The principal the impersonation is on behalf of (recorded for accountability). Must be a user in this environment.","example":"01931a73-8b00-7000-8000-000000000000"},"reason":{"type":"string","description":"Mandatory justification (GDPR purpose limitation); recorded in the audit log on mint and redeem.","example":"Investigating support ticket #4821","maxLength":500,"minLength":0},"redirectUrl":{"type":["string","null"],"description":"Optional post-redeem landing URL for the `url` redeem link; its origin must be in the environment's allowed origins. Unlike the dashboard link this plane appends nothing to it, so a fragment is fine. Omit to use the environment's configured impersonation landing URL.","example":"https://app.example.com/dashboard"},"expiresInSeconds":{"type":["integer","null"],"format":"int64","description":"Optional token lifetime in seconds, 60..600. Omit for the 600s default.","example":600,"maximum":600,"minimum":60}},"required":["actorUserId","reason"]},"ServerImpersonationTokenResponse":{"type":"object","description":"A minted impersonation token.","properties":{"token":{"type":"string","description":"The single-use token. Redeem via POST /_torii/auth/session/impersonate, or hand the ready-to-use `url` to an operator."},"expiresInSeconds":{"type":"integer","format":"int64","description":"The token's lifetime in seconds (the resolved value after any override).","example":600},"url":{"type":["string","null"],"description":"A ready-to-use, navigable redeem link on the environment's Frontend API host. Opening it in a browser establishes the impersonated session and redirects to the landing URL. Backed by the same single-use token. Null when no landing URL could be resolved: no `redirectUrl` given and the environment has no impersonation landing URL configured — redeem the `token` via POST instead.","example":"https://auth.example.com/_torii/auth/session/impersonate?token=…"}},"required":["expiresInSeconds","token"]},"ServerUserSearchRequest":{"type":"object","description":"Optional filter body for `POST /users/search`. Every field is tri-state: omit to skip that filter, send a value to apply it. The three id-selectors (`userIds`, `emailAddresses`, `email`) resolve users to a set of ids and, when more than one is supplied, are combined with AND (intersection); a supplied id-selector whose resolved set is empty returns an empty page. `name` additionally accepts JSON null to match users with no name; an explicit null or blank `email` contributes no restriction; the non-nullable `statuses` field rejects null.","properties":{"name":{"type":["string","null"],"description":"Filter by name (case-insensitive substring match). Send null to require users with no name.","example":"Ada"},"userIds":{"type":"array","description":"Restrict to these user ids (the explicit batch-by-id lookup), at most 100. AND-combined with the other id-selectors; an empty list returns an empty page.","example":["01931a73-8b00-7000-8000-000000000000"],"items":{"type":"string","format":"uuid"}},"emailAddresses":{"type":"array","description":"Resolve users by exact (case-insensitive) email address (one or more, at most 100). Unlike `email`, never matches a superstring. AND-combined with the other id-selectors; an empty list, or addresses matching nobody, returns an empty page.","example":["ada@example.com"],"items":{"type":"string"}},"email":{"type":["string","null"],"description":"Filter by primary email (case-insensitive substring match). AND-combined with the other id-selectors. An explicit null or blank value contributes no restriction.","example":"@example.com"},"statuses":{"type":"array","description":"Filter by user status. Returns users matching any of the supplied statuses.","items":{"type":"string","enum":["active","banned","deleted"]},"uniqueItems":true},"createdAfter":{"type":["string","null"],"format":"date-time","description":"Only return users created at or after this instant (ISO-8601 UTC).","example":"2026-01-01T00:00:00Z"},"createdBefore":{"type":["string","null"],"format":"date-time","description":"Only return users created at or before this instant (ISO-8601 UTC).","example":"2026-12-31T23:59:59Z"},"organizationId":{"type":["string","null"],"format":"uuid","description":"Only return members of this organization. An organization from another environment matches nobody. Not an id-selector: it is applied as a membership semi-join, so it is never capped and always ANDs with the rest of the filters.","example":"01931a73-8b00-7000-8000-000000000000"}}},"CursorPageResponseServerUserResponse":{"type":"object","description":"A single page of results in a cursor-paginated list. Pass `nextCursor` as the `cursor` query parameter to fetch the following page.","properties":{"items":{"type":"array","description":"Items in this page, in stable order.","items":{"$ref":"#/components/schemas/ServerUserResponse"}},"nextCursor":{"type":["string","null"],"format":"uuid","description":"Cursor to pass to fetch the next page. Null when this is the last page.","example":"01931a73-8b00-7000-8000-000000000000"},"hasMore":{"type":"boolean","description":"True if more pages are available (equivalent to `nextCursor != null`).","example":true}},"required":["hasMore","items"]},"CreateEnvironmentInvitationServerRequest":{"type":"object","properties":{"email":{"type":"string"},"expiresInDays":{"type":["integer","null"],"format":"int32"},"redirectUrl":{"type":["string","null"]},"publicMetadata":{"type":"object","additionalProperties":true},"privateMetadata":{"type":"object","additionalProperties":true}},"required":["email","privateMetadata","publicMetadata"]},"EnvironmentInvitationResponse":{"type":"object","properties":{"id":{"type":"string","format":"uuid"},"environmentId":{"type":"string","format":"uuid"},"email":{"type":"string"},"status":{"type":"string","enum":["PENDING","ACCEPTED","REVOKED","EXPIRED"]},"expiresAt":{"type":"string","format":"date-time"},"createdAt":{"type":"string","format":"date-time"},"acceptedAt":{"type":["string","null"],"format":"date-time"},"revokedAt":{"type":["string","null"],"format":"date-time"}},"required":["createdAt","email","environmentId","expiresAt","id","status"]},"UpdateUserRequest":{"type":"object","description":"PATCH body for updating an end-user. Every field is tri-state: omit the key entirely to leave the field unchanged, send a non-null value to set it, or send JSON null to clear it.","properties":{"firstName":{"type":["string","null"],"description":"New first (given) name. Send null to clear; omit to leave unchanged.","example":"Ada"},"lastName":{"type":["string","null"],"description":"New last (family) name. Send null to clear; omit to leave unchanged.","example":"Lovelace"},"locale":{"type":["string","null"],"description":"New preferred locale. Send null to clear; omit to leave unchanged.","enum":["en","da"]},"unsafeMetadata":{"type":"object","additionalProperties":true,"description":"Deep-merges into the user's unsafe metadata (a key set to null removes it); omit to leave unchanged. Counts toward the 8 KB combined metadata budget.","example":{"onboardingStep":2}}}},"UpdateUserMetadataRequest":{"type":"object","description":"PATCH body for a user's metadata bags. Each bag is tri-state: omit to leave it unchanged, or send an object value. Whether the object merges into or replaces the bag depends on the endpoint (see its operation description).","properties":{"publicMetadata":{"type":"object","additionalProperties":true,"description":"Public metadata bag: SDK-readable, server-written. Part of the 8 KB combined metadata budget.","example":{"plan":"pro"}},"privateMetadata":{"type":"object","additionalProperties":true,"description":"Private metadata bag: server-only, never exposed to the SDK or in a JWT. Part of the 8 KB combined metadata budget.","example":{"billingCustomerId":"cus_123"}},"unsafeMetadata":{"type":"object","additionalProperties":true,"description":"Unsafe metadata bag: readable and writable by the end-user via the SDK. Part of the 8 KB combined metadata budget.","example":{"onboardingStep":2}}}},"UpdateOrganizationMetadataRequest":{"type":"object","properties":{"publicMetadata":{"type":"object","additionalProperties":true,"description":"Public metadata bag. An organization's bag is readable over the client API by any member; a MEMBERSHIP's bags are server-plane only and are never returned on a client-facing read. Capped at 8 KB on its own.","example":{"plan":"enterprise"}},"privateMetadata":{"type":"object","additionalProperties":true,"description":"Private metadata bag: server-only. Never exposed to the SDK, never in a JWT. Capped at 8 KB on its own.","example":{"crmAccountId":"acct_123"}}}},"ServerOrganizationResponse":{"type":"object","properties":{"id":{"type":"string","format":"uuid"},"name":{"type":"string"},"slug":{"type":["string","null"]},"roleSetId":{"type":["string","null"],"format":"uuid"},"publicMetadata":{"type":"object","additionalProperties":true},"privateMetadata":{"type":"object","additionalProperties":true},"createdAt":{"type":"string","format":"date-time"}},"required":["createdAt","id","name","privateMetadata","publicMetadata"]},"ServerOrganizationMemberResponse":{"type":"object","properties":{"organizationId":{"type":"string","format":"uuid"},"userId":{"type":"string","format":"uuid"},"role":{"type":"string"},"roleName":{"type":["string","null"]},"publicMetadata":{"type":"object","additionalProperties":true},"privateMetadata":{"type":"object","additionalProperties":true},"joinedAt":{"type":"string","format":"date-time"}},"required":["joinedAt","organizationId","privateMetadata","publicMetadata","role","userId"]},"UserSessionResponse":{"type":"object","description":"An active end-user session in your environment.","properties":{"id":{"type":"string","format":"uuid","description":"Unique identifier for this session.","example":"01931a74-1234-7000-8000-000000000000"},"userId":{"type":"string","format":"uuid","description":"Identifier of the end-user this session belongs to.","example":"01931a73-8b00-7000-8000-000000000000"},"environmentId":{"type":"string","format":"uuid","description":"Identifier of the environment this session belongs to.","example":"01931a72-0000-7000-8000-000000000000"},"userAgent":{"type":["string","null"],"description":"Raw User-Agent string captured when the session was created.","example":"Mozilla/5.0 (Macintosh; Intel Mac OS X 14_6_0) AppleWebKit/537.36"},"ipAddress":{"type":["string","null"],"description":"IP address captured when the session was created.","example":"203.0.113.42"},"createdAt":{"type":"string","format":"date-time","description":"When this session was created (ISO-8601 UTC).","example":"2026-05-16T09:30:00Z"},"expiresAt":{"type":"string","format":"date-time","description":"When this session expires (ISO-8601 UTC).","example":"2026-05-23T09:30:00Z"},"lastUsedAt":{"type":"string","format":"date-time","description":"When this session was last seen by the API (ISO-8601 UTC).","example":"2026-05-16T11:42:00Z"},"activeOrganizationId":{"type":["string","null"],"format":"uuid","description":"Active organization pinned to this session (the `o` claim on re-mint)."},"impersonatedBy":{"type":["string","null"],"format":"uuid","description":"Platform user behind this session when it was established via impersonation; null for normal sign-ins."}},"required":["createdAt","environmentId","expiresAt","id","lastUsedAt","userId"]},"CursorPageResponseServerUserOrganizationResponse":{"type":"object","description":"A single page of results in a cursor-paginated list. Pass `nextCursor` as the `cursor` query parameter to fetch the following page.","properties":{"items":{"type":"array","description":"Items in this page, in stable order.","items":{"$ref":"#/components/schemas/ServerUserOrganizationResponse"}},"nextCursor":{"type":["string","null"],"format":"uuid","description":"Cursor to pass to fetch the next page. Null when this is the last page.","example":"01931a73-8b00-7000-8000-000000000000"},"hasMore":{"type":"boolean","description":"True if more pages are available (equivalent to `nextCursor != null`).","example":true}},"required":["hasMore","items"]},"ServerUserOrganizationResponse":{"type":"object","properties":{"organizationId":{"type":"string","format":"uuid"},"name":{"type":"string","description":"The organization's display name."},"slug":{"type":["string","null"],"description":"The organization's slug, when it has one."},"role":{"type":"string","description":"This user's role key in the organization (e.g. org:administrator)."},"roleName":{"type":["string","null"],"description":"Display name of that role, from the organization's bound role set. Null when the organization has no bound set or the key is not in it."},"publicMetadata":{"type":"object","additionalProperties":true,"description":"The MEMBERSHIP's public metadata bag, not the organization's.","example":{"seat":"billable"}},"privateMetadata":{"type":"object","additionalProperties":true,"description":"The MEMBERSHIP's private metadata bag, not the organization's. Server-only, never exposed to the SDK.","example":{"crmContactId":"con_123"}},"joinedAt":{"type":"string","format":"date-time"}},"required":["joinedAt","name","organizationId","privateMetadata","publicMetadata","role"]},"CursorPageResponseServerOrganizationResponse":{"type":"object","description":"A single page of results in a cursor-paginated list. Pass `nextCursor` as the `cursor` query parameter to fetch the following page.","properties":{"items":{"type":"array","description":"Items in this page, in stable order.","items":{"$ref":"#/components/schemas/ServerOrganizationResponse"}},"nextCursor":{"type":["string","null"],"format":"uuid","description":"Cursor to pass to fetch the next page. Null when this is the last page.","example":"01931a73-8b00-7000-8000-000000000000"},"hasMore":{"type":"boolean","description":"True if more pages are available (equivalent to `nextCursor != null`).","example":true}},"required":["hasMore","items"]},"CursorPageResponseServerOrganizationMemberResponse":{"type":"object","description":"A single page of results in a cursor-paginated list. Pass `nextCursor` as the `cursor` query parameter to fetch the following page.","properties":{"items":{"type":"array","description":"Items in this page, in stable order.","items":{"$ref":"#/components/schemas/ServerOrganizationMemberResponse"}},"nextCursor":{"type":["string","null"],"format":"uuid","description":"Cursor to pass to fetch the next page. Null when this is the last page.","example":"01931a73-8b00-7000-8000-000000000000"},"hasMore":{"type":"boolean","description":"True if more pages are available (equivalent to `nextCursor != null`).","example":true}},"required":["hasMore","items"]},"CursorPageResponseEnvironmentInvitationResponse":{"type":"object","description":"A single page of results in a cursor-paginated list. Pass `nextCursor` as the `cursor` query parameter to fetch the following page.","properties":{"items":{"type":"array","description":"Items in this page, in stable order.","items":{"$ref":"#/components/schemas/EnvironmentInvitationResponse"}},"nextCursor":{"type":["string","null"],"format":"uuid","description":"Cursor to pass to fetch the next page. Null when this is the last page.","example":"01931a73-8b00-7000-8000-000000000000"},"hasMore":{"type":"boolean","description":"True if more pages are available (equivalent to `nextCursor != null`).","example":true}},"required":["hasMore","items"]}},"securitySchemes":{"bearerAuth":{"type":"http","description":"Backend secret key (`sk_live_*` / `sk_test_*`) sent as `Authorization: Bearer <key>`.","scheme":"bearer"}}}}
1
+ {"openapi":"3.1.0","info":{"title":"Torii Backend API","description":"Server-to-server API (BAPI) for backend SDKs. Authenticated with a secret key (Bearer sk_live_* / sk_test_*).","version":"v1"},"servers":[{"url":"https://api.toriiauth.eu","description":"Production backend API"}],"security":[{"bearerAuth":[]}],"tags":[{"name":"Allowed Origins","description":"Escape-hatch origins for non-web stacks (secret key auth)"},{"name":"Server Impersonation","description":"Secret-key impersonation token minting"},{"name":"Invitations","description":"Invite end-users into the environment (secret key auth)"},{"name":"Server Users","description":"Server user management endpoints (secret key auth)"},{"name":"Server Sessions","description":"Server session management endpoints (secret key auth)"},{"name":"Server Organizations","description":"Server organization + membership metadata endpoints (secret key auth)"}],"paths":{"/api/server/v1/allowed-origins":{"get":{"tags":["Allowed Origins"],"summary":"List escape-hatch origins for this environment","operationId":"list","responses":{"200":{"description":"OK","content":{"application/json":{"schema":{"$ref":"#/components/schemas/AllowedOriginsResponse"}}}}}},"put":{"tags":["Allowed Origins"],"summary":"Replace the escape-hatch origins for this environment","description":"Full origins incl. non-http schemes (e.g. capacitor://localhost). Replaces the list.","operationId":"set","requestBody":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/SetAllowedOriginsRequest"}}},"required":true},"responses":{"200":{"description":"OK","content":{"application/json":{"schema":{"$ref":"#/components/schemas/AllowedOriginsResponse"}}}}}}},"/api/server/v1/users":{"post":{"tags":["Server Users"],"summary":"Create user","description":"Creates an end-user in your environment. All body fields are optional; supply at minimum an email if you want the user to be able to sign in via email + password.","operationId":"createUser","requestBody":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/CreateUserRequest"}}},"required":true},"responses":{"201":{"description":"The created user.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ServerUserResponse"}}}},"400":{"description":"Invalid body (e.g. weak password, malformed email).","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/ProblemDetail"}}}},"401":{"description":"Missing or invalid secret key.","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/ProblemDetail"}}}},"409":{"description":"Another user with this email already exists in the environment.","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/ProblemDetail"}}}}}}},"/api/server/v1/users/{userId}/unban":{"post":{"tags":["Server Users"],"summary":"Unban user","description":"Reverses a previous ban. The user can sign in again on next request.","operationId":"unbanUser","parameters":[{"name":"userId","in":"path","description":"Identifier of the user to unban.","required":true,"schema":{"type":"string","format":"uuid"},"example":"01931a73-8b00-7000-8000-000000000000"}],"responses":{"200":{"description":"The (now active) user.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ServerUserResponse"}}}},"401":{"description":"Missing or invalid secret key.","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/ProblemDetail"}}}},"403":{"description":"User belongs to a different environment.","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/ProblemDetail"}}}},"404":{"description":"No user with this id.","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/ProblemDetail"}}}}}}},"/api/server/v1/users/{userId}/impersonation-token":{"post":{"tags":["Server Impersonation"],"summary":"Mint an impersonation token","description":"Creates a single-use, short-lived impersonation token for the target user, attributed to `actorUserId`. Redeem it programmatically via `POST /_torii/auth/session/impersonate` (access token in the body), or hand the returned `url` to an operator to open in a browser (establishes the session and redirects to the landing URL). Counts against the same per-period impersonation quota and usage ledger as the dashboard.","operationId":"mintImpersonationToken","parameters":[{"name":"userId","in":"path","description":"The user to impersonate.","required":true,"schema":{"type":"string","format":"uuid"},"example":"01931a73-8b00-7000-8000-000000000000"}],"requestBody":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ServerImpersonationTokenRequest"}}},"required":true},"responses":{"200":{"description":"The minted token, its lifetime, and (when a landing URL resolves) a ready-to-use redeem URL.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ServerImpersonationTokenResponse"}}}},"400":{"description":"Deleted target, `expiresInSeconds` out of the 60..600 range, or `redirectUrl` malformed / not in the environment's allowed origins.","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/ProblemDetail"}}}},"401":{"description":"Missing or invalid secret key.","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/ProblemDetail"}}}},"402":{"description":"Plan does not include impersonation, or the per-period quota is exhausted.","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/ProblemDetail"}}}},"403":{"description":"Target or actor is in another environment, or impersonation is disabled for this environment.","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/ProblemDetail"}}}}}}},"/api/server/v1/users/{userId}/ban":{"post":{"tags":["Server Users"],"summary":"Ban user","description":"Marks the user as banned and revokes all their active sessions.","operationId":"banUser","parameters":[{"name":"userId","in":"path","description":"Identifier of the user to ban.","required":true,"schema":{"type":"string","format":"uuid"},"example":"01931a73-8b00-7000-8000-000000000000"}],"responses":{"200":{"description":"The (now banned) user.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ServerUserResponse"}}}},"401":{"description":"Missing or invalid secret key.","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/ProblemDetail"}}}},"403":{"description":"User belongs to a different environment.","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/ProblemDetail"}}}},"404":{"description":"No user with this id.","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/ProblemDetail"}}}}}}},"/api/server/v1/users/search":{"post":{"tags":["Server Users"],"summary":"Search users","description":"Returns a cursor-paginated page of end-users in the environment matching the optional filters. Uses POST so the filter body can be sent without URL-encoding. Three id-selectors resolve users to a set of ids (`userIds`, the explicit batch-by-id lookup; `emailAddresses`, exact and case-insensitive; `email`, a case-insensitive substring); when more than one is supplied they are combined with AND (intersection). The remaining filters (`name`, `statuses`, `createdAfter`/`createdBefore`) apply on top.","operationId":"searchUsers","parameters":[{"name":"limit","in":"query","description":"Maximum number of items in the returned page (default 20).","required":false,"schema":{"type":"integer","format":"int32","default":20},"example":50},{"name":"cursor","in":"query","description":"Opaque cursor returned by the previous page's `nextCursor`. Omit to fetch the first page.","required":false,"schema":{"type":"string","format":"uuid"},"example":"01931a73-8b00-7000-8000-000000000000"}],"requestBody":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ServerUserSearchRequest"}}}},"responses":{"200":{"description":"Page of matching users.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/CursorPageResponseServerUserResponse"}}}},"400":{"description":"An id-selector list exceeds 100 entries.","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/ProblemDetail"}}}},"401":{"description":"Missing or invalid secret key.","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/ProblemDetail"}}}}}}},"/api/server/v1/invitations":{"get":{"tags":["Invitations"],"summary":"List invitations for this environment","operationId":"list_1","parameters":[{"name":"status","in":"query","required":false,"schema":{"type":"array","items":{"type":"string"}}},{"name":"search","in":"query","required":false,"schema":{"type":"string"}},{"name":"limit","in":"query","required":false,"schema":{"type":"integer","format":"int32","default":20}},{"name":"cursor","in":"query","required":false,"schema":{"type":"string","format":"uuid"}}],"responses":{"200":{"description":"OK","content":{"application/json":{"schema":{"$ref":"#/components/schemas/CursorPageResponseEnvironmentInvitationResponse"}}}}}},"post":{"tags":["Invitations"],"summary":"Create an invitation with optional pre-seeded metadata","operationId":"create","requestBody":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/CreateEnvironmentInvitationServerRequest"}}},"required":true},"responses":{"201":{"description":"The created invitation. The email has been sent.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/EnvironmentInvitationResponse"}}}},"400":{"description":"Invalid body, metadata over the 8KB budget, or the environment has no sign-up URL configured.","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/ProblemDetail"}}}},"401":{"description":"Missing or invalid secret key.","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/ProblemDetail"}}}},"409":{"description":"This email already has an account in the environment.","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/ProblemDetail"}}}},"429":{"description":"The environment's invitation rate limit is exhausted.","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/ProblemDetail"}}}}}}},"/api/server/v1/invitations/{invitationId}/resend":{"post":{"tags":["Invitations"],"summary":"Resend a pending invitation with a fresh link","operationId":"resend","parameters":[{"name":"invitationId","in":"path","required":true,"schema":{"type":"string","format":"uuid"}}],"responses":{"200":{"description":"OK","content":{"application/json":{"schema":{"$ref":"#/components/schemas/EnvironmentInvitationResponse"}}}}}}},"/api/server/v1/users/{userId}":{"get":{"tags":["Server Users"],"summary":"Get user","description":"Returns the full profile for one end-user.","operationId":"getUser","parameters":[{"name":"userId","in":"path","description":"Identifier of the user to fetch.","required":true,"schema":{"type":"string","format":"uuid"},"example":"01931a73-8b00-7000-8000-000000000000"}],"responses":{"200":{"description":"The user.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ServerUserResponse"}}}},"401":{"description":"Missing or invalid secret key.","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/ProblemDetail"}}}},"403":{"description":"User belongs to a different environment.","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/ProblemDetail"}}}},"404":{"description":"No user with this id.","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/ProblemDetail"}}}}}},"delete":{"tags":["Server Users"],"summary":"Delete user","description":"Soft-deletes the user. Not idempotent at the HTTP layer: the authorization grant for the user is revoked on the first successful delete, so a subsequent DELETE for the same id returns 403 rather than 204. Treat 403 from a retry as a confirmation that the user is already deleted.","operationId":"deleteUser","parameters":[{"name":"userId","in":"path","description":"Identifier of the user to delete.","required":true,"schema":{"type":"string","format":"uuid"},"example":"01931a73-8b00-7000-8000-000000000000"}],"responses":{"204":{"description":"User deleted."},"401":{"description":"Missing or invalid secret key.","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/ProblemDetail"}}}},"403":{"description":"User belongs to a different environment.","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/ProblemDetail"}}}},"404":{"description":"No user with this id.","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/ProblemDetail"}}}}}},"patch":{"tags":["Server Users"],"summary":"Update user","description":"Partial update with tri-state PATCH semantics. Every field in `UpdateUserRequest` is tri-state: omit the key to leave the field unchanged, send a non-null value to set it, or send JSON null to clear it.","operationId":"updateUser","parameters":[{"name":"userId","in":"path","description":"Identifier of the user to update.","required":true,"schema":{"type":"string","format":"uuid"},"example":"01931a73-8b00-7000-8000-000000000000"}],"requestBody":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/UpdateUserRequest"}}},"required":true},"responses":{"200":{"description":"The updated user.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ServerUserResponse"}}}},"400":{"description":"Invalid body.","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/ProblemDetail"}}}},"401":{"description":"Missing or invalid secret key.","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/ProblemDetail"}}}},"403":{"description":"User belongs to a different environment.","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/ProblemDetail"}}}},"404":{"description":"No user with this id.","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/ProblemDetail"}}}}}}},"/api/server/v1/users/{userId}/metadata":{"patch":{"tags":["Server Users"],"summary":"Update user metadata","description":"Deep-merges into any of the three metadata bags. Each bag is tri-state: omit the key to leave the bag unchanged, or send an object to deep-merge into the existing bag (a key set to null removes it). The merged metadata is capped at 8 KB total across `publicMetadata`, `privateMetadata`, and `unsafeMetadata` combined (no per-bag limit).","operationId":"updateUserMetadata","parameters":[{"name":"userId","in":"path","description":"Identifier of the user to update.","required":true,"schema":{"type":"string","format":"uuid"},"example":"01931a73-8b00-7000-8000-000000000000"}],"requestBody":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/UpdateUserMetadataRequest"}}},"required":true},"responses":{"200":{"description":"The updated user.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ServerUserResponse"}}}},"400":{"description":"A bag exceeds its size limit.","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/ProblemDetail"}}}},"401":{"description":"Missing or invalid secret key.","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/ProblemDetail"}}}},"403":{"description":"User belongs to a different environment.","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/ProblemDetail"}}}},"404":{"description":"No user with this id.","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/ProblemDetail"}}}}}}},"/api/server/v1/organizations/{organizationId}/metadata":{"patch":{"tags":["Server Organizations"],"summary":"Update organization metadata","description":"Deep-merges into either metadata bag. Each bag is tri-state: omit the key to leave the bag unchanged, or send an object to deep-merge into it (a key set to null removes it). Each bag is capped at 8 KB on its own, measured on the merged result rather than on the patch you send. A request naming neither bag is a 400.","operationId":"updateOrganizationMetadata","parameters":[{"name":"organizationId","in":"path","required":true,"schema":{"type":"string","format":"uuid"}}],"requestBody":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/UpdateOrganizationMetadataRequest"}}},"required":true},"responses":{"200":{"description":"The updated organization.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ServerOrganizationResponse"}}}},"400":{"description":"The merged metadata exceeds the size limit.","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/ProblemDetail"}}}},"401":{"description":"Missing or invalid secret key.","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/ProblemDetail"}}}},"404":{"description":"No organization with this id in the key's environment.","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/ProblemDetail"}}}}}}},"/api/server/v1/organizations/{organizationId}/members/{memberUserId}/metadata":{"patch":{"tags":["Server Organizations"],"summary":"Update organization membership metadata","description":"Deep-merges into either bag on one membership, with the same tri-state contract as the organization endpoint. Each bag on the membership has its own 8 KB budget, separate from the organization's bags.","operationId":"updateMemberMetadata","parameters":[{"name":"organizationId","in":"path","required":true,"schema":{"type":"string","format":"uuid"}},{"name":"memberUserId","in":"path","required":true,"schema":{"type":"string","format":"uuid"}}],"requestBody":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/UpdateOrganizationMetadataRequest"}}},"required":true},"responses":{"200":{"description":"The updated membership.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ServerOrganizationMemberResponse"}}}},"400":{"description":"The merged metadata exceeds the size limit.","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/ProblemDetail"}}}},"401":{"description":"Missing or invalid secret key.","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/ProblemDetail"}}}},"404":{"description":"No such organization in the key's environment, or the user is not a member of it.","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/ProblemDetail"}}}}}}},"/api/server/v1/invitations/{invitationId}":{"get":{"tags":["Invitations"],"summary":"Get an invitation by id, including both metadata bags","operationId":"get","parameters":[{"name":"invitationId","in":"path","required":true,"schema":{"type":"string","format":"uuid"}}],"responses":{"200":{"description":"OK","content":{"application/json":{"schema":{"$ref":"#/components/schemas/EnvironmentInvitationDetailResponse"}}}}}},"delete":{"tags":["Invitations"],"summary":"Revoke a pending invitation","operationId":"revoke","parameters":[{"name":"invitationId","in":"path","required":true,"schema":{"type":"string","format":"uuid"}}],"responses":{"200":{"description":"OK"}}},"patch":{"tags":["Invitations"],"summary":"Deep-merge metadata into a pending invitation","operationId":"updateMetadata","parameters":[{"name":"invitationId","in":"path","required":true,"schema":{"type":"string","format":"uuid"}}],"requestBody":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/UpdateEnvironmentInvitationMetadataRequest"}}},"required":true},"responses":{"200":{"description":"The updated invitation.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/EnvironmentInvitationDetailResponse"}}}},"400":{"description":"Merged metadata over the 8KB budget, or a body naming neither bag.","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/ProblemDetail"}}}},"401":{"description":"Missing or invalid secret key.","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/ProblemDetail"}}}},"404":{"description":"No such invitation in this environment.","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/ProblemDetail"}}}},"409":{"description":"The invitation is accepted, revoked or expired (`invitation_not_pending`, with the state on `invitationStatus`), or its state could not be resolved consistently (`invitation_patch_conflict`, a server-side fault — do not retry in a loop).","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/ProblemDetail"}}}}}}},"/api/server/v1/users/{userId}/sessions":{"get":{"tags":["Server Sessions"],"summary":"List user sessions","description":"Returns all active (unexpired, unrevoked) sessions for the user, ordered by most recently used.","operationId":"listSessions","parameters":[{"name":"userId","in":"path","description":"Identifier of the user whose sessions to list.","required":true,"schema":{"type":"string","format":"uuid"},"example":"01931a73-8b00-7000-8000-000000000000"}],"responses":{"200":{"description":"All active sessions for the user.","content":{"application/json":{"schema":{"type":"array","items":{"$ref":"#/components/schemas/UserSessionResponse"}}}}},"401":{"description":"Missing or invalid secret key.","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/ProblemDetail"}}}},"403":{"description":"User belongs to a different environment.","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/ProblemDetail"}}}}}},"delete":{"tags":["Server Sessions"],"summary":"Revoke all sessions","description":"Immediately revokes every active session for the user. Idempotent.","operationId":"revokeAllSessions","parameters":[{"name":"userId","in":"path","description":"Identifier of the user whose sessions to revoke.","required":true,"schema":{"type":"string","format":"uuid"},"example":"01931a73-8b00-7000-8000-000000000000"}],"responses":{"204":{"description":"Sessions revoked."},"401":{"description":"Missing or invalid secret key.","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/ProblemDetail"}}}},"403":{"description":"User belongs to a different environment.","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/ProblemDetail"}}}}}}},"/api/server/v1/users/{userId}/organizations":{"get":{"tags":["Server Users"],"summary":"List a user's organizations","description":"Returns a cursor-paginated page of the organizations this user is a member of, with the user's role in each and that membership's metadata bags. The mirror image of listing an organization's members. Note the bags are the MEMBERSHIP's, not the organization's: read the organization itself for those.","operationId":"listUserOrganizations","parameters":[{"name":"userId","in":"path","description":"Identifier of the user whose organizations to list.","required":true,"schema":{"type":"string","format":"uuid"},"example":"01931a73-8b00-7000-8000-000000000000"},{"name":"limit","in":"query","description":"Maximum number of items in the returned page (default 20).","required":false,"schema":{"type":"integer","format":"int32","default":20},"example":50},{"name":"cursor","in":"query","description":"Opaque cursor returned by the previous page's `nextCursor`. Omit to fetch the first page.","required":false,"schema":{"type":"string","format":"uuid"},"example":"01931a73-8b00-7000-8000-000000000000"}],"responses":{"200":{"description":"Page of memberships (empty when the user belongs to no organization).","content":{"application/json":{"schema":{"$ref":"#/components/schemas/CursorPageResponseServerUserOrganizationResponse"}}}},"401":{"description":"Missing or invalid secret key.","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/ProblemDetail"}}}},"403":{"description":"The user belongs to a different environment, or no user has this id: the two are deliberately indistinguishable so a key cannot probe for foreign user ids.","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/ProblemDetail"}}}}}}},"/api/server/v1/organizations":{"get":{"tags":["Server Organizations"],"summary":"List organizations","description":"Cursor-paginated page of the environment's organizations, with both metadata bags. Optional `name` filter is a case-insensitive substring match.","operationId":"listOrganizations","parameters":[{"name":"name","in":"query","description":"Case-insensitive substring filter on the organization name.","required":false,"schema":{"type":"string"},"example":"acme"},{"name":"limit","in":"query","description":"Maximum number of items in the returned page (default 20; values outside 1-100 are clamped).","required":false,"schema":{"type":"integer","format":"int32","default":20},"example":50},{"name":"cursor","in":"query","description":"Opaque cursor returned by the previous page's `nextCursor`. Omit to fetch the first page.","required":false,"schema":{"type":"string","format":"uuid"},"example":"01931a73-8b00-7000-8000-000000000000"}],"responses":{"200":{"description":"Page of organizations.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/CursorPageResponseServerOrganizationResponse"}}}},"401":{"description":"Missing or invalid secret key.","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/ProblemDetail"}}}}}}},"/api/server/v1/organizations/{organizationId}":{"get":{"tags":["Server Organizations"],"summary":"Get an organization","description":"One organization with both metadata bags.","operationId":"getOrganization","parameters":[{"name":"organizationId","in":"path","required":true,"schema":{"type":"string","format":"uuid"}}],"responses":{"200":{"description":"The organization.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ServerOrganizationResponse"}}}},"401":{"description":"Missing or invalid secret key.","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/ProblemDetail"}}}},"404":{"description":"No organization with this id in the key's environment.","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/ProblemDetail"}}}}}}},"/api/server/v1/organizations/{organizationId}/members":{"get":{"tags":["Server Organizations"],"summary":"List organization members","description":"Cursor-paginated page of the organization's USER memberships, each with both metadata bags. Ordered by member user id ascending (a creation-ordered uuid v7, which is also the seek key), NOT by join time.","operationId":"listMembers","parameters":[{"name":"organizationId","in":"path","required":true,"schema":{"type":"string","format":"uuid"}},{"name":"limit","in":"query","description":"Maximum number of items in the returned page (default 20; values outside 1-100 are clamped).","required":false,"schema":{"type":"integer","format":"int32","default":20},"example":50},{"name":"cursor","in":"query","description":"Opaque cursor returned by the previous page's `nextCursor`. Omit to fetch the first page.","required":false,"schema":{"type":"string","format":"uuid"},"example":"01931a73-8b00-7000-8000-000000000000"}],"responses":{"200":{"description":"Page of the organization's members.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/CursorPageResponseServerOrganizationMemberResponse"}}}},"401":{"description":"Missing or invalid secret key.","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/ProblemDetail"}}}},"404":{"description":"No organization with this id in the key's environment.","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/ProblemDetail"}}}}}}},"/api/server/v1/users/{userId}/sessions/{sessionId}":{"delete":{"tags":["Server Sessions"],"summary":"Revoke specific session","description":"Revokes a single session by id. Idempotent: returns 204 even if the session was already revoked or expired.","operationId":"revokeSession","parameters":[{"name":"userId","in":"path","description":"Identifier of the user who owns the session.","required":true,"schema":{"type":"string","format":"uuid"},"example":"01931a73-8b00-7000-8000-000000000000"},{"name":"sessionId","in":"path","description":"Identifier of the session to revoke.","required":true,"schema":{"type":"string","format":"uuid"},"example":"01931a74-1234-7000-8000-000000000000"}],"responses":{"204":{"description":"Session revoked."},"401":{"description":"Missing or invalid secret key.","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/ProblemDetail"}}}},"403":{"description":"User or session belongs to a different environment.","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/ProblemDetail"}}}}}}}},"components":{"schemas":{"SetAllowedOriginsRequest":{"type":"object","properties":{"origins":{"type":"array","items":{"type":"string"}}},"required":["origins"]},"AllowedOriginsResponse":{"type":"object","properties":{"origins":{"type":"array","items":{"type":"string"}}},"required":["origins"]},"CreateUserRequest":{"type":"object","description":"Request body for creating an end-user in your environment. All fields are optional; supply at minimum an email if you want the user to be able to sign in via email + password.","properties":{"email":{"type":["string","null"],"description":"Primary email for the new user. If omitted, the user is created without a sign-in identity.","example":"ada@example.com"},"password":{"type":["string","null"],"description":"Initial password. Subject to the environment's password policy. Omit to create a passwordless user (e.g. social-only).","example":"correct horse battery staple"},"firstName":{"type":["string","null"],"description":"First (given) name to seed on the profile.","example":"Ada"},"lastName":{"type":["string","null"],"description":"Last (family) name to seed on the profile.","example":"Lovelace"},"publicMetadata":{"type":"object","additionalProperties":true,"description":"Initial public metadata (SDK-readable, server-written). Part of the 8 KB combined metadata budget.","example":{"plan":"free"}},"privateMetadata":{"type":"object","additionalProperties":true,"description":"Initial private metadata (server-only). Part of the 8 KB combined metadata budget.","example":{"billingCustomerId":"cus_123"}},"unsafeMetadata":{"type":"object","additionalProperties":true,"description":"Initial unsafe metadata (end-user writable). Part of the 8 KB combined metadata budget.","example":{"onboardingStep":0}}}},"ProblemDetail":{"type":"object","properties":{"type":{"type":"string","format":"uri"},"title":{"type":"string"},"status":{"type":"integer","format":"int32"},"detail":{"type":"string"},"instance":{"type":"string","format":"uri"},"properties":{"type":"object","additionalProperties":{}}}},"ServerUserResponse":{"type":"object","description":"An end-user, including server-only private metadata. Returned only on the secret-key backend API.","properties":{"id":{"type":"string","format":"uuid","description":"Unique identifier for this user.","example":"01931a73-8b00-7000-8000-000000000000"},"environmentId":{"type":"string","format":"uuid","description":"Identifier of the environment this user belongs to.","example":"01931a72-0000-7000-8000-000000000000"},"name":{"type":["string","null"],"description":"Full name on the profile, if any.","example":"Ada Lovelace"},"firstName":{"type":["string","null"],"description":"First (given) name on the profile, if any.","example":"Ada"},"lastName":{"type":["string","null"],"description":"Last (family) name on the profile, if any.","example":"Lovelace"},"locale":{"type":["string","null"],"description":"Preferred locale for emails and UI messages.","enum":["en","da"]},"status":{"type":"string","description":"Lifecycle status of the user (e.g. active, banned).","enum":["active","banned","deleted"]},"createdAt":{"type":"string","format":"date-time","description":"When this user was created (ISO-8601 UTC).","example":"2026-05-16T09:30:00Z"},"updatedAt":{"type":"string","format":"date-time","description":"When this user was last modified (ISO-8601 UTC).","example":"2026-05-16T10:00:00Z"},"email":{"type":["string","null"],"description":"Primary email on the profile, if any.","example":"ada@example.com"},"emailVerifiedAt":{"type":["string","null"],"format":"date-time","description":"When this user's primary email was verified, if it has been verified.","example":"2026-05-16T09:35:00Z"},"deletedAt":{"type":["string","null"],"format":"date-time","description":"When this user was deleted, if soft-deleted. Null for active users.","example":"2026-05-20T12:00:00Z"},"publicMetadata":{"type":"object","additionalProperties":true,"description":"Public metadata: readable by the SDK, writable only server-side.","example":{"plan":"pro"}},"privateMetadata":{"type":"object","additionalProperties":true,"description":"Private metadata: server-only. Never exposed to the SDK or in a JWT.","example":{"billingCustomerId":"cus_123"}},"unsafeMetadata":{"type":"object","additionalProperties":true,"description":"Unsafe metadata: readable and writable by the end-user via the SDK.","example":{"onboardingStep":2}}},"required":["createdAt","environmentId","id","privateMetadata","publicMetadata","status","unsafeMetadata","updatedAt"]},"ServerImpersonationTokenRequest":{"type":"object","description":"Body for minting an impersonation token.","properties":{"actorUserId":{"type":"string","format":"uuid","description":"The principal the impersonation is on behalf of (recorded for accountability). Must be a user in this environment.","example":"01931a73-8b00-7000-8000-000000000000"},"reason":{"type":"string","description":"Mandatory justification (GDPR purpose limitation); recorded in the audit log on mint and redeem.","example":"Investigating support ticket #4821","maxLength":500,"minLength":0},"redirectUrl":{"type":["string","null"],"description":"Optional post-redeem landing URL for the `url` redeem link; its origin must be in the environment's allowed origins. Unlike the dashboard link this plane appends nothing to it, so a fragment is fine. Omit to use the environment's configured impersonation landing URL.","example":"https://app.example.com/dashboard"},"expiresInSeconds":{"type":["integer","null"],"format":"int64","description":"Optional token lifetime in seconds, 60..600. Omit for the 600s default.","example":600,"maximum":600,"minimum":60}},"required":["actorUserId","reason"]},"ServerImpersonationTokenResponse":{"type":"object","description":"A minted impersonation token.","properties":{"token":{"type":"string","description":"The single-use token. Redeem via POST /_torii/auth/session/impersonate, or hand the ready-to-use `url` to an operator."},"expiresInSeconds":{"type":"integer","format":"int64","description":"The token's lifetime in seconds (the resolved value after any override).","example":600},"url":{"type":["string","null"],"description":"A ready-to-use, navigable redeem link on the environment's Frontend API host. Opening it in a browser establishes the impersonated session and redirects to the landing URL. Backed by the same single-use token. Null when no landing URL could be resolved: no `redirectUrl` given and the environment has no impersonation landing URL configured — redeem the `token` via POST instead.","example":"https://auth.example.com/_torii/auth/session/impersonate?token=…"}},"required":["expiresInSeconds","token"]},"ServerUserSearchRequest":{"type":"object","description":"Optional filter body for `POST /users/search`. Every field is tri-state: omit to skip that filter, send a value to apply it. The three id-selectors (`userIds`, `emailAddresses`, `email`) resolve users to a set of ids and, when more than one is supplied, are combined with AND (intersection); a supplied id-selector whose resolved set is empty returns an empty page. `name` additionally accepts JSON null to match users with no name; an explicit null or blank `email` contributes no restriction; the non-nullable `statuses` field rejects null.","properties":{"name":{"type":["string","null"],"description":"Filter by name (case-insensitive substring match). Send null to require users with no name.","example":"Ada"},"userIds":{"type":"array","description":"Restrict to these user ids (the explicit batch-by-id lookup), at most 100. AND-combined with the other id-selectors; an empty list returns an empty page.","example":["01931a73-8b00-7000-8000-000000000000"],"items":{"type":"string","format":"uuid"}},"emailAddresses":{"type":"array","description":"Resolve users by exact (case-insensitive) email address (one or more, at most 100). Unlike `email`, never matches a superstring. AND-combined with the other id-selectors; an empty list, or addresses matching nobody, returns an empty page.","example":["ada@example.com"],"items":{"type":"string"}},"email":{"type":["string","null"],"description":"Filter by primary email (case-insensitive substring match). AND-combined with the other id-selectors. An explicit null or blank value contributes no restriction.","example":"@example.com"},"statuses":{"type":"array","description":"Filter by user status. Returns users matching any of the supplied statuses.","items":{"type":"string","enum":["active","banned","deleted"]},"uniqueItems":true},"createdAfter":{"type":["string","null"],"format":"date-time","description":"Only return users created at or after this instant (ISO-8601 UTC).","example":"2026-01-01T00:00:00Z"},"createdBefore":{"type":["string","null"],"format":"date-time","description":"Only return users created at or before this instant (ISO-8601 UTC).","example":"2026-12-31T23:59:59Z"},"organizationId":{"type":["string","null"],"format":"uuid","description":"Only return members of this organization. An organization from another environment matches nobody. Not an id-selector: it is applied as a membership semi-join, so it is never capped and always ANDs with the rest of the filters.","example":"01931a73-8b00-7000-8000-000000000000"}}},"CursorPageResponseServerUserResponse":{"type":"object","description":"A single page of results in a cursor-paginated list. Pass `nextCursor` as the `cursor` query parameter to fetch the following page.","properties":{"items":{"type":"array","description":"Items in this page, in stable order.","items":{"$ref":"#/components/schemas/ServerUserResponse"}},"nextCursor":{"type":["string","null"],"format":"uuid","description":"Cursor to pass to fetch the next page. Null when this is the last page.","example":"01931a73-8b00-7000-8000-000000000000"},"hasMore":{"type":"boolean","description":"True if more pages are available (equivalent to `nextCursor != null`).","example":true}},"required":["hasMore","items"]},"CreateEnvironmentInvitationServerRequest":{"type":"object","properties":{"email":{"type":"string"},"expiresInDays":{"type":["integer","null"],"format":"int32"},"redirectUrl":{"type":["string","null"]},"publicMetadata":{"type":"object","additionalProperties":true},"privateMetadata":{"type":"object","additionalProperties":true}},"required":["email","privateMetadata","publicMetadata"]},"EnvironmentInvitationResponse":{"type":"object","properties":{"id":{"type":"string","format":"uuid"},"environmentId":{"type":"string","format":"uuid"},"email":{"type":"string"},"status":{"type":"string","enum":["PENDING","ACCEPTED","REVOKED","EXPIRED"]},"expiresAt":{"type":"string","format":"date-time"},"createdAt":{"type":"string","format":"date-time"},"acceptedAt":{"type":["string","null"],"format":"date-time"},"revokedAt":{"type":["string","null"],"format":"date-time"}},"required":["createdAt","email","environmentId","expiresAt","id","status"]},"UpdateUserRequest":{"type":"object","description":"PATCH body for updating an end-user. Every field is tri-state: omit the key entirely to leave the field unchanged, send a non-null value to set it, or send JSON null to clear it.","properties":{"firstName":{"type":["string","null"],"description":"New first (given) name. Send null to clear; omit to leave unchanged.","example":"Ada"},"lastName":{"type":["string","null"],"description":"New last (family) name. Send null to clear; omit to leave unchanged.","example":"Lovelace"},"locale":{"type":["string","null"],"description":"New preferred locale. Send null to clear; omit to leave unchanged.","enum":["en","da"]},"unsafeMetadata":{"type":"object","additionalProperties":true,"description":"Deep-merges into the user's unsafe metadata (a key set to null removes it); omit to leave unchanged. Counts toward the 8 KB combined metadata budget.","example":{"onboardingStep":2}}}},"UpdateUserMetadataRequest":{"type":"object","description":"PATCH body for a user's metadata bags. Each bag is tri-state: omit to leave it unchanged, or send an object value. Whether the object merges into or replaces the bag depends on the endpoint (see its operation description).","properties":{"publicMetadata":{"type":"object","additionalProperties":true,"description":"Public metadata bag: SDK-readable, server-written. Part of the 8 KB combined metadata budget.","example":{"plan":"pro"}},"privateMetadata":{"type":"object","additionalProperties":true,"description":"Private metadata bag: server-only, never exposed to the SDK or in a JWT. Part of the 8 KB combined metadata budget.","example":{"billingCustomerId":"cus_123"}},"unsafeMetadata":{"type":"object","additionalProperties":true,"description":"Unsafe metadata bag: readable and writable by the end-user via the SDK. Part of the 8 KB combined metadata budget.","example":{"onboardingStep":2}}}},"UpdateOrganizationMetadataRequest":{"type":"object","properties":{"publicMetadata":{"type":"object","additionalProperties":true,"description":"Public metadata bag. An organization's bag is readable over the client API by any member; a MEMBERSHIP's bags are server-plane only and are never returned on a client-facing read. Capped at 8 KB on its own.","example":{"plan":"enterprise"}},"privateMetadata":{"type":"object","additionalProperties":true,"description":"Private metadata bag: server-only. Never exposed to the SDK, never in a JWT. Capped at 8 KB on its own.","example":{"crmAccountId":"acct_123"}}}},"ServerOrganizationResponse":{"type":"object","properties":{"id":{"type":"string","format":"uuid"},"name":{"type":"string"},"slug":{"type":["string","null"]},"roleSetId":{"type":["string","null"],"format":"uuid"},"publicMetadata":{"type":"object","additionalProperties":true},"privateMetadata":{"type":"object","additionalProperties":true},"createdAt":{"type":"string","format":"date-time"}},"required":["createdAt","id","name","privateMetadata","publicMetadata"]},"ServerOrganizationMemberResponse":{"type":"object","properties":{"organizationId":{"type":"string","format":"uuid"},"userId":{"type":"string","format":"uuid"},"role":{"type":"string"},"roleName":{"type":["string","null"]},"publicMetadata":{"type":"object","additionalProperties":true},"privateMetadata":{"type":"object","additionalProperties":true},"joinedAt":{"type":"string","format":"date-time"}},"required":["joinedAt","organizationId","privateMetadata","publicMetadata","role","userId"]},"UpdateEnvironmentInvitationMetadataRequest":{"type":"object","properties":{"publicMetadata":{"type":"object","additionalProperties":true,"description":"Deep-merged into the invitation's public metadata. A key set to null is removed.","example":{"tenantId":"acme"}},"privateMetadata":{"type":"object","additionalProperties":true,"description":"Deep-merged into the invitation's private metadata. A key set to null is removed.","example":{"internalRef":"CRM-42"}}}},"EnvironmentInvitationDetailResponse":{"type":"object","properties":{"id":{"type":"string","format":"uuid"},"environmentId":{"type":"string","format":"uuid"},"email":{"type":"string"},"status":{"type":"string","enum":["PENDING","ACCEPTED","REVOKED","EXPIRED"]},"expiresAt":{"type":"string","format":"date-time"},"createdAt":{"type":"string","format":"date-time"},"acceptedAt":{"type":["string","null"],"format":"date-time"},"revokedAt":{"type":["string","null"],"format":"date-time"},"publicMetadata":{"type":"object","additionalProperties":true},"privateMetadata":{"type":"object","additionalProperties":true}},"required":["createdAt","email","environmentId","expiresAt","id","privateMetadata","publicMetadata","status"]},"UserSessionResponse":{"type":"object","description":"An active end-user session in your environment.","properties":{"id":{"type":"string","format":"uuid","description":"Unique identifier for this session.","example":"01931a74-1234-7000-8000-000000000000"},"userId":{"type":"string","format":"uuid","description":"Identifier of the end-user this session belongs to.","example":"01931a73-8b00-7000-8000-000000000000"},"environmentId":{"type":"string","format":"uuid","description":"Identifier of the environment this session belongs to.","example":"01931a72-0000-7000-8000-000000000000"},"userAgent":{"type":["string","null"],"description":"Raw User-Agent string captured when the session was created.","example":"Mozilla/5.0 (Macintosh; Intel Mac OS X 14_6_0) AppleWebKit/537.36"},"ipAddress":{"type":["string","null"],"description":"IP address captured when the session was created.","example":"203.0.113.42"},"createdAt":{"type":"string","format":"date-time","description":"When this session was created (ISO-8601 UTC).","example":"2026-05-16T09:30:00Z"},"expiresAt":{"type":"string","format":"date-time","description":"When this session expires (ISO-8601 UTC).","example":"2026-05-23T09:30:00Z"},"lastUsedAt":{"type":"string","format":"date-time","description":"When this session was last seen by the API (ISO-8601 UTC).","example":"2026-05-16T11:42:00Z"},"activeOrganizationId":{"type":["string","null"],"format":"uuid","description":"Active organization pinned to this session (the `o` claim on re-mint)."},"impersonatedBy":{"type":["string","null"],"format":"uuid","description":"Platform user behind this session when it was established via impersonation; null for normal sign-ins."}},"required":["createdAt","environmentId","expiresAt","id","lastUsedAt","userId"]},"CursorPageResponseServerUserOrganizationResponse":{"type":"object","description":"A single page of results in a cursor-paginated list. Pass `nextCursor` as the `cursor` query parameter to fetch the following page.","properties":{"items":{"type":"array","description":"Items in this page, in stable order.","items":{"$ref":"#/components/schemas/ServerUserOrganizationResponse"}},"nextCursor":{"type":["string","null"],"format":"uuid","description":"Cursor to pass to fetch the next page. Null when this is the last page.","example":"01931a73-8b00-7000-8000-000000000000"},"hasMore":{"type":"boolean","description":"True if more pages are available (equivalent to `nextCursor != null`).","example":true}},"required":["hasMore","items"]},"ServerUserOrganizationResponse":{"type":"object","properties":{"organizationId":{"type":"string","format":"uuid"},"name":{"type":"string","description":"The organization's display name."},"slug":{"type":["string","null"],"description":"The organization's slug, when it has one."},"role":{"type":"string","description":"This user's role key in the organization (e.g. org:administrator)."},"roleName":{"type":["string","null"],"description":"Display name of that role, from the organization's bound role set. Null when the organization has no bound set or the key is not in it."},"publicMetadata":{"type":"object","additionalProperties":true,"description":"The MEMBERSHIP's public metadata bag, not the organization's.","example":{"seat":"billable"}},"privateMetadata":{"type":"object","additionalProperties":true,"description":"The MEMBERSHIP's private metadata bag, not the organization's. Server-only, never exposed to the SDK.","example":{"crmContactId":"con_123"}},"joinedAt":{"type":"string","format":"date-time"}},"required":["joinedAt","name","organizationId","privateMetadata","publicMetadata","role"]},"CursorPageResponseServerOrganizationResponse":{"type":"object","description":"A single page of results in a cursor-paginated list. Pass `nextCursor` as the `cursor` query parameter to fetch the following page.","properties":{"items":{"type":"array","description":"Items in this page, in stable order.","items":{"$ref":"#/components/schemas/ServerOrganizationResponse"}},"nextCursor":{"type":["string","null"],"format":"uuid","description":"Cursor to pass to fetch the next page. Null when this is the last page.","example":"01931a73-8b00-7000-8000-000000000000"},"hasMore":{"type":"boolean","description":"True if more pages are available (equivalent to `nextCursor != null`).","example":true}},"required":["hasMore","items"]},"CursorPageResponseServerOrganizationMemberResponse":{"type":"object","description":"A single page of results in a cursor-paginated list. Pass `nextCursor` as the `cursor` query parameter to fetch the following page.","properties":{"items":{"type":"array","description":"Items in this page, in stable order.","items":{"$ref":"#/components/schemas/ServerOrganizationMemberResponse"}},"nextCursor":{"type":["string","null"],"format":"uuid","description":"Cursor to pass to fetch the next page. Null when this is the last page.","example":"01931a73-8b00-7000-8000-000000000000"},"hasMore":{"type":"boolean","description":"True if more pages are available (equivalent to `nextCursor != null`).","example":true}},"required":["hasMore","items"]},"CursorPageResponseEnvironmentInvitationResponse":{"type":"object","description":"A single page of results in a cursor-paginated list. Pass `nextCursor` as the `cursor` query parameter to fetch the following page.","properties":{"items":{"type":"array","description":"Items in this page, in stable order.","items":{"$ref":"#/components/schemas/EnvironmentInvitationResponse"}},"nextCursor":{"type":["string","null"],"format":"uuid","description":"Cursor to pass to fetch the next page. Null when this is the last page.","example":"01931a73-8b00-7000-8000-000000000000"},"hasMore":{"type":"boolean","description":"True if more pages are available (equivalent to `nextCursor != null`).","example":true}},"required":["hasMore","items"]}},"securitySchemes":{"bearerAuth":{"type":"http","description":"Backend secret key (`sk_live_*` / `sk_test_*`) sent as `Authorization: Bearer <key>`.","scheme":"bearer"}}}}
@@ -85,19 +85,19 @@ module ToriiBackendGenerated
85
85
  return data, status_code, headers
86
86
  end
87
87
 
88
- # Get an invitation by id
88
+ # Get an invitation by id, including both metadata bags
89
89
  # @param invitation_id [String]
90
90
  # @param [Hash] opts the optional parameters
91
- # @return [EnvironmentInvitationResponse]
91
+ # @return [EnvironmentInvitationDetailResponse]
92
92
  def get(invitation_id, opts = {})
93
93
  data, _status_code, _headers = get_with_http_info(invitation_id, opts)
94
94
  data
95
95
  end
96
96
 
97
- # Get an invitation by id
97
+ # Get an invitation by id, including both metadata bags
98
98
  # @param invitation_id [String]
99
99
  # @param [Hash] opts the optional parameters
100
- # @return [Array<(EnvironmentInvitationResponse, Integer, Hash)>] EnvironmentInvitationResponse data, response status code and response headers
100
+ # @return [Array<(EnvironmentInvitationDetailResponse, Integer, Hash)>] EnvironmentInvitationDetailResponse data, response status code and response headers
101
101
  def get_with_http_info(invitation_id, opts = {})
102
102
  if @api_client.config.debugging
103
103
  @api_client.config.logger.debug 'Calling API: InvitationsApi.get ...'
@@ -124,7 +124,7 @@ module ToriiBackendGenerated
124
124
  post_body = opts[:debug_body]
125
125
 
126
126
  # return_type
127
- return_type = opts[:debug_return_type] || 'EnvironmentInvitationResponse'
127
+ return_type = opts[:debug_return_type] || 'EnvironmentInvitationDetailResponse'
128
128
 
129
129
  # auth_names
130
130
  auth_names = opts[:debug_auth_names] || ['bearerAuth']
@@ -332,5 +332,77 @@ module ToriiBackendGenerated
332
332
  end
333
333
  return data, status_code, headers
334
334
  end
335
+
336
+ # Deep-merge metadata into a pending invitation
337
+ # @param invitation_id [String]
338
+ # @param update_environment_invitation_metadata_request [UpdateEnvironmentInvitationMetadataRequest]
339
+ # @param [Hash] opts the optional parameters
340
+ # @return [EnvironmentInvitationDetailResponse]
341
+ def update_metadata(invitation_id, update_environment_invitation_metadata_request, opts = {})
342
+ data, _status_code, _headers = update_metadata_with_http_info(invitation_id, update_environment_invitation_metadata_request, opts)
343
+ data
344
+ end
345
+
346
+ # Deep-merge metadata into a pending invitation
347
+ # @param invitation_id [String]
348
+ # @param update_environment_invitation_metadata_request [UpdateEnvironmentInvitationMetadataRequest]
349
+ # @param [Hash] opts the optional parameters
350
+ # @return [Array<(EnvironmentInvitationDetailResponse, Integer, Hash)>] EnvironmentInvitationDetailResponse data, response status code and response headers
351
+ def update_metadata_with_http_info(invitation_id, update_environment_invitation_metadata_request, opts = {})
352
+ if @api_client.config.debugging
353
+ @api_client.config.logger.debug 'Calling API: InvitationsApi.update_metadata ...'
354
+ end
355
+ # verify the required parameter 'invitation_id' is set
356
+ if @api_client.config.client_side_validation && invitation_id.nil?
357
+ fail ArgumentError, "Missing the required parameter 'invitation_id' when calling InvitationsApi.update_metadata"
358
+ end
359
+ # verify the required parameter 'update_environment_invitation_metadata_request' is set
360
+ if @api_client.config.client_side_validation && update_environment_invitation_metadata_request.nil?
361
+ fail ArgumentError, "Missing the required parameter 'update_environment_invitation_metadata_request' when calling InvitationsApi.update_metadata"
362
+ end
363
+ # resource path
364
+ local_var_path = '/api/server/v1/invitations/{invitationId}'.sub('{invitationId}', CGI.escape(invitation_id.to_s))
365
+
366
+ # query parameters
367
+ query_params = opts[:query_params] || {}
368
+
369
+ # header parameters
370
+ header_params = opts[:header_params] || {}
371
+ # HTTP header 'Accept' (if needed)
372
+ header_params['Accept'] = @api_client.select_header_accept(['application/json', 'application/problem+json']) unless header_params['Accept']
373
+ # HTTP header 'Content-Type'
374
+ content_type = @api_client.select_header_content_type(['application/json'])
375
+ if !content_type.nil?
376
+ header_params['Content-Type'] = content_type
377
+ end
378
+
379
+ # form parameters
380
+ form_params = opts[:form_params] || {}
381
+
382
+ # http body (model)
383
+ post_body = opts[:debug_body] || @api_client.object_to_http_body(update_environment_invitation_metadata_request)
384
+
385
+ # return_type
386
+ return_type = opts[:debug_return_type] || 'EnvironmentInvitationDetailResponse'
387
+
388
+ # auth_names
389
+ auth_names = opts[:debug_auth_names] || ['bearerAuth']
390
+
391
+ new_options = opts.merge(
392
+ :operation => :"InvitationsApi.update_metadata",
393
+ :header_params => header_params,
394
+ :query_params => query_params,
395
+ :form_params => form_params,
396
+ :body => post_body,
397
+ :auth_names => auth_names,
398
+ :return_type => return_type
399
+ )
400
+
401
+ data, status_code, headers = @api_client.call_api(:PATCH, local_var_path, new_options)
402
+ if @api_client.config.debugging
403
+ @api_client.config.logger.debug "API called: InvitationsApi#update_metadata\nData: #{data.inspect}\nStatus code: #{status_code}\nHeaders: #{headers}"
404
+ end
405
+ return data, status_code, headers
406
+ end
335
407
  end
336
408
  end
@@ -0,0 +1,394 @@
1
+ =begin
2
+ #Torii Backend API
3
+
4
+ #Server-to-server API (BAPI) for backend SDKs. Authenticated with a secret key (Bearer sk_live_* / sk_test_*).
5
+
6
+ The version of the OpenAPI document: v1
7
+
8
+ Generated by: https://openapi-generator.tech
9
+ Generator version: 7.22.0
10
+
11
+ =end
12
+
13
+ require 'date'
14
+ require 'time'
15
+
16
+ module ToriiBackendGenerated
17
+ class EnvironmentInvitationDetailResponse < ApiModelBase
18
+ attr_accessor :id
19
+
20
+ attr_accessor :environment_id
21
+
22
+ attr_accessor :email
23
+
24
+ attr_accessor :status
25
+
26
+ attr_accessor :expires_at
27
+
28
+ attr_accessor :created_at
29
+
30
+ attr_accessor :accepted_at
31
+
32
+ attr_accessor :revoked_at
33
+
34
+ attr_accessor :public_metadata
35
+
36
+ attr_accessor :private_metadata
37
+
38
+ class EnumAttributeValidator
39
+ attr_reader :datatype
40
+ attr_reader :allowable_values
41
+
42
+ def initialize(datatype, allowable_values)
43
+ @allowable_values = allowable_values.map do |value|
44
+ case datatype.to_s
45
+ when /Integer/i
46
+ value.to_i
47
+ when /Float/i
48
+ value.to_f
49
+ else
50
+ value
51
+ end
52
+ end
53
+ end
54
+
55
+ def valid?(value)
56
+ !value || allowable_values.include?(value)
57
+ end
58
+ end
59
+
60
+ # Attribute mapping from ruby-style variable name to JSON key.
61
+ def self.attribute_map
62
+ {
63
+ :'id' => :'id',
64
+ :'environment_id' => :'environmentId',
65
+ :'email' => :'email',
66
+ :'status' => :'status',
67
+ :'expires_at' => :'expiresAt',
68
+ :'created_at' => :'createdAt',
69
+ :'accepted_at' => :'acceptedAt',
70
+ :'revoked_at' => :'revokedAt',
71
+ :'public_metadata' => :'publicMetadata',
72
+ :'private_metadata' => :'privateMetadata'
73
+ }
74
+ end
75
+
76
+ # Returns attribute mapping this model knows about
77
+ def self.acceptable_attribute_map
78
+ attribute_map
79
+ end
80
+
81
+ # Returns all the JSON keys this model knows about
82
+ def self.acceptable_attributes
83
+ acceptable_attribute_map.values
84
+ end
85
+
86
+ # Attribute type mapping.
87
+ def self.openapi_types
88
+ {
89
+ :'id' => :'String',
90
+ :'environment_id' => :'String',
91
+ :'email' => :'String',
92
+ :'status' => :'String',
93
+ :'expires_at' => :'Time',
94
+ :'created_at' => :'Time',
95
+ :'accepted_at' => :'Time',
96
+ :'revoked_at' => :'Time',
97
+ :'public_metadata' => :'Hash<String, Object>',
98
+ :'private_metadata' => :'Hash<String, Object>'
99
+ }
100
+ end
101
+
102
+ # List of attributes with nullable: true
103
+ def self.openapi_nullable
104
+ Set.new([
105
+ :'accepted_at',
106
+ :'revoked_at',
107
+ ])
108
+ end
109
+
110
+ # Initializes the object
111
+ # @param [Hash] attributes Model attributes in the form of hash
112
+ def initialize(attributes = {})
113
+ if (!attributes.is_a?(Hash))
114
+ fail ArgumentError, "The input argument (attributes) must be a hash in `ToriiBackendGenerated::EnvironmentInvitationDetailResponse` initialize method"
115
+ end
116
+
117
+ # check to see if the attribute exists and convert string to symbol for hash key
118
+ acceptable_attribute_map = self.class.acceptable_attribute_map
119
+ attributes = attributes.each_with_object({}) { |(k, v), h|
120
+ if (!acceptable_attribute_map.key?(k.to_sym))
121
+ fail ArgumentError, "`#{k}` is not a valid attribute in `ToriiBackendGenerated::EnvironmentInvitationDetailResponse`. Please check the name to make sure it's valid. List of attributes: " + acceptable_attribute_map.keys.inspect
122
+ end
123
+ h[k.to_sym] = v
124
+ }
125
+
126
+ if attributes.key?(:'id')
127
+ self.id = attributes[:'id']
128
+ else
129
+ self.id = nil
130
+ end
131
+
132
+ if attributes.key?(:'environment_id')
133
+ self.environment_id = attributes[:'environment_id']
134
+ else
135
+ self.environment_id = nil
136
+ end
137
+
138
+ if attributes.key?(:'email')
139
+ self.email = attributes[:'email']
140
+ else
141
+ self.email = nil
142
+ end
143
+
144
+ if attributes.key?(:'status')
145
+ self.status = attributes[:'status']
146
+ else
147
+ self.status = nil
148
+ end
149
+
150
+ if attributes.key?(:'expires_at')
151
+ self.expires_at = attributes[:'expires_at']
152
+ else
153
+ self.expires_at = nil
154
+ end
155
+
156
+ if attributes.key?(:'created_at')
157
+ self.created_at = attributes[:'created_at']
158
+ else
159
+ self.created_at = nil
160
+ end
161
+
162
+ if attributes.key?(:'accepted_at')
163
+ self.accepted_at = attributes[:'accepted_at']
164
+ end
165
+
166
+ if attributes.key?(:'revoked_at')
167
+ self.revoked_at = attributes[:'revoked_at']
168
+ end
169
+
170
+ if attributes.key?(:'public_metadata')
171
+ if (value = attributes[:'public_metadata']).is_a?(Hash)
172
+ self.public_metadata = value
173
+ end
174
+ else
175
+ self.public_metadata = nil
176
+ end
177
+
178
+ if attributes.key?(:'private_metadata')
179
+ if (value = attributes[:'private_metadata']).is_a?(Hash)
180
+ self.private_metadata = value
181
+ end
182
+ else
183
+ self.private_metadata = nil
184
+ end
185
+ end
186
+
187
+ # Show invalid properties with the reasons. Usually used together with valid?
188
+ # @return Array for valid properties with the reasons
189
+ def list_invalid_properties
190
+ warn '[DEPRECATED] the `list_invalid_properties` method is obsolete'
191
+ invalid_properties = Array.new
192
+ if @id.nil?
193
+ invalid_properties.push('invalid value for "id", id cannot be nil.')
194
+ end
195
+
196
+ if @environment_id.nil?
197
+ invalid_properties.push('invalid value for "environment_id", environment_id cannot be nil.')
198
+ end
199
+
200
+ if @email.nil?
201
+ invalid_properties.push('invalid value for "email", email cannot be nil.')
202
+ end
203
+
204
+ if @status.nil?
205
+ invalid_properties.push('invalid value for "status", status cannot be nil.')
206
+ end
207
+
208
+ if @expires_at.nil?
209
+ invalid_properties.push('invalid value for "expires_at", expires_at cannot be nil.')
210
+ end
211
+
212
+ if @created_at.nil?
213
+ invalid_properties.push('invalid value for "created_at", created_at cannot be nil.')
214
+ end
215
+
216
+ if @public_metadata.nil?
217
+ invalid_properties.push('invalid value for "public_metadata", public_metadata cannot be nil.')
218
+ end
219
+
220
+ if @private_metadata.nil?
221
+ invalid_properties.push('invalid value for "private_metadata", private_metadata cannot be nil.')
222
+ end
223
+
224
+ invalid_properties
225
+ end
226
+
227
+ # Check to see if the all the properties in the model are valid
228
+ # @return true if the model is valid
229
+ def valid?
230
+ warn '[DEPRECATED] the `valid?` method is obsolete'
231
+ return false if @id.nil?
232
+ return false if @environment_id.nil?
233
+ return false if @email.nil?
234
+ return false if @status.nil?
235
+ status_validator = EnumAttributeValidator.new('String', ["PENDING", "ACCEPTED", "REVOKED", "EXPIRED"])
236
+ return false unless status_validator.valid?(@status)
237
+ return false if @expires_at.nil?
238
+ return false if @created_at.nil?
239
+ return false if @public_metadata.nil?
240
+ return false if @private_metadata.nil?
241
+ true
242
+ end
243
+
244
+ # Custom attribute writer method with validation
245
+ # @param [Object] id Value to be assigned
246
+ def id=(id)
247
+ if id.nil?
248
+ fail ArgumentError, 'id cannot be nil'
249
+ end
250
+
251
+ @id = id
252
+ end
253
+
254
+ # Custom attribute writer method with validation
255
+ # @param [Object] environment_id Value to be assigned
256
+ def environment_id=(environment_id)
257
+ if environment_id.nil?
258
+ fail ArgumentError, 'environment_id cannot be nil'
259
+ end
260
+
261
+ @environment_id = environment_id
262
+ end
263
+
264
+ # Custom attribute writer method with validation
265
+ # @param [Object] email Value to be assigned
266
+ def email=(email)
267
+ if email.nil?
268
+ fail ArgumentError, 'email cannot be nil'
269
+ end
270
+
271
+ @email = email
272
+ end
273
+
274
+ # Custom attribute writer method checking allowed values (enum).
275
+ # @param [Object] status Object to be assigned
276
+ def status=(status)
277
+ validator = EnumAttributeValidator.new('String', ["PENDING", "ACCEPTED", "REVOKED", "EXPIRED"])
278
+ unless validator.valid?(status)
279
+ fail ArgumentError, "invalid value for \"status\", must be one of #{validator.allowable_values}."
280
+ end
281
+ @status = status
282
+ end
283
+
284
+ # Custom attribute writer method with validation
285
+ # @param [Object] expires_at Value to be assigned
286
+ def expires_at=(expires_at)
287
+ if expires_at.nil?
288
+ fail ArgumentError, 'expires_at cannot be nil'
289
+ end
290
+
291
+ @expires_at = expires_at
292
+ end
293
+
294
+ # Custom attribute writer method with validation
295
+ # @param [Object] created_at Value to be assigned
296
+ def created_at=(created_at)
297
+ if created_at.nil?
298
+ fail ArgumentError, 'created_at cannot be nil'
299
+ end
300
+
301
+ @created_at = created_at
302
+ end
303
+
304
+ # Custom attribute writer method with validation
305
+ # @param [Object] public_metadata Value to be assigned
306
+ def public_metadata=(public_metadata)
307
+ if public_metadata.nil?
308
+ fail ArgumentError, 'public_metadata cannot be nil'
309
+ end
310
+
311
+ @public_metadata = public_metadata
312
+ end
313
+
314
+ # Custom attribute writer method with validation
315
+ # @param [Object] private_metadata Value to be assigned
316
+ def private_metadata=(private_metadata)
317
+ if private_metadata.nil?
318
+ fail ArgumentError, 'private_metadata cannot be nil'
319
+ end
320
+
321
+ @private_metadata = private_metadata
322
+ end
323
+
324
+ # Checks equality by comparing each attribute.
325
+ # @param [Object] Object to be compared
326
+ def ==(o)
327
+ return true if self.equal?(o)
328
+ self.class == o.class &&
329
+ id == o.id &&
330
+ environment_id == o.environment_id &&
331
+ email == o.email &&
332
+ status == o.status &&
333
+ expires_at == o.expires_at &&
334
+ created_at == o.created_at &&
335
+ accepted_at == o.accepted_at &&
336
+ revoked_at == o.revoked_at &&
337
+ public_metadata == o.public_metadata &&
338
+ private_metadata == o.private_metadata
339
+ end
340
+
341
+ # @see the `==` method
342
+ # @param [Object] Object to be compared
343
+ def eql?(o)
344
+ self == o
345
+ end
346
+
347
+ # Calculates hash code according to all attributes.
348
+ # @return [Integer] Hash code
349
+ def hash
350
+ [id, environment_id, email, status, expires_at, created_at, accepted_at, revoked_at, public_metadata, private_metadata].hash
351
+ end
352
+
353
+ # Builds the object from hash
354
+ # @param [Hash] attributes Model attributes in the form of hash
355
+ # @return [Object] Returns the model itself
356
+ def self.build_from_hash(attributes)
357
+ return nil unless attributes.is_a?(Hash)
358
+ attributes = attributes.transform_keys(&:to_sym)
359
+ transformed_hash = {}
360
+ openapi_types.each_pair do |key, type|
361
+ if attributes.key?(attribute_map[key]) && attributes[attribute_map[key]].nil?
362
+ transformed_hash["#{key}"] = nil
363
+ elsif type =~ /\AArray<(.*)>/i
364
+ # check to ensure the input is an array given that the attribute
365
+ # is documented as an array but the input is not
366
+ if attributes[attribute_map[key]].is_a?(Array)
367
+ transformed_hash["#{key}"] = attributes[attribute_map[key]].map { |v| _deserialize($1, v) }
368
+ end
369
+ elsif !attributes[attribute_map[key]].nil?
370
+ transformed_hash["#{key}"] = _deserialize(type, attributes[attribute_map[key]])
371
+ end
372
+ end
373
+ new(transformed_hash)
374
+ end
375
+
376
+ # Returns the object in the form of hash
377
+ # @return [Hash] Returns the object in the form of hash
378
+ def to_hash
379
+ hash = {}
380
+ self.class.attribute_map.each_pair do |attr, param|
381
+ value = self.send(attr)
382
+ if value.nil?
383
+ is_nullable = self.class.openapi_nullable.include?(attr)
384
+ next if !is_nullable || (is_nullable && !instance_variable_defined?(:"@#{attr}"))
385
+ end
386
+
387
+ hash[param] = _to_hash(value)
388
+ end
389
+ hash
390
+ end
391
+
392
+ end
393
+
394
+ end
@@ -0,0 +1,162 @@
1
+ =begin
2
+ #Torii Backend API
3
+
4
+ #Server-to-server API (BAPI) for backend SDKs. Authenticated with a secret key (Bearer sk_live_* / sk_test_*).
5
+
6
+ The version of the OpenAPI document: v1
7
+
8
+ Generated by: https://openapi-generator.tech
9
+ Generator version: 7.22.0
10
+
11
+ =end
12
+
13
+ require 'date'
14
+ require 'time'
15
+
16
+ module ToriiBackendGenerated
17
+ class UpdateEnvironmentInvitationMetadataRequest < ApiModelBase
18
+ # Deep-merged into the invitation's public metadata. A key set to null is removed.
19
+ attr_accessor :public_metadata
20
+
21
+ # Deep-merged into the invitation's private metadata. A key set to null is removed.
22
+ attr_accessor :private_metadata
23
+
24
+ # Attribute mapping from ruby-style variable name to JSON key.
25
+ def self.attribute_map
26
+ {
27
+ :'public_metadata' => :'publicMetadata',
28
+ :'private_metadata' => :'privateMetadata'
29
+ }
30
+ end
31
+
32
+ # Returns attribute mapping this model knows about
33
+ def self.acceptable_attribute_map
34
+ attribute_map
35
+ end
36
+
37
+ # Returns all the JSON keys this model knows about
38
+ def self.acceptable_attributes
39
+ acceptable_attribute_map.values
40
+ end
41
+
42
+ # Attribute type mapping.
43
+ def self.openapi_types
44
+ {
45
+ :'public_metadata' => :'Hash<String, Object>',
46
+ :'private_metadata' => :'Hash<String, Object>'
47
+ }
48
+ end
49
+
50
+ # List of attributes with nullable: true
51
+ def self.openapi_nullable
52
+ Set.new([
53
+ ])
54
+ end
55
+
56
+ # Initializes the object
57
+ # @param [Hash] attributes Model attributes in the form of hash
58
+ def initialize(attributes = {})
59
+ if (!attributes.is_a?(Hash))
60
+ fail ArgumentError, "The input argument (attributes) must be a hash in `ToriiBackendGenerated::UpdateEnvironmentInvitationMetadataRequest` initialize method"
61
+ end
62
+
63
+ # check to see if the attribute exists and convert string to symbol for hash key
64
+ acceptable_attribute_map = self.class.acceptable_attribute_map
65
+ attributes = attributes.each_with_object({}) { |(k, v), h|
66
+ if (!acceptable_attribute_map.key?(k.to_sym))
67
+ fail ArgumentError, "`#{k}` is not a valid attribute in `ToriiBackendGenerated::UpdateEnvironmentInvitationMetadataRequest`. Please check the name to make sure it's valid. List of attributes: " + acceptable_attribute_map.keys.inspect
68
+ end
69
+ h[k.to_sym] = v
70
+ }
71
+
72
+ if attributes.key?(:'public_metadata')
73
+ if (value = attributes[:'public_metadata']).is_a?(Hash)
74
+ self.public_metadata = value
75
+ end
76
+ end
77
+
78
+ if attributes.key?(:'private_metadata')
79
+ if (value = attributes[:'private_metadata']).is_a?(Hash)
80
+ self.private_metadata = value
81
+ end
82
+ end
83
+ end
84
+
85
+ # Show invalid properties with the reasons. Usually used together with valid?
86
+ # @return Array for valid properties with the reasons
87
+ def list_invalid_properties
88
+ warn '[DEPRECATED] the `list_invalid_properties` method is obsolete'
89
+ invalid_properties = Array.new
90
+ invalid_properties
91
+ end
92
+
93
+ # Check to see if the all the properties in the model are valid
94
+ # @return true if the model is valid
95
+ def valid?
96
+ warn '[DEPRECATED] the `valid?` method is obsolete'
97
+ true
98
+ end
99
+
100
+ # Checks equality by comparing each attribute.
101
+ # @param [Object] Object to be compared
102
+ def ==(o)
103
+ return true if self.equal?(o)
104
+ self.class == o.class &&
105
+ public_metadata == o.public_metadata &&
106
+ private_metadata == o.private_metadata
107
+ end
108
+
109
+ # @see the `==` method
110
+ # @param [Object] Object to be compared
111
+ def eql?(o)
112
+ self == o
113
+ end
114
+
115
+ # Calculates hash code according to all attributes.
116
+ # @return [Integer] Hash code
117
+ def hash
118
+ [public_metadata, private_metadata].hash
119
+ end
120
+
121
+ # Builds the object from hash
122
+ # @param [Hash] attributes Model attributes in the form of hash
123
+ # @return [Object] Returns the model itself
124
+ def self.build_from_hash(attributes)
125
+ return nil unless attributes.is_a?(Hash)
126
+ attributes = attributes.transform_keys(&:to_sym)
127
+ transformed_hash = {}
128
+ openapi_types.each_pair do |key, type|
129
+ if attributes.key?(attribute_map[key]) && attributes[attribute_map[key]].nil?
130
+ transformed_hash["#{key}"] = nil
131
+ elsif type =~ /\AArray<(.*)>/i
132
+ # check to ensure the input is an array given that the attribute
133
+ # is documented as an array but the input is not
134
+ if attributes[attribute_map[key]].is_a?(Array)
135
+ transformed_hash["#{key}"] = attributes[attribute_map[key]].map { |v| _deserialize($1, v) }
136
+ end
137
+ elsif !attributes[attribute_map[key]].nil?
138
+ transformed_hash["#{key}"] = _deserialize(type, attributes[attribute_map[key]])
139
+ end
140
+ end
141
+ new(transformed_hash)
142
+ end
143
+
144
+ # Returns the object in the form of hash
145
+ # @return [Hash] Returns the object in the form of hash
146
+ def to_hash
147
+ hash = {}
148
+ self.class.attribute_map.each_pair do |attr, param|
149
+ value = self.send(attr)
150
+ if value.nil?
151
+ is_nullable = self.class.openapi_nullable.include?(attr)
152
+ next if !is_nullable || (is_nullable && !instance_variable_defined?(:"@#{attr}"))
153
+ end
154
+
155
+ hash[param] = _to_hash(value)
156
+ end
157
+ hash
158
+ end
159
+
160
+ end
161
+
162
+ end
@@ -26,6 +26,7 @@ require 'torii_backend_generated/models/cursor_page_response_server_organization
26
26
  require 'torii_backend_generated/models/cursor_page_response_server_organization_response'
27
27
  require 'torii_backend_generated/models/cursor_page_response_server_user_organization_response'
28
28
  require 'torii_backend_generated/models/cursor_page_response_server_user_response'
29
+ require 'torii_backend_generated/models/environment_invitation_detail_response'
29
30
  require 'torii_backend_generated/models/environment_invitation_response'
30
31
  require 'torii_backend_generated/models/problem_detail'
31
32
  require 'torii_backend_generated/models/server_impersonation_token_request'
@@ -36,6 +37,7 @@ require 'torii_backend_generated/models/server_user_organization_response'
36
37
  require 'torii_backend_generated/models/server_user_response'
37
38
  require 'torii_backend_generated/models/server_user_search_request'
38
39
  require 'torii_backend_generated/models/set_allowed_origins_request'
40
+ require 'torii_backend_generated/models/update_environment_invitation_metadata_request'
39
41
  require 'torii_backend_generated/models/update_organization_metadata_request'
40
42
  require 'torii_backend_generated/models/update_user_metadata_request'
41
43
  require 'torii_backend_generated/models/update_user_request'
@@ -0,0 +1,94 @@
1
+ =begin
2
+ #Torii Backend API
3
+
4
+ #Server-to-server API (BAPI) for backend SDKs. Authenticated with a secret key (Bearer sk_live_* / sk_test_*).
5
+
6
+ The version of the OpenAPI document: v1
7
+
8
+ Generated by: https://openapi-generator.tech
9
+ Generator version: 7.22.0
10
+
11
+ =end
12
+
13
+ require 'spec_helper'
14
+ require 'json'
15
+ require 'date'
16
+
17
+ # Unit tests for ToriiBackendGenerated::EnvironmentInvitationDetailResponse
18
+ # Automatically generated by openapi-generator (https://openapi-generator.tech)
19
+ # Please update as you see appropriate
20
+ describe ToriiBackendGenerated::EnvironmentInvitationDetailResponse do
21
+ #let(:instance) { ToriiBackendGenerated::EnvironmentInvitationDetailResponse.new }
22
+
23
+ describe 'test an instance of EnvironmentInvitationDetailResponse' do
24
+ it 'should create an instance of EnvironmentInvitationDetailResponse' do
25
+ # uncomment below to test the instance creation
26
+ #expect(instance).to be_instance_of(ToriiBackendGenerated::EnvironmentInvitationDetailResponse)
27
+ end
28
+ end
29
+
30
+ describe 'test attribute "id"' do
31
+ it 'should work' do
32
+ # assertion here. ref: https://rspec.info/features/3-12/rspec-expectations/built-in-matchers/
33
+ end
34
+ end
35
+
36
+ describe 'test attribute "environment_id"' do
37
+ it 'should work' do
38
+ # assertion here. ref: https://rspec.info/features/3-12/rspec-expectations/built-in-matchers/
39
+ end
40
+ end
41
+
42
+ describe 'test attribute "email"' do
43
+ it 'should work' do
44
+ # assertion here. ref: https://rspec.info/features/3-12/rspec-expectations/built-in-matchers/
45
+ end
46
+ end
47
+
48
+ describe 'test attribute "status"' do
49
+ it 'should work' do
50
+ # assertion here. ref: https://rspec.info/features/3-12/rspec-expectations/built-in-matchers/
51
+ # validator = Petstore::EnumTest::EnumAttributeValidator.new('String', ["PENDING", "ACCEPTED", "REVOKED", "EXPIRED"])
52
+ # validator.allowable_values.each do |value|
53
+ # expect { instance.status = value }.not_to raise_error
54
+ # end
55
+ end
56
+ end
57
+
58
+ describe 'test attribute "expires_at"' do
59
+ it 'should work' do
60
+ # assertion here. ref: https://rspec.info/features/3-12/rspec-expectations/built-in-matchers/
61
+ end
62
+ end
63
+
64
+ describe 'test attribute "created_at"' do
65
+ it 'should work' do
66
+ # assertion here. ref: https://rspec.info/features/3-12/rspec-expectations/built-in-matchers/
67
+ end
68
+ end
69
+
70
+ describe 'test attribute "accepted_at"' do
71
+ it 'should work' do
72
+ # assertion here. ref: https://rspec.info/features/3-12/rspec-expectations/built-in-matchers/
73
+ end
74
+ end
75
+
76
+ describe 'test attribute "revoked_at"' do
77
+ it 'should work' do
78
+ # assertion here. ref: https://rspec.info/features/3-12/rspec-expectations/built-in-matchers/
79
+ end
80
+ end
81
+
82
+ describe 'test attribute "public_metadata"' do
83
+ it 'should work' do
84
+ # assertion here. ref: https://rspec.info/features/3-12/rspec-expectations/built-in-matchers/
85
+ end
86
+ end
87
+
88
+ describe 'test attribute "private_metadata"' do
89
+ it 'should work' do
90
+ # assertion here. ref: https://rspec.info/features/3-12/rspec-expectations/built-in-matchers/
91
+ end
92
+ end
93
+
94
+ end
@@ -0,0 +1,42 @@
1
+ =begin
2
+ #Torii Backend API
3
+
4
+ #Server-to-server API (BAPI) for backend SDKs. Authenticated with a secret key (Bearer sk_live_* / sk_test_*).
5
+
6
+ The version of the OpenAPI document: v1
7
+
8
+ Generated by: https://openapi-generator.tech
9
+ Generator version: 7.22.0
10
+
11
+ =end
12
+
13
+ require 'spec_helper'
14
+ require 'json'
15
+ require 'date'
16
+
17
+ # Unit tests for ToriiBackendGenerated::UpdateEnvironmentInvitationMetadataRequest
18
+ # Automatically generated by openapi-generator (https://openapi-generator.tech)
19
+ # Please update as you see appropriate
20
+ describe ToriiBackendGenerated::UpdateEnvironmentInvitationMetadataRequest do
21
+ #let(:instance) { ToriiBackendGenerated::UpdateEnvironmentInvitationMetadataRequest.new }
22
+
23
+ describe 'test an instance of UpdateEnvironmentInvitationMetadataRequest' do
24
+ it 'should create an instance of UpdateEnvironmentInvitationMetadataRequest' do
25
+ # uncomment below to test the instance creation
26
+ #expect(instance).to be_instance_of(ToriiBackendGenerated::UpdateEnvironmentInvitationMetadataRequest)
27
+ end
28
+ end
29
+
30
+ describe 'test attribute "public_metadata"' do
31
+ it 'should work' do
32
+ # assertion here. ref: https://rspec.info/features/3-12/rspec-expectations/built-in-matchers/
33
+ end
34
+ end
35
+
36
+ describe 'test attribute "private_metadata"' do
37
+ it 'should work' do
38
+ # assertion here. ref: https://rspec.info/features/3-12/rspec-expectations/built-in-matchers/
39
+ end
40
+ end
41
+
42
+ end
@@ -2,6 +2,6 @@
2
2
 
3
3
  module Torii
4
4
  module Backend
5
- VERSION = '0.0.12'
5
+ VERSION = '0.0.13'
6
6
  end
7
7
  end
metadata CHANGED
@@ -1,14 +1,14 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: torii-backend
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.0.12
4
+ version: 0.0.13
5
5
  platform: ruby
6
6
  authors:
7
7
  - torii
8
8
  autorequire:
9
9
  bindir: bin
10
10
  cert_chain: []
11
- date: 2026-08-08 00:00:00.000000000 Z
11
+ date: 2026-08-10 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: jwt
@@ -132,6 +132,7 @@ files:
132
132
  - src/torii/backend/generated/lib/torii_backend_generated/models/cursor_page_response_server_organization_response.rb
133
133
  - src/torii/backend/generated/lib/torii_backend_generated/models/cursor_page_response_server_user_organization_response.rb
134
134
  - src/torii/backend/generated/lib/torii_backend_generated/models/cursor_page_response_server_user_response.rb
135
+ - src/torii/backend/generated/lib/torii_backend_generated/models/environment_invitation_detail_response.rb
135
136
  - src/torii/backend/generated/lib/torii_backend_generated/models/environment_invitation_response.rb
136
137
  - src/torii/backend/generated/lib/torii_backend_generated/models/problem_detail.rb
137
138
  - src/torii/backend/generated/lib/torii_backend_generated/models/server_impersonation_token_request.rb
@@ -142,6 +143,7 @@ files:
142
143
  - src/torii/backend/generated/lib/torii_backend_generated/models/server_user_response.rb
143
144
  - src/torii/backend/generated/lib/torii_backend_generated/models/server_user_search_request.rb
144
145
  - src/torii/backend/generated/lib/torii_backend_generated/models/set_allowed_origins_request.rb
146
+ - src/torii/backend/generated/lib/torii_backend_generated/models/update_environment_invitation_metadata_request.rb
145
147
  - src/torii/backend/generated/lib/torii_backend_generated/models/update_organization_metadata_request.rb
146
148
  - src/torii/backend/generated/lib/torii_backend_generated/models/update_user_metadata_request.rb
147
149
  - src/torii/backend/generated/lib/torii_backend_generated/models/update_user_request.rb
@@ -161,6 +163,7 @@ files:
161
163
  - src/torii/backend/generated/spec/models/cursor_page_response_server_organization_response_spec.rb
162
164
  - src/torii/backend/generated/spec/models/cursor_page_response_server_user_organization_response_spec.rb
163
165
  - src/torii/backend/generated/spec/models/cursor_page_response_server_user_response_spec.rb
166
+ - src/torii/backend/generated/spec/models/environment_invitation_detail_response_spec.rb
164
167
  - src/torii/backend/generated/spec/models/environment_invitation_response_spec.rb
165
168
  - src/torii/backend/generated/spec/models/problem_detail_spec.rb
166
169
  - src/torii/backend/generated/spec/models/server_impersonation_token_request_spec.rb
@@ -171,6 +174,7 @@ files:
171
174
  - src/torii/backend/generated/spec/models/server_user_response_spec.rb
172
175
  - src/torii/backend/generated/spec/models/server_user_search_request_spec.rb
173
176
  - src/torii/backend/generated/spec/models/set_allowed_origins_request_spec.rb
177
+ - src/torii/backend/generated/spec/models/update_environment_invitation_metadata_request_spec.rb
174
178
  - src/torii/backend/generated/spec/models/update_organization_metadata_request_spec.rb
175
179
  - src/torii/backend/generated/spec/models/update_user_metadata_request_spec.rb
176
180
  - src/torii/backend/generated/spec/models/update_user_request_spec.rb