diff --git a/.claude/CLAUDE-KNOWLEDGE.md b/.claude/CLAUDE-KNOWLEDGE.md index ac6d53b48c..a4013491d5 100644 --- a/.claude/CLAUDE-KNOWLEDGE.md +++ b/.claude/CLAUDE-KNOWLEDGE.md @@ -356,6 +356,33 @@ Then restart the dev server. This rebuilds all packages and generates the necess ## Q: How is backwards compatibility for the offer→product rename handled in the payments purchase APIs? A: API v1 requests are routed through the `v2beta1` migration. The migration wraps the latest handlers, accepts legacy `offer_id`/`offer_inline` request fields, translates product-related errors back to the old offer error codes/messages, and augments responses (like `validate-code`) with `offer`/`conflicting_group_offers` aliases alongside the new `product` fields. Newer API versions keep the product-only contract. +### Q: What's the reliable way to run targeted tests across backend, dashboard, stack-shared, and e2e at once? +A: Run from the monorepo root with explicit file paths: `pnpm test run "" "" ...`. This works even when individual packages do not define a local `test` script. Also avoid passing an extra `run` argument to package-level `test` scripts that already execute `vitest run`. + +### Q: What's the new Authorization header format for Stack token forwarding? +A: Use `getAuthorizationHeader()`, which returns `Bearer stackauth_`. The payload encodes both `accessToken` and `refreshToken`, and request-like token stores should parse this format first, with legacy `x-stack-auth` remaining as a backward-compatible fallback. + +### Q: What RequestLike header shapes are supported by tokenStore overrides? +A: `RequestLike` accepts both `{ headers: { get(name): string | null } }` and `{ headers: Record }`. Header lookup is case-insensitive for record-style headers, and supports `authorization`, `x-stack-auth`, and `cookie`. + +### Q: Which env var should emulator onboarding URLs use for dashboard port? +A: Use `EMULATOR_DASHBOARD_PORT` (default `26700`) or explicit `STACK_LOCAL_EMULATOR_DASHBOARD_URL`. Do not derive emulator URLs from `NEXT_PUBLIC_STACK_PORT_PREFIX`, because that points to the host dev environment ports (e.g. `92xx`) rather than the emulator host-forwarded ports. + +### Q: Why does `PATCH /api/v1/internal/projects/current` fail in local emulator when updating only `onboarding_state`? +A: `createOrUpdateProjectWithLegacyConfig` always called `overrideEnvironmentConfigOverride`, even when there were zero config override keys to apply. In local emulator mode, environment config overrides are intentionally blocked, so this threw `Environment configuration overrides cannot be changed in the local emulator` and returned 500. The fix is to skip `overrideEnvironmentConfigOverride` unless `configOverrideOverride` has at least one key. + +### Q: Why might local emulator UI changes in `apps/dashboard` not appear immediately at `localhost:26700`? +A: The QEMU local emulator serves the dashboard from the Docker image bundled inside the VM, not from the host repo's live source tree. Source edits in `apps/dashboard` are reflected in lint/typecheck/tests immediately, but you need an updated emulator image/runtime to see the visual change on `26700`. + +### Q: Why can local emulator onboarding break with `ParseError` on non-`.ts` config files (e.g. `test-config.untracked`)? +A: The emulator writes TypeScript-style config source (`import type ...` and `config: StackConfig`) and later evaluates it with Jiti. If the filename has a non-TS extension, Jiti may parse it as plain JS and fail. Fix by evaluating unknown extensions as TypeScript (use a `.ts` eval filename fallback) and add regression coverage for non-`.ts` config paths. + +### Q: How should docs fetch the canonical AI setup prompt text? +A: Expose an unauthenticated backend endpoint at `/api/v1/setup-prompt` that returns `getSdkSetupPrompt("ai-prompt", { tanstackQuery: false })` as plain text and sets `Cache-Control: public, max-age=60`. Mintlify docs should fetch `https://api.stack-auth.com/api/v1/setup-prompt` directly when docs and API are on different origins. + +### Q: Can Mintlify snippets import other snippets? +A: No. Keep snippet logic inline within each snippet file; avoid snippet-to-snippet imports. For setup prompt fetching, point directly to `https://api.stack-auth.com/api/v1/setup-prompt` when docs run on a different origin/port than the API. + ## Q: How does `/api/v1/ai/query/generate` reject invalid AI tool names? A: Invalid `tools` entries are rejected by `requestBodySchema` in `apps/backend/src/lib/ai/schema.ts` via `yupString().oneOf(TOOL_NAMES)`, so the endpoint returns a structured `SCHEMA_ERROR` object mentioning `body.tools[n]` rather than a custom `"Invalid tool names"` string from handler logic. diff --git a/AGENTS.md b/AGENTS.md index 409bce584f..9653199d65 100644 --- a/AGENTS.md +++ b/AGENTS.md @@ -74,7 +74,7 @@ To see all development ports, refer to the index.html of `apps/dev-launchpad/pub - Always run typecheck, lint, and test to make sure your changes are working as expected. You can save time by only linting and testing the files you've changed (and/or related E2E tests). - The project uses a custom route handler system in the backend for consistent API responses - When writing tests, prefer .toMatchInlineSnapshot over other selectors, if possible. You can check (and modify) the snapshot-serializer.ts file to see how the snapshots are formatted and how non-deterministic values are handled. -- Whenever you learn something new, or at the latest right before you call the `Stop` tool, write whatever you learned into the ./claude/CLAUDE-KNOWLEDGE.md file, in the Q&A format in there. You will later be able to look up knowledge from there (based on the question you asked). +- Whenever you learn something new, or at the latest right before you call the `Stop` tool, write whatever you learned into the .claude/CLAUDE-KNOWLEDGE.md file, in the Q&A format in there. You will later be able to look up knowledge from there (based on the question you asked). - Animations: Keep hover/click transitions snappy and fast. Don't delay the action with a pre-transition (e.g. no fade-in when hovering a button) — it makes the UI feel sluggish. Instead, apply transitions after the action, like a smooth fade-out when the hover ends. - Whenever you make changes in the dashboard, provide the user with a deep link to the dashboard page that you've just changed. Usually, this takes the form of `http://localhost:01/projects/-selector-/...`, although sometimes it's different. If $NEXT_PUBLIC_STACK_PORT_PREFIX is set to 91, 92, or 93, use `a.localhost`, `b.localhost`, and `c.localhost` for the domains, respectively. - To update the list of apps available, edit `apps-frontend.tsx` and `apps-config.ts`. When you're tasked to implement a new app or a new page, always check existing apps for inspiration on how you could implement the new app or page. diff --git a/apps/backend/prisma/migrations/20260420000000_add_project_onboarding_state/migration.sql b/apps/backend/prisma/migrations/20260420000000_add_project_onboarding_state/migration.sql new file mode 100644 index 0000000000..40411aed73 --- /dev/null +++ b/apps/backend/prisma/migrations/20260420000000_add_project_onboarding_state/migration.sql @@ -0,0 +1,2 @@ +ALTER TABLE "Project" + ADD COLUMN "onboardingState" JSONB; diff --git a/apps/backend/prisma/migrations/20260420000000_add_project_onboarding_state/tests/default-and-updates.ts b/apps/backend/prisma/migrations/20260420000000_add_project_onboarding_state/tests/default-and-updates.ts new file mode 100644 index 0000000000..a474db0171 --- /dev/null +++ b/apps/backend/prisma/migrations/20260420000000_add_project_onboarding_state/tests/default-and-updates.ts @@ -0,0 +1,57 @@ +import { randomUUID } from "crypto"; +import type { Sql } from "postgres"; +import { expect } from "vitest"; + +export const preMigration = async (sql: Sql) => { + const projectId = `test-${randomUUID()}`; + await sql` + INSERT INTO "Project" ("id", "createdAt", "updatedAt", "displayName", "description", "isProductionMode") + VALUES (${projectId}, NOW(), NOW(), 'Onboarding State Project', '', false) + `; + return { projectId }; +}; + +export const postMigration = async (sql: Sql, ctx: Awaited>) => { + const rows = await sql` + SELECT "onboardingState" + FROM "Project" + WHERE "id" = ${ctx.projectId} + `; + expect(rows).toHaveLength(1); + expect(rows[0].onboardingState).toBeNull(); + + const onboardingState = { + selected_config_choice: "create-new", + selected_apps: ["authentication", "emails"], + selected_sign_in_methods: ["credential", "magicLink"], + selected_email_theme_id: null, + selected_payments_country: "US", + }; + await sql` + UPDATE "Project" + SET "onboardingState" = ${JSON.stringify(onboardingState)}::jsonb + WHERE "id" = ${ctx.projectId} + `; + + const updatedRows = await sql` + SELECT "onboardingState" + FROM "Project" + WHERE "id" = ${ctx.projectId} + `; + expect(updatedRows).toHaveLength(1); + expect(updatedRows[0].onboardingState).toMatchInlineSnapshot(` + { + "selected_apps": [ + "authentication", + "emails", + ], + "selected_config_choice": "create-new", + "selected_email_theme_id": null, + "selected_payments_country": "US", + "selected_sign_in_methods": [ + "credential", + "magicLink", + ], + } + `); +}; diff --git a/apps/backend/prisma/schema.prisma b/apps/backend/prisma/schema.prisma index 1b20c77b17..0b32726af2 100644 --- a/apps/backend/prisma/schema.prisma +++ b/apps/backend/prisma/schema.prisma @@ -27,6 +27,7 @@ model Project { isProductionMode Boolean ownerTeamId String? @db.Uuid onboardingStatus String @default("completed") + onboardingState Json? logoUrl String? logoFullUrl String? diff --git a/apps/backend/scripts/generate-openapi-fumadocs.ts b/apps/backend/scripts/generate-openapi-fumadocs.ts index 003335c492..6b55da252c 100644 --- a/apps/backend/scripts/generate-openapi-fumadocs.ts +++ b/apps/backend/scripts/generate-openapi-fumadocs.ts @@ -4,6 +4,7 @@ import { webhookEvents } from '@stackframe/stack-shared/dist/interface/webhooks' import { writeFileSyncIfChanged } from '@stackframe/stack-shared/dist/utils/fs'; import { HTTP_METHODS } from '@stackframe/stack-shared/dist/utils/http'; import { typedKeys } from '@stackframe/stack-shared/dist/utils/objects'; +import { stringCompare } from '@stackframe/stack-shared/dist/utils/strings'; import fs from 'fs'; import { glob } from 'glob'; import path from 'path'; @@ -29,7 +30,7 @@ async function main() { // Generate OpenAPI specs for each audience (let parseOpenAPI handle the filtering) const filePathPrefix = path.resolve(process.platform === "win32" ? "apps/src/app/api/latest" : "src/app/api/latest"); const importPathPrefix = "@/app/api/latest"; - const filePaths = [...await glob(filePathPrefix + "/**/route.{js,jsx,ts,tsx}")]; + const filePaths = [...await glob(filePathPrefix + "/**/route.{js,jsx,ts,tsx}")].sort((a, b) => stringCompare(a, b)); const endpoints = new Map(await Promise.all(filePaths.map(async (filePath) => { if (!filePath.startsWith(filePathPrefix)) { diff --git a/apps/backend/src/app/api/latest/internal/local-emulator/project/route.tsx b/apps/backend/src/app/api/latest/internal/local-emulator/project/route.tsx index 5e13731498..fd6ccf5149 100644 --- a/apps/backend/src/app/api/latest/internal/local-emulator/project/route.tsx +++ b/apps/backend/src/app/api/latest/internal/local-emulator/project/route.tsx @@ -4,15 +4,25 @@ import { LOCAL_EMULATOR_ADMIN_USER_ID, LOCAL_EMULATOR_ONLY_ENDPOINT_MESSAGE, LOCAL_EMULATOR_OWNER_TEAM_ID, + isLocalEmulatorOnboardingEnabledInConfig, isLocalEmulatorEnabled, readConfigFromFile, resolveEmulatorPath, - writeConfigToFile, + writeShowOnboardingConfigToFile, } from "@/lib/local-emulator"; import { DEFAULT_BRANCH_ID, getSoleTenancyFromProjectBranch } from "@/lib/tenancies"; import { getPrismaClientForTenancy, globalPrismaClient } from "@/prisma-client"; import { createSmartRouteHandler } from "@/route-handlers/smart-route-handler"; -import { clientOrHigherAuthTypeSchema, yupNumber, yupObject, yupString } from "@stackframe/stack-shared/dist/schema-fields"; +import { + clientOrHigherAuthTypeSchema, + projectOnboardingStatusSchema, + projectOnboardingStatusValues, + type ProjectOnboardingStatus, + yupBoolean, + yupNumber, + yupObject, + yupString, +} from "@stackframe/stack-shared/dist/schema-fields"; import { generateSecureRandomString } from "@stackframe/stack-shared/dist/utils/crypto"; import { StackAssertionError, StatusError } from "@stackframe/stack-shared/dist/utils/errors"; import { generateUuid } from "@stackframe/stack-shared/dist/utils/uuids"; @@ -23,6 +33,10 @@ type LocalEmulatorProjectMappingRow = { projectId: string, }; +function isProjectOnboardingStatus(value: string): value is ProjectOnboardingStatus { + return projectOnboardingStatusValues.some((status) => status === value); +} + async function assertLocalEmulatorOwnerTeamReadiness() { const internalTenancy = await getSoleTenancyFromProjectBranch("internal", DEFAULT_BRANCH_ID); const internalPrisma = await getPrismaClientForTenancy(internalTenancy); @@ -177,6 +191,66 @@ async function getOrCreateCredentials(projectId: string) { }; } +async function syncLocalEmulatorOnboardingStatus(projectId: string, showOnboarding: boolean): Promise { + const onboardingStateColumnExistsRows = await globalPrismaClient.$queryRaw>(Prisma.sql` + SELECT EXISTS ( + SELECT 1 + FROM information_schema.columns + WHERE table_schema = 'public' + AND table_name = 'Project' + AND column_name = 'onboardingState' + ) AS "exists" + `); + const onboardingStateColumnExists = onboardingStateColumnExistsRows[0]?.exists === true; + + const rows = await globalPrismaClient.$queryRaw>(Prisma.sql` + SELECT "onboardingStatus" + FROM "Project" + WHERE "id" = ${projectId} + LIMIT 1 + `); + const row = rows.length > 0 ? rows[0] : undefined; + if (!row) { + throw new StackAssertionError("Local emulator project not found while syncing onboarding state.", { projectId }); + } + if (!isProjectOnboardingStatus(row.onboardingStatus)) { + throw new StackAssertionError("Project onboarding status in DB is invalid.", { + projectId, + onboardingStatus: row.onboardingStatus, + }); + } + const currentOnboardingStatus = row.onboardingStatus; + + if (!showOnboarding) { + if (onboardingStateColumnExists) { + await globalPrismaClient.$executeRaw(Prisma.sql` + UPDATE "Project" + SET "onboardingStatus" = 'completed', + "onboardingState" = NULL + WHERE "id" = ${projectId} + `); + } else { + await globalPrismaClient.$executeRaw(Prisma.sql` + UPDATE "Project" + SET "onboardingStatus" = 'completed' + WHERE "id" = ${projectId} + `); + } + return "completed"; + } + + if (currentOnboardingStatus === "completed") { + await globalPrismaClient.$executeRaw(Prisma.sql` + UPDATE "Project" + SET "onboardingStatus" = 'config_choice' + WHERE "id" = ${projectId} + `); + return "config_choice"; + } + + return currentOnboardingStatus; +} + export const POST = createSmartRouteHandler({ metadata: { hidden: true, @@ -205,6 +279,8 @@ export const POST = createSmartRouteHandler({ secret_server_key: yupString().defined(), super_secret_admin_key: yupString().defined(), branch_config_override_string: yupString().defined(), + onboarding_status: projectOnboardingStatusSchema.defined(), + onboarding_outstanding: yupBoolean().defined(), }).defined(), }), handler: async (req) => { @@ -230,17 +306,19 @@ export const POST = createSmartRouteHandler({ throw new StatusError(StatusError.BadRequest, `Config file not found: ${absoluteFilePath}`); } - // If the file is empty, write a default config const fileContent = await fs.readFile(resolvedFilePath, "utf-8"); - if (fileContent.trim() === "") { - await writeConfigToFile(absoluteFilePath, {}); - } + const shouldWriteShowOnboardingConfig = fileContent.trim() === ""; await assertLocalEmulatorOwnerTeamReadiness(); const { projectId } = await getOrCreateLocalEmulatorProjectId(absoluteFilePath); + const showOnboarding = shouldWriteShowOnboardingConfig || await isLocalEmulatorOnboardingEnabledInConfig(absoluteFilePath); + const onboardingStatus = await syncLocalEmulatorOnboardingStatus(projectId, showOnboarding); const credentials = await getOrCreateCredentials(projectId); const fileConfig = await readConfigFromFile(absoluteFilePath); + if (shouldWriteShowOnboardingConfig) { + await writeShowOnboardingConfigToFile(absoluteFilePath); + } return { statusCode: 200 as const, @@ -251,6 +329,8 @@ export const POST = createSmartRouteHandler({ secret_server_key: credentials.secretServerKey, super_secret_admin_key: credentials.superSecretAdminKey, branch_config_override_string: JSON.stringify(fileConfig), + onboarding_status: onboardingStatus, + onboarding_outstanding: onboardingStatus !== "completed", }, }; }, diff --git a/apps/backend/src/lib/local-emulator.test.ts b/apps/backend/src/lib/local-emulator.test.ts index bded64af07..cbb3fffdfd 100644 --- a/apps/backend/src/lib/local-emulator.test.ts +++ b/apps/backend/src/lib/local-emulator.test.ts @@ -4,8 +4,10 @@ import path from "path"; import { afterEach, describe, expect, it, vi } from "vitest"; import { LOCAL_EMULATOR_HOST_MOUNT_ROOT_ENV, + isLocalEmulatorOnboardingEnabledInConfig, readConfigFromFile, writeConfigToFile, + writeShowOnboardingConfigToFile, } from "./local-emulator"; describe("local emulator config", () => { @@ -38,12 +40,20 @@ describe("local emulator config", () => { await expect(readConfigFromFile("/irrelevant/path/stack.config.ts")).resolves.toEqual({}); }); + it("treats show-onboarding config as an empty config override", async () => { + const content = `export const config = "show-onboarding";\n`; + vi.stubEnv("STACK_LOCAL_EMULATOR_CONFIG_CONTENT", Buffer.from(content).toString("base64")); + + await expect(readConfigFromFile("/irrelevant/path/stack.config.ts")).resolves.toEqual({}); + await expect(isLocalEmulatorOnboardingEnabledInConfig("/irrelevant/path/stack.config.ts")).resolves.toBe(true); + }); + it("throws when the config module does not export config", async () => { const content = `export default { auth: { allowLocalhost: true } };\n`; vi.stubEnv("STACK_LOCAL_EMULATOR_CONFIG_CONTENT", Buffer.from(content).toString("base64")); await expect(readConfigFromFile("/irrelevant/path/stack.config.ts")).rejects.toThrow( - "Invalid config in /irrelevant/path/stack.config.ts. The file must export a 'config' object." + "Invalid config in /irrelevant/path/stack.config.ts. The file must export a 'config' object or \"show-onboarding\"." ); }); @@ -81,6 +91,41 @@ describe("local emulator config", () => { ); }); + it("writes show-onboarding config files to the host mount", async () => { + const hostMountRoot = await fs.mkdtemp(path.join(os.tmpdir(), "stack-host-mount-")); + const absoluteFilePath = "/Users/foo/project/stack.config.ts"; + const mountedParentPath = path.join(hostMountRoot, "/Users/foo/project"); + const mountedFilePath = path.join(hostMountRoot, absoluteFilePath); + await fs.mkdir(mountedParentPath, { recursive: true }); + + vi.stubEnv(LOCAL_EMULATOR_HOST_MOUNT_ROOT_ENV, hostMountRoot); + + await writeShowOnboardingConfigToFile(absoluteFilePath); + + await expect(fs.readFile(mountedFilePath, "utf-8")).resolves.toBe( + `import type { StackConfig } from "@stackframe/js";\n\nexport const config: StackConfig = "show-onboarding";\n` + ); + }); + + it("supports non-ts config filenames by evaluating them as TypeScript", async () => { + const hostMountRoot = await fs.mkdtemp(path.join(os.tmpdir(), "stack-host-mount-")); + const absoluteFilePath = "/Users/foo/project/test-config.untracked"; + const mountedParentPath = path.join(hostMountRoot, "/Users/foo/project"); + const mountedFilePath = path.join(hostMountRoot, absoluteFilePath); + await fs.mkdir(mountedParentPath, { recursive: true }); + + vi.stubEnv(LOCAL_EMULATOR_HOST_MOUNT_ROOT_ENV, hostMountRoot); + + await writeConfigToFile(absoluteFilePath, { auth: { allowLocalhost: true } }); + + await expect(readConfigFromFile(absoluteFilePath)).resolves.toEqual({ + auth: { + allowLocalhost: true, + }, + }); + await expect(fs.readFile(mountedFilePath, "utf-8")).resolves.toContain(`import type { StackConfig }`); + }); + it("fails loudly when the QEMU host mount root is configured but unavailable", async () => { const hostMountRoot = await fs.mkdtemp(path.join(os.tmpdir(), "stack-host-mount-")); vi.stubEnv(LOCAL_EMULATOR_HOST_MOUNT_ROOT_ENV, hostMountRoot); diff --git a/apps/backend/src/lib/local-emulator.ts b/apps/backend/src/lib/local-emulator.ts index c56379d47d..841045afa0 100644 --- a/apps/backend/src/lib/local-emulator.ts +++ b/apps/backend/src/lib/local-emulator.ts @@ -17,6 +17,9 @@ export const LOCAL_EMULATOR_ENV_CONFIG_BLOCKED_MESSAGE = export const LOCAL_EMULATOR_ONLY_ENDPOINT_MESSAGE = "This endpoint is only available in local emulator mode (set NEXT_PUBLIC_STACK_IS_LOCAL_EMULATOR=true)."; export const LOCAL_EMULATOR_HOST_MOUNT_ROOT_ENV = "STACK_LOCAL_EMULATOR_HOST_MOUNT_ROOT"; +export const LOCAL_EMULATOR_SHOW_ONBOARDING_VALUE = "show-onboarding" as const; + +type LocalEmulatorConfigValue = Record | typeof LOCAL_EMULATOR_SHOW_ONBOARDING_VALUE; export function isLocalEmulatorEnabled() { return getEnvVariable("NEXT_PUBLIC_STACK_IS_LOCAL_EMULATOR", "") === "true"; @@ -54,33 +57,57 @@ export function resolveEmulatorPath(filePath: string): string { return filePath; } -export async function readConfigFromFile(filePath: string): Promise> { +async function readConfigContent(filePath: string): Promise { // Check for base64-encoded config content override from env var const envContent = getEnvVariable("STACK_LOCAL_EMULATOR_CONFIG_CONTENT", ""); - let content: string; if (envContent) { - content = Buffer.from(envContent, "base64").toString("utf-8"); - } else { - const resolvedPath = resolveEmulatorPath(filePath); - try { - content = await fs.readFile(resolvedPath, "utf-8"); - } catch (e: any) { - if (e?.code === "ENOENT") { - return {}; - } - throw e; + return Buffer.from(envContent, "base64").toString("utf-8"); + } + const resolvedPath = resolveEmulatorPath(filePath); + try { + return await fs.readFile(resolvedPath, "utf-8"); + } catch (e: any) { + if (e?.code === "ENOENT") { + return ""; } + throw e; } +} +async function readConfigValueFromFile(filePath: string): Promise { + const content = await readConfigContent(filePath); if (content.trim() === "") { return {}; } + const evalFilename = /\.[cm]?tsx?$/.test(filePath) ? filePath : `${filePath}.ts`; const jiti = createJiti(import.meta.url, { cache: false }); - const mod = jiti.evalModule(content, { filename: filePath }) as Record; + let mod: Record; + try { + mod = jiti.evalModule(content, { filename: evalFilename }) as Record; + } catch (e) { + const message = e instanceof Error ? e.message : String(e); + throw new StatusError(StatusError.BadRequest, `Error evaluating config in ${filePath}: ${message}`); + } const config = mod.config; + if (config === LOCAL_EMULATOR_SHOW_ONBOARDING_VALUE) { + return config; + } if (!isValidConfig(config)) { - throw new StatusError(StatusError.BadRequest, `Invalid config in ${filePath}. The file must export a 'config' object.`); + throw new StatusError(StatusError.BadRequest, `Invalid config in ${filePath}. The file must export a 'config' object or "show-onboarding".`); + } + return config; +} + +export async function isLocalEmulatorOnboardingEnabledInConfig(filePath: string): Promise { + const config = await readConfigValueFromFile(filePath); + return config === LOCAL_EMULATOR_SHOW_ONBOARDING_VALUE; +} + +export async function readConfigFromFile(filePath: string): Promise> { + const config = await readConfigValueFromFile(filePath); + if (config === LOCAL_EMULATOR_SHOW_ONBOARDING_VALUE) { + return {}; } return config; } @@ -102,3 +129,21 @@ export async function writeConfigToFile(filePath: string, config: Record { + const resolvedPath = resolveEmulatorPath(filePath); + const dir = path.dirname(resolvedPath); + const hostMountRoot = getEnvVariable(LOCAL_EMULATOR_HOST_MOUNT_ROOT_ENV, ""); + if (hostMountRoot) { + try { + await fs.access(dir); + } catch { + throw new Error(`Local emulator host mount root ${hostMountRoot} is configured but the parent directory for ${filePath} is not available at ${dir}. Ensure the host filesystem is mounted correctly.`); + } + } else { + await fs.mkdir(dir, { recursive: true }); + } + const importPackage = detectImportPackageFromDir(dir) ?? "@stackframe/js"; + const content = `import type { StackConfig } from "${importPackage}";\n\nexport const config: StackConfig = "show-onboarding";\n`; + await fs.writeFile(resolvedPath, content, "utf-8"); +} diff --git a/apps/backend/src/lib/openapi.tsx b/apps/backend/src/lib/openapi.tsx index fe037148d8..f49778773e 100644 --- a/apps/backend/src/lib/openapi.tsx +++ b/apps/backend/src/lib/openapi.tsx @@ -34,7 +34,13 @@ export function parseOpenAPI(options: { )] )) .filter(([_, handlersByMethod]) => Object.keys(handlersByMethod).length > 0) - .sort(([_a, handlersByMethodA], [_b, handlersByMethodB]) => stringCompare((Object.values(handlersByMethodA)[0] as any).tags[0] ?? "", (Object.values(handlersByMethodB)[0] as any).tags[0] ?? "")), + .sort(([pathA, handlersByMethodA], [pathB, handlersByMethodB]) => { + const tagComparison = stringCompare((Object.values(handlersByMethodA)[0] as any).tags[0] ?? "", (Object.values(handlersByMethodB)[0] as any).tags[0] ?? ""); + if (tagComparison !== 0) { + return tagComparison; + } + return stringCompare(pathA, pathB); + }), ), }; } diff --git a/apps/backend/src/lib/projects.tsx b/apps/backend/src/lib/projects.tsx index c654691781..ef5a4a93de 100644 --- a/apps/backend/src/lib/projects.tsx +++ b/apps/backend/src/lib/projects.tsx @@ -55,6 +55,13 @@ export function getProjectQuery(projectId: string): RawQuery { - const onboardingStatusColumnExistsRows = await tx.$queryRaw>` + const onboardingColumnExistsRows = await tx.$queryRaw>` SELECT EXISTS ( SELECT 1 FROM information_schema.columns WHERE table_schema = 'public' AND table_name = 'Project' AND column_name = 'onboardingStatus' - ) AS "exists" + ) AS "onboardingStatusExists", + EXISTS ( + SELECT 1 + FROM information_schema.columns + WHERE table_schema = 'public' + AND table_name = 'Project' + AND column_name = 'onboardingState' + ) AS "onboardingStateExists" `; - const onboardingStatusColumnExists = onboardingStatusColumnExistsRows[0]?.exists === true; + const onboardingStatusColumnExists = onboardingColumnExistsRows[0]?.onboardingStatusExists === true; + const onboardingStateColumnExists = onboardingColumnExistsRows[0]?.onboardingStateExists === true; let project: Prisma.ProjectGetPayload<{}>; let branchId: string; @@ -176,6 +192,17 @@ export async function createOrUpdateProjectWithLegacyConfig( branchId = options.branchId; } + if (onboardingStateColumnExists && options.data.onboarding_state !== undefined) { + const onboardingStateString = options.data.onboarding_state == null + ? null + : JSON.stringify(options.data.onboarding_state); + await tx.$executeRaw` + UPDATE "Project" + SET "onboardingState" = ${onboardingStateString}::jsonb + WHERE "id" = ${project.id} + `; + } + return [project.id, branchId]; }); @@ -292,8 +319,6 @@ export async function createOrUpdateProjectWithLegacyConfig( branchId: branchId, environmentConfigOverrideOverride: configOverrideOverride, }); - - const result = await getProject(projectId); if (!result) { throw new StackAssertionError("Project not found after creation/update", { projectId }); diff --git a/apps/dashboard/src/app/(main)/(protected)/(outside-dashboard)/new-project/page-client-parts/content.tsx b/apps/dashboard/src/app/(main)/(protected)/(outside-dashboard)/new-project/page-client-parts/content.tsx index e495d24320..99a454bd92 100644 --- a/apps/dashboard/src/app/(main)/(protected)/(outside-dashboard)/new-project/page-client-parts/content.tsx +++ b/apps/dashboard/src/app/(main)/(protected)/(outside-dashboard)/new-project/page-client-parts/content.tsx @@ -34,7 +34,9 @@ import { beginPendingAction, endPendingAction, getStackAppInternals, + isProjectOnboardingState, isProjectOnboardingStatus, + type ProjectOnboardingState, } from "./shared"; export default function PageClient() { @@ -68,6 +70,7 @@ function PageClientInner() { const mode = searchParams.get("mode"); const [projectStatuses, setProjectStatuses] = useState>(new Map()); + const [projectOnboardingStates, setProjectOnboardingStates] = useState>(new Map()); const [loadingStatuses, setLoadingStatuses] = useState(true); const [, startStatusTransition] = useTransition(); const [projectName, setProjectName] = useState(displayNameFromSearch ?? ""); @@ -128,6 +131,7 @@ function PageClientInner() { } const statusMap = new Map(); + const onboardingStateMap = new Map(); for (const item of body.items) { if (item == null || typeof item !== "object" || !("id" in item) || typeof item.id !== "string") { continue; @@ -138,10 +142,17 @@ function PageClientInner() { throw new Error(`Project ${item.id} returned an invalid onboarding status.`); } statusMap.set(item.id, onboardingStatus); + + const onboardingState = "onboarding_state" in item ? item.onboarding_state : null; + if (onboardingState != null && !isProjectOnboardingState(onboardingState)) { + throw new Error(`Project ${item.id} returned an invalid onboarding state.`); + } + onboardingStateMap.set(item.id, onboardingState); } if (!cancelled) { setProjectStatuses(statusMap); + setProjectOnboardingStates(onboardingStateMap); } } finally { if (!cancelled) { @@ -169,6 +180,13 @@ function PageClientInner() { return projectStatuses.get(selectedProjectId) ?? null; }, [projectStatuses, selectedProjectId]); + const selectedProjectOnboardingState = useMemo(() => { + if (selectedProjectId == null) { + return null; + } + return projectOnboardingStates.get(selectedProjectId) ?? null; + }, [projectOnboardingStates, selectedProjectId]); + useEffect(() => { if (selectedProject == null || loadingStatuses || selectedProjectStatus !== "completed") { return; @@ -207,7 +225,33 @@ function PageClientInner() { await appInternals.refreshOwnedProjects(); }; - if (isLocalEmulator) { + const setSelectedProjectOnboardingState = async (project: AdminOwnedProject, onboardingState: ProjectOnboardingState | null) => { + const projectInternals = getStackAppInternals(project.app); + + const response = await projectInternals.sendRequest( + "/internal/projects/current", + { + method: "PATCH", + headers: { + "content-type": "application/json", + }, + body: JSON.stringify({ onboarding_state: onboardingState }), + }, + "admin", + ); + + if (!response.ok) { + throw new Error(`Failed to update onboarding state: ${response.status} ${await response.text()}`); + } + + setProjectOnboardingStates((previous) => { + const next = new Map(previous); + next.set(project.id, onboardingState); + return next; + }); + }; + + if (isLocalEmulator && selectedProjectId == null) { return (
@@ -361,6 +405,11 @@ function PageClientInner() { next.set(newProject.id, "config_choice"); return next; }); + setProjectOnboardingStates((previous) => { + const next = new Map(previous); + next.set(newProject.id, null); + return next; + }); if (redirectToNeonConfirmWith != null) { const confirmSearchParams = new URLSearchParams(redirectToNeonConfirmWith); @@ -472,9 +521,12 @@ function PageClientInner() { updateSearchParams({ mode: nextMode })} setStatus={(nextStatus) => setSelectedProjectStatus(selectedProject, nextStatus)} + setOnboardingState={(nextState) => setSelectedProjectOnboardingState(selectedProject, nextState)} + clearOnboardingState={() => setSelectedProjectOnboardingState(selectedProject, null)} onComplete={() => { router.push(`/projects/${encodeURIComponent(selectedProject.id)}`); }} diff --git a/apps/dashboard/src/app/(main)/(protected)/(outside-dashboard)/new-project/page-client-parts/project-onboarding-wizard.test.tsx b/apps/dashboard/src/app/(main)/(protected)/(outside-dashboard)/new-project/page-client-parts/project-onboarding-wizard.test.tsx index aa55dd95cc..ddccb656d6 100644 --- a/apps/dashboard/src/app/(main)/(protected)/(outside-dashboard)/new-project/page-client-parts/project-onboarding-wizard.test.tsx +++ b/apps/dashboard/src/app/(main)/(protected)/(outside-dashboard)/new-project/page-client-parts/project-onboarding-wizard.test.tsx @@ -77,6 +77,10 @@ vi.mock("@/components/ui", () => ({ cn: (...classNames: Array) => classNames.filter(Boolean).join(" "), })); +vi.mock("@/lib/env", () => ({ + getPublicEnvVar: () => "false", +})); + vi.mock("@/lib/config-update", () => ({ useUpdateConfig: () => vi.fn(async () => true), })); @@ -133,12 +137,25 @@ vi.mock("./link-existing-onboarding", () => ({ })); import { ProjectOnboardingWizard } from "./project-onboarding-wizard"; +import { normalizeProjectOnboardingState, REQUIRED_APP_IDS } from "./shared"; afterEach(() => { cleanup(); }); describe("ProjectOnboardingWizard", () => { + it("keeps required apps when normalizing persisted onboarding state", () => { + const normalizedState = normalizeProjectOnboardingState({ + selected_config_choice: "create-new", + selected_apps: [], + selected_sign_in_methods: [], + selected_email_theme_id: null, + selected_payments_country: "US", + }); + + expect(normalizedState.selected_apps).toEqual(REQUIRED_APP_IDS); + }); + it("completes onboarding automatically after Stripe setup returns successfully", async () => { const setStatus = vi.fn(async () => {}); const onComplete = vi.fn(); @@ -183,9 +200,12 @@ describe("ProjectOnboardingWizard", () => { {})} + clearOnboardingState={vi.fn(async () => {})} onComplete={onComplete} />, ); diff --git a/apps/dashboard/src/app/(main)/(protected)/(outside-dashboard)/new-project/page-client-parts/project-onboarding-wizard.tsx b/apps/dashboard/src/app/(main)/(protected)/(outside-dashboard)/new-project/page-client-parts/project-onboarding-wizard.tsx index 02f6c72ecd..0323b5170b 100644 --- a/apps/dashboard/src/app/(main)/(protected)/(outside-dashboard)/new-project/page-client-parts/project-onboarding-wizard.tsx +++ b/apps/dashboard/src/app/(main)/(protected)/(outside-dashboard)/new-project/page-client-parts/project-onboarding-wizard.tsx @@ -17,6 +17,7 @@ import { TooltipProvider, Typography, } from "@/components/ui"; +import { getPublicEnvVar } from "@/lib/env"; import { useUpdateConfig } from "@/lib/config-update"; import { ArrowsClockwiseIcon, @@ -30,6 +31,7 @@ import { } from "@phosphor-icons/react"; import { AdminOwnedProject, AuthPage } from "@stackframe/stack"; import { type AppId } from "@stackframe/stack-shared/dist/apps/apps-config"; +import { type EnvironmentConfigOverrideOverride } from "@stackframe/stack-shared/dist/config/schema"; import { projectOnboardingStatusValues, type ProjectOnboardingStatus } from "@stackframe/stack-shared/dist/schema-fields"; import { allProviders } from "@stackframe/stack-shared/dist/utils/oauth"; import { runAsynchronouslyWithAlert } from "@stackframe/stack-shared/dist/utils/promises"; @@ -49,9 +51,15 @@ import { deriveInitialApps, deriveInitialSignInMethods, getStepIndex, + normalizeProjectOnboardingState, + createProjectOnboardingState, + OAUTH_SIGN_IN_METHODS, + type OnboardingConfigChoice, + type OnboardingPaymentsCountry, orderedAppIds, PAYMENT_COUNTRY_OPTIONS, PRIMARY_APP_IDS, + type ProjectOnboardingState, REQUIRED_APP_IDS, SIGN_IN_METHODS, type SignInMethod, @@ -63,28 +71,47 @@ const PROJECT_ONBOARDING_STATUSES = projectOnboardingStatusValues; export function ProjectOnboardingWizard(props: { project: AdminOwnedProject, status: ProjectOnboardingStatus, + onboardingState: ProjectOnboardingState | null, mode: string | null, setMode: (mode: string | null) => void, setStatus: (status: ProjectOnboardingStatus) => Promise, + setOnboardingState: (state: ProjectOnboardingState) => Promise, + clearOnboardingState: () => Promise, onComplete: () => void, }) { const router = useRouter(); - const { project, status, setMode, setStatus, onComplete } = props; + const { project, status, onboardingState, setMode, setStatus, setOnboardingState, clearOnboardingState, onComplete } = props; + const isLocalEmulator = getPublicEnvVar("NEXT_PUBLIC_STACK_IS_LOCAL_EMULATOR") === "true"; const completeConfig = project.useConfig(); const updateConfig = useUpdateConfig(); const setProjectOnboardingStatus = setStatus; const finishProjectOnboarding = onComplete; + const deriveCurrentOnboardingState = useCallback((onboardingStatus: ProjectOnboardingStatus): ProjectOnboardingState => { + const defaultState = createProjectOnboardingState({ + selectedConfigChoice: "create-new", + selectedApps: deriveInitialApps(completeConfig, onboardingStatus), + selectedSignInMethods: deriveInitialSignInMethods(project, onboardingStatus), + selectedEmailThemeId: completeConfig.emails.selectedThemeId, + selectedPaymentsCountry: "US", + localEmulator: isLocalEmulator, + }); + if (onboardingState == null) { + return defaultState; + } + return normalizeProjectOnboardingState(onboardingState, { localEmulator: isLocalEmulator }); + }, [completeConfig, isLocalEmulator, onboardingState, project]); + const initialOnboardingState = deriveCurrentOnboardingState(status); const [saving, setSaving] = useState(false); - const [selectedApps, setSelectedApps] = useState>(() => deriveInitialApps(completeConfig, status)); - const [signInMethods, setSignInMethods] = useState>(() => deriveInitialSignInMethods(project, status)); + const [selectedApps, setSelectedApps] = useState>(() => new Set(initialOnboardingState.selected_apps)); + const [signInMethods, setSignInMethods] = useState>(() => new Set(initialOnboardingState.selected_sign_in_methods)); const [trustedDomain, setTrustedDomain] = useState(""); const [domainHandlerPath, setDomainHandlerPath] = useState("/handler"); const [managedSubdomain, setManagedSubdomain] = useState(""); const [managedSenderLocalPart, setManagedSenderLocalPart] = useState(""); const [managedDomainSetupStatus, setManagedDomainSetupStatus] = useState(null); - const [selectedEmailThemeId, setSelectedEmailThemeId] = useState(completeConfig.emails.selectedThemeId); - const [selectedPaymentsCountry, setSelectedPaymentsCountry] = useState("US"); - const [selectedConfigChoice, setSelectedConfigChoice] = useState<"create-new" | "link-existing">("create-new"); + const [selectedEmailThemeId, setSelectedEmailThemeId] = useState(initialOnboardingState.selected_email_theme_id); + const [selectedPaymentsCountry, setSelectedPaymentsCountry] = useState(initialOnboardingState.selected_payments_country); + const [selectedConfigChoice, setSelectedConfigChoice] = useState(initialOnboardingState.selected_config_choice); const [authSetupMobileTab, setAuthSetupMobileTab] = useState<"methods" | "preview">("methods"); const [domainSetupAutoAdvanceError, setDomainSetupAutoAdvanceError] = useState(null); const [domainSetupAutoAdvancing, setDomainSetupAutoAdvancing] = useState(false); @@ -107,8 +134,9 @@ export function ProjectOnboardingWizard(props: { } previousProjectId.current = project.id; - setSelectedApps(deriveInitialApps(completeConfig, status)); - setSignInMethods(deriveInitialSignInMethods(project, status)); + const onboardingState = deriveCurrentOnboardingState(status); + setSelectedApps(new Set(onboardingState.selected_apps)); + setSignInMethods(new Set(onboardingState.selected_sign_in_methods)); const trustedDomains = Object.values(completeConfig.domains.trustedDomains) .filter((entry) => entry.baseUrl != null) @@ -129,17 +157,18 @@ export function ProjectOnboardingWizard(props: { const serverConfig = completeConfig.emails.server; setManagedSubdomain(serverConfig.managedSubdomain ?? ""); setManagedSenderLocalPart(serverConfig.managedSenderLocalPart ?? ""); - setSelectedEmailThemeId(completeConfig.emails.selectedThemeId); + setSelectedEmailThemeId(onboardingState.selected_email_theme_id); setManagedDomainSetupStatus(null); - setSelectedConfigChoice("create-new"); + setSelectedConfigChoice(onboardingState.selected_config_choice); + setSelectedPaymentsCountry(onboardingState.selected_payments_country); setAuthSetupMobileTab("methods"); setDomainSetupAutoAdvanceError(null); setDomainSetupAutoAdvancing(false); paymentsAutoCompletingRef.current = false; - }, [completeConfig, project, project.id, status]); + }, [completeConfig, deriveCurrentOnboardingState, project, project.id, status]); const emailThemes = project.app.useEmailThemes(); - const isLinkExistingMode = props.mode === "link-existing"; + const isLinkExistingMode = !isLocalEmulator && props.mode === "link-existing"; const paymentsAppEnabledInConfig = completeConfig.apps.installed.payments?.enabled === true; const includePayments = ( status === "payments_setup" @@ -241,12 +270,118 @@ export function ProjectOnboardingWizard(props: { }); }; + const buildOnboardingState = useCallback((): ProjectOnboardingState => { + return createProjectOnboardingState({ + selectedConfigChoice, + selectedApps, + selectedSignInMethods: signInMethods, + selectedEmailThemeId: selectedEmailThemeId ?? completeConfig.emails.selectedThemeId, + selectedPaymentsCountry, + localEmulator: isLocalEmulator, + }); + }, [completeConfig.emails.selectedThemeId, isLocalEmulator, selectedApps, selectedConfigChoice, selectedEmailThemeId, selectedPaymentsCountry, signInMethods]); + + const persistOnboardingState = useCallback(async () => { + await setOnboardingState(buildOnboardingState()); + }, [buildOnboardingState, setOnboardingState]); + + const buildBranchConfigUpdate = useCallback(() => { + const emailThemeId = selectedEmailThemeId ?? completeConfig.emails.selectedThemeId; + const configUpdate: EnvironmentConfigOverrideOverride = { + "auth.password.allowSignIn": signInMethods.has("credential"), + "auth.otp.allowSignIn": signInMethods.has("magicLink"), + "auth.passkey.allowSignIn": signInMethods.has("passkey"), + "emails.selectedThemeId": emailThemeId, + }; + for (const appId of ALL_APP_IDS) { + configUpdate[`apps.installed.${appId}.enabled`] = selectedApps.has(appId); + } + if (isLocalEmulator) { + configUpdate["auth.oauth.providers.google"] = signInMethods.has("google") ? { + type: "google", + allowSignIn: true, + allowConnectedAccounts: true, + } : null; + configUpdate["auth.oauth.providers.github"] = signInMethods.has("github") ? { + type: "github", + allowSignIn: true, + allowConnectedAccounts: true, + } : null; + configUpdate["auth.oauth.providers.microsoft"] = signInMethods.has("microsoft") ? { + type: "microsoft", + allowSignIn: true, + allowConnectedAccounts: true, + } : null; + } + return configUpdate; + }, [completeConfig.emails.selectedThemeId, isLocalEmulator, selectedApps, selectedEmailThemeId, signInMethods]); + + const buildEnvironmentOAuthConfigUpdate = useCallback(() => { + return { + "auth.oauth.providers.google": signInMethods.has("google") ? { + type: "google", + isShared: true, + allowSignIn: true, + allowConnectedAccounts: true, + } : null, + "auth.oauth.providers.github": signInMethods.has("github") ? { + type: "github", + isShared: true, + allowSignIn: true, + allowConnectedAccounts: true, + } : null, + "auth.oauth.providers.microsoft": signInMethods.has("microsoft") ? { + type: "microsoft", + isShared: true, + allowSignIn: true, + allowConnectedAccounts: true, + } : null, + }; + }, [signInMethods]); + const finalizeOnboarding = useCallback(async () => { await runWithSaving(async () => { + if (!isLinkExistingMode) { + await persistOnboardingState(); + + const branchConfigUpdated = await updateConfig({ + adminApp: props.project.app, + configUpdate: buildBranchConfigUpdate(), + pushable: true, + }); + if (!branchConfigUpdated) { + return; + } + + if (!isLocalEmulator) { + const providersUpdated = await updateConfig({ + adminApp: props.project.app, + configUpdate: buildEnvironmentOAuthConfigUpdate(), + pushable: false, + }); + if (!providersUpdated) { + return; + } + } + } + await setProjectOnboardingStatus("completed"); + await clearOnboardingState(); finishProjectOnboarding(); }); - }, [finishProjectOnboarding, runWithSaving, setProjectOnboardingStatus]); + }, [ + buildBranchConfigUpdate, + buildEnvironmentOAuthConfigUpdate, + finishProjectOnboarding, + isLinkExistingMode, + isLocalEmulator, + persistOnboardingState, + props.project.app, + clearOnboardingState, + runWithSaving, + setProjectOnboardingStatus, + updateConfig, + ]); useEffect(() => { if (status !== "payments_setup" || stripeAccountInfo?.details_submitted !== true || paymentsAutoCompletingRef.current) { @@ -256,13 +391,14 @@ export function ProjectOnboardingWizard(props: { paymentsAutoCompletingRef.current = true; runAsynchronouslyWithAlert(async () => { try { + await persistOnboardingState(); await setStatus("welcome"); } catch (error) { paymentsAutoCompletingRef.current = false; throw error; } }); - }, [setStatus, status, stripeAccountInfo?.details_submitted]); + }, [persistOnboardingState, setStatus, status, stripeAccountInfo?.details_submitted]); if (props.status === "welcome") { return ( @@ -275,7 +411,7 @@ export function ProjectOnboardingWizard(props: { ); } - if (props.status === "config_choice" && props.mode === "link-existing") { + if (props.status === "config_choice" && props.mode === "link-existing" && !isLocalEmulator) { return ( runAsynchronouslyWithAlert(() => runWithSaving(async () => { + await persistOnboardingState(); + await props.setStatus("apps_selection"); + }))} + > + Continue + + } + > +
+ + This local project is ready for onboarding. + + + Next, we will guide you through the onboarding flow to set up your Stack Auth configuration. + +
+ + ); + } + const createNewSelected = selectedConfigChoice === "create-new"; const linkExistingSelected = selectedConfigChoice === "link-existing"; @@ -319,6 +490,7 @@ export function ProjectOnboardingWizard(props: { className="w-full rounded-full" loading={saving} onClick={() => runAsynchronouslyWithAlert(() => runWithSaving(async () => { + await persistOnboardingState(); if (selectedConfigChoice === "create-new") { await props.setStatus("apps_selection"); } else { @@ -415,21 +587,7 @@ export function ProjectOnboardingWizard(props: { className="w-full rounded-full" loading={saving} onClick={() => runAsynchronouslyWithAlert(() => runWithSaving(async () => { - const appConfigUpdateEntries = new Map( - ALL_APP_IDS.map((appId) => [ - `apps.installed.${appId}.enabled`, - selectedApps.has(appId), - ]) - ); - - const configUpdated = await updateConfig({ - adminApp: props.project.app, - configUpdate: Object.fromEntries(appConfigUpdateEntries), - pushable: true, - }); - if (!configUpdated) { - return; - } + await persistOnboardingState(); await props.setStatus("auth_setup"); }))} > @@ -514,6 +672,10 @@ export function ProjectOnboardingWizard(props: { } if (props.status === "auth_setup") { + const availableSignInMethods = isLocalEmulator + ? SIGN_IN_METHODS.filter((method) => !OAUTH_SIGN_IN_METHODS.some((oauthMethod) => oauthMethod === method.id)) + : SIGN_IN_METHODS; + return ( @@ -614,14 +733,14 @@ export function ProjectOnboardingWizard(props: { Sign-in methods
- {SIGN_IN_METHODS.map((method, index) => { + {availableSignInMethods.map((method, index) => { const checked = signInMethods.has(method.id); return (
+
+
diff --git a/docs-mintlify/images/setup-tools/bun.svg b/docs-mintlify/images/setup-tools/bun.svg new file mode 100644 index 0000000000..7ef15001d2 --- /dev/null +++ b/docs-mintlify/images/setup-tools/bun.svg @@ -0,0 +1 @@ +Bun Logo \ No newline at end of file diff --git a/docs-mintlify/images/setup-tools/cli.svg b/docs-mintlify/images/setup-tools/cli.svg new file mode 100644 index 0000000000..857dd04c71 --- /dev/null +++ b/docs-mintlify/images/setup-tools/cli.svg @@ -0,0 +1 @@ +GNU Bash \ No newline at end of file diff --git a/docs-mintlify/images/setup-tools/convex.svg b/docs-mintlify/images/setup-tools/convex.svg new file mode 100644 index 0000000000..8622c4c072 --- /dev/null +++ b/docs-mintlify/images/setup-tools/convex.svg @@ -0,0 +1,5 @@ + + + + + diff --git a/docs-mintlify/images/setup-tools/javascript.svg b/docs-mintlify/images/setup-tools/javascript.svg new file mode 100644 index 0000000000..3bcf02b0ba --- /dev/null +++ b/docs-mintlify/images/setup-tools/javascript.svg @@ -0,0 +1 @@ +JavaScript \ No newline at end of file diff --git a/docs-mintlify/images/setup-tools/mcp.svg b/docs-mintlify/images/setup-tools/mcp.svg new file mode 100644 index 0000000000..b01b160e21 --- /dev/null +++ b/docs-mintlify/images/setup-tools/mcp.svg @@ -0,0 +1 @@ +Model Context Protocol \ No newline at end of file diff --git a/docs-mintlify/images/setup-tools/nextjs.svg b/docs-mintlify/images/setup-tools/nextjs.svg new file mode 100644 index 0000000000..06a2bd6eed --- /dev/null +++ b/docs-mintlify/images/setup-tools/nextjs.svg @@ -0,0 +1 @@ +Next.js \ No newline at end of file diff --git a/docs-mintlify/images/setup-tools/nodejs.svg b/docs-mintlify/images/setup-tools/nodejs.svg new file mode 100644 index 0000000000..007d7cc4c7 --- /dev/null +++ b/docs-mintlify/images/setup-tools/nodejs.svg @@ -0,0 +1 @@ +Node.js \ No newline at end of file diff --git a/docs-mintlify/images/setup-tools/react.svg b/docs-mintlify/images/setup-tools/react.svg new file mode 100644 index 0000000000..6f10b52ca7 --- /dev/null +++ b/docs-mintlify/images/setup-tools/react.svg @@ -0,0 +1 @@ +React \ No newline at end of file diff --git a/docs-mintlify/images/setup-tools/supabase.svg b/docs-mintlify/images/setup-tools/supabase.svg new file mode 100644 index 0000000000..ea1cf3bbae --- /dev/null +++ b/docs-mintlify/images/setup-tools/supabase.svg @@ -0,0 +1 @@ +Supabase \ No newline at end of file diff --git a/docs-mintlify/images/setup-tools/tanstack.svg b/docs-mintlify/images/setup-tools/tanstack.svg new file mode 100644 index 0000000000..3e6d68517e --- /dev/null +++ b/docs-mintlify/images/setup-tools/tanstack.svg @@ -0,0 +1 @@ +TanStack \ No newline at end of file diff --git a/docs-mintlify/index.mdx b/docs-mintlify/index.mdx index 178331d71b..4ca9f2653d 100644 --- a/docs-mintlify/index.mdx +++ b/docs-mintlify/index.mdx @@ -4,7 +4,7 @@ description: "Stack Auth documentation for setup, components, SDK usage, and RES sidebarTitle: "Overview" --- -import { HomePromptIsland } from "/snippets/home-prompt-island.jsx"; +import { GeneratedSetupPromptText, generatedSetupPromptText } from "/snippets/home-prompt-island.jsx"; import { DocsAppsHomeGrid } from "/snippets/docs-apps-home-grid.jsx"; export const SectionLink = ({ href, children }) => ( @@ -15,7 +15,58 @@ export const ChipLink = ({ href, children }) => ( {children} ); - +export const copyGeneratedSetupPrompt = async (event) => { + const button = event.currentTarget; + try { + await navigator.clipboard.writeText(generatedSetupPromptText); + button.textContent = "Copied"; + } catch { + button.textContent = "Copy failed"; + } + window.setTimeout(() => { + button.textContent = "Copy prompt"; + }, 1300); +}; + +
+

+ Agent-first setup +

+ +

+ Start with a single prompt. +

+

+ Set up Stack Auth by copying the prompt below into your favorite coding agent. +

+ +
+ + +
+
+ + +
@@ -45,9 +96,6 @@ export const ChipLink = ({ href, children }) => (
Explore Apps -

- Open app guides from a home-screen style quick access grid, modeled after dashboard Overview. -

diff --git a/docs-mintlify/openapi/admin.json b/docs-mintlify/openapi/admin.json new file mode 100644 index 0000000000..488cd764b7 --- /dev/null +++ b/docs-mintlify/openapi/admin.json @@ -0,0 +1,10993 @@ +{ + "openapi": "3.1.0", + "info": { + "title": "Stack REST API", + "version": "1.0.0" + }, + "servers": [ + { + "url": "https://api.stack-auth.com/api/v1", + "description": "Stack REST API" + } + ], + "paths": { + "/": { + "get": { + "summary": "/api/v1", + "description": "Returns a human-readable message with some useful information about the API.", + "parameters": [ + { + "name": "X-Stack-Project-Id", + "in": "header", + "schema": { + "type": "string", + "example": "e0b52f4d-dece-408c-af49-d23061bb0f8d", + "description": "The unique identifier of the project" + }, + "description": "The unique identifier of the project", + "example": "e0b52f4d-dece-408c-af49-d23061bb0f8d", + "required": false + }, + { + "name": "X-Stack-Branch-Id", + "in": "header", + "schema": { + "type": "string", + "example": "e0b52f4d-dece-408c-af49-d23061bb0f8d", + "description": "The unique identifier of the project" + }, + "description": "The unique identifier of the project", + "example": "e0b52f4d-dece-408c-af49-d23061bb0f8d", + "required": false + }, + { + "name": "X-Stack-Access-Type", + "in": "header", + "schema": { + "type": "string" + }, + "required": false + }, + { + "name": "X-Stack-Access-Token", + "in": "header", + "schema": { + "type": "string" + }, + "required": false + }, + { + "name": "X-Stack-Refresh-Token", + "in": "header", + "schema": { + "type": "string" + }, + "required": false + }, + { + "name": "X-Stack-Publishable-Client-Key", + "in": "header", + "schema": { + "type": "string" + }, + "required": false + }, + { + "name": "X-Stack-Secret-Server-Key", + "in": "header", + "schema": { + "type": "string" + }, + "required": false + }, + { + "name": "X-Stack-Super-Secret-Admin-Key", + "in": "header", + "schema": { + "type": "string" + }, + "required": false + } + ], + "tags": [], + "x-full-url": "https://api.stack-auth.com/api/v1/", + "responses": { + "200": { + "description": "Successful response", + "content": { + "text/plain": { + "schema": { + "type": "string", + "example": "Welcome to the Stack API endpoint! Please refer to the documentation at https://docs.stack-auth.com/\n\nAuthentication: None" + } + } + } + } + } + } + }, + "/internal/ai-chat/{threadId}": { + "patch": { + "summary": "Save a chat message", + "description": "Save a chat message", + "parameters": [ + { + "name": "threadId", + "in": "path", + "schema": { + "type": "string" + }, + "required": true + } + ], + "requestBody": { + "required": true, + "content": { + "application/json": { + "schema": { + "type": "object", + "properties": { + "message": { + "type": "object" + } + }, + "required": [ + "message" + ], + "example": {} + } + } + } + }, + "tags": [ + "AI Chat" + ], + "x-full-url": "https://api.stack-auth.com/api/v1/internal/ai-chat/{threadId}", + "responses": { + "200": { + "description": "Successful response", + "content": { + "application/json": { + "schema": { + "type": "object", + "properties": {} + } + } + } + } + } + } + }, + "/auth/anonymous/sign-up": { + "post": { + "summary": "Sign up anonymously", + "description": "Create a new anonymous account with no email", + "parameters": [], + "tags": [ + "Anonymous" + ], + "x-full-url": "https://api.stack-auth.com/api/v1/auth/anonymous/sign-up", + "responses": { + "200": { + "description": "Successful response", + "content": { + "application/json": { + "schema": { + "type": "object", + "properties": { + "access_token": { + "type": "string" + }, + "refresh_token": { + "type": "string" + }, + "user_id": { + "type": "string" + } + }, + "required": [ + "access_token", + "refresh_token", + "user_id" + ] + } + } + } + } + } + } + }, + "/team-api-keys": { + "get": { + "summary": "List team API keys", + "description": "List all team API keys for the project with their metadata and status", + "parameters": [ + { + "name": "team_id", + "in": "query", + "schema": { + "type": "string" + }, + "required": true + } + ], + "tags": [ + "API Keys" + ], + "x-full-url": "https://api.stack-auth.com/api/v1/team-api-keys", + "responses": { + "200": { + "description": "Successful response", + "content": { + "application/json": { + "schema": { + "type": "object", + "properties": { + "items": { + "type": "array", + "items": { + "type": "object", + "properties": { + "id": { + "type": "string" + }, + "description": { + "type": "string" + }, + "expires_at_millis": { + "type": "number" + }, + "manually_revoked_at_millis": { + "type": "number" + }, + "created_at_millis": { + "type": "number" + }, + "is_public": { + "type": "boolean" + }, + "value": { + "type": "object", + "properties": { + "last_four": { + "type": "string" + } + }, + "required": [ + "last_four" + ] + }, + "type": { + "type": "string" + }, + "team_id": { + "type": "string" + } + }, + "required": [ + "id", + "description", + "created_at_millis", + "is_public", + "value", + "type", + "team_id" + ] + } + }, + "pagination": { + "type": "object", + "properties": { + "next_cursor": { + "type": "string", + "example": "b3d396b8-c574-4c80-97b3-50031675ceb2", + "description": "The cursor to fetch the next page of results. null if there is no next page." + } + }, + "required": [] + } + }, + "required": [ + "items" + ] + } + } + } + } + } + }, + "post": { + "summary": "Create team API key", + "description": "Create a new API key for a user or team", + "parameters": [], + "requestBody": { + "required": true, + "content": { + "application/json": { + "schema": { + "type": "object", + "properties": { + "description": { + "type": "string" + }, + "expires_at_millis": { + "type": "number" + }, + "is_public": { + "type": "boolean" + }, + "team_id": { + "type": "string" + } + }, + "required": [ + "description", + "team_id" + ], + "example": {} + } + } + } + }, + "tags": [ + "API Keys" + ], + "x-full-url": "https://api.stack-auth.com/api/v1/team-api-keys", + "responses": { + "200": { + "description": "Successful response", + "content": { + "application/json": { + "schema": { + "type": "object", + "properties": { + "value": { + "type": "string" + }, + "id": { + "type": "string" + }, + "description": { + "type": "string" + }, + "expires_at_millis": { + "type": "number" + }, + "manually_revoked_at_millis": { + "type": "number" + }, + "created_at_millis": { + "type": "number" + }, + "is_public": { + "type": "boolean" + }, + "type": { + "type": "string" + }, + "team_id": { + "type": "string" + } + }, + "required": [ + "value", + "id", + "description", + "created_at_millis", + "is_public", + "type", + "team_id" + ] + } + } + } + } + } + } + }, + "/team-api-keys/check": { + "post": { + "summary": "Check team API key validity", + "description": "Validate a team API key", + "parameters": [], + "requestBody": { + "required": true, + "content": { + "application/json": { + "schema": { + "type": "object", + "properties": { + "api_key": { + "type": "string" + } + }, + "required": [ + "api_key" + ], + "example": {} + } + } + } + }, + "tags": [ + "API Keys" + ], + "x-full-url": "https://api.stack-auth.com/api/v1/team-api-keys/check", + "responses": { + "200": { + "description": "Successful response", + "content": { + "application/json": { + "schema": { + "type": "object", + "properties": { + "id": { + "type": "string" + }, + "description": { + "type": "string" + }, + "expires_at_millis": { + "type": "number" + }, + "manually_revoked_at_millis": { + "type": "number" + }, + "created_at_millis": { + "type": "number" + }, + "is_public": { + "type": "boolean" + }, + "value": { + "type": "object", + "properties": { + "last_four": { + "type": "string" + } + }, + "required": [ + "last_four" + ] + }, + "type": { + "type": "string" + }, + "team_id": { + "type": "string" + } + }, + "required": [ + "id", + "description", + "created_at_millis", + "is_public", + "value", + "type", + "team_id" + ] + } + } + } + } + } + } + }, + "/team-api-keys/{api_key_id}": { + "get": { + "summary": "Get team API key details", + "description": "Get details of a specific team API key", + "parameters": [ + { + "name": "api_key_id", + "in": "path", + "schema": { + "type": "string" + }, + "required": true + } + ], + "tags": [ + "API Keys" + ], + "x-full-url": "https://api.stack-auth.com/api/v1/team-api-keys/{api_key_id}", + "responses": { + "200": { + "description": "Successful response", + "content": { + "application/json": { + "schema": { + "type": "object", + "properties": { + "id": { + "type": "string" + }, + "description": { + "type": "string" + }, + "expires_at_millis": { + "type": "number" + }, + "manually_revoked_at_millis": { + "type": "number" + }, + "created_at_millis": { + "type": "number" + }, + "is_public": { + "type": "boolean" + }, + "value": { + "type": "object", + "properties": { + "last_four": { + "type": "string" + } + }, + "required": [ + "last_four" + ] + }, + "type": { + "type": "string" + }, + "team_id": { + "type": "string" + } + }, + "required": [ + "id", + "description", + "created_at_millis", + "is_public", + "value", + "type", + "team_id" + ] + } + } + } + } + } + }, + "patch": { + "summary": "Update team API key", + "description": "Update an team API key", + "parameters": [ + { + "name": "api_key_id", + "in": "path", + "schema": { + "type": "string" + }, + "required": true + } + ], + "requestBody": { + "required": true, + "content": { + "application/json": { + "schema": { + "type": "object", + "properties": { + "description": { + "type": "string" + }, + "revoked": { + "type": "boolean" + } + }, + "example": {} + } + } + } + }, + "tags": [ + "API Keys" + ], + "x-full-url": "https://api.stack-auth.com/api/v1/team-api-keys/{api_key_id}", + "responses": { + "200": { + "description": "Successful response", + "content": { + "application/json": { + "schema": { + "type": "object", + "properties": { + "id": { + "type": "string" + }, + "description": { + "type": "string" + }, + "expires_at_millis": { + "type": "number" + }, + "manually_revoked_at_millis": { + "type": "number" + }, + "created_at_millis": { + "type": "number" + }, + "is_public": { + "type": "boolean" + }, + "value": { + "type": "object", + "properties": { + "last_four": { + "type": "string" + } + }, + "required": [ + "last_four" + ] + }, + "type": { + "type": "string" + }, + "team_id": { + "type": "string" + } + }, + "required": [ + "id", + "description", + "created_at_millis", + "is_public", + "value", + "type", + "team_id" + ] + } + } + } + } + } + } + }, + "/user-api-keys": { + "get": { + "summary": "List user API keys", + "description": "List all user API keys for the project with their metadata and status", + "parameters": [ + { + "name": "user_id", + "in": "query", + "schema": { + "type": "string" + }, + "required": false + } + ], + "tags": [ + "API Keys" + ], + "x-full-url": "https://api.stack-auth.com/api/v1/user-api-keys", + "responses": { + "200": { + "description": "Successful response", + "content": { + "application/json": { + "schema": { + "type": "object", + "properties": { + "items": { + "type": "array", + "items": { + "type": "object", + "properties": { + "id": { + "type": "string" + }, + "description": { + "type": "string" + }, + "expires_at_millis": { + "type": "number" + }, + "manually_revoked_at_millis": { + "type": "number" + }, + "created_at_millis": { + "type": "number" + }, + "is_public": { + "type": "boolean" + }, + "value": { + "type": "object", + "properties": { + "last_four": { + "type": "string" + } + }, + "required": [ + "last_four" + ] + }, + "type": { + "type": "string" + }, + "user_id": { + "type": "string", + "example": "3241a285-8329-4d69-8f3d-316e08cf140c", + "description": "The ID of the user, or the special value `me` for the currently authenticated user" + } + }, + "required": [ + "id", + "description", + "created_at_millis", + "is_public", + "value", + "type", + "user_id" + ] + } + }, + "pagination": { + "type": "object", + "properties": { + "next_cursor": { + "type": "string", + "example": "b3d396b8-c574-4c80-97b3-50031675ceb2", + "description": "The cursor to fetch the next page of results. null if there is no next page." + } + }, + "required": [] + } + }, + "required": [ + "items" + ] + } + } + } + } + } + }, + "post": { + "summary": "Create user API key", + "description": "Create a new API key for a user or team", + "parameters": [], + "requestBody": { + "required": true, + "content": { + "application/json": { + "schema": { + "type": "object", + "properties": { + "description": { + "type": "string" + }, + "expires_at_millis": { + "type": "number" + }, + "is_public": { + "type": "boolean" + }, + "user_id": { + "type": "string", + "example": "3241a285-8329-4d69-8f3d-316e08cf140c", + "description": "The ID of the user, or the special value `me` for the currently authenticated user" + } + }, + "required": [ + "description", + "user_id" + ], + "example": { + "user_id": "3241a285-8329-4d69-8f3d-316e08cf140c" + } + } + } + } + }, + "tags": [ + "API Keys" + ], + "x-full-url": "https://api.stack-auth.com/api/v1/user-api-keys", + "responses": { + "200": { + "description": "Successful response", + "content": { + "application/json": { + "schema": { + "type": "object", + "properties": { + "value": { + "type": "string" + }, + "id": { + "type": "string" + }, + "description": { + "type": "string" + }, + "expires_at_millis": { + "type": "number" + }, + "manually_revoked_at_millis": { + "type": "number" + }, + "created_at_millis": { + "type": "number" + }, + "is_public": { + "type": "boolean" + }, + "type": { + "type": "string" + }, + "user_id": { + "type": "string", + "example": "3241a285-8329-4d69-8f3d-316e08cf140c", + "description": "The ID of the user, or the special value `me` for the currently authenticated user" + } + }, + "required": [ + "value", + "id", + "description", + "created_at_millis", + "is_public", + "type", + "user_id" + ] + } + } + } + } + } + } + }, + "/user-api-keys/check": { + "post": { + "summary": "Check user API key validity", + "description": "Validate a user API key", + "parameters": [], + "requestBody": { + "required": true, + "content": { + "application/json": { + "schema": { + "type": "object", + "properties": { + "api_key": { + "type": "string" + } + }, + "required": [ + "api_key" + ], + "example": {} + } + } + } + }, + "tags": [ + "API Keys" + ], + "x-full-url": "https://api.stack-auth.com/api/v1/user-api-keys/check", + "responses": { + "200": { + "description": "Successful response", + "content": { + "application/json": { + "schema": { + "type": "object", + "properties": { + "id": { + "type": "string" + }, + "description": { + "type": "string" + }, + "expires_at_millis": { + "type": "number" + }, + "manually_revoked_at_millis": { + "type": "number" + }, + "created_at_millis": { + "type": "number" + }, + "is_public": { + "type": "boolean" + }, + "value": { + "type": "object", + "properties": { + "last_four": { + "type": "string" + } + }, + "required": [ + "last_four" + ] + }, + "type": { + "type": "string" + }, + "user_id": { + "type": "string", + "example": "3241a285-8329-4d69-8f3d-316e08cf140c", + "description": "The ID of the user, or the special value `me` for the currently authenticated user" + } + }, + "required": [ + "id", + "description", + "created_at_millis", + "is_public", + "value", + "type", + "user_id" + ] + } + } + } + } + } + } + }, + "/user-api-keys/{api_key_id}": { + "get": { + "summary": "Get user API key details", + "description": "Get details of a specific user API key", + "parameters": [ + { + "name": "api_key_id", + "in": "path", + "schema": { + "type": "string" + }, + "required": true + } + ], + "tags": [ + "API Keys" + ], + "x-full-url": "https://api.stack-auth.com/api/v1/user-api-keys/{api_key_id}", + "responses": { + "200": { + "description": "Successful response", + "content": { + "application/json": { + "schema": { + "type": "object", + "properties": { + "id": { + "type": "string" + }, + "description": { + "type": "string" + }, + "expires_at_millis": { + "type": "number" + }, + "manually_revoked_at_millis": { + "type": "number" + }, + "created_at_millis": { + "type": "number" + }, + "is_public": { + "type": "boolean" + }, + "value": { + "type": "object", + "properties": { + "last_four": { + "type": "string" + } + }, + "required": [ + "last_four" + ] + }, + "type": { + "type": "string" + }, + "user_id": { + "type": "string", + "example": "3241a285-8329-4d69-8f3d-316e08cf140c", + "description": "The ID of the user, or the special value `me` for the currently authenticated user" + } + }, + "required": [ + "id", + "description", + "created_at_millis", + "is_public", + "value", + "type", + "user_id" + ] + } + } + } + } + } + }, + "patch": { + "summary": "Update user API key", + "description": "Update an user API key", + "parameters": [ + { + "name": "api_key_id", + "in": "path", + "schema": { + "type": "string" + }, + "required": true + } + ], + "requestBody": { + "required": true, + "content": { + "application/json": { + "schema": { + "type": "object", + "properties": { + "description": { + "type": "string" + }, + "revoked": { + "type": "boolean" + } + }, + "example": {} + } + } + } + }, + "tags": [ + "API Keys" + ], + "x-full-url": "https://api.stack-auth.com/api/v1/user-api-keys/{api_key_id}", + "responses": { + "200": { + "description": "Successful response", + "content": { + "application/json": { + "schema": { + "type": "object", + "properties": { + "id": { + "type": "string" + }, + "description": { + "type": "string" + }, + "expires_at_millis": { + "type": "number" + }, + "manually_revoked_at_millis": { + "type": "number" + }, + "created_at_millis": { + "type": "number" + }, + "is_public": { + "type": "boolean" + }, + "value": { + "type": "object", + "properties": { + "last_four": { + "type": "string" + } + }, + "required": [ + "last_four" + ] + }, + "type": { + "type": "string" + }, + "user_id": { + "type": "string", + "example": "3241a285-8329-4d69-8f3d-316e08cf140c", + "description": "The ID of the user, or the special value `me` for the currently authenticated user" + } + }, + "required": [ + "id", + "description", + "created_at_millis", + "is_public", + "value", + "type", + "user_id" + ] + } + } + } + } + } + } + }, + "/auth/cli": { + "post": { + "summary": "Initiate CLI authentication", + "description": "Create a new CLI authentication session and return polling and login codes", + "parameters": [], + "requestBody": { + "required": true, + "content": { + "application/json": { + "schema": { + "type": "object", + "properties": { + "expires_in_millis": { + "type": "number", + "default": 7200000 + }, + "anon_refresh_token": { + "type": "string" + } + }, + "example": {} + } + } + } + }, + "tags": [ + "CLI Authentication" + ], + "x-full-url": "https://api.stack-auth.com/api/v1/auth/cli", + "responses": { + "200": { + "description": "Successful response", + "content": { + "application/json": { + "schema": { + "type": "object", + "properties": { + "polling_code": { + "type": "string" + }, + "login_code": { + "type": "string" + }, + "expires_at": { + "type": "string" + } + }, + "required": [ + "polling_code", + "login_code", + "expires_at" + ] + } + } + } + } + } + } + }, + "/auth/cli/complete": { + "post": { + "summary": "Complete CLI authentication", + "description": "Inspect, claim, or complete a CLI authentication session", + "parameters": [], + "requestBody": { + "required": true, + "content": { + "application/json": { + "schema": { + "type": "object", + "properties": { + "login_code": { + "type": "string" + }, + "mode": { + "type": "string", + "default": "complete" + }, + "refresh_token": { + "type": "string" + } + }, + "required": [ + "login_code" + ], + "example": {} + } + } + } + }, + "tags": [ + "CLI Authentication" + ], + "x-full-url": "https://api.stack-auth.com/api/v1/auth/cli/complete", + "responses": { + "200": { + "description": "Successful response", + "content": { + "application/json": { + "schema": { + "type": "object", + "properties": { + "success": { + "type": "boolean" + } + }, + "required": [ + "success" + ] + } + } + } + } + } + } + }, + "/auth/cli/poll": { + "post": { + "summary": "Poll CLI authentication status", + "description": "Check the status of a CLI authentication session using the polling code", + "parameters": [], + "requestBody": { + "required": true, + "content": { + "application/json": { + "schema": { + "type": "object", + "properties": { + "polling_code": { + "type": "string" + } + }, + "required": [ + "polling_code" + ], + "example": {} + } + } + } + }, + "tags": [ + "CLI Authentication" + ], + "x-full-url": "https://api.stack-auth.com/api/v1/auth/cli/poll", + "responses": { + "200": { + "description": "Successful response", + "content": { + "application/json": { + "schema": { + "type": "object", + "properties": { + "status": { + "type": "string" + }, + "refresh_token": { + "type": "string" + } + }, + "required": [ + "status" + ] + } + } + } + }, + "201": { + "description": "Successful response", + "content": { + "application/json": { + "schema": { + "type": "object", + "properties": { + "status": { + "type": "string" + }, + "refresh_token": { + "type": "string" + } + }, + "required": [ + "status" + ] + } + } + } + } + } + } + }, + "/connected-accounts/{user_id}": { + "get": { + "summary": "List connected accounts", + "description": "Retrieves a list of all connected accounts for a user.", + "parameters": [ + { + "name": "user_id", + "in": "path", + "schema": { + "type": "string", + "example": "3241a285-8329-4d69-8f3d-316e08cf140c", + "description": "The ID of the user, or the special value `me` for the currently authenticated user" + }, + "description": "The ID of the user, or the special value `me` for the currently authenticated user", + "required": false + } + ], + "tags": [ + "Connected Accounts" + ], + "x-full-url": "https://api.stack-auth.com/api/v1/connected-accounts/{user_id}", + "responses": { + "200": { + "description": "Successful response", + "content": { + "application/json": { + "schema": { + "type": "object", + "properties": { + "items": { + "type": "array", + "items": { + "type": "object", + "properties": { + "user_id": { + "type": "string", + "example": "3241a285-8329-4d69-8f3d-316e08cf140c", + "description": "The ID of the user, or the special value `me` for the currently authenticated user" + }, + "provider": { + "type": "string", + "example": "google", + "description": "Provider config ID of the OAuth provider. This uniquely identifies the provider config on config.json file" + }, + "provider_account_id": { + "type": "string", + "example": "google-account-id-12345", + "description": "Account ID of the OAuth provider. This uniquely identifies the account on the provider side." + } + }, + "required": [ + "user_id", + "provider", + "provider_account_id" + ] + } + }, + "pagination": { + "type": "object", + "properties": { + "next_cursor": { + "type": "string", + "example": "b3d396b8-c574-4c80-97b3-50031675ceb2", + "description": "The cursor to fetch the next page of results. null if there is no next page." + } + }, + "required": [] + } + }, + "required": [ + "items" + ] + } + } + } + } + } + } + }, + "/contact-channels": { + "get": { + "summary": "List contact channels", + "description": "Retrieves a list of all contact channels for a user.", + "parameters": [ + { + "name": "user_id", + "in": "query", + "schema": { + "type": "string", + "example": "3241a285-8329-4d69-8f3d-316e08cf140c", + "description": "The ID of the user, or the special value `me` for the currently authenticated user" + }, + "description": "The ID of the user, or the special value `me` for the currently authenticated user", + "required": false + }, + { + "name": "contact_channel_id", + "in": "query", + "schema": { + "type": "string" + }, + "required": false + } + ], + "tags": [ + "Contact Channels" + ], + "x-full-url": "https://api.stack-auth.com/api/v1/contact-channels", + "responses": { + "200": { + "description": "Successful response", + "content": { + "application/json": { + "schema": { + "type": "object", + "properties": { + "items": { + "type": "array", + "items": { + "type": "object", + "properties": { + "user_id": { + "type": "string", + "example": "3241a285-8329-4d69-8f3d-316e08cf140c", + "description": "The unique identifier of the user" + }, + "id": { + "type": "string", + "example": "b3d396b8-c574-4c80-97b3-50031675ceb2", + "description": "The unique identifier of the contact channel" + }, + "value": { + "type": "string", + "example": "johndoe@example.com", + "description": "The value of the contact channel. For email, this should be a valid email address." + }, + "type": { + "type": "string", + "example": "email", + "description": "The type of the contact channel. Currently only \"email\" is supported." + }, + "used_for_auth": { + "type": "boolean", + "example": true, + "description": "Whether the contact channel is used for authentication. If this is set to `true`, the user will be able to sign in with the contact channel with password or OTP." + }, + "is_verified": { + "type": "boolean", + "example": true, + "description": "Whether the contact channel has been verified. If this is set to `true`, the contact channel has been verified to belong to the user." + }, + "is_primary": { + "type": "boolean", + "example": true, + "description": "Whether the contact channel is the primary contact channel. If this is set to `true`, it will be used for authentication and notifications by default." + } + }, + "required": [ + "user_id", + "id", + "value", + "type", + "used_for_auth", + "is_verified", + "is_primary" + ] + } + }, + "pagination": { + "type": "object", + "properties": { + "next_cursor": { + "type": "string", + "example": "b3d396b8-c574-4c80-97b3-50031675ceb2", + "description": "The cursor to fetch the next page of results. null if there is no next page." + } + }, + "required": [] + } + }, + "required": [ + "items" + ] + } + } + } + } + } + }, + "post": { + "summary": "Create a contact channel", + "description": "Add a new contact channel for a user.", + "parameters": [ + { + "name": "user_id", + "in": "query", + "schema": { + "type": "string", + "example": "3241a285-8329-4d69-8f3d-316e08cf140c", + "description": "The ID of the user, or the special value `me` for the currently authenticated user" + }, + "description": "The ID of the user, or the special value `me` for the currently authenticated user", + "required": false + }, + { + "name": "contact_channel_id", + "in": "query", + "schema": { + "type": "string" + }, + "required": false + } + ], + "requestBody": { + "required": true, + "content": { + "application/json": { + "schema": { + "type": "object", + "properties": { + "is_verified": { + "type": "boolean", + "example": true, + "description": "Whether the contact channel has been verified. If this is set to `true`, the contact channel has been verified to belong to the user." + }, + "user_id": { + "type": "string", + "example": "3241a285-8329-4d69-8f3d-316e08cf140c", + "description": "The ID of the user, or the special value `me` for the currently authenticated user" + }, + "value": { + "type": "string", + "example": "johndoe@example.com", + "description": "The value of the contact channel. For email, this should be a valid email address." + }, + "type": { + "type": "string", + "example": "email", + "description": "The type of the contact channel. Currently only \"email\" is supported." + }, + "used_for_auth": { + "type": "boolean", + "example": true, + "description": "Whether the contact channel is used for authentication. If this is set to `true`, the user will be able to sign in with the contact channel with password or OTP." + }, + "is_primary": { + "type": "boolean", + "example": true, + "description": "Whether the contact channel is the primary contact channel. If this is set to `true`, it will be used for authentication and notifications by default." + } + }, + "required": [ + "user_id", + "value", + "type", + "used_for_auth" + ], + "example": { + "is_verified": true, + "user_id": "3241a285-8329-4d69-8f3d-316e08cf140c", + "value": "johndoe@example.com", + "type": "email", + "used_for_auth": true, + "is_primary": true + } + } + } + } + }, + "tags": [ + "Contact Channels" + ], + "x-full-url": "https://api.stack-auth.com/api/v1/contact-channels", + "responses": { + "201": { + "description": "Successful response", + "content": { + "application/json": { + "schema": { + "type": "object", + "properties": { + "user_id": { + "type": "string", + "example": "3241a285-8329-4d69-8f3d-316e08cf140c", + "description": "The unique identifier of the user" + }, + "id": { + "type": "string", + "example": "b3d396b8-c574-4c80-97b3-50031675ceb2", + "description": "The unique identifier of the contact channel" + }, + "value": { + "type": "string", + "example": "johndoe@example.com", + "description": "The value of the contact channel. For email, this should be a valid email address." + }, + "type": { + "type": "string", + "example": "email", + "description": "The type of the contact channel. Currently only \"email\" is supported." + }, + "used_for_auth": { + "type": "boolean", + "example": true, + "description": "Whether the contact channel is used for authentication. If this is set to `true`, the user will be able to sign in with the contact channel with password or OTP." + }, + "is_verified": { + "type": "boolean", + "example": true, + "description": "Whether the contact channel has been verified. If this is set to `true`, the contact channel has been verified to belong to the user." + }, + "is_primary": { + "type": "boolean", + "example": true, + "description": "Whether the contact channel is the primary contact channel. If this is set to `true`, it will be used for authentication and notifications by default." + } + }, + "required": [ + "user_id", + "id", + "value", + "type", + "used_for_auth", + "is_verified", + "is_primary" + ] + } + } + } + } + } + } + }, + "/contact-channels/verify": { + "post": { + "summary": "Verify an email", + "description": "Verify an email address of a user", + "parameters": [], + "requestBody": { + "required": true, + "content": { + "application/json": { + "schema": { + "type": "object", + "properties": { + "code": { + "type": "string", + "example": "u3h6gn4w24pqc8ya679inrhjwh1rybth6a7thurqhnpf2", + "description": "A 45 character code" + } + }, + "required": [ + "code" + ], + "example": { + "code": "u3h6gn4w24pqc8ya679inrhjwh1rybth6a7thurqhnpf2" + } + } + } + } + }, + "tags": [ + "Contact Channels" + ], + "x-full-url": "https://api.stack-auth.com/api/v1/contact-channels/verify", + "responses": { + "200": { + "description": "Successful response", + "content": { + "application/json": { + "schema": { + "type": "object", + "properties": { + "success": { + "type": "boolean", + "description": "Always equal to true.", + "example": true + } + }, + "required": [ + "success" + ] + } + } + } + } + } + } + }, + "/contact-channels/verify/check-code": { + "post": { + "summary": "Check email verification code", + "description": "Check if an email verification code is valid without using it", + "parameters": [], + "requestBody": { + "required": true, + "content": { + "application/json": { + "schema": { + "type": "object", + "properties": { + "code": { + "type": "string", + "example": "u3h6gn4w24pqc8ya679inrhjwh1rybth6a7thurqhnpf2", + "description": "A 45 character code" + } + }, + "required": [ + "code" + ], + "example": { + "code": "u3h6gn4w24pqc8ya679inrhjwh1rybth6a7thurqhnpf2" + } + } + } + } + }, + "tags": [ + "Contact Channels" + ], + "x-full-url": "https://api.stack-auth.com/api/v1/contact-channels/verify/check-code", + "responses": { + "200": { + "description": "Successful response", + "content": { + "application/json": { + "schema": { + "type": "object", + "properties": { + "is_code_valid": { + "type": "boolean" + } + }, + "required": [ + "is_code_valid" + ] + } + } + } + } + } + } + }, + "/contact-channels/{user_id}/{contact_channel_id}": { + "get": { + "summary": "Get a contact channel", + "description": "Retrieves a specific contact channel by the user ID and the contact channel ID.", + "parameters": [ + { + "name": "user_id", + "in": "query", + "schema": { + "type": "string", + "example": "3241a285-8329-4d69-8f3d-316e08cf140c", + "description": "The ID of the user, or the special value `me` for the currently authenticated user" + }, + "description": "The ID of the user, or the special value `me` for the currently authenticated user", + "required": false + }, + { + "name": "contact_channel_id", + "in": "query", + "schema": { + "type": "string" + }, + "required": false + }, + { + "name": "user_id", + "in": "path", + "schema": { + "type": "string", + "example": "me", + "description": "the user that the contact channel belongs to" + }, + "description": "the user that the contact channel belongs to", + "required": true + }, + { + "name": "contact_channel_id", + "in": "path", + "schema": { + "type": "string", + "example": "b3d396b8-c574-4c80-97b3-50031675ceb2", + "description": "the target contact channel" + }, + "description": "the target contact channel", + "required": true + } + ], + "tags": [ + "Contact Channels" + ], + "x-full-url": "https://api.stack-auth.com/api/v1/contact-channels/{user_id}/{contact_channel_id}", + "responses": { + "200": { + "description": "Successful response", + "content": { + "application/json": { + "schema": { + "type": "object", + "properties": { + "user_id": { + "type": "string", + "example": "3241a285-8329-4d69-8f3d-316e08cf140c", + "description": "The unique identifier of the user" + }, + "id": { + "type": "string", + "example": "b3d396b8-c574-4c80-97b3-50031675ceb2", + "description": "The unique identifier of the contact channel" + }, + "value": { + "type": "string", + "example": "johndoe@example.com", + "description": "The value of the contact channel. For email, this should be a valid email address." + }, + "type": { + "type": "string", + "example": "email", + "description": "The type of the contact channel. Currently only \"email\" is supported." + }, + "used_for_auth": { + "type": "boolean", + "example": true, + "description": "Whether the contact channel is used for authentication. If this is set to `true`, the user will be able to sign in with the contact channel with password or OTP." + }, + "is_verified": { + "type": "boolean", + "example": true, + "description": "Whether the contact channel has been verified. If this is set to `true`, the contact channel has been verified to belong to the user." + }, + "is_primary": { + "type": "boolean", + "example": true, + "description": "Whether the contact channel is the primary contact channel. If this is set to `true`, it will be used for authentication and notifications by default." + } + }, + "required": [ + "user_id", + "id", + "value", + "type", + "used_for_auth", + "is_verified", + "is_primary" + ] + } + } + } + } + } + }, + "delete": { + "summary": "Delete a contact channel", + "description": "Removes a contact channel for a given user.", + "parameters": [ + { + "name": "user_id", + "in": "query", + "schema": { + "type": "string", + "example": "3241a285-8329-4d69-8f3d-316e08cf140c", + "description": "The ID of the user, or the special value `me` for the currently authenticated user" + }, + "description": "The ID of the user, or the special value `me` for the currently authenticated user", + "required": false + }, + { + "name": "contact_channel_id", + "in": "query", + "schema": { + "type": "string" + }, + "required": false + }, + { + "name": "user_id", + "in": "path", + "schema": { + "type": "string", + "example": "me", + "description": "the user that the contact channel belongs to" + }, + "description": "the user that the contact channel belongs to", + "required": true + }, + { + "name": "contact_channel_id", + "in": "path", + "schema": { + "type": "string", + "example": "b3d396b8-c574-4c80-97b3-50031675ceb2", + "description": "the target contact channel" + }, + "description": "the target contact channel", + "required": true + } + ], + "tags": [ + "Contact Channels" + ], + "x-full-url": "https://api.stack-auth.com/api/v1/contact-channels/{user_id}/{contact_channel_id}", + "responses": { + "200": { + "description": "Successful response", + "content": { + "application/json": { + "schema": { + "type": "object", + "properties": { + "success": { + "type": "boolean", + "description": "Always equal to true.", + "example": true + } + }, + "required": [ + "success" + ] + } + } + } + } + } + }, + "patch": { + "summary": "Update a contact channel", + "description": "Updates an existing contact channel. Only the values provided will be updated.", + "parameters": [ + { + "name": "user_id", + "in": "query", + "schema": { + "type": "string", + "example": "3241a285-8329-4d69-8f3d-316e08cf140c", + "description": "The ID of the user, or the special value `me` for the currently authenticated user" + }, + "description": "The ID of the user, or the special value `me` for the currently authenticated user", + "required": false + }, + { + "name": "contact_channel_id", + "in": "query", + "schema": { + "type": "string" + }, + "required": false + }, + { + "name": "user_id", + "in": "path", + "schema": { + "type": "string", + "example": "me", + "description": "the user that the contact channel belongs to" + }, + "description": "the user that the contact channel belongs to", + "required": true + }, + { + "name": "contact_channel_id", + "in": "path", + "schema": { + "type": "string", + "example": "b3d396b8-c574-4c80-97b3-50031675ceb2", + "description": "the target contact channel" + }, + "description": "the target contact channel", + "required": true + } + ], + "requestBody": { + "required": true, + "content": { + "application/json": { + "schema": { + "type": "object", + "properties": { + "is_verified": { + "type": "boolean", + "example": true, + "description": "Whether the contact channel has been verified. If this is set to `true`, the contact channel has been verified to belong to the user." + }, + "value": { + "type": "string", + "example": "johndoe@example.com", + "description": "The value of the contact channel. For email, this should be a valid email address." + }, + "type": { + "type": "string", + "example": "email", + "description": "The type of the contact channel. Currently only \"email\" is supported." + }, + "used_for_auth": { + "type": "boolean", + "example": true, + "description": "Whether the contact channel is used for authentication. If this is set to `true`, the user will be able to sign in with the contact channel with password or OTP." + }, + "is_primary": { + "type": "boolean", + "example": true, + "description": "Whether the contact channel is the primary contact channel. If this is set to `true`, it will be used for authentication and notifications by default." + } + }, + "example": { + "is_verified": true, + "value": "johndoe@example.com", + "type": "email", + "used_for_auth": true, + "is_primary": true + } + } + } + } + }, + "tags": [ + "Contact Channels" + ], + "x-full-url": "https://api.stack-auth.com/api/v1/contact-channels/{user_id}/{contact_channel_id}", + "responses": { + "200": { + "description": "Successful response", + "content": { + "application/json": { + "schema": { + "type": "object", + "properties": { + "user_id": { + "type": "string", + "example": "3241a285-8329-4d69-8f3d-316e08cf140c", + "description": "The unique identifier of the user" + }, + "id": { + "type": "string", + "example": "b3d396b8-c574-4c80-97b3-50031675ceb2", + "description": "The unique identifier of the contact channel" + }, + "value": { + "type": "string", + "example": "johndoe@example.com", + "description": "The value of the contact channel. For email, this should be a valid email address." + }, + "type": { + "type": "string", + "example": "email", + "description": "The type of the contact channel. Currently only \"email\" is supported." + }, + "used_for_auth": { + "type": "boolean", + "example": true, + "description": "Whether the contact channel is used for authentication. If this is set to `true`, the user will be able to sign in with the contact channel with password or OTP." + }, + "is_verified": { + "type": "boolean", + "example": true, + "description": "Whether the contact channel has been verified. If this is set to `true`, the contact channel has been verified to belong to the user." + }, + "is_primary": { + "type": "boolean", + "example": true, + "description": "Whether the contact channel is the primary contact channel. If this is set to `true`, it will be used for authentication and notifications by default." + } + }, + "required": [ + "user_id", + "id", + "value", + "type", + "used_for_auth", + "is_verified", + "is_primary" + ] + } + } + } + } + } + } + }, + "/contact-channels/{user_id}/{contact_channel_id}/send-verification-code": { + "post": { + "summary": "Send contact channel verification code", + "description": "Send a code to the user's contact channel for verifying the contact channel.", + "parameters": [ + { + "name": "user_id", + "in": "path", + "schema": { + "type": "string", + "example": "me", + "description": "The user to send the verification code to." + }, + "description": "The user to send the verification code to.", + "required": true + }, + { + "name": "contact_channel_id", + "in": "path", + "schema": { + "type": "string", + "example": "b3d396b8-c574-4c80-97b3-50031675ceb2", + "description": "The contact channel to send the verification code to." + }, + "description": "The contact channel to send the verification code to.", + "required": true + } + ], + "requestBody": { + "required": true, + "content": { + "application/json": { + "schema": { + "type": "object", + "properties": { + "callback_url": { + "type": "string", + "example": "https://example.com/handler/email-verification", + "description": "The base callback URL to construct a verification link for the verification e-mail. A query parameter `code` with the verification code will be appended to it. The page should then make a request to the `/contact-channels/verify` endpoint." + } + }, + "required": [ + "callback_url" + ], + "example": { + "callback_url": "https://example.com/handler/email-verification" + } + } + } + } + }, + "tags": [ + "Contact Channels" + ], + "x-full-url": "https://api.stack-auth.com/api/v1/contact-channels/{user_id}/{contact_channel_id}/send-verification-code", + "responses": { + "200": { + "description": "Successful response", + "content": { + "application/json": { + "schema": { + "type": "object", + "properties": { + "success": { + "type": "boolean", + "description": "Always equal to true.", + "example": true + } + }, + "required": [ + "success" + ] + } + } + } + } + } + } + }, + "/data-vault/stores/{id}/get": { + "post": { + "summary": "Retrieve encrypted value from data vault", + "description": "Retrieves and decrypts a value from the data vault using a hashed key", + "parameters": [ + { + "name": "id", + "in": "path", + "schema": { + "type": "string" + }, + "required": true + } + ], + "requestBody": { + "required": true, + "content": { + "application/json": { + "schema": { + "type": "object", + "properties": { + "hashed_key": { + "type": "string" + } + }, + "required": [ + "hashed_key" + ], + "example": {} + } + } + } + }, + "tags": [ + "DataVault" + ], + "x-full-url": "https://api.stack-auth.com/api/v1/data-vault/stores/{id}/get", + "responses": { + "200": { + "description": "Successful response", + "content": { + "application/json": { + "schema": { + "type": "object", + "properties": { + "encrypted_value": { + "type": "string" + } + }, + "required": [ + "encrypted_value" + ] + } + } + } + } + } + } + }, + "/data-vault/stores/{id}/set": { + "post": { + "summary": "Store encrypted value in data vault", + "description": "Stores a hashed key and encrypted value in the data vault for a specific store", + "parameters": [ + { + "name": "id", + "in": "path", + "schema": { + "type": "string" + }, + "required": true + } + ], + "requestBody": { + "required": true, + "content": { + "application/json": { + "schema": { + "type": "object", + "properties": { + "hashed_key": { + "type": "string" + }, + "encrypted_value": { + "type": "string" + } + }, + "required": [ + "hashed_key", + "encrypted_value" + ], + "example": {} + } + } + } + }, + "tags": [ + "DataVault" + ], + "x-full-url": "https://api.stack-auth.com/api/v1/data-vault/stores/{id}/set", + "responses": { + "200": { + "description": "Successful response", + "content": { + "application/json": { + "schema": { + "type": "object", + "properties": { + "success": { + "type": "boolean", + "description": "Always equal to true.", + "example": true + } + }, + "required": [ + "success" + ] + } + } + } + } + } + } + }, + "/emails/capacity-boost": { + "post": { + "summary": "Activate email capacity boost", + "description": "Temporarily increases email capacity by 4x for 4 hours.", + "parameters": [], + "tags": [ + "Emails" + ], + "x-full-url": "https://api.stack-auth.com/api/v1/emails/capacity-boost", + "responses": { + "200": { + "description": "Successful response", + "content": { + "application/json": { + "schema": { + "type": "object", + "properties": { + "expires_at": { + "type": "string" + } + }, + "required": [ + "expires_at" + ] + } + } + } + } + } + } + }, + "/emails/delivery-info": { + "get": { + "summary": "Get email delivery info", + "description": "Returns delivery statistics and capacity information for the current tenancy.", + "parameters": [], + "tags": [ + "Emails" + ], + "x-full-url": "https://api.stack-auth.com/api/v1/emails/delivery-info", + "responses": { + "200": { + "description": "Successful response", + "content": { + "application/json": { + "schema": { + "type": "object", + "properties": { + "stats": { + "type": "object", + "properties": { + "hour": { + "type": "object", + "properties": { + "sent": { + "type": "number" + }, + "bounced": { + "type": "number" + }, + "marked_as_spam": { + "type": "number" + } + }, + "required": [ + "sent", + "bounced", + "marked_as_spam" + ] + }, + "day": { + "type": "object", + "properties": { + "sent": { + "type": "number" + }, + "bounced": { + "type": "number" + }, + "marked_as_spam": { + "type": "number" + } + }, + "required": [ + "sent", + "bounced", + "marked_as_spam" + ] + }, + "week": { + "type": "object", + "properties": { + "sent": { + "type": "number" + }, + "bounced": { + "type": "number" + }, + "marked_as_spam": { + "type": "number" + } + }, + "required": [ + "sent", + "bounced", + "marked_as_spam" + ] + }, + "month": { + "type": "object", + "properties": { + "sent": { + "type": "number" + }, + "bounced": { + "type": "number" + }, + "marked_as_spam": { + "type": "number" + } + }, + "required": [ + "sent", + "bounced", + "marked_as_spam" + ] + } + }, + "required": [ + "hour", + "day", + "week", + "month" + ] + }, + "capacity": { + "type": "object", + "properties": { + "rate_per_second": { + "type": "number" + }, + "boost_multiplier": { + "type": "number" + }, + "penalty_factor": { + "type": "number" + }, + "is_boost_active": { + "type": "boolean" + }, + "boost_expires_at": { + "type": "string" + } + }, + "required": [ + "rate_per_second", + "boost_multiplier", + "penalty_factor", + "is_boost_active" + ] + } + }, + "required": [ + "stats", + "capacity" + ] + } + } + } + } + } + } + }, + "/emails/notification-preference/{user_id}": { + "get": { + "summary": "List notification preferences", + "description": "Get all notification preferences for a user, showing which notification categories are enabled or disabled.", + "parameters": [ + { + "name": "user_id", + "in": "path", + "schema": { + "type": "string", + "example": "3241a285-8329-4d69-8f3d-316e08cf140c", + "description": "The ID of the user, or the special value `me` for the currently authenticated user" + }, + "description": "The ID of the user, or the special value `me` for the currently authenticated user", + "required": false + } + ], + "tags": [ + "Emails" + ], + "x-full-url": "https://api.stack-auth.com/api/v1/emails/notification-preference/{user_id}", + "responses": { + "200": { + "description": "Successful response", + "content": { + "application/json": { + "schema": { + "type": "object", + "properties": { + "items": { + "type": "array", + "items": { + "type": "object", + "properties": { + "notification_category_id": { + "type": "string" + }, + "notification_category_name": { + "type": "string" + }, + "enabled": { + "type": "boolean" + }, + "can_disable": { + "type": "boolean" + } + }, + "required": [ + "notification_category_id", + "notification_category_name", + "enabled", + "can_disable" + ] + } + }, + "pagination": { + "type": "object", + "properties": { + "next_cursor": { + "type": "string", + "example": "b3d396b8-c574-4c80-97b3-50031675ceb2", + "description": "The cursor to fetch the next page of results. null if there is no next page." + } + }, + "required": [] + } + }, + "required": [ + "items" + ] + } + } + } + } + } + } + }, + "/emails/notification-preference/{user_id}/{notification_category_id}": { + "patch": { + "summary": "Update notification preference", + "description": "Enable or disable a specific notification category for a user.", + "parameters": [ + { + "name": "user_id", + "in": "path", + "schema": { + "type": "string", + "example": "3241a285-8329-4d69-8f3d-316e08cf140c", + "description": "The ID of the user, or the special value `me` for the currently authenticated user" + }, + "description": "The ID of the user, or the special value `me` for the currently authenticated user", + "required": true + }, + { + "name": "notification_category_id", + "in": "path", + "schema": { + "type": "string" + }, + "required": false + } + ], + "requestBody": { + "required": true, + "content": { + "application/json": { + "schema": { + "type": "object", + "properties": { + "enabled": { + "type": "boolean" + } + }, + "required": [ + "enabled" + ], + "example": {} + } + } + } + }, + "tags": [ + "Emails" + ], + "x-full-url": "https://api.stack-auth.com/api/v1/emails/notification-preference/{user_id}/{notification_category_id}", + "responses": { + "200": { + "description": "Successful response", + "content": { + "application/json": { + "schema": { + "type": "object", + "properties": { + "notification_category_id": { + "type": "string" + }, + "notification_category_name": { + "type": "string" + }, + "enabled": { + "type": "boolean" + }, + "can_disable": { + "type": "boolean" + } + }, + "required": [ + "notification_category_id", + "notification_category_name", + "enabled", + "can_disable" + ] + } + } + } + } + } + } + }, + "/emails/outbox": { + "get": { + "summary": "List email outbox", + "description": "Lists all emails in the outbox with optional filtering by status or simple_status.", + "parameters": [ + { + "name": "status", + "in": "query", + "schema": { + "type": "string" + }, + "required": false + }, + { + "name": "simple_status", + "in": "query", + "schema": { + "type": "string" + }, + "required": false + }, + { + "name": "limit", + "in": "query", + "schema": { + "type": "string", + "description": "The maximum number of items to return. Maximum allowed is 100" + }, + "description": "The maximum number of items to return. Maximum allowed is 100", + "required": false + }, + { + "name": "cursor", + "in": "query", + "schema": { + "type": "string", + "description": "The cursor to start the result set from (email ID)" + }, + "description": "The cursor to start the result set from (email ID)", + "required": false + } + ], + "tags": [ + "Emails" + ], + "x-full-url": "https://api.stack-auth.com/api/v1/emails/outbox", + "responses": { + "200": { + "description": "Successful response", + "content": { + "application/json": { + "schema": { + "type": "object", + "properties": { + "items": { + "type": "array", + "items": { + "type": "object" + } + }, + "pagination": { + "type": "object", + "properties": { + "next_cursor": { + "type": "string", + "example": "b3d396b8-c574-4c80-97b3-50031675ceb2", + "description": "The cursor to fetch the next page of results. null if there is no next page." + } + }, + "required": [] + } + }, + "required": [ + "items" + ] + } + } + } + } + } + } + }, + "/emails/outbox/{id}": { + "get": { + "summary": "Get email outbox entry", + "description": "Gets a single email from the outbox by ID.", + "parameters": [ + { + "name": "status", + "in": "query", + "schema": { + "type": "string" + }, + "required": false + }, + { + "name": "simple_status", + "in": "query", + "schema": { + "type": "string" + }, + "required": false + }, + { + "name": "id", + "in": "path", + "schema": { + "type": "string" + }, + "required": false + } + ], + "tags": [ + "Emails" + ], + "x-full-url": "https://api.stack-auth.com/api/v1/emails/outbox/{id}", + "responses": { + "200": { + "description": "Successful response", + "content": { + "application/json": { + "schema": {} + } + } + } + } + }, + "patch": { + "summary": "Update email outbox entry", + "description": "Updates an email in the outbox. Can be used to edit email content, pause/resume, or cancel emails. Only emails in editable states (`paused`, `preparing`, `rendering`, `render-error`, `scheduled`, `queued`, `server-error`) can be modified.", + "parameters": [ + { + "name": "status", + "in": "query", + "schema": { + "type": "string" + }, + "required": false + }, + { + "name": "simple_status", + "in": "query", + "schema": { + "type": "string" + }, + "required": false + }, + { + "name": "id", + "in": "path", + "schema": { + "type": "string" + }, + "required": false + } + ], + "requestBody": { + "required": true, + "content": { + "application/json": { + "schema": { + "type": "object", + "properties": { + "tsx_source": { + "type": "string" + }, + "theme_id": { + "type": "string" + }, + "to": { + "type": "object" + }, + "variables": { + "type": "object", + "properties": {}, + "required": [] + }, + "skip_deliverability_check": { + "type": "boolean" + }, + "scheduled_at_millis": { + "type": "number" + }, + "is_paused": { + "type": "boolean" + }, + "cancel": { + "type": "boolean" + } + }, + "example": {} + } + } + } + }, + "tags": [ + "Emails" + ], + "x-full-url": "https://api.stack-auth.com/api/v1/emails/outbox/{id}", + "responses": { + "200": { + "description": "Successful response", + "content": { + "application/json": { + "schema": {} + } + } + } + } + } + }, + "/emails/render-email": { + "post": { + "summary": "Render email theme", + "description": "Renders HTML content using the specified email theme", + "parameters": [], + "tags": [ + "Emails" + ], + "x-full-url": "https://api.stack-auth.com/api/v1/emails/render-email", + "responses": { + "200": { + "description": "Successful response", + "content": { + "application/json": { + "schema": { + "type": "object", + "properties": { + "html": { + "type": "string" + }, + "subject": { + "type": "string" + }, + "notification_category": { + "type": "string" + }, + "editable_regions": { + "type": "object" + } + }, + "required": [ + "html" + ] + } + } + } + } + } + } + }, + "/emails/send-email": { + "post": { + "summary": "Send email", + "description": "Send an email to a list of users. The content field should contain either {html} for HTML emails, {template_id, variables} for template-based emails, or {draft_id} for a draft email.", + "parameters": [], + "tags": [ + "Emails" + ], + "x-full-url": "https://api.stack-auth.com/api/v1/emails/send-email", + "responses": { + "200": { + "description": "Successful response", + "content": { + "application/json": { + "schema": { + "type": "object", + "properties": { + "results": { + "type": "array", + "items": { + "type": "object", + "properties": { + "user_id": { + "type": "string" + } + }, + "required": [ + "user_id" + ] + } + } + }, + "required": [ + "results" + ] + } + } + } + } + } + } + }, + "/internal/feature-requests": { + "get": { + "summary": "Get feature requests", + "description": "Fetch all feature requests with upvote status for the current user", + "parameters": [], + "tags": [ + "Internal" + ], + "x-full-url": "https://api.stack-auth.com/api/v1/internal/feature-requests", + "responses": { + "200": { + "description": "Successful response", + "content": { + "application/json": { + "schema": { + "type": "object", + "properties": { + "posts": { + "type": "array", + "items": { + "type": "object", + "properties": { + "id": { + "type": "string" + }, + "title": { + "type": "string" + }, + "content": { + "type": "string" + }, + "upvotes": { + "type": "number" + }, + "date": { + "type": "string" + }, + "postStatus": { + "type": "object", + "properties": { + "name": { + "type": "string" + }, + "color": { + "type": "string" + } + }, + "required": [ + "name", + "color" + ] + }, + "userHasUpvoted": { + "type": "boolean" + } + }, + "required": [ + "id", + "title", + "upvotes", + "date", + "userHasUpvoted" + ] + } + } + }, + "required": [ + "posts" + ] + } + } + } + } + } + }, + "post": { + "summary": "Create feature request", + "description": "Create a new feature request", + "parameters": [], + "requestBody": { + "required": true, + "content": { + "application/json": { + "schema": { + "type": "object", + "properties": { + "title": { + "type": "string" + }, + "content": { + "type": "string" + }, + "category": { + "type": "string" + }, + "tags": { + "type": "array", + "items": { + "type": "string" + } + }, + "commentsAllowed": { + "type": "boolean" + }, + "customInputValues": { + "type": "object", + "properties": {}, + "required": [] + } + }, + "required": [ + "title" + ], + "example": {} + } + } + } + }, + "tags": [ + "Internal" + ], + "x-full-url": "https://api.stack-auth.com/api/v1/internal/feature-requests", + "responses": { + "200": { + "description": "Successful response", + "content": { + "application/json": { + "schema": { + "type": "object", + "properties": { + "success": { + "type": "boolean" + }, + "id": { + "type": "string" + } + }, + "required": [ + "success" + ] + } + } + } + } + } + } + }, + "/internal/feature-requests/{featureRequestId}/upvote": { + "post": { + "summary": "Toggle upvote on feature request", + "description": "Toggle upvote on a feature request for the current user", + "parameters": [ + { + "name": "featureRequestId", + "in": "path", + "schema": { + "type": "string" + }, + "required": true + } + ], + "requestBody": { + "required": true, + "content": { + "application/json": { + "schema": { + "type": "object", + "properties": {}, + "example": {} + } + } + } + }, + "tags": [ + "Internal" + ], + "x-full-url": "https://api.stack-auth.com/api/v1/internal/feature-requests/{featureRequestId}/upvote", + "responses": { + "200": { + "description": "Successful response", + "content": { + "application/json": { + "schema": { + "type": "object", + "properties": { + "success": { + "type": "boolean" + }, + "upvoted": { + "type": "boolean" + } + }, + "required": [ + "success" + ] + } + } + } + } + } + } + }, + "/internal/feedback": { + "post": { + "summary": "Submit support feedback", + "description": "Send a support feedback message to the internal Stack Auth inbox. Auth is optional — works from both the dashboard (authenticated) and the dev tool (unauthenticated).", + "parameters": [], + "requestBody": { + "required": true, + "content": { + "application/json": { + "schema": { + "type": "object", + "properties": { + "name": { + "type": "string" + }, + "email": { + "type": "string" + }, + "message": { + "type": "string" + }, + "feedback_type": { + "type": "string" + } + }, + "required": [ + "email", + "message" + ], + "example": {} + } + } + } + }, + "tags": [ + "Internal" + ], + "x-full-url": "https://api.stack-auth.com/api/v1/internal/feedback", + "responses": { + "200": { + "description": "Successful response", + "content": { + "application/json": { + "schema": { + "type": "object", + "properties": { + "success": { + "type": "boolean" + } + }, + "required": [ + "success" + ] + } + } + } + } + } + } + }, + "/internal/preview/create-project": { + "post": { + "summary": "Create a preview project", + "description": "Creates a new project pre-filled with dummy data for the preview environment. Only available when NEXT_PUBLIC_STACK_IS_PREVIEW=true.", + "parameters": [], + "requestBody": { + "required": true, + "content": { + "application/json": { + "schema": { + "type": "object", + "properties": {}, + "example": {} + } + } + } + }, + "tags": [ + "Internal" + ], + "x-full-url": "https://api.stack-auth.com/api/v1/internal/preview/create-project", + "responses": { + "200": { + "description": "Successful response", + "content": { + "application/json": { + "schema": { + "type": "object", + "properties": { + "project_id": { + "type": "string" + } + }, + "required": [ + "project_id" + ] + } + } + } + } + } + } + }, + "/auth/oauth/authorize/{provider_id}": { + "get": { + "summary": "OAuth authorize endpoint", + "description": "This endpoint is used to initiate the OAuth authorization flow. there are two purposes for this endpoint: 1. Authenticate a user with an OAuth provider. 2. Link an existing user with an OAuth provider.", + "parameters": [ + { + "name": "type", + "in": "query", + "schema": { + "type": "string", + "default": "authenticate" + }, + "required": false + }, + { + "name": "token", + "in": "query", + "schema": { + "type": "string", + "default": "" + }, + "required": false + }, + { + "name": "provider_scope", + "in": "query", + "schema": { + "type": "string" + }, + "required": false + }, + { + "name": "error_redirect_uri", + "in": "query", + "schema": { + "type": "string" + }, + "required": false + }, + { + "name": "after_callback_redirect_url", + "in": "query", + "schema": { + "type": "string" + }, + "required": false + }, + { + "name": "stack_response_mode", + "in": "query", + "schema": { + "type": "string", + "default": "redirect" + }, + "required": false + }, + { + "name": "bot_challenge_token", + "in": "query", + "schema": { + "type": "string" + }, + "required": false + }, + { + "name": "bot_challenge_phase", + "in": "query", + "schema": { + "type": "string" + }, + "required": false + }, + { + "name": "bot_challenge_unavailable", + "in": "query", + "schema": { + "type": "string" + }, + "required": false + }, + { + "name": "client_id", + "in": "query", + "schema": { + "type": "string" + }, + "required": true + }, + { + "name": "client_secret", + "in": "query", + "schema": { + "type": "string" + }, + "required": true + }, + { + "name": "redirect_uri", + "in": "query", + "schema": { + "type": "string" + }, + "required": true + }, + { + "name": "scope", + "in": "query", + "schema": { + "type": "string" + }, + "required": true + }, + { + "name": "state", + "in": "query", + "schema": { + "type": "string" + }, + "required": true + }, + { + "name": "grant_type", + "in": "query", + "schema": { + "type": "string" + }, + "required": true + }, + { + "name": "code_challenge", + "in": "query", + "schema": { + "type": "string" + }, + "required": true + }, + { + "name": "code_challenge_method", + "in": "query", + "schema": { + "type": "string" + }, + "required": true + }, + { + "name": "response_type", + "in": "query", + "schema": { + "type": "string" + }, + "required": true + }, + { + "name": "provider_id", + "in": "path", + "schema": { + "type": "string" + }, + "required": true + } + ], + "tags": [ + "Oauth" + ], + "x-full-url": "https://api.stack-auth.com/api/v1/auth/oauth/authorize/{provider_id}", + "responses": { + "200": { + "description": "Successful response", + "content": { + "application/json": { + "schema": { + "type": "object", + "properties": { + "location": { + "type": "string" + } + }, + "required": [ + "location" + ] + } + } + } + }, + "307": { + "description": "Successful response", + "content": { + "text/plain": { + "schema": { + "type": "string" + } + } + } + } + } + } + }, + "/auth/oauth/cross-domain/authorize": { + "post": { + "summary": "Create cross-domain auth handoff redirect", + "description": "Creates a one-time OAuth authorization code redirect for cross-domain sign-in handoff using PKCE.", + "parameters": [ + { + "name": "x-stack-publishable-client-key", + "in": "header", + "schema": { + "type": "string" + }, + "required": true + }, + { + "name": "x-stack-refresh-token", + "in": "header", + "schema": { + "type": "string" + }, + "required": true + } + ], + "requestBody": { + "required": true, + "content": { + "application/json": { + "schema": { + "type": "object", + "properties": { + "redirect_uri": { + "type": "string" + }, + "state": { + "type": "string" + }, + "code_challenge": { + "type": "string" + }, + "code_challenge_method": { + "type": "string", + "default": "S256" + }, + "after_callback_redirect_url": { + "type": "string" + } + }, + "required": [ + "redirect_uri", + "state", + "code_challenge" + ], + "example": {} + } + } + } + }, + "tags": [ + "Oauth" + ], + "x-full-url": "https://api.stack-auth.com/api/v1/auth/oauth/cross-domain/authorize", + "responses": { + "200": { + "description": "Successful response", + "content": { + "application/json": { + "schema": { + "type": "object", + "properties": { + "redirect_url": { + "type": "string" + } + }, + "required": [ + "redirect_url" + ] + } + } + } + } + } + } + }, + "/auth/oauth/token": { + "post": { + "summary": "OAuth token endpoints", + "description": "This endpoint is used to exchange an authorization code or refresh token for an access token.", + "parameters": [], + "requestBody": { + "required": true, + "content": { + "application/json": { + "schema": { + "type": "object", + "properties": { + "grant_type": { + "type": "string" + }, + "client_id": { + "type": "string" + }, + "client_secret": { + "type": "string" + } + }, + "required": [ + "grant_type" + ], + "example": {} + } + } + } + }, + "tags": [ + "Oauth" + ], + "x-full-url": "https://api.stack-auth.com/api/v1/auth/oauth/token", + "responses": { + "200": { + "description": "Successful response", + "content": { + "application/json": { + "schema": {} + } + } + } + } + } + }, + "/oauth-providers": { + "get": { + "summary": "List OAuth providers", + "description": "Retrieves a list of all OAuth providers for a user.", + "parameters": [ + { + "name": "user_id", + "in": "query", + "schema": { + "type": "string" + }, + "required": false + } + ], + "tags": [ + "Oauth" + ], + "x-full-url": "https://api.stack-auth.com/api/v1/oauth-providers", + "responses": { + "200": { + "description": "Successful response", + "content": { + "application/json": { + "schema": { + "type": "object", + "properties": { + "items": { + "type": "array", + "items": { + "type": "object", + "properties": { + "account_id": { + "type": "string", + "example": "google-account-id-12345", + "description": "Account ID of the OAuth provider. This uniquely identifies the account on the provider side." + }, + "user_id": { + "type": "string", + "example": "3241a285-8329-4d69-8f3d-316e08cf140c", + "description": "The ID of the user, or the special value `me` for the currently authenticated user" + }, + "id": { + "type": "string", + "example": "b3d396b8-c574-4c80-97b3-50031675ceb2", + "description": "The unique identifier of the OAuth provider" + }, + "email": { + "type": "string", + "example": "test@gmail.com", + "description": "Email of the OAuth provider. This is used to display and identify the OAuth provider in the UI." + }, + "provider_config_id": { + "type": "string", + "example": "google", + "description": "Provider config ID of the OAuth provider. This uniquely identifies the provider config on config.json file" + }, + "type": { + "type": "string", + "example": "google", + "description": "OAuth provider type, one of `google`, `github`, `microsoft`, `spotify`, `facebook`, `discord`, `gitlab`, `bitbucket`, `linkedin`, `apple`, `x`, `twitch`" + }, + "allow_sign_in": { + "type": "boolean", + "example": true, + "description": "Whether the user can use this OAuth provider to sign in. Only one OAuth provider per type can have this set to `true`." + }, + "allow_connected_accounts": { + "type": "boolean", + "example": true, + "description": "Whether the user can use this OAuth provider as connected account. Multiple OAuth providers per type can have this set to `true`." + } + }, + "required": [ + "account_id", + "user_id", + "id", + "provider_config_id", + "type", + "allow_sign_in", + "allow_connected_accounts" + ] + } + }, + "pagination": { + "type": "object", + "properties": { + "next_cursor": { + "type": "string", + "example": "b3d396b8-c574-4c80-97b3-50031675ceb2", + "description": "The cursor to fetch the next page of results. null if there is no next page." + } + }, + "required": [] + } + }, + "required": [ + "items" + ] + } + } + } + } + } + }, + "post": { + "summary": "Create an OAuth provider", + "description": "Add a new OAuth provider for a user.", + "parameters": [], + "requestBody": { + "required": true, + "content": { + "application/json": { + "schema": { + "type": "object", + "properties": { + "user_id": { + "type": "string", + "example": "3241a285-8329-4d69-8f3d-316e08cf140c", + "description": "The ID of the user, or the special value `me` for the currently authenticated user" + }, + "provider_config_id": { + "type": "string" + }, + "email": { + "type": "string", + "example": "test@gmail.com", + "description": "Email of the OAuth provider. This is used to display and identify the OAuth provider in the UI." + }, + "allow_sign_in": { + "type": "boolean", + "example": true, + "description": "Whether the user can use this OAuth provider to sign in. Only one OAuth provider per type can have this set to `true`." + }, + "allow_connected_accounts": { + "type": "boolean", + "example": true, + "description": "Whether the user can use this OAuth provider as connected account. Multiple OAuth providers per type can have this set to `true`." + }, + "account_id": { + "type": "string", + "example": "google-account-id-12345", + "description": "Account ID of the OAuth provider. This uniquely identifies the account on the provider side." + } + }, + "required": [ + "user_id", + "provider_config_id", + "allow_sign_in", + "allow_connected_accounts", + "account_id" + ], + "example": { + "user_id": "3241a285-8329-4d69-8f3d-316e08cf140c", + "email": "test@gmail.com", + "allow_sign_in": true, + "allow_connected_accounts": true, + "account_id": "google-account-id-12345" + } + } + } + } + }, + "tags": [ + "Oauth" + ], + "x-full-url": "https://api.stack-auth.com/api/v1/oauth-providers", + "responses": { + "201": { + "description": "Successful response", + "content": { + "application/json": { + "schema": { + "type": "object", + "properties": { + "account_id": { + "type": "string", + "example": "google-account-id-12345", + "description": "Account ID of the OAuth provider. This uniquely identifies the account on the provider side." + }, + "user_id": { + "type": "string", + "example": "3241a285-8329-4d69-8f3d-316e08cf140c", + "description": "The ID of the user, or the special value `me` for the currently authenticated user" + }, + "id": { + "type": "string", + "example": "b3d396b8-c574-4c80-97b3-50031675ceb2", + "description": "The unique identifier of the OAuth provider" + }, + "email": { + "type": "string", + "example": "test@gmail.com", + "description": "Email of the OAuth provider. This is used to display and identify the OAuth provider in the UI." + }, + "provider_config_id": { + "type": "string", + "example": "google", + "description": "Provider config ID of the OAuth provider. This uniquely identifies the provider config on config.json file" + }, + "type": { + "type": "string", + "example": "google", + "description": "OAuth provider type, one of `google`, `github`, `microsoft`, `spotify`, `facebook`, `discord`, `gitlab`, `bitbucket`, `linkedin`, `apple`, `x`, `twitch`" + }, + "allow_sign_in": { + "type": "boolean", + "example": true, + "description": "Whether the user can use this OAuth provider to sign in. Only one OAuth provider per type can have this set to `true`." + }, + "allow_connected_accounts": { + "type": "boolean", + "example": true, + "description": "Whether the user can use this OAuth provider as connected account. Multiple OAuth providers per type can have this set to `true`." + } + }, + "required": [ + "account_id", + "user_id", + "id", + "provider_config_id", + "type", + "allow_sign_in", + "allow_connected_accounts" + ] + } + } + } + } + } + } + }, + "/oauth-providers/{user_id}/{provider_id}": { + "get": { + "summary": "Get an OAuth provider", + "description": "Retrieves a specific OAuth provider by the user ID and the OAuth provider ID.", + "parameters": [ + { + "name": "provider_id", + "in": "path", + "schema": { + "type": "string" + }, + "required": true + }, + { + "name": "user_id", + "in": "path", + "schema": { + "type": "string", + "example": "3241a285-8329-4d69-8f3d-316e08cf140c", + "description": "The ID of the user, or the special value `me` for the currently authenticated user" + }, + "description": "The ID of the user, or the special value `me` for the currently authenticated user", + "required": true + } + ], + "tags": [ + "Oauth" + ], + "x-full-url": "https://api.stack-auth.com/api/v1/oauth-providers/{user_id}/{provider_id}", + "responses": { + "200": { + "description": "Successful response", + "content": { + "application/json": { + "schema": { + "type": "object", + "properties": { + "account_id": { + "type": "string", + "example": "google-account-id-12345", + "description": "Account ID of the OAuth provider. This uniquely identifies the account on the provider side." + }, + "user_id": { + "type": "string", + "example": "3241a285-8329-4d69-8f3d-316e08cf140c", + "description": "The ID of the user, or the special value `me` for the currently authenticated user" + }, + "id": { + "type": "string", + "example": "b3d396b8-c574-4c80-97b3-50031675ceb2", + "description": "The unique identifier of the OAuth provider" + }, + "email": { + "type": "string", + "example": "test@gmail.com", + "description": "Email of the OAuth provider. This is used to display and identify the OAuth provider in the UI." + }, + "provider_config_id": { + "type": "string", + "example": "google", + "description": "Provider config ID of the OAuth provider. This uniquely identifies the provider config on config.json file" + }, + "type": { + "type": "string", + "example": "google", + "description": "OAuth provider type, one of `google`, `github`, `microsoft`, `spotify`, `facebook`, `discord`, `gitlab`, `bitbucket`, `linkedin`, `apple`, `x`, `twitch`" + }, + "allow_sign_in": { + "type": "boolean", + "example": true, + "description": "Whether the user can use this OAuth provider to sign in. Only one OAuth provider per type can have this set to `true`." + }, + "allow_connected_accounts": { + "type": "boolean", + "example": true, + "description": "Whether the user can use this OAuth provider as connected account. Multiple OAuth providers per type can have this set to `true`." + } + }, + "required": [ + "account_id", + "user_id", + "id", + "provider_config_id", + "type", + "allow_sign_in", + "allow_connected_accounts" + ] + } + } + } + } + } + }, + "delete": { + "summary": "Delete an OAuth provider", + "description": "Removes an OAuth provider for a given user.", + "parameters": [ + { + "name": "provider_id", + "in": "path", + "schema": { + "type": "string" + }, + "required": true + }, + { + "name": "user_id", + "in": "path", + "schema": { + "type": "string", + "example": "3241a285-8329-4d69-8f3d-316e08cf140c", + "description": "The ID of the user, or the special value `me` for the currently authenticated user" + }, + "description": "The ID of the user, or the special value `me` for the currently authenticated user", + "required": true + } + ], + "tags": [ + "Oauth" + ], + "x-full-url": "https://api.stack-auth.com/api/v1/oauth-providers/{user_id}/{provider_id}", + "responses": { + "200": { + "description": "Successful response", + "content": { + "application/json": { + "schema": { + "type": "object", + "properties": { + "success": { + "type": "boolean", + "description": "Always equal to true.", + "example": true + } + }, + "required": [ + "success" + ] + } + } + } + } + } + }, + "patch": { + "summary": "Update an OAuth provider", + "description": "Updates an existing OAuth provider. Only the values provided will be updated.", + "parameters": [ + { + "name": "provider_id", + "in": "path", + "schema": { + "type": "string" + }, + "required": true + }, + { + "name": "user_id", + "in": "path", + "schema": { + "type": "string", + "example": "3241a285-8329-4d69-8f3d-316e08cf140c", + "description": "The ID of the user, or the special value `me` for the currently authenticated user" + }, + "description": "The ID of the user, or the special value `me` for the currently authenticated user", + "required": true + } + ], + "requestBody": { + "required": true, + "content": { + "application/json": { + "schema": { + "type": "object", + "properties": { + "email": { + "type": "string", + "example": "test@gmail.com", + "description": "Email of the OAuth provider. This is used to display and identify the OAuth provider in the UI." + }, + "account_id": { + "type": "string", + "example": "google-account-id-12345", + "description": "Account ID of the OAuth provider. This uniquely identifies the account on the provider side." + }, + "allow_sign_in": { + "type": "boolean", + "example": true, + "description": "Whether the user can use this OAuth provider to sign in. Only one OAuth provider per type can have this set to `true`." + }, + "allow_connected_accounts": { + "type": "boolean", + "example": true, + "description": "Whether the user can use this OAuth provider as connected account. Multiple OAuth providers per type can have this set to `true`." + } + }, + "example": { + "email": "test@gmail.com", + "account_id": "google-account-id-12345", + "allow_sign_in": true, + "allow_connected_accounts": true + } + } + } + } + }, + "tags": [ + "Oauth" + ], + "x-full-url": "https://api.stack-auth.com/api/v1/oauth-providers/{user_id}/{provider_id}", + "responses": { + "200": { + "description": "Successful response", + "content": { + "application/json": { + "schema": { + "type": "object", + "properties": { + "account_id": { + "type": "string", + "example": "google-account-id-12345", + "description": "Account ID of the OAuth provider. This uniquely identifies the account on the provider side." + }, + "user_id": { + "type": "string", + "example": "3241a285-8329-4d69-8f3d-316e08cf140c", + "description": "The ID of the user, or the special value `me` for the currently authenticated user" + }, + "id": { + "type": "string", + "example": "b3d396b8-c574-4c80-97b3-50031675ceb2", + "description": "The unique identifier of the OAuth provider" + }, + "email": { + "type": "string", + "example": "test@gmail.com", + "description": "Email of the OAuth provider. This is used to display and identify the OAuth provider in the UI." + }, + "provider_config_id": { + "type": "string", + "example": "google", + "description": "Provider config ID of the OAuth provider. This uniquely identifies the provider config on config.json file" + }, + "type": { + "type": "string", + "example": "google", + "description": "OAuth provider type, one of `google`, `github`, `microsoft`, `spotify`, `facebook`, `discord`, `gitlab`, `bitbucket`, `linkedin`, `apple`, `x`, `twitch`" + }, + "allow_sign_in": { + "type": "boolean", + "example": true, + "description": "Whether the user can use this OAuth provider to sign in. Only one OAuth provider per type can have this set to `true`." + }, + "allow_connected_accounts": { + "type": "boolean", + "example": true, + "description": "Whether the user can use this OAuth provider as connected account. Multiple OAuth providers per type can have this set to `true`." + } + }, + "required": [ + "account_id", + "user_id", + "id", + "provider_config_id", + "type", + "allow_sign_in", + "allow_connected_accounts" + ] + } + } + } + } + } + } + }, + "/internal/ai-conversations": { + "get": { + "summary": "List AI conversations", + "description": "List AI conversations for the current user filtered by project", + "parameters": [ + { + "name": "projectId", + "in": "query", + "schema": { + "type": "string" + }, + "required": true + } + ], + "tags": [ + "Others" + ], + "x-full-url": "https://api.stack-auth.com/api/v1/internal/ai-conversations", + "responses": { + "200": { + "description": "Successful response", + "content": { + "application/json": { + "schema": { + "type": "object", + "properties": { + "conversations": { + "type": "array", + "items": { + "type": "object", + "properties": { + "id": { + "type": "string" + }, + "title": { + "type": "string" + }, + "projectId": { + "type": "string" + }, + "updatedAt": { + "type": "string" + } + }, + "required": [ + "id", + "title", + "projectId", + "updatedAt" + ] + } + } + }, + "required": [ + "conversations" + ] + } + } + } + } + } + }, + "post": { + "summary": "Create AI conversation", + "description": "Create a new AI conversation with optional initial messages", + "parameters": [], + "requestBody": { + "required": true, + "content": { + "application/json": { + "schema": { + "type": "object", + "properties": { + "title": { + "type": "string" + }, + "projectId": { + "type": "string" + }, + "messages": { + "type": "array", + "items": { + "type": "object", + "properties": { + "role": { + "type": "string" + }, + "content": { + "type": "object" + } + }, + "required": [ + "role", + "content" + ] + } + } + }, + "required": [ + "title", + "projectId", + "messages" + ], + "example": {} + } + } + } + }, + "tags": [ + "Others" + ], + "x-full-url": "https://api.stack-auth.com/api/v1/internal/ai-conversations", + "responses": { + "200": { + "description": "Successful response", + "content": { + "application/json": { + "schema": { + "type": "object", + "properties": { + "id": { + "type": "string" + }, + "title": { + "type": "string" + } + }, + "required": [ + "id", + "title" + ] + } + } + } + } + } + } + }, + "/internal/ai-conversations/{conversationId}": { + "get": { + "summary": "Get AI conversation", + "description": "Fetch a single AI conversation with all its messages", + "parameters": [ + { + "name": "conversationId", + "in": "path", + "schema": { + "type": "string" + }, + "required": true + } + ], + "tags": [ + "Others" + ], + "x-full-url": "https://api.stack-auth.com/api/v1/internal/ai-conversations/{conversationId}", + "responses": { + "200": { + "description": "Successful response", + "content": { + "application/json": { + "schema": { + "type": "object", + "properties": { + "id": { + "type": "string" + }, + "title": { + "type": "string" + }, + "projectId": { + "type": "string" + }, + "messages": { + "type": "array", + "items": { + "type": "object", + "properties": { + "id": { + "type": "string" + }, + "role": { + "type": "string" + }, + "content": { + "type": "object" + } + }, + "required": [ + "id", + "role", + "content" + ] + } + } + }, + "required": [ + "id", + "title", + "projectId", + "messages" + ] + } + } + } + } + } + }, + "delete": { + "summary": "Delete AI conversation", + "description": "Delete an AI conversation and all its messages", + "parameters": [ + { + "name": "conversationId", + "in": "path", + "schema": { + "type": "string" + }, + "required": true + } + ], + "tags": [ + "Others" + ], + "x-full-url": "https://api.stack-auth.com/api/v1/internal/ai-conversations/{conversationId}", + "responses": { + "200": { + "description": "Successful response", + "content": { + "application/json": { + "schema": { + "type": "object", + "properties": {} + } + } + } + } + } + }, + "patch": { + "summary": "Update AI conversation", + "description": "Update the title of an AI conversation", + "parameters": [ + { + "name": "conversationId", + "in": "path", + "schema": { + "type": "string" + }, + "required": true + } + ], + "requestBody": { + "required": true, + "content": { + "application/json": { + "schema": { + "type": "object", + "properties": { + "title": { + "type": "string" + } + }, + "required": [ + "title" + ], + "example": {} + } + } + } + }, + "tags": [ + "Others" + ], + "x-full-url": "https://api.stack-auth.com/api/v1/internal/ai-conversations/{conversationId}", + "responses": { + "200": { + "description": "Successful response", + "content": { + "application/json": { + "schema": { + "type": "object", + "properties": {} + } + } + } + } + } + } + }, + "/internal/ai-conversations/{conversationId}/messages": { + "put": { + "summary": "Replace conversation messages", + "description": "Replace all messages in a conversation", + "parameters": [ + { + "name": "conversationId", + "in": "path", + "schema": { + "type": "string" + }, + "required": true + } + ], + "requestBody": { + "required": true, + "content": { + "application/json": { + "schema": { + "type": "object", + "properties": { + "messages": { + "type": "array", + "items": { + "type": "object", + "properties": { + "role": { + "type": "string" + }, + "content": { + "type": "object" + } + }, + "required": [ + "role", + "content" + ] + } + } + }, + "required": [ + "messages" + ], + "example": {} + } + } + } + }, + "tags": [ + "Others" + ], + "x-full-url": "https://api.stack-auth.com/api/v1/internal/ai-conversations/{conversationId}/messages", + "responses": { + "200": { + "description": "Successful response", + "content": { + "application/json": { + "schema": { + "type": "object", + "properties": {} + } + } + } + } + } + } + }, + "/auth/mfa/sign-in": { + "post": { + "summary": "MFA sign in", + "description": "Complete multi-factor authorization to sign in, with a TOTP and an MFA attempt code", + "parameters": [], + "requestBody": { + "required": true, + "content": { + "application/json": { + "schema": { + "type": "object", + "properties": { + "type": { + "type": "string" + }, + "totp": { + "type": "string" + }, + "code": { + "type": "string", + "example": "u3h6gn4w24pqc8ya679inrhjwh1rybth6a7thurqhnpf2", + "description": "A 45 character code" + } + }, + "required": [ + "type", + "totp", + "code" + ], + "example": { + "code": "u3h6gn4w24pqc8ya679inrhjwh1rybth6a7thurqhnpf2" + } + } + } + } + }, + "tags": [ + "OTP" + ], + "x-full-url": "https://api.stack-auth.com/api/v1/auth/mfa/sign-in", + "responses": { + "200": { + "description": "Successful response", + "content": { + "application/json": { + "schema": { + "type": "object", + "properties": { + "refresh_token": { + "type": "string", + "example": "i8ns3aq2...14y", + "description": "Long-lived refresh token that can be used to obtain a new access token" + }, + "access_token": { + "type": "string", + "example": "eyJhmMiJB2TO...diI4QT", + "description": "Short-lived access token that can be used to authenticate the user" + }, + "is_new_user": { + "type": "boolean", + "example": true, + "description": "Whether the user is a new user" + }, + "user_id": { + "type": "string", + "example": "3241a285-8329-4d69-8f3d-316e08cf140c", + "description": "The unique identifier of the user" + } + }, + "required": [ + "refresh_token", + "access_token", + "is_new_user", + "user_id" + ] + } + } + } + } + } + } + }, + "/auth/otp/send-sign-in-code": { + "post": { + "summary": "Send sign-in code", + "description": "Send a code to the user's email address for sign-in.", + "parameters": [], + "requestBody": { + "required": true, + "content": { + "application/json": { + "schema": { + "type": "object", + "properties": { + "email": { + "type": "string", + "example": "johndoe@example.com", + "description": "The email to sign in with." + }, + "callback_url": { + "type": "string", + "example": "https://example.com/handler/magic-link-callback", + "description": "The base callback URL to construct the magic link from. A query parameter `code` with the verification code will be appended to it. The page should then make a request to the `/auth/otp/sign-in` endpoint." + }, + "bot_challenge_token": { + "type": "string" + }, + "bot_challenge_phase": { + "type": "string" + }, + "bot_challenge_unavailable": { + "type": "string" + } + }, + "required": [ + "email", + "callback_url" + ], + "example": { + "email": "johndoe@example.com", + "callback_url": "https://example.com/handler/magic-link-callback" + } + } + } + } + }, + "tags": [ + "OTP" + ], + "x-full-url": "https://api.stack-auth.com/api/v1/auth/otp/send-sign-in-code", + "responses": { + "200": { + "description": "Successful response", + "content": { + "application/json": { + "schema": { + "type": "object", + "properties": { + "nonce": { + "type": "string", + "example": "u3h6gn4w24pqc8ya679inrhjwh1rybth6a7thurqhnpf2", + "description": "A token that must be stored temporarily and provided when verifying the 6-digit code" + } + }, + "required": [ + "nonce" + ] + } + } + } + } + } + } + }, + "/auth/otp/sign-in": { + "post": { + "summary": "Sign in with a code", + "description": "", + "parameters": [], + "requestBody": { + "required": true, + "content": { + "application/json": { + "schema": { + "type": "object", + "properties": { + "code": { + "type": "string", + "example": "u3h6gn4w24pqc8ya679inrhjwh1rybth6a7thurqhnpf2", + "description": "A 45-character verification code. For magic links, this is the code found in the \"code\" URL query parameter. For OTP, this is formed by concatenating the 6-digit code entered by the user with the nonce (received during code creation)" + } + }, + "required": [ + "code" + ], + "example": { + "code": "u3h6gn4w24pqc8ya679inrhjwh1rybth6a7thurqhnpf2" + } + } + } + } + }, + "tags": [ + "OTP" + ], + "x-full-url": "https://api.stack-auth.com/api/v1/auth/otp/sign-in", + "responses": { + "200": { + "description": "Successful response", + "content": { + "application/json": { + "schema": { + "type": "object", + "properties": { + "refresh_token": { + "type": "string", + "example": "i8ns3aq2...14y", + "description": "Long-lived refresh token that can be used to obtain a new access token" + }, + "access_token": { + "type": "string", + "example": "eyJhmMiJB2TO...diI4QT", + "description": "Short-lived access token that can be used to authenticate the user" + }, + "is_new_user": { + "type": "boolean", + "example": true, + "description": "Whether the user is a new user" + }, + "user_id": { + "type": "string", + "example": "3241a285-8329-4d69-8f3d-316e08cf140c", + "description": "The unique identifier of the user" + } + }, + "required": [ + "refresh_token", + "access_token", + "is_new_user", + "user_id" + ] + } + } + } + } + } + } + }, + "/auth/otp/sign-in/check-code": { + "post": { + "summary": "Check sign in code", + "description": "Check if a sign in code is valid without using it", + "parameters": [], + "requestBody": { + "required": true, + "content": { + "application/json": { + "schema": { + "type": "object", + "properties": { + "code": { + "type": "string", + "example": "u3h6gn4w24pqc8ya679inrhjwh1rybth6a7thurqhnpf2", + "description": "A 45-character verification code. For magic links, this is the code found in the \"code\" URL query parameter. For OTP, this is formed by concatenating the 6-digit code entered by the user with the nonce (received during code creation)" + } + }, + "required": [ + "code" + ], + "example": { + "code": "u3h6gn4w24pqc8ya679inrhjwh1rybth6a7thurqhnpf2" + } + } + } + } + }, + "tags": [ + "OTP" + ], + "x-full-url": "https://api.stack-auth.com/api/v1/auth/otp/sign-in/check-code", + "responses": { + "200": { + "description": "Successful response", + "content": { + "application/json": { + "schema": { + "type": "object", + "properties": { + "is_code_valid": { + "type": "boolean" + } + }, + "required": [ + "is_code_valid" + ] + } + } + } + } + } + } + }, + "/auth/password/reset": { + "post": { + "summary": "Reset password with a code", + "description": "Reset password with a code", + "parameters": [], + "requestBody": { + "required": true, + "content": { + "application/json": { + "schema": { + "type": "object", + "properties": { + "password": { + "type": "string" + }, + "code": { + "type": "string", + "example": "u3h6gn4w24pqc8ya679inrhjwh1rybth6a7thurqhnpf2", + "description": "A 45 character code" + } + }, + "required": [ + "password", + "code" + ], + "example": { + "code": "u3h6gn4w24pqc8ya679inrhjwh1rybth6a7thurqhnpf2" + } + } + } + } + }, + "tags": [ + "Password" + ], + "x-full-url": "https://api.stack-auth.com/api/v1/auth/password/reset", + "responses": { + "200": { + "description": "Successful response", + "content": { + "application/json": { + "schema": { + "type": "object", + "properties": { + "success": { + "type": "boolean", + "description": "Always equal to true.", + "example": true + } + }, + "required": [ + "success" + ] + } + } + } + } + } + } + }, + "/auth/password/reset/check-code": { + "post": { + "summary": "Check reset password code", + "description": "Check if a reset password code is valid without using it", + "parameters": [], + "requestBody": { + "required": true, + "content": { + "application/json": { + "schema": { + "type": "object", + "properties": { + "code": { + "type": "string", + "example": "u3h6gn4w24pqc8ya679inrhjwh1rybth6a7thurqhnpf2", + "description": "A 45 character code" + } + }, + "required": [ + "code" + ], + "example": { + "code": "u3h6gn4w24pqc8ya679inrhjwh1rybth6a7thurqhnpf2" + } + } + } + } + }, + "tags": [ + "Password" + ], + "x-full-url": "https://api.stack-auth.com/api/v1/auth/password/reset/check-code", + "responses": { + "200": { + "description": "Successful response", + "content": { + "application/json": { + "schema": { + "type": "object", + "properties": { + "is_code_valid": { + "type": "boolean" + } + }, + "required": [ + "is_code_valid" + ] + } + } + } + } + } + } + }, + "/auth/password/send-reset-code": { + "post": { + "summary": "Send reset password code", + "description": "Send a code to the user's email address for resetting the password.", + "parameters": [], + "requestBody": { + "required": true, + "content": { + "application/json": { + "schema": { + "type": "object", + "properties": { + "email": { + "type": "string" + }, + "callback_url": { + "type": "string" + } + }, + "required": [ + "email", + "callback_url" + ], + "example": {} + } + } + } + }, + "tags": [ + "Password" + ], + "x-full-url": "https://api.stack-auth.com/api/v1/auth/password/send-reset-code", + "responses": { + "200": { + "description": "Successful response", + "content": { + "application/json": { + "schema": { + "type": "object", + "properties": { + "success": { + "type": "string" + } + }, + "required": [ + "success" + ] + } + } + } + } + } + } + }, + "/auth/password/set": { + "post": { + "summary": "Set password", + "description": "Set a new password for the current user", + "parameters": [], + "requestBody": { + "required": true, + "content": { + "application/json": { + "schema": { + "type": "object", + "properties": { + "password": { + "type": "string" + } + }, + "required": [ + "password" + ], + "example": {} + } + } + } + }, + "tags": [ + "Password" + ], + "x-full-url": "https://api.stack-auth.com/api/v1/auth/password/set", + "responses": { + "200": { + "description": "Successful response", + "content": { + "application/json": { + "schema": { + "type": "object", + "properties": { + "success": { + "type": "boolean", + "description": "Always equal to true.", + "example": true + } + }, + "required": [ + "success" + ] + } + } + } + } + } + } + }, + "/auth/password/sign-in": { + "post": { + "summary": "Sign in with email and password", + "description": "Sign in to an account with email and password", + "parameters": [], + "requestBody": { + "required": true, + "content": { + "application/json": { + "schema": { + "type": "object", + "properties": { + "email": { + "type": "string" + }, + "password": { + "type": "string" + } + }, + "required": [ + "email", + "password" + ], + "example": {} + } + } + } + }, + "tags": [ + "Password" + ], + "x-full-url": "https://api.stack-auth.com/api/v1/auth/password/sign-in", + "responses": { + "200": { + "description": "Successful response", + "content": { + "application/json": { + "schema": { + "type": "object", + "properties": { + "access_token": { + "type": "string" + }, + "refresh_token": { + "type": "string" + }, + "user_id": { + "type": "string" + } + }, + "required": [ + "access_token", + "refresh_token", + "user_id" + ] + } + } + } + } + } + } + }, + "/auth/password/sign-up": { + "post": { + "summary": "Sign up with email and password", + "description": "Create a new account with email and password", + "parameters": [], + "requestBody": { + "required": true, + "content": { + "application/json": { + "schema": { + "type": "object", + "properties": { + "email": { + "type": "string", + "example": "johndoe@example.com", + "description": "The email to sign in with." + }, + "password": { + "type": "string" + }, + "verification_callback_url": { + "type": "string", + "example": "https://example.com/handler/email-verification", + "description": "The base callback URL to construct a verification link for the verification e-mail. A query parameter `code` with the verification code will be appended to it. The page should then make a request to the `/contact-channels/verify` endpoint." + }, + "bot_challenge_token": { + "type": "string" + }, + "bot_challenge_phase": { + "type": "string" + }, + "bot_challenge_unavailable": { + "type": "string" + } + }, + "required": [ + "email", + "password" + ], + "example": { + "email": "johndoe@example.com", + "verification_callback_url": "https://example.com/handler/email-verification" + } + } + } + } + }, + "tags": [ + "Password" + ], + "x-full-url": "https://api.stack-auth.com/api/v1/auth/password/sign-up", + "responses": { + "200": { + "description": "Successful response", + "content": { + "application/json": { + "schema": { + "type": "object", + "properties": { + "access_token": { + "type": "string" + }, + "refresh_token": { + "type": "string" + }, + "user_id": { + "type": "string" + } + }, + "required": [ + "access_token", + "refresh_token", + "user_id" + ] + } + } + } + } + } + } + }, + "/auth/password/update": { + "post": { + "summary": "Update password", + "description": "Update the password of the current user, requires the old password", + "parameters": [ + { + "name": "x-stack-refresh-token", + "in": "header", + "schema": { + "type": "string" + }, + "required": false + } + ], + "requestBody": { + "required": true, + "content": { + "application/json": { + "schema": { + "type": "object", + "properties": { + "old_password": { + "type": "string" + }, + "new_password": { + "type": "string" + } + }, + "required": [ + "old_password", + "new_password" + ], + "example": {} + } + } + } + }, + "tags": [ + "Password" + ], + "x-full-url": "https://api.stack-auth.com/api/v1/auth/password/update", + "responses": { + "200": { + "description": "Successful response", + "content": { + "application/json": { + "schema": { + "type": "object", + "properties": { + "success": { + "type": "boolean", + "description": "Always equal to true.", + "example": true + } + }, + "required": [ + "success" + ] + } + } + } + } + } + } + }, + "/payments/items/{customer_type}/{customer_id}/{item_id}": { + "get": { + "summary": "Get Item", + "description": "Retrieves information about a specific item (credits, quotas, etc.) for a customer.", + "parameters": [ + { + "name": "customer_type", + "in": "path", + "schema": { + "type": "string", + "example": "user", + "description": "The type of customer" + }, + "description": "The type of customer", + "required": true + }, + { + "name": "customer_id", + "in": "path", + "schema": { + "type": "string", + "example": "user_1234567890abcdef", + "description": "The ID of the customer" + }, + "description": "The ID of the customer", + "required": true + }, + { + "name": "item_id", + "in": "path", + "schema": { + "type": "string", + "example": "credits", + "description": "The ID of the item to retrieve" + }, + "description": "The ID of the item to retrieve", + "required": true + } + ], + "tags": [ + "Payments" + ], + "x-full-url": "https://api.stack-auth.com/api/v1/payments/items/{customer_type}/{customer_id}/{item_id}", + "responses": { + "200": { + "description": "Successful response", + "content": { + "application/json": { + "schema": { + "type": "object", + "properties": { + "id": { + "type": "string", + "example": "credits", + "description": "The ID of the item" + }, + "display_name": { + "type": "string", + "example": "API Credits", + "description": "The human-readable name of the item" + }, + "quantity": { + "type": "number", + "example": 1000, + "description": "The current quantity of the item (can be negative)" + } + }, + "required": [ + "id", + "display_name", + "quantity" + ] + } + } + } + } + } + } + }, + "/payments/items/{customer_type}/{customer_id}/{item_id}/update-quantity": { + "post": { + "summary": "Update Item Quantity", + "description": "Updates the quantity of an item for a customer. Can increase or decrease quantities, with optional expiration and negative balance control.", + "parameters": [ + { + "name": "allow_negative", + "in": "query", + "schema": { + "type": "string", + "example": "false", + "description": "Whether to allow the quantity to go negative" + }, + "description": "Whether to allow the quantity to go negative", + "required": true + }, + { + "name": "customer_type", + "in": "path", + "schema": { + "type": "string", + "example": "user", + "description": "The type of customer" + }, + "description": "The type of customer", + "required": true + }, + { + "name": "customer_id", + "in": "path", + "schema": { + "type": "string", + "example": "user_1234567890abcdef", + "description": "The ID of the customer" + }, + "description": "The ID of the customer", + "required": true + }, + { + "name": "item_id", + "in": "path", + "schema": { + "type": "string", + "example": "credits", + "description": "The ID of the item to update" + }, + "description": "The ID of the item to update", + "required": true + } + ], + "requestBody": { + "required": true, + "content": { + "application/json": { + "schema": { + "type": "object", + "properties": { + "delta": { + "type": "number", + "example": 100, + "description": "The amount to change the quantity by (positive to increase, negative to decrease)" + }, + "expires_at": { + "type": "string", + "example": "2024-12-31T23:59:59Z", + "description": "Optional expiration date for this quantity change (ISO 8601 format)" + }, + "description": { + "type": "string", + "example": "Monthly subscription renewal", + "description": "Optional description for this quantity change" + } + }, + "required": [ + "delta" + ], + "example": { + "delta": 100, + "expires_at": "2024-12-31T23:59:59Z", + "description": "Monthly subscription renewal" + } + } + } + } + }, + "tags": [ + "Payments" + ], + "x-full-url": "https://api.stack-auth.com/api/v1/payments/items/{customer_type}/{customer_id}/{item_id}/update-quantity", + "responses": { + "200": { + "description": "Successful response", + "content": { + "application/json": { + "schema": { + "type": "object", + "properties": {} + } + } + } + } + } + } + }, + "/payments/purchases/create-purchase-url": { + "post": { + "summary": "Create Purchase URL", + "description": "Creates a secure checkout URL for purchasing a product.", + "parameters": [], + "requestBody": { + "required": true, + "content": { + "application/json": { + "schema": { + "type": "object", + "properties": { + "customer_type": { + "type": "string", + "example": "user", + "description": "The type of customer making the purchase" + }, + "customer_id": { + "type": "string", + "example": "user_1234567890abcdef", + "description": "The ID of the customer (user ID, team ID, or custom customer ID)" + }, + "product_id": { + "type": "string", + "example": "prod_premium_monthly", + "description": "The ID of the product to purchase. Either this or product_inline should be given." + }, + "product_inline": { + "type": "object", + "properties": { + "display_name": { + "type": "string" + }, + "customer_type": { + "type": "string" + }, + "free_trial": { + "type": "array", + "items": { + "type": "number" + } + }, + "server_only": { + "type": "boolean", + "default": true + }, + "stackable": { + "type": "boolean", + "default": false + }, + "prices": { + "type": "object", + "properties": {}, + "required": [] + }, + "included_items": { + "type": "object", + "properties": {}, + "required": [] + }, + "client_metadata": { + "type": "object", + "example": { + "featureFlag": true, + "source": "marketing-campaign" + }, + "description": "Client metadata. Used as a data store, accessible from the client side. Do not store information that should not be exposed to the client." + }, + "client_read_only_metadata": { + "type": "object", + "example": { + "featureFlag": true, + "source": "marketing-campaign" + }, + "description": "Client read-only, server-writable metadata. Used as a data store, accessible from the client side. Do not store information that should not be exposed to the client. The client can read this data, but cannot modify it. This is useful for things like subscription status." + }, + "server_metadata": { + "type": "object", + "example": { + "featureFlag": true, + "source": "marketing-campaign" + }, + "description": "Server metadata. Used as a data store, only accessible from the server side. You can store secret information related to the product here." + } + }, + "required": [ + "display_name", + "customer_type" + ], + "description": "Inline product definition. Either this or product_id should be given." + }, + "return_url": { + "type": "string", + "example": "https://myapp.com/purchase-success", + "description": "URL to redirect to after purchase completion. Must be configured as a trusted domain in the project configuration." + } + }, + "required": [ + "customer_type", + "customer_id" + ], + "example": { + "customer_type": "user", + "customer_id": "user_1234567890abcdef", + "product_id": "prod_premium_monthly", + "return_url": "https://myapp.com/purchase-success" + } + } + } + } + }, + "tags": [ + "Payments" + ], + "x-full-url": "https://api.stack-auth.com/api/v1/payments/purchases/create-purchase-url", + "responses": { + "200": { + "description": "Successful response", + "content": { + "application/json": { + "schema": { + "type": "object", + "properties": { + "url": { + "type": "string", + "description": "The secure checkout URL for completing the purchase" + } + }, + "required": [ + "url" + ] + } + } + } + } + } + } + }, + "/payments/purchases/purchase-session": { + "post": { + "summary": "Create Purchase Session", + "description": "Creates a purchase session for completing a purchase.", + "parameters": [], + "requestBody": { + "required": true, + "content": { + "application/json": { + "schema": { + "type": "object", + "properties": { + "full_code": { + "type": "string", + "example": "proj_abc123_def456ghi789", + "description": "The verification code, given as a query parameter in the purchase URL" + }, + "price_id": { + "type": "string", + "example": "price_1234567890abcdef", + "description": "The Stack auth price ID to purchase" + }, + "quantity": { + "type": "number", + "example": 1, + "description": "The quantity to purchase", + "default": 1 + } + }, + "required": [ + "full_code", + "price_id" + ], + "example": { + "full_code": "proj_abc123_def456ghi789", + "price_id": "price_1234567890abcdef", + "quantity": 1 + } + } + } + } + }, + "tags": [ + "Payments" + ], + "x-full-url": "https://api.stack-auth.com/api/v1/payments/purchases/purchase-session", + "responses": { + "200": { + "description": "Successful response", + "content": { + "application/json": { + "schema": { + "type": "object", + "properties": { + "client_secret": { + "type": "string", + "example": "1234567890abcdef_secret_xyz123", + "description": "The Stripe client secret for completing the payment" + } + }, + "required": [ + "client_secret" + ] + } + } + } + } + } + } + }, + "/payments/purchases/validate-code": { + "post": { + "summary": "Validate Purchase Code", + "description": "Validates a purchase verification code and returns purchase details including available prices.", + "parameters": [], + "requestBody": { + "required": true, + "content": { + "application/json": { + "schema": { + "type": "object", + "properties": { + "full_code": { + "type": "string", + "example": "proj_abc123_def456ghi789", + "description": "The verification code, given as a query parameter in the purchase URL" + }, + "return_url": { + "type": "string", + "example": "https://myapp.com/purchase-success", + "description": "URL to redirect to after purchase completion" + } + }, + "required": [ + "full_code" + ], + "example": { + "full_code": "proj_abc123_def456ghi789", + "return_url": "https://myapp.com/purchase-success" + } + } + } + } + }, + "tags": [ + "Payments" + ], + "x-full-url": "https://api.stack-auth.com/api/v1/payments/purchases/validate-code", + "responses": { + "200": { + "description": "Successful response", + "content": { + "application/json": { + "schema": { + "type": "object", + "properties": { + "product": { + "type": "object", + "properties": { + "display_name": { + "type": "string" + }, + "customer_type": { + "type": "string" + }, + "free_trial": { + "type": "array", + "items": { + "type": "number" + } + }, + "server_only": { + "type": "boolean", + "default": true + }, + "stackable": { + "type": "boolean", + "default": false + }, + "prices": { + "type": "object", + "properties": {}, + "required": [] + }, + "included_items": { + "type": "object", + "properties": {}, + "required": [] + }, + "client_metadata": { + "type": "object", + "example": { + "featureFlag": true, + "source": "marketing-campaign" + }, + "description": "Client metadata. Used as a data store, accessible from the client side. Do not store information that should not be exposed to the client." + }, + "client_read_only_metadata": { + "type": "object", + "example": { + "featureFlag": true, + "source": "marketing-campaign" + }, + "description": "Client read-only, server-writable metadata. Used as a data store, accessible from the client side. Do not store information that should not be exposed to the client. The client can read this data, but cannot modify it. This is useful for things like subscription status." + }, + "server_metadata": { + "type": "object", + "example": { + "featureFlag": true, + "source": "marketing-campaign" + }, + "description": "Server metadata. Used as a data store, only accessible from the server side. You can store secret information related to the product here." + } + }, + "required": [ + "display_name", + "customer_type" + ] + }, + "stripe_account_id": { + "type": "string" + }, + "project_id": { + "type": "string" + }, + "project_logo_url": { + "type": "string" + }, + "already_bought_non_stackable": { + "type": "boolean" + }, + "conflicting_products": { + "type": "array", + "items": { + "type": "object", + "properties": { + "product_id": { + "type": "string" + }, + "display_name": { + "type": "string" + } + }, + "required": [ + "product_id", + "display_name" + ] + } + }, + "test_mode": { + "type": "boolean" + }, + "charges_enabled": { + "type": "boolean" + } + }, + "required": [ + "stripe_account_id", + "project_id", + "already_bought_non_stackable", + "conflicting_products", + "test_mode", + "charges_enabled" + ] + } + } + } + } + } + } + }, + "/project-permission-definitions": { + "get": { + "summary": "List project permission definitions", + "description": "Query and filter project permission definitions (the equivalent of listing permissions on the Stack dashboard)", + "parameters": [], + "tags": [ + "Permissions" + ], + "x-full-url": "https://api.stack-auth.com/api/v1/project-permission-definitions", + "responses": { + "200": { + "description": "Successful response", + "content": { + "application/json": { + "schema": { + "type": "object", + "properties": { + "items": { + "type": "array", + "items": { + "type": "object", + "properties": { + "id": { + "type": "string", + "example": "read_secret_info", + "description": "The permission ID used to uniquely identify a permission. Can either be a custom permission with lowercase letters, numbers, `:`, and `_` characters, or one of the system permissions: `$update_team`, `$delete_team`, `$read_members`, `$remove_members`, `$invite_members`, `$manage_api_keys`" + }, + "description": { + "type": "string", + "example": "Read secret information", + "description": "A human-readable description of the permission" + }, + "contained_permission_ids": { + "type": "array", + "items": { + "type": "string", + "example": "read_secret_info", + "description": "The permission ID used to uniquely identify a permission. Can either be a custom permission with lowercase letters, numbers, `:`, and `_` characters, or one of the system permissions: `$update_team`, `$delete_team`, `$read_members`, `$remove_members`, `$invite_members`, `$manage_api_keys`" + }, + "example": [ + "read_public_info" + ], + "description": "The IDs of the permissions that are contained in this permission" + } + }, + "required": [ + "id", + "contained_permission_ids" + ] + } + }, + "pagination": { + "type": "object", + "properties": { + "next_cursor": { + "type": "string", + "example": "b3d396b8-c574-4c80-97b3-50031675ceb2", + "description": "The cursor to fetch the next page of results. null if there is no next page." + } + }, + "required": [] + } + }, + "required": [ + "items" + ] + } + } + } + } + } + }, + "post": { + "summary": "Create a new project permission definition", + "description": "Create a new project permission definition (the equivalent of creating a new permission on the Stack dashboard)", + "parameters": [], + "requestBody": { + "required": true, + "content": { + "application/json": { + "schema": { + "type": "object", + "properties": { + "id": { + "type": "string", + "example": "read_secret_info", + "description": "The permission ID used to uniquely identify a permission. Can only contain lowercase letters, numbers, \":\", and \"_\" characters" + }, + "description": { + "type": "string", + "example": "Read secret information", + "description": "A human-readable description of the permission" + }, + "contained_permission_ids": { + "type": "array", + "items": { + "type": "string", + "example": "read_secret_info", + "description": "The permission ID used to uniquely identify a permission. Can either be a custom permission with lowercase letters, numbers, `:`, and `_` characters, or one of the system permissions: `$update_team`, `$delete_team`, `$read_members`, `$remove_members`, `$invite_members`, `$manage_api_keys`" + }, + "example": [ + "read_public_info" + ], + "description": "The IDs of the permissions that are contained in this permission" + } + }, + "required": [ + "id" + ], + "example": { + "id": "read_secret_info", + "description": "Read secret information", + "contained_permission_ids": [ + "read_public_info" + ] + } + } + } + } + }, + "tags": [ + "Permissions" + ], + "x-full-url": "https://api.stack-auth.com/api/v1/project-permission-definitions", + "responses": { + "201": { + "description": "Successful response", + "content": { + "application/json": { + "schema": { + "type": "object", + "properties": { + "id": { + "type": "string", + "example": "read_secret_info", + "description": "The permission ID used to uniquely identify a permission. Can either be a custom permission with lowercase letters, numbers, `:`, and `_` characters, or one of the system permissions: `$update_team`, `$delete_team`, `$read_members`, `$remove_members`, `$invite_members`, `$manage_api_keys`" + }, + "description": { + "type": "string", + "example": "Read secret information", + "description": "A human-readable description of the permission" + }, + "contained_permission_ids": { + "type": "array", + "items": { + "type": "string", + "example": "read_secret_info", + "description": "The permission ID used to uniquely identify a permission. Can either be a custom permission with lowercase letters, numbers, `:`, and `_` characters, or one of the system permissions: `$update_team`, `$delete_team`, `$read_members`, `$remove_members`, `$invite_members`, `$manage_api_keys`" + }, + "example": [ + "read_public_info" + ], + "description": "The IDs of the permissions that are contained in this permission" + } + }, + "required": [ + "id", + "contained_permission_ids" + ] + } + } + } + } + } + } + }, + "/project-permission-definitions/{permission_id}": { + "delete": { + "summary": "Delete a project permission definition", + "description": "Delete a project permission definition (the equivalent of deleting a permission on the Stack dashboard)", + "parameters": [ + { + "name": "permission_id", + "in": "path", + "schema": { + "type": "string", + "example": "read_secret_info", + "description": "The permission ID used to uniquely identify a permission. Can either be a custom permission with lowercase letters, numbers, `:`, and `_` characters, or one of the system permissions: `$update_team`, `$delete_team`, `$read_members`, `$remove_members`, `$invite_members`, `$manage_api_keys`" + }, + "description": "The permission ID used to uniquely identify a permission. Can either be a custom permission with lowercase letters, numbers, `:`, and `_` characters, or one of the system permissions: `$update_team`, `$delete_team`, `$read_members`, `$remove_members`, `$invite_members`, `$manage_api_keys`", + "required": true + } + ], + "tags": [ + "Permissions" + ], + "x-full-url": "https://api.stack-auth.com/api/v1/project-permission-definitions/{permission_id}", + "responses": { + "200": { + "description": "Successful response", + "content": { + "application/json": { + "schema": { + "type": "object", + "properties": { + "success": { + "type": "boolean", + "description": "Always equal to true.", + "example": true + } + }, + "required": [ + "success" + ] + } + } + } + } + } + }, + "patch": { + "summary": "Update a project permission definition", + "description": "Update a project permission definition (the equivalent of updating a permission on the Stack dashboard)", + "parameters": [ + { + "name": "permission_id", + "in": "path", + "schema": { + "type": "string", + "example": "read_secret_info", + "description": "The permission ID used to uniquely identify a permission. Can either be a custom permission with lowercase letters, numbers, `:`, and `_` characters, or one of the system permissions: `$update_team`, `$delete_team`, `$read_members`, `$remove_members`, `$invite_members`, `$manage_api_keys`" + }, + "description": "The permission ID used to uniquely identify a permission. Can either be a custom permission with lowercase letters, numbers, `:`, and `_` characters, or one of the system permissions: `$update_team`, `$delete_team`, `$read_members`, `$remove_members`, `$invite_members`, `$manage_api_keys`", + "required": true + } + ], + "requestBody": { + "required": true, + "content": { + "application/json": { + "schema": { + "type": "object", + "properties": { + "id": { + "type": "string", + "example": "read_secret_info", + "description": "The permission ID used to uniquely identify a permission. Can only contain lowercase letters, numbers, \":\", and \"_\" characters" + }, + "description": { + "type": "string", + "example": "Read secret information", + "description": "A human-readable description of the permission" + }, + "contained_permission_ids": { + "type": "array", + "items": { + "type": "string", + "example": "read_secret_info", + "description": "The permission ID used to uniquely identify a permission. Can either be a custom permission with lowercase letters, numbers, `:`, and `_` characters, or one of the system permissions: `$update_team`, `$delete_team`, `$read_members`, `$remove_members`, `$invite_members`, `$manage_api_keys`" + }, + "example": [ + "read_public_info" + ], + "description": "The IDs of the permissions that are contained in this permission" + } + }, + "example": { + "id": "read_secret_info", + "description": "Read secret information", + "contained_permission_ids": [ + "read_public_info" + ] + } + } + } + } + }, + "tags": [ + "Permissions" + ], + "x-full-url": "https://api.stack-auth.com/api/v1/project-permission-definitions/{permission_id}", + "responses": { + "200": { + "description": "Successful response", + "content": { + "application/json": { + "schema": { + "type": "object", + "properties": { + "id": { + "type": "string", + "example": "read_secret_info", + "description": "The permission ID used to uniquely identify a permission. Can either be a custom permission with lowercase letters, numbers, `:`, and `_` characters, or one of the system permissions: `$update_team`, `$delete_team`, `$read_members`, `$remove_members`, `$invite_members`, `$manage_api_keys`" + }, + "description": { + "type": "string", + "example": "Read secret information", + "description": "A human-readable description of the permission" + }, + "contained_permission_ids": { + "type": "array", + "items": { + "type": "string", + "example": "read_secret_info", + "description": "The permission ID used to uniquely identify a permission. Can either be a custom permission with lowercase letters, numbers, `:`, and `_` characters, or one of the system permissions: `$update_team`, `$delete_team`, `$read_members`, `$remove_members`, `$invite_members`, `$manage_api_keys`" + }, + "example": [ + "read_public_info" + ], + "description": "The IDs of the permissions that are contained in this permission" + } + }, + "required": [ + "id", + "contained_permission_ids" + ] + } + } + } + } + } + } + }, + "/project-permissions": { + "get": { + "summary": "List project permissions", + "description": "Query and filter the permission with `user_id` and `permission_id`. `(user_id, permission_id)` together uniquely identify a permission.", + "parameters": [ + { + "name": "user_id", + "in": "query", + "schema": { + "type": "string", + "example": "me", + "description": "Filter with the user ID. If set, only the permissions this user has will be returned. Client request must set `user_id=me`" + }, + "description": "Filter with the user ID. If set, only the permissions this user has will be returned. Client request must set `user_id=me`", + "required": false + }, + { + "name": "permission_id", + "in": "query", + "schema": { + "type": "string", + "example": "16399452-c4f3-4554-8e44-c2d67bb60360", + "description": "Filter with the permission ID. If set, only the permissions with this specific ID will be returned" + }, + "description": "Filter with the permission ID. If set, only the permissions with this specific ID will be returned", + "required": false + }, + { + "name": "recursive", + "in": "query", + "schema": { + "type": "string", + "example": "true", + "description": "Whether to list permissions recursively. If set to `false`, only the permission the users directly have will be listed. If set to `true` all the direct and indirect permissions will be listed." + }, + "description": "Whether to list permissions recursively. If set to `false`, only the permission the users directly have will be listed. If set to `true` all the direct and indirect permissions will be listed.", + "required": false + } + ], + "tags": [ + "Permissions" + ], + "x-full-url": "https://api.stack-auth.com/api/v1/project-permissions", + "responses": { + "200": { + "description": "Successful response", + "content": { + "application/json": { + "schema": { + "type": "object", + "properties": { + "items": { + "type": "array", + "items": { + "type": "object", + "properties": { + "id": { + "type": "string", + "example": "read_secret_info", + "description": "The permission ID used to uniquely identify a permission. Can either be a custom permission with lowercase letters, numbers, `:`, and `_` characters, or one of the system permissions: `$update_team`, `$delete_team`, `$read_members`, `$remove_members`, `$invite_members`, `$manage_api_keys`" + }, + "user_id": { + "type": "string", + "example": "3241a285-8329-4d69-8f3d-316e08cf140c", + "description": "The unique identifier of the user" + } + }, + "required": [ + "id", + "user_id" + ] + } + }, + "pagination": { + "type": "object", + "properties": { + "next_cursor": { + "type": "string", + "example": "b3d396b8-c574-4c80-97b3-50031675ceb2", + "description": "The cursor to fetch the next page of results. null if there is no next page." + } + }, + "required": [] + } + }, + "required": [ + "items" + ] + } + } + } + } + } + } + }, + "/project-permissions/{user_id}/{permission_id}": { + "post": { + "summary": "Grant a global permission to a user", + "description": "Grant a global permission to a user (the permission must be created first on the Stack dashboard)", + "parameters": [ + { + "name": "user_id", + "in": "path", + "schema": { + "type": "string", + "example": "3241a285-8329-4d69-8f3d-316e08cf140c", + "description": "The ID of the user, or the special value `me` for the currently authenticated user" + }, + "description": "The ID of the user, or the special value `me` for the currently authenticated user", + "required": false + }, + { + "name": "permission_id", + "in": "path", + "schema": { + "type": "string", + "example": "read_secret_info", + "description": "The permission ID used to uniquely identify a permission. Can either be a custom permission with lowercase letters, numbers, `:`, and `_` characters, or one of the system permissions: `$update_team`, `$delete_team`, `$read_members`, `$remove_members`, `$invite_members`, `$manage_api_keys`" + }, + "description": "The permission ID used to uniquely identify a permission. Can either be a custom permission with lowercase letters, numbers, `:`, and `_` characters, or one of the system permissions: `$update_team`, `$delete_team`, `$read_members`, `$remove_members`, `$invite_members`, `$manage_api_keys`", + "required": false + } + ], + "requestBody": { + "required": true, + "content": { + "application/json": { + "schema": { + "type": "object", + "properties": {}, + "example": {} + } + } + } + }, + "tags": [ + "Permissions" + ], + "x-full-url": "https://api.stack-auth.com/api/v1/project-permissions/{user_id}/{permission_id}", + "responses": { + "201": { + "description": "Successful response", + "content": { + "application/json": { + "schema": { + "type": "object", + "properties": { + "id": { + "type": "string", + "example": "read_secret_info", + "description": "The permission ID used to uniquely identify a permission. Can either be a custom permission with lowercase letters, numbers, `:`, and `_` characters, or one of the system permissions: `$update_team`, `$delete_team`, `$read_members`, `$remove_members`, `$invite_members`, `$manage_api_keys`" + }, + "user_id": { + "type": "string", + "example": "3241a285-8329-4d69-8f3d-316e08cf140c", + "description": "The unique identifier of the user" + } + }, + "required": [ + "id", + "user_id" + ] + } + } + } + } + } + }, + "delete": { + "summary": "Revoke a global permission from a user", + "description": "Revoke a global permission from a user", + "parameters": [ + { + "name": "user_id", + "in": "path", + "schema": { + "type": "string", + "example": "3241a285-8329-4d69-8f3d-316e08cf140c", + "description": "The ID of the user, or the special value `me` for the currently authenticated user" + }, + "description": "The ID of the user, or the special value `me` for the currently authenticated user", + "required": true + }, + { + "name": "permission_id", + "in": "path", + "schema": { + "type": "string", + "example": "read_secret_info", + "description": "The permission ID used to uniquely identify a permission. Can either be a custom permission with lowercase letters, numbers, `:`, and `_` characters, or one of the system permissions: `$update_team`, `$delete_team`, `$read_members`, `$remove_members`, `$invite_members`, `$manage_api_keys`" + }, + "description": "The permission ID used to uniquely identify a permission. Can either be a custom permission with lowercase letters, numbers, `:`, and `_` characters, or one of the system permissions: `$update_team`, `$delete_team`, `$read_members`, `$remove_members`, `$invite_members`, `$manage_api_keys`", + "required": true + } + ], + "tags": [ + "Permissions" + ], + "x-full-url": "https://api.stack-auth.com/api/v1/project-permissions/{user_id}/{permission_id}", + "responses": { + "200": { + "description": "Successful response", + "content": { + "application/json": { + "schema": { + "type": "object", + "properties": { + "success": { + "type": "boolean", + "description": "Always equal to true.", + "example": true + } + }, + "required": [ + "success" + ] + } + } + } + } + } + } + }, + "/team-permission-definitions": { + "get": { + "summary": "List team permission definitions", + "description": "Query and filter the permission with team_id, user_id, and permission_id (the equivalent of listing permissions on the Stack dashboard)", + "parameters": [], + "tags": [ + "Permissions" + ], + "x-full-url": "https://api.stack-auth.com/api/v1/team-permission-definitions", + "responses": { + "200": { + "description": "Successful response", + "content": { + "application/json": { + "schema": { + "type": "object", + "properties": { + "items": { + "type": "array", + "items": { + "type": "object", + "properties": { + "id": { + "type": "string", + "example": "read_secret_info", + "description": "The permission ID used to uniquely identify a permission. Can either be a custom permission with lowercase letters, numbers, `:`, and `_` characters, or one of the system permissions: `$update_team`, `$delete_team`, `$read_members`, `$remove_members`, `$invite_members`, `$manage_api_keys`" + }, + "description": { + "type": "string", + "example": "Read secret information", + "description": "A human-readable description of the permission" + }, + "contained_permission_ids": { + "type": "array", + "items": { + "type": "string", + "example": "read_secret_info", + "description": "The permission ID used to uniquely identify a permission. Can either be a custom permission with lowercase letters, numbers, `:`, and `_` characters, or one of the system permissions: `$update_team`, `$delete_team`, `$read_members`, `$remove_members`, `$invite_members`, `$manage_api_keys`" + }, + "example": [ + "read_public_info" + ], + "description": "The IDs of the permissions that are contained in this permission" + } + }, + "required": [ + "id", + "contained_permission_ids" + ] + } + }, + "pagination": { + "type": "object", + "properties": { + "next_cursor": { + "type": "string", + "example": "b3d396b8-c574-4c80-97b3-50031675ceb2", + "description": "The cursor to fetch the next page of results. null if there is no next page." + } + }, + "required": [] + } + }, + "required": [ + "items" + ] + } + } + } + } + } + }, + "post": { + "summary": "Create a new team permission definition", + "description": "Create a new permission definition (the equivalent of creating a new permission on the Stack dashboard)", + "parameters": [], + "requestBody": { + "required": true, + "content": { + "application/json": { + "schema": { + "type": "object", + "properties": { + "id": { + "type": "string", + "example": "read_secret_info", + "description": "The permission ID used to uniquely identify a permission. Can only contain lowercase letters, numbers, \":\", and \"_\" characters" + }, + "description": { + "type": "string", + "example": "Read secret information", + "description": "A human-readable description of the permission" + }, + "contained_permission_ids": { + "type": "array", + "items": { + "type": "string", + "example": "read_secret_info", + "description": "The permission ID used to uniquely identify a permission. Can either be a custom permission with lowercase letters, numbers, `:`, and `_` characters, or one of the system permissions: `$update_team`, `$delete_team`, `$read_members`, `$remove_members`, `$invite_members`, `$manage_api_keys`" + }, + "example": [ + "read_public_info" + ], + "description": "The IDs of the permissions that are contained in this permission" + } + }, + "required": [ + "id" + ], + "example": { + "id": "read_secret_info", + "description": "Read secret information", + "contained_permission_ids": [ + "read_public_info" + ] + } + } + } + } + }, + "tags": [ + "Permissions" + ], + "x-full-url": "https://api.stack-auth.com/api/v1/team-permission-definitions", + "responses": { + "201": { + "description": "Successful response", + "content": { + "application/json": { + "schema": { + "type": "object", + "properties": { + "id": { + "type": "string", + "example": "read_secret_info", + "description": "The permission ID used to uniquely identify a permission. Can either be a custom permission with lowercase letters, numbers, `:`, and `_` characters, or one of the system permissions: `$update_team`, `$delete_team`, `$read_members`, `$remove_members`, `$invite_members`, `$manage_api_keys`" + }, + "description": { + "type": "string", + "example": "Read secret information", + "description": "A human-readable description of the permission" + }, + "contained_permission_ids": { + "type": "array", + "items": { + "type": "string", + "example": "read_secret_info", + "description": "The permission ID used to uniquely identify a permission. Can either be a custom permission with lowercase letters, numbers, `:`, and `_` characters, or one of the system permissions: `$update_team`, `$delete_team`, `$read_members`, `$remove_members`, `$invite_members`, `$manage_api_keys`" + }, + "example": [ + "read_public_info" + ], + "description": "The IDs of the permissions that are contained in this permission" + } + }, + "required": [ + "id", + "contained_permission_ids" + ] + } + } + } + } + } + } + }, + "/team-permission-definitions/{permission_id}": { + "delete": { + "summary": "Delete a team permission definition", + "description": "Delete a permission definition (the equivalent of deleting a permission on the Stack dashboard)", + "parameters": [ + { + "name": "permission_id", + "in": "path", + "schema": { + "type": "string", + "example": "read_secret_info", + "description": "The permission ID used to uniquely identify a permission. Can either be a custom permission with lowercase letters, numbers, `:`, and `_` characters, or one of the system permissions: `$update_team`, `$delete_team`, `$read_members`, `$remove_members`, `$invite_members`, `$manage_api_keys`" + }, + "description": "The permission ID used to uniquely identify a permission. Can either be a custom permission with lowercase letters, numbers, `:`, and `_` characters, or one of the system permissions: `$update_team`, `$delete_team`, `$read_members`, `$remove_members`, `$invite_members`, `$manage_api_keys`", + "required": true + } + ], + "tags": [ + "Permissions" + ], + "x-full-url": "https://api.stack-auth.com/api/v1/team-permission-definitions/{permission_id}", + "responses": { + "200": { + "description": "Successful response", + "content": { + "application/json": { + "schema": { + "type": "object", + "properties": { + "success": { + "type": "boolean", + "description": "Always equal to true.", + "example": true + } + }, + "required": [ + "success" + ] + } + } + } + } + } + }, + "patch": { + "summary": "Update a team permission definition", + "description": "Update a permission definition (the equivalent of updating a permission on the Stack dashboard)", + "parameters": [ + { + "name": "permission_id", + "in": "path", + "schema": { + "type": "string", + "example": "read_secret_info", + "description": "The permission ID used to uniquely identify a permission. Can either be a custom permission with lowercase letters, numbers, `:`, and `_` characters, or one of the system permissions: `$update_team`, `$delete_team`, `$read_members`, `$remove_members`, `$invite_members`, `$manage_api_keys`" + }, + "description": "The permission ID used to uniquely identify a permission. Can either be a custom permission with lowercase letters, numbers, `:`, and `_` characters, or one of the system permissions: `$update_team`, `$delete_team`, `$read_members`, `$remove_members`, `$invite_members`, `$manage_api_keys`", + "required": true + } + ], + "requestBody": { + "required": true, + "content": { + "application/json": { + "schema": { + "type": "object", + "properties": { + "id": { + "type": "string", + "example": "read_secret_info", + "description": "The permission ID used to uniquely identify a permission. Can only contain lowercase letters, numbers, \":\", and \"_\" characters" + }, + "description": { + "type": "string", + "example": "Read secret information", + "description": "A human-readable description of the permission" + }, + "contained_permission_ids": { + "type": "array", + "items": { + "type": "string", + "example": "read_secret_info", + "description": "The permission ID used to uniquely identify a permission. Can either be a custom permission with lowercase letters, numbers, `:`, and `_` characters, or one of the system permissions: `$update_team`, `$delete_team`, `$read_members`, `$remove_members`, `$invite_members`, `$manage_api_keys`" + }, + "example": [ + "read_public_info" + ], + "description": "The IDs of the permissions that are contained in this permission" + } + }, + "example": { + "id": "read_secret_info", + "description": "Read secret information", + "contained_permission_ids": [ + "read_public_info" + ] + } + } + } + } + }, + "tags": [ + "Permissions" + ], + "x-full-url": "https://api.stack-auth.com/api/v1/team-permission-definitions/{permission_id}", + "responses": { + "200": { + "description": "Successful response", + "content": { + "application/json": { + "schema": { + "type": "object", + "properties": { + "id": { + "type": "string", + "example": "read_secret_info", + "description": "The permission ID used to uniquely identify a permission. Can either be a custom permission with lowercase letters, numbers, `:`, and `_` characters, or one of the system permissions: `$update_team`, `$delete_team`, `$read_members`, `$remove_members`, `$invite_members`, `$manage_api_keys`" + }, + "description": { + "type": "string", + "example": "Read secret information", + "description": "A human-readable description of the permission" + }, + "contained_permission_ids": { + "type": "array", + "items": { + "type": "string", + "example": "read_secret_info", + "description": "The permission ID used to uniquely identify a permission. Can either be a custom permission with lowercase letters, numbers, `:`, and `_` characters, or one of the system permissions: `$update_team`, `$delete_team`, `$read_members`, `$remove_members`, `$invite_members`, `$manage_api_keys`" + }, + "example": [ + "read_public_info" + ], + "description": "The IDs of the permissions that are contained in this permission" + } + }, + "required": [ + "id", + "contained_permission_ids" + ] + } + } + } + } + } + } + }, + "/team-permissions": { + "get": { + "summary": "List team permissions of a user", + "description": "Query and filter the permission with `team_id`, `user_id`, and `permission_id`. Note that this might contain the permissions with the same permission ID across different teams and users. `(team_id, user_id, permission_id)` together uniquely identify a permission.", + "parameters": [ + { + "name": "team_id", + "in": "query", + "schema": { + "type": "string", + "example": "cce084a3-28b7-418e-913e-c8ee6d802ea4", + "description": "Filter with the team ID. If set, only the permissions of the members in a specific team will be returned." + }, + "description": "Filter with the team ID. If set, only the permissions of the members in a specific team will be returned.", + "required": false + }, + { + "name": "user_id", + "in": "query", + "schema": { + "type": "string", + "example": "me", + "description": "Filter with the user ID. If set, only the permissions this user has will be returned. Client request must set `user_id=me`" + }, + "description": "Filter with the user ID. If set, only the permissions this user has will be returned. Client request must set `user_id=me`", + "required": false + }, + { + "name": "permission_id", + "in": "query", + "schema": { + "type": "string", + "example": "16399452-c4f3-4554-8e44-c2d67bb60360", + "description": "Filter with the permission ID. If set, only the permissions with this specific ID will be returned" + }, + "description": "Filter with the permission ID. If set, only the permissions with this specific ID will be returned", + "required": false + }, + { + "name": "recursive", + "in": "query", + "schema": { + "type": "string", + "example": "true", + "description": "Whether to list permissions recursively. If set to `false`, only the permission the users directly have will be listed. If set to `true` all the direct and indirect permissions will be listed." + }, + "description": "Whether to list permissions recursively. If set to `false`, only the permission the users directly have will be listed. If set to `true` all the direct and indirect permissions will be listed.", + "required": false + } + ], + "tags": [ + "Permissions" + ], + "x-full-url": "https://api.stack-auth.com/api/v1/team-permissions", + "responses": { + "200": { + "description": "Successful response", + "content": { + "application/json": { + "schema": { + "type": "object", + "properties": { + "items": { + "type": "array", + "items": { + "type": "object", + "properties": { + "id": { + "type": "string", + "example": "read_secret_info", + "description": "The permission ID used to uniquely identify a permission. Can either be a custom permission with lowercase letters, numbers, `:`, and `_` characters, or one of the system permissions: `$update_team`, `$delete_team`, `$read_members`, `$remove_members`, `$invite_members`, `$manage_api_keys`" + }, + "user_id": { + "type": "string", + "example": "3241a285-8329-4d69-8f3d-316e08cf140c", + "description": "The unique identifier of the user" + }, + "team_id": { + "type": "string", + "example": "ad962777-8244-496a-b6a2-e0c6a449c79e", + "description": "The unique identifier of the team" + } + }, + "required": [ + "id", + "user_id", + "team_id" + ] + } + }, + "pagination": { + "type": "object", + "properties": { + "next_cursor": { + "type": "string", + "example": "b3d396b8-c574-4c80-97b3-50031675ceb2", + "description": "The cursor to fetch the next page of results. null if there is no next page." + } + }, + "required": [] + } + }, + "required": [ + "items" + ] + } + } + } + } + } + } + }, + "/team-permissions/{team_id}/{user_id}/{permission_id}": { + "post": { + "summary": "Grant a team permission to a user", + "description": "Grant a team permission to a user (the team permission must be created first on the Stack dashboard)", + "parameters": [ + { + "name": "team_id", + "in": "path", + "schema": { + "type": "string" + }, + "required": false + }, + { + "name": "user_id", + "in": "path", + "schema": { + "type": "string", + "example": "3241a285-8329-4d69-8f3d-316e08cf140c", + "description": "The ID of the user, or the special value `me` for the currently authenticated user" + }, + "description": "The ID of the user, or the special value `me` for the currently authenticated user", + "required": false + }, + { + "name": "permission_id", + "in": "path", + "schema": { + "type": "string", + "example": "read_secret_info", + "description": "The permission ID used to uniquely identify a permission. Can either be a custom permission with lowercase letters, numbers, `:`, and `_` characters, or one of the system permissions: `$update_team`, `$delete_team`, `$read_members`, `$remove_members`, `$invite_members`, `$manage_api_keys`" + }, + "description": "The permission ID used to uniquely identify a permission. Can either be a custom permission with lowercase letters, numbers, `:`, and `_` characters, or one of the system permissions: `$update_team`, `$delete_team`, `$read_members`, `$remove_members`, `$invite_members`, `$manage_api_keys`", + "required": false + } + ], + "requestBody": { + "required": true, + "content": { + "application/json": { + "schema": { + "type": "object", + "properties": {}, + "example": {} + } + } + } + }, + "tags": [ + "Permissions" + ], + "x-full-url": "https://api.stack-auth.com/api/v1/team-permissions/{team_id}/{user_id}/{permission_id}", + "responses": { + "201": { + "description": "Successful response", + "content": { + "application/json": { + "schema": { + "type": "object", + "properties": { + "id": { + "type": "string", + "example": "read_secret_info", + "description": "The permission ID used to uniquely identify a permission. Can either be a custom permission with lowercase letters, numbers, `:`, and `_` characters, or one of the system permissions: `$update_team`, `$delete_team`, `$read_members`, `$remove_members`, `$invite_members`, `$manage_api_keys`" + }, + "user_id": { + "type": "string", + "example": "3241a285-8329-4d69-8f3d-316e08cf140c", + "description": "The unique identifier of the user" + }, + "team_id": { + "type": "string", + "example": "ad962777-8244-496a-b6a2-e0c6a449c79e", + "description": "The unique identifier of the team" + } + }, + "required": [ + "id", + "user_id", + "team_id" + ] + } + } + } + } + } + }, + "delete": { + "summary": "Revoke a team permission from a user", + "description": "Revoke a team permission from a user", + "parameters": [ + { + "name": "team_id", + "in": "path", + "schema": { + "type": "string" + }, + "required": true + }, + { + "name": "user_id", + "in": "path", + "schema": { + "type": "string", + "example": "3241a285-8329-4d69-8f3d-316e08cf140c", + "description": "The ID of the user, or the special value `me` for the currently authenticated user" + }, + "description": "The ID of the user, or the special value `me` for the currently authenticated user", + "required": true + }, + { + "name": "permission_id", + "in": "path", + "schema": { + "type": "string", + "example": "read_secret_info", + "description": "The permission ID used to uniquely identify a permission. Can either be a custom permission with lowercase letters, numbers, `:`, and `_` characters, or one of the system permissions: `$update_team`, `$delete_team`, `$read_members`, `$remove_members`, `$invite_members`, `$manage_api_keys`" + }, + "description": "The permission ID used to uniquely identify a permission. Can either be a custom permission with lowercase letters, numbers, `:`, and `_` characters, or one of the system permissions: `$update_team`, `$delete_team`, `$read_members`, `$remove_members`, `$invite_members`, `$manage_api_keys`", + "required": true + } + ], + "tags": [ + "Permissions" + ], + "x-full-url": "https://api.stack-auth.com/api/v1/team-permissions/{team_id}/{user_id}/{permission_id}", + "responses": { + "200": { + "description": "Successful response", + "content": { + "application/json": { + "schema": { + "type": "object", + "properties": { + "success": { + "type": "boolean", + "description": "Always equal to true.", + "example": true + } + }, + "required": [ + "success" + ] + } + } + } + } + } + } + }, + "/projects/current": { + "get": { + "summary": "Get the current project", + "description": "Get the current project information including display name, OAuth providers and authentication methods. Useful for displaying the available login options to the user.", + "parameters": [], + "tags": [ + "Projects" + ], + "x-full-url": "https://api.stack-auth.com/api/v1/projects/current", + "responses": { + "200": { + "description": "Successful response", + "content": { + "application/json": { + "schema": { + "type": "object", + "properties": { + "id": { + "type": "string", + "example": "e0b52f4d-dece-408c-af49-d23061bb0f8d", + "description": "The unique identifier of the project" + }, + "display_name": { + "type": "string", + "example": "MyMusic", + "description": "Human-readable project display name. This is not a unique identifier." + } + }, + "required": [ + "id", + "display_name" + ] + } + } + } + } + } + } + }, + "/auth/sessions": { + "get": { + "summary": "List sessions", + "description": "List all sessions for the current user.", + "parameters": [ + { + "name": "user_id", + "in": "query", + "schema": { + "type": "string", + "example": "3241a285-8329-4d69-8f3d-316e08cf140c", + "description": "The ID of the user, or the special value `me` for the currently authenticated user" + }, + "description": "The ID of the user, or the special value `me` for the currently authenticated user", + "required": true + } + ], + "tags": [ + "Sessions" + ], + "x-full-url": "https://api.stack-auth.com/api/v1/auth/sessions", + "responses": { + "200": { + "description": "Successful response", + "content": { + "application/json": { + "schema": { + "type": "object", + "properties": { + "items": { + "type": "array", + "items": { + "type": "object", + "properties": { + "id": { + "type": "string" + }, + "user_id": { + "type": "string" + }, + "created_at": { + "type": "number" + }, + "is_impersonation": { + "type": "boolean" + }, + "last_used_at": { + "type": "number" + }, + "is_current_session": { + "type": "boolean" + }, + "last_used_at_end_user_ip_info": { + "type": "object", + "properties": { + "ip": { + "type": "string" + }, + "countryCode": { + "type": "string" + }, + "regionCode": { + "type": "string" + }, + "cityName": { + "type": "string" + }, + "latitude": { + "type": "number" + }, + "longitude": { + "type": "number" + }, + "tzIdentifier": { + "type": "string" + } + }, + "required": [ + "ip" + ] + } + }, + "required": [ + "id", + "user_id", + "created_at", + "is_impersonation" + ] + } + }, + "pagination": { + "type": "object", + "properties": { + "next_cursor": { + "type": "string", + "example": "b3d396b8-c574-4c80-97b3-50031675ceb2", + "description": "The cursor to fetch the next page of results. null if there is no next page." + } + }, + "required": [] + } + }, + "required": [ + "items" + ] + } + } + } + } + } + }, + "post": { + "summary": "Create session", + "description": "Create a new session for a given user. This will return a refresh token that can be used to impersonate the user.", + "parameters": [], + "requestBody": { + "required": true, + "content": { + "application/json": { + "schema": { + "type": "object", + "properties": { + "user_id": { + "type": "string", + "example": "3241a285-8329-4d69-8f3d-316e08cf140c", + "description": "The ID of the user, or the special value `me` for the currently authenticated user" + }, + "expires_in_millis": { + "type": "number", + "default": 31536000000 + }, + "is_impersonation": { + "type": "boolean" + } + }, + "required": [ + "user_id" + ], + "example": { + "user_id": "3241a285-8329-4d69-8f3d-316e08cf140c" + } + } + } + } + }, + "tags": [ + "Sessions" + ], + "x-full-url": "https://api.stack-auth.com/api/v1/auth/sessions", + "responses": { + "200": { + "description": "Successful response", + "content": { + "application/json": { + "schema": { + "type": "object", + "properties": { + "refresh_token": { + "type": "string" + }, + "access_token": { + "type": "string" + } + }, + "required": [ + "refresh_token", + "access_token" + ] + } + } + } + } + } + } + }, + "/auth/sessions/current": { + "delete": { + "summary": "Sign out of the current session", + "description": "Sign out of the current session and invalidate the refresh token", + "parameters": [], + "tags": [ + "Sessions" + ], + "x-full-url": "https://api.stack-auth.com/api/v1/auth/sessions/current", + "responses": { + "200": { + "description": "Successful response", + "content": { + "application/json": { + "schema": { + "type": "object", + "properties": { + "success": { + "type": "boolean", + "description": "Always equal to true.", + "example": true + } + }, + "required": [ + "success" + ] + } + } + } + } + } + } + }, + "/auth/sessions/current/refresh": { + "post": { + "summary": "Refresh access token", + "description": "Get a new access token using a refresh token", + "parameters": [ + { + "name": "x-stack-refresh-token", + "in": "header", + "schema": { + "type": "string" + }, + "required": true + } + ], + "tags": [ + "Sessions" + ], + "x-full-url": "https://api.stack-auth.com/api/v1/auth/sessions/current/refresh", + "responses": { + "200": { + "description": "Successful response", + "content": { + "application/json": { + "schema": { + "type": "object", + "properties": { + "access_token": { + "type": "string" + } + }, + "required": [ + "access_token" + ] + } + } + } + } + } + } + }, + "/auth/sessions/{id}": { + "delete": { + "summary": "Delete session", + "description": "Delete a session by ID.", + "parameters": [ + { + "name": "user_id", + "in": "query", + "schema": { + "type": "string", + "example": "3241a285-8329-4d69-8f3d-316e08cf140c", + "description": "The ID of the user, or the special value `me` for the currently authenticated user" + }, + "description": "The ID of the user, or the special value `me` for the currently authenticated user", + "required": true + }, + { + "name": "id", + "in": "path", + "schema": { + "type": "string" + }, + "required": true + } + ], + "tags": [ + "Sessions" + ], + "x-full-url": "https://api.stack-auth.com/api/v1/auth/sessions/{id}", + "responses": { + "200": { + "description": "Successful response", + "content": { + "application/json": { + "schema": { + "type": "object", + "properties": { + "success": { + "type": "boolean", + "description": "Always equal to true.", + "example": true + } + }, + "required": [ + "success" + ] + } + } + } + } + } + } + }, + "/team-invitations": { + "get": { + "summary": "List team invitations", + "description": "", + "parameters": [ + { + "name": "team_id", + "in": "query", + "schema": { + "type": "string", + "description": "The team ID to list invitations for. Required unless user_id is provided." + }, + "description": "The team ID to list invitations for. Required unless user_id is provided.", + "required": false + }, + { + "name": "user_id", + "in": "query", + "schema": { + "type": "string", + "description": "List invitations sent to this user's verified emails. Must be \"me\" for client access. Cannot be combined with team_id." + }, + "description": "List invitations sent to this user's verified emails. Must be \"me\" for client access. Cannot be combined with team_id.", + "required": false + } + ], + "tags": [ + "Teams" + ], + "x-full-url": "https://api.stack-auth.com/api/v1/team-invitations", + "responses": { + "200": { + "description": "Successful response", + "content": { + "application/json": { + "schema": { + "type": "object", + "properties": { + "items": { + "type": "array", + "items": { + "type": "object", + "properties": { + "id": { + "type": "string" + }, + "team_id": { + "type": "string", + "example": "ad962777-8244-496a-b6a2-e0c6a449c79e", + "description": "The unique identifier of the team" + }, + "team_display_name": { + "type": "string" + }, + "expires_at_millis": { + "type": "number" + }, + "recipient_email": { + "type": "string" + } + }, + "required": [ + "id", + "team_id", + "team_display_name", + "expires_at_millis", + "recipient_email" + ] + } + }, + "pagination": { + "type": "object", + "properties": { + "next_cursor": { + "type": "string", + "example": "b3d396b8-c574-4c80-97b3-50031675ceb2", + "description": "The cursor to fetch the next page of results. null if there is no next page." + } + }, + "required": [] + } + }, + "required": [ + "items" + ] + } + } + } + } + } + } + }, + "/team-invitations/accept": { + "post": { + "summary": "Accept the team invitation", + "description": "Accept invitation and add user to the team", + "parameters": [], + "requestBody": { + "required": true, + "content": { + "application/json": { + "schema": { + "type": "object", + "properties": { + "code": { + "type": "string", + "example": "u3h6gn4w24pqc8ya679inrhjwh1rybth6a7thurqhnpf2", + "description": "A 45 character code" + } + }, + "required": [ + "code" + ], + "example": { + "code": "u3h6gn4w24pqc8ya679inrhjwh1rybth6a7thurqhnpf2" + } + } + } + } + }, + "tags": [ + "Teams" + ], + "x-full-url": "https://api.stack-auth.com/api/v1/team-invitations/accept", + "responses": { + "200": { + "description": "Successful response", + "content": { + "application/json": { + "schema": { + "type": "object", + "properties": {} + } + } + } + } + } + } + }, + "/team-invitations/accept/check-code": { + "post": { + "summary": "Check if a team invitation code is valid", + "description": "Check if a team invitation code is valid without using it", + "parameters": [], + "requestBody": { + "required": true, + "content": { + "application/json": { + "schema": { + "type": "object", + "properties": { + "code": { + "type": "string", + "example": "u3h6gn4w24pqc8ya679inrhjwh1rybth6a7thurqhnpf2", + "description": "A 45 character code" + } + }, + "required": [ + "code" + ], + "example": { + "code": "u3h6gn4w24pqc8ya679inrhjwh1rybth6a7thurqhnpf2" + } + } + } + } + }, + "tags": [ + "Teams" + ], + "x-full-url": "https://api.stack-auth.com/api/v1/team-invitations/accept/check-code", + "responses": { + "200": { + "description": "Successful response", + "content": { + "application/json": { + "schema": { + "type": "object", + "properties": { + "is_code_valid": { + "type": "boolean" + } + }, + "required": [ + "is_code_valid" + ] + } + } + } + } + } + } + }, + "/team-invitations/accept/details": { + "post": { + "summary": "Get team invitation details", + "description": "Get additional information about a team invitation code", + "parameters": [], + "requestBody": { + "required": true, + "content": { + "application/json": { + "schema": { + "type": "object", + "properties": { + "code": { + "type": "string", + "example": "u3h6gn4w24pqc8ya679inrhjwh1rybth6a7thurqhnpf2", + "description": "A 45 character code" + } + }, + "required": [ + "code" + ], + "example": { + "code": "u3h6gn4w24pqc8ya679inrhjwh1rybth6a7thurqhnpf2" + } + } + } + } + }, + "tags": [ + "Teams" + ], + "x-full-url": "https://api.stack-auth.com/api/v1/team-invitations/accept/details", + "responses": { + "200": { + "description": "Successful response", + "content": { + "application/json": { + "schema": { + "type": "object", + "properties": { + "team_id": { + "type": "string" + }, + "team_display_name": { + "type": "string" + } + }, + "required": [ + "team_id", + "team_display_name" + ] + } + } + } + } + } + } + }, + "/team-invitations/send-code": { + "post": { + "summary": "Send an email to invite a user to a team", + "description": "The user receiving this email can join the team by clicking on the link in the email. If the user does not have an account yet, they will be prompted to create one.", + "parameters": [], + "requestBody": { + "required": true, + "content": { + "application/json": { + "schema": { + "type": "object", + "properties": { + "team_id": { + "type": "string", + "example": "ad962777-8244-496a-b6a2-e0c6a449c79e", + "description": "The unique identifier of the team" + }, + "email": { + "type": "string", + "example": "johndoe@example.com", + "description": "The email of the user to invite." + }, + "callback_url": { + "type": "string", + "example": "https://example.com/handler/team-invitation", + "description": "The base callback URL to construct an invite link with. A query parameter `code` with the verification code will be appended to it. The page should then make a request to the `/team-invitations/accept` endpoint." + } + }, + "required": [ + "team_id", + "email", + "callback_url" + ], + "example": { + "team_id": "ad962777-8244-496a-b6a2-e0c6a449c79e", + "email": "johndoe@example.com", + "callback_url": "https://example.com/handler/team-invitation" + } + } + } + } + }, + "tags": [ + "Teams" + ], + "x-full-url": "https://api.stack-auth.com/api/v1/team-invitations/send-code", + "responses": { + "200": { + "description": "Successful response", + "content": { + "application/json": { + "schema": { + "type": "object", + "properties": { + "success": { + "type": "boolean" + }, + "id": { + "type": "string" + } + }, + "required": [ + "success", + "id" + ] + } + } + } + } + } + } + }, + "/team-invitations/{id}": { + "delete": { + "summary": "Delete a team invitation", + "description": "", + "parameters": [ + { + "name": "team_id", + "in": "query", + "schema": { + "type": "string", + "description": "The team ID to list invitations for. Required unless user_id is provided." + }, + "description": "The team ID to list invitations for. Required unless user_id is provided.", + "required": false + }, + { + "name": "id", + "in": "path", + "schema": { + "type": "string" + }, + "required": true + } + ], + "tags": [ + "Teams" + ], + "x-full-url": "https://api.stack-auth.com/api/v1/team-invitations/{id}", + "responses": { + "200": { + "description": "Successful response", + "content": { + "application/json": { + "schema": { + "type": "object", + "properties": { + "success": { + "type": "boolean", + "description": "Always equal to true.", + "example": true + } + }, + "required": [ + "success" + ] + } + } + } + } + } + } + }, + "/team-invitations/{id}/accept": { + "post": { + "summary": "Accept a team invitation by ID", + "description": "Accepts a team invitation for the specified user. The user must have a verified email matching the invitation's recipient email. This marks the invitation as used and adds the user to the team.", + "parameters": [ + { + "name": "user_id", + "in": "query", + "schema": { + "type": "string", + "example": "3241a285-8329-4d69-8f3d-316e08cf140c", + "description": "The ID of the user, or the special value `me` for the currently authenticated user" + }, + "description": "The ID of the user, or the special value `me` for the currently authenticated user", + "required": true + }, + { + "name": "id", + "in": "path", + "schema": { + "type": "string" + }, + "required": true + } + ], + "tags": [ + "Teams" + ], + "x-full-url": "https://api.stack-auth.com/api/v1/team-invitations/{id}/accept", + "responses": { + "200": { + "description": "Successful response", + "content": { + "application/json": { + "schema": { + "type": "object", + "properties": {} + } + } + } + } + } + } + }, + "/team-member-profiles": { + "get": { + "summary": "List team members profiles", + "description": "List team members profiles and filter by team ID and user ID", + "parameters": [ + { + "name": "user_id", + "in": "query", + "schema": { + "type": "string" + }, + "required": false + }, + { + "name": "team_id", + "in": "query", + "schema": { + "type": "string" + }, + "required": false + } + ], + "tags": [ + "Teams" + ], + "x-full-url": "https://api.stack-auth.com/api/v1/team-member-profiles", + "responses": { + "200": { + "description": "Successful response", + "content": { + "application/json": { + "schema": { + "type": "object", + "properties": { + "items": { + "type": "array", + "items": { + "type": "object", + "properties": { + "user": { + "type": "object", + "properties": { + "id": { + "type": "string", + "example": "3241a285-8329-4d69-8f3d-316e08cf140c", + "description": "The unique identifier of the user" + }, + "primary_email": { + "type": "string", + "example": "johndoe@example.com", + "description": "Primary email" + }, + "primary_email_verified": { + "type": "boolean", + "example": true, + "description": "Whether the primary email has been verified to belong to this user" + }, + "primary_email_auth_enabled": { + "type": "boolean", + "example": true, + "description": "Whether the primary email is used for authentication. If this is set to `false`, the user will not be able to sign in with the primary email with password or OTP" + }, + "display_name": { + "type": "string", + "example": "John Doe", + "description": "Human-readable user display name. This is not a unique identifier." + }, + "selected_team": { + "type": "object", + "properties": { + "created_at_millis": { + "type": "number", + "example": 1630000000000, + "description": "The time the team was created (the number of milliseconds since epoch, January 1, 1970, UTC)" + }, + "server_metadata": { + "type": "object", + "example": { + "key": "value" + }, + "description": "Server metadata. Used as a data store, only accessible from the server side. You can store secret information related to the team here." + }, + "id": { + "type": "string", + "example": "ad962777-8244-496a-b6a2-e0c6a449c79e", + "description": "The unique identifier of the team" + }, + "display_name": { + "type": "string", + "example": "My Team", + "description": "Human-readable team display name. This is not a unique identifier." + }, + "profile_image_url": { + "type": "string", + "example": "https://example.com/image.jpg", + "description": "URL of the profile image for team. Can be a Base64 encoded image. Must be smaller than 100KB. Please compress and crop to a square before passing in." + }, + "client_metadata": { + "type": "object", + "example": { + "key": "value" + }, + "description": "Client metadata. Used as a data store, accessible from the client side. Do not store information that should not be exposed to the client." + }, + "client_read_only_metadata": { + "type": "object", + "example": { + "key": "value" + }, + "description": "Client read-only, server-writable metadata. Used as a data store, accessible from the client side. Do not store information that should not be exposed to the client. The client can read this data, but cannot modify it. This is useful for things like subscription status." + } + }, + "required": [ + "created_at_millis", + "id", + "display_name" + ] + }, + "selected_team_id": { + "type": "string", + "example": "team-id", + "description": "ID of the team currently selected by the user" + }, + "profile_image_url": { + "type": "string", + "example": "https://example.com/image.jpg", + "description": "URL of the profile image for user. Can be a Base64 encoded image. Must be smaller than 100KB. Please compress and crop to a square before passing in." + }, + "signed_up_at_millis": { + "type": "number", + "example": 1630000000000, + "description": "The time the user signed up (identify) => `(the number of milliseconds since epoch, January 1, 1970, UTC)`" + }, + "client_metadata": { + "type": "object", + "example": { + "key": "value" + }, + "description": "Client metadata. Used as a data store, accessible from the client side. Do not store information that should not be exposed to the client." + }, + "client_read_only_metadata": { + "type": "object", + "example": { + "key": "value" + }, + "description": "Client read-only, server-writable metadata. Used as a data store, accessible from the client side. Do not store information that should not be exposed to the client. The client can read this data, but cannot modify it. This is useful for things like subscription status." + }, + "server_metadata": { + "type": "object", + "example": { + "key": "value" + }, + "description": "Server metadata. Used as a data store, only accessible from the server side. You can store secret information related to the user here." + }, + "last_active_at_millis": { + "type": "number", + "example": 1630000000000, + "description": "The time the user was last active (identify) => `(the number of milliseconds since epoch, January 1, 1970, UTC)`" + }, + "is_anonymous": { + "type": "boolean" + }, + "is_restricted": { + "type": "boolean", + "example": false, + "description": "Whether the user is in restricted state (has signed up but not completed onboarding requirements)" + }, + "restricted_reason": { + "type": "object", + "properties": { + "type": { + "type": "string" + } + }, + "required": [ + "type" + ], + "example": null, + "description": "The reason why the user is restricted (e.g., type: \"email_not_verified\", \"anonymous\", or \"restricted_by_administrator\"), null if not restricted" + }, + "restricted_by_admin": { + "type": "boolean", + "example": false, + "description": "Whether the user is restricted by an administrator. Can be set manually or by sign-up rules." + }, + "restricted_by_admin_reason": { + "type": "string", + "example": null, + "description": "Public reason shown to the user explaining why they are restricted. Optional." + }, + "restricted_by_admin_private_details": { + "type": "string", + "example": null, + "description": "Private details about the restriction (e.g., which sign-up rule triggered). Only visible to server access and above." + }, + "country_code": { + "type": "string", + "example": "US", + "description": "Best-effort ISO country code captured at sign-up time from request geo headers." + }, + "risk_scores": { + "type": "object", + "properties": { + "sign_up": { + "type": "object", + "properties": { + "bot": { + "type": "number" + }, + "free_trial_abuse": { + "type": "number" + } + }, + "required": [ + "bot", + "free_trial_abuse" + ] + } + }, + "required": [ + "sign_up" + ], + "example": { + "sign_up": { + "bot": 0, + "free_trial_abuse": 0 + } + }, + "description": "User risk scores used for sign-up risk evaluation." + } + }, + "required": [ + "id", + "primary_email_verified", + "primary_email_auth_enabled", + "signed_up_at_millis", + "last_active_at_millis", + "is_anonymous", + "is_restricted", + "restricted_by_admin", + "risk_scores" + ] + }, + "team_id": { + "type": "string", + "example": "ad962777-8244-496a-b6a2-e0c6a449c79e", + "description": "The unique identifier of the team" + }, + "user_id": { + "type": "string", + "example": "3241a285-8329-4d69-8f3d-316e08cf140c", + "description": "The unique identifier of the user" + }, + "display_name": { + "type": "string", + "example": "John Doe", + "description": "Human-readable team member display name. This is not a unique identifier. Note that this is separate from the display_name of the user." + }, + "profile_image_url": { + "type": "string", + "example": "https://example.com/image.jpg", + "description": "URL of the profile image for team member. Can be a Base64 encoded image. Must be smaller than 100KB. Please compress and crop to a square before passing in." + } + }, + "required": [ + "user", + "team_id", + "user_id" + ] + } + }, + "pagination": { + "type": "object", + "properties": { + "next_cursor": { + "type": "string", + "example": "b3d396b8-c574-4c80-97b3-50031675ceb2", + "description": "The cursor to fetch the next page of results. null if there is no next page." + } + }, + "required": [] + } + }, + "required": [ + "items" + ] + } + } + } + } + } + } + }, + "/team-member-profiles/{team_id}/{user_id}": { + "get": { + "summary": "Get a team member profile", + "description": "Get a team member profile by user ID", + "parameters": [ + { + "name": "team_id", + "in": "path", + "schema": { + "type": "string" + }, + "required": true + }, + { + "name": "user_id", + "in": "path", + "schema": { + "type": "string", + "example": "3241a285-8329-4d69-8f3d-316e08cf140c", + "description": "The ID of the user, or the special value `me` for the currently authenticated user" + }, + "description": "The ID of the user, or the special value `me` for the currently authenticated user", + "required": true + } + ], + "tags": [ + "Teams" + ], + "x-full-url": "https://api.stack-auth.com/api/v1/team-member-profiles/{team_id}/{user_id}", + "responses": { + "200": { + "description": "Successful response", + "content": { + "application/json": { + "schema": { + "type": "object", + "properties": { + "user": { + "type": "object", + "properties": { + "id": { + "type": "string", + "example": "3241a285-8329-4d69-8f3d-316e08cf140c", + "description": "The unique identifier of the user" + }, + "primary_email": { + "type": "string", + "example": "johndoe@example.com", + "description": "Primary email" + }, + "primary_email_verified": { + "type": "boolean", + "example": true, + "description": "Whether the primary email has been verified to belong to this user" + }, + "primary_email_auth_enabled": { + "type": "boolean", + "example": true, + "description": "Whether the primary email is used for authentication. If this is set to `false`, the user will not be able to sign in with the primary email with password or OTP" + }, + "display_name": { + "type": "string", + "example": "John Doe", + "description": "Human-readable user display name. This is not a unique identifier." + }, + "selected_team": { + "type": "object", + "properties": { + "created_at_millis": { + "type": "number", + "example": 1630000000000, + "description": "The time the team was created (the number of milliseconds since epoch, January 1, 1970, UTC)" + }, + "server_metadata": { + "type": "object", + "example": { + "key": "value" + }, + "description": "Server metadata. Used as a data store, only accessible from the server side. You can store secret information related to the team here." + }, + "id": { + "type": "string", + "example": "ad962777-8244-496a-b6a2-e0c6a449c79e", + "description": "The unique identifier of the team" + }, + "display_name": { + "type": "string", + "example": "My Team", + "description": "Human-readable team display name. This is not a unique identifier." + }, + "profile_image_url": { + "type": "string", + "example": "https://example.com/image.jpg", + "description": "URL of the profile image for team. Can be a Base64 encoded image. Must be smaller than 100KB. Please compress and crop to a square before passing in." + }, + "client_metadata": { + "type": "object", + "example": { + "key": "value" + }, + "description": "Client metadata. Used as a data store, accessible from the client side. Do not store information that should not be exposed to the client." + }, + "client_read_only_metadata": { + "type": "object", + "example": { + "key": "value" + }, + "description": "Client read-only, server-writable metadata. Used as a data store, accessible from the client side. Do not store information that should not be exposed to the client. The client can read this data, but cannot modify it. This is useful for things like subscription status." + } + }, + "required": [ + "created_at_millis", + "id", + "display_name" + ] + }, + "selected_team_id": { + "type": "string", + "example": "team-id", + "description": "ID of the team currently selected by the user" + }, + "profile_image_url": { + "type": "string", + "example": "https://example.com/image.jpg", + "description": "URL of the profile image for user. Can be a Base64 encoded image. Must be smaller than 100KB. Please compress and crop to a square before passing in." + }, + "signed_up_at_millis": { + "type": "number", + "example": 1630000000000, + "description": "The time the user signed up (identify) => `(the number of milliseconds since epoch, January 1, 1970, UTC)`" + }, + "client_metadata": { + "type": "object", + "example": { + "key": "value" + }, + "description": "Client metadata. Used as a data store, accessible from the client side. Do not store information that should not be exposed to the client." + }, + "client_read_only_metadata": { + "type": "object", + "example": { + "key": "value" + }, + "description": "Client read-only, server-writable metadata. Used as a data store, accessible from the client side. Do not store information that should not be exposed to the client. The client can read this data, but cannot modify it. This is useful for things like subscription status." + }, + "server_metadata": { + "type": "object", + "example": { + "key": "value" + }, + "description": "Server metadata. Used as a data store, only accessible from the server side. You can store secret information related to the user here." + }, + "last_active_at_millis": { + "type": "number", + "example": 1630000000000, + "description": "The time the user was last active (identify) => `(the number of milliseconds since epoch, January 1, 1970, UTC)`" + }, + "is_anonymous": { + "type": "boolean" + }, + "is_restricted": { + "type": "boolean", + "example": false, + "description": "Whether the user is in restricted state (has signed up but not completed onboarding requirements)" + }, + "restricted_reason": { + "type": "object", + "properties": { + "type": { + "type": "string" + } + }, + "required": [ + "type" + ], + "example": null, + "description": "The reason why the user is restricted (e.g., type: \"email_not_verified\", \"anonymous\", or \"restricted_by_administrator\"), null if not restricted" + }, + "restricted_by_admin": { + "type": "boolean", + "example": false, + "description": "Whether the user is restricted by an administrator. Can be set manually or by sign-up rules." + }, + "restricted_by_admin_reason": { + "type": "string", + "example": null, + "description": "Public reason shown to the user explaining why they are restricted. Optional." + }, + "restricted_by_admin_private_details": { + "type": "string", + "example": null, + "description": "Private details about the restriction (e.g., which sign-up rule triggered). Only visible to server access and above." + }, + "country_code": { + "type": "string", + "example": "US", + "description": "Best-effort ISO country code captured at sign-up time from request geo headers." + }, + "risk_scores": { + "type": "object", + "properties": { + "sign_up": { + "type": "object", + "properties": { + "bot": { + "type": "number" + }, + "free_trial_abuse": { + "type": "number" + } + }, + "required": [ + "bot", + "free_trial_abuse" + ] + } + }, + "required": [ + "sign_up" + ], + "example": { + "sign_up": { + "bot": 0, + "free_trial_abuse": 0 + } + }, + "description": "User risk scores used for sign-up risk evaluation." + } + }, + "required": [ + "id", + "primary_email_verified", + "primary_email_auth_enabled", + "signed_up_at_millis", + "last_active_at_millis", + "is_anonymous", + "is_restricted", + "restricted_by_admin", + "risk_scores" + ] + }, + "team_id": { + "type": "string", + "example": "ad962777-8244-496a-b6a2-e0c6a449c79e", + "description": "The unique identifier of the team" + }, + "user_id": { + "type": "string", + "example": "3241a285-8329-4d69-8f3d-316e08cf140c", + "description": "The unique identifier of the user" + }, + "display_name": { + "type": "string", + "example": "John Doe", + "description": "Human-readable team member display name. This is not a unique identifier. Note that this is separate from the display_name of the user." + }, + "profile_image_url": { + "type": "string", + "example": "https://example.com/image.jpg", + "description": "URL of the profile image for team member. Can be a Base64 encoded image. Must be smaller than 100KB. Please compress and crop to a square before passing in." + } + }, + "required": [ + "user", + "team_id", + "user_id" + ] + } + } + } + } + } + }, + "patch": { + "summary": "Update a team member profile", + "description": "Update a team member profile by user ID", + "parameters": [ + { + "name": "team_id", + "in": "path", + "schema": { + "type": "string" + }, + "required": true + }, + { + "name": "user_id", + "in": "path", + "schema": { + "type": "string", + "example": "3241a285-8329-4d69-8f3d-316e08cf140c", + "description": "The ID of the user, or the special value `me` for the currently authenticated user" + }, + "description": "The ID of the user, or the special value `me` for the currently authenticated user", + "required": true + } + ], + "requestBody": { + "required": true, + "content": { + "application/json": { + "schema": { + "type": "object", + "properties": { + "display_name": { + "type": "string", + "example": "John Doe", + "description": "Human-readable team member display name. This is not a unique identifier. Note that this is separate from the display_name of the user." + }, + "profile_image_url": { + "type": "string", + "example": "https://example.com/image.jpg", + "description": "URL of the profile image for team member. Can be a Base64 encoded image. Must be smaller than 100KB. Please compress and crop to a square before passing in." + } + }, + "example": { + "display_name": "John Doe", + "profile_image_url": "https://example.com/image.jpg" + } + } + } + } + }, + "tags": [ + "Teams" + ], + "x-full-url": "https://api.stack-auth.com/api/v1/team-member-profiles/{team_id}/{user_id}", + "responses": { + "200": { + "description": "Successful response", + "content": { + "application/json": { + "schema": { + "type": "object", + "properties": { + "user": { + "type": "object", + "properties": { + "id": { + "type": "string", + "example": "3241a285-8329-4d69-8f3d-316e08cf140c", + "description": "The unique identifier of the user" + }, + "primary_email": { + "type": "string", + "example": "johndoe@example.com", + "description": "Primary email" + }, + "primary_email_verified": { + "type": "boolean", + "example": true, + "description": "Whether the primary email has been verified to belong to this user" + }, + "primary_email_auth_enabled": { + "type": "boolean", + "example": true, + "description": "Whether the primary email is used for authentication. If this is set to `false`, the user will not be able to sign in with the primary email with password or OTP" + }, + "display_name": { + "type": "string", + "example": "John Doe", + "description": "Human-readable user display name. This is not a unique identifier." + }, + "selected_team": { + "type": "object", + "properties": { + "created_at_millis": { + "type": "number", + "example": 1630000000000, + "description": "The time the team was created (the number of milliseconds since epoch, January 1, 1970, UTC)" + }, + "server_metadata": { + "type": "object", + "example": { + "key": "value" + }, + "description": "Server metadata. Used as a data store, only accessible from the server side. You can store secret information related to the team here." + }, + "id": { + "type": "string", + "example": "ad962777-8244-496a-b6a2-e0c6a449c79e", + "description": "The unique identifier of the team" + }, + "display_name": { + "type": "string", + "example": "My Team", + "description": "Human-readable team display name. This is not a unique identifier." + }, + "profile_image_url": { + "type": "string", + "example": "https://example.com/image.jpg", + "description": "URL of the profile image for team. Can be a Base64 encoded image. Must be smaller than 100KB. Please compress and crop to a square before passing in." + }, + "client_metadata": { + "type": "object", + "example": { + "key": "value" + }, + "description": "Client metadata. Used as a data store, accessible from the client side. Do not store information that should not be exposed to the client." + }, + "client_read_only_metadata": { + "type": "object", + "example": { + "key": "value" + }, + "description": "Client read-only, server-writable metadata. Used as a data store, accessible from the client side. Do not store information that should not be exposed to the client. The client can read this data, but cannot modify it. This is useful for things like subscription status." + } + }, + "required": [ + "created_at_millis", + "id", + "display_name" + ] + }, + "selected_team_id": { + "type": "string", + "example": "team-id", + "description": "ID of the team currently selected by the user" + }, + "profile_image_url": { + "type": "string", + "example": "https://example.com/image.jpg", + "description": "URL of the profile image for user. Can be a Base64 encoded image. Must be smaller than 100KB. Please compress and crop to a square before passing in." + }, + "signed_up_at_millis": { + "type": "number", + "example": 1630000000000, + "description": "The time the user signed up (identify) => `(the number of milliseconds since epoch, January 1, 1970, UTC)`" + }, + "client_metadata": { + "type": "object", + "example": { + "key": "value" + }, + "description": "Client metadata. Used as a data store, accessible from the client side. Do not store information that should not be exposed to the client." + }, + "client_read_only_metadata": { + "type": "object", + "example": { + "key": "value" + }, + "description": "Client read-only, server-writable metadata. Used as a data store, accessible from the client side. Do not store information that should not be exposed to the client. The client can read this data, but cannot modify it. This is useful for things like subscription status." + }, + "server_metadata": { + "type": "object", + "example": { + "key": "value" + }, + "description": "Server metadata. Used as a data store, only accessible from the server side. You can store secret information related to the user here." + }, + "last_active_at_millis": { + "type": "number", + "example": 1630000000000, + "description": "The time the user was last active (identify) => `(the number of milliseconds since epoch, January 1, 1970, UTC)`" + }, + "is_anonymous": { + "type": "boolean" + }, + "is_restricted": { + "type": "boolean", + "example": false, + "description": "Whether the user is in restricted state (has signed up but not completed onboarding requirements)" + }, + "restricted_reason": { + "type": "object", + "properties": { + "type": { + "type": "string" + } + }, + "required": [ + "type" + ], + "example": null, + "description": "The reason why the user is restricted (e.g., type: \"email_not_verified\", \"anonymous\", or \"restricted_by_administrator\"), null if not restricted" + }, + "restricted_by_admin": { + "type": "boolean", + "example": false, + "description": "Whether the user is restricted by an administrator. Can be set manually or by sign-up rules." + }, + "restricted_by_admin_reason": { + "type": "string", + "example": null, + "description": "Public reason shown to the user explaining why they are restricted. Optional." + }, + "restricted_by_admin_private_details": { + "type": "string", + "example": null, + "description": "Private details about the restriction (e.g., which sign-up rule triggered). Only visible to server access and above." + }, + "country_code": { + "type": "string", + "example": "US", + "description": "Best-effort ISO country code captured at sign-up time from request geo headers." + }, + "risk_scores": { + "type": "object", + "properties": { + "sign_up": { + "type": "object", + "properties": { + "bot": { + "type": "number" + }, + "free_trial_abuse": { + "type": "number" + } + }, + "required": [ + "bot", + "free_trial_abuse" + ] + } + }, + "required": [ + "sign_up" + ], + "example": { + "sign_up": { + "bot": 0, + "free_trial_abuse": 0 + } + }, + "description": "User risk scores used for sign-up risk evaluation." + } + }, + "required": [ + "id", + "primary_email_verified", + "primary_email_auth_enabled", + "signed_up_at_millis", + "last_active_at_millis", + "is_anonymous", + "is_restricted", + "restricted_by_admin", + "risk_scores" + ] + }, + "team_id": { + "type": "string", + "example": "ad962777-8244-496a-b6a2-e0c6a449c79e", + "description": "The unique identifier of the team" + }, + "user_id": { + "type": "string", + "example": "3241a285-8329-4d69-8f3d-316e08cf140c", + "description": "The unique identifier of the user" + }, + "display_name": { + "type": "string", + "example": "John Doe", + "description": "Human-readable team member display name. This is not a unique identifier. Note that this is separate from the display_name of the user." + }, + "profile_image_url": { + "type": "string", + "example": "https://example.com/image.jpg", + "description": "URL of the profile image for team member. Can be a Base64 encoded image. Must be smaller than 100KB. Please compress and crop to a square before passing in." + } + }, + "required": [ + "user", + "team_id", + "user_id" + ] + } + } + } + } + } + } + }, + "/team-memberships/{team_id}/{user_id}": { + "post": { + "summary": "Add a user to a team", + "description": "", + "parameters": [ + { + "name": "team_id", + "in": "path", + "schema": { + "type": "string" + }, + "required": false + }, + { + "name": "user_id", + "in": "path", + "schema": { + "type": "string", + "example": "3241a285-8329-4d69-8f3d-316e08cf140c", + "description": "The ID of the user, or the special value `me` for the currently authenticated user" + }, + "description": "The ID of the user, or the special value `me` for the currently authenticated user", + "required": false + } + ], + "requestBody": { + "required": true, + "content": { + "application/json": { + "schema": { + "type": "object", + "properties": {}, + "example": {} + } + } + } + }, + "tags": [ + "Teams" + ], + "x-full-url": "https://api.stack-auth.com/api/v1/team-memberships/{team_id}/{user_id}", + "responses": { + "201": { + "description": "Successful response", + "content": { + "application/json": { + "schema": { + "type": "object", + "properties": { + "team_id": { + "type": "string" + }, + "user_id": { + "type": "string" + } + }, + "required": [ + "team_id", + "user_id" + ] + } + } + } + } + } + }, + "delete": { + "summary": "Remove a user from a team", + "description": "", + "parameters": [ + { + "name": "team_id", + "in": "path", + "schema": { + "type": "string" + }, + "required": true + }, + { + "name": "user_id", + "in": "path", + "schema": { + "type": "string", + "example": "3241a285-8329-4d69-8f3d-316e08cf140c", + "description": "The ID of the user, or the special value `me` for the currently authenticated user" + }, + "description": "The ID of the user, or the special value `me` for the currently authenticated user", + "required": true + } + ], + "tags": [ + "Teams" + ], + "x-full-url": "https://api.stack-auth.com/api/v1/team-memberships/{team_id}/{user_id}", + "responses": { + "200": { + "description": "Successful response", + "content": { + "application/json": { + "schema": { + "type": "object", + "properties": { + "success": { + "type": "boolean", + "description": "Always equal to true.", + "example": true + } + }, + "required": [ + "success" + ] + } + } + } + } + } + } + }, + "/teams": { + "get": { + "summary": "List teams", + "description": "List all the teams in the project.", + "parameters": [ + { + "name": "user_id", + "in": "query", + "schema": { + "type": "string", + "example": "me", + "description": "Filter for the teams that the user is a member of. Can be either `me` or an ID. Must be `me` in the client API" + }, + "description": "Filter for the teams that the user is a member of. Can be either `me` or an ID. Must be `me` in the client API", + "required": false + } + ], + "tags": [ + "Teams" + ], + "x-full-url": "https://api.stack-auth.com/api/v1/teams", + "responses": { + "200": { + "description": "Successful response", + "content": { + "application/json": { + "schema": { + "type": "object", + "properties": { + "items": { + "type": "array", + "items": { + "type": "object", + "properties": { + "created_at_millis": { + "type": "number", + "example": 1630000000000, + "description": "The time the team was created (the number of milliseconds since epoch, January 1, 1970, UTC)" + }, + "server_metadata": { + "type": "object", + "example": { + "key": "value" + }, + "description": "Server metadata. Used as a data store, only accessible from the server side. You can store secret information related to the team here." + }, + "id": { + "type": "string", + "example": "ad962777-8244-496a-b6a2-e0c6a449c79e", + "description": "The unique identifier of the team" + }, + "display_name": { + "type": "string", + "example": "My Team", + "description": "Human-readable team display name. This is not a unique identifier." + }, + "profile_image_url": { + "type": "string", + "example": "https://example.com/image.jpg", + "description": "URL of the profile image for team. Can be a Base64 encoded image. Must be smaller than 100KB. Please compress and crop to a square before passing in." + }, + "client_metadata": { + "type": "object", + "example": { + "key": "value" + }, + "description": "Client metadata. Used as a data store, accessible from the client side. Do not store information that should not be exposed to the client." + }, + "client_read_only_metadata": { + "type": "object", + "example": { + "key": "value" + }, + "description": "Client read-only, server-writable metadata. Used as a data store, accessible from the client side. Do not store information that should not be exposed to the client. The client can read this data, but cannot modify it. This is useful for things like subscription status." + } + }, + "required": [ + "created_at_millis", + "id", + "display_name" + ] + } + }, + "pagination": { + "type": "object", + "properties": { + "next_cursor": { + "type": "string", + "example": "b3d396b8-c574-4c80-97b3-50031675ceb2", + "description": "The cursor to fetch the next page of results. null if there is no next page." + } + }, + "required": [] + } + }, + "required": [ + "items" + ] + } + } + } + } + } + }, + "post": { + "summary": "Create a team", + "description": "Create a new team and optionally add the current user as a member.", + "parameters": [], + "requestBody": { + "required": true, + "content": { + "application/json": { + "schema": { + "type": "object", + "properties": { + "display_name": { + "type": "string", + "example": "My Team", + "description": "Human-readable team display name. This is not a unique identifier." + }, + "creator_user_id": { + "type": "string", + "example": "me", + "description": "The ID of the creator of the team. If not specified, the user will not be added to the team. Can be either \"me\" or the ID of the user. Only used on the client side." + }, + "client_read_only_metadata": { + "type": "object", + "example": { + "key": "value" + }, + "description": "Client read-only, server-writable metadata. Used as a data store, accessible from the client side. Do not store information that should not be exposed to the client. The client can read this data, but cannot modify it. This is useful for things like subscription status." + }, + "server_metadata": { + "type": "object", + "example": { + "key": "value" + }, + "description": "Server metadata. Used as a data store, only accessible from the server side. You can store secret information related to the team here." + }, + "profile_image_url": { + "type": "string", + "example": "https://example.com/image.jpg", + "description": "URL of the profile image for team. Can be a Base64 encoded image. Must be smaller than 100KB. Please compress and crop to a square before passing in." + }, + "client_metadata": { + "type": "object", + "example": { + "key": "value" + }, + "description": "Client metadata. Used as a data store, accessible from the client side. Do not store information that should not be exposed to the client." + } + }, + "required": [ + "display_name" + ], + "example": { + "display_name": "My Team", + "creator_user_id": "me", + "client_read_only_metadata": { + "key": "value" + }, + "server_metadata": { + "key": "value" + }, + "profile_image_url": "https://example.com/image.jpg", + "client_metadata": { + "key": "value" + } + } + } + } + } + }, + "tags": [ + "Teams" + ], + "x-full-url": "https://api.stack-auth.com/api/v1/teams", + "responses": { + "201": { + "description": "Successful response", + "content": { + "application/json": { + "schema": { + "type": "object", + "properties": { + "created_at_millis": { + "type": "number", + "example": 1630000000000, + "description": "The time the team was created (the number of milliseconds since epoch, January 1, 1970, UTC)" + }, + "server_metadata": { + "type": "object", + "example": { + "key": "value" + }, + "description": "Server metadata. Used as a data store, only accessible from the server side. You can store secret information related to the team here." + }, + "id": { + "type": "string", + "example": "ad962777-8244-496a-b6a2-e0c6a449c79e", + "description": "The unique identifier of the team" + }, + "display_name": { + "type": "string", + "example": "My Team", + "description": "Human-readable team display name. This is not a unique identifier." + }, + "profile_image_url": { + "type": "string", + "example": "https://example.com/image.jpg", + "description": "URL of the profile image for team. Can be a Base64 encoded image. Must be smaller than 100KB. Please compress and crop to a square before passing in." + }, + "client_metadata": { + "type": "object", + "example": { + "key": "value" + }, + "description": "Client metadata. Used as a data store, accessible from the client side. Do not store information that should not be exposed to the client." + }, + "client_read_only_metadata": { + "type": "object", + "example": { + "key": "value" + }, + "description": "Client read-only, server-writable metadata. Used as a data store, accessible from the client side. Do not store information that should not be exposed to the client. The client can read this data, but cannot modify it. This is useful for things like subscription status." + } + }, + "required": [ + "created_at_millis", + "id", + "display_name" + ] + } + } + } + } + } + } + }, + "/teams/{team_id}": { + "get": { + "summary": "Get a team", + "description": "Get a team by ID.", + "parameters": [ + { + "name": "team_id", + "in": "path", + "schema": { + "type": "string" + }, + "required": true + } + ], + "tags": [ + "Teams" + ], + "x-full-url": "https://api.stack-auth.com/api/v1/teams/{team_id}", + "responses": { + "200": { + "description": "Successful response", + "content": { + "application/json": { + "schema": { + "type": "object", + "properties": { + "created_at_millis": { + "type": "number", + "example": 1630000000000, + "description": "The time the team was created (the number of milliseconds since epoch, January 1, 1970, UTC)" + }, + "server_metadata": { + "type": "object", + "example": { + "key": "value" + }, + "description": "Server metadata. Used as a data store, only accessible from the server side. You can store secret information related to the team here." + }, + "id": { + "type": "string", + "example": "ad962777-8244-496a-b6a2-e0c6a449c79e", + "description": "The unique identifier of the team" + }, + "display_name": { + "type": "string", + "example": "My Team", + "description": "Human-readable team display name. This is not a unique identifier." + }, + "profile_image_url": { + "type": "string", + "example": "https://example.com/image.jpg", + "description": "URL of the profile image for team. Can be a Base64 encoded image. Must be smaller than 100KB. Please compress and crop to a square before passing in." + }, + "client_metadata": { + "type": "object", + "example": { + "key": "value" + }, + "description": "Client metadata. Used as a data store, accessible from the client side. Do not store information that should not be exposed to the client." + }, + "client_read_only_metadata": { + "type": "object", + "example": { + "key": "value" + }, + "description": "Client read-only, server-writable metadata. Used as a data store, accessible from the client side. Do not store information that should not be exposed to the client. The client can read this data, but cannot modify it. This is useful for things like subscription status." + } + }, + "required": [ + "created_at_millis", + "id", + "display_name" + ] + } + } + } + } + } + }, + "delete": { + "summary": "Delete a team", + "description": "Delete a team by ID.", + "parameters": [ + { + "name": "team_id", + "in": "path", + "schema": { + "type": "string" + }, + "required": true + } + ], + "tags": [ + "Teams" + ], + "x-full-url": "https://api.stack-auth.com/api/v1/teams/{team_id}", + "responses": { + "200": { + "description": "Successful response", + "content": { + "application/json": { + "schema": { + "type": "object", + "properties": { + "success": { + "type": "boolean", + "description": "Always equal to true.", + "example": true + } + }, + "required": [ + "success" + ] + } + } + } + } + } + }, + "patch": { + "summary": "Update a team", + "description": "Update the team information by ID.", + "parameters": [ + { + "name": "team_id", + "in": "path", + "schema": { + "type": "string" + }, + "required": true + } + ], + "requestBody": { + "required": true, + "content": { + "application/json": { + "schema": { + "type": "object", + "properties": { + "client_read_only_metadata": { + "type": "object", + "example": { + "key": "value" + }, + "description": "Client read-only, server-writable metadata. Used as a data store, accessible from the client side. Do not store information that should not be exposed to the client. The client can read this data, but cannot modify it. This is useful for things like subscription status." + }, + "server_metadata": { + "type": "object", + "example": { + "key": "value" + }, + "description": "Server metadata. Used as a data store, only accessible from the server side. You can store secret information related to the team here." + }, + "display_name": { + "type": "string", + "example": "My Team", + "description": "Human-readable team display name. This is not a unique identifier." + }, + "profile_image_url": { + "type": "string", + "example": "https://example.com/image.jpg", + "description": "URL of the profile image for team. Can be a Base64 encoded image. Must be smaller than 100KB. Please compress and crop to a square before passing in." + }, + "client_metadata": { + "type": "object", + "example": { + "key": "value" + }, + "description": "Client metadata. Used as a data store, accessible from the client side. Do not store information that should not be exposed to the client." + } + }, + "example": { + "client_read_only_metadata": { + "key": "value" + }, + "server_metadata": { + "key": "value" + }, + "display_name": "My Team", + "profile_image_url": "https://example.com/image.jpg", + "client_metadata": { + "key": "value" + } + } + } + } + } + }, + "tags": [ + "Teams" + ], + "x-full-url": "https://api.stack-auth.com/api/v1/teams/{team_id}", + "responses": { + "200": { + "description": "Successful response", + "content": { + "application/json": { + "schema": { + "type": "object", + "properties": { + "created_at_millis": { + "type": "number", + "example": 1630000000000, + "description": "The time the team was created (the number of milliseconds since epoch, January 1, 1970, UTC)" + }, + "server_metadata": { + "type": "object", + "example": { + "key": "value" + }, + "description": "Server metadata. Used as a data store, only accessible from the server side. You can store secret information related to the team here." + }, + "id": { + "type": "string", + "example": "ad962777-8244-496a-b6a2-e0c6a449c79e", + "description": "The unique identifier of the team" + }, + "display_name": { + "type": "string", + "example": "My Team", + "description": "Human-readable team display name. This is not a unique identifier." + }, + "profile_image_url": { + "type": "string", + "example": "https://example.com/image.jpg", + "description": "URL of the profile image for team. Can be a Base64 encoded image. Must be smaller than 100KB. Please compress and crop to a square before passing in." + }, + "client_metadata": { + "type": "object", + "example": { + "key": "value" + }, + "description": "Client metadata. Used as a data store, accessible from the client side. Do not store information that should not be exposed to the client." + }, + "client_read_only_metadata": { + "type": "object", + "example": { + "key": "value" + }, + "description": "Client read-only, server-writable metadata. Used as a data store, accessible from the client side. Do not store information that should not be exposed to the client. The client can read this data, but cannot modify it. This is useful for things like subscription status." + } + }, + "required": [ + "created_at_millis", + "id", + "display_name" + ] + } + } + } + } + } + } + }, + "/users": { + "get": { + "summary": "List users", + "description": "Lists all the users in the project. By default, only fully onboarded users are returned. Restricted users (those who haven't completed onboarding requirements like email verification) are included if `include_restricted` is set to `true`. Anonymous users are included if `include_anonymous` is set to `true` (which also includes restricted users).", + "parameters": [ + { + "name": "team_id", + "in": "query", + "schema": { + "type": "string", + "description": "Only return users who are members of the given team" + }, + "description": "Only return users who are members of the given team", + "required": false + }, + { + "name": "limit", + "in": "query", + "schema": { + "type": "number", + "description": "The maximum number of items to return" + }, + "description": "The maximum number of items to return", + "required": false + }, + { + "name": "cursor", + "in": "query", + "schema": { + "type": "string", + "description": "The cursor to start the result set from." + }, + "description": "The cursor to start the result set from.", + "required": false + }, + { + "name": "order_by", + "in": "query", + "schema": { + "type": "string", + "description": "The field to sort the results by. Defaults to signed_up_at" + }, + "description": "The field to sort the results by. Defaults to signed_up_at", + "required": false + }, + { + "name": "desc", + "in": "query", + "schema": { + "type": "string", + "description": "Whether to sort the results in descending order. Defaults to false" + }, + "description": "Whether to sort the results in descending order. Defaults to false", + "required": false + }, + { + "name": "query", + "in": "query", + "schema": { + "type": "string", + "description": "A search query to filter the results by. This is a free-text search that is applied to the user's id (exact-match only), display name and primary email." + }, + "description": "A search query to filter the results by. This is a free-text search that is applied to the user's id (exact-match only), display name and primary email.", + "required": false + }, + { + "name": "include_anonymous", + "in": "query", + "schema": { + "type": "string", + "description": "Whether to include anonymous users in the results. When true, also includes restricted users. Defaults to false" + }, + "description": "Whether to include anonymous users in the results. When true, also includes restricted users. Defaults to false", + "required": false + }, + { + "name": "only_anonymous", + "in": "query", + "schema": { + "type": "string", + "description": "Whether to return only anonymous users. When true, implies include_anonymous=true. Defaults to false" + }, + "description": "Whether to return only anonymous users. When true, implies include_anonymous=true. Defaults to false", + "required": false + }, + { + "name": "include_restricted", + "in": "query", + "schema": { + "type": "string", + "description": "Whether to include restricted users in the results. Defaults to false" + }, + "description": "Whether to include restricted users in the results. Defaults to false", + "required": false + } + ], + "tags": [ + "Users" + ], + "x-full-url": "https://api.stack-auth.com/api/v1/users", + "responses": { + "200": { + "description": "Successful response", + "content": { + "application/json": { + "schema": { + "type": "object", + "properties": { + "items": { + "type": "array", + "items": { + "type": "object", + "properties": { + "id": { + "type": "string", + "example": "3241a285-8329-4d69-8f3d-316e08cf140c", + "description": "The unique identifier of the user" + }, + "primary_email": { + "type": "string", + "example": "johndoe@example.com", + "description": "Primary email" + }, + "primary_email_verified": { + "type": "boolean", + "example": true, + "description": "Whether the primary email has been verified to belong to this user" + }, + "primary_email_auth_enabled": { + "type": "boolean", + "example": true, + "description": "Whether the primary email is used for authentication. If this is set to `false`, the user will not be able to sign in with the primary email with password or OTP" + }, + "display_name": { + "type": "string", + "example": "John Doe", + "description": "Human-readable user display name. This is not a unique identifier." + }, + "selected_team": { + "type": "object", + "properties": { + "created_at_millis": { + "type": "number", + "example": 1630000000000, + "description": "The time the team was created (the number of milliseconds since epoch, January 1, 1970, UTC)" + }, + "server_metadata": { + "type": "object", + "example": { + "key": "value" + }, + "description": "Server metadata. Used as a data store, only accessible from the server side. You can store secret information related to the team here." + }, + "id": { + "type": "string", + "example": "ad962777-8244-496a-b6a2-e0c6a449c79e", + "description": "The unique identifier of the team" + }, + "display_name": { + "type": "string", + "example": "My Team", + "description": "Human-readable team display name. This is not a unique identifier." + }, + "profile_image_url": { + "type": "string", + "example": "https://example.com/image.jpg", + "description": "URL of the profile image for team. Can be a Base64 encoded image. Must be smaller than 100KB. Please compress and crop to a square before passing in." + }, + "client_metadata": { + "type": "object", + "example": { + "key": "value" + }, + "description": "Client metadata. Used as a data store, accessible from the client side. Do not store information that should not be exposed to the client." + }, + "client_read_only_metadata": { + "type": "object", + "example": { + "key": "value" + }, + "description": "Client read-only, server-writable metadata. Used as a data store, accessible from the client side. Do not store information that should not be exposed to the client. The client can read this data, but cannot modify it. This is useful for things like subscription status." + } + }, + "required": [ + "created_at_millis", + "id", + "display_name" + ] + }, + "selected_team_id": { + "type": "string", + "example": "team-id", + "description": "ID of the team currently selected by the user" + }, + "profile_image_url": { + "type": "string", + "example": "https://example.com/image.jpg", + "description": "URL of the profile image for user. Can be a Base64 encoded image. Must be smaller than 100KB. Please compress and crop to a square before passing in." + }, + "signed_up_at_millis": { + "type": "number", + "example": 1630000000000, + "description": "The time the user signed up (identify) => `(the number of milliseconds since epoch, January 1, 1970, UTC)`" + }, + "client_metadata": { + "type": "object", + "example": { + "key": "value" + }, + "description": "Client metadata. Used as a data store, accessible from the client side. Do not store information that should not be exposed to the client." + }, + "client_read_only_metadata": { + "type": "object", + "example": { + "key": "value" + }, + "description": "Client read-only, server-writable metadata. Used as a data store, accessible from the client side. Do not store information that should not be exposed to the client. The client can read this data, but cannot modify it. This is useful for things like subscription status." + }, + "server_metadata": { + "type": "object", + "example": { + "key": "value" + }, + "description": "Server metadata. Used as a data store, only accessible from the server side. You can store secret information related to the user here." + }, + "last_active_at_millis": { + "type": "number", + "example": 1630000000000, + "description": "The time the user was last active (identify) => `(the number of milliseconds since epoch, January 1, 1970, UTC)`" + }, + "is_anonymous": { + "type": "boolean" + }, + "is_restricted": { + "type": "boolean", + "example": false, + "description": "Whether the user is in restricted state (has signed up but not completed onboarding requirements)" + }, + "restricted_reason": { + "type": "object", + "properties": { + "type": { + "type": "string" + } + }, + "required": [ + "type" + ], + "example": null, + "description": "The reason why the user is restricted (e.g., type: \"email_not_verified\", \"anonymous\", or \"restricted_by_administrator\"), null if not restricted" + }, + "restricted_by_admin": { + "type": "boolean", + "example": false, + "description": "Whether the user is restricted by an administrator. Can be set manually or by sign-up rules." + }, + "restricted_by_admin_reason": { + "type": "string", + "example": null, + "description": "Public reason shown to the user explaining why they are restricted. Optional." + }, + "restricted_by_admin_private_details": { + "type": "string", + "example": null, + "description": "Private details about the restriction (e.g., which sign-up rule triggered). Only visible to server access and above." + }, + "country_code": { + "type": "string", + "example": "US", + "description": "Best-effort ISO country code captured at sign-up time from request geo headers." + }, + "risk_scores": { + "type": "object", + "properties": { + "sign_up": { + "type": "object", + "properties": { + "bot": { + "type": "number" + }, + "free_trial_abuse": { + "type": "number" + } + }, + "required": [ + "bot", + "free_trial_abuse" + ] + } + }, + "required": [ + "sign_up" + ], + "example": { + "sign_up": { + "bot": 0, + "free_trial_abuse": 0 + } + }, + "description": "User risk scores used for sign-up risk evaluation." + } + }, + "required": [ + "id", + "primary_email_verified", + "primary_email_auth_enabled", + "signed_up_at_millis", + "last_active_at_millis", + "is_anonymous", + "is_restricted", + "restricted_by_admin", + "risk_scores" + ] + } + }, + "pagination": { + "type": "object", + "properties": { + "next_cursor": { + "type": "string", + "example": "b3d396b8-c574-4c80-97b3-50031675ceb2", + "description": "The cursor to fetch the next page of results. null if there is no next page." + } + }, + "required": [] + } + }, + "required": [ + "items" + ] + } + } + } + } + } + }, + "post": { + "summary": "Create user", + "description": "Creates a new user. E-mail authentication is always enabled, and no password is set, meaning the only way to authenticate the newly created user is through magic link.", + "parameters": [], + "requestBody": { + "required": true, + "content": { + "application/json": { + "schema": { + "type": "object", + "properties": { + "is_anonymous": { + "type": "boolean" + }, + "display_name": { + "type": "string", + "example": "John Doe", + "description": "Human-readable user display name. This is not a unique identifier." + }, + "profile_image_url": { + "type": "string", + "example": "https://example.com/image.jpg", + "description": "URL of the profile image for user. Can be a Base64 encoded image. Must be smaller than 100KB. Please compress and crop to a square before passing in." + }, + "client_metadata": { + "type": "object", + "example": { + "key": "value" + }, + "description": "Client metadata. Used as a data store, accessible from the client side. Do not store information that should not be exposed to the client." + }, + "client_read_only_metadata": { + "type": "object", + "example": { + "key": "value" + }, + "description": "Client read-only, server-writable metadata. Used as a data store, accessible from the client side. Do not store information that should not be exposed to the client. The client can read this data, but cannot modify it. This is useful for things like subscription status." + }, + "server_metadata": { + "type": "object", + "example": { + "key": "value" + }, + "description": "Server metadata. Used as a data store, only accessible from the server side. You can store secret information related to the user here." + }, + "primary_email": { + "type": "string", + "example": "johndoe@example.com", + "description": "Primary email" + }, + "primary_email_verified": { + "type": "boolean", + "example": true, + "description": "Whether the primary email has been verified to belong to this user" + }, + "primary_email_auth_enabled": { + "type": "boolean", + "example": true, + "description": "Whether the primary email is used for authentication. If this is set to `false`, the user will not be able to sign in with the primary email with password or OTP" + }, + "password": { + "type": "string", + "example": "my-new-password", + "description": "Sets the user's password. Doing so revokes all current sessions." + }, + "password_hash": { + "type": "string", + "description": "If `password` is not given, sets the user's password hash to the given string in Modular Crypt Format (ex.: `$2a$10$VIhIOofSMqGdGlL4wzE//e.77dAQGqNtF/1dT7bqCrVtQuInWy2qi`). Doing so revokes all current sessions." + }, + "totp_secret_base64": { + "type": "string", + "example": "dG90cC1zZWNyZXQ=", + "description": "Enables 2FA and sets a TOTP secret for the user. Set to null to disable 2FA." + }, + "restricted_by_admin": { + "type": "boolean", + "example": false, + "description": "Whether the user is restricted by an administrator. Can be set manually or by sign-up rules." + }, + "restricted_by_admin_reason": { + "type": "string", + "example": null, + "description": "Public reason shown to the user explaining why they are restricted. Optional." + }, + "restricted_by_admin_private_details": { + "type": "string", + "example": null, + "description": "Private details about the restriction (e.g., which sign-up rule triggered). Only visible to server access and above." + }, + "country_code": { + "type": "string", + "example": "US", + "description": "Best-effort ISO country code captured at sign-up time from request geo headers." + }, + "risk_scores": { + "type": "object", + "properties": { + "sign_up": { + "type": "object", + "properties": { + "bot": { + "type": "number" + }, + "free_trial_abuse": { + "type": "number" + } + }, + "required": [ + "bot", + "free_trial_abuse" + ] + } + }, + "required": [ + "sign_up" + ] + } + }, + "example": { + "display_name": "John Doe", + "profile_image_url": "https://example.com/image.jpg", + "client_metadata": { + "key": "value" + }, + "client_read_only_metadata": { + "key": "value" + }, + "server_metadata": { + "key": "value" + }, + "primary_email": "johndoe@example.com", + "primary_email_verified": true, + "primary_email_auth_enabled": true, + "password": "my-new-password", + "totp_secret_base64": "dG90cC1zZWNyZXQ=", + "restricted_by_admin": false, + "restricted_by_admin_reason": null, + "restricted_by_admin_private_details": null, + "country_code": "US" + } + } + } + } + }, + "tags": [ + "Users" + ], + "x-full-url": "https://api.stack-auth.com/api/v1/users", + "responses": { + "201": { + "description": "Successful response", + "content": { + "application/json": { + "schema": { + "type": "object", + "properties": { + "id": { + "type": "string", + "example": "3241a285-8329-4d69-8f3d-316e08cf140c", + "description": "The unique identifier of the user" + }, + "primary_email": { + "type": "string", + "example": "johndoe@example.com", + "description": "Primary email" + }, + "primary_email_verified": { + "type": "boolean", + "example": true, + "description": "Whether the primary email has been verified to belong to this user" + }, + "primary_email_auth_enabled": { + "type": "boolean", + "example": true, + "description": "Whether the primary email is used for authentication. If this is set to `false`, the user will not be able to sign in with the primary email with password or OTP" + }, + "display_name": { + "type": "string", + "example": "John Doe", + "description": "Human-readable user display name. This is not a unique identifier." + }, + "selected_team": { + "type": "object", + "properties": { + "created_at_millis": { + "type": "number", + "example": 1630000000000, + "description": "The time the team was created (the number of milliseconds since epoch, January 1, 1970, UTC)" + }, + "server_metadata": { + "type": "object", + "example": { + "key": "value" + }, + "description": "Server metadata. Used as a data store, only accessible from the server side. You can store secret information related to the team here." + }, + "id": { + "type": "string", + "example": "ad962777-8244-496a-b6a2-e0c6a449c79e", + "description": "The unique identifier of the team" + }, + "display_name": { + "type": "string", + "example": "My Team", + "description": "Human-readable team display name. This is not a unique identifier." + }, + "profile_image_url": { + "type": "string", + "example": "https://example.com/image.jpg", + "description": "URL of the profile image for team. Can be a Base64 encoded image. Must be smaller than 100KB. Please compress and crop to a square before passing in." + }, + "client_metadata": { + "type": "object", + "example": { + "key": "value" + }, + "description": "Client metadata. Used as a data store, accessible from the client side. Do not store information that should not be exposed to the client." + }, + "client_read_only_metadata": { + "type": "object", + "example": { + "key": "value" + }, + "description": "Client read-only, server-writable metadata. Used as a data store, accessible from the client side. Do not store information that should not be exposed to the client. The client can read this data, but cannot modify it. This is useful for things like subscription status." + } + }, + "required": [ + "created_at_millis", + "id", + "display_name" + ] + }, + "selected_team_id": { + "type": "string", + "example": "team-id", + "description": "ID of the team currently selected by the user" + }, + "profile_image_url": { + "type": "string", + "example": "https://example.com/image.jpg", + "description": "URL of the profile image for user. Can be a Base64 encoded image. Must be smaller than 100KB. Please compress and crop to a square before passing in." + }, + "signed_up_at_millis": { + "type": "number", + "example": 1630000000000, + "description": "The time the user signed up (identify) => `(the number of milliseconds since epoch, January 1, 1970, UTC)`" + }, + "client_metadata": { + "type": "object", + "example": { + "key": "value" + }, + "description": "Client metadata. Used as a data store, accessible from the client side. Do not store information that should not be exposed to the client." + }, + "client_read_only_metadata": { + "type": "object", + "example": { + "key": "value" + }, + "description": "Client read-only, server-writable metadata. Used as a data store, accessible from the client side. Do not store information that should not be exposed to the client. The client can read this data, but cannot modify it. This is useful for things like subscription status." + }, + "server_metadata": { + "type": "object", + "example": { + "key": "value" + }, + "description": "Server metadata. Used as a data store, only accessible from the server side. You can store secret information related to the user here." + }, + "last_active_at_millis": { + "type": "number", + "example": 1630000000000, + "description": "The time the user was last active (identify) => `(the number of milliseconds since epoch, January 1, 1970, UTC)`" + }, + "is_anonymous": { + "type": "boolean" + }, + "is_restricted": { + "type": "boolean", + "example": false, + "description": "Whether the user is in restricted state (has signed up but not completed onboarding requirements)" + }, + "restricted_reason": { + "type": "object", + "properties": { + "type": { + "type": "string" + } + }, + "required": [ + "type" + ], + "example": null, + "description": "The reason why the user is restricted (e.g., type: \"email_not_verified\", \"anonymous\", or \"restricted_by_administrator\"), null if not restricted" + }, + "restricted_by_admin": { + "type": "boolean", + "example": false, + "description": "Whether the user is restricted by an administrator. Can be set manually or by sign-up rules." + }, + "restricted_by_admin_reason": { + "type": "string", + "example": null, + "description": "Public reason shown to the user explaining why they are restricted. Optional." + }, + "restricted_by_admin_private_details": { + "type": "string", + "example": null, + "description": "Private details about the restriction (e.g., which sign-up rule triggered). Only visible to server access and above." + }, + "country_code": { + "type": "string", + "example": "US", + "description": "Best-effort ISO country code captured at sign-up time from request geo headers." + }, + "risk_scores": { + "type": "object", + "properties": { + "sign_up": { + "type": "object", + "properties": { + "bot": { + "type": "number" + }, + "free_trial_abuse": { + "type": "number" + } + }, + "required": [ + "bot", + "free_trial_abuse" + ] + } + }, + "required": [ + "sign_up" + ], + "example": { + "sign_up": { + "bot": 0, + "free_trial_abuse": 0 + } + }, + "description": "User risk scores used for sign-up risk evaluation." + } + }, + "required": [ + "id", + "primary_email_verified", + "primary_email_auth_enabled", + "signed_up_at_millis", + "last_active_at_millis", + "is_anonymous", + "is_restricted", + "restricted_by_admin", + "risk_scores" + ] + } + } + } + } + } + } + }, + "/users/me": { + "get": { + "summary": "Get current user", + "description": "Gets the currently authenticated user.", + "parameters": [], + "tags": [ + "Users" + ], + "x-full-url": "https://api.stack-auth.com/api/v1/users/me", + "responses": { + "200": { + "description": "Successful response", + "content": { + "application/json": { + "schema": { + "type": "object", + "properties": { + "id": { + "type": "string", + "example": "3241a285-8329-4d69-8f3d-316e08cf140c", + "description": "The unique identifier of the user" + }, + "primary_email": { + "type": "string", + "example": "johndoe@example.com", + "description": "Primary email" + }, + "primary_email_verified": { + "type": "boolean", + "example": true, + "description": "Whether the primary email has been verified to belong to this user" + }, + "primary_email_auth_enabled": { + "type": "boolean", + "example": true, + "description": "Whether the primary email is used for authentication. If this is set to `false`, the user will not be able to sign in with the primary email with password or OTP" + }, + "display_name": { + "type": "string", + "example": "John Doe", + "description": "Human-readable user display name. This is not a unique identifier." + }, + "selected_team": { + "type": "object", + "properties": { + "created_at_millis": { + "type": "number", + "example": 1630000000000, + "description": "The time the team was created (the number of milliseconds since epoch, January 1, 1970, UTC)" + }, + "server_metadata": { + "type": "object", + "example": { + "key": "value" + }, + "description": "Server metadata. Used as a data store, only accessible from the server side. You can store secret information related to the team here." + }, + "id": { + "type": "string", + "example": "ad962777-8244-496a-b6a2-e0c6a449c79e", + "description": "The unique identifier of the team" + }, + "display_name": { + "type": "string", + "example": "My Team", + "description": "Human-readable team display name. This is not a unique identifier." + }, + "profile_image_url": { + "type": "string", + "example": "https://example.com/image.jpg", + "description": "URL of the profile image for team. Can be a Base64 encoded image. Must be smaller than 100KB. Please compress and crop to a square before passing in." + }, + "client_metadata": { + "type": "object", + "example": { + "key": "value" + }, + "description": "Client metadata. Used as a data store, accessible from the client side. Do not store information that should not be exposed to the client." + }, + "client_read_only_metadata": { + "type": "object", + "example": { + "key": "value" + }, + "description": "Client read-only, server-writable metadata. Used as a data store, accessible from the client side. Do not store information that should not be exposed to the client. The client can read this data, but cannot modify it. This is useful for things like subscription status." + } + }, + "required": [ + "created_at_millis", + "id", + "display_name" + ] + }, + "selected_team_id": { + "type": "string", + "example": "team-id", + "description": "ID of the team currently selected by the user" + }, + "profile_image_url": { + "type": "string", + "example": "https://example.com/image.jpg", + "description": "URL of the profile image for user. Can be a Base64 encoded image. Must be smaller than 100KB. Please compress and crop to a square before passing in." + }, + "signed_up_at_millis": { + "type": "number", + "example": 1630000000000, + "description": "The time the user signed up (identify) => `(the number of milliseconds since epoch, January 1, 1970, UTC)`" + }, + "client_metadata": { + "type": "object", + "example": { + "key": "value" + }, + "description": "Client metadata. Used as a data store, accessible from the client side. Do not store information that should not be exposed to the client." + }, + "client_read_only_metadata": { + "type": "object", + "example": { + "key": "value" + }, + "description": "Client read-only, server-writable metadata. Used as a data store, accessible from the client side. Do not store information that should not be exposed to the client. The client can read this data, but cannot modify it. This is useful for things like subscription status." + }, + "server_metadata": { + "type": "object", + "example": { + "key": "value" + }, + "description": "Server metadata. Used as a data store, only accessible from the server side. You can store secret information related to the user here." + }, + "last_active_at_millis": { + "type": "number", + "example": 1630000000000, + "description": "The time the user was last active (identify) => `(the number of milliseconds since epoch, January 1, 1970, UTC)`" + }, + "is_anonymous": { + "type": "boolean" + }, + "is_restricted": { + "type": "boolean", + "example": false, + "description": "Whether the user is in restricted state (has signed up but not completed onboarding requirements)" + }, + "restricted_reason": { + "type": "object", + "properties": { + "type": { + "type": "string" + } + }, + "required": [ + "type" + ], + "example": null, + "description": "The reason why the user is restricted (e.g., type: \"email_not_verified\", \"anonymous\", or \"restricted_by_administrator\"), null if not restricted" + }, + "restricted_by_admin": { + "type": "boolean", + "example": false, + "description": "Whether the user is restricted by an administrator. Can be set manually or by sign-up rules." + }, + "restricted_by_admin_reason": { + "type": "string", + "example": null, + "description": "Public reason shown to the user explaining why they are restricted. Optional." + }, + "restricted_by_admin_private_details": { + "type": "string", + "example": null, + "description": "Private details about the restriction (e.g., which sign-up rule triggered). Only visible to server access and above." + }, + "country_code": { + "type": "string", + "example": "US", + "description": "Best-effort ISO country code captured at sign-up time from request geo headers." + }, + "risk_scores": { + "type": "object", + "properties": { + "sign_up": { + "type": "object", + "properties": { + "bot": { + "type": "number" + }, + "free_trial_abuse": { + "type": "number" + } + }, + "required": [ + "bot", + "free_trial_abuse" + ] + } + }, + "required": [ + "sign_up" + ], + "example": { + "sign_up": { + "bot": 0, + "free_trial_abuse": 0 + } + }, + "description": "User risk scores used for sign-up risk evaluation." + } + }, + "required": [ + "id", + "primary_email_verified", + "primary_email_auth_enabled", + "signed_up_at_millis", + "last_active_at_millis", + "is_anonymous", + "is_restricted", + "restricted_by_admin", + "risk_scores" + ] + } + } + } + } + } + }, + "delete": { + "summary": "Delete current user", + "description": "Deletes the currently authenticated user. Use this with caution.", + "parameters": [], + "tags": [ + "Users" + ], + "x-full-url": "https://api.stack-auth.com/api/v1/users/me", + "responses": { + "200": { + "description": "Successful response", + "content": { + "application/json": { + "schema": { + "type": "object", + "properties": { + "success": { + "type": "boolean", + "description": "Always equal to true.", + "example": true + } + }, + "required": [ + "success" + ] + } + } + } + } + } + }, + "patch": { + "summary": "Update current user", + "description": "Updates the currently authenticated user. Only the values provided will be updated.", + "parameters": [], + "requestBody": { + "required": true, + "content": { + "application/json": { + "schema": { + "type": "object", + "properties": { + "display_name": { + "type": "string", + "example": "John Doe", + "description": "Human-readable user display name. This is not a unique identifier." + }, + "profile_image_url": { + "type": "string", + "example": "https://example.com/image.jpg", + "description": "URL of the profile image for user. Can be a Base64 encoded image. Must be smaller than 100KB. Please compress and crop to a square before passing in." + }, + "client_metadata": { + "type": "object", + "example": { + "key": "value" + }, + "description": "Client metadata. Used as a data store, accessible from the client side. Do not store information that should not be exposed to the client." + }, + "client_read_only_metadata": { + "type": "object", + "example": { + "key": "value" + }, + "description": "Client read-only, server-writable metadata. Used as a data store, accessible from the client side. Do not store information that should not be exposed to the client. The client can read this data, but cannot modify it. This is useful for things like subscription status." + }, + "server_metadata": { + "type": "object", + "example": { + "key": "value" + }, + "description": "Server metadata. Used as a data store, only accessible from the server side. You can store secret information related to the user here." + }, + "primary_email": { + "type": "string", + "example": "johndoe@example.com", + "description": "Primary email" + }, + "primary_email_verified": { + "type": "boolean", + "example": true, + "description": "Whether the primary email has been verified to belong to this user" + }, + "primary_email_auth_enabled": { + "type": "boolean", + "example": true, + "description": "Whether the primary email is used for authentication. If this is set to `false`, the user will not be able to sign in with the primary email with password or OTP" + }, + "password": { + "type": "string", + "example": "my-new-password", + "description": "Sets the user's password. Doing so revokes all current sessions." + }, + "password_hash": { + "type": "string", + "description": "If `password` is not given, sets the user's password hash to the given string in Modular Crypt Format (ex.: `$2a$10$VIhIOofSMqGdGlL4wzE//e.77dAQGqNtF/1dT7bqCrVtQuInWy2qi`). Doing so revokes all current sessions." + }, + "totp_secret_base64": { + "type": "string", + "example": "dG90cC1zZWNyZXQ=", + "description": "Enables 2FA and sets a TOTP secret for the user. Set to null to disable 2FA." + }, + "selected_team_id": { + "type": "string", + "example": "team-id", + "description": "ID of the team currently selected by the user" + }, + "is_anonymous": { + "type": "boolean" + }, + "restricted_by_admin": { + "type": "boolean", + "example": false, + "description": "Whether the user is restricted by an administrator. Can be set manually or by sign-up rules." + }, + "restricted_by_admin_reason": { + "type": "string", + "example": null, + "description": "Public reason shown to the user explaining why they are restricted. Optional." + }, + "restricted_by_admin_private_details": { + "type": "string", + "example": null, + "description": "Private details about the restriction (e.g., which sign-up rule triggered). Only visible to server access and above." + }, + "country_code": { + "type": "string", + "example": "US", + "description": "Best-effort ISO country code captured at sign-up time from request geo headers." + }, + "risk_scores": { + "type": "object", + "properties": { + "sign_up": { + "type": "object", + "properties": { + "bot": { + "type": "number" + }, + "free_trial_abuse": { + "type": "number" + } + }, + "required": [ + "bot", + "free_trial_abuse" + ] + } + }, + "required": [ + "sign_up" + ] + } + }, + "example": { + "display_name": "John Doe", + "profile_image_url": "https://example.com/image.jpg", + "client_metadata": { + "key": "value" + }, + "client_read_only_metadata": { + "key": "value" + }, + "server_metadata": { + "key": "value" + }, + "primary_email": "johndoe@example.com", + "primary_email_verified": true, + "primary_email_auth_enabled": true, + "password": "my-new-password", + "totp_secret_base64": "dG90cC1zZWNyZXQ=", + "selected_team_id": "team-id", + "restricted_by_admin": false, + "restricted_by_admin_reason": null, + "restricted_by_admin_private_details": null, + "country_code": "US" + } + } + } + } + }, + "tags": [ + "Users" + ], + "x-full-url": "https://api.stack-auth.com/api/v1/users/me", + "responses": { + "200": { + "description": "Successful response", + "content": { + "application/json": { + "schema": { + "type": "object", + "properties": { + "id": { + "type": "string", + "example": "3241a285-8329-4d69-8f3d-316e08cf140c", + "description": "The unique identifier of the user" + }, + "primary_email": { + "type": "string", + "example": "johndoe@example.com", + "description": "Primary email" + }, + "primary_email_verified": { + "type": "boolean", + "example": true, + "description": "Whether the primary email has been verified to belong to this user" + }, + "primary_email_auth_enabled": { + "type": "boolean", + "example": true, + "description": "Whether the primary email is used for authentication. If this is set to `false`, the user will not be able to sign in with the primary email with password or OTP" + }, + "display_name": { + "type": "string", + "example": "John Doe", + "description": "Human-readable user display name. This is not a unique identifier." + }, + "selected_team": { + "type": "object", + "properties": { + "created_at_millis": { + "type": "number", + "example": 1630000000000, + "description": "The time the team was created (the number of milliseconds since epoch, January 1, 1970, UTC)" + }, + "server_metadata": { + "type": "object", + "example": { + "key": "value" + }, + "description": "Server metadata. Used as a data store, only accessible from the server side. You can store secret information related to the team here." + }, + "id": { + "type": "string", + "example": "ad962777-8244-496a-b6a2-e0c6a449c79e", + "description": "The unique identifier of the team" + }, + "display_name": { + "type": "string", + "example": "My Team", + "description": "Human-readable team display name. This is not a unique identifier." + }, + "profile_image_url": { + "type": "string", + "example": "https://example.com/image.jpg", + "description": "URL of the profile image for team. Can be a Base64 encoded image. Must be smaller than 100KB. Please compress and crop to a square before passing in." + }, + "client_metadata": { + "type": "object", + "example": { + "key": "value" + }, + "description": "Client metadata. Used as a data store, accessible from the client side. Do not store information that should not be exposed to the client." + }, + "client_read_only_metadata": { + "type": "object", + "example": { + "key": "value" + }, + "description": "Client read-only, server-writable metadata. Used as a data store, accessible from the client side. Do not store information that should not be exposed to the client. The client can read this data, but cannot modify it. This is useful for things like subscription status." + } + }, + "required": [ + "created_at_millis", + "id", + "display_name" + ] + }, + "selected_team_id": { + "type": "string", + "example": "team-id", + "description": "ID of the team currently selected by the user" + }, + "profile_image_url": { + "type": "string", + "example": "https://example.com/image.jpg", + "description": "URL of the profile image for user. Can be a Base64 encoded image. Must be smaller than 100KB. Please compress and crop to a square before passing in." + }, + "signed_up_at_millis": { + "type": "number", + "example": 1630000000000, + "description": "The time the user signed up (identify) => `(the number of milliseconds since epoch, January 1, 1970, UTC)`" + }, + "client_metadata": { + "type": "object", + "example": { + "key": "value" + }, + "description": "Client metadata. Used as a data store, accessible from the client side. Do not store information that should not be exposed to the client." + }, + "client_read_only_metadata": { + "type": "object", + "example": { + "key": "value" + }, + "description": "Client read-only, server-writable metadata. Used as a data store, accessible from the client side. Do not store information that should not be exposed to the client. The client can read this data, but cannot modify it. This is useful for things like subscription status." + }, + "server_metadata": { + "type": "object", + "example": { + "key": "value" + }, + "description": "Server metadata. Used as a data store, only accessible from the server side. You can store secret information related to the user here." + }, + "last_active_at_millis": { + "type": "number", + "example": 1630000000000, + "description": "The time the user was last active (identify) => `(the number of milliseconds since epoch, January 1, 1970, UTC)`" + }, + "is_anonymous": { + "type": "boolean" + }, + "is_restricted": { + "type": "boolean", + "example": false, + "description": "Whether the user is in restricted state (has signed up but not completed onboarding requirements)" + }, + "restricted_reason": { + "type": "object", + "properties": { + "type": { + "type": "string" + } + }, + "required": [ + "type" + ], + "example": null, + "description": "The reason why the user is restricted (e.g., type: \"email_not_verified\", \"anonymous\", or \"restricted_by_administrator\"), null if not restricted" + }, + "restricted_by_admin": { + "type": "boolean", + "example": false, + "description": "Whether the user is restricted by an administrator. Can be set manually or by sign-up rules." + }, + "restricted_by_admin_reason": { + "type": "string", + "example": null, + "description": "Public reason shown to the user explaining why they are restricted. Optional." + }, + "restricted_by_admin_private_details": { + "type": "string", + "example": null, + "description": "Private details about the restriction (e.g., which sign-up rule triggered). Only visible to server access and above." + }, + "country_code": { + "type": "string", + "example": "US", + "description": "Best-effort ISO country code captured at sign-up time from request geo headers." + }, + "risk_scores": { + "type": "object", + "properties": { + "sign_up": { + "type": "object", + "properties": { + "bot": { + "type": "number" + }, + "free_trial_abuse": { + "type": "number" + } + }, + "required": [ + "bot", + "free_trial_abuse" + ] + } + }, + "required": [ + "sign_up" + ], + "example": { + "sign_up": { + "bot": 0, + "free_trial_abuse": 0 + } + }, + "description": "User risk scores used for sign-up risk evaluation." + } + }, + "required": [ + "id", + "primary_email_verified", + "primary_email_auth_enabled", + "signed_up_at_millis", + "last_active_at_millis", + "is_anonymous", + "is_restricted", + "restricted_by_admin", + "risk_scores" + ] + } + } + } + } + } + } + }, + "/users/{user_id}": { + "get": { + "summary": "Get user", + "description": "Gets a user by user ID.", + "parameters": [ + { + "name": "user_id", + "in": "path", + "schema": { + "type": "string", + "example": "3241a285-8329-4d69-8f3d-316e08cf140c", + "description": "The ID of the user, or the special value `me` for the currently authenticated user" + }, + "description": "The ID of the user, or the special value `me` for the currently authenticated user", + "required": true + } + ], + "tags": [ + "Users" + ], + "x-full-url": "https://api.stack-auth.com/api/v1/users/{user_id}", + "responses": { + "200": { + "description": "Successful response", + "content": { + "application/json": { + "schema": { + "type": "object", + "properties": { + "id": { + "type": "string", + "example": "3241a285-8329-4d69-8f3d-316e08cf140c", + "description": "The unique identifier of the user" + }, + "primary_email": { + "type": "string", + "example": "johndoe@example.com", + "description": "Primary email" + }, + "primary_email_verified": { + "type": "boolean", + "example": true, + "description": "Whether the primary email has been verified to belong to this user" + }, + "primary_email_auth_enabled": { + "type": "boolean", + "example": true, + "description": "Whether the primary email is used for authentication. If this is set to `false`, the user will not be able to sign in with the primary email with password or OTP" + }, + "display_name": { + "type": "string", + "example": "John Doe", + "description": "Human-readable user display name. This is not a unique identifier." + }, + "selected_team": { + "type": "object", + "properties": { + "created_at_millis": { + "type": "number", + "example": 1630000000000, + "description": "The time the team was created (the number of milliseconds since epoch, January 1, 1970, UTC)" + }, + "server_metadata": { + "type": "object", + "example": { + "key": "value" + }, + "description": "Server metadata. Used as a data store, only accessible from the server side. You can store secret information related to the team here." + }, + "id": { + "type": "string", + "example": "ad962777-8244-496a-b6a2-e0c6a449c79e", + "description": "The unique identifier of the team" + }, + "display_name": { + "type": "string", + "example": "My Team", + "description": "Human-readable team display name. This is not a unique identifier." + }, + "profile_image_url": { + "type": "string", + "example": "https://example.com/image.jpg", + "description": "URL of the profile image for team. Can be a Base64 encoded image. Must be smaller than 100KB. Please compress and crop to a square before passing in." + }, + "client_metadata": { + "type": "object", + "example": { + "key": "value" + }, + "description": "Client metadata. Used as a data store, accessible from the client side. Do not store information that should not be exposed to the client." + }, + "client_read_only_metadata": { + "type": "object", + "example": { + "key": "value" + }, + "description": "Client read-only, server-writable metadata. Used as a data store, accessible from the client side. Do not store information that should not be exposed to the client. The client can read this data, but cannot modify it. This is useful for things like subscription status." + } + }, + "required": [ + "created_at_millis", + "id", + "display_name" + ] + }, + "selected_team_id": { + "type": "string", + "example": "team-id", + "description": "ID of the team currently selected by the user" + }, + "profile_image_url": { + "type": "string", + "example": "https://example.com/image.jpg", + "description": "URL of the profile image for user. Can be a Base64 encoded image. Must be smaller than 100KB. Please compress and crop to a square before passing in." + }, + "signed_up_at_millis": { + "type": "number", + "example": 1630000000000, + "description": "The time the user signed up (identify) => `(the number of milliseconds since epoch, January 1, 1970, UTC)`" + }, + "client_metadata": { + "type": "object", + "example": { + "key": "value" + }, + "description": "Client metadata. Used as a data store, accessible from the client side. Do not store information that should not be exposed to the client." + }, + "client_read_only_metadata": { + "type": "object", + "example": { + "key": "value" + }, + "description": "Client read-only, server-writable metadata. Used as a data store, accessible from the client side. Do not store information that should not be exposed to the client. The client can read this data, but cannot modify it. This is useful for things like subscription status." + }, + "server_metadata": { + "type": "object", + "example": { + "key": "value" + }, + "description": "Server metadata. Used as a data store, only accessible from the server side. You can store secret information related to the user here." + }, + "last_active_at_millis": { + "type": "number", + "example": 1630000000000, + "description": "The time the user was last active (identify) => `(the number of milliseconds since epoch, January 1, 1970, UTC)`" + }, + "is_anonymous": { + "type": "boolean" + }, + "is_restricted": { + "type": "boolean", + "example": false, + "description": "Whether the user is in restricted state (has signed up but not completed onboarding requirements)" + }, + "restricted_reason": { + "type": "object", + "properties": { + "type": { + "type": "string" + } + }, + "required": [ + "type" + ], + "example": null, + "description": "The reason why the user is restricted (e.g., type: \"email_not_verified\", \"anonymous\", or \"restricted_by_administrator\"), null if not restricted" + }, + "restricted_by_admin": { + "type": "boolean", + "example": false, + "description": "Whether the user is restricted by an administrator. Can be set manually or by sign-up rules." + }, + "restricted_by_admin_reason": { + "type": "string", + "example": null, + "description": "Public reason shown to the user explaining why they are restricted. Optional." + }, + "restricted_by_admin_private_details": { + "type": "string", + "example": null, + "description": "Private details about the restriction (e.g., which sign-up rule triggered). Only visible to server access and above." + }, + "country_code": { + "type": "string", + "example": "US", + "description": "Best-effort ISO country code captured at sign-up time from request geo headers." + }, + "risk_scores": { + "type": "object", + "properties": { + "sign_up": { + "type": "object", + "properties": { + "bot": { + "type": "number" + }, + "free_trial_abuse": { + "type": "number" + } + }, + "required": [ + "bot", + "free_trial_abuse" + ] + } + }, + "required": [ + "sign_up" + ], + "example": { + "sign_up": { + "bot": 0, + "free_trial_abuse": 0 + } + }, + "description": "User risk scores used for sign-up risk evaluation." + } + }, + "required": [ + "id", + "primary_email_verified", + "primary_email_auth_enabled", + "signed_up_at_millis", + "last_active_at_millis", + "is_anonymous", + "is_restricted", + "restricted_by_admin", + "risk_scores" + ] + } + } + } + } + } + }, + "delete": { + "summary": "Delete user", + "description": "Deletes a user. Use this with caution.", + "parameters": [ + { + "name": "user_id", + "in": "path", + "schema": { + "type": "string", + "example": "3241a285-8329-4d69-8f3d-316e08cf140c", + "description": "The ID of the user, or the special value `me` for the currently authenticated user" + }, + "description": "The ID of the user, or the special value `me` for the currently authenticated user", + "required": true + } + ], + "tags": [ + "Users" + ], + "x-full-url": "https://api.stack-auth.com/api/v1/users/{user_id}", + "responses": { + "200": { + "description": "Successful response", + "content": { + "application/json": { + "schema": { + "type": "object", + "properties": { + "success": { + "type": "boolean", + "description": "Always equal to true.", + "example": true + } + }, + "required": [ + "success" + ] + } + } + } + } + } + }, + "patch": { + "summary": "Update user", + "description": "Updates a user. Only the values provided will be updated.", + "parameters": [ + { + "name": "user_id", + "in": "path", + "schema": { + "type": "string", + "example": "3241a285-8329-4d69-8f3d-316e08cf140c", + "description": "The ID of the user, or the special value `me` for the currently authenticated user" + }, + "description": "The ID of the user, or the special value `me` for the currently authenticated user", + "required": true + } + ], + "requestBody": { + "required": true, + "content": { + "application/json": { + "schema": { + "type": "object", + "properties": { + "display_name": { + "type": "string", + "example": "John Doe", + "description": "Human-readable user display name. This is not a unique identifier." + }, + "profile_image_url": { + "type": "string", + "example": "https://example.com/image.jpg", + "description": "URL of the profile image for user. Can be a Base64 encoded image. Must be smaller than 100KB. Please compress and crop to a square before passing in." + }, + "client_metadata": { + "type": "object", + "example": { + "key": "value" + }, + "description": "Client metadata. Used as a data store, accessible from the client side. Do not store information that should not be exposed to the client." + }, + "client_read_only_metadata": { + "type": "object", + "example": { + "key": "value" + }, + "description": "Client read-only, server-writable metadata. Used as a data store, accessible from the client side. Do not store information that should not be exposed to the client. The client can read this data, but cannot modify it. This is useful for things like subscription status." + }, + "server_metadata": { + "type": "object", + "example": { + "key": "value" + }, + "description": "Server metadata. Used as a data store, only accessible from the server side. You can store secret information related to the user here." + }, + "primary_email": { + "type": "string", + "example": "johndoe@example.com", + "description": "Primary email" + }, + "primary_email_verified": { + "type": "boolean", + "example": true, + "description": "Whether the primary email has been verified to belong to this user" + }, + "primary_email_auth_enabled": { + "type": "boolean", + "example": true, + "description": "Whether the primary email is used for authentication. If this is set to `false`, the user will not be able to sign in with the primary email with password or OTP" + }, + "password": { + "type": "string", + "example": "my-new-password", + "description": "Sets the user's password. Doing so revokes all current sessions." + }, + "password_hash": { + "type": "string", + "description": "If `password` is not given, sets the user's password hash to the given string in Modular Crypt Format (ex.: `$2a$10$VIhIOofSMqGdGlL4wzE//e.77dAQGqNtF/1dT7bqCrVtQuInWy2qi`). Doing so revokes all current sessions." + }, + "totp_secret_base64": { + "type": "string", + "example": "dG90cC1zZWNyZXQ=", + "description": "Enables 2FA and sets a TOTP secret for the user. Set to null to disable 2FA." + }, + "selected_team_id": { + "type": "string", + "example": "team-id", + "description": "ID of the team currently selected by the user" + }, + "is_anonymous": { + "type": "boolean" + }, + "restricted_by_admin": { + "type": "boolean", + "example": false, + "description": "Whether the user is restricted by an administrator. Can be set manually or by sign-up rules." + }, + "restricted_by_admin_reason": { + "type": "string", + "example": null, + "description": "Public reason shown to the user explaining why they are restricted. Optional." + }, + "restricted_by_admin_private_details": { + "type": "string", + "example": null, + "description": "Private details about the restriction (e.g., which sign-up rule triggered). Only visible to server access and above." + }, + "country_code": { + "type": "string", + "example": "US", + "description": "Best-effort ISO country code captured at sign-up time from request geo headers." + }, + "risk_scores": { + "type": "object", + "properties": { + "sign_up": { + "type": "object", + "properties": { + "bot": { + "type": "number" + }, + "free_trial_abuse": { + "type": "number" + } + }, + "required": [ + "bot", + "free_trial_abuse" + ] + } + }, + "required": [ + "sign_up" + ] + } + }, + "example": { + "display_name": "John Doe", + "profile_image_url": "https://example.com/image.jpg", + "client_metadata": { + "key": "value" + }, + "client_read_only_metadata": { + "key": "value" + }, + "server_metadata": { + "key": "value" + }, + "primary_email": "johndoe@example.com", + "primary_email_verified": true, + "primary_email_auth_enabled": true, + "password": "my-new-password", + "totp_secret_base64": "dG90cC1zZWNyZXQ=", + "selected_team_id": "team-id", + "restricted_by_admin": false, + "restricted_by_admin_reason": null, + "restricted_by_admin_private_details": null, + "country_code": "US" + } + } + } + } + }, + "tags": [ + "Users" + ], + "x-full-url": "https://api.stack-auth.com/api/v1/users/{user_id}", + "responses": { + "200": { + "description": "Successful response", + "content": { + "application/json": { + "schema": { + "type": "object", + "properties": { + "id": { + "type": "string", + "example": "3241a285-8329-4d69-8f3d-316e08cf140c", + "description": "The unique identifier of the user" + }, + "primary_email": { + "type": "string", + "example": "johndoe@example.com", + "description": "Primary email" + }, + "primary_email_verified": { + "type": "boolean", + "example": true, + "description": "Whether the primary email has been verified to belong to this user" + }, + "primary_email_auth_enabled": { + "type": "boolean", + "example": true, + "description": "Whether the primary email is used for authentication. If this is set to `false`, the user will not be able to sign in with the primary email with password or OTP" + }, + "display_name": { + "type": "string", + "example": "John Doe", + "description": "Human-readable user display name. This is not a unique identifier." + }, + "selected_team": { + "type": "object", + "properties": { + "created_at_millis": { + "type": "number", + "example": 1630000000000, + "description": "The time the team was created (the number of milliseconds since epoch, January 1, 1970, UTC)" + }, + "server_metadata": { + "type": "object", + "example": { + "key": "value" + }, + "description": "Server metadata. Used as a data store, only accessible from the server side. You can store secret information related to the team here." + }, + "id": { + "type": "string", + "example": "ad962777-8244-496a-b6a2-e0c6a449c79e", + "description": "The unique identifier of the team" + }, + "display_name": { + "type": "string", + "example": "My Team", + "description": "Human-readable team display name. This is not a unique identifier." + }, + "profile_image_url": { + "type": "string", + "example": "https://example.com/image.jpg", + "description": "URL of the profile image for team. Can be a Base64 encoded image. Must be smaller than 100KB. Please compress and crop to a square before passing in." + }, + "client_metadata": { + "type": "object", + "example": { + "key": "value" + }, + "description": "Client metadata. Used as a data store, accessible from the client side. Do not store information that should not be exposed to the client." + }, + "client_read_only_metadata": { + "type": "object", + "example": { + "key": "value" + }, + "description": "Client read-only, server-writable metadata. Used as a data store, accessible from the client side. Do not store information that should not be exposed to the client. The client can read this data, but cannot modify it. This is useful for things like subscription status." + } + }, + "required": [ + "created_at_millis", + "id", + "display_name" + ] + }, + "selected_team_id": { + "type": "string", + "example": "team-id", + "description": "ID of the team currently selected by the user" + }, + "profile_image_url": { + "type": "string", + "example": "https://example.com/image.jpg", + "description": "URL of the profile image for user. Can be a Base64 encoded image. Must be smaller than 100KB. Please compress and crop to a square before passing in." + }, + "signed_up_at_millis": { + "type": "number", + "example": 1630000000000, + "description": "The time the user signed up (identify) => `(the number of milliseconds since epoch, January 1, 1970, UTC)`" + }, + "client_metadata": { + "type": "object", + "example": { + "key": "value" + }, + "description": "Client metadata. Used as a data store, accessible from the client side. Do not store information that should not be exposed to the client." + }, + "client_read_only_metadata": { + "type": "object", + "example": { + "key": "value" + }, + "description": "Client read-only, server-writable metadata. Used as a data store, accessible from the client side. Do not store information that should not be exposed to the client. The client can read this data, but cannot modify it. This is useful for things like subscription status." + }, + "server_metadata": { + "type": "object", + "example": { + "key": "value" + }, + "description": "Server metadata. Used as a data store, only accessible from the server side. You can store secret information related to the user here." + }, + "last_active_at_millis": { + "type": "number", + "example": 1630000000000, + "description": "The time the user was last active (identify) => `(the number of milliseconds since epoch, January 1, 1970, UTC)`" + }, + "is_anonymous": { + "type": "boolean" + }, + "is_restricted": { + "type": "boolean", + "example": false, + "description": "Whether the user is in restricted state (has signed up but not completed onboarding requirements)" + }, + "restricted_reason": { + "type": "object", + "properties": { + "type": { + "type": "string" + } + }, + "required": [ + "type" + ], + "example": null, + "description": "The reason why the user is restricted (e.g., type: \"email_not_verified\", \"anonymous\", or \"restricted_by_administrator\"), null if not restricted" + }, + "restricted_by_admin": { + "type": "boolean", + "example": false, + "description": "Whether the user is restricted by an administrator. Can be set manually or by sign-up rules." + }, + "restricted_by_admin_reason": { + "type": "string", + "example": null, + "description": "Public reason shown to the user explaining why they are restricted. Optional." + }, + "restricted_by_admin_private_details": { + "type": "string", + "example": null, + "description": "Private details about the restriction (e.g., which sign-up rule triggered). Only visible to server access and above." + }, + "country_code": { + "type": "string", + "example": "US", + "description": "Best-effort ISO country code captured at sign-up time from request geo headers." + }, + "risk_scores": { + "type": "object", + "properties": { + "sign_up": { + "type": "object", + "properties": { + "bot": { + "type": "number" + }, + "free_trial_abuse": { + "type": "number" + } + }, + "required": [ + "bot", + "free_trial_abuse" + ] + } + }, + "required": [ + "sign_up" + ], + "example": { + "sign_up": { + "bot": 0, + "free_trial_abuse": 0 + } + }, + "description": "User risk scores used for sign-up risk evaluation." + } + }, + "required": [ + "id", + "primary_email_verified", + "primary_email_auth_enabled", + "signed_up_at_millis", + "last_active_at_millis", + "is_anonymous", + "is_restricted", + "restricted_by_admin", + "risk_scores" + ] + } + } + } + } + } + } + } + } +} \ No newline at end of file diff --git a/docs-mintlify/openapi/client.json b/docs-mintlify/openapi/client.json new file mode 100644 index 0000000000..99ed937a5d --- /dev/null +++ b/docs-mintlify/openapi/client.json @@ -0,0 +1,6566 @@ +{ + "openapi": "3.1.0", + "info": { + "title": "Stack REST API", + "version": "1.0.0" + }, + "servers": [ + { + "url": "https://api.stack-auth.com/api/v1", + "description": "Stack REST API" + } + ], + "paths": { + "/": { + "get": { + "summary": "/api/v1", + "description": "Returns a human-readable message with some useful information about the API.", + "parameters": [ + { + "name": "X-Stack-Project-Id", + "in": "header", + "schema": { + "type": "string", + "example": "e0b52f4d-dece-408c-af49-d23061bb0f8d", + "description": "The unique identifier of the project" + }, + "description": "The unique identifier of the project", + "example": "e0b52f4d-dece-408c-af49-d23061bb0f8d", + "required": false + }, + { + "name": "X-Stack-Branch-Id", + "in": "header", + "schema": { + "type": "string", + "example": "e0b52f4d-dece-408c-af49-d23061bb0f8d", + "description": "The unique identifier of the project" + }, + "description": "The unique identifier of the project", + "example": "e0b52f4d-dece-408c-af49-d23061bb0f8d", + "required": false + }, + { + "name": "X-Stack-Access-Type", + "in": "header", + "schema": { + "type": "string" + }, + "required": false + }, + { + "name": "X-Stack-Access-Token", + "in": "header", + "schema": { + "type": "string" + }, + "required": false + }, + { + "name": "X-Stack-Refresh-Token", + "in": "header", + "schema": { + "type": "string" + }, + "required": false + }, + { + "name": "X-Stack-Publishable-Client-Key", + "in": "header", + "schema": { + "type": "string" + }, + "required": false + }, + { + "name": "X-Stack-Secret-Server-Key", + "in": "header", + "schema": { + "type": "string" + }, + "required": false + }, + { + "name": "X-Stack-Super-Secret-Admin-Key", + "in": "header", + "schema": { + "type": "string" + }, + "required": false + } + ], + "tags": [], + "x-full-url": "https://api.stack-auth.com/api/v1/", + "responses": { + "200": { + "description": "Successful response", + "content": { + "text/plain": { + "schema": { + "type": "string", + "example": "Welcome to the Stack API endpoint! Please refer to the documentation at https://docs.stack-auth.com/\n\nAuthentication: None" + } + } + } + } + } + } + }, + "/auth/anonymous/sign-up": { + "post": { + "summary": "Sign up anonymously", + "description": "Create a new anonymous account with no email", + "parameters": [], + "tags": [ + "Anonymous" + ], + "x-full-url": "https://api.stack-auth.com/api/v1/auth/anonymous/sign-up", + "responses": { + "200": { + "description": "Successful response", + "content": { + "application/json": { + "schema": { + "type": "object", + "properties": { + "access_token": { + "type": "string" + }, + "refresh_token": { + "type": "string" + }, + "user_id": { + "type": "string" + } + }, + "required": [ + "access_token", + "refresh_token", + "user_id" + ] + } + } + } + } + } + } + }, + "/team-api-keys": { + "get": { + "summary": "List team API keys", + "description": "List all team API keys for the project with their metadata and status", + "parameters": [ + { + "name": "team_id", + "in": "query", + "schema": { + "type": "string" + }, + "required": true + } + ], + "tags": [ + "API Keys" + ], + "x-full-url": "https://api.stack-auth.com/api/v1/team-api-keys", + "responses": { + "200": { + "description": "Successful response", + "content": { + "application/json": { + "schema": { + "type": "object", + "properties": { + "items": { + "type": "array", + "items": { + "type": "object", + "properties": { + "id": { + "type": "string" + }, + "description": { + "type": "string" + }, + "expires_at_millis": { + "type": "number" + }, + "manually_revoked_at_millis": { + "type": "number" + }, + "created_at_millis": { + "type": "number" + }, + "is_public": { + "type": "boolean" + }, + "value": { + "type": "object", + "properties": { + "last_four": { + "type": "string" + } + }, + "required": [ + "last_four" + ] + }, + "type": { + "type": "string" + }, + "team_id": { + "type": "string" + } + }, + "required": [ + "id", + "description", + "created_at_millis", + "is_public", + "value", + "type", + "team_id" + ] + } + }, + "pagination": { + "type": "object", + "properties": { + "next_cursor": { + "type": "string", + "example": "b3d396b8-c574-4c80-97b3-50031675ceb2", + "description": "The cursor to fetch the next page of results. null if there is no next page." + } + }, + "required": [] + } + }, + "required": [ + "items" + ] + } + } + } + } + } + }, + "post": { + "summary": "Create team API key", + "description": "Create a new API key for a user or team", + "parameters": [], + "requestBody": { + "required": true, + "content": { + "application/json": { + "schema": { + "type": "object", + "properties": { + "description": { + "type": "string" + }, + "expires_at_millis": { + "type": "number" + }, + "is_public": { + "type": "boolean" + }, + "team_id": { + "type": "string" + } + }, + "required": [ + "description", + "team_id" + ], + "example": {} + } + } + } + }, + "tags": [ + "API Keys" + ], + "x-full-url": "https://api.stack-auth.com/api/v1/team-api-keys", + "responses": { + "200": { + "description": "Successful response", + "content": { + "application/json": { + "schema": { + "type": "object", + "properties": { + "value": { + "type": "string" + }, + "id": { + "type": "string" + }, + "description": { + "type": "string" + }, + "expires_at_millis": { + "type": "number" + }, + "manually_revoked_at_millis": { + "type": "number" + }, + "created_at_millis": { + "type": "number" + }, + "is_public": { + "type": "boolean" + }, + "type": { + "type": "string" + }, + "team_id": { + "type": "string" + } + }, + "required": [ + "value", + "id", + "description", + "created_at_millis", + "is_public", + "type", + "team_id" + ] + } + } + } + } + } + } + }, + "/team-api-keys/{api_key_id}": { + "get": { + "summary": "Get team API key details", + "description": "Get details of a specific team API key", + "parameters": [ + { + "name": "api_key_id", + "in": "path", + "schema": { + "type": "string" + }, + "required": true + } + ], + "tags": [ + "API Keys" + ], + "x-full-url": "https://api.stack-auth.com/api/v1/team-api-keys/{api_key_id}", + "responses": { + "200": { + "description": "Successful response", + "content": { + "application/json": { + "schema": { + "type": "object", + "properties": { + "id": { + "type": "string" + }, + "description": { + "type": "string" + }, + "expires_at_millis": { + "type": "number" + }, + "manually_revoked_at_millis": { + "type": "number" + }, + "created_at_millis": { + "type": "number" + }, + "is_public": { + "type": "boolean" + }, + "value": { + "type": "object", + "properties": { + "last_four": { + "type": "string" + } + }, + "required": [ + "last_four" + ] + }, + "type": { + "type": "string" + }, + "team_id": { + "type": "string" + } + }, + "required": [ + "id", + "description", + "created_at_millis", + "is_public", + "value", + "type", + "team_id" + ] + } + } + } + } + } + }, + "patch": { + "summary": "Update team API key", + "description": "Update an team API key", + "parameters": [ + { + "name": "api_key_id", + "in": "path", + "schema": { + "type": "string" + }, + "required": true + } + ], + "requestBody": { + "required": true, + "content": { + "application/json": { + "schema": { + "type": "object", + "properties": { + "description": { + "type": "string" + }, + "revoked": { + "type": "boolean" + } + }, + "example": {} + } + } + } + }, + "tags": [ + "API Keys" + ], + "x-full-url": "https://api.stack-auth.com/api/v1/team-api-keys/{api_key_id}", + "responses": { + "200": { + "description": "Successful response", + "content": { + "application/json": { + "schema": { + "type": "object", + "properties": { + "id": { + "type": "string" + }, + "description": { + "type": "string" + }, + "expires_at_millis": { + "type": "number" + }, + "manually_revoked_at_millis": { + "type": "number" + }, + "created_at_millis": { + "type": "number" + }, + "is_public": { + "type": "boolean" + }, + "value": { + "type": "object", + "properties": { + "last_four": { + "type": "string" + } + }, + "required": [ + "last_four" + ] + }, + "type": { + "type": "string" + }, + "team_id": { + "type": "string" + } + }, + "required": [ + "id", + "description", + "created_at_millis", + "is_public", + "value", + "type", + "team_id" + ] + } + } + } + } + } + } + }, + "/user-api-keys": { + "get": { + "summary": "List user API keys", + "description": "List all user API keys for the project with their metadata and status", + "parameters": [ + { + "name": "user_id", + "in": "query", + "schema": { + "type": "string" + }, + "required": false + } + ], + "tags": [ + "API Keys" + ], + "x-full-url": "https://api.stack-auth.com/api/v1/user-api-keys", + "responses": { + "200": { + "description": "Successful response", + "content": { + "application/json": { + "schema": { + "type": "object", + "properties": { + "items": { + "type": "array", + "items": { + "type": "object", + "properties": { + "id": { + "type": "string" + }, + "description": { + "type": "string" + }, + "expires_at_millis": { + "type": "number" + }, + "manually_revoked_at_millis": { + "type": "number" + }, + "created_at_millis": { + "type": "number" + }, + "is_public": { + "type": "boolean" + }, + "value": { + "type": "object", + "properties": { + "last_four": { + "type": "string" + } + }, + "required": [ + "last_four" + ] + }, + "type": { + "type": "string" + }, + "user_id": { + "type": "string", + "example": "3241a285-8329-4d69-8f3d-316e08cf140c", + "description": "The ID of the user, or the special value `me` for the currently authenticated user" + } + }, + "required": [ + "id", + "description", + "created_at_millis", + "is_public", + "value", + "type", + "user_id" + ] + } + }, + "pagination": { + "type": "object", + "properties": { + "next_cursor": { + "type": "string", + "example": "b3d396b8-c574-4c80-97b3-50031675ceb2", + "description": "The cursor to fetch the next page of results. null if there is no next page." + } + }, + "required": [] + } + }, + "required": [ + "items" + ] + } + } + } + } + } + }, + "post": { + "summary": "Create user API key", + "description": "Create a new API key for a user or team", + "parameters": [], + "requestBody": { + "required": true, + "content": { + "application/json": { + "schema": { + "type": "object", + "properties": { + "description": { + "type": "string" + }, + "expires_at_millis": { + "type": "number" + }, + "is_public": { + "type": "boolean" + }, + "user_id": { + "type": "string", + "example": "3241a285-8329-4d69-8f3d-316e08cf140c", + "description": "The ID of the user, or the special value `me` for the currently authenticated user" + } + }, + "required": [ + "description", + "user_id" + ], + "example": { + "user_id": "3241a285-8329-4d69-8f3d-316e08cf140c" + } + } + } + } + }, + "tags": [ + "API Keys" + ], + "x-full-url": "https://api.stack-auth.com/api/v1/user-api-keys", + "responses": { + "200": { + "description": "Successful response", + "content": { + "application/json": { + "schema": { + "type": "object", + "properties": { + "value": { + "type": "string" + }, + "id": { + "type": "string" + }, + "description": { + "type": "string" + }, + "expires_at_millis": { + "type": "number" + }, + "manually_revoked_at_millis": { + "type": "number" + }, + "created_at_millis": { + "type": "number" + }, + "is_public": { + "type": "boolean" + }, + "type": { + "type": "string" + }, + "user_id": { + "type": "string", + "example": "3241a285-8329-4d69-8f3d-316e08cf140c", + "description": "The ID of the user, or the special value `me` for the currently authenticated user" + } + }, + "required": [ + "value", + "id", + "description", + "created_at_millis", + "is_public", + "type", + "user_id" + ] + } + } + } + } + } + } + }, + "/user-api-keys/{api_key_id}": { + "get": { + "summary": "Get user API key details", + "description": "Get details of a specific user API key", + "parameters": [ + { + "name": "api_key_id", + "in": "path", + "schema": { + "type": "string" + }, + "required": true + } + ], + "tags": [ + "API Keys" + ], + "x-full-url": "https://api.stack-auth.com/api/v1/user-api-keys/{api_key_id}", + "responses": { + "200": { + "description": "Successful response", + "content": { + "application/json": { + "schema": { + "type": "object", + "properties": { + "id": { + "type": "string" + }, + "description": { + "type": "string" + }, + "expires_at_millis": { + "type": "number" + }, + "manually_revoked_at_millis": { + "type": "number" + }, + "created_at_millis": { + "type": "number" + }, + "is_public": { + "type": "boolean" + }, + "value": { + "type": "object", + "properties": { + "last_four": { + "type": "string" + } + }, + "required": [ + "last_four" + ] + }, + "type": { + "type": "string" + }, + "user_id": { + "type": "string", + "example": "3241a285-8329-4d69-8f3d-316e08cf140c", + "description": "The ID of the user, or the special value `me` for the currently authenticated user" + } + }, + "required": [ + "id", + "description", + "created_at_millis", + "is_public", + "value", + "type", + "user_id" + ] + } + } + } + } + } + }, + "patch": { + "summary": "Update user API key", + "description": "Update an user API key", + "parameters": [ + { + "name": "api_key_id", + "in": "path", + "schema": { + "type": "string" + }, + "required": true + } + ], + "requestBody": { + "required": true, + "content": { + "application/json": { + "schema": { + "type": "object", + "properties": { + "description": { + "type": "string" + }, + "revoked": { + "type": "boolean" + } + }, + "example": {} + } + } + } + }, + "tags": [ + "API Keys" + ], + "x-full-url": "https://api.stack-auth.com/api/v1/user-api-keys/{api_key_id}", + "responses": { + "200": { + "description": "Successful response", + "content": { + "application/json": { + "schema": { + "type": "object", + "properties": { + "id": { + "type": "string" + }, + "description": { + "type": "string" + }, + "expires_at_millis": { + "type": "number" + }, + "manually_revoked_at_millis": { + "type": "number" + }, + "created_at_millis": { + "type": "number" + }, + "is_public": { + "type": "boolean" + }, + "value": { + "type": "object", + "properties": { + "last_four": { + "type": "string" + } + }, + "required": [ + "last_four" + ] + }, + "type": { + "type": "string" + }, + "user_id": { + "type": "string", + "example": "3241a285-8329-4d69-8f3d-316e08cf140c", + "description": "The ID of the user, or the special value `me` for the currently authenticated user" + } + }, + "required": [ + "id", + "description", + "created_at_millis", + "is_public", + "value", + "type", + "user_id" + ] + } + } + } + } + } + } + }, + "/auth/cli": { + "post": { + "summary": "Initiate CLI authentication", + "description": "Create a new CLI authentication session and return polling and login codes", + "parameters": [], + "requestBody": { + "required": true, + "content": { + "application/json": { + "schema": { + "type": "object", + "properties": { + "expires_in_millis": { + "type": "number", + "default": 7200000 + }, + "anon_refresh_token": { + "type": "string" + } + }, + "example": {} + } + } + } + }, + "tags": [ + "CLI Authentication" + ], + "x-full-url": "https://api.stack-auth.com/api/v1/auth/cli", + "responses": { + "200": { + "description": "Successful response", + "content": { + "application/json": { + "schema": { + "type": "object", + "properties": { + "polling_code": { + "type": "string" + }, + "login_code": { + "type": "string" + }, + "expires_at": { + "type": "string" + } + }, + "required": [ + "polling_code", + "login_code", + "expires_at" + ] + } + } + } + } + } + } + }, + "/auth/cli/complete": { + "post": { + "summary": "Complete CLI authentication", + "description": "Inspect, claim, or complete a CLI authentication session", + "parameters": [], + "requestBody": { + "required": true, + "content": { + "application/json": { + "schema": { + "type": "object", + "properties": { + "login_code": { + "type": "string" + }, + "mode": { + "type": "string", + "default": "complete" + }, + "refresh_token": { + "type": "string" + } + }, + "required": [ + "login_code" + ], + "example": {} + } + } + } + }, + "tags": [ + "CLI Authentication" + ], + "x-full-url": "https://api.stack-auth.com/api/v1/auth/cli/complete", + "responses": { + "200": { + "description": "Successful response", + "content": { + "application/json": { + "schema": { + "type": "object", + "properties": { + "success": { + "type": "boolean" + } + }, + "required": [ + "success" + ] + } + } + } + } + } + } + }, + "/auth/cli/poll": { + "post": { + "summary": "Poll CLI authentication status", + "description": "Check the status of a CLI authentication session using the polling code", + "parameters": [], + "requestBody": { + "required": true, + "content": { + "application/json": { + "schema": { + "type": "object", + "properties": { + "polling_code": { + "type": "string" + } + }, + "required": [ + "polling_code" + ], + "example": {} + } + } + } + }, + "tags": [ + "CLI Authentication" + ], + "x-full-url": "https://api.stack-auth.com/api/v1/auth/cli/poll", + "responses": { + "200": { + "description": "Successful response", + "content": { + "application/json": { + "schema": { + "type": "object", + "properties": { + "status": { + "type": "string" + }, + "refresh_token": { + "type": "string" + } + }, + "required": [ + "status" + ] + } + } + } + }, + "201": { + "description": "Successful response", + "content": { + "application/json": { + "schema": { + "type": "object", + "properties": { + "status": { + "type": "string" + }, + "refresh_token": { + "type": "string" + } + }, + "required": [ + "status" + ] + } + } + } + } + } + } + }, + "/connected-accounts/{user_id}": { + "get": { + "summary": "List connected accounts", + "description": "Retrieves a list of all connected accounts for a user.", + "parameters": [ + { + "name": "user_id", + "in": "path", + "schema": { + "type": "string", + "example": "3241a285-8329-4d69-8f3d-316e08cf140c", + "description": "The ID of the user, or the special value `me` for the currently authenticated user" + }, + "description": "The ID of the user, or the special value `me` for the currently authenticated user", + "required": false + } + ], + "tags": [ + "Connected Accounts" + ], + "x-full-url": "https://api.stack-auth.com/api/v1/connected-accounts/{user_id}", + "responses": { + "200": { + "description": "Successful response", + "content": { + "application/json": { + "schema": { + "type": "object", + "properties": { + "items": { + "type": "array", + "items": { + "type": "object", + "properties": { + "user_id": { + "type": "string", + "example": "3241a285-8329-4d69-8f3d-316e08cf140c", + "description": "The ID of the user, or the special value `me` for the currently authenticated user" + }, + "provider": { + "type": "string", + "example": "google", + "description": "Provider config ID of the OAuth provider. This uniquely identifies the provider config on config.json file" + }, + "provider_account_id": { + "type": "string", + "example": "google-account-id-12345", + "description": "Account ID of the OAuth provider. This uniquely identifies the account on the provider side." + } + }, + "required": [ + "user_id", + "provider", + "provider_account_id" + ] + } + }, + "pagination": { + "type": "object", + "properties": { + "next_cursor": { + "type": "string", + "example": "b3d396b8-c574-4c80-97b3-50031675ceb2", + "description": "The cursor to fetch the next page of results. null if there is no next page." + } + }, + "required": [] + } + }, + "required": [ + "items" + ] + } + } + } + } + } + } + }, + "/contact-channels": { + "get": { + "summary": "List contact channels", + "description": "Retrieves a list of all contact channels for a user.", + "parameters": [ + { + "name": "user_id", + "in": "query", + "schema": { + "type": "string", + "example": "3241a285-8329-4d69-8f3d-316e08cf140c", + "description": "The ID of the user, or the special value `me` for the currently authenticated user" + }, + "description": "The ID of the user, or the special value `me` for the currently authenticated user", + "required": false + }, + { + "name": "contact_channel_id", + "in": "query", + "schema": { + "type": "string" + }, + "required": false + } + ], + "tags": [ + "Contact Channels" + ], + "x-full-url": "https://api.stack-auth.com/api/v1/contact-channels", + "responses": { + "200": { + "description": "Successful response", + "content": { + "application/json": { + "schema": { + "type": "object", + "properties": { + "items": { + "type": "array", + "items": { + "type": "object", + "properties": { + "user_id": { + "type": "string", + "example": "3241a285-8329-4d69-8f3d-316e08cf140c", + "description": "The unique identifier of the user" + }, + "id": { + "type": "string", + "example": "b3d396b8-c574-4c80-97b3-50031675ceb2", + "description": "The unique identifier of the contact channel" + }, + "value": { + "type": "string", + "example": "johndoe@example.com", + "description": "The value of the contact channel. For email, this should be a valid email address." + }, + "type": { + "type": "string", + "example": "email", + "description": "The type of the contact channel. Currently only \"email\" is supported." + }, + "used_for_auth": { + "type": "boolean", + "example": true, + "description": "Whether the contact channel is used for authentication. If this is set to `true`, the user will be able to sign in with the contact channel with password or OTP." + }, + "is_verified": { + "type": "boolean", + "example": true, + "description": "Whether the contact channel has been verified. If this is set to `true`, the contact channel has been verified to belong to the user." + }, + "is_primary": { + "type": "boolean", + "example": true, + "description": "Whether the contact channel is the primary contact channel. If this is set to `true`, it will be used for authentication and notifications by default." + } + }, + "required": [ + "user_id", + "id", + "value", + "type", + "used_for_auth", + "is_verified", + "is_primary" + ] + } + }, + "pagination": { + "type": "object", + "properties": { + "next_cursor": { + "type": "string", + "example": "b3d396b8-c574-4c80-97b3-50031675ceb2", + "description": "The cursor to fetch the next page of results. null if there is no next page." + } + }, + "required": [] + } + }, + "required": [ + "items" + ] + } + } + } + } + } + }, + "post": { + "summary": "Create a contact channel", + "description": "Add a new contact channel for a user.", + "parameters": [ + { + "name": "user_id", + "in": "query", + "schema": { + "type": "string", + "example": "3241a285-8329-4d69-8f3d-316e08cf140c", + "description": "The ID of the user, or the special value `me` for the currently authenticated user" + }, + "description": "The ID of the user, or the special value `me` for the currently authenticated user", + "required": false + }, + { + "name": "contact_channel_id", + "in": "query", + "schema": { + "type": "string" + }, + "required": false + } + ], + "requestBody": { + "required": true, + "content": { + "application/json": { + "schema": { + "type": "object", + "properties": { + "user_id": { + "type": "string", + "example": "3241a285-8329-4d69-8f3d-316e08cf140c", + "description": "The ID of the user, or the special value `me` for the currently authenticated user" + }, + "value": { + "type": "string", + "example": "johndoe@example.com", + "description": "The value of the contact channel. For email, this should be a valid email address." + }, + "type": { + "type": "string", + "example": "email", + "description": "The type of the contact channel. Currently only \"email\" is supported." + }, + "used_for_auth": { + "type": "boolean", + "example": true, + "description": "Whether the contact channel is used for authentication. If this is set to `true`, the user will be able to sign in with the contact channel with password or OTP." + }, + "is_primary": { + "type": "boolean", + "example": true, + "description": "Whether the contact channel is the primary contact channel. If this is set to `true`, it will be used for authentication and notifications by default." + } + }, + "required": [ + "user_id", + "value", + "type", + "used_for_auth" + ], + "example": { + "user_id": "3241a285-8329-4d69-8f3d-316e08cf140c", + "value": "johndoe@example.com", + "type": "email", + "used_for_auth": true, + "is_primary": true + } + } + } + } + }, + "tags": [ + "Contact Channels" + ], + "x-full-url": "https://api.stack-auth.com/api/v1/contact-channels", + "responses": { + "201": { + "description": "Successful response", + "content": { + "application/json": { + "schema": { + "type": "object", + "properties": { + "user_id": { + "type": "string", + "example": "3241a285-8329-4d69-8f3d-316e08cf140c", + "description": "The unique identifier of the user" + }, + "id": { + "type": "string", + "example": "b3d396b8-c574-4c80-97b3-50031675ceb2", + "description": "The unique identifier of the contact channel" + }, + "value": { + "type": "string", + "example": "johndoe@example.com", + "description": "The value of the contact channel. For email, this should be a valid email address." + }, + "type": { + "type": "string", + "example": "email", + "description": "The type of the contact channel. Currently only \"email\" is supported." + }, + "used_for_auth": { + "type": "boolean", + "example": true, + "description": "Whether the contact channel is used for authentication. If this is set to `true`, the user will be able to sign in with the contact channel with password or OTP." + }, + "is_verified": { + "type": "boolean", + "example": true, + "description": "Whether the contact channel has been verified. If this is set to `true`, the contact channel has been verified to belong to the user." + }, + "is_primary": { + "type": "boolean", + "example": true, + "description": "Whether the contact channel is the primary contact channel. If this is set to `true`, it will be used for authentication and notifications by default." + } + }, + "required": [ + "user_id", + "id", + "value", + "type", + "used_for_auth", + "is_verified", + "is_primary" + ] + } + } + } + } + } + } + }, + "/contact-channels/verify": { + "post": { + "summary": "Verify an email", + "description": "Verify an email address of a user", + "parameters": [], + "requestBody": { + "required": true, + "content": { + "application/json": { + "schema": { + "type": "object", + "properties": { + "code": { + "type": "string", + "example": "u3h6gn4w24pqc8ya679inrhjwh1rybth6a7thurqhnpf2", + "description": "A 45 character code" + } + }, + "required": [ + "code" + ], + "example": { + "code": "u3h6gn4w24pqc8ya679inrhjwh1rybth6a7thurqhnpf2" + } + } + } + } + }, + "tags": [ + "Contact Channels" + ], + "x-full-url": "https://api.stack-auth.com/api/v1/contact-channels/verify", + "responses": { + "200": { + "description": "Successful response", + "content": { + "application/json": { + "schema": { + "type": "object", + "properties": { + "success": { + "type": "boolean", + "description": "Always equal to true.", + "example": true + } + }, + "required": [ + "success" + ] + } + } + } + } + } + } + }, + "/contact-channels/verify/check-code": { + "post": { + "summary": "Check email verification code", + "description": "Check if an email verification code is valid without using it", + "parameters": [], + "requestBody": { + "required": true, + "content": { + "application/json": { + "schema": { + "type": "object", + "properties": { + "code": { + "type": "string", + "example": "u3h6gn4w24pqc8ya679inrhjwh1rybth6a7thurqhnpf2", + "description": "A 45 character code" + } + }, + "required": [ + "code" + ], + "example": { + "code": "u3h6gn4w24pqc8ya679inrhjwh1rybth6a7thurqhnpf2" + } + } + } + } + }, + "tags": [ + "Contact Channels" + ], + "x-full-url": "https://api.stack-auth.com/api/v1/contact-channels/verify/check-code", + "responses": { + "200": { + "description": "Successful response", + "content": { + "application/json": { + "schema": { + "type": "object", + "properties": { + "is_code_valid": { + "type": "boolean" + } + }, + "required": [ + "is_code_valid" + ] + } + } + } + } + } + } + }, + "/contact-channels/{user_id}/{contact_channel_id}": { + "get": { + "summary": "Get a contact channel", + "description": "Retrieves a specific contact channel by the user ID and the contact channel ID.", + "parameters": [ + { + "name": "user_id", + "in": "query", + "schema": { + "type": "string", + "example": "3241a285-8329-4d69-8f3d-316e08cf140c", + "description": "The ID of the user, or the special value `me` for the currently authenticated user" + }, + "description": "The ID of the user, or the special value `me` for the currently authenticated user", + "required": false + }, + { + "name": "contact_channel_id", + "in": "query", + "schema": { + "type": "string" + }, + "required": false + }, + { + "name": "user_id", + "in": "path", + "schema": { + "type": "string", + "example": "me", + "description": "the user that the contact channel belongs to" + }, + "description": "the user that the contact channel belongs to", + "required": true + }, + { + "name": "contact_channel_id", + "in": "path", + "schema": { + "type": "string", + "example": "b3d396b8-c574-4c80-97b3-50031675ceb2", + "description": "the target contact channel" + }, + "description": "the target contact channel", + "required": true + } + ], + "tags": [ + "Contact Channels" + ], + "x-full-url": "https://api.stack-auth.com/api/v1/contact-channels/{user_id}/{contact_channel_id}", + "responses": { + "200": { + "description": "Successful response", + "content": { + "application/json": { + "schema": { + "type": "object", + "properties": { + "user_id": { + "type": "string", + "example": "3241a285-8329-4d69-8f3d-316e08cf140c", + "description": "The unique identifier of the user" + }, + "id": { + "type": "string", + "example": "b3d396b8-c574-4c80-97b3-50031675ceb2", + "description": "The unique identifier of the contact channel" + }, + "value": { + "type": "string", + "example": "johndoe@example.com", + "description": "The value of the contact channel. For email, this should be a valid email address." + }, + "type": { + "type": "string", + "example": "email", + "description": "The type of the contact channel. Currently only \"email\" is supported." + }, + "used_for_auth": { + "type": "boolean", + "example": true, + "description": "Whether the contact channel is used for authentication. If this is set to `true`, the user will be able to sign in with the contact channel with password or OTP." + }, + "is_verified": { + "type": "boolean", + "example": true, + "description": "Whether the contact channel has been verified. If this is set to `true`, the contact channel has been verified to belong to the user." + }, + "is_primary": { + "type": "boolean", + "example": true, + "description": "Whether the contact channel is the primary contact channel. If this is set to `true`, it will be used for authentication and notifications by default." + } + }, + "required": [ + "user_id", + "id", + "value", + "type", + "used_for_auth", + "is_verified", + "is_primary" + ] + } + } + } + } + } + }, + "delete": { + "summary": "Delete a contact channel", + "description": "Removes a contact channel for a given user.", + "parameters": [ + { + "name": "user_id", + "in": "query", + "schema": { + "type": "string", + "example": "3241a285-8329-4d69-8f3d-316e08cf140c", + "description": "The ID of the user, or the special value `me` for the currently authenticated user" + }, + "description": "The ID of the user, or the special value `me` for the currently authenticated user", + "required": false + }, + { + "name": "contact_channel_id", + "in": "query", + "schema": { + "type": "string" + }, + "required": false + }, + { + "name": "user_id", + "in": "path", + "schema": { + "type": "string", + "example": "me", + "description": "the user that the contact channel belongs to" + }, + "description": "the user that the contact channel belongs to", + "required": true + }, + { + "name": "contact_channel_id", + "in": "path", + "schema": { + "type": "string", + "example": "b3d396b8-c574-4c80-97b3-50031675ceb2", + "description": "the target contact channel" + }, + "description": "the target contact channel", + "required": true + } + ], + "tags": [ + "Contact Channels" + ], + "x-full-url": "https://api.stack-auth.com/api/v1/contact-channels/{user_id}/{contact_channel_id}", + "responses": { + "200": { + "description": "Successful response", + "content": { + "application/json": { + "schema": { + "type": "object", + "properties": { + "success": { + "type": "boolean", + "description": "Always equal to true.", + "example": true + } + }, + "required": [ + "success" + ] + } + } + } + } + } + }, + "patch": { + "summary": "Update a contact channel", + "description": "Updates an existing contact channel. Only the values provided will be updated.", + "parameters": [ + { + "name": "user_id", + "in": "query", + "schema": { + "type": "string", + "example": "3241a285-8329-4d69-8f3d-316e08cf140c", + "description": "The ID of the user, or the special value `me` for the currently authenticated user" + }, + "description": "The ID of the user, or the special value `me` for the currently authenticated user", + "required": false + }, + { + "name": "contact_channel_id", + "in": "query", + "schema": { + "type": "string" + }, + "required": false + }, + { + "name": "user_id", + "in": "path", + "schema": { + "type": "string", + "example": "me", + "description": "the user that the contact channel belongs to" + }, + "description": "the user that the contact channel belongs to", + "required": true + }, + { + "name": "contact_channel_id", + "in": "path", + "schema": { + "type": "string", + "example": "b3d396b8-c574-4c80-97b3-50031675ceb2", + "description": "the target contact channel" + }, + "description": "the target contact channel", + "required": true + } + ], + "requestBody": { + "required": true, + "content": { + "application/json": { + "schema": { + "type": "object", + "properties": { + "value": { + "type": "string", + "example": "johndoe@example.com", + "description": "The value of the contact channel. For email, this should be a valid email address." + }, + "type": { + "type": "string", + "example": "email", + "description": "The type of the contact channel. Currently only \"email\" is supported." + }, + "used_for_auth": { + "type": "boolean", + "example": true, + "description": "Whether the contact channel is used for authentication. If this is set to `true`, the user will be able to sign in with the contact channel with password or OTP." + }, + "is_primary": { + "type": "boolean", + "example": true, + "description": "Whether the contact channel is the primary contact channel. If this is set to `true`, it will be used for authentication and notifications by default." + } + }, + "example": { + "value": "johndoe@example.com", + "type": "email", + "used_for_auth": true, + "is_primary": true + } + } + } + } + }, + "tags": [ + "Contact Channels" + ], + "x-full-url": "https://api.stack-auth.com/api/v1/contact-channels/{user_id}/{contact_channel_id}", + "responses": { + "200": { + "description": "Successful response", + "content": { + "application/json": { + "schema": { + "type": "object", + "properties": { + "user_id": { + "type": "string", + "example": "3241a285-8329-4d69-8f3d-316e08cf140c", + "description": "The unique identifier of the user" + }, + "id": { + "type": "string", + "example": "b3d396b8-c574-4c80-97b3-50031675ceb2", + "description": "The unique identifier of the contact channel" + }, + "value": { + "type": "string", + "example": "johndoe@example.com", + "description": "The value of the contact channel. For email, this should be a valid email address." + }, + "type": { + "type": "string", + "example": "email", + "description": "The type of the contact channel. Currently only \"email\" is supported." + }, + "used_for_auth": { + "type": "boolean", + "example": true, + "description": "Whether the contact channel is used for authentication. If this is set to `true`, the user will be able to sign in with the contact channel with password or OTP." + }, + "is_verified": { + "type": "boolean", + "example": true, + "description": "Whether the contact channel has been verified. If this is set to `true`, the contact channel has been verified to belong to the user." + }, + "is_primary": { + "type": "boolean", + "example": true, + "description": "Whether the contact channel is the primary contact channel. If this is set to `true`, it will be used for authentication and notifications by default." + } + }, + "required": [ + "user_id", + "id", + "value", + "type", + "used_for_auth", + "is_verified", + "is_primary" + ] + } + } + } + } + } + } + }, + "/contact-channels/{user_id}/{contact_channel_id}/send-verification-code": { + "post": { + "summary": "Send contact channel verification code", + "description": "Send a code to the user's contact channel for verifying the contact channel.", + "parameters": [ + { + "name": "user_id", + "in": "path", + "schema": { + "type": "string", + "example": "me", + "description": "The user to send the verification code to." + }, + "description": "The user to send the verification code to.", + "required": true + }, + { + "name": "contact_channel_id", + "in": "path", + "schema": { + "type": "string", + "example": "b3d396b8-c574-4c80-97b3-50031675ceb2", + "description": "The contact channel to send the verification code to." + }, + "description": "The contact channel to send the verification code to.", + "required": true + } + ], + "requestBody": { + "required": true, + "content": { + "application/json": { + "schema": { + "type": "object", + "properties": { + "callback_url": { + "type": "string", + "example": "https://example.com/handler/email-verification", + "description": "The base callback URL to construct a verification link for the verification e-mail. A query parameter `code` with the verification code will be appended to it. The page should then make a request to the `/contact-channels/verify` endpoint." + } + }, + "required": [ + "callback_url" + ], + "example": { + "callback_url": "https://example.com/handler/email-verification" + } + } + } + } + }, + "tags": [ + "Contact Channels" + ], + "x-full-url": "https://api.stack-auth.com/api/v1/contact-channels/{user_id}/{contact_channel_id}/send-verification-code", + "responses": { + "200": { + "description": "Successful response", + "content": { + "application/json": { + "schema": { + "type": "object", + "properties": { + "success": { + "type": "boolean", + "description": "Always equal to true.", + "example": true + } + }, + "required": [ + "success" + ] + } + } + } + } + } + } + }, + "/emails/notification-preference/{user_id}": { + "get": { + "summary": "List notification preferences", + "description": "Get all notification preferences for a user, showing which notification categories are enabled or disabled.", + "parameters": [ + { + "name": "user_id", + "in": "path", + "schema": { + "type": "string", + "example": "3241a285-8329-4d69-8f3d-316e08cf140c", + "description": "The ID of the user, or the special value `me` for the currently authenticated user" + }, + "description": "The ID of the user, or the special value `me` for the currently authenticated user", + "required": false + } + ], + "tags": [ + "Emails" + ], + "x-full-url": "https://api.stack-auth.com/api/v1/emails/notification-preference/{user_id}", + "responses": { + "200": { + "description": "Successful response", + "content": { + "application/json": { + "schema": { + "type": "object", + "properties": { + "items": { + "type": "array", + "items": { + "type": "object", + "properties": { + "notification_category_id": { + "type": "string" + }, + "notification_category_name": { + "type": "string" + }, + "enabled": { + "type": "boolean" + }, + "can_disable": { + "type": "boolean" + } + }, + "required": [ + "notification_category_id", + "notification_category_name", + "enabled", + "can_disable" + ] + } + }, + "pagination": { + "type": "object", + "properties": { + "next_cursor": { + "type": "string", + "example": "b3d396b8-c574-4c80-97b3-50031675ceb2", + "description": "The cursor to fetch the next page of results. null if there is no next page." + } + }, + "required": [] + } + }, + "required": [ + "items" + ] + } + } + } + } + } + } + }, + "/emails/notification-preference/{user_id}/{notification_category_id}": { + "patch": { + "summary": "Update notification preference", + "description": "Enable or disable a specific notification category for a user.", + "parameters": [ + { + "name": "user_id", + "in": "path", + "schema": { + "type": "string", + "example": "3241a285-8329-4d69-8f3d-316e08cf140c", + "description": "The ID of the user, or the special value `me` for the currently authenticated user" + }, + "description": "The ID of the user, or the special value `me` for the currently authenticated user", + "required": true + }, + { + "name": "notification_category_id", + "in": "path", + "schema": { + "type": "string" + }, + "required": false + } + ], + "requestBody": { + "required": true, + "content": { + "application/json": { + "schema": { + "type": "object", + "properties": { + "enabled": { + "type": "boolean" + } + }, + "required": [ + "enabled" + ], + "example": {} + } + } + } + }, + "tags": [ + "Emails" + ], + "x-full-url": "https://api.stack-auth.com/api/v1/emails/notification-preference/{user_id}/{notification_category_id}", + "responses": { + "200": { + "description": "Successful response", + "content": { + "application/json": { + "schema": { + "type": "object", + "properties": { + "notification_category_id": { + "type": "string" + }, + "notification_category_name": { + "type": "string" + }, + "enabled": { + "type": "boolean" + }, + "can_disable": { + "type": "boolean" + } + }, + "required": [ + "notification_category_id", + "notification_category_name", + "enabled", + "can_disable" + ] + } + } + } + } + } + } + }, + "/internal/feature-requests": { + "get": { + "summary": "Get feature requests", + "description": "Fetch all feature requests with upvote status for the current user", + "parameters": [], + "tags": [ + "Internal" + ], + "x-full-url": "https://api.stack-auth.com/api/v1/internal/feature-requests", + "responses": { + "200": { + "description": "Successful response", + "content": { + "application/json": { + "schema": { + "type": "object", + "properties": { + "posts": { + "type": "array", + "items": { + "type": "object", + "properties": { + "id": { + "type": "string" + }, + "title": { + "type": "string" + }, + "content": { + "type": "string" + }, + "upvotes": { + "type": "number" + }, + "date": { + "type": "string" + }, + "postStatus": { + "type": "object", + "properties": { + "name": { + "type": "string" + }, + "color": { + "type": "string" + } + }, + "required": [ + "name", + "color" + ] + }, + "userHasUpvoted": { + "type": "boolean" + } + }, + "required": [ + "id", + "title", + "upvotes", + "date", + "userHasUpvoted" + ] + } + } + }, + "required": [ + "posts" + ] + } + } + } + } + } + }, + "post": { + "summary": "Create feature request", + "description": "Create a new feature request", + "parameters": [], + "requestBody": { + "required": true, + "content": { + "application/json": { + "schema": { + "type": "object", + "properties": { + "title": { + "type": "string" + }, + "content": { + "type": "string" + }, + "category": { + "type": "string" + }, + "tags": { + "type": "array", + "items": { + "type": "string" + } + }, + "commentsAllowed": { + "type": "boolean" + }, + "customInputValues": { + "type": "object", + "properties": {}, + "required": [] + } + }, + "required": [ + "title" + ], + "example": {} + } + } + } + }, + "tags": [ + "Internal" + ], + "x-full-url": "https://api.stack-auth.com/api/v1/internal/feature-requests", + "responses": { + "200": { + "description": "Successful response", + "content": { + "application/json": { + "schema": { + "type": "object", + "properties": { + "success": { + "type": "boolean" + }, + "id": { + "type": "string" + } + }, + "required": [ + "success" + ] + } + } + } + } + } + } + }, + "/internal/feature-requests/{featureRequestId}/upvote": { + "post": { + "summary": "Toggle upvote on feature request", + "description": "Toggle upvote on a feature request for the current user", + "parameters": [ + { + "name": "featureRequestId", + "in": "path", + "schema": { + "type": "string" + }, + "required": true + } + ], + "requestBody": { + "required": true, + "content": { + "application/json": { + "schema": { + "type": "object", + "properties": {}, + "example": {} + } + } + } + }, + "tags": [ + "Internal" + ], + "x-full-url": "https://api.stack-auth.com/api/v1/internal/feature-requests/{featureRequestId}/upvote", + "responses": { + "200": { + "description": "Successful response", + "content": { + "application/json": { + "schema": { + "type": "object", + "properties": { + "success": { + "type": "boolean" + }, + "upvoted": { + "type": "boolean" + } + }, + "required": [ + "success" + ] + } + } + } + } + } + } + }, + "/internal/feedback": { + "post": { + "summary": "Submit support feedback", + "description": "Send a support feedback message to the internal Stack Auth inbox. Auth is optional — works from both the dashboard (authenticated) and the dev tool (unauthenticated).", + "parameters": [], + "requestBody": { + "required": true, + "content": { + "application/json": { + "schema": { + "type": "object", + "properties": { + "name": { + "type": "string" + }, + "email": { + "type": "string" + }, + "message": { + "type": "string" + }, + "feedback_type": { + "type": "string" + } + }, + "required": [ + "email", + "message" + ], + "example": {} + } + } + } + }, + "tags": [ + "Internal" + ], + "x-full-url": "https://api.stack-auth.com/api/v1/internal/feedback", + "responses": { + "200": { + "description": "Successful response", + "content": { + "application/json": { + "schema": { + "type": "object", + "properties": { + "success": { + "type": "boolean" + } + }, + "required": [ + "success" + ] + } + } + } + } + } + } + }, + "/internal/preview/create-project": { + "post": { + "summary": "Create a preview project", + "description": "Creates a new project pre-filled with dummy data for the preview environment. Only available when NEXT_PUBLIC_STACK_IS_PREVIEW=true.", + "parameters": [], + "requestBody": { + "required": true, + "content": { + "application/json": { + "schema": { + "type": "object", + "properties": {}, + "example": {} + } + } + } + }, + "tags": [ + "Internal" + ], + "x-full-url": "https://api.stack-auth.com/api/v1/internal/preview/create-project", + "responses": { + "200": { + "description": "Successful response", + "content": { + "application/json": { + "schema": { + "type": "object", + "properties": { + "project_id": { + "type": "string" + } + }, + "required": [ + "project_id" + ] + } + } + } + } + } + } + }, + "/auth/oauth/authorize/{provider_id}": { + "get": { + "summary": "OAuth authorize endpoint", + "description": "This endpoint is used to initiate the OAuth authorization flow. there are two purposes for this endpoint: 1. Authenticate a user with an OAuth provider. 2. Link an existing user with an OAuth provider.", + "parameters": [ + { + "name": "type", + "in": "query", + "schema": { + "type": "string", + "default": "authenticate" + }, + "required": false + }, + { + "name": "token", + "in": "query", + "schema": { + "type": "string", + "default": "" + }, + "required": false + }, + { + "name": "provider_scope", + "in": "query", + "schema": { + "type": "string" + }, + "required": false + }, + { + "name": "error_redirect_uri", + "in": "query", + "schema": { + "type": "string" + }, + "required": false + }, + { + "name": "after_callback_redirect_url", + "in": "query", + "schema": { + "type": "string" + }, + "required": false + }, + { + "name": "stack_response_mode", + "in": "query", + "schema": { + "type": "string", + "default": "redirect" + }, + "required": false + }, + { + "name": "bot_challenge_token", + "in": "query", + "schema": { + "type": "string" + }, + "required": false + }, + { + "name": "bot_challenge_phase", + "in": "query", + "schema": { + "type": "string" + }, + "required": false + }, + { + "name": "bot_challenge_unavailable", + "in": "query", + "schema": { + "type": "string" + }, + "required": false + }, + { + "name": "client_id", + "in": "query", + "schema": { + "type": "string" + }, + "required": true + }, + { + "name": "client_secret", + "in": "query", + "schema": { + "type": "string" + }, + "required": true + }, + { + "name": "redirect_uri", + "in": "query", + "schema": { + "type": "string" + }, + "required": true + }, + { + "name": "scope", + "in": "query", + "schema": { + "type": "string" + }, + "required": true + }, + { + "name": "state", + "in": "query", + "schema": { + "type": "string" + }, + "required": true + }, + { + "name": "grant_type", + "in": "query", + "schema": { + "type": "string" + }, + "required": true + }, + { + "name": "code_challenge", + "in": "query", + "schema": { + "type": "string" + }, + "required": true + }, + { + "name": "code_challenge_method", + "in": "query", + "schema": { + "type": "string" + }, + "required": true + }, + { + "name": "response_type", + "in": "query", + "schema": { + "type": "string" + }, + "required": true + }, + { + "name": "provider_id", + "in": "path", + "schema": { + "type": "string" + }, + "required": true + } + ], + "tags": [ + "Oauth" + ], + "x-full-url": "https://api.stack-auth.com/api/v1/auth/oauth/authorize/{provider_id}", + "responses": { + "200": { + "description": "Successful response", + "content": { + "application/json": { + "schema": { + "type": "object", + "properties": { + "location": { + "type": "string" + } + }, + "required": [ + "location" + ] + } + } + } + }, + "307": { + "description": "Successful response", + "content": { + "text/plain": { + "schema": { + "type": "string" + } + } + } + } + } + } + }, + "/auth/oauth/cross-domain/authorize": { + "post": { + "summary": "Create cross-domain auth handoff redirect", + "description": "Creates a one-time OAuth authorization code redirect for cross-domain sign-in handoff using PKCE.", + "parameters": [ + { + "name": "x-stack-publishable-client-key", + "in": "header", + "schema": { + "type": "string" + }, + "required": true + }, + { + "name": "x-stack-refresh-token", + "in": "header", + "schema": { + "type": "string" + }, + "required": true + } + ], + "requestBody": { + "required": true, + "content": { + "application/json": { + "schema": { + "type": "object", + "properties": { + "redirect_uri": { + "type": "string" + }, + "state": { + "type": "string" + }, + "code_challenge": { + "type": "string" + }, + "code_challenge_method": { + "type": "string", + "default": "S256" + }, + "after_callback_redirect_url": { + "type": "string" + } + }, + "required": [ + "redirect_uri", + "state", + "code_challenge" + ], + "example": {} + } + } + } + }, + "tags": [ + "Oauth" + ], + "x-full-url": "https://api.stack-auth.com/api/v1/auth/oauth/cross-domain/authorize", + "responses": { + "200": { + "description": "Successful response", + "content": { + "application/json": { + "schema": { + "type": "object", + "properties": { + "redirect_url": { + "type": "string" + } + }, + "required": [ + "redirect_url" + ] + } + } + } + } + } + } + }, + "/auth/oauth/token": { + "post": { + "summary": "OAuth token endpoints", + "description": "This endpoint is used to exchange an authorization code or refresh token for an access token.", + "parameters": [], + "requestBody": { + "required": true, + "content": { + "application/json": { + "schema": { + "type": "object", + "properties": { + "grant_type": { + "type": "string" + }, + "client_id": { + "type": "string" + }, + "client_secret": { + "type": "string" + } + }, + "required": [ + "grant_type" + ], + "example": {} + } + } + } + }, + "tags": [ + "Oauth" + ], + "x-full-url": "https://api.stack-auth.com/api/v1/auth/oauth/token", + "responses": { + "200": { + "description": "Successful response", + "content": { + "application/json": { + "schema": {} + } + } + } + } + } + }, + "/oauth-providers": { + "get": { + "summary": "List OAuth providers", + "description": "Retrieves a list of all OAuth providers for a user.", + "parameters": [ + { + "name": "user_id", + "in": "query", + "schema": { + "type": "string" + }, + "required": false + } + ], + "tags": [ + "Oauth" + ], + "x-full-url": "https://api.stack-auth.com/api/v1/oauth-providers", + "responses": { + "200": { + "description": "Successful response", + "content": { + "application/json": { + "schema": { + "type": "object", + "properties": { + "items": { + "type": "array", + "items": { + "type": "object", + "properties": { + "user_id": { + "type": "string", + "example": "3241a285-8329-4d69-8f3d-316e08cf140c", + "description": "The ID of the user, or the special value `me` for the currently authenticated user" + }, + "id": { + "type": "string", + "example": "b3d396b8-c574-4c80-97b3-50031675ceb2", + "description": "The unique identifier of the OAuth provider" + }, + "email": { + "type": "string", + "example": "test@gmail.com", + "description": "Email of the OAuth provider. This is used to display and identify the OAuth provider in the UI." + }, + "provider_config_id": { + "type": "string", + "example": "google", + "description": "Provider config ID of the OAuth provider. This uniquely identifies the provider config on config.json file" + }, + "type": { + "type": "string", + "example": "google", + "description": "OAuth provider type, one of `google`, `github`, `microsoft`, `spotify`, `facebook`, `discord`, `gitlab`, `bitbucket`, `linkedin`, `apple`, `x`, `twitch`" + }, + "allow_sign_in": { + "type": "boolean", + "example": true, + "description": "Whether the user can use this OAuth provider to sign in. Only one OAuth provider per type can have this set to `true`." + }, + "allow_connected_accounts": { + "type": "boolean", + "example": true, + "description": "Whether the user can use this OAuth provider as connected account. Multiple OAuth providers per type can have this set to `true`." + } + }, + "required": [ + "user_id", + "id", + "provider_config_id", + "type", + "allow_sign_in", + "allow_connected_accounts" + ] + } + }, + "pagination": { + "type": "object", + "properties": { + "next_cursor": { + "type": "string", + "example": "b3d396b8-c574-4c80-97b3-50031675ceb2", + "description": "The cursor to fetch the next page of results. null if there is no next page." + } + }, + "required": [] + } + }, + "required": [ + "items" + ] + } + } + } + } + } + } + }, + "/oauth-providers/{user_id}/{provider_id}": { + "get": { + "summary": "Get an OAuth provider", + "description": "Retrieves a specific OAuth provider by the user ID and the OAuth provider ID.", + "parameters": [ + { + "name": "provider_id", + "in": "path", + "schema": { + "type": "string" + }, + "required": true + }, + { + "name": "user_id", + "in": "path", + "schema": { + "type": "string", + "example": "3241a285-8329-4d69-8f3d-316e08cf140c", + "description": "The ID of the user, or the special value `me` for the currently authenticated user" + }, + "description": "The ID of the user, or the special value `me` for the currently authenticated user", + "required": true + } + ], + "tags": [ + "Oauth" + ], + "x-full-url": "https://api.stack-auth.com/api/v1/oauth-providers/{user_id}/{provider_id}", + "responses": { + "200": { + "description": "Successful response", + "content": { + "application/json": { + "schema": { + "type": "object", + "properties": { + "user_id": { + "type": "string", + "example": "3241a285-8329-4d69-8f3d-316e08cf140c", + "description": "The ID of the user, or the special value `me` for the currently authenticated user" + }, + "id": { + "type": "string", + "example": "b3d396b8-c574-4c80-97b3-50031675ceb2", + "description": "The unique identifier of the OAuth provider" + }, + "email": { + "type": "string", + "example": "test@gmail.com", + "description": "Email of the OAuth provider. This is used to display and identify the OAuth provider in the UI." + }, + "provider_config_id": { + "type": "string", + "example": "google", + "description": "Provider config ID of the OAuth provider. This uniquely identifies the provider config on config.json file" + }, + "type": { + "type": "string", + "example": "google", + "description": "OAuth provider type, one of `google`, `github`, `microsoft`, `spotify`, `facebook`, `discord`, `gitlab`, `bitbucket`, `linkedin`, `apple`, `x`, `twitch`" + }, + "allow_sign_in": { + "type": "boolean", + "example": true, + "description": "Whether the user can use this OAuth provider to sign in. Only one OAuth provider per type can have this set to `true`." + }, + "allow_connected_accounts": { + "type": "boolean", + "example": true, + "description": "Whether the user can use this OAuth provider as connected account. Multiple OAuth providers per type can have this set to `true`." + } + }, + "required": [ + "user_id", + "id", + "provider_config_id", + "type", + "allow_sign_in", + "allow_connected_accounts" + ] + } + } + } + } + } + }, + "delete": { + "summary": "Delete an OAuth provider", + "description": "Removes an OAuth provider for a given user.", + "parameters": [ + { + "name": "provider_id", + "in": "path", + "schema": { + "type": "string" + }, + "required": true + }, + { + "name": "user_id", + "in": "path", + "schema": { + "type": "string", + "example": "3241a285-8329-4d69-8f3d-316e08cf140c", + "description": "The ID of the user, or the special value `me` for the currently authenticated user" + }, + "description": "The ID of the user, or the special value `me` for the currently authenticated user", + "required": true + } + ], + "tags": [ + "Oauth" + ], + "x-full-url": "https://api.stack-auth.com/api/v1/oauth-providers/{user_id}/{provider_id}", + "responses": { + "200": { + "description": "Successful response", + "content": { + "application/json": { + "schema": { + "type": "object", + "properties": { + "success": { + "type": "boolean", + "description": "Always equal to true.", + "example": true + } + }, + "required": [ + "success" + ] + } + } + } + } + } + }, + "patch": { + "summary": "Update an OAuth provider", + "description": "Updates an existing OAuth provider for a user.", + "parameters": [ + { + "name": "provider_id", + "in": "path", + "schema": { + "type": "string" + }, + "required": true + }, + { + "name": "user_id", + "in": "path", + "schema": { + "type": "string", + "example": "3241a285-8329-4d69-8f3d-316e08cf140c", + "description": "The ID of the user, or the special value `me` for the currently authenticated user" + }, + "description": "The ID of the user, or the special value `me` for the currently authenticated user", + "required": true + } + ], + "requestBody": { + "required": true, + "content": { + "application/json": { + "schema": { + "type": "object", + "properties": { + "allow_sign_in": { + "type": "boolean", + "example": true, + "description": "Whether the user can use this OAuth provider to sign in. Only one OAuth provider per type can have this set to `true`." + }, + "allow_connected_accounts": { + "type": "boolean", + "example": true, + "description": "Whether the user can use this OAuth provider as connected account. Multiple OAuth providers per type can have this set to `true`." + } + }, + "example": { + "allow_sign_in": true, + "allow_connected_accounts": true + } + } + } + } + }, + "tags": [ + "Oauth" + ], + "x-full-url": "https://api.stack-auth.com/api/v1/oauth-providers/{user_id}/{provider_id}", + "responses": { + "200": { + "description": "Successful response", + "content": { + "application/json": { + "schema": { + "type": "object", + "properties": { + "user_id": { + "type": "string", + "example": "3241a285-8329-4d69-8f3d-316e08cf140c", + "description": "The ID of the user, or the special value `me` for the currently authenticated user" + }, + "id": { + "type": "string", + "example": "b3d396b8-c574-4c80-97b3-50031675ceb2", + "description": "The unique identifier of the OAuth provider" + }, + "email": { + "type": "string", + "example": "test@gmail.com", + "description": "Email of the OAuth provider. This is used to display and identify the OAuth provider in the UI." + }, + "provider_config_id": { + "type": "string", + "example": "google", + "description": "Provider config ID of the OAuth provider. This uniquely identifies the provider config on config.json file" + }, + "type": { + "type": "string", + "example": "google", + "description": "OAuth provider type, one of `google`, `github`, `microsoft`, `spotify`, `facebook`, `discord`, `gitlab`, `bitbucket`, `linkedin`, `apple`, `x`, `twitch`" + }, + "allow_sign_in": { + "type": "boolean", + "example": true, + "description": "Whether the user can use this OAuth provider to sign in. Only one OAuth provider per type can have this set to `true`." + }, + "allow_connected_accounts": { + "type": "boolean", + "example": true, + "description": "Whether the user can use this OAuth provider as connected account. Multiple OAuth providers per type can have this set to `true`." + } + }, + "required": [ + "user_id", + "id", + "provider_config_id", + "type", + "allow_sign_in", + "allow_connected_accounts" + ] + } + } + } + } + } + } + }, + "/internal/ai-conversations": { + "get": { + "summary": "List AI conversations", + "description": "List AI conversations for the current user filtered by project", + "parameters": [ + { + "name": "projectId", + "in": "query", + "schema": { + "type": "string" + }, + "required": true + } + ], + "tags": [ + "Others" + ], + "x-full-url": "https://api.stack-auth.com/api/v1/internal/ai-conversations", + "responses": { + "200": { + "description": "Successful response", + "content": { + "application/json": { + "schema": { + "type": "object", + "properties": { + "conversations": { + "type": "array", + "items": { + "type": "object", + "properties": { + "id": { + "type": "string" + }, + "title": { + "type": "string" + }, + "projectId": { + "type": "string" + }, + "updatedAt": { + "type": "string" + } + }, + "required": [ + "id", + "title", + "projectId", + "updatedAt" + ] + } + } + }, + "required": [ + "conversations" + ] + } + } + } + } + } + }, + "post": { + "summary": "Create AI conversation", + "description": "Create a new AI conversation with optional initial messages", + "parameters": [], + "requestBody": { + "required": true, + "content": { + "application/json": { + "schema": { + "type": "object", + "properties": { + "title": { + "type": "string" + }, + "projectId": { + "type": "string" + }, + "messages": { + "type": "array", + "items": { + "type": "object", + "properties": { + "role": { + "type": "string" + }, + "content": { + "type": "object" + } + }, + "required": [ + "role", + "content" + ] + } + } + }, + "required": [ + "title", + "projectId", + "messages" + ], + "example": {} + } + } + } + }, + "tags": [ + "Others" + ], + "x-full-url": "https://api.stack-auth.com/api/v1/internal/ai-conversations", + "responses": { + "200": { + "description": "Successful response", + "content": { + "application/json": { + "schema": { + "type": "object", + "properties": { + "id": { + "type": "string" + }, + "title": { + "type": "string" + } + }, + "required": [ + "id", + "title" + ] + } + } + } + } + } + } + }, + "/internal/ai-conversations/{conversationId}": { + "get": { + "summary": "Get AI conversation", + "description": "Fetch a single AI conversation with all its messages", + "parameters": [ + { + "name": "conversationId", + "in": "path", + "schema": { + "type": "string" + }, + "required": true + } + ], + "tags": [ + "Others" + ], + "x-full-url": "https://api.stack-auth.com/api/v1/internal/ai-conversations/{conversationId}", + "responses": { + "200": { + "description": "Successful response", + "content": { + "application/json": { + "schema": { + "type": "object", + "properties": { + "id": { + "type": "string" + }, + "title": { + "type": "string" + }, + "projectId": { + "type": "string" + }, + "messages": { + "type": "array", + "items": { + "type": "object", + "properties": { + "id": { + "type": "string" + }, + "role": { + "type": "string" + }, + "content": { + "type": "object" + } + }, + "required": [ + "id", + "role", + "content" + ] + } + } + }, + "required": [ + "id", + "title", + "projectId", + "messages" + ] + } + } + } + } + } + }, + "delete": { + "summary": "Delete AI conversation", + "description": "Delete an AI conversation and all its messages", + "parameters": [ + { + "name": "conversationId", + "in": "path", + "schema": { + "type": "string" + }, + "required": true + } + ], + "tags": [ + "Others" + ], + "x-full-url": "https://api.stack-auth.com/api/v1/internal/ai-conversations/{conversationId}", + "responses": { + "200": { + "description": "Successful response", + "content": { + "application/json": { + "schema": { + "type": "object", + "properties": {} + } + } + } + } + } + }, + "patch": { + "summary": "Update AI conversation", + "description": "Update the title of an AI conversation", + "parameters": [ + { + "name": "conversationId", + "in": "path", + "schema": { + "type": "string" + }, + "required": true + } + ], + "requestBody": { + "required": true, + "content": { + "application/json": { + "schema": { + "type": "object", + "properties": { + "title": { + "type": "string" + } + }, + "required": [ + "title" + ], + "example": {} + } + } + } + }, + "tags": [ + "Others" + ], + "x-full-url": "https://api.stack-auth.com/api/v1/internal/ai-conversations/{conversationId}", + "responses": { + "200": { + "description": "Successful response", + "content": { + "application/json": { + "schema": { + "type": "object", + "properties": {} + } + } + } + } + } + } + }, + "/internal/ai-conversations/{conversationId}/messages": { + "put": { + "summary": "Replace conversation messages", + "description": "Replace all messages in a conversation", + "parameters": [ + { + "name": "conversationId", + "in": "path", + "schema": { + "type": "string" + }, + "required": true + } + ], + "requestBody": { + "required": true, + "content": { + "application/json": { + "schema": { + "type": "object", + "properties": { + "messages": { + "type": "array", + "items": { + "type": "object", + "properties": { + "role": { + "type": "string" + }, + "content": { + "type": "object" + } + }, + "required": [ + "role", + "content" + ] + } + } + }, + "required": [ + "messages" + ], + "example": {} + } + } + } + }, + "tags": [ + "Others" + ], + "x-full-url": "https://api.stack-auth.com/api/v1/internal/ai-conversations/{conversationId}/messages", + "responses": { + "200": { + "description": "Successful response", + "content": { + "application/json": { + "schema": { + "type": "object", + "properties": {} + } + } + } + } + } + } + }, + "/auth/mfa/sign-in": { + "post": { + "summary": "MFA sign in", + "description": "Complete multi-factor authorization to sign in, with a TOTP and an MFA attempt code", + "parameters": [], + "requestBody": { + "required": true, + "content": { + "application/json": { + "schema": { + "type": "object", + "properties": { + "type": { + "type": "string" + }, + "totp": { + "type": "string" + }, + "code": { + "type": "string", + "example": "u3h6gn4w24pqc8ya679inrhjwh1rybth6a7thurqhnpf2", + "description": "A 45 character code" + } + }, + "required": [ + "type", + "totp", + "code" + ], + "example": { + "code": "u3h6gn4w24pqc8ya679inrhjwh1rybth6a7thurqhnpf2" + } + } + } + } + }, + "tags": [ + "OTP" + ], + "x-full-url": "https://api.stack-auth.com/api/v1/auth/mfa/sign-in", + "responses": { + "200": { + "description": "Successful response", + "content": { + "application/json": { + "schema": { + "type": "object", + "properties": { + "refresh_token": { + "type": "string", + "example": "i8ns3aq2...14y", + "description": "Long-lived refresh token that can be used to obtain a new access token" + }, + "access_token": { + "type": "string", + "example": "eyJhmMiJB2TO...diI4QT", + "description": "Short-lived access token that can be used to authenticate the user" + }, + "is_new_user": { + "type": "boolean", + "example": true, + "description": "Whether the user is a new user" + }, + "user_id": { + "type": "string", + "example": "3241a285-8329-4d69-8f3d-316e08cf140c", + "description": "The unique identifier of the user" + } + }, + "required": [ + "refresh_token", + "access_token", + "is_new_user", + "user_id" + ] + } + } + } + } + } + } + }, + "/auth/otp/send-sign-in-code": { + "post": { + "summary": "Send sign-in code", + "description": "Send a code to the user's email address for sign-in.", + "parameters": [], + "requestBody": { + "required": true, + "content": { + "application/json": { + "schema": { + "type": "object", + "properties": { + "email": { + "type": "string", + "example": "johndoe@example.com", + "description": "The email to sign in with." + }, + "callback_url": { + "type": "string", + "example": "https://example.com/handler/magic-link-callback", + "description": "The base callback URL to construct the magic link from. A query parameter `code` with the verification code will be appended to it. The page should then make a request to the `/auth/otp/sign-in` endpoint." + }, + "bot_challenge_token": { + "type": "string" + }, + "bot_challenge_phase": { + "type": "string" + }, + "bot_challenge_unavailable": { + "type": "string" + } + }, + "required": [ + "email", + "callback_url" + ], + "example": { + "email": "johndoe@example.com", + "callback_url": "https://example.com/handler/magic-link-callback" + } + } + } + } + }, + "tags": [ + "OTP" + ], + "x-full-url": "https://api.stack-auth.com/api/v1/auth/otp/send-sign-in-code", + "responses": { + "200": { + "description": "Successful response", + "content": { + "application/json": { + "schema": { + "type": "object", + "properties": { + "nonce": { + "type": "string", + "example": "u3h6gn4w24pqc8ya679inrhjwh1rybth6a7thurqhnpf2", + "description": "A token that must be stored temporarily and provided when verifying the 6-digit code" + } + }, + "required": [ + "nonce" + ] + } + } + } + } + } + } + }, + "/auth/otp/sign-in": { + "post": { + "summary": "Sign in with a code", + "description": "", + "parameters": [], + "requestBody": { + "required": true, + "content": { + "application/json": { + "schema": { + "type": "object", + "properties": { + "code": { + "type": "string", + "example": "u3h6gn4w24pqc8ya679inrhjwh1rybth6a7thurqhnpf2", + "description": "A 45-character verification code. For magic links, this is the code found in the \"code\" URL query parameter. For OTP, this is formed by concatenating the 6-digit code entered by the user with the nonce (received during code creation)" + } + }, + "required": [ + "code" + ], + "example": { + "code": "u3h6gn4w24pqc8ya679inrhjwh1rybth6a7thurqhnpf2" + } + } + } + } + }, + "tags": [ + "OTP" + ], + "x-full-url": "https://api.stack-auth.com/api/v1/auth/otp/sign-in", + "responses": { + "200": { + "description": "Successful response", + "content": { + "application/json": { + "schema": { + "type": "object", + "properties": { + "refresh_token": { + "type": "string", + "example": "i8ns3aq2...14y", + "description": "Long-lived refresh token that can be used to obtain a new access token" + }, + "access_token": { + "type": "string", + "example": "eyJhmMiJB2TO...diI4QT", + "description": "Short-lived access token that can be used to authenticate the user" + }, + "is_new_user": { + "type": "boolean", + "example": true, + "description": "Whether the user is a new user" + }, + "user_id": { + "type": "string", + "example": "3241a285-8329-4d69-8f3d-316e08cf140c", + "description": "The unique identifier of the user" + } + }, + "required": [ + "refresh_token", + "access_token", + "is_new_user", + "user_id" + ] + } + } + } + } + } + } + }, + "/auth/otp/sign-in/check-code": { + "post": { + "summary": "Check sign in code", + "description": "Check if a sign in code is valid without using it", + "parameters": [], + "requestBody": { + "required": true, + "content": { + "application/json": { + "schema": { + "type": "object", + "properties": { + "code": { + "type": "string", + "example": "u3h6gn4w24pqc8ya679inrhjwh1rybth6a7thurqhnpf2", + "description": "A 45-character verification code. For magic links, this is the code found in the \"code\" URL query parameter. For OTP, this is formed by concatenating the 6-digit code entered by the user with the nonce (received during code creation)" + } + }, + "required": [ + "code" + ], + "example": { + "code": "u3h6gn4w24pqc8ya679inrhjwh1rybth6a7thurqhnpf2" + } + } + } + } + }, + "tags": [ + "OTP" + ], + "x-full-url": "https://api.stack-auth.com/api/v1/auth/otp/sign-in/check-code", + "responses": { + "200": { + "description": "Successful response", + "content": { + "application/json": { + "schema": { + "type": "object", + "properties": { + "is_code_valid": { + "type": "boolean" + } + }, + "required": [ + "is_code_valid" + ] + } + } + } + } + } + } + }, + "/auth/password/reset": { + "post": { + "summary": "Reset password with a code", + "description": "Reset password with a code", + "parameters": [], + "requestBody": { + "required": true, + "content": { + "application/json": { + "schema": { + "type": "object", + "properties": { + "password": { + "type": "string" + }, + "code": { + "type": "string", + "example": "u3h6gn4w24pqc8ya679inrhjwh1rybth6a7thurqhnpf2", + "description": "A 45 character code" + } + }, + "required": [ + "password", + "code" + ], + "example": { + "code": "u3h6gn4w24pqc8ya679inrhjwh1rybth6a7thurqhnpf2" + } + } + } + } + }, + "tags": [ + "Password" + ], + "x-full-url": "https://api.stack-auth.com/api/v1/auth/password/reset", + "responses": { + "200": { + "description": "Successful response", + "content": { + "application/json": { + "schema": { + "type": "object", + "properties": { + "success": { + "type": "boolean", + "description": "Always equal to true.", + "example": true + } + }, + "required": [ + "success" + ] + } + } + } + } + } + } + }, + "/auth/password/reset/check-code": { + "post": { + "summary": "Check reset password code", + "description": "Check if a reset password code is valid without using it", + "parameters": [], + "requestBody": { + "required": true, + "content": { + "application/json": { + "schema": { + "type": "object", + "properties": { + "code": { + "type": "string", + "example": "u3h6gn4w24pqc8ya679inrhjwh1rybth6a7thurqhnpf2", + "description": "A 45 character code" + } + }, + "required": [ + "code" + ], + "example": { + "code": "u3h6gn4w24pqc8ya679inrhjwh1rybth6a7thurqhnpf2" + } + } + } + } + }, + "tags": [ + "Password" + ], + "x-full-url": "https://api.stack-auth.com/api/v1/auth/password/reset/check-code", + "responses": { + "200": { + "description": "Successful response", + "content": { + "application/json": { + "schema": { + "type": "object", + "properties": { + "is_code_valid": { + "type": "boolean" + } + }, + "required": [ + "is_code_valid" + ] + } + } + } + } + } + } + }, + "/auth/password/send-reset-code": { + "post": { + "summary": "Send reset password code", + "description": "Send a code to the user's email address for resetting the password.", + "parameters": [], + "requestBody": { + "required": true, + "content": { + "application/json": { + "schema": { + "type": "object", + "properties": { + "email": { + "type": "string" + }, + "callback_url": { + "type": "string" + } + }, + "required": [ + "email", + "callback_url" + ], + "example": {} + } + } + } + }, + "tags": [ + "Password" + ], + "x-full-url": "https://api.stack-auth.com/api/v1/auth/password/send-reset-code", + "responses": { + "200": { + "description": "Successful response", + "content": { + "application/json": { + "schema": { + "type": "object", + "properties": { + "success": { + "type": "string" + } + }, + "required": [ + "success" + ] + } + } + } + } + } + } + }, + "/auth/password/set": { + "post": { + "summary": "Set password", + "description": "Set a new password for the current user", + "parameters": [], + "requestBody": { + "required": true, + "content": { + "application/json": { + "schema": { + "type": "object", + "properties": { + "password": { + "type": "string" + } + }, + "required": [ + "password" + ], + "example": {} + } + } + } + }, + "tags": [ + "Password" + ], + "x-full-url": "https://api.stack-auth.com/api/v1/auth/password/set", + "responses": { + "200": { + "description": "Successful response", + "content": { + "application/json": { + "schema": { + "type": "object", + "properties": { + "success": { + "type": "boolean", + "description": "Always equal to true.", + "example": true + } + }, + "required": [ + "success" + ] + } + } + } + } + } + } + }, + "/auth/password/sign-in": { + "post": { + "summary": "Sign in with email and password", + "description": "Sign in to an account with email and password", + "parameters": [], + "requestBody": { + "required": true, + "content": { + "application/json": { + "schema": { + "type": "object", + "properties": { + "email": { + "type": "string" + }, + "password": { + "type": "string" + } + }, + "required": [ + "email", + "password" + ], + "example": {} + } + } + } + }, + "tags": [ + "Password" + ], + "x-full-url": "https://api.stack-auth.com/api/v1/auth/password/sign-in", + "responses": { + "200": { + "description": "Successful response", + "content": { + "application/json": { + "schema": { + "type": "object", + "properties": { + "access_token": { + "type": "string" + }, + "refresh_token": { + "type": "string" + }, + "user_id": { + "type": "string" + } + }, + "required": [ + "access_token", + "refresh_token", + "user_id" + ] + } + } + } + } + } + } + }, + "/auth/password/sign-up": { + "post": { + "summary": "Sign up with email and password", + "description": "Create a new account with email and password", + "parameters": [], + "requestBody": { + "required": true, + "content": { + "application/json": { + "schema": { + "type": "object", + "properties": { + "email": { + "type": "string", + "example": "johndoe@example.com", + "description": "The email to sign in with." + }, + "password": { + "type": "string" + }, + "verification_callback_url": { + "type": "string", + "example": "https://example.com/handler/email-verification", + "description": "The base callback URL to construct a verification link for the verification e-mail. A query parameter `code` with the verification code will be appended to it. The page should then make a request to the `/contact-channels/verify` endpoint." + }, + "bot_challenge_token": { + "type": "string" + }, + "bot_challenge_phase": { + "type": "string" + }, + "bot_challenge_unavailable": { + "type": "string" + } + }, + "required": [ + "email", + "password" + ], + "example": { + "email": "johndoe@example.com", + "verification_callback_url": "https://example.com/handler/email-verification" + } + } + } + } + }, + "tags": [ + "Password" + ], + "x-full-url": "https://api.stack-auth.com/api/v1/auth/password/sign-up", + "responses": { + "200": { + "description": "Successful response", + "content": { + "application/json": { + "schema": { + "type": "object", + "properties": { + "access_token": { + "type": "string" + }, + "refresh_token": { + "type": "string" + }, + "user_id": { + "type": "string" + } + }, + "required": [ + "access_token", + "refresh_token", + "user_id" + ] + } + } + } + } + } + } + }, + "/auth/password/update": { + "post": { + "summary": "Update password", + "description": "Update the password of the current user, requires the old password", + "parameters": [ + { + "name": "x-stack-refresh-token", + "in": "header", + "schema": { + "type": "string" + }, + "required": false + } + ], + "requestBody": { + "required": true, + "content": { + "application/json": { + "schema": { + "type": "object", + "properties": { + "old_password": { + "type": "string" + }, + "new_password": { + "type": "string" + } + }, + "required": [ + "old_password", + "new_password" + ], + "example": {} + } + } + } + }, + "tags": [ + "Password" + ], + "x-full-url": "https://api.stack-auth.com/api/v1/auth/password/update", + "responses": { + "200": { + "description": "Successful response", + "content": { + "application/json": { + "schema": { + "type": "object", + "properties": { + "success": { + "type": "boolean", + "description": "Always equal to true.", + "example": true + } + }, + "required": [ + "success" + ] + } + } + } + } + } + } + }, + "/payments/items/{customer_type}/{customer_id}/{item_id}": { + "get": { + "summary": "Get Item", + "description": "Retrieves information about a specific item (credits, quotas, etc.) for a customer.", + "parameters": [ + { + "name": "customer_type", + "in": "path", + "schema": { + "type": "string", + "example": "user", + "description": "The type of customer" + }, + "description": "The type of customer", + "required": true + }, + { + "name": "customer_id", + "in": "path", + "schema": { + "type": "string", + "example": "user_1234567890abcdef", + "description": "The ID of the customer" + }, + "description": "The ID of the customer", + "required": true + }, + { + "name": "item_id", + "in": "path", + "schema": { + "type": "string", + "example": "credits", + "description": "The ID of the item to retrieve" + }, + "description": "The ID of the item to retrieve", + "required": true + } + ], + "tags": [ + "Payments" + ], + "x-full-url": "https://api.stack-auth.com/api/v1/payments/items/{customer_type}/{customer_id}/{item_id}", + "responses": { + "200": { + "description": "Successful response", + "content": { + "application/json": { + "schema": { + "type": "object", + "properties": { + "id": { + "type": "string", + "example": "credits", + "description": "The ID of the item" + }, + "display_name": { + "type": "string", + "example": "API Credits", + "description": "The human-readable name of the item" + }, + "quantity": { + "type": "number", + "example": 1000, + "description": "The current quantity of the item (can be negative)" + } + }, + "required": [ + "id", + "display_name", + "quantity" + ] + } + } + } + } + } + } + }, + "/payments/purchases/create-purchase-url": { + "post": { + "summary": "Create Purchase URL", + "description": "Creates a secure checkout URL for purchasing a product.", + "parameters": [], + "requestBody": { + "required": true, + "content": { + "application/json": { + "schema": { + "type": "object", + "properties": { + "customer_type": { + "type": "string", + "example": "user", + "description": "The type of customer making the purchase" + }, + "customer_id": { + "type": "string", + "example": "user_1234567890abcdef", + "description": "The ID of the customer (user ID, team ID, or custom customer ID)" + }, + "product_id": { + "type": "string", + "example": "prod_premium_monthly", + "description": "The ID of the product to purchase. Either this or product_inline should be given." + }, + "product_inline": { + "type": "object", + "properties": { + "display_name": { + "type": "string" + }, + "customer_type": { + "type": "string" + }, + "free_trial": { + "type": "array", + "items": { + "type": "number" + } + }, + "server_only": { + "type": "boolean", + "default": true + }, + "stackable": { + "type": "boolean", + "default": false + }, + "prices": { + "type": "object", + "properties": {}, + "required": [] + }, + "included_items": { + "type": "object", + "properties": {}, + "required": [] + }, + "client_metadata": { + "type": "object", + "example": { + "featureFlag": true, + "source": "marketing-campaign" + }, + "description": "Client metadata. Used as a data store, accessible from the client side. Do not store information that should not be exposed to the client." + }, + "client_read_only_metadata": { + "type": "object", + "example": { + "featureFlag": true, + "source": "marketing-campaign" + }, + "description": "Client read-only, server-writable metadata. Used as a data store, accessible from the client side. Do not store information that should not be exposed to the client. The client can read this data, but cannot modify it. This is useful for things like subscription status." + }, + "server_metadata": { + "type": "object", + "example": { + "featureFlag": true, + "source": "marketing-campaign" + }, + "description": "Server metadata. Used as a data store, only accessible from the server side. You can store secret information related to the product here." + } + }, + "required": [ + "display_name", + "customer_type" + ], + "description": "Inline product definition. Either this or product_id should be given." + }, + "return_url": { + "type": "string", + "example": "https://myapp.com/purchase-success", + "description": "URL to redirect to after purchase completion. Must be configured as a trusted domain in the project configuration." + } + }, + "required": [ + "customer_type", + "customer_id" + ], + "example": { + "customer_type": "user", + "customer_id": "user_1234567890abcdef", + "product_id": "prod_premium_monthly", + "return_url": "https://myapp.com/purchase-success" + } + } + } + } + }, + "tags": [ + "Payments" + ], + "x-full-url": "https://api.stack-auth.com/api/v1/payments/purchases/create-purchase-url", + "responses": { + "200": { + "description": "Successful response", + "content": { + "application/json": { + "schema": { + "type": "object", + "properties": { + "url": { + "type": "string", + "description": "The secure checkout URL for completing the purchase" + } + }, + "required": [ + "url" + ] + } + } + } + } + } + } + }, + "/payments/purchases/purchase-session": { + "post": { + "summary": "Create Purchase Session", + "description": "Creates a purchase session for completing a purchase.", + "parameters": [], + "requestBody": { + "required": true, + "content": { + "application/json": { + "schema": { + "type": "object", + "properties": { + "full_code": { + "type": "string", + "example": "proj_abc123_def456ghi789", + "description": "The verification code, given as a query parameter in the purchase URL" + }, + "price_id": { + "type": "string", + "example": "price_1234567890abcdef", + "description": "The Stack auth price ID to purchase" + }, + "quantity": { + "type": "number", + "example": 1, + "description": "The quantity to purchase", + "default": 1 + } + }, + "required": [ + "full_code", + "price_id" + ], + "example": { + "full_code": "proj_abc123_def456ghi789", + "price_id": "price_1234567890abcdef", + "quantity": 1 + } + } + } + } + }, + "tags": [ + "Payments" + ], + "x-full-url": "https://api.stack-auth.com/api/v1/payments/purchases/purchase-session", + "responses": { + "200": { + "description": "Successful response", + "content": { + "application/json": { + "schema": { + "type": "object", + "properties": { + "client_secret": { + "type": "string", + "example": "1234567890abcdef_secret_xyz123", + "description": "The Stripe client secret for completing the payment" + } + }, + "required": [ + "client_secret" + ] + } + } + } + } + } + } + }, + "/payments/purchases/validate-code": { + "post": { + "summary": "Validate Purchase Code", + "description": "Validates a purchase verification code and returns purchase details including available prices.", + "parameters": [], + "requestBody": { + "required": true, + "content": { + "application/json": { + "schema": { + "type": "object", + "properties": { + "full_code": { + "type": "string", + "example": "proj_abc123_def456ghi789", + "description": "The verification code, given as a query parameter in the purchase URL" + }, + "return_url": { + "type": "string", + "example": "https://myapp.com/purchase-success", + "description": "URL to redirect to after purchase completion" + } + }, + "required": [ + "full_code" + ], + "example": { + "full_code": "proj_abc123_def456ghi789", + "return_url": "https://myapp.com/purchase-success" + } + } + } + } + }, + "tags": [ + "Payments" + ], + "x-full-url": "https://api.stack-auth.com/api/v1/payments/purchases/validate-code", + "responses": { + "200": { + "description": "Successful response", + "content": { + "application/json": { + "schema": { + "type": "object", + "properties": { + "product": { + "type": "object", + "properties": { + "display_name": { + "type": "string" + }, + "customer_type": { + "type": "string" + }, + "free_trial": { + "type": "array", + "items": { + "type": "number" + } + }, + "server_only": { + "type": "boolean", + "default": true + }, + "stackable": { + "type": "boolean", + "default": false + }, + "prices": { + "type": "object", + "properties": {}, + "required": [] + }, + "included_items": { + "type": "object", + "properties": {}, + "required": [] + }, + "client_metadata": { + "type": "object", + "example": { + "featureFlag": true, + "source": "marketing-campaign" + }, + "description": "Client metadata. Used as a data store, accessible from the client side. Do not store information that should not be exposed to the client." + }, + "client_read_only_metadata": { + "type": "object", + "example": { + "featureFlag": true, + "source": "marketing-campaign" + }, + "description": "Client read-only, server-writable metadata. Used as a data store, accessible from the client side. Do not store information that should not be exposed to the client. The client can read this data, but cannot modify it. This is useful for things like subscription status." + }, + "server_metadata": { + "type": "object", + "example": { + "featureFlag": true, + "source": "marketing-campaign" + }, + "description": "Server metadata. Used as a data store, only accessible from the server side. You can store secret information related to the product here." + } + }, + "required": [ + "display_name", + "customer_type" + ] + }, + "stripe_account_id": { + "type": "string" + }, + "project_id": { + "type": "string" + }, + "project_logo_url": { + "type": "string" + }, + "already_bought_non_stackable": { + "type": "boolean" + }, + "conflicting_products": { + "type": "array", + "items": { + "type": "object", + "properties": { + "product_id": { + "type": "string" + }, + "display_name": { + "type": "string" + } + }, + "required": [ + "product_id", + "display_name" + ] + } + }, + "test_mode": { + "type": "boolean" + }, + "charges_enabled": { + "type": "boolean" + } + }, + "required": [ + "stripe_account_id", + "project_id", + "already_bought_non_stackable", + "conflicting_products", + "test_mode", + "charges_enabled" + ] + } + } + } + } + } + } + }, + "/project-permissions": { + "get": { + "summary": "List project permissions", + "description": "List global permissions of the current user. `user_id=me` must be set for client requests. `(user_id, permission_id)` together uniquely identify a permission.", + "parameters": [ + { + "name": "user_id", + "in": "query", + "schema": { + "type": "string", + "example": "me", + "description": "Filter with the user ID. If set, only the permissions this user has will be returned. Client request must set `user_id=me`" + }, + "description": "Filter with the user ID. If set, only the permissions this user has will be returned. Client request must set `user_id=me`", + "required": false + }, + { + "name": "permission_id", + "in": "query", + "schema": { + "type": "string", + "example": "16399452-c4f3-4554-8e44-c2d67bb60360", + "description": "Filter with the permission ID. If set, only the permissions with this specific ID will be returned" + }, + "description": "Filter with the permission ID. If set, only the permissions with this specific ID will be returned", + "required": false + }, + { + "name": "recursive", + "in": "query", + "schema": { + "type": "string", + "example": "true", + "description": "Whether to list permissions recursively. If set to `false`, only the permission the users directly have will be listed. If set to `true` all the direct and indirect permissions will be listed." + }, + "description": "Whether to list permissions recursively. If set to `false`, only the permission the users directly have will be listed. If set to `true` all the direct and indirect permissions will be listed.", + "required": false + } + ], + "tags": [ + "Permissions" + ], + "x-full-url": "https://api.stack-auth.com/api/v1/project-permissions", + "responses": { + "200": { + "description": "Successful response", + "content": { + "application/json": { + "schema": { + "type": "object", + "properties": { + "items": { + "type": "array", + "items": { + "type": "object", + "properties": { + "id": { + "type": "string", + "example": "read_secret_info", + "description": "The permission ID used to uniquely identify a permission. Can either be a custom permission with lowercase letters, numbers, `:`, and `_` characters, or one of the system permissions: `$update_team`, `$delete_team`, `$read_members`, `$remove_members`, `$invite_members`, `$manage_api_keys`" + }, + "user_id": { + "type": "string", + "example": "3241a285-8329-4d69-8f3d-316e08cf140c", + "description": "The unique identifier of the user" + } + }, + "required": [ + "id", + "user_id" + ] + } + }, + "pagination": { + "type": "object", + "properties": { + "next_cursor": { + "type": "string", + "example": "b3d396b8-c574-4c80-97b3-50031675ceb2", + "description": "The cursor to fetch the next page of results. null if there is no next page." + } + }, + "required": [] + } + }, + "required": [ + "items" + ] + } + } + } + } + } + } + }, + "/team-permissions": { + "get": { + "summary": "List team permissions", + "description": "List team permissions of the current user. `user_id=me` must be set for client requests. Note that this might contain the permissions with the same permission ID across different teams. `(team_id, user_id, permission_id)` together uniquely identify a permission.", + "parameters": [ + { + "name": "team_id", + "in": "query", + "schema": { + "type": "string", + "example": "cce084a3-28b7-418e-913e-c8ee6d802ea4", + "description": "Filter with the team ID. If set, only the permissions of the members in a specific team will be returned." + }, + "description": "Filter with the team ID. If set, only the permissions of the members in a specific team will be returned.", + "required": false + }, + { + "name": "user_id", + "in": "query", + "schema": { + "type": "string", + "example": "me", + "description": "Filter with the user ID. If set, only the permissions this user has will be returned. Client request must set `user_id=me`" + }, + "description": "Filter with the user ID. If set, only the permissions this user has will be returned. Client request must set `user_id=me`", + "required": false + }, + { + "name": "permission_id", + "in": "query", + "schema": { + "type": "string", + "example": "16399452-c4f3-4554-8e44-c2d67bb60360", + "description": "Filter with the permission ID. If set, only the permissions with this specific ID will be returned" + }, + "description": "Filter with the permission ID. If set, only the permissions with this specific ID will be returned", + "required": false + }, + { + "name": "recursive", + "in": "query", + "schema": { + "type": "string", + "example": "true", + "description": "Whether to list permissions recursively. If set to `false`, only the permission the users directly have will be listed. If set to `true` all the direct and indirect permissions will be listed." + }, + "description": "Whether to list permissions recursively. If set to `false`, only the permission the users directly have will be listed. If set to `true` all the direct and indirect permissions will be listed.", + "required": false + } + ], + "tags": [ + "Permissions" + ], + "x-full-url": "https://api.stack-auth.com/api/v1/team-permissions", + "responses": { + "200": { + "description": "Successful response", + "content": { + "application/json": { + "schema": { + "type": "object", + "properties": { + "items": { + "type": "array", + "items": { + "type": "object", + "properties": { + "id": { + "type": "string", + "example": "read_secret_info", + "description": "The permission ID used to uniquely identify a permission. Can either be a custom permission with lowercase letters, numbers, `:`, and `_` characters, or one of the system permissions: `$update_team`, `$delete_team`, `$read_members`, `$remove_members`, `$invite_members`, `$manage_api_keys`" + }, + "user_id": { + "type": "string", + "example": "3241a285-8329-4d69-8f3d-316e08cf140c", + "description": "The unique identifier of the user" + }, + "team_id": { + "type": "string", + "example": "ad962777-8244-496a-b6a2-e0c6a449c79e", + "description": "The unique identifier of the team" + } + }, + "required": [ + "id", + "user_id", + "team_id" + ] + } + }, + "pagination": { + "type": "object", + "properties": { + "next_cursor": { + "type": "string", + "example": "b3d396b8-c574-4c80-97b3-50031675ceb2", + "description": "The cursor to fetch the next page of results. null if there is no next page." + } + }, + "required": [] + } + }, + "required": [ + "items" + ] + } + } + } + } + } + } + }, + "/projects/current": { + "get": { + "summary": "Get the current project", + "description": "Get the current project information including display name, OAuth providers and authentication methods. Useful for displaying the available login options to the user.", + "parameters": [], + "tags": [ + "Projects" + ], + "x-full-url": "https://api.stack-auth.com/api/v1/projects/current", + "responses": { + "200": { + "description": "Successful response", + "content": { + "application/json": { + "schema": { + "type": "object", + "properties": { + "id": { + "type": "string", + "example": "e0b52f4d-dece-408c-af49-d23061bb0f8d", + "description": "The unique identifier of the project" + }, + "display_name": { + "type": "string", + "example": "MyMusic", + "description": "Human-readable project display name. This is not a unique identifier." + } + }, + "required": [ + "id", + "display_name" + ] + } + } + } + } + } + } + }, + "/auth/sessions": { + "get": { + "summary": "List sessions", + "description": "List all sessions for the current user.", + "parameters": [ + { + "name": "user_id", + "in": "query", + "schema": { + "type": "string", + "example": "3241a285-8329-4d69-8f3d-316e08cf140c", + "description": "The ID of the user, or the special value `me` for the currently authenticated user" + }, + "description": "The ID of the user, or the special value `me` for the currently authenticated user", + "required": true + } + ], + "tags": [ + "Sessions" + ], + "x-full-url": "https://api.stack-auth.com/api/v1/auth/sessions", + "responses": { + "200": { + "description": "Successful response", + "content": { + "application/json": { + "schema": { + "type": "object", + "properties": { + "items": { + "type": "array", + "items": { + "type": "object", + "properties": { + "id": { + "type": "string" + }, + "user_id": { + "type": "string" + }, + "created_at": { + "type": "number" + }, + "is_impersonation": { + "type": "boolean" + }, + "last_used_at": { + "type": "number" + }, + "is_current_session": { + "type": "boolean" + }, + "last_used_at_end_user_ip_info": { + "type": "object", + "properties": { + "ip": { + "type": "string" + }, + "countryCode": { + "type": "string" + }, + "regionCode": { + "type": "string" + }, + "cityName": { + "type": "string" + }, + "latitude": { + "type": "number" + }, + "longitude": { + "type": "number" + }, + "tzIdentifier": { + "type": "string" + } + }, + "required": [ + "ip" + ] + } + }, + "required": [ + "id", + "user_id", + "created_at", + "is_impersonation" + ] + } + }, + "pagination": { + "type": "object", + "properties": { + "next_cursor": { + "type": "string", + "example": "b3d396b8-c574-4c80-97b3-50031675ceb2", + "description": "The cursor to fetch the next page of results. null if there is no next page." + } + }, + "required": [] + } + }, + "required": [ + "items" + ] + } + } + } + } + } + } + }, + "/auth/sessions/current": { + "delete": { + "summary": "Sign out of the current session", + "description": "Sign out of the current session and invalidate the refresh token", + "parameters": [], + "tags": [ + "Sessions" + ], + "x-full-url": "https://api.stack-auth.com/api/v1/auth/sessions/current", + "responses": { + "200": { + "description": "Successful response", + "content": { + "application/json": { + "schema": { + "type": "object", + "properties": { + "success": { + "type": "boolean", + "description": "Always equal to true.", + "example": true + } + }, + "required": [ + "success" + ] + } + } + } + } + } + } + }, + "/auth/sessions/current/refresh": { + "post": { + "summary": "Refresh access token", + "description": "Get a new access token using a refresh token", + "parameters": [ + { + "name": "x-stack-refresh-token", + "in": "header", + "schema": { + "type": "string" + }, + "required": true + } + ], + "tags": [ + "Sessions" + ], + "x-full-url": "https://api.stack-auth.com/api/v1/auth/sessions/current/refresh", + "responses": { + "200": { + "description": "Successful response", + "content": { + "application/json": { + "schema": { + "type": "object", + "properties": { + "access_token": { + "type": "string" + } + }, + "required": [ + "access_token" + ] + } + } + } + } + } + } + }, + "/auth/sessions/{id}": { + "delete": { + "summary": "Delete session", + "description": "Delete a session by ID.", + "parameters": [ + { + "name": "user_id", + "in": "query", + "schema": { + "type": "string", + "example": "3241a285-8329-4d69-8f3d-316e08cf140c", + "description": "The ID of the user, or the special value `me` for the currently authenticated user" + }, + "description": "The ID of the user, or the special value `me` for the currently authenticated user", + "required": true + }, + { + "name": "id", + "in": "path", + "schema": { + "type": "string" + }, + "required": true + } + ], + "tags": [ + "Sessions" + ], + "x-full-url": "https://api.stack-auth.com/api/v1/auth/sessions/{id}", + "responses": { + "200": { + "description": "Successful response", + "content": { + "application/json": { + "schema": { + "type": "object", + "properties": { + "success": { + "type": "boolean", + "description": "Always equal to true.", + "example": true + } + }, + "required": [ + "success" + ] + } + } + } + } + } + } + }, + "/team-invitations": { + "get": { + "summary": "List team invitations", + "description": "", + "parameters": [ + { + "name": "team_id", + "in": "query", + "schema": { + "type": "string", + "description": "The team ID to list invitations for. Required unless user_id is provided." + }, + "description": "The team ID to list invitations for. Required unless user_id is provided.", + "required": false + }, + { + "name": "user_id", + "in": "query", + "schema": { + "type": "string", + "description": "List invitations sent to this user's verified emails. Must be \"me\" for client access. Cannot be combined with team_id." + }, + "description": "List invitations sent to this user's verified emails. Must be \"me\" for client access. Cannot be combined with team_id.", + "required": false + } + ], + "tags": [ + "Teams" + ], + "x-full-url": "https://api.stack-auth.com/api/v1/team-invitations", + "responses": { + "200": { + "description": "Successful response", + "content": { + "application/json": { + "schema": { + "type": "object", + "properties": { + "items": { + "type": "array", + "items": { + "type": "object", + "properties": { + "id": { + "type": "string" + }, + "team_id": { + "type": "string", + "example": "ad962777-8244-496a-b6a2-e0c6a449c79e", + "description": "The unique identifier of the team" + }, + "team_display_name": { + "type": "string" + }, + "expires_at_millis": { + "type": "number" + }, + "recipient_email": { + "type": "string" + } + }, + "required": [ + "id", + "team_id", + "team_display_name", + "expires_at_millis", + "recipient_email" + ] + } + }, + "pagination": { + "type": "object", + "properties": { + "next_cursor": { + "type": "string", + "example": "b3d396b8-c574-4c80-97b3-50031675ceb2", + "description": "The cursor to fetch the next page of results. null if there is no next page." + } + }, + "required": [] + } + }, + "required": [ + "items" + ] + } + } + } + } + } + } + }, + "/team-invitations/accept": { + "post": { + "summary": "Accept the team invitation", + "description": "Accept invitation and add user to the team", + "parameters": [], + "requestBody": { + "required": true, + "content": { + "application/json": { + "schema": { + "type": "object", + "properties": { + "code": { + "type": "string", + "example": "u3h6gn4w24pqc8ya679inrhjwh1rybth6a7thurqhnpf2", + "description": "A 45 character code" + } + }, + "required": [ + "code" + ], + "example": { + "code": "u3h6gn4w24pqc8ya679inrhjwh1rybth6a7thurqhnpf2" + } + } + } + } + }, + "tags": [ + "Teams" + ], + "x-full-url": "https://api.stack-auth.com/api/v1/team-invitations/accept", + "responses": { + "200": { + "description": "Successful response", + "content": { + "application/json": { + "schema": { + "type": "object", + "properties": {} + } + } + } + } + } + } + }, + "/team-invitations/accept/check-code": { + "post": { + "summary": "Check if a team invitation code is valid", + "description": "Check if a team invitation code is valid without using it", + "parameters": [], + "requestBody": { + "required": true, + "content": { + "application/json": { + "schema": { + "type": "object", + "properties": { + "code": { + "type": "string", + "example": "u3h6gn4w24pqc8ya679inrhjwh1rybth6a7thurqhnpf2", + "description": "A 45 character code" + } + }, + "required": [ + "code" + ], + "example": { + "code": "u3h6gn4w24pqc8ya679inrhjwh1rybth6a7thurqhnpf2" + } + } + } + } + }, + "tags": [ + "Teams" + ], + "x-full-url": "https://api.stack-auth.com/api/v1/team-invitations/accept/check-code", + "responses": { + "200": { + "description": "Successful response", + "content": { + "application/json": { + "schema": { + "type": "object", + "properties": { + "is_code_valid": { + "type": "boolean" + } + }, + "required": [ + "is_code_valid" + ] + } + } + } + } + } + } + }, + "/team-invitations/accept/details": { + "post": { + "summary": "Get team invitation details", + "description": "Get additional information about a team invitation code", + "parameters": [], + "requestBody": { + "required": true, + "content": { + "application/json": { + "schema": { + "type": "object", + "properties": { + "code": { + "type": "string", + "example": "u3h6gn4w24pqc8ya679inrhjwh1rybth6a7thurqhnpf2", + "description": "A 45 character code" + } + }, + "required": [ + "code" + ], + "example": { + "code": "u3h6gn4w24pqc8ya679inrhjwh1rybth6a7thurqhnpf2" + } + } + } + } + }, + "tags": [ + "Teams" + ], + "x-full-url": "https://api.stack-auth.com/api/v1/team-invitations/accept/details", + "responses": { + "200": { + "description": "Successful response", + "content": { + "application/json": { + "schema": { + "type": "object", + "properties": { + "team_id": { + "type": "string" + }, + "team_display_name": { + "type": "string" + } + }, + "required": [ + "team_id", + "team_display_name" + ] + } + } + } + } + } + } + }, + "/team-invitations/send-code": { + "post": { + "summary": "Send an email to invite a user to a team", + "description": "The user receiving this email can join the team by clicking on the link in the email. If the user does not have an account yet, they will be prompted to create one.", + "parameters": [], + "requestBody": { + "required": true, + "content": { + "application/json": { + "schema": { + "type": "object", + "properties": { + "team_id": { + "type": "string", + "example": "ad962777-8244-496a-b6a2-e0c6a449c79e", + "description": "The unique identifier of the team" + }, + "email": { + "type": "string", + "example": "johndoe@example.com", + "description": "The email of the user to invite." + }, + "callback_url": { + "type": "string", + "example": "https://example.com/handler/team-invitation", + "description": "The base callback URL to construct an invite link with. A query parameter `code` with the verification code will be appended to it. The page should then make a request to the `/team-invitations/accept` endpoint." + } + }, + "required": [ + "team_id", + "email", + "callback_url" + ], + "example": { + "team_id": "ad962777-8244-496a-b6a2-e0c6a449c79e", + "email": "johndoe@example.com", + "callback_url": "https://example.com/handler/team-invitation" + } + } + } + } + }, + "tags": [ + "Teams" + ], + "x-full-url": "https://api.stack-auth.com/api/v1/team-invitations/send-code", + "responses": { + "200": { + "description": "Successful response", + "content": { + "application/json": { + "schema": { + "type": "object", + "properties": { + "success": { + "type": "boolean" + }, + "id": { + "type": "string" + } + }, + "required": [ + "success", + "id" + ] + } + } + } + } + } + } + }, + "/team-invitations/{id}": { + "delete": { + "summary": "Delete a team invitation", + "description": "", + "parameters": [ + { + "name": "team_id", + "in": "query", + "schema": { + "type": "string", + "description": "The team ID to list invitations for. Required unless user_id is provided." + }, + "description": "The team ID to list invitations for. Required unless user_id is provided.", + "required": false + }, + { + "name": "id", + "in": "path", + "schema": { + "type": "string" + }, + "required": true + } + ], + "tags": [ + "Teams" + ], + "x-full-url": "https://api.stack-auth.com/api/v1/team-invitations/{id}", + "responses": { + "200": { + "description": "Successful response", + "content": { + "application/json": { + "schema": { + "type": "object", + "properties": { + "success": { + "type": "boolean", + "description": "Always equal to true.", + "example": true + } + }, + "required": [ + "success" + ] + } + } + } + } + } + } + }, + "/team-invitations/{id}/accept": { + "post": { + "summary": "Accept a team invitation by ID", + "description": "Accepts a team invitation for the specified user. The user must have a verified email matching the invitation's recipient email. This marks the invitation as used and adds the user to the team.", + "parameters": [ + { + "name": "user_id", + "in": "query", + "schema": { + "type": "string", + "example": "3241a285-8329-4d69-8f3d-316e08cf140c", + "description": "The ID of the user, or the special value `me` for the currently authenticated user" + }, + "description": "The ID of the user, or the special value `me` for the currently authenticated user", + "required": true + }, + { + "name": "id", + "in": "path", + "schema": { + "type": "string" + }, + "required": true + } + ], + "tags": [ + "Teams" + ], + "x-full-url": "https://api.stack-auth.com/api/v1/team-invitations/{id}/accept", + "responses": { + "200": { + "description": "Successful response", + "content": { + "application/json": { + "schema": { + "type": "object", + "properties": {} + } + } + } + } + } + } + }, + "/team-member-profiles": { + "get": { + "summary": "List team members profiles", + "description": "List team members profiles. You always need to specify a `team_id` that your are a member of on the client. You can always filter for your own profile by setting `me` as the `user_id` in the path parameters. If you want list all the profiles in a team, you need to have the `$read_members` permission in that team.", + "parameters": [ + { + "name": "user_id", + "in": "query", + "schema": { + "type": "string" + }, + "required": false + }, + { + "name": "team_id", + "in": "query", + "schema": { + "type": "string" + }, + "required": false + } + ], + "tags": [ + "Teams" + ], + "x-full-url": "https://api.stack-auth.com/api/v1/team-member-profiles", + "responses": { + "200": { + "description": "Successful response", + "content": { + "application/json": { + "schema": { + "type": "object", + "properties": { + "items": { + "type": "array", + "items": { + "type": "object", + "properties": { + "team_id": { + "type": "string", + "example": "ad962777-8244-496a-b6a2-e0c6a449c79e", + "description": "The unique identifier of the team" + }, + "user_id": { + "type": "string", + "example": "3241a285-8329-4d69-8f3d-316e08cf140c", + "description": "The unique identifier of the user" + }, + "display_name": { + "type": "string", + "example": "John Doe", + "description": "Human-readable team member display name. This is not a unique identifier. Note that this is separate from the display_name of the user." + }, + "profile_image_url": { + "type": "string", + "example": "https://example.com/image.jpg", + "description": "URL of the profile image for team member. Can be a Base64 encoded image. Must be smaller than 100KB. Please compress and crop to a square before passing in." + } + }, + "required": [ + "team_id", + "user_id" + ] + } + }, + "pagination": { + "type": "object", + "properties": { + "next_cursor": { + "type": "string", + "example": "b3d396b8-c574-4c80-97b3-50031675ceb2", + "description": "The cursor to fetch the next page of results. null if there is no next page." + } + }, + "required": [] + } + }, + "required": [ + "items" + ] + } + } + } + } + } + } + }, + "/team-member-profiles/{team_id}/{user_id}": { + "get": { + "summary": "Get a team member profile", + "description": "Get a team member profile. you can always get your own profile by setting `me` as the `user_id` in the path parameters on the client. If you want to get someone else's profile in a team, you need to have the `$read_members` permission in that team.", + "parameters": [ + { + "name": "team_id", + "in": "path", + "schema": { + "type": "string" + }, + "required": true + }, + { + "name": "user_id", + "in": "path", + "schema": { + "type": "string", + "example": "3241a285-8329-4d69-8f3d-316e08cf140c", + "description": "The ID of the user, or the special value `me` for the currently authenticated user" + }, + "description": "The ID of the user, or the special value `me` for the currently authenticated user", + "required": true + } + ], + "tags": [ + "Teams" + ], + "x-full-url": "https://api.stack-auth.com/api/v1/team-member-profiles/{team_id}/{user_id}", + "responses": { + "200": { + "description": "Successful response", + "content": { + "application/json": { + "schema": { + "type": "object", + "properties": { + "team_id": { + "type": "string", + "example": "ad962777-8244-496a-b6a2-e0c6a449c79e", + "description": "The unique identifier of the team" + }, + "user_id": { + "type": "string", + "example": "3241a285-8329-4d69-8f3d-316e08cf140c", + "description": "The unique identifier of the user" + }, + "display_name": { + "type": "string", + "example": "John Doe", + "description": "Human-readable team member display name. This is not a unique identifier. Note that this is separate from the display_name of the user." + }, + "profile_image_url": { + "type": "string", + "example": "https://example.com/image.jpg", + "description": "URL of the profile image for team member. Can be a Base64 encoded image. Must be smaller than 100KB. Please compress and crop to a square before passing in." + } + }, + "required": [ + "team_id", + "user_id" + ] + } + } + } + } + } + }, + "patch": { + "summary": "Update your team member profile", + "description": "Update your own team member profile. `user_id` must be `me` in the path parameters on the client.", + "parameters": [ + { + "name": "team_id", + "in": "path", + "schema": { + "type": "string" + }, + "required": true + }, + { + "name": "user_id", + "in": "path", + "schema": { + "type": "string", + "example": "3241a285-8329-4d69-8f3d-316e08cf140c", + "description": "The ID of the user, or the special value `me` for the currently authenticated user" + }, + "description": "The ID of the user, or the special value `me` for the currently authenticated user", + "required": true + } + ], + "requestBody": { + "required": true, + "content": { + "application/json": { + "schema": { + "type": "object", + "properties": { + "display_name": { + "type": "string", + "example": "John Doe", + "description": "Human-readable team member display name. This is not a unique identifier. Note that this is separate from the display_name of the user." + }, + "profile_image_url": { + "type": "string", + "example": "https://example.com/image.jpg", + "description": "URL of the profile image for team member. Can be a Base64 encoded image. Must be smaller than 100KB. Please compress and crop to a square before passing in." + } + }, + "example": { + "display_name": "John Doe", + "profile_image_url": "https://example.com/image.jpg" + } + } + } + } + }, + "tags": [ + "Teams" + ], + "x-full-url": "https://api.stack-auth.com/api/v1/team-member-profiles/{team_id}/{user_id}", + "responses": { + "200": { + "description": "Successful response", + "content": { + "application/json": { + "schema": { + "type": "object", + "properties": { + "team_id": { + "type": "string", + "example": "ad962777-8244-496a-b6a2-e0c6a449c79e", + "description": "The unique identifier of the team" + }, + "user_id": { + "type": "string", + "example": "3241a285-8329-4d69-8f3d-316e08cf140c", + "description": "The unique identifier of the user" + }, + "display_name": { + "type": "string", + "example": "John Doe", + "description": "Human-readable team member display name. This is not a unique identifier. Note that this is separate from the display_name of the user." + }, + "profile_image_url": { + "type": "string", + "example": "https://example.com/image.jpg", + "description": "URL of the profile image for team member. Can be a Base64 encoded image. Must be smaller than 100KB. Please compress and crop to a square before passing in." + } + }, + "required": [ + "team_id", + "user_id" + ] + } + } + } + } + } + } + }, + "/team-memberships/{team_id}/{user_id}": { + "delete": { + "summary": "Remove a user from a team", + "description": "All the users are allowed to remove themselves from a team (`user_id=me`). Only the users who have the `$remove_members` permission are allowed to remove other users from a team. `team_id` is must an ID of a team that the user is a member of.", + "parameters": [ + { + "name": "team_id", + "in": "path", + "schema": { + "type": "string" + }, + "required": true + }, + { + "name": "user_id", + "in": "path", + "schema": { + "type": "string", + "example": "3241a285-8329-4d69-8f3d-316e08cf140c", + "description": "The ID of the user, or the special value `me` for the currently authenticated user" + }, + "description": "The ID of the user, or the special value `me` for the currently authenticated user", + "required": true + } + ], + "tags": [ + "Teams" + ], + "x-full-url": "https://api.stack-auth.com/api/v1/team-memberships/{team_id}/{user_id}", + "responses": { + "200": { + "description": "Successful response", + "content": { + "application/json": { + "schema": { + "type": "object", + "properties": { + "success": { + "type": "boolean", + "description": "Always equal to true.", + "example": true + } + }, + "required": [ + "success" + ] + } + } + } + } + } + } + }, + "/teams": { + "get": { + "summary": "List teams", + "description": "List all the teams that the current user is a member of. `user_id=me` must be passed in the query parameters.", + "parameters": [ + { + "name": "user_id", + "in": "query", + "schema": { + "type": "string", + "example": "me", + "description": "Filter for the teams that the user is a member of. Can be either `me` or an ID. Must be `me` in the client API" + }, + "description": "Filter for the teams that the user is a member of. Can be either `me` or an ID. Must be `me` in the client API", + "required": false + } + ], + "tags": [ + "Teams" + ], + "x-full-url": "https://api.stack-auth.com/api/v1/teams", + "responses": { + "200": { + "description": "Successful response", + "content": { + "application/json": { + "schema": { + "type": "object", + "properties": { + "items": { + "type": "array", + "items": { + "type": "object", + "properties": { + "id": { + "type": "string", + "example": "ad962777-8244-496a-b6a2-e0c6a449c79e", + "description": "The unique identifier of the team" + }, + "display_name": { + "type": "string", + "example": "My Team", + "description": "Human-readable team display name. This is not a unique identifier." + }, + "profile_image_url": { + "type": "string", + "example": "https://example.com/image.jpg", + "description": "URL of the profile image for team. Can be a Base64 encoded image. Must be smaller than 100KB. Please compress and crop to a square before passing in." + }, + "client_metadata": { + "type": "object", + "example": { + "key": "value" + }, + "description": "Client metadata. Used as a data store, accessible from the client side. Do not store information that should not be exposed to the client." + }, + "client_read_only_metadata": { + "type": "object", + "example": { + "key": "value" + }, + "description": "Client read-only, server-writable metadata. Used as a data store, accessible from the client side. Do not store information that should not be exposed to the client. The client can read this data, but cannot modify it. This is useful for things like subscription status." + } + }, + "required": [ + "id", + "display_name" + ] + } + }, + "pagination": { + "type": "object", + "properties": { + "next_cursor": { + "type": "string", + "example": "b3d396b8-c574-4c80-97b3-50031675ceb2", + "description": "The cursor to fetch the next page of results. null if there is no next page." + } + }, + "required": [] + } + }, + "required": [ + "items" + ] + } + } + } + } + } + }, + "post": { + "summary": "Create a team", + "description": "Create a new team and optionally add the current user as a member.", + "parameters": [], + "requestBody": { + "required": true, + "content": { + "application/json": { + "schema": { + "type": "object", + "properties": { + "display_name": { + "type": "string", + "example": "My Team", + "description": "Human-readable team display name. This is not a unique identifier." + }, + "creator_user_id": { + "type": "string", + "example": "me", + "description": "The ID of the creator of the team. If not specified, the user will not be added to the team. Can be either \"me\" or the ID of the user. Only used on the client side." + }, + "profile_image_url": { + "type": "string", + "example": "https://example.com/image.jpg", + "description": "URL of the profile image for team. Can be a Base64 encoded image. Must be smaller than 100KB. Please compress and crop to a square before passing in." + }, + "client_metadata": { + "type": "object", + "example": { + "key": "value" + }, + "description": "Client metadata. Used as a data store, accessible from the client side. Do not store information that should not be exposed to the client." + } + }, + "required": [ + "display_name" + ], + "example": { + "display_name": "My Team", + "creator_user_id": "me", + "profile_image_url": "https://example.com/image.jpg", + "client_metadata": { + "key": "value" + } + } + } + } + } + }, + "tags": [ + "Teams" + ], + "x-full-url": "https://api.stack-auth.com/api/v1/teams", + "responses": { + "201": { + "description": "Successful response", + "content": { + "application/json": { + "schema": { + "type": "object", + "properties": { + "id": { + "type": "string", + "example": "ad962777-8244-496a-b6a2-e0c6a449c79e", + "description": "The unique identifier of the team" + }, + "display_name": { + "type": "string", + "example": "My Team", + "description": "Human-readable team display name. This is not a unique identifier." + }, + "profile_image_url": { + "type": "string", + "example": "https://example.com/image.jpg", + "description": "URL of the profile image for team. Can be a Base64 encoded image. Must be smaller than 100KB. Please compress and crop to a square before passing in." + }, + "client_metadata": { + "type": "object", + "example": { + "key": "value" + }, + "description": "Client metadata. Used as a data store, accessible from the client side. Do not store information that should not be exposed to the client." + }, + "client_read_only_metadata": { + "type": "object", + "example": { + "key": "value" + }, + "description": "Client read-only, server-writable metadata. Used as a data store, accessible from the client side. Do not store information that should not be exposed to the client. The client can read this data, but cannot modify it. This is useful for things like subscription status." + } + }, + "required": [ + "id", + "display_name" + ] + } + } + } + } + } + } + }, + "/teams/{team_id}": { + "get": { + "summary": "Get a team", + "description": "Get a team that the current user is a member of.", + "parameters": [ + { + "name": "team_id", + "in": "path", + "schema": { + "type": "string" + }, + "required": true + } + ], + "tags": [ + "Teams" + ], + "x-full-url": "https://api.stack-auth.com/api/v1/teams/{team_id}", + "responses": { + "200": { + "description": "Successful response", + "content": { + "application/json": { + "schema": { + "type": "object", + "properties": { + "id": { + "type": "string", + "example": "ad962777-8244-496a-b6a2-e0c6a449c79e", + "description": "The unique identifier of the team" + }, + "display_name": { + "type": "string", + "example": "My Team", + "description": "Human-readable team display name. This is not a unique identifier." + }, + "profile_image_url": { + "type": "string", + "example": "https://example.com/image.jpg", + "description": "URL of the profile image for team. Can be a Base64 encoded image. Must be smaller than 100KB. Please compress and crop to a square before passing in." + }, + "client_metadata": { + "type": "object", + "example": { + "key": "value" + }, + "description": "Client metadata. Used as a data store, accessible from the client side. Do not store information that should not be exposed to the client." + }, + "client_read_only_metadata": { + "type": "object", + "example": { + "key": "value" + }, + "description": "Client read-only, server-writable metadata. Used as a data store, accessible from the client side. Do not store information that should not be exposed to the client. The client can read this data, but cannot modify it. This is useful for things like subscription status." + } + }, + "required": [ + "id", + "display_name" + ] + } + } + } + } + } + }, + "delete": { + "summary": "Delete a team", + "description": "Delete a team. Only allowed if the current user is a member of the team and has the `$delete_team` permission.", + "parameters": [ + { + "name": "team_id", + "in": "path", + "schema": { + "type": "string" + }, + "required": true + } + ], + "tags": [ + "Teams" + ], + "x-full-url": "https://api.stack-auth.com/api/v1/teams/{team_id}", + "responses": { + "200": { + "description": "Successful response", + "content": { + "application/json": { + "schema": { + "type": "object", + "properties": { + "success": { + "type": "boolean", + "description": "Always equal to true.", + "example": true + } + }, + "required": [ + "success" + ] + } + } + } + } + } + }, + "patch": { + "summary": "Update a team", + "description": "Update the team information. Only allowed if the current user is a member of the team and has the `$update_team` permission.", + "parameters": [ + { + "name": "team_id", + "in": "path", + "schema": { + "type": "string" + }, + "required": true + } + ], + "requestBody": { + "required": true, + "content": { + "application/json": { + "schema": { + "type": "object", + "properties": { + "display_name": { + "type": "string", + "example": "My Team", + "description": "Human-readable team display name. This is not a unique identifier." + }, + "profile_image_url": { + "type": "string", + "example": "https://example.com/image.jpg", + "description": "URL of the profile image for team. Can be a Base64 encoded image. Must be smaller than 100KB. Please compress and crop to a square before passing in." + }, + "client_metadata": { + "type": "object", + "example": { + "key": "value" + }, + "description": "Client metadata. Used as a data store, accessible from the client side. Do not store information that should not be exposed to the client." + } + }, + "example": { + "display_name": "My Team", + "profile_image_url": "https://example.com/image.jpg", + "client_metadata": { + "key": "value" + } + } + } + } + } + }, + "tags": [ + "Teams" + ], + "x-full-url": "https://api.stack-auth.com/api/v1/teams/{team_id}", + "responses": { + "200": { + "description": "Successful response", + "content": { + "application/json": { + "schema": { + "type": "object", + "properties": { + "id": { + "type": "string", + "example": "ad962777-8244-496a-b6a2-e0c6a449c79e", + "description": "The unique identifier of the team" + }, + "display_name": { + "type": "string", + "example": "My Team", + "description": "Human-readable team display name. This is not a unique identifier." + }, + "profile_image_url": { + "type": "string", + "example": "https://example.com/image.jpg", + "description": "URL of the profile image for team. Can be a Base64 encoded image. Must be smaller than 100KB. Please compress and crop to a square before passing in." + }, + "client_metadata": { + "type": "object", + "example": { + "key": "value" + }, + "description": "Client metadata. Used as a data store, accessible from the client side. Do not store information that should not be exposed to the client." + }, + "client_read_only_metadata": { + "type": "object", + "example": { + "key": "value" + }, + "description": "Client read-only, server-writable metadata. Used as a data store, accessible from the client side. Do not store information that should not be exposed to the client. The client can read this data, but cannot modify it. This is useful for things like subscription status." + } + }, + "required": [ + "id", + "display_name" + ] + } + } + } + } + } + } + }, + "/users/me": { + "get": { + "summary": "Get current user", + "description": "Gets the currently authenticated user.", + "parameters": [], + "tags": [ + "Users" + ], + "x-full-url": "https://api.stack-auth.com/api/v1/users/me", + "responses": { + "200": { + "description": "Successful response", + "content": { + "application/json": { + "schema": { + "type": "object", + "properties": { + "selected_team": { + "type": "object", + "properties": { + "id": { + "type": "string", + "example": "ad962777-8244-496a-b6a2-e0c6a449c79e", + "description": "The unique identifier of the team" + }, + "display_name": { + "type": "string", + "example": "My Team", + "description": "Human-readable team display name. This is not a unique identifier." + }, + "profile_image_url": { + "type": "string", + "example": "https://example.com/image.jpg", + "description": "URL of the profile image for team. Can be a Base64 encoded image. Must be smaller than 100KB. Please compress and crop to a square before passing in." + }, + "client_metadata": { + "type": "object", + "example": { + "key": "value" + }, + "description": "Client metadata. Used as a data store, accessible from the client side. Do not store information that should not be exposed to the client." + }, + "client_read_only_metadata": { + "type": "object", + "example": { + "key": "value" + }, + "description": "Client read-only, server-writable metadata. Used as a data store, accessible from the client side. Do not store information that should not be exposed to the client. The client can read this data, but cannot modify it. This is useful for things like subscription status." + } + }, + "required": [ + "id", + "display_name" + ] + }, + "id": { + "type": "string", + "example": "3241a285-8329-4d69-8f3d-316e08cf140c", + "description": "The unique identifier of the user" + }, + "primary_email": { + "type": "string", + "example": "johndoe@example.com", + "description": "Primary email" + }, + "primary_email_verified": { + "type": "boolean", + "example": true, + "description": "Whether the primary email has been verified to belong to this user" + }, + "display_name": { + "type": "string", + "example": "John Doe", + "description": "Human-readable user display name. This is not a unique identifier." + }, + "client_metadata": { + "type": "object", + "example": { + "key": "value" + }, + "description": "Client metadata. Used as a data store, accessible from the client side. Do not store information that should not be exposed to the client." + }, + "client_read_only_metadata": { + "type": "object", + "example": { + "key": "value" + }, + "description": "Client read-only, server-writable metadata. Used as a data store, accessible from the client side. Do not store information that should not be exposed to the client. The client can read this data, but cannot modify it. This is useful for things like subscription status." + }, + "profile_image_url": { + "type": "string", + "example": "https://example.com/image.jpg", + "description": "URL of the profile image for user. Can be a Base64 encoded image. Must be smaller than 100KB. Please compress and crop to a square before passing in." + }, + "signed_up_at_millis": { + "type": "number", + "example": 1630000000000, + "description": "The time the user signed up (identify) => `(the number of milliseconds since epoch, January 1, 1970, UTC)`" + }, + "selected_team_id": { + "type": "string", + "example": "team-id", + "description": "ID of the team currently selected by the user" + }, + "is_anonymous": { + "type": "boolean" + }, + "is_restricted": { + "type": "boolean", + "example": false, + "description": "Whether the user is in restricted state (has signed up but not completed onboarding requirements)" + }, + "restricted_reason": { + "type": "object", + "properties": { + "type": { + "type": "string" + } + }, + "required": [ + "type" + ], + "example": null, + "description": "The reason why the user is restricted (e.g., type: \"email_not_verified\", \"anonymous\", or \"restricted_by_administrator\"), null if not restricted" + }, + "restricted_by_admin": { + "type": "boolean", + "example": false, + "description": "Whether the user is restricted by an administrator. Can be set manually or by sign-up rules." + }, + "restricted_by_admin_reason": { + "type": "string", + "example": null, + "description": "Public reason shown to the user explaining why they are restricted. Optional." + } + }, + "required": [ + "id", + "primary_email_verified", + "signed_up_at_millis", + "is_anonymous", + "is_restricted", + "restricted_by_admin" + ] + } + } + } + } + } + }, + "delete": { + "summary": "Delete current user", + "description": "Deletes the currently authenticated user. Use this with caution.", + "parameters": [], + "tags": [ + "Users" + ], + "x-full-url": "https://api.stack-auth.com/api/v1/users/me", + "responses": { + "200": { + "description": "Successful response", + "content": { + "application/json": { + "schema": { + "type": "object", + "properties": { + "success": { + "type": "boolean", + "description": "Always equal to true.", + "example": true + } + }, + "required": [ + "success" + ] + } + } + } + } + } + }, + "patch": { + "summary": "Update current user", + "description": "Updates the currently authenticated user. Only the values provided will be updated.", + "parameters": [], + "requestBody": { + "required": true, + "content": { + "application/json": { + "schema": { + "type": "object", + "properties": { + "display_name": { + "type": "string", + "example": "John Doe", + "description": "Human-readable user display name. This is not a unique identifier." + }, + "profile_image_url": { + "type": "string", + "example": "https://example.com/image.jpg", + "description": "URL of the profile image for user. Can be a Base64 encoded image. Must be smaller than 100KB. Please compress and crop to a square before passing in." + }, + "client_metadata": { + "type": "object", + "example": { + "key": "value" + }, + "description": "Client metadata. Used as a data store, accessible from the client side. Do not store information that should not be exposed to the client." + }, + "selected_team_id": { + "type": "string", + "example": "team-id", + "description": "ID of the team currently selected by the user" + }, + "totp_secret_base64": { + "type": "string", + "example": "dG90cC1zZWNyZXQ=", + "description": "Enables 2FA and sets a TOTP secret for the user. Set to null to disable 2FA." + }, + "primary_email": { + "type": "string", + "example": "johndoe@example.com", + "description": "Primary email" + } + }, + "example": { + "display_name": "John Doe", + "profile_image_url": "https://example.com/image.jpg", + "client_metadata": { + "key": "value" + }, + "selected_team_id": "team-id", + "totp_secret_base64": "dG90cC1zZWNyZXQ=", + "primary_email": "johndoe@example.com" + } + } + } + } + }, + "tags": [ + "Users" + ], + "x-full-url": "https://api.stack-auth.com/api/v1/users/me", + "responses": { + "200": { + "description": "Successful response", + "content": { + "application/json": { + "schema": { + "type": "object", + "properties": { + "selected_team": { + "type": "object", + "properties": { + "id": { + "type": "string", + "example": "ad962777-8244-496a-b6a2-e0c6a449c79e", + "description": "The unique identifier of the team" + }, + "display_name": { + "type": "string", + "example": "My Team", + "description": "Human-readable team display name. This is not a unique identifier." + }, + "profile_image_url": { + "type": "string", + "example": "https://example.com/image.jpg", + "description": "URL of the profile image for team. Can be a Base64 encoded image. Must be smaller than 100KB. Please compress and crop to a square before passing in." + }, + "client_metadata": { + "type": "object", + "example": { + "key": "value" + }, + "description": "Client metadata. Used as a data store, accessible from the client side. Do not store information that should not be exposed to the client." + }, + "client_read_only_metadata": { + "type": "object", + "example": { + "key": "value" + }, + "description": "Client read-only, server-writable metadata. Used as a data store, accessible from the client side. Do not store information that should not be exposed to the client. The client can read this data, but cannot modify it. This is useful for things like subscription status." + } + }, + "required": [ + "id", + "display_name" + ] + }, + "id": { + "type": "string", + "example": "3241a285-8329-4d69-8f3d-316e08cf140c", + "description": "The unique identifier of the user" + }, + "primary_email": { + "type": "string", + "example": "johndoe@example.com", + "description": "Primary email" + }, + "primary_email_verified": { + "type": "boolean", + "example": true, + "description": "Whether the primary email has been verified to belong to this user" + }, + "display_name": { + "type": "string", + "example": "John Doe", + "description": "Human-readable user display name. This is not a unique identifier." + }, + "client_metadata": { + "type": "object", + "example": { + "key": "value" + }, + "description": "Client metadata. Used as a data store, accessible from the client side. Do not store information that should not be exposed to the client." + }, + "client_read_only_metadata": { + "type": "object", + "example": { + "key": "value" + }, + "description": "Client read-only, server-writable metadata. Used as a data store, accessible from the client side. Do not store information that should not be exposed to the client. The client can read this data, but cannot modify it. This is useful for things like subscription status." + }, + "profile_image_url": { + "type": "string", + "example": "https://example.com/image.jpg", + "description": "URL of the profile image for user. Can be a Base64 encoded image. Must be smaller than 100KB. Please compress and crop to a square before passing in." + }, + "signed_up_at_millis": { + "type": "number", + "example": 1630000000000, + "description": "The time the user signed up (identify) => `(the number of milliseconds since epoch, January 1, 1970, UTC)`" + }, + "selected_team_id": { + "type": "string", + "example": "team-id", + "description": "ID of the team currently selected by the user" + }, + "is_anonymous": { + "type": "boolean" + }, + "is_restricted": { + "type": "boolean", + "example": false, + "description": "Whether the user is in restricted state (has signed up but not completed onboarding requirements)" + }, + "restricted_reason": { + "type": "object", + "properties": { + "type": { + "type": "string" + } + }, + "required": [ + "type" + ], + "example": null, + "description": "The reason why the user is restricted (e.g., type: \"email_not_verified\", \"anonymous\", or \"restricted_by_administrator\"), null if not restricted" + }, + "restricted_by_admin": { + "type": "boolean", + "example": false, + "description": "Whether the user is restricted by an administrator. Can be set manually or by sign-up rules." + }, + "restricted_by_admin_reason": { + "type": "string", + "example": null, + "description": "Public reason shown to the user explaining why they are restricted. Optional." + } + }, + "required": [ + "id", + "primary_email_verified", + "signed_up_at_millis", + "is_anonymous", + "is_restricted", + "restricted_by_admin" + ] + } + } + } + } + } + } + } + } +} \ No newline at end of file diff --git a/docs-mintlify/openapi/server.json b/docs-mintlify/openapi/server.json new file mode 100644 index 0000000000..72c2d42572 --- /dev/null +++ b/docs-mintlify/openapi/server.json @@ -0,0 +1,10275 @@ +{ + "openapi": "3.1.0", + "info": { + "title": "Stack REST API", + "version": "1.0.0" + }, + "servers": [ + { + "url": "https://api.stack-auth.com/api/v1", + "description": "Stack REST API" + } + ], + "paths": { + "/": { + "get": { + "summary": "/api/v1", + "description": "Returns a human-readable message with some useful information about the API.", + "parameters": [ + { + "name": "X-Stack-Project-Id", + "in": "header", + "schema": { + "type": "string", + "example": "e0b52f4d-dece-408c-af49-d23061bb0f8d", + "description": "The unique identifier of the project" + }, + "description": "The unique identifier of the project", + "example": "e0b52f4d-dece-408c-af49-d23061bb0f8d", + "required": false + }, + { + "name": "X-Stack-Branch-Id", + "in": "header", + "schema": { + "type": "string", + "example": "e0b52f4d-dece-408c-af49-d23061bb0f8d", + "description": "The unique identifier of the project" + }, + "description": "The unique identifier of the project", + "example": "e0b52f4d-dece-408c-af49-d23061bb0f8d", + "required": false + }, + { + "name": "X-Stack-Access-Type", + "in": "header", + "schema": { + "type": "string" + }, + "required": false + }, + { + "name": "X-Stack-Access-Token", + "in": "header", + "schema": { + "type": "string" + }, + "required": false + }, + { + "name": "X-Stack-Refresh-Token", + "in": "header", + "schema": { + "type": "string" + }, + "required": false + }, + { + "name": "X-Stack-Publishable-Client-Key", + "in": "header", + "schema": { + "type": "string" + }, + "required": false + }, + { + "name": "X-Stack-Secret-Server-Key", + "in": "header", + "schema": { + "type": "string" + }, + "required": false + }, + { + "name": "X-Stack-Super-Secret-Admin-Key", + "in": "header", + "schema": { + "type": "string" + }, + "required": false + } + ], + "tags": [], + "x-full-url": "https://api.stack-auth.com/api/v1/", + "responses": { + "200": { + "description": "Successful response", + "content": { + "text/plain": { + "schema": { + "type": "string", + "example": "Welcome to the Stack API endpoint! Please refer to the documentation at https://docs.stack-auth.com/\n\nAuthentication: None" + } + } + } + } + } + } + }, + "/auth/anonymous/sign-up": { + "post": { + "summary": "Sign up anonymously", + "description": "Create a new anonymous account with no email", + "parameters": [], + "tags": [ + "Anonymous" + ], + "x-full-url": "https://api.stack-auth.com/api/v1/auth/anonymous/sign-up", + "responses": { + "200": { + "description": "Successful response", + "content": { + "application/json": { + "schema": { + "type": "object", + "properties": { + "access_token": { + "type": "string" + }, + "refresh_token": { + "type": "string" + }, + "user_id": { + "type": "string" + } + }, + "required": [ + "access_token", + "refresh_token", + "user_id" + ] + } + } + } + } + } + } + }, + "/team-api-keys": { + "get": { + "summary": "List team API keys", + "description": "List all team API keys for the project with their metadata and status", + "parameters": [ + { + "name": "team_id", + "in": "query", + "schema": { + "type": "string" + }, + "required": true + } + ], + "tags": [ + "API Keys" + ], + "x-full-url": "https://api.stack-auth.com/api/v1/team-api-keys", + "responses": { + "200": { + "description": "Successful response", + "content": { + "application/json": { + "schema": { + "type": "object", + "properties": { + "items": { + "type": "array", + "items": { + "type": "object", + "properties": { + "id": { + "type": "string" + }, + "description": { + "type": "string" + }, + "expires_at_millis": { + "type": "number" + }, + "manually_revoked_at_millis": { + "type": "number" + }, + "created_at_millis": { + "type": "number" + }, + "is_public": { + "type": "boolean" + }, + "value": { + "type": "object", + "properties": { + "last_four": { + "type": "string" + } + }, + "required": [ + "last_four" + ] + }, + "type": { + "type": "string" + }, + "team_id": { + "type": "string" + } + }, + "required": [ + "id", + "description", + "created_at_millis", + "is_public", + "value", + "type", + "team_id" + ] + } + }, + "pagination": { + "type": "object", + "properties": { + "next_cursor": { + "type": "string", + "example": "b3d396b8-c574-4c80-97b3-50031675ceb2", + "description": "The cursor to fetch the next page of results. null if there is no next page." + } + }, + "required": [] + } + }, + "required": [ + "items" + ] + } + } + } + } + } + }, + "post": { + "summary": "Create team API key", + "description": "Create a new API key for a user or team", + "parameters": [], + "requestBody": { + "required": true, + "content": { + "application/json": { + "schema": { + "type": "object", + "properties": { + "description": { + "type": "string" + }, + "expires_at_millis": { + "type": "number" + }, + "is_public": { + "type": "boolean" + }, + "team_id": { + "type": "string" + } + }, + "required": [ + "description", + "team_id" + ], + "example": {} + } + } + } + }, + "tags": [ + "API Keys" + ], + "x-full-url": "https://api.stack-auth.com/api/v1/team-api-keys", + "responses": { + "200": { + "description": "Successful response", + "content": { + "application/json": { + "schema": { + "type": "object", + "properties": { + "value": { + "type": "string" + }, + "id": { + "type": "string" + }, + "description": { + "type": "string" + }, + "expires_at_millis": { + "type": "number" + }, + "manually_revoked_at_millis": { + "type": "number" + }, + "created_at_millis": { + "type": "number" + }, + "is_public": { + "type": "boolean" + }, + "type": { + "type": "string" + }, + "team_id": { + "type": "string" + } + }, + "required": [ + "value", + "id", + "description", + "created_at_millis", + "is_public", + "type", + "team_id" + ] + } + } + } + } + } + } + }, + "/team-api-keys/check": { + "post": { + "summary": "Check team API key validity", + "description": "Validate a team API key", + "parameters": [], + "requestBody": { + "required": true, + "content": { + "application/json": { + "schema": { + "type": "object", + "properties": { + "api_key": { + "type": "string" + } + }, + "required": [ + "api_key" + ], + "example": {} + } + } + } + }, + "tags": [ + "API Keys" + ], + "x-full-url": "https://api.stack-auth.com/api/v1/team-api-keys/check", + "responses": { + "200": { + "description": "Successful response", + "content": { + "application/json": { + "schema": { + "type": "object", + "properties": { + "id": { + "type": "string" + }, + "description": { + "type": "string" + }, + "expires_at_millis": { + "type": "number" + }, + "manually_revoked_at_millis": { + "type": "number" + }, + "created_at_millis": { + "type": "number" + }, + "is_public": { + "type": "boolean" + }, + "value": { + "type": "object", + "properties": { + "last_four": { + "type": "string" + } + }, + "required": [ + "last_four" + ] + }, + "type": { + "type": "string" + }, + "team_id": { + "type": "string" + } + }, + "required": [ + "id", + "description", + "created_at_millis", + "is_public", + "value", + "type", + "team_id" + ] + } + } + } + } + } + } + }, + "/team-api-keys/{api_key_id}": { + "get": { + "summary": "Get team API key details", + "description": "Get details of a specific team API key", + "parameters": [ + { + "name": "api_key_id", + "in": "path", + "schema": { + "type": "string" + }, + "required": true + } + ], + "tags": [ + "API Keys" + ], + "x-full-url": "https://api.stack-auth.com/api/v1/team-api-keys/{api_key_id}", + "responses": { + "200": { + "description": "Successful response", + "content": { + "application/json": { + "schema": { + "type": "object", + "properties": { + "id": { + "type": "string" + }, + "description": { + "type": "string" + }, + "expires_at_millis": { + "type": "number" + }, + "manually_revoked_at_millis": { + "type": "number" + }, + "created_at_millis": { + "type": "number" + }, + "is_public": { + "type": "boolean" + }, + "value": { + "type": "object", + "properties": { + "last_four": { + "type": "string" + } + }, + "required": [ + "last_four" + ] + }, + "type": { + "type": "string" + }, + "team_id": { + "type": "string" + } + }, + "required": [ + "id", + "description", + "created_at_millis", + "is_public", + "value", + "type", + "team_id" + ] + } + } + } + } + } + }, + "patch": { + "summary": "Update team API key", + "description": "Update an team API key", + "parameters": [ + { + "name": "api_key_id", + "in": "path", + "schema": { + "type": "string" + }, + "required": true + } + ], + "requestBody": { + "required": true, + "content": { + "application/json": { + "schema": { + "type": "object", + "properties": { + "description": { + "type": "string" + }, + "revoked": { + "type": "boolean" + } + }, + "example": {} + } + } + } + }, + "tags": [ + "API Keys" + ], + "x-full-url": "https://api.stack-auth.com/api/v1/team-api-keys/{api_key_id}", + "responses": { + "200": { + "description": "Successful response", + "content": { + "application/json": { + "schema": { + "type": "object", + "properties": { + "id": { + "type": "string" + }, + "description": { + "type": "string" + }, + "expires_at_millis": { + "type": "number" + }, + "manually_revoked_at_millis": { + "type": "number" + }, + "created_at_millis": { + "type": "number" + }, + "is_public": { + "type": "boolean" + }, + "value": { + "type": "object", + "properties": { + "last_four": { + "type": "string" + } + }, + "required": [ + "last_four" + ] + }, + "type": { + "type": "string" + }, + "team_id": { + "type": "string" + } + }, + "required": [ + "id", + "description", + "created_at_millis", + "is_public", + "value", + "type", + "team_id" + ] + } + } + } + } + } + } + }, + "/user-api-keys": { + "get": { + "summary": "List user API keys", + "description": "List all user API keys for the project with their metadata and status", + "parameters": [ + { + "name": "user_id", + "in": "query", + "schema": { + "type": "string" + }, + "required": false + } + ], + "tags": [ + "API Keys" + ], + "x-full-url": "https://api.stack-auth.com/api/v1/user-api-keys", + "responses": { + "200": { + "description": "Successful response", + "content": { + "application/json": { + "schema": { + "type": "object", + "properties": { + "items": { + "type": "array", + "items": { + "type": "object", + "properties": { + "id": { + "type": "string" + }, + "description": { + "type": "string" + }, + "expires_at_millis": { + "type": "number" + }, + "manually_revoked_at_millis": { + "type": "number" + }, + "created_at_millis": { + "type": "number" + }, + "is_public": { + "type": "boolean" + }, + "value": { + "type": "object", + "properties": { + "last_four": { + "type": "string" + } + }, + "required": [ + "last_four" + ] + }, + "type": { + "type": "string" + }, + "user_id": { + "type": "string", + "example": "3241a285-8329-4d69-8f3d-316e08cf140c", + "description": "The ID of the user, or the special value `me` for the currently authenticated user" + } + }, + "required": [ + "id", + "description", + "created_at_millis", + "is_public", + "value", + "type", + "user_id" + ] + } + }, + "pagination": { + "type": "object", + "properties": { + "next_cursor": { + "type": "string", + "example": "b3d396b8-c574-4c80-97b3-50031675ceb2", + "description": "The cursor to fetch the next page of results. null if there is no next page." + } + }, + "required": [] + } + }, + "required": [ + "items" + ] + } + } + } + } + } + }, + "post": { + "summary": "Create user API key", + "description": "Create a new API key for a user or team", + "parameters": [], + "requestBody": { + "required": true, + "content": { + "application/json": { + "schema": { + "type": "object", + "properties": { + "description": { + "type": "string" + }, + "expires_at_millis": { + "type": "number" + }, + "is_public": { + "type": "boolean" + }, + "user_id": { + "type": "string", + "example": "3241a285-8329-4d69-8f3d-316e08cf140c", + "description": "The ID of the user, or the special value `me` for the currently authenticated user" + } + }, + "required": [ + "description", + "user_id" + ], + "example": { + "user_id": "3241a285-8329-4d69-8f3d-316e08cf140c" + } + } + } + } + }, + "tags": [ + "API Keys" + ], + "x-full-url": "https://api.stack-auth.com/api/v1/user-api-keys", + "responses": { + "200": { + "description": "Successful response", + "content": { + "application/json": { + "schema": { + "type": "object", + "properties": { + "value": { + "type": "string" + }, + "id": { + "type": "string" + }, + "description": { + "type": "string" + }, + "expires_at_millis": { + "type": "number" + }, + "manually_revoked_at_millis": { + "type": "number" + }, + "created_at_millis": { + "type": "number" + }, + "is_public": { + "type": "boolean" + }, + "type": { + "type": "string" + }, + "user_id": { + "type": "string", + "example": "3241a285-8329-4d69-8f3d-316e08cf140c", + "description": "The ID of the user, or the special value `me` for the currently authenticated user" + } + }, + "required": [ + "value", + "id", + "description", + "created_at_millis", + "is_public", + "type", + "user_id" + ] + } + } + } + } + } + } + }, + "/user-api-keys/check": { + "post": { + "summary": "Check user API key validity", + "description": "Validate a user API key", + "parameters": [], + "requestBody": { + "required": true, + "content": { + "application/json": { + "schema": { + "type": "object", + "properties": { + "api_key": { + "type": "string" + } + }, + "required": [ + "api_key" + ], + "example": {} + } + } + } + }, + "tags": [ + "API Keys" + ], + "x-full-url": "https://api.stack-auth.com/api/v1/user-api-keys/check", + "responses": { + "200": { + "description": "Successful response", + "content": { + "application/json": { + "schema": { + "type": "object", + "properties": { + "id": { + "type": "string" + }, + "description": { + "type": "string" + }, + "expires_at_millis": { + "type": "number" + }, + "manually_revoked_at_millis": { + "type": "number" + }, + "created_at_millis": { + "type": "number" + }, + "is_public": { + "type": "boolean" + }, + "value": { + "type": "object", + "properties": { + "last_four": { + "type": "string" + } + }, + "required": [ + "last_four" + ] + }, + "type": { + "type": "string" + }, + "user_id": { + "type": "string", + "example": "3241a285-8329-4d69-8f3d-316e08cf140c", + "description": "The ID of the user, or the special value `me` for the currently authenticated user" + } + }, + "required": [ + "id", + "description", + "created_at_millis", + "is_public", + "value", + "type", + "user_id" + ] + } + } + } + } + } + } + }, + "/user-api-keys/{api_key_id}": { + "get": { + "summary": "Get user API key details", + "description": "Get details of a specific user API key", + "parameters": [ + { + "name": "api_key_id", + "in": "path", + "schema": { + "type": "string" + }, + "required": true + } + ], + "tags": [ + "API Keys" + ], + "x-full-url": "https://api.stack-auth.com/api/v1/user-api-keys/{api_key_id}", + "responses": { + "200": { + "description": "Successful response", + "content": { + "application/json": { + "schema": { + "type": "object", + "properties": { + "id": { + "type": "string" + }, + "description": { + "type": "string" + }, + "expires_at_millis": { + "type": "number" + }, + "manually_revoked_at_millis": { + "type": "number" + }, + "created_at_millis": { + "type": "number" + }, + "is_public": { + "type": "boolean" + }, + "value": { + "type": "object", + "properties": { + "last_four": { + "type": "string" + } + }, + "required": [ + "last_four" + ] + }, + "type": { + "type": "string" + }, + "user_id": { + "type": "string", + "example": "3241a285-8329-4d69-8f3d-316e08cf140c", + "description": "The ID of the user, or the special value `me` for the currently authenticated user" + } + }, + "required": [ + "id", + "description", + "created_at_millis", + "is_public", + "value", + "type", + "user_id" + ] + } + } + } + } + } + }, + "patch": { + "summary": "Update user API key", + "description": "Update an user API key", + "parameters": [ + { + "name": "api_key_id", + "in": "path", + "schema": { + "type": "string" + }, + "required": true + } + ], + "requestBody": { + "required": true, + "content": { + "application/json": { + "schema": { + "type": "object", + "properties": { + "description": { + "type": "string" + }, + "revoked": { + "type": "boolean" + } + }, + "example": {} + } + } + } + }, + "tags": [ + "API Keys" + ], + "x-full-url": "https://api.stack-auth.com/api/v1/user-api-keys/{api_key_id}", + "responses": { + "200": { + "description": "Successful response", + "content": { + "application/json": { + "schema": { + "type": "object", + "properties": { + "id": { + "type": "string" + }, + "description": { + "type": "string" + }, + "expires_at_millis": { + "type": "number" + }, + "manually_revoked_at_millis": { + "type": "number" + }, + "created_at_millis": { + "type": "number" + }, + "is_public": { + "type": "boolean" + }, + "value": { + "type": "object", + "properties": { + "last_four": { + "type": "string" + } + }, + "required": [ + "last_four" + ] + }, + "type": { + "type": "string" + }, + "user_id": { + "type": "string", + "example": "3241a285-8329-4d69-8f3d-316e08cf140c", + "description": "The ID of the user, or the special value `me` for the currently authenticated user" + } + }, + "required": [ + "id", + "description", + "created_at_millis", + "is_public", + "value", + "type", + "user_id" + ] + } + } + } + } + } + } + }, + "/auth/cli": { + "post": { + "summary": "Initiate CLI authentication", + "description": "Create a new CLI authentication session and return polling and login codes", + "parameters": [], + "requestBody": { + "required": true, + "content": { + "application/json": { + "schema": { + "type": "object", + "properties": { + "expires_in_millis": { + "type": "number", + "default": 7200000 + }, + "anon_refresh_token": { + "type": "string" + } + }, + "example": {} + } + } + } + }, + "tags": [ + "CLI Authentication" + ], + "x-full-url": "https://api.stack-auth.com/api/v1/auth/cli", + "responses": { + "200": { + "description": "Successful response", + "content": { + "application/json": { + "schema": { + "type": "object", + "properties": { + "polling_code": { + "type": "string" + }, + "login_code": { + "type": "string" + }, + "expires_at": { + "type": "string" + } + }, + "required": [ + "polling_code", + "login_code", + "expires_at" + ] + } + } + } + } + } + } + }, + "/auth/cli/complete": { + "post": { + "summary": "Complete CLI authentication", + "description": "Inspect, claim, or complete a CLI authentication session", + "parameters": [], + "requestBody": { + "required": true, + "content": { + "application/json": { + "schema": { + "type": "object", + "properties": { + "login_code": { + "type": "string" + }, + "mode": { + "type": "string", + "default": "complete" + }, + "refresh_token": { + "type": "string" + } + }, + "required": [ + "login_code" + ], + "example": {} + } + } + } + }, + "tags": [ + "CLI Authentication" + ], + "x-full-url": "https://api.stack-auth.com/api/v1/auth/cli/complete", + "responses": { + "200": { + "description": "Successful response", + "content": { + "application/json": { + "schema": { + "type": "object", + "properties": { + "success": { + "type": "boolean" + } + }, + "required": [ + "success" + ] + } + } + } + } + } + } + }, + "/auth/cli/poll": { + "post": { + "summary": "Poll CLI authentication status", + "description": "Check the status of a CLI authentication session using the polling code", + "parameters": [], + "requestBody": { + "required": true, + "content": { + "application/json": { + "schema": { + "type": "object", + "properties": { + "polling_code": { + "type": "string" + } + }, + "required": [ + "polling_code" + ], + "example": {} + } + } + } + }, + "tags": [ + "CLI Authentication" + ], + "x-full-url": "https://api.stack-auth.com/api/v1/auth/cli/poll", + "responses": { + "200": { + "description": "Successful response", + "content": { + "application/json": { + "schema": { + "type": "object", + "properties": { + "status": { + "type": "string" + }, + "refresh_token": { + "type": "string" + } + }, + "required": [ + "status" + ] + } + } + } + }, + "201": { + "description": "Successful response", + "content": { + "application/json": { + "schema": { + "type": "object", + "properties": { + "status": { + "type": "string" + }, + "refresh_token": { + "type": "string" + } + }, + "required": [ + "status" + ] + } + } + } + } + } + } + }, + "/connected-accounts/{user_id}": { + "get": { + "summary": "List connected accounts", + "description": "Retrieves a list of all connected accounts for a user.", + "parameters": [ + { + "name": "user_id", + "in": "path", + "schema": { + "type": "string", + "example": "3241a285-8329-4d69-8f3d-316e08cf140c", + "description": "The ID of the user, or the special value `me` for the currently authenticated user" + }, + "description": "The ID of the user, or the special value `me` for the currently authenticated user", + "required": false + } + ], + "tags": [ + "Connected Accounts" + ], + "x-full-url": "https://api.stack-auth.com/api/v1/connected-accounts/{user_id}", + "responses": { + "200": { + "description": "Successful response", + "content": { + "application/json": { + "schema": { + "type": "object", + "properties": { + "items": { + "type": "array", + "items": { + "type": "object", + "properties": { + "user_id": { + "type": "string", + "example": "3241a285-8329-4d69-8f3d-316e08cf140c", + "description": "The ID of the user, or the special value `me` for the currently authenticated user" + }, + "provider": { + "type": "string", + "example": "google", + "description": "Provider config ID of the OAuth provider. This uniquely identifies the provider config on config.json file" + }, + "provider_account_id": { + "type": "string", + "example": "google-account-id-12345", + "description": "Account ID of the OAuth provider. This uniquely identifies the account on the provider side." + } + }, + "required": [ + "user_id", + "provider", + "provider_account_id" + ] + } + }, + "pagination": { + "type": "object", + "properties": { + "next_cursor": { + "type": "string", + "example": "b3d396b8-c574-4c80-97b3-50031675ceb2", + "description": "The cursor to fetch the next page of results. null if there is no next page." + } + }, + "required": [] + } + }, + "required": [ + "items" + ] + } + } + } + } + } + } + }, + "/contact-channels": { + "get": { + "summary": "List contact channels", + "description": "Retrieves a list of all contact channels for a user.", + "parameters": [ + { + "name": "user_id", + "in": "query", + "schema": { + "type": "string", + "example": "3241a285-8329-4d69-8f3d-316e08cf140c", + "description": "The ID of the user, or the special value `me` for the currently authenticated user" + }, + "description": "The ID of the user, or the special value `me` for the currently authenticated user", + "required": false + }, + { + "name": "contact_channel_id", + "in": "query", + "schema": { + "type": "string" + }, + "required": false + } + ], + "tags": [ + "Contact Channels" + ], + "x-full-url": "https://api.stack-auth.com/api/v1/contact-channels", + "responses": { + "200": { + "description": "Successful response", + "content": { + "application/json": { + "schema": { + "type": "object", + "properties": { + "items": { + "type": "array", + "items": { + "type": "object", + "properties": { + "user_id": { + "type": "string", + "example": "3241a285-8329-4d69-8f3d-316e08cf140c", + "description": "The unique identifier of the user" + }, + "id": { + "type": "string", + "example": "b3d396b8-c574-4c80-97b3-50031675ceb2", + "description": "The unique identifier of the contact channel" + }, + "value": { + "type": "string", + "example": "johndoe@example.com", + "description": "The value of the contact channel. For email, this should be a valid email address." + }, + "type": { + "type": "string", + "example": "email", + "description": "The type of the contact channel. Currently only \"email\" is supported." + }, + "used_for_auth": { + "type": "boolean", + "example": true, + "description": "Whether the contact channel is used for authentication. If this is set to `true`, the user will be able to sign in with the contact channel with password or OTP." + }, + "is_verified": { + "type": "boolean", + "example": true, + "description": "Whether the contact channel has been verified. If this is set to `true`, the contact channel has been verified to belong to the user." + }, + "is_primary": { + "type": "boolean", + "example": true, + "description": "Whether the contact channel is the primary contact channel. If this is set to `true`, it will be used for authentication and notifications by default." + } + }, + "required": [ + "user_id", + "id", + "value", + "type", + "used_for_auth", + "is_verified", + "is_primary" + ] + } + }, + "pagination": { + "type": "object", + "properties": { + "next_cursor": { + "type": "string", + "example": "b3d396b8-c574-4c80-97b3-50031675ceb2", + "description": "The cursor to fetch the next page of results. null if there is no next page." + } + }, + "required": [] + } + }, + "required": [ + "items" + ] + } + } + } + } + } + }, + "post": { + "summary": "Create a contact channel", + "description": "Add a new contact channel for a user.", + "parameters": [ + { + "name": "user_id", + "in": "query", + "schema": { + "type": "string", + "example": "3241a285-8329-4d69-8f3d-316e08cf140c", + "description": "The ID of the user, or the special value `me` for the currently authenticated user" + }, + "description": "The ID of the user, or the special value `me` for the currently authenticated user", + "required": false + }, + { + "name": "contact_channel_id", + "in": "query", + "schema": { + "type": "string" + }, + "required": false + } + ], + "requestBody": { + "required": true, + "content": { + "application/json": { + "schema": { + "type": "object", + "properties": { + "is_verified": { + "type": "boolean", + "example": true, + "description": "Whether the contact channel has been verified. If this is set to `true`, the contact channel has been verified to belong to the user." + }, + "user_id": { + "type": "string", + "example": "3241a285-8329-4d69-8f3d-316e08cf140c", + "description": "The ID of the user, or the special value `me` for the currently authenticated user" + }, + "value": { + "type": "string", + "example": "johndoe@example.com", + "description": "The value of the contact channel. For email, this should be a valid email address." + }, + "type": { + "type": "string", + "example": "email", + "description": "The type of the contact channel. Currently only \"email\" is supported." + }, + "used_for_auth": { + "type": "boolean", + "example": true, + "description": "Whether the contact channel is used for authentication. If this is set to `true`, the user will be able to sign in with the contact channel with password or OTP." + }, + "is_primary": { + "type": "boolean", + "example": true, + "description": "Whether the contact channel is the primary contact channel. If this is set to `true`, it will be used for authentication and notifications by default." + } + }, + "required": [ + "user_id", + "value", + "type", + "used_for_auth" + ], + "example": { + "is_verified": true, + "user_id": "3241a285-8329-4d69-8f3d-316e08cf140c", + "value": "johndoe@example.com", + "type": "email", + "used_for_auth": true, + "is_primary": true + } + } + } + } + }, + "tags": [ + "Contact Channels" + ], + "x-full-url": "https://api.stack-auth.com/api/v1/contact-channels", + "responses": { + "201": { + "description": "Successful response", + "content": { + "application/json": { + "schema": { + "type": "object", + "properties": { + "user_id": { + "type": "string", + "example": "3241a285-8329-4d69-8f3d-316e08cf140c", + "description": "The unique identifier of the user" + }, + "id": { + "type": "string", + "example": "b3d396b8-c574-4c80-97b3-50031675ceb2", + "description": "The unique identifier of the contact channel" + }, + "value": { + "type": "string", + "example": "johndoe@example.com", + "description": "The value of the contact channel. For email, this should be a valid email address." + }, + "type": { + "type": "string", + "example": "email", + "description": "The type of the contact channel. Currently only \"email\" is supported." + }, + "used_for_auth": { + "type": "boolean", + "example": true, + "description": "Whether the contact channel is used for authentication. If this is set to `true`, the user will be able to sign in with the contact channel with password or OTP." + }, + "is_verified": { + "type": "boolean", + "example": true, + "description": "Whether the contact channel has been verified. If this is set to `true`, the contact channel has been verified to belong to the user." + }, + "is_primary": { + "type": "boolean", + "example": true, + "description": "Whether the contact channel is the primary contact channel. If this is set to `true`, it will be used for authentication and notifications by default." + } + }, + "required": [ + "user_id", + "id", + "value", + "type", + "used_for_auth", + "is_verified", + "is_primary" + ] + } + } + } + } + } + } + }, + "/contact-channels/verify": { + "post": { + "summary": "Verify an email", + "description": "Verify an email address of a user", + "parameters": [], + "requestBody": { + "required": true, + "content": { + "application/json": { + "schema": { + "type": "object", + "properties": { + "code": { + "type": "string", + "example": "u3h6gn4w24pqc8ya679inrhjwh1rybth6a7thurqhnpf2", + "description": "A 45 character code" + } + }, + "required": [ + "code" + ], + "example": { + "code": "u3h6gn4w24pqc8ya679inrhjwh1rybth6a7thurqhnpf2" + } + } + } + } + }, + "tags": [ + "Contact Channels" + ], + "x-full-url": "https://api.stack-auth.com/api/v1/contact-channels/verify", + "responses": { + "200": { + "description": "Successful response", + "content": { + "application/json": { + "schema": { + "type": "object", + "properties": { + "success": { + "type": "boolean", + "description": "Always equal to true.", + "example": true + } + }, + "required": [ + "success" + ] + } + } + } + } + } + } + }, + "/contact-channels/verify/check-code": { + "post": { + "summary": "Check email verification code", + "description": "Check if an email verification code is valid without using it", + "parameters": [], + "requestBody": { + "required": true, + "content": { + "application/json": { + "schema": { + "type": "object", + "properties": { + "code": { + "type": "string", + "example": "u3h6gn4w24pqc8ya679inrhjwh1rybth6a7thurqhnpf2", + "description": "A 45 character code" + } + }, + "required": [ + "code" + ], + "example": { + "code": "u3h6gn4w24pqc8ya679inrhjwh1rybth6a7thurqhnpf2" + } + } + } + } + }, + "tags": [ + "Contact Channels" + ], + "x-full-url": "https://api.stack-auth.com/api/v1/contact-channels/verify/check-code", + "responses": { + "200": { + "description": "Successful response", + "content": { + "application/json": { + "schema": { + "type": "object", + "properties": { + "is_code_valid": { + "type": "boolean" + } + }, + "required": [ + "is_code_valid" + ] + } + } + } + } + } + } + }, + "/contact-channels/{user_id}/{contact_channel_id}": { + "get": { + "summary": "Get a contact channel", + "description": "Retrieves a specific contact channel by the user ID and the contact channel ID.", + "parameters": [ + { + "name": "user_id", + "in": "query", + "schema": { + "type": "string", + "example": "3241a285-8329-4d69-8f3d-316e08cf140c", + "description": "The ID of the user, or the special value `me` for the currently authenticated user" + }, + "description": "The ID of the user, or the special value `me` for the currently authenticated user", + "required": false + }, + { + "name": "contact_channel_id", + "in": "query", + "schema": { + "type": "string" + }, + "required": false + }, + { + "name": "user_id", + "in": "path", + "schema": { + "type": "string", + "example": "me", + "description": "the user that the contact channel belongs to" + }, + "description": "the user that the contact channel belongs to", + "required": true + }, + { + "name": "contact_channel_id", + "in": "path", + "schema": { + "type": "string", + "example": "b3d396b8-c574-4c80-97b3-50031675ceb2", + "description": "the target contact channel" + }, + "description": "the target contact channel", + "required": true + } + ], + "tags": [ + "Contact Channels" + ], + "x-full-url": "https://api.stack-auth.com/api/v1/contact-channels/{user_id}/{contact_channel_id}", + "responses": { + "200": { + "description": "Successful response", + "content": { + "application/json": { + "schema": { + "type": "object", + "properties": { + "user_id": { + "type": "string", + "example": "3241a285-8329-4d69-8f3d-316e08cf140c", + "description": "The unique identifier of the user" + }, + "id": { + "type": "string", + "example": "b3d396b8-c574-4c80-97b3-50031675ceb2", + "description": "The unique identifier of the contact channel" + }, + "value": { + "type": "string", + "example": "johndoe@example.com", + "description": "The value of the contact channel. For email, this should be a valid email address." + }, + "type": { + "type": "string", + "example": "email", + "description": "The type of the contact channel. Currently only \"email\" is supported." + }, + "used_for_auth": { + "type": "boolean", + "example": true, + "description": "Whether the contact channel is used for authentication. If this is set to `true`, the user will be able to sign in with the contact channel with password or OTP." + }, + "is_verified": { + "type": "boolean", + "example": true, + "description": "Whether the contact channel has been verified. If this is set to `true`, the contact channel has been verified to belong to the user." + }, + "is_primary": { + "type": "boolean", + "example": true, + "description": "Whether the contact channel is the primary contact channel. If this is set to `true`, it will be used for authentication and notifications by default." + } + }, + "required": [ + "user_id", + "id", + "value", + "type", + "used_for_auth", + "is_verified", + "is_primary" + ] + } + } + } + } + } + }, + "delete": { + "summary": "Delete a contact channel", + "description": "Removes a contact channel for a given user.", + "parameters": [ + { + "name": "user_id", + "in": "query", + "schema": { + "type": "string", + "example": "3241a285-8329-4d69-8f3d-316e08cf140c", + "description": "The ID of the user, or the special value `me` for the currently authenticated user" + }, + "description": "The ID of the user, or the special value `me` for the currently authenticated user", + "required": false + }, + { + "name": "contact_channel_id", + "in": "query", + "schema": { + "type": "string" + }, + "required": false + }, + { + "name": "user_id", + "in": "path", + "schema": { + "type": "string", + "example": "me", + "description": "the user that the contact channel belongs to" + }, + "description": "the user that the contact channel belongs to", + "required": true + }, + { + "name": "contact_channel_id", + "in": "path", + "schema": { + "type": "string", + "example": "b3d396b8-c574-4c80-97b3-50031675ceb2", + "description": "the target contact channel" + }, + "description": "the target contact channel", + "required": true + } + ], + "tags": [ + "Contact Channels" + ], + "x-full-url": "https://api.stack-auth.com/api/v1/contact-channels/{user_id}/{contact_channel_id}", + "responses": { + "200": { + "description": "Successful response", + "content": { + "application/json": { + "schema": { + "type": "object", + "properties": { + "success": { + "type": "boolean", + "description": "Always equal to true.", + "example": true + } + }, + "required": [ + "success" + ] + } + } + } + } + } + }, + "patch": { + "summary": "Update a contact channel", + "description": "Updates an existing contact channel. Only the values provided will be updated.", + "parameters": [ + { + "name": "user_id", + "in": "query", + "schema": { + "type": "string", + "example": "3241a285-8329-4d69-8f3d-316e08cf140c", + "description": "The ID of the user, or the special value `me` for the currently authenticated user" + }, + "description": "The ID of the user, or the special value `me` for the currently authenticated user", + "required": false + }, + { + "name": "contact_channel_id", + "in": "query", + "schema": { + "type": "string" + }, + "required": false + }, + { + "name": "user_id", + "in": "path", + "schema": { + "type": "string", + "example": "me", + "description": "the user that the contact channel belongs to" + }, + "description": "the user that the contact channel belongs to", + "required": true + }, + { + "name": "contact_channel_id", + "in": "path", + "schema": { + "type": "string", + "example": "b3d396b8-c574-4c80-97b3-50031675ceb2", + "description": "the target contact channel" + }, + "description": "the target contact channel", + "required": true + } + ], + "requestBody": { + "required": true, + "content": { + "application/json": { + "schema": { + "type": "object", + "properties": { + "is_verified": { + "type": "boolean", + "example": true, + "description": "Whether the contact channel has been verified. If this is set to `true`, the contact channel has been verified to belong to the user." + }, + "value": { + "type": "string", + "example": "johndoe@example.com", + "description": "The value of the contact channel. For email, this should be a valid email address." + }, + "type": { + "type": "string", + "example": "email", + "description": "The type of the contact channel. Currently only \"email\" is supported." + }, + "used_for_auth": { + "type": "boolean", + "example": true, + "description": "Whether the contact channel is used for authentication. If this is set to `true`, the user will be able to sign in with the contact channel with password or OTP." + }, + "is_primary": { + "type": "boolean", + "example": true, + "description": "Whether the contact channel is the primary contact channel. If this is set to `true`, it will be used for authentication and notifications by default." + } + }, + "example": { + "is_verified": true, + "value": "johndoe@example.com", + "type": "email", + "used_for_auth": true, + "is_primary": true + } + } + } + } + }, + "tags": [ + "Contact Channels" + ], + "x-full-url": "https://api.stack-auth.com/api/v1/contact-channels/{user_id}/{contact_channel_id}", + "responses": { + "200": { + "description": "Successful response", + "content": { + "application/json": { + "schema": { + "type": "object", + "properties": { + "user_id": { + "type": "string", + "example": "3241a285-8329-4d69-8f3d-316e08cf140c", + "description": "The unique identifier of the user" + }, + "id": { + "type": "string", + "example": "b3d396b8-c574-4c80-97b3-50031675ceb2", + "description": "The unique identifier of the contact channel" + }, + "value": { + "type": "string", + "example": "johndoe@example.com", + "description": "The value of the contact channel. For email, this should be a valid email address." + }, + "type": { + "type": "string", + "example": "email", + "description": "The type of the contact channel. Currently only \"email\" is supported." + }, + "used_for_auth": { + "type": "boolean", + "example": true, + "description": "Whether the contact channel is used for authentication. If this is set to `true`, the user will be able to sign in with the contact channel with password or OTP." + }, + "is_verified": { + "type": "boolean", + "example": true, + "description": "Whether the contact channel has been verified. If this is set to `true`, the contact channel has been verified to belong to the user." + }, + "is_primary": { + "type": "boolean", + "example": true, + "description": "Whether the contact channel is the primary contact channel. If this is set to `true`, it will be used for authentication and notifications by default." + } + }, + "required": [ + "user_id", + "id", + "value", + "type", + "used_for_auth", + "is_verified", + "is_primary" + ] + } + } + } + } + } + } + }, + "/contact-channels/{user_id}/{contact_channel_id}/send-verification-code": { + "post": { + "summary": "Send contact channel verification code", + "description": "Send a code to the user's contact channel for verifying the contact channel.", + "parameters": [ + { + "name": "user_id", + "in": "path", + "schema": { + "type": "string", + "example": "me", + "description": "The user to send the verification code to." + }, + "description": "The user to send the verification code to.", + "required": true + }, + { + "name": "contact_channel_id", + "in": "path", + "schema": { + "type": "string", + "example": "b3d396b8-c574-4c80-97b3-50031675ceb2", + "description": "The contact channel to send the verification code to." + }, + "description": "The contact channel to send the verification code to.", + "required": true + } + ], + "requestBody": { + "required": true, + "content": { + "application/json": { + "schema": { + "type": "object", + "properties": { + "callback_url": { + "type": "string", + "example": "https://example.com/handler/email-verification", + "description": "The base callback URL to construct a verification link for the verification e-mail. A query parameter `code` with the verification code will be appended to it. The page should then make a request to the `/contact-channels/verify` endpoint." + } + }, + "required": [ + "callback_url" + ], + "example": { + "callback_url": "https://example.com/handler/email-verification" + } + } + } + } + }, + "tags": [ + "Contact Channels" + ], + "x-full-url": "https://api.stack-auth.com/api/v1/contact-channels/{user_id}/{contact_channel_id}/send-verification-code", + "responses": { + "200": { + "description": "Successful response", + "content": { + "application/json": { + "schema": { + "type": "object", + "properties": { + "success": { + "type": "boolean", + "description": "Always equal to true.", + "example": true + } + }, + "required": [ + "success" + ] + } + } + } + } + } + } + }, + "/data-vault/stores/{id}/get": { + "post": { + "summary": "Retrieve encrypted value from data vault", + "description": "Retrieves and decrypts a value from the data vault using a hashed key", + "parameters": [ + { + "name": "id", + "in": "path", + "schema": { + "type": "string" + }, + "required": true + } + ], + "requestBody": { + "required": true, + "content": { + "application/json": { + "schema": { + "type": "object", + "properties": { + "hashed_key": { + "type": "string" + } + }, + "required": [ + "hashed_key" + ], + "example": {} + } + } + } + }, + "tags": [ + "DataVault" + ], + "x-full-url": "https://api.stack-auth.com/api/v1/data-vault/stores/{id}/get", + "responses": { + "200": { + "description": "Successful response", + "content": { + "application/json": { + "schema": { + "type": "object", + "properties": { + "encrypted_value": { + "type": "string" + } + }, + "required": [ + "encrypted_value" + ] + } + } + } + } + } + } + }, + "/data-vault/stores/{id}/set": { + "post": { + "summary": "Store encrypted value in data vault", + "description": "Stores a hashed key and encrypted value in the data vault for a specific store", + "parameters": [ + { + "name": "id", + "in": "path", + "schema": { + "type": "string" + }, + "required": true + } + ], + "requestBody": { + "required": true, + "content": { + "application/json": { + "schema": { + "type": "object", + "properties": { + "hashed_key": { + "type": "string" + }, + "encrypted_value": { + "type": "string" + } + }, + "required": [ + "hashed_key", + "encrypted_value" + ], + "example": {} + } + } + } + }, + "tags": [ + "DataVault" + ], + "x-full-url": "https://api.stack-auth.com/api/v1/data-vault/stores/{id}/set", + "responses": { + "200": { + "description": "Successful response", + "content": { + "application/json": { + "schema": { + "type": "object", + "properties": { + "success": { + "type": "boolean", + "description": "Always equal to true.", + "example": true + } + }, + "required": [ + "success" + ] + } + } + } + } + } + } + }, + "/emails/capacity-boost": { + "post": { + "summary": "Activate email capacity boost", + "description": "Temporarily increases email capacity by 4x for 4 hours.", + "parameters": [], + "tags": [ + "Emails" + ], + "x-full-url": "https://api.stack-auth.com/api/v1/emails/capacity-boost", + "responses": { + "200": { + "description": "Successful response", + "content": { + "application/json": { + "schema": { + "type": "object", + "properties": { + "expires_at": { + "type": "string" + } + }, + "required": [ + "expires_at" + ] + } + } + } + } + } + } + }, + "/emails/delivery-info": { + "get": { + "summary": "Get email delivery info", + "description": "Returns delivery statistics and capacity information for the current tenancy.", + "parameters": [], + "tags": [ + "Emails" + ], + "x-full-url": "https://api.stack-auth.com/api/v1/emails/delivery-info", + "responses": { + "200": { + "description": "Successful response", + "content": { + "application/json": { + "schema": { + "type": "object", + "properties": { + "stats": { + "type": "object", + "properties": { + "hour": { + "type": "object", + "properties": { + "sent": { + "type": "number" + }, + "bounced": { + "type": "number" + }, + "marked_as_spam": { + "type": "number" + } + }, + "required": [ + "sent", + "bounced", + "marked_as_spam" + ] + }, + "day": { + "type": "object", + "properties": { + "sent": { + "type": "number" + }, + "bounced": { + "type": "number" + }, + "marked_as_spam": { + "type": "number" + } + }, + "required": [ + "sent", + "bounced", + "marked_as_spam" + ] + }, + "week": { + "type": "object", + "properties": { + "sent": { + "type": "number" + }, + "bounced": { + "type": "number" + }, + "marked_as_spam": { + "type": "number" + } + }, + "required": [ + "sent", + "bounced", + "marked_as_spam" + ] + }, + "month": { + "type": "object", + "properties": { + "sent": { + "type": "number" + }, + "bounced": { + "type": "number" + }, + "marked_as_spam": { + "type": "number" + } + }, + "required": [ + "sent", + "bounced", + "marked_as_spam" + ] + } + }, + "required": [ + "hour", + "day", + "week", + "month" + ] + }, + "capacity": { + "type": "object", + "properties": { + "rate_per_second": { + "type": "number" + }, + "boost_multiplier": { + "type": "number" + }, + "penalty_factor": { + "type": "number" + }, + "is_boost_active": { + "type": "boolean" + }, + "boost_expires_at": { + "type": "string" + } + }, + "required": [ + "rate_per_second", + "boost_multiplier", + "penalty_factor", + "is_boost_active" + ] + } + }, + "required": [ + "stats", + "capacity" + ] + } + } + } + } + } + } + }, + "/emails/notification-preference/{user_id}": { + "get": { + "summary": "List notification preferences", + "description": "Get all notification preferences for a user, showing which notification categories are enabled or disabled.", + "parameters": [ + { + "name": "user_id", + "in": "path", + "schema": { + "type": "string", + "example": "3241a285-8329-4d69-8f3d-316e08cf140c", + "description": "The ID of the user, or the special value `me` for the currently authenticated user" + }, + "description": "The ID of the user, or the special value `me` for the currently authenticated user", + "required": false + } + ], + "tags": [ + "Emails" + ], + "x-full-url": "https://api.stack-auth.com/api/v1/emails/notification-preference/{user_id}", + "responses": { + "200": { + "description": "Successful response", + "content": { + "application/json": { + "schema": { + "type": "object", + "properties": { + "items": { + "type": "array", + "items": { + "type": "object", + "properties": { + "notification_category_id": { + "type": "string" + }, + "notification_category_name": { + "type": "string" + }, + "enabled": { + "type": "boolean" + }, + "can_disable": { + "type": "boolean" + } + }, + "required": [ + "notification_category_id", + "notification_category_name", + "enabled", + "can_disable" + ] + } + }, + "pagination": { + "type": "object", + "properties": { + "next_cursor": { + "type": "string", + "example": "b3d396b8-c574-4c80-97b3-50031675ceb2", + "description": "The cursor to fetch the next page of results. null if there is no next page." + } + }, + "required": [] + } + }, + "required": [ + "items" + ] + } + } + } + } + } + } + }, + "/emails/notification-preference/{user_id}/{notification_category_id}": { + "patch": { + "summary": "Update notification preference", + "description": "Enable or disable a specific notification category for a user.", + "parameters": [ + { + "name": "user_id", + "in": "path", + "schema": { + "type": "string", + "example": "3241a285-8329-4d69-8f3d-316e08cf140c", + "description": "The ID of the user, or the special value `me` for the currently authenticated user" + }, + "description": "The ID of the user, or the special value `me` for the currently authenticated user", + "required": true + }, + { + "name": "notification_category_id", + "in": "path", + "schema": { + "type": "string" + }, + "required": false + } + ], + "requestBody": { + "required": true, + "content": { + "application/json": { + "schema": { + "type": "object", + "properties": { + "enabled": { + "type": "boolean" + } + }, + "required": [ + "enabled" + ], + "example": {} + } + } + } + }, + "tags": [ + "Emails" + ], + "x-full-url": "https://api.stack-auth.com/api/v1/emails/notification-preference/{user_id}/{notification_category_id}", + "responses": { + "200": { + "description": "Successful response", + "content": { + "application/json": { + "schema": { + "type": "object", + "properties": { + "notification_category_id": { + "type": "string" + }, + "notification_category_name": { + "type": "string" + }, + "enabled": { + "type": "boolean" + }, + "can_disable": { + "type": "boolean" + } + }, + "required": [ + "notification_category_id", + "notification_category_name", + "enabled", + "can_disable" + ] + } + } + } + } + } + } + }, + "/emails/outbox": { + "get": { + "summary": "List email outbox", + "description": "Lists all emails in the outbox with optional filtering by status or simple_status.", + "parameters": [ + { + "name": "status", + "in": "query", + "schema": { + "type": "string" + }, + "required": false + }, + { + "name": "simple_status", + "in": "query", + "schema": { + "type": "string" + }, + "required": false + }, + { + "name": "limit", + "in": "query", + "schema": { + "type": "string", + "description": "The maximum number of items to return. Maximum allowed is 100" + }, + "description": "The maximum number of items to return. Maximum allowed is 100", + "required": false + }, + { + "name": "cursor", + "in": "query", + "schema": { + "type": "string", + "description": "The cursor to start the result set from (email ID)" + }, + "description": "The cursor to start the result set from (email ID)", + "required": false + } + ], + "tags": [ + "Emails" + ], + "x-full-url": "https://api.stack-auth.com/api/v1/emails/outbox", + "responses": { + "200": { + "description": "Successful response", + "content": { + "application/json": { + "schema": { + "type": "object", + "properties": { + "items": { + "type": "array", + "items": { + "type": "object" + } + }, + "pagination": { + "type": "object", + "properties": { + "next_cursor": { + "type": "string", + "example": "b3d396b8-c574-4c80-97b3-50031675ceb2", + "description": "The cursor to fetch the next page of results. null if there is no next page." + } + }, + "required": [] + } + }, + "required": [ + "items" + ] + } + } + } + } + } + } + }, + "/emails/outbox/{id}": { + "get": { + "summary": "Get email outbox entry", + "description": "Gets a single email from the outbox by ID.", + "parameters": [ + { + "name": "status", + "in": "query", + "schema": { + "type": "string" + }, + "required": false + }, + { + "name": "simple_status", + "in": "query", + "schema": { + "type": "string" + }, + "required": false + }, + { + "name": "id", + "in": "path", + "schema": { + "type": "string" + }, + "required": false + } + ], + "tags": [ + "Emails" + ], + "x-full-url": "https://api.stack-auth.com/api/v1/emails/outbox/{id}", + "responses": { + "200": { + "description": "Successful response", + "content": { + "application/json": { + "schema": {} + } + } + } + } + }, + "patch": { + "summary": "Update email outbox entry", + "description": "Updates an email in the outbox. Can be used to edit email content, pause/resume, or cancel emails. Only emails in editable states (`paused`, `preparing`, `rendering`, `render-error`, `scheduled`, `queued`, `server-error`) can be modified.", + "parameters": [ + { + "name": "status", + "in": "query", + "schema": { + "type": "string" + }, + "required": false + }, + { + "name": "simple_status", + "in": "query", + "schema": { + "type": "string" + }, + "required": false + }, + { + "name": "id", + "in": "path", + "schema": { + "type": "string" + }, + "required": false + } + ], + "requestBody": { + "required": true, + "content": { + "application/json": { + "schema": { + "type": "object", + "properties": { + "tsx_source": { + "type": "string" + }, + "theme_id": { + "type": "string" + }, + "to": { + "type": "object" + }, + "variables": { + "type": "object", + "properties": {}, + "required": [] + }, + "skip_deliverability_check": { + "type": "boolean" + }, + "scheduled_at_millis": { + "type": "number" + }, + "is_paused": { + "type": "boolean" + }, + "cancel": { + "type": "boolean" + } + }, + "example": {} + } + } + } + }, + "tags": [ + "Emails" + ], + "x-full-url": "https://api.stack-auth.com/api/v1/emails/outbox/{id}", + "responses": { + "200": { + "description": "Successful response", + "content": { + "application/json": { + "schema": {} + } + } + } + } + } + }, + "/emails/send-email": { + "post": { + "summary": "Send email", + "description": "Send an email to a list of users. The content field should contain either {html} for HTML emails, {template_id, variables} for template-based emails, or {draft_id} for a draft email.", + "parameters": [], + "tags": [ + "Emails" + ], + "x-full-url": "https://api.stack-auth.com/api/v1/emails/send-email", + "responses": { + "200": { + "description": "Successful response", + "content": { + "application/json": { + "schema": { + "type": "object", + "properties": { + "results": { + "type": "array", + "items": { + "type": "object", + "properties": { + "user_id": { + "type": "string" + } + }, + "required": [ + "user_id" + ] + } + } + }, + "required": [ + "results" + ] + } + } + } + } + } + } + }, + "/internal/feature-requests": { + "get": { + "summary": "Get feature requests", + "description": "Fetch all feature requests with upvote status for the current user", + "parameters": [], + "tags": [ + "Internal" + ], + "x-full-url": "https://api.stack-auth.com/api/v1/internal/feature-requests", + "responses": { + "200": { + "description": "Successful response", + "content": { + "application/json": { + "schema": { + "type": "object", + "properties": { + "posts": { + "type": "array", + "items": { + "type": "object", + "properties": { + "id": { + "type": "string" + }, + "title": { + "type": "string" + }, + "content": { + "type": "string" + }, + "upvotes": { + "type": "number" + }, + "date": { + "type": "string" + }, + "postStatus": { + "type": "object", + "properties": { + "name": { + "type": "string" + }, + "color": { + "type": "string" + } + }, + "required": [ + "name", + "color" + ] + }, + "userHasUpvoted": { + "type": "boolean" + } + }, + "required": [ + "id", + "title", + "upvotes", + "date", + "userHasUpvoted" + ] + } + } + }, + "required": [ + "posts" + ] + } + } + } + } + } + }, + "post": { + "summary": "Create feature request", + "description": "Create a new feature request", + "parameters": [], + "requestBody": { + "required": true, + "content": { + "application/json": { + "schema": { + "type": "object", + "properties": { + "title": { + "type": "string" + }, + "content": { + "type": "string" + }, + "category": { + "type": "string" + }, + "tags": { + "type": "array", + "items": { + "type": "string" + } + }, + "commentsAllowed": { + "type": "boolean" + }, + "customInputValues": { + "type": "object", + "properties": {}, + "required": [] + } + }, + "required": [ + "title" + ], + "example": {} + } + } + } + }, + "tags": [ + "Internal" + ], + "x-full-url": "https://api.stack-auth.com/api/v1/internal/feature-requests", + "responses": { + "200": { + "description": "Successful response", + "content": { + "application/json": { + "schema": { + "type": "object", + "properties": { + "success": { + "type": "boolean" + }, + "id": { + "type": "string" + } + }, + "required": [ + "success" + ] + } + } + } + } + } + } + }, + "/internal/feature-requests/{featureRequestId}/upvote": { + "post": { + "summary": "Toggle upvote on feature request", + "description": "Toggle upvote on a feature request for the current user", + "parameters": [ + { + "name": "featureRequestId", + "in": "path", + "schema": { + "type": "string" + }, + "required": true + } + ], + "requestBody": { + "required": true, + "content": { + "application/json": { + "schema": { + "type": "object", + "properties": {}, + "example": {} + } + } + } + }, + "tags": [ + "Internal" + ], + "x-full-url": "https://api.stack-auth.com/api/v1/internal/feature-requests/{featureRequestId}/upvote", + "responses": { + "200": { + "description": "Successful response", + "content": { + "application/json": { + "schema": { + "type": "object", + "properties": { + "success": { + "type": "boolean" + }, + "upvoted": { + "type": "boolean" + } + }, + "required": [ + "success" + ] + } + } + } + } + } + } + }, + "/internal/feedback": { + "post": { + "summary": "Submit support feedback", + "description": "Send a support feedback message to the internal Stack Auth inbox. Auth is optional — works from both the dashboard (authenticated) and the dev tool (unauthenticated).", + "parameters": [], + "requestBody": { + "required": true, + "content": { + "application/json": { + "schema": { + "type": "object", + "properties": { + "name": { + "type": "string" + }, + "email": { + "type": "string" + }, + "message": { + "type": "string" + }, + "feedback_type": { + "type": "string" + } + }, + "required": [ + "email", + "message" + ], + "example": {} + } + } + } + }, + "tags": [ + "Internal" + ], + "x-full-url": "https://api.stack-auth.com/api/v1/internal/feedback", + "responses": { + "200": { + "description": "Successful response", + "content": { + "application/json": { + "schema": { + "type": "object", + "properties": { + "success": { + "type": "boolean" + } + }, + "required": [ + "success" + ] + } + } + } + } + } + } + }, + "/internal/preview/create-project": { + "post": { + "summary": "Create a preview project", + "description": "Creates a new project pre-filled with dummy data for the preview environment. Only available when NEXT_PUBLIC_STACK_IS_PREVIEW=true.", + "parameters": [], + "requestBody": { + "required": true, + "content": { + "application/json": { + "schema": { + "type": "object", + "properties": {}, + "example": {} + } + } + } + }, + "tags": [ + "Internal" + ], + "x-full-url": "https://api.stack-auth.com/api/v1/internal/preview/create-project", + "responses": { + "200": { + "description": "Successful response", + "content": { + "application/json": { + "schema": { + "type": "object", + "properties": { + "project_id": { + "type": "string" + } + }, + "required": [ + "project_id" + ] + } + } + } + } + } + } + }, + "/auth/oauth/authorize/{provider_id}": { + "get": { + "summary": "OAuth authorize endpoint", + "description": "This endpoint is used to initiate the OAuth authorization flow. there are two purposes for this endpoint: 1. Authenticate a user with an OAuth provider. 2. Link an existing user with an OAuth provider.", + "parameters": [ + { + "name": "type", + "in": "query", + "schema": { + "type": "string", + "default": "authenticate" + }, + "required": false + }, + { + "name": "token", + "in": "query", + "schema": { + "type": "string", + "default": "" + }, + "required": false + }, + { + "name": "provider_scope", + "in": "query", + "schema": { + "type": "string" + }, + "required": false + }, + { + "name": "error_redirect_uri", + "in": "query", + "schema": { + "type": "string" + }, + "required": false + }, + { + "name": "after_callback_redirect_url", + "in": "query", + "schema": { + "type": "string" + }, + "required": false + }, + { + "name": "stack_response_mode", + "in": "query", + "schema": { + "type": "string", + "default": "redirect" + }, + "required": false + }, + { + "name": "bot_challenge_token", + "in": "query", + "schema": { + "type": "string" + }, + "required": false + }, + { + "name": "bot_challenge_phase", + "in": "query", + "schema": { + "type": "string" + }, + "required": false + }, + { + "name": "bot_challenge_unavailable", + "in": "query", + "schema": { + "type": "string" + }, + "required": false + }, + { + "name": "client_id", + "in": "query", + "schema": { + "type": "string" + }, + "required": true + }, + { + "name": "client_secret", + "in": "query", + "schema": { + "type": "string" + }, + "required": true + }, + { + "name": "redirect_uri", + "in": "query", + "schema": { + "type": "string" + }, + "required": true + }, + { + "name": "scope", + "in": "query", + "schema": { + "type": "string" + }, + "required": true + }, + { + "name": "state", + "in": "query", + "schema": { + "type": "string" + }, + "required": true + }, + { + "name": "grant_type", + "in": "query", + "schema": { + "type": "string" + }, + "required": true + }, + { + "name": "code_challenge", + "in": "query", + "schema": { + "type": "string" + }, + "required": true + }, + { + "name": "code_challenge_method", + "in": "query", + "schema": { + "type": "string" + }, + "required": true + }, + { + "name": "response_type", + "in": "query", + "schema": { + "type": "string" + }, + "required": true + }, + { + "name": "provider_id", + "in": "path", + "schema": { + "type": "string" + }, + "required": true + } + ], + "tags": [ + "Oauth" + ], + "x-full-url": "https://api.stack-auth.com/api/v1/auth/oauth/authorize/{provider_id}", + "responses": { + "200": { + "description": "Successful response", + "content": { + "application/json": { + "schema": { + "type": "object", + "properties": { + "location": { + "type": "string" + } + }, + "required": [ + "location" + ] + } + } + } + }, + "307": { + "description": "Successful response", + "content": { + "text/plain": { + "schema": { + "type": "string" + } + } + } + } + } + } + }, + "/auth/oauth/cross-domain/authorize": { + "post": { + "summary": "Create cross-domain auth handoff redirect", + "description": "Creates a one-time OAuth authorization code redirect for cross-domain sign-in handoff using PKCE.", + "parameters": [ + { + "name": "x-stack-publishable-client-key", + "in": "header", + "schema": { + "type": "string" + }, + "required": true + }, + { + "name": "x-stack-refresh-token", + "in": "header", + "schema": { + "type": "string" + }, + "required": true + } + ], + "requestBody": { + "required": true, + "content": { + "application/json": { + "schema": { + "type": "object", + "properties": { + "redirect_uri": { + "type": "string" + }, + "state": { + "type": "string" + }, + "code_challenge": { + "type": "string" + }, + "code_challenge_method": { + "type": "string", + "default": "S256" + }, + "after_callback_redirect_url": { + "type": "string" + } + }, + "required": [ + "redirect_uri", + "state", + "code_challenge" + ], + "example": {} + } + } + } + }, + "tags": [ + "Oauth" + ], + "x-full-url": "https://api.stack-auth.com/api/v1/auth/oauth/cross-domain/authorize", + "responses": { + "200": { + "description": "Successful response", + "content": { + "application/json": { + "schema": { + "type": "object", + "properties": { + "redirect_url": { + "type": "string" + } + }, + "required": [ + "redirect_url" + ] + } + } + } + } + } + } + }, + "/auth/oauth/token": { + "post": { + "summary": "OAuth token endpoints", + "description": "This endpoint is used to exchange an authorization code or refresh token for an access token.", + "parameters": [], + "requestBody": { + "required": true, + "content": { + "application/json": { + "schema": { + "type": "object", + "properties": { + "grant_type": { + "type": "string" + }, + "client_id": { + "type": "string" + }, + "client_secret": { + "type": "string" + } + }, + "required": [ + "grant_type" + ], + "example": {} + } + } + } + }, + "tags": [ + "Oauth" + ], + "x-full-url": "https://api.stack-auth.com/api/v1/auth/oauth/token", + "responses": { + "200": { + "description": "Successful response", + "content": { + "application/json": { + "schema": {} + } + } + } + } + } + }, + "/oauth-providers": { + "get": { + "summary": "List OAuth providers", + "description": "Retrieves a list of all OAuth providers for a user.", + "parameters": [ + { + "name": "user_id", + "in": "query", + "schema": { + "type": "string" + }, + "required": false + } + ], + "tags": [ + "Oauth" + ], + "x-full-url": "https://api.stack-auth.com/api/v1/oauth-providers", + "responses": { + "200": { + "description": "Successful response", + "content": { + "application/json": { + "schema": { + "type": "object", + "properties": { + "items": { + "type": "array", + "items": { + "type": "object", + "properties": { + "account_id": { + "type": "string", + "example": "google-account-id-12345", + "description": "Account ID of the OAuth provider. This uniquely identifies the account on the provider side." + }, + "user_id": { + "type": "string", + "example": "3241a285-8329-4d69-8f3d-316e08cf140c", + "description": "The ID of the user, or the special value `me` for the currently authenticated user" + }, + "id": { + "type": "string", + "example": "b3d396b8-c574-4c80-97b3-50031675ceb2", + "description": "The unique identifier of the OAuth provider" + }, + "email": { + "type": "string", + "example": "test@gmail.com", + "description": "Email of the OAuth provider. This is used to display and identify the OAuth provider in the UI." + }, + "provider_config_id": { + "type": "string", + "example": "google", + "description": "Provider config ID of the OAuth provider. This uniquely identifies the provider config on config.json file" + }, + "type": { + "type": "string", + "example": "google", + "description": "OAuth provider type, one of `google`, `github`, `microsoft`, `spotify`, `facebook`, `discord`, `gitlab`, `bitbucket`, `linkedin`, `apple`, `x`, `twitch`" + }, + "allow_sign_in": { + "type": "boolean", + "example": true, + "description": "Whether the user can use this OAuth provider to sign in. Only one OAuth provider per type can have this set to `true`." + }, + "allow_connected_accounts": { + "type": "boolean", + "example": true, + "description": "Whether the user can use this OAuth provider as connected account. Multiple OAuth providers per type can have this set to `true`." + } + }, + "required": [ + "account_id", + "user_id", + "id", + "provider_config_id", + "type", + "allow_sign_in", + "allow_connected_accounts" + ] + } + }, + "pagination": { + "type": "object", + "properties": { + "next_cursor": { + "type": "string", + "example": "b3d396b8-c574-4c80-97b3-50031675ceb2", + "description": "The cursor to fetch the next page of results. null if there is no next page." + } + }, + "required": [] + } + }, + "required": [ + "items" + ] + } + } + } + } + } + }, + "post": { + "summary": "Create an OAuth provider", + "description": "Add a new OAuth provider for a user.", + "parameters": [], + "requestBody": { + "required": true, + "content": { + "application/json": { + "schema": { + "type": "object", + "properties": { + "user_id": { + "type": "string", + "example": "3241a285-8329-4d69-8f3d-316e08cf140c", + "description": "The ID of the user, or the special value `me` for the currently authenticated user" + }, + "provider_config_id": { + "type": "string" + }, + "email": { + "type": "string", + "example": "test@gmail.com", + "description": "Email of the OAuth provider. This is used to display and identify the OAuth provider in the UI." + }, + "allow_sign_in": { + "type": "boolean", + "example": true, + "description": "Whether the user can use this OAuth provider to sign in. Only one OAuth provider per type can have this set to `true`." + }, + "allow_connected_accounts": { + "type": "boolean", + "example": true, + "description": "Whether the user can use this OAuth provider as connected account. Multiple OAuth providers per type can have this set to `true`." + }, + "account_id": { + "type": "string", + "example": "google-account-id-12345", + "description": "Account ID of the OAuth provider. This uniquely identifies the account on the provider side." + } + }, + "required": [ + "user_id", + "provider_config_id", + "allow_sign_in", + "allow_connected_accounts", + "account_id" + ], + "example": { + "user_id": "3241a285-8329-4d69-8f3d-316e08cf140c", + "email": "test@gmail.com", + "allow_sign_in": true, + "allow_connected_accounts": true, + "account_id": "google-account-id-12345" + } + } + } + } + }, + "tags": [ + "Oauth" + ], + "x-full-url": "https://api.stack-auth.com/api/v1/oauth-providers", + "responses": { + "201": { + "description": "Successful response", + "content": { + "application/json": { + "schema": { + "type": "object", + "properties": { + "account_id": { + "type": "string", + "example": "google-account-id-12345", + "description": "Account ID of the OAuth provider. This uniquely identifies the account on the provider side." + }, + "user_id": { + "type": "string", + "example": "3241a285-8329-4d69-8f3d-316e08cf140c", + "description": "The ID of the user, or the special value `me` for the currently authenticated user" + }, + "id": { + "type": "string", + "example": "b3d396b8-c574-4c80-97b3-50031675ceb2", + "description": "The unique identifier of the OAuth provider" + }, + "email": { + "type": "string", + "example": "test@gmail.com", + "description": "Email of the OAuth provider. This is used to display and identify the OAuth provider in the UI." + }, + "provider_config_id": { + "type": "string", + "example": "google", + "description": "Provider config ID of the OAuth provider. This uniquely identifies the provider config on config.json file" + }, + "type": { + "type": "string", + "example": "google", + "description": "OAuth provider type, one of `google`, `github`, `microsoft`, `spotify`, `facebook`, `discord`, `gitlab`, `bitbucket`, `linkedin`, `apple`, `x`, `twitch`" + }, + "allow_sign_in": { + "type": "boolean", + "example": true, + "description": "Whether the user can use this OAuth provider to sign in. Only one OAuth provider per type can have this set to `true`." + }, + "allow_connected_accounts": { + "type": "boolean", + "example": true, + "description": "Whether the user can use this OAuth provider as connected account. Multiple OAuth providers per type can have this set to `true`." + } + }, + "required": [ + "account_id", + "user_id", + "id", + "provider_config_id", + "type", + "allow_sign_in", + "allow_connected_accounts" + ] + } + } + } + } + } + } + }, + "/oauth-providers/{user_id}/{provider_id}": { + "get": { + "summary": "Get an OAuth provider", + "description": "Retrieves a specific OAuth provider by the user ID and the OAuth provider ID.", + "parameters": [ + { + "name": "provider_id", + "in": "path", + "schema": { + "type": "string" + }, + "required": true + }, + { + "name": "user_id", + "in": "path", + "schema": { + "type": "string", + "example": "3241a285-8329-4d69-8f3d-316e08cf140c", + "description": "The ID of the user, or the special value `me` for the currently authenticated user" + }, + "description": "The ID of the user, or the special value `me` for the currently authenticated user", + "required": true + } + ], + "tags": [ + "Oauth" + ], + "x-full-url": "https://api.stack-auth.com/api/v1/oauth-providers/{user_id}/{provider_id}", + "responses": { + "200": { + "description": "Successful response", + "content": { + "application/json": { + "schema": { + "type": "object", + "properties": { + "account_id": { + "type": "string", + "example": "google-account-id-12345", + "description": "Account ID of the OAuth provider. This uniquely identifies the account on the provider side." + }, + "user_id": { + "type": "string", + "example": "3241a285-8329-4d69-8f3d-316e08cf140c", + "description": "The ID of the user, or the special value `me` for the currently authenticated user" + }, + "id": { + "type": "string", + "example": "b3d396b8-c574-4c80-97b3-50031675ceb2", + "description": "The unique identifier of the OAuth provider" + }, + "email": { + "type": "string", + "example": "test@gmail.com", + "description": "Email of the OAuth provider. This is used to display and identify the OAuth provider in the UI." + }, + "provider_config_id": { + "type": "string", + "example": "google", + "description": "Provider config ID of the OAuth provider. This uniquely identifies the provider config on config.json file" + }, + "type": { + "type": "string", + "example": "google", + "description": "OAuth provider type, one of `google`, `github`, `microsoft`, `spotify`, `facebook`, `discord`, `gitlab`, `bitbucket`, `linkedin`, `apple`, `x`, `twitch`" + }, + "allow_sign_in": { + "type": "boolean", + "example": true, + "description": "Whether the user can use this OAuth provider to sign in. Only one OAuth provider per type can have this set to `true`." + }, + "allow_connected_accounts": { + "type": "boolean", + "example": true, + "description": "Whether the user can use this OAuth provider as connected account. Multiple OAuth providers per type can have this set to `true`." + } + }, + "required": [ + "account_id", + "user_id", + "id", + "provider_config_id", + "type", + "allow_sign_in", + "allow_connected_accounts" + ] + } + } + } + } + } + }, + "delete": { + "summary": "Delete an OAuth provider", + "description": "Removes an OAuth provider for a given user.", + "parameters": [ + { + "name": "provider_id", + "in": "path", + "schema": { + "type": "string" + }, + "required": true + }, + { + "name": "user_id", + "in": "path", + "schema": { + "type": "string", + "example": "3241a285-8329-4d69-8f3d-316e08cf140c", + "description": "The ID of the user, or the special value `me` for the currently authenticated user" + }, + "description": "The ID of the user, or the special value `me` for the currently authenticated user", + "required": true + } + ], + "tags": [ + "Oauth" + ], + "x-full-url": "https://api.stack-auth.com/api/v1/oauth-providers/{user_id}/{provider_id}", + "responses": { + "200": { + "description": "Successful response", + "content": { + "application/json": { + "schema": { + "type": "object", + "properties": { + "success": { + "type": "boolean", + "description": "Always equal to true.", + "example": true + } + }, + "required": [ + "success" + ] + } + } + } + } + } + }, + "patch": { + "summary": "Update an OAuth provider", + "description": "Updates an existing OAuth provider. Only the values provided will be updated.", + "parameters": [ + { + "name": "provider_id", + "in": "path", + "schema": { + "type": "string" + }, + "required": true + }, + { + "name": "user_id", + "in": "path", + "schema": { + "type": "string", + "example": "3241a285-8329-4d69-8f3d-316e08cf140c", + "description": "The ID of the user, or the special value `me` for the currently authenticated user" + }, + "description": "The ID of the user, or the special value `me` for the currently authenticated user", + "required": true + } + ], + "requestBody": { + "required": true, + "content": { + "application/json": { + "schema": { + "type": "object", + "properties": { + "email": { + "type": "string", + "example": "test@gmail.com", + "description": "Email of the OAuth provider. This is used to display and identify the OAuth provider in the UI." + }, + "account_id": { + "type": "string", + "example": "google-account-id-12345", + "description": "Account ID of the OAuth provider. This uniquely identifies the account on the provider side." + }, + "allow_sign_in": { + "type": "boolean", + "example": true, + "description": "Whether the user can use this OAuth provider to sign in. Only one OAuth provider per type can have this set to `true`." + }, + "allow_connected_accounts": { + "type": "boolean", + "example": true, + "description": "Whether the user can use this OAuth provider as connected account. Multiple OAuth providers per type can have this set to `true`." + } + }, + "example": { + "email": "test@gmail.com", + "account_id": "google-account-id-12345", + "allow_sign_in": true, + "allow_connected_accounts": true + } + } + } + } + }, + "tags": [ + "Oauth" + ], + "x-full-url": "https://api.stack-auth.com/api/v1/oauth-providers/{user_id}/{provider_id}", + "responses": { + "200": { + "description": "Successful response", + "content": { + "application/json": { + "schema": { + "type": "object", + "properties": { + "account_id": { + "type": "string", + "example": "google-account-id-12345", + "description": "Account ID of the OAuth provider. This uniquely identifies the account on the provider side." + }, + "user_id": { + "type": "string", + "example": "3241a285-8329-4d69-8f3d-316e08cf140c", + "description": "The ID of the user, or the special value `me` for the currently authenticated user" + }, + "id": { + "type": "string", + "example": "b3d396b8-c574-4c80-97b3-50031675ceb2", + "description": "The unique identifier of the OAuth provider" + }, + "email": { + "type": "string", + "example": "test@gmail.com", + "description": "Email of the OAuth provider. This is used to display and identify the OAuth provider in the UI." + }, + "provider_config_id": { + "type": "string", + "example": "google", + "description": "Provider config ID of the OAuth provider. This uniquely identifies the provider config on config.json file" + }, + "type": { + "type": "string", + "example": "google", + "description": "OAuth provider type, one of `google`, `github`, `microsoft`, `spotify`, `facebook`, `discord`, `gitlab`, `bitbucket`, `linkedin`, `apple`, `x`, `twitch`" + }, + "allow_sign_in": { + "type": "boolean", + "example": true, + "description": "Whether the user can use this OAuth provider to sign in. Only one OAuth provider per type can have this set to `true`." + }, + "allow_connected_accounts": { + "type": "boolean", + "example": true, + "description": "Whether the user can use this OAuth provider as connected account. Multiple OAuth providers per type can have this set to `true`." + } + }, + "required": [ + "account_id", + "user_id", + "id", + "provider_config_id", + "type", + "allow_sign_in", + "allow_connected_accounts" + ] + } + } + } + } + } + } + }, + "/internal/ai-conversations": { + "get": { + "summary": "List AI conversations", + "description": "List AI conversations for the current user filtered by project", + "parameters": [ + { + "name": "projectId", + "in": "query", + "schema": { + "type": "string" + }, + "required": true + } + ], + "tags": [ + "Others" + ], + "x-full-url": "https://api.stack-auth.com/api/v1/internal/ai-conversations", + "responses": { + "200": { + "description": "Successful response", + "content": { + "application/json": { + "schema": { + "type": "object", + "properties": { + "conversations": { + "type": "array", + "items": { + "type": "object", + "properties": { + "id": { + "type": "string" + }, + "title": { + "type": "string" + }, + "projectId": { + "type": "string" + }, + "updatedAt": { + "type": "string" + } + }, + "required": [ + "id", + "title", + "projectId", + "updatedAt" + ] + } + } + }, + "required": [ + "conversations" + ] + } + } + } + } + } + }, + "post": { + "summary": "Create AI conversation", + "description": "Create a new AI conversation with optional initial messages", + "parameters": [], + "requestBody": { + "required": true, + "content": { + "application/json": { + "schema": { + "type": "object", + "properties": { + "title": { + "type": "string" + }, + "projectId": { + "type": "string" + }, + "messages": { + "type": "array", + "items": { + "type": "object", + "properties": { + "role": { + "type": "string" + }, + "content": { + "type": "object" + } + }, + "required": [ + "role", + "content" + ] + } + } + }, + "required": [ + "title", + "projectId", + "messages" + ], + "example": {} + } + } + } + }, + "tags": [ + "Others" + ], + "x-full-url": "https://api.stack-auth.com/api/v1/internal/ai-conversations", + "responses": { + "200": { + "description": "Successful response", + "content": { + "application/json": { + "schema": { + "type": "object", + "properties": { + "id": { + "type": "string" + }, + "title": { + "type": "string" + } + }, + "required": [ + "id", + "title" + ] + } + } + } + } + } + } + }, + "/internal/ai-conversations/{conversationId}": { + "get": { + "summary": "Get AI conversation", + "description": "Fetch a single AI conversation with all its messages", + "parameters": [ + { + "name": "conversationId", + "in": "path", + "schema": { + "type": "string" + }, + "required": true + } + ], + "tags": [ + "Others" + ], + "x-full-url": "https://api.stack-auth.com/api/v1/internal/ai-conversations/{conversationId}", + "responses": { + "200": { + "description": "Successful response", + "content": { + "application/json": { + "schema": { + "type": "object", + "properties": { + "id": { + "type": "string" + }, + "title": { + "type": "string" + }, + "projectId": { + "type": "string" + }, + "messages": { + "type": "array", + "items": { + "type": "object", + "properties": { + "id": { + "type": "string" + }, + "role": { + "type": "string" + }, + "content": { + "type": "object" + } + }, + "required": [ + "id", + "role", + "content" + ] + } + } + }, + "required": [ + "id", + "title", + "projectId", + "messages" + ] + } + } + } + } + } + }, + "delete": { + "summary": "Delete AI conversation", + "description": "Delete an AI conversation and all its messages", + "parameters": [ + { + "name": "conversationId", + "in": "path", + "schema": { + "type": "string" + }, + "required": true + } + ], + "tags": [ + "Others" + ], + "x-full-url": "https://api.stack-auth.com/api/v1/internal/ai-conversations/{conversationId}", + "responses": { + "200": { + "description": "Successful response", + "content": { + "application/json": { + "schema": { + "type": "object", + "properties": {} + } + } + } + } + } + }, + "patch": { + "summary": "Update AI conversation", + "description": "Update the title of an AI conversation", + "parameters": [ + { + "name": "conversationId", + "in": "path", + "schema": { + "type": "string" + }, + "required": true + } + ], + "requestBody": { + "required": true, + "content": { + "application/json": { + "schema": { + "type": "object", + "properties": { + "title": { + "type": "string" + } + }, + "required": [ + "title" + ], + "example": {} + } + } + } + }, + "tags": [ + "Others" + ], + "x-full-url": "https://api.stack-auth.com/api/v1/internal/ai-conversations/{conversationId}", + "responses": { + "200": { + "description": "Successful response", + "content": { + "application/json": { + "schema": { + "type": "object", + "properties": {} + } + } + } + } + } + } + }, + "/internal/ai-conversations/{conversationId}/messages": { + "put": { + "summary": "Replace conversation messages", + "description": "Replace all messages in a conversation", + "parameters": [ + { + "name": "conversationId", + "in": "path", + "schema": { + "type": "string" + }, + "required": true + } + ], + "requestBody": { + "required": true, + "content": { + "application/json": { + "schema": { + "type": "object", + "properties": { + "messages": { + "type": "array", + "items": { + "type": "object", + "properties": { + "role": { + "type": "string" + }, + "content": { + "type": "object" + } + }, + "required": [ + "role", + "content" + ] + } + } + }, + "required": [ + "messages" + ], + "example": {} + } + } + } + }, + "tags": [ + "Others" + ], + "x-full-url": "https://api.stack-auth.com/api/v1/internal/ai-conversations/{conversationId}/messages", + "responses": { + "200": { + "description": "Successful response", + "content": { + "application/json": { + "schema": { + "type": "object", + "properties": {} + } + } + } + } + } + } + }, + "/auth/mfa/sign-in": { + "post": { + "summary": "MFA sign in", + "description": "Complete multi-factor authorization to sign in, with a TOTP and an MFA attempt code", + "parameters": [], + "requestBody": { + "required": true, + "content": { + "application/json": { + "schema": { + "type": "object", + "properties": { + "type": { + "type": "string" + }, + "totp": { + "type": "string" + }, + "code": { + "type": "string", + "example": "u3h6gn4w24pqc8ya679inrhjwh1rybth6a7thurqhnpf2", + "description": "A 45 character code" + } + }, + "required": [ + "type", + "totp", + "code" + ], + "example": { + "code": "u3h6gn4w24pqc8ya679inrhjwh1rybth6a7thurqhnpf2" + } + } + } + } + }, + "tags": [ + "OTP" + ], + "x-full-url": "https://api.stack-auth.com/api/v1/auth/mfa/sign-in", + "responses": { + "200": { + "description": "Successful response", + "content": { + "application/json": { + "schema": { + "type": "object", + "properties": { + "refresh_token": { + "type": "string", + "example": "i8ns3aq2...14y", + "description": "Long-lived refresh token that can be used to obtain a new access token" + }, + "access_token": { + "type": "string", + "example": "eyJhmMiJB2TO...diI4QT", + "description": "Short-lived access token that can be used to authenticate the user" + }, + "is_new_user": { + "type": "boolean", + "example": true, + "description": "Whether the user is a new user" + }, + "user_id": { + "type": "string", + "example": "3241a285-8329-4d69-8f3d-316e08cf140c", + "description": "The unique identifier of the user" + } + }, + "required": [ + "refresh_token", + "access_token", + "is_new_user", + "user_id" + ] + } + } + } + } + } + } + }, + "/auth/otp/send-sign-in-code": { + "post": { + "summary": "Send sign-in code", + "description": "Send a code to the user's email address for sign-in.", + "parameters": [], + "requestBody": { + "required": true, + "content": { + "application/json": { + "schema": { + "type": "object", + "properties": { + "email": { + "type": "string", + "example": "johndoe@example.com", + "description": "The email to sign in with." + }, + "callback_url": { + "type": "string", + "example": "https://example.com/handler/magic-link-callback", + "description": "The base callback URL to construct the magic link from. A query parameter `code` with the verification code will be appended to it. The page should then make a request to the `/auth/otp/sign-in` endpoint." + }, + "bot_challenge_token": { + "type": "string" + }, + "bot_challenge_phase": { + "type": "string" + }, + "bot_challenge_unavailable": { + "type": "string" + } + }, + "required": [ + "email", + "callback_url" + ], + "example": { + "email": "johndoe@example.com", + "callback_url": "https://example.com/handler/magic-link-callback" + } + } + } + } + }, + "tags": [ + "OTP" + ], + "x-full-url": "https://api.stack-auth.com/api/v1/auth/otp/send-sign-in-code", + "responses": { + "200": { + "description": "Successful response", + "content": { + "application/json": { + "schema": { + "type": "object", + "properties": { + "nonce": { + "type": "string", + "example": "u3h6gn4w24pqc8ya679inrhjwh1rybth6a7thurqhnpf2", + "description": "A token that must be stored temporarily and provided when verifying the 6-digit code" + } + }, + "required": [ + "nonce" + ] + } + } + } + } + } + } + }, + "/auth/otp/sign-in": { + "post": { + "summary": "Sign in with a code", + "description": "", + "parameters": [], + "requestBody": { + "required": true, + "content": { + "application/json": { + "schema": { + "type": "object", + "properties": { + "code": { + "type": "string", + "example": "u3h6gn4w24pqc8ya679inrhjwh1rybth6a7thurqhnpf2", + "description": "A 45-character verification code. For magic links, this is the code found in the \"code\" URL query parameter. For OTP, this is formed by concatenating the 6-digit code entered by the user with the nonce (received during code creation)" + } + }, + "required": [ + "code" + ], + "example": { + "code": "u3h6gn4w24pqc8ya679inrhjwh1rybth6a7thurqhnpf2" + } + } + } + } + }, + "tags": [ + "OTP" + ], + "x-full-url": "https://api.stack-auth.com/api/v1/auth/otp/sign-in", + "responses": { + "200": { + "description": "Successful response", + "content": { + "application/json": { + "schema": { + "type": "object", + "properties": { + "refresh_token": { + "type": "string", + "example": "i8ns3aq2...14y", + "description": "Long-lived refresh token that can be used to obtain a new access token" + }, + "access_token": { + "type": "string", + "example": "eyJhmMiJB2TO...diI4QT", + "description": "Short-lived access token that can be used to authenticate the user" + }, + "is_new_user": { + "type": "boolean", + "example": true, + "description": "Whether the user is a new user" + }, + "user_id": { + "type": "string", + "example": "3241a285-8329-4d69-8f3d-316e08cf140c", + "description": "The unique identifier of the user" + } + }, + "required": [ + "refresh_token", + "access_token", + "is_new_user", + "user_id" + ] + } + } + } + } + } + } + }, + "/auth/otp/sign-in/check-code": { + "post": { + "summary": "Check sign in code", + "description": "Check if a sign in code is valid without using it", + "parameters": [], + "requestBody": { + "required": true, + "content": { + "application/json": { + "schema": { + "type": "object", + "properties": { + "code": { + "type": "string", + "example": "u3h6gn4w24pqc8ya679inrhjwh1rybth6a7thurqhnpf2", + "description": "A 45-character verification code. For magic links, this is the code found in the \"code\" URL query parameter. For OTP, this is formed by concatenating the 6-digit code entered by the user with the nonce (received during code creation)" + } + }, + "required": [ + "code" + ], + "example": { + "code": "u3h6gn4w24pqc8ya679inrhjwh1rybth6a7thurqhnpf2" + } + } + } + } + }, + "tags": [ + "OTP" + ], + "x-full-url": "https://api.stack-auth.com/api/v1/auth/otp/sign-in/check-code", + "responses": { + "200": { + "description": "Successful response", + "content": { + "application/json": { + "schema": { + "type": "object", + "properties": { + "is_code_valid": { + "type": "boolean" + } + }, + "required": [ + "is_code_valid" + ] + } + } + } + } + } + } + }, + "/auth/password/reset": { + "post": { + "summary": "Reset password with a code", + "description": "Reset password with a code", + "parameters": [], + "requestBody": { + "required": true, + "content": { + "application/json": { + "schema": { + "type": "object", + "properties": { + "password": { + "type": "string" + }, + "code": { + "type": "string", + "example": "u3h6gn4w24pqc8ya679inrhjwh1rybth6a7thurqhnpf2", + "description": "A 45 character code" + } + }, + "required": [ + "password", + "code" + ], + "example": { + "code": "u3h6gn4w24pqc8ya679inrhjwh1rybth6a7thurqhnpf2" + } + } + } + } + }, + "tags": [ + "Password" + ], + "x-full-url": "https://api.stack-auth.com/api/v1/auth/password/reset", + "responses": { + "200": { + "description": "Successful response", + "content": { + "application/json": { + "schema": { + "type": "object", + "properties": { + "success": { + "type": "boolean", + "description": "Always equal to true.", + "example": true + } + }, + "required": [ + "success" + ] + } + } + } + } + } + } + }, + "/auth/password/reset/check-code": { + "post": { + "summary": "Check reset password code", + "description": "Check if a reset password code is valid without using it", + "parameters": [], + "requestBody": { + "required": true, + "content": { + "application/json": { + "schema": { + "type": "object", + "properties": { + "code": { + "type": "string", + "example": "u3h6gn4w24pqc8ya679inrhjwh1rybth6a7thurqhnpf2", + "description": "A 45 character code" + } + }, + "required": [ + "code" + ], + "example": { + "code": "u3h6gn4w24pqc8ya679inrhjwh1rybth6a7thurqhnpf2" + } + } + } + } + }, + "tags": [ + "Password" + ], + "x-full-url": "https://api.stack-auth.com/api/v1/auth/password/reset/check-code", + "responses": { + "200": { + "description": "Successful response", + "content": { + "application/json": { + "schema": { + "type": "object", + "properties": { + "is_code_valid": { + "type": "boolean" + } + }, + "required": [ + "is_code_valid" + ] + } + } + } + } + } + } + }, + "/auth/password/send-reset-code": { + "post": { + "summary": "Send reset password code", + "description": "Send a code to the user's email address for resetting the password.", + "parameters": [], + "requestBody": { + "required": true, + "content": { + "application/json": { + "schema": { + "type": "object", + "properties": { + "email": { + "type": "string" + }, + "callback_url": { + "type": "string" + } + }, + "required": [ + "email", + "callback_url" + ], + "example": {} + } + } + } + }, + "tags": [ + "Password" + ], + "x-full-url": "https://api.stack-auth.com/api/v1/auth/password/send-reset-code", + "responses": { + "200": { + "description": "Successful response", + "content": { + "application/json": { + "schema": { + "type": "object", + "properties": { + "success": { + "type": "string" + } + }, + "required": [ + "success" + ] + } + } + } + } + } + } + }, + "/auth/password/set": { + "post": { + "summary": "Set password", + "description": "Set a new password for the current user", + "parameters": [], + "requestBody": { + "required": true, + "content": { + "application/json": { + "schema": { + "type": "object", + "properties": { + "password": { + "type": "string" + } + }, + "required": [ + "password" + ], + "example": {} + } + } + } + }, + "tags": [ + "Password" + ], + "x-full-url": "https://api.stack-auth.com/api/v1/auth/password/set", + "responses": { + "200": { + "description": "Successful response", + "content": { + "application/json": { + "schema": { + "type": "object", + "properties": { + "success": { + "type": "boolean", + "description": "Always equal to true.", + "example": true + } + }, + "required": [ + "success" + ] + } + } + } + } + } + } + }, + "/auth/password/sign-in": { + "post": { + "summary": "Sign in with email and password", + "description": "Sign in to an account with email and password", + "parameters": [], + "requestBody": { + "required": true, + "content": { + "application/json": { + "schema": { + "type": "object", + "properties": { + "email": { + "type": "string" + }, + "password": { + "type": "string" + } + }, + "required": [ + "email", + "password" + ], + "example": {} + } + } + } + }, + "tags": [ + "Password" + ], + "x-full-url": "https://api.stack-auth.com/api/v1/auth/password/sign-in", + "responses": { + "200": { + "description": "Successful response", + "content": { + "application/json": { + "schema": { + "type": "object", + "properties": { + "access_token": { + "type": "string" + }, + "refresh_token": { + "type": "string" + }, + "user_id": { + "type": "string" + } + }, + "required": [ + "access_token", + "refresh_token", + "user_id" + ] + } + } + } + } + } + } + }, + "/auth/password/sign-up": { + "post": { + "summary": "Sign up with email and password", + "description": "Create a new account with email and password", + "parameters": [], + "requestBody": { + "required": true, + "content": { + "application/json": { + "schema": { + "type": "object", + "properties": { + "email": { + "type": "string", + "example": "johndoe@example.com", + "description": "The email to sign in with." + }, + "password": { + "type": "string" + }, + "verification_callback_url": { + "type": "string", + "example": "https://example.com/handler/email-verification", + "description": "The base callback URL to construct a verification link for the verification e-mail. A query parameter `code` with the verification code will be appended to it. The page should then make a request to the `/contact-channels/verify` endpoint." + }, + "bot_challenge_token": { + "type": "string" + }, + "bot_challenge_phase": { + "type": "string" + }, + "bot_challenge_unavailable": { + "type": "string" + } + }, + "required": [ + "email", + "password" + ], + "example": { + "email": "johndoe@example.com", + "verification_callback_url": "https://example.com/handler/email-verification" + } + } + } + } + }, + "tags": [ + "Password" + ], + "x-full-url": "https://api.stack-auth.com/api/v1/auth/password/sign-up", + "responses": { + "200": { + "description": "Successful response", + "content": { + "application/json": { + "schema": { + "type": "object", + "properties": { + "access_token": { + "type": "string" + }, + "refresh_token": { + "type": "string" + }, + "user_id": { + "type": "string" + } + }, + "required": [ + "access_token", + "refresh_token", + "user_id" + ] + } + } + } + } + } + } + }, + "/auth/password/update": { + "post": { + "summary": "Update password", + "description": "Update the password of the current user, requires the old password", + "parameters": [ + { + "name": "x-stack-refresh-token", + "in": "header", + "schema": { + "type": "string" + }, + "required": false + } + ], + "requestBody": { + "required": true, + "content": { + "application/json": { + "schema": { + "type": "object", + "properties": { + "old_password": { + "type": "string" + }, + "new_password": { + "type": "string" + } + }, + "required": [ + "old_password", + "new_password" + ], + "example": {} + } + } + } + }, + "tags": [ + "Password" + ], + "x-full-url": "https://api.stack-auth.com/api/v1/auth/password/update", + "responses": { + "200": { + "description": "Successful response", + "content": { + "application/json": { + "schema": { + "type": "object", + "properties": { + "success": { + "type": "boolean", + "description": "Always equal to true.", + "example": true + } + }, + "required": [ + "success" + ] + } + } + } + } + } + } + }, + "/payments/items/{customer_type}/{customer_id}/{item_id}": { + "get": { + "summary": "Get Item", + "description": "Retrieves information about a specific item (credits, quotas, etc.) for a customer.", + "parameters": [ + { + "name": "customer_type", + "in": "path", + "schema": { + "type": "string", + "example": "user", + "description": "The type of customer" + }, + "description": "The type of customer", + "required": true + }, + { + "name": "customer_id", + "in": "path", + "schema": { + "type": "string", + "example": "user_1234567890abcdef", + "description": "The ID of the customer" + }, + "description": "The ID of the customer", + "required": true + }, + { + "name": "item_id", + "in": "path", + "schema": { + "type": "string", + "example": "credits", + "description": "The ID of the item to retrieve" + }, + "description": "The ID of the item to retrieve", + "required": true + } + ], + "tags": [ + "Payments" + ], + "x-full-url": "https://api.stack-auth.com/api/v1/payments/items/{customer_type}/{customer_id}/{item_id}", + "responses": { + "200": { + "description": "Successful response", + "content": { + "application/json": { + "schema": { + "type": "object", + "properties": { + "id": { + "type": "string", + "example": "credits", + "description": "The ID of the item" + }, + "display_name": { + "type": "string", + "example": "API Credits", + "description": "The human-readable name of the item" + }, + "quantity": { + "type": "number", + "example": 1000, + "description": "The current quantity of the item (can be negative)" + } + }, + "required": [ + "id", + "display_name", + "quantity" + ] + } + } + } + } + } + } + }, + "/payments/items/{customer_type}/{customer_id}/{item_id}/update-quantity": { + "post": { + "summary": "Update Item Quantity", + "description": "Updates the quantity of an item for a customer. Can increase or decrease quantities, with optional expiration and negative balance control.", + "parameters": [ + { + "name": "allow_negative", + "in": "query", + "schema": { + "type": "string", + "example": "false", + "description": "Whether to allow the quantity to go negative" + }, + "description": "Whether to allow the quantity to go negative", + "required": true + }, + { + "name": "customer_type", + "in": "path", + "schema": { + "type": "string", + "example": "user", + "description": "The type of customer" + }, + "description": "The type of customer", + "required": true + }, + { + "name": "customer_id", + "in": "path", + "schema": { + "type": "string", + "example": "user_1234567890abcdef", + "description": "The ID of the customer" + }, + "description": "The ID of the customer", + "required": true + }, + { + "name": "item_id", + "in": "path", + "schema": { + "type": "string", + "example": "credits", + "description": "The ID of the item to update" + }, + "description": "The ID of the item to update", + "required": true + } + ], + "requestBody": { + "required": true, + "content": { + "application/json": { + "schema": { + "type": "object", + "properties": { + "delta": { + "type": "number", + "example": 100, + "description": "The amount to change the quantity by (positive to increase, negative to decrease)" + }, + "expires_at": { + "type": "string", + "example": "2024-12-31T23:59:59Z", + "description": "Optional expiration date for this quantity change (ISO 8601 format)" + }, + "description": { + "type": "string", + "example": "Monthly subscription renewal", + "description": "Optional description for this quantity change" + } + }, + "required": [ + "delta" + ], + "example": { + "delta": 100, + "expires_at": "2024-12-31T23:59:59Z", + "description": "Monthly subscription renewal" + } + } + } + } + }, + "tags": [ + "Payments" + ], + "x-full-url": "https://api.stack-auth.com/api/v1/payments/items/{customer_type}/{customer_id}/{item_id}/update-quantity", + "responses": { + "200": { + "description": "Successful response", + "content": { + "application/json": { + "schema": { + "type": "object", + "properties": {} + } + } + } + } + } + } + }, + "/payments/purchases/create-purchase-url": { + "post": { + "summary": "Create Purchase URL", + "description": "Creates a secure checkout URL for purchasing a product.", + "parameters": [], + "requestBody": { + "required": true, + "content": { + "application/json": { + "schema": { + "type": "object", + "properties": { + "customer_type": { + "type": "string", + "example": "user", + "description": "The type of customer making the purchase" + }, + "customer_id": { + "type": "string", + "example": "user_1234567890abcdef", + "description": "The ID of the customer (user ID, team ID, or custom customer ID)" + }, + "product_id": { + "type": "string", + "example": "prod_premium_monthly", + "description": "The ID of the product to purchase. Either this or product_inline should be given." + }, + "product_inline": { + "type": "object", + "properties": { + "display_name": { + "type": "string" + }, + "customer_type": { + "type": "string" + }, + "free_trial": { + "type": "array", + "items": { + "type": "number" + } + }, + "server_only": { + "type": "boolean", + "default": true + }, + "stackable": { + "type": "boolean", + "default": false + }, + "prices": { + "type": "object", + "properties": {}, + "required": [] + }, + "included_items": { + "type": "object", + "properties": {}, + "required": [] + }, + "client_metadata": { + "type": "object", + "example": { + "featureFlag": true, + "source": "marketing-campaign" + }, + "description": "Client metadata. Used as a data store, accessible from the client side. Do not store information that should not be exposed to the client." + }, + "client_read_only_metadata": { + "type": "object", + "example": { + "featureFlag": true, + "source": "marketing-campaign" + }, + "description": "Client read-only, server-writable metadata. Used as a data store, accessible from the client side. Do not store information that should not be exposed to the client. The client can read this data, but cannot modify it. This is useful for things like subscription status." + }, + "server_metadata": { + "type": "object", + "example": { + "featureFlag": true, + "source": "marketing-campaign" + }, + "description": "Server metadata. Used as a data store, only accessible from the server side. You can store secret information related to the product here." + } + }, + "required": [ + "display_name", + "customer_type" + ], + "description": "Inline product definition. Either this or product_id should be given." + }, + "return_url": { + "type": "string", + "example": "https://myapp.com/purchase-success", + "description": "URL to redirect to after purchase completion. Must be configured as a trusted domain in the project configuration." + } + }, + "required": [ + "customer_type", + "customer_id" + ], + "example": { + "customer_type": "user", + "customer_id": "user_1234567890abcdef", + "product_id": "prod_premium_monthly", + "return_url": "https://myapp.com/purchase-success" + } + } + } + } + }, + "tags": [ + "Payments" + ], + "x-full-url": "https://api.stack-auth.com/api/v1/payments/purchases/create-purchase-url", + "responses": { + "200": { + "description": "Successful response", + "content": { + "application/json": { + "schema": { + "type": "object", + "properties": { + "url": { + "type": "string", + "description": "The secure checkout URL for completing the purchase" + } + }, + "required": [ + "url" + ] + } + } + } + } + } + } + }, + "/payments/purchases/purchase-session": { + "post": { + "summary": "Create Purchase Session", + "description": "Creates a purchase session for completing a purchase.", + "parameters": [], + "requestBody": { + "required": true, + "content": { + "application/json": { + "schema": { + "type": "object", + "properties": { + "full_code": { + "type": "string", + "example": "proj_abc123_def456ghi789", + "description": "The verification code, given as a query parameter in the purchase URL" + }, + "price_id": { + "type": "string", + "example": "price_1234567890abcdef", + "description": "The Stack auth price ID to purchase" + }, + "quantity": { + "type": "number", + "example": 1, + "description": "The quantity to purchase", + "default": 1 + } + }, + "required": [ + "full_code", + "price_id" + ], + "example": { + "full_code": "proj_abc123_def456ghi789", + "price_id": "price_1234567890abcdef", + "quantity": 1 + } + } + } + } + }, + "tags": [ + "Payments" + ], + "x-full-url": "https://api.stack-auth.com/api/v1/payments/purchases/purchase-session", + "responses": { + "200": { + "description": "Successful response", + "content": { + "application/json": { + "schema": { + "type": "object", + "properties": { + "client_secret": { + "type": "string", + "example": "1234567890abcdef_secret_xyz123", + "description": "The Stripe client secret for completing the payment" + } + }, + "required": [ + "client_secret" + ] + } + } + } + } + } + } + }, + "/payments/purchases/validate-code": { + "post": { + "summary": "Validate Purchase Code", + "description": "Validates a purchase verification code and returns purchase details including available prices.", + "parameters": [], + "requestBody": { + "required": true, + "content": { + "application/json": { + "schema": { + "type": "object", + "properties": { + "full_code": { + "type": "string", + "example": "proj_abc123_def456ghi789", + "description": "The verification code, given as a query parameter in the purchase URL" + }, + "return_url": { + "type": "string", + "example": "https://myapp.com/purchase-success", + "description": "URL to redirect to after purchase completion" + } + }, + "required": [ + "full_code" + ], + "example": { + "full_code": "proj_abc123_def456ghi789", + "return_url": "https://myapp.com/purchase-success" + } + } + } + } + }, + "tags": [ + "Payments" + ], + "x-full-url": "https://api.stack-auth.com/api/v1/payments/purchases/validate-code", + "responses": { + "200": { + "description": "Successful response", + "content": { + "application/json": { + "schema": { + "type": "object", + "properties": { + "product": { + "type": "object", + "properties": { + "display_name": { + "type": "string" + }, + "customer_type": { + "type": "string" + }, + "free_trial": { + "type": "array", + "items": { + "type": "number" + } + }, + "server_only": { + "type": "boolean", + "default": true + }, + "stackable": { + "type": "boolean", + "default": false + }, + "prices": { + "type": "object", + "properties": {}, + "required": [] + }, + "included_items": { + "type": "object", + "properties": {}, + "required": [] + }, + "client_metadata": { + "type": "object", + "example": { + "featureFlag": true, + "source": "marketing-campaign" + }, + "description": "Client metadata. Used as a data store, accessible from the client side. Do not store information that should not be exposed to the client." + }, + "client_read_only_metadata": { + "type": "object", + "example": { + "featureFlag": true, + "source": "marketing-campaign" + }, + "description": "Client read-only, server-writable metadata. Used as a data store, accessible from the client side. Do not store information that should not be exposed to the client. The client can read this data, but cannot modify it. This is useful for things like subscription status." + }, + "server_metadata": { + "type": "object", + "example": { + "featureFlag": true, + "source": "marketing-campaign" + }, + "description": "Server metadata. Used as a data store, only accessible from the server side. You can store secret information related to the product here." + } + }, + "required": [ + "display_name", + "customer_type" + ] + }, + "stripe_account_id": { + "type": "string" + }, + "project_id": { + "type": "string" + }, + "project_logo_url": { + "type": "string" + }, + "already_bought_non_stackable": { + "type": "boolean" + }, + "conflicting_products": { + "type": "array", + "items": { + "type": "object", + "properties": { + "product_id": { + "type": "string" + }, + "display_name": { + "type": "string" + } + }, + "required": [ + "product_id", + "display_name" + ] + } + }, + "test_mode": { + "type": "boolean" + }, + "charges_enabled": { + "type": "boolean" + } + }, + "required": [ + "stripe_account_id", + "project_id", + "already_bought_non_stackable", + "conflicting_products", + "test_mode", + "charges_enabled" + ] + } + } + } + } + } + } + }, + "/project-permissions": { + "get": { + "summary": "List project permissions", + "description": "Query and filter the permission with `user_id` and `permission_id`. `(user_id, permission_id)` together uniquely identify a permission.", + "parameters": [ + { + "name": "user_id", + "in": "query", + "schema": { + "type": "string", + "example": "me", + "description": "Filter with the user ID. If set, only the permissions this user has will be returned. Client request must set `user_id=me`" + }, + "description": "Filter with the user ID. If set, only the permissions this user has will be returned. Client request must set `user_id=me`", + "required": false + }, + { + "name": "permission_id", + "in": "query", + "schema": { + "type": "string", + "example": "16399452-c4f3-4554-8e44-c2d67bb60360", + "description": "Filter with the permission ID. If set, only the permissions with this specific ID will be returned" + }, + "description": "Filter with the permission ID. If set, only the permissions with this specific ID will be returned", + "required": false + }, + { + "name": "recursive", + "in": "query", + "schema": { + "type": "string", + "example": "true", + "description": "Whether to list permissions recursively. If set to `false`, only the permission the users directly have will be listed. If set to `true` all the direct and indirect permissions will be listed." + }, + "description": "Whether to list permissions recursively. If set to `false`, only the permission the users directly have will be listed. If set to `true` all the direct and indirect permissions will be listed.", + "required": false + } + ], + "tags": [ + "Permissions" + ], + "x-full-url": "https://api.stack-auth.com/api/v1/project-permissions", + "responses": { + "200": { + "description": "Successful response", + "content": { + "application/json": { + "schema": { + "type": "object", + "properties": { + "items": { + "type": "array", + "items": { + "type": "object", + "properties": { + "id": { + "type": "string", + "example": "read_secret_info", + "description": "The permission ID used to uniquely identify a permission. Can either be a custom permission with lowercase letters, numbers, `:`, and `_` characters, or one of the system permissions: `$update_team`, `$delete_team`, `$read_members`, `$remove_members`, `$invite_members`, `$manage_api_keys`" + }, + "user_id": { + "type": "string", + "example": "3241a285-8329-4d69-8f3d-316e08cf140c", + "description": "The unique identifier of the user" + } + }, + "required": [ + "id", + "user_id" + ] + } + }, + "pagination": { + "type": "object", + "properties": { + "next_cursor": { + "type": "string", + "example": "b3d396b8-c574-4c80-97b3-50031675ceb2", + "description": "The cursor to fetch the next page of results. null if there is no next page." + } + }, + "required": [] + } + }, + "required": [ + "items" + ] + } + } + } + } + } + } + }, + "/project-permissions/{user_id}/{permission_id}": { + "post": { + "summary": "Grant a global permission to a user", + "description": "Grant a global permission to a user (the permission must be created first on the Stack dashboard)", + "parameters": [ + { + "name": "user_id", + "in": "path", + "schema": { + "type": "string", + "example": "3241a285-8329-4d69-8f3d-316e08cf140c", + "description": "The ID of the user, or the special value `me` for the currently authenticated user" + }, + "description": "The ID of the user, or the special value `me` for the currently authenticated user", + "required": false + }, + { + "name": "permission_id", + "in": "path", + "schema": { + "type": "string", + "example": "read_secret_info", + "description": "The permission ID used to uniquely identify a permission. Can either be a custom permission with lowercase letters, numbers, `:`, and `_` characters, or one of the system permissions: `$update_team`, `$delete_team`, `$read_members`, `$remove_members`, `$invite_members`, `$manage_api_keys`" + }, + "description": "The permission ID used to uniquely identify a permission. Can either be a custom permission with lowercase letters, numbers, `:`, and `_` characters, or one of the system permissions: `$update_team`, `$delete_team`, `$read_members`, `$remove_members`, `$invite_members`, `$manage_api_keys`", + "required": false + } + ], + "requestBody": { + "required": true, + "content": { + "application/json": { + "schema": { + "type": "object", + "properties": {}, + "example": {} + } + } + } + }, + "tags": [ + "Permissions" + ], + "x-full-url": "https://api.stack-auth.com/api/v1/project-permissions/{user_id}/{permission_id}", + "responses": { + "201": { + "description": "Successful response", + "content": { + "application/json": { + "schema": { + "type": "object", + "properties": { + "id": { + "type": "string", + "example": "read_secret_info", + "description": "The permission ID used to uniquely identify a permission. Can either be a custom permission with lowercase letters, numbers, `:`, and `_` characters, or one of the system permissions: `$update_team`, `$delete_team`, `$read_members`, `$remove_members`, `$invite_members`, `$manage_api_keys`" + }, + "user_id": { + "type": "string", + "example": "3241a285-8329-4d69-8f3d-316e08cf140c", + "description": "The unique identifier of the user" + } + }, + "required": [ + "id", + "user_id" + ] + } + } + } + } + } + }, + "delete": { + "summary": "Revoke a global permission from a user", + "description": "Revoke a global permission from a user", + "parameters": [ + { + "name": "user_id", + "in": "path", + "schema": { + "type": "string", + "example": "3241a285-8329-4d69-8f3d-316e08cf140c", + "description": "The ID of the user, or the special value `me` for the currently authenticated user" + }, + "description": "The ID of the user, or the special value `me` for the currently authenticated user", + "required": true + }, + { + "name": "permission_id", + "in": "path", + "schema": { + "type": "string", + "example": "read_secret_info", + "description": "The permission ID used to uniquely identify a permission. Can either be a custom permission with lowercase letters, numbers, `:`, and `_` characters, or one of the system permissions: `$update_team`, `$delete_team`, `$read_members`, `$remove_members`, `$invite_members`, `$manage_api_keys`" + }, + "description": "The permission ID used to uniquely identify a permission. Can either be a custom permission with lowercase letters, numbers, `:`, and `_` characters, or one of the system permissions: `$update_team`, `$delete_team`, `$read_members`, `$remove_members`, `$invite_members`, `$manage_api_keys`", + "required": true + } + ], + "tags": [ + "Permissions" + ], + "x-full-url": "https://api.stack-auth.com/api/v1/project-permissions/{user_id}/{permission_id}", + "responses": { + "200": { + "description": "Successful response", + "content": { + "application/json": { + "schema": { + "type": "object", + "properties": { + "success": { + "type": "boolean", + "description": "Always equal to true.", + "example": true + } + }, + "required": [ + "success" + ] + } + } + } + } + } + } + }, + "/team-permissions": { + "get": { + "summary": "List team permissions of a user", + "description": "Query and filter the permission with `team_id`, `user_id`, and `permission_id`. Note that this might contain the permissions with the same permission ID across different teams and users. `(team_id, user_id, permission_id)` together uniquely identify a permission.", + "parameters": [ + { + "name": "team_id", + "in": "query", + "schema": { + "type": "string", + "example": "cce084a3-28b7-418e-913e-c8ee6d802ea4", + "description": "Filter with the team ID. If set, only the permissions of the members in a specific team will be returned." + }, + "description": "Filter with the team ID. If set, only the permissions of the members in a specific team will be returned.", + "required": false + }, + { + "name": "user_id", + "in": "query", + "schema": { + "type": "string", + "example": "me", + "description": "Filter with the user ID. If set, only the permissions this user has will be returned. Client request must set `user_id=me`" + }, + "description": "Filter with the user ID. If set, only the permissions this user has will be returned. Client request must set `user_id=me`", + "required": false + }, + { + "name": "permission_id", + "in": "query", + "schema": { + "type": "string", + "example": "16399452-c4f3-4554-8e44-c2d67bb60360", + "description": "Filter with the permission ID. If set, only the permissions with this specific ID will be returned" + }, + "description": "Filter with the permission ID. If set, only the permissions with this specific ID will be returned", + "required": false + }, + { + "name": "recursive", + "in": "query", + "schema": { + "type": "string", + "example": "true", + "description": "Whether to list permissions recursively. If set to `false`, only the permission the users directly have will be listed. If set to `true` all the direct and indirect permissions will be listed." + }, + "description": "Whether to list permissions recursively. If set to `false`, only the permission the users directly have will be listed. If set to `true` all the direct and indirect permissions will be listed.", + "required": false + } + ], + "tags": [ + "Permissions" + ], + "x-full-url": "https://api.stack-auth.com/api/v1/team-permissions", + "responses": { + "200": { + "description": "Successful response", + "content": { + "application/json": { + "schema": { + "type": "object", + "properties": { + "items": { + "type": "array", + "items": { + "type": "object", + "properties": { + "id": { + "type": "string", + "example": "read_secret_info", + "description": "The permission ID used to uniquely identify a permission. Can either be a custom permission with lowercase letters, numbers, `:`, and `_` characters, or one of the system permissions: `$update_team`, `$delete_team`, `$read_members`, `$remove_members`, `$invite_members`, `$manage_api_keys`" + }, + "user_id": { + "type": "string", + "example": "3241a285-8329-4d69-8f3d-316e08cf140c", + "description": "The unique identifier of the user" + }, + "team_id": { + "type": "string", + "example": "ad962777-8244-496a-b6a2-e0c6a449c79e", + "description": "The unique identifier of the team" + } + }, + "required": [ + "id", + "user_id", + "team_id" + ] + } + }, + "pagination": { + "type": "object", + "properties": { + "next_cursor": { + "type": "string", + "example": "b3d396b8-c574-4c80-97b3-50031675ceb2", + "description": "The cursor to fetch the next page of results. null if there is no next page." + } + }, + "required": [] + } + }, + "required": [ + "items" + ] + } + } + } + } + } + } + }, + "/team-permissions/{team_id}/{user_id}/{permission_id}": { + "post": { + "summary": "Grant a team permission to a user", + "description": "Grant a team permission to a user (the team permission must be created first on the Stack dashboard)", + "parameters": [ + { + "name": "team_id", + "in": "path", + "schema": { + "type": "string" + }, + "required": false + }, + { + "name": "user_id", + "in": "path", + "schema": { + "type": "string", + "example": "3241a285-8329-4d69-8f3d-316e08cf140c", + "description": "The ID of the user, or the special value `me` for the currently authenticated user" + }, + "description": "The ID of the user, or the special value `me` for the currently authenticated user", + "required": false + }, + { + "name": "permission_id", + "in": "path", + "schema": { + "type": "string", + "example": "read_secret_info", + "description": "The permission ID used to uniquely identify a permission. Can either be a custom permission with lowercase letters, numbers, `:`, and `_` characters, or one of the system permissions: `$update_team`, `$delete_team`, `$read_members`, `$remove_members`, `$invite_members`, `$manage_api_keys`" + }, + "description": "The permission ID used to uniquely identify a permission. Can either be a custom permission with lowercase letters, numbers, `:`, and `_` characters, or one of the system permissions: `$update_team`, `$delete_team`, `$read_members`, `$remove_members`, `$invite_members`, `$manage_api_keys`", + "required": false + } + ], + "requestBody": { + "required": true, + "content": { + "application/json": { + "schema": { + "type": "object", + "properties": {}, + "example": {} + } + } + } + }, + "tags": [ + "Permissions" + ], + "x-full-url": "https://api.stack-auth.com/api/v1/team-permissions/{team_id}/{user_id}/{permission_id}", + "responses": { + "201": { + "description": "Successful response", + "content": { + "application/json": { + "schema": { + "type": "object", + "properties": { + "id": { + "type": "string", + "example": "read_secret_info", + "description": "The permission ID used to uniquely identify a permission. Can either be a custom permission with lowercase letters, numbers, `:`, and `_` characters, or one of the system permissions: `$update_team`, `$delete_team`, `$read_members`, `$remove_members`, `$invite_members`, `$manage_api_keys`" + }, + "user_id": { + "type": "string", + "example": "3241a285-8329-4d69-8f3d-316e08cf140c", + "description": "The unique identifier of the user" + }, + "team_id": { + "type": "string", + "example": "ad962777-8244-496a-b6a2-e0c6a449c79e", + "description": "The unique identifier of the team" + } + }, + "required": [ + "id", + "user_id", + "team_id" + ] + } + } + } + } + } + }, + "delete": { + "summary": "Revoke a team permission from a user", + "description": "Revoke a team permission from a user", + "parameters": [ + { + "name": "team_id", + "in": "path", + "schema": { + "type": "string" + }, + "required": true + }, + { + "name": "user_id", + "in": "path", + "schema": { + "type": "string", + "example": "3241a285-8329-4d69-8f3d-316e08cf140c", + "description": "The ID of the user, or the special value `me` for the currently authenticated user" + }, + "description": "The ID of the user, or the special value `me` for the currently authenticated user", + "required": true + }, + { + "name": "permission_id", + "in": "path", + "schema": { + "type": "string", + "example": "read_secret_info", + "description": "The permission ID used to uniquely identify a permission. Can either be a custom permission with lowercase letters, numbers, `:`, and `_` characters, or one of the system permissions: `$update_team`, `$delete_team`, `$read_members`, `$remove_members`, `$invite_members`, `$manage_api_keys`" + }, + "description": "The permission ID used to uniquely identify a permission. Can either be a custom permission with lowercase letters, numbers, `:`, and `_` characters, or one of the system permissions: `$update_team`, `$delete_team`, `$read_members`, `$remove_members`, `$invite_members`, `$manage_api_keys`", + "required": true + } + ], + "tags": [ + "Permissions" + ], + "x-full-url": "https://api.stack-auth.com/api/v1/team-permissions/{team_id}/{user_id}/{permission_id}", + "responses": { + "200": { + "description": "Successful response", + "content": { + "application/json": { + "schema": { + "type": "object", + "properties": { + "success": { + "type": "boolean", + "description": "Always equal to true.", + "example": true + } + }, + "required": [ + "success" + ] + } + } + } + } + } + } + }, + "/projects/current": { + "get": { + "summary": "Get the current project", + "description": "Get the current project information including display name, OAuth providers and authentication methods. Useful for displaying the available login options to the user.", + "parameters": [], + "tags": [ + "Projects" + ], + "x-full-url": "https://api.stack-auth.com/api/v1/projects/current", + "responses": { + "200": { + "description": "Successful response", + "content": { + "application/json": { + "schema": { + "type": "object", + "properties": { + "id": { + "type": "string", + "example": "e0b52f4d-dece-408c-af49-d23061bb0f8d", + "description": "The unique identifier of the project" + }, + "display_name": { + "type": "string", + "example": "MyMusic", + "description": "Human-readable project display name. This is not a unique identifier." + } + }, + "required": [ + "id", + "display_name" + ] + } + } + } + } + } + } + }, + "/auth/sessions": { + "get": { + "summary": "List sessions", + "description": "List all sessions for the current user.", + "parameters": [ + { + "name": "user_id", + "in": "query", + "schema": { + "type": "string", + "example": "3241a285-8329-4d69-8f3d-316e08cf140c", + "description": "The ID of the user, or the special value `me` for the currently authenticated user" + }, + "description": "The ID of the user, or the special value `me` for the currently authenticated user", + "required": true + } + ], + "tags": [ + "Sessions" + ], + "x-full-url": "https://api.stack-auth.com/api/v1/auth/sessions", + "responses": { + "200": { + "description": "Successful response", + "content": { + "application/json": { + "schema": { + "type": "object", + "properties": { + "items": { + "type": "array", + "items": { + "type": "object", + "properties": { + "id": { + "type": "string" + }, + "user_id": { + "type": "string" + }, + "created_at": { + "type": "number" + }, + "is_impersonation": { + "type": "boolean" + }, + "last_used_at": { + "type": "number" + }, + "is_current_session": { + "type": "boolean" + }, + "last_used_at_end_user_ip_info": { + "type": "object", + "properties": { + "ip": { + "type": "string" + }, + "countryCode": { + "type": "string" + }, + "regionCode": { + "type": "string" + }, + "cityName": { + "type": "string" + }, + "latitude": { + "type": "number" + }, + "longitude": { + "type": "number" + }, + "tzIdentifier": { + "type": "string" + } + }, + "required": [ + "ip" + ] + } + }, + "required": [ + "id", + "user_id", + "created_at", + "is_impersonation" + ] + } + }, + "pagination": { + "type": "object", + "properties": { + "next_cursor": { + "type": "string", + "example": "b3d396b8-c574-4c80-97b3-50031675ceb2", + "description": "The cursor to fetch the next page of results. null if there is no next page." + } + }, + "required": [] + } + }, + "required": [ + "items" + ] + } + } + } + } + } + }, + "post": { + "summary": "Create session", + "description": "Create a new session for a given user. This will return a refresh token that can be used to impersonate the user.", + "parameters": [], + "requestBody": { + "required": true, + "content": { + "application/json": { + "schema": { + "type": "object", + "properties": { + "user_id": { + "type": "string", + "example": "3241a285-8329-4d69-8f3d-316e08cf140c", + "description": "The ID of the user, or the special value `me` for the currently authenticated user" + }, + "expires_in_millis": { + "type": "number", + "default": 31536000000 + }, + "is_impersonation": { + "type": "boolean" + } + }, + "required": [ + "user_id" + ], + "example": { + "user_id": "3241a285-8329-4d69-8f3d-316e08cf140c" + } + } + } + } + }, + "tags": [ + "Sessions" + ], + "x-full-url": "https://api.stack-auth.com/api/v1/auth/sessions", + "responses": { + "200": { + "description": "Successful response", + "content": { + "application/json": { + "schema": { + "type": "object", + "properties": { + "refresh_token": { + "type": "string" + }, + "access_token": { + "type": "string" + } + }, + "required": [ + "refresh_token", + "access_token" + ] + } + } + } + } + } + } + }, + "/auth/sessions/current": { + "delete": { + "summary": "Sign out of the current session", + "description": "Sign out of the current session and invalidate the refresh token", + "parameters": [], + "tags": [ + "Sessions" + ], + "x-full-url": "https://api.stack-auth.com/api/v1/auth/sessions/current", + "responses": { + "200": { + "description": "Successful response", + "content": { + "application/json": { + "schema": { + "type": "object", + "properties": { + "success": { + "type": "boolean", + "description": "Always equal to true.", + "example": true + } + }, + "required": [ + "success" + ] + } + } + } + } + } + } + }, + "/auth/sessions/current/refresh": { + "post": { + "summary": "Refresh access token", + "description": "Get a new access token using a refresh token", + "parameters": [ + { + "name": "x-stack-refresh-token", + "in": "header", + "schema": { + "type": "string" + }, + "required": true + } + ], + "tags": [ + "Sessions" + ], + "x-full-url": "https://api.stack-auth.com/api/v1/auth/sessions/current/refresh", + "responses": { + "200": { + "description": "Successful response", + "content": { + "application/json": { + "schema": { + "type": "object", + "properties": { + "access_token": { + "type": "string" + } + }, + "required": [ + "access_token" + ] + } + } + } + } + } + } + }, + "/auth/sessions/{id}": { + "delete": { + "summary": "Delete session", + "description": "Delete a session by ID.", + "parameters": [ + { + "name": "user_id", + "in": "query", + "schema": { + "type": "string", + "example": "3241a285-8329-4d69-8f3d-316e08cf140c", + "description": "The ID of the user, or the special value `me` for the currently authenticated user" + }, + "description": "The ID of the user, or the special value `me` for the currently authenticated user", + "required": true + }, + { + "name": "id", + "in": "path", + "schema": { + "type": "string" + }, + "required": true + } + ], + "tags": [ + "Sessions" + ], + "x-full-url": "https://api.stack-auth.com/api/v1/auth/sessions/{id}", + "responses": { + "200": { + "description": "Successful response", + "content": { + "application/json": { + "schema": { + "type": "object", + "properties": { + "success": { + "type": "boolean", + "description": "Always equal to true.", + "example": true + } + }, + "required": [ + "success" + ] + } + } + } + } + } + } + }, + "/team-invitations": { + "get": { + "summary": "List team invitations", + "description": "", + "parameters": [ + { + "name": "team_id", + "in": "query", + "schema": { + "type": "string", + "description": "The team ID to list invitations for. Required unless user_id is provided." + }, + "description": "The team ID to list invitations for. Required unless user_id is provided.", + "required": false + }, + { + "name": "user_id", + "in": "query", + "schema": { + "type": "string", + "description": "List invitations sent to this user's verified emails. Must be \"me\" for client access. Cannot be combined with team_id." + }, + "description": "List invitations sent to this user's verified emails. Must be \"me\" for client access. Cannot be combined with team_id.", + "required": false + } + ], + "tags": [ + "Teams" + ], + "x-full-url": "https://api.stack-auth.com/api/v1/team-invitations", + "responses": { + "200": { + "description": "Successful response", + "content": { + "application/json": { + "schema": { + "type": "object", + "properties": { + "items": { + "type": "array", + "items": { + "type": "object", + "properties": { + "id": { + "type": "string" + }, + "team_id": { + "type": "string", + "example": "ad962777-8244-496a-b6a2-e0c6a449c79e", + "description": "The unique identifier of the team" + }, + "team_display_name": { + "type": "string" + }, + "expires_at_millis": { + "type": "number" + }, + "recipient_email": { + "type": "string" + } + }, + "required": [ + "id", + "team_id", + "team_display_name", + "expires_at_millis", + "recipient_email" + ] + } + }, + "pagination": { + "type": "object", + "properties": { + "next_cursor": { + "type": "string", + "example": "b3d396b8-c574-4c80-97b3-50031675ceb2", + "description": "The cursor to fetch the next page of results. null if there is no next page." + } + }, + "required": [] + } + }, + "required": [ + "items" + ] + } + } + } + } + } + } + }, + "/team-invitations/accept": { + "post": { + "summary": "Accept the team invitation", + "description": "Accept invitation and add user to the team", + "parameters": [], + "requestBody": { + "required": true, + "content": { + "application/json": { + "schema": { + "type": "object", + "properties": { + "code": { + "type": "string", + "example": "u3h6gn4w24pqc8ya679inrhjwh1rybth6a7thurqhnpf2", + "description": "A 45 character code" + } + }, + "required": [ + "code" + ], + "example": { + "code": "u3h6gn4w24pqc8ya679inrhjwh1rybth6a7thurqhnpf2" + } + } + } + } + }, + "tags": [ + "Teams" + ], + "x-full-url": "https://api.stack-auth.com/api/v1/team-invitations/accept", + "responses": { + "200": { + "description": "Successful response", + "content": { + "application/json": { + "schema": { + "type": "object", + "properties": {} + } + } + } + } + } + } + }, + "/team-invitations/accept/check-code": { + "post": { + "summary": "Check if a team invitation code is valid", + "description": "Check if a team invitation code is valid without using it", + "parameters": [], + "requestBody": { + "required": true, + "content": { + "application/json": { + "schema": { + "type": "object", + "properties": { + "code": { + "type": "string", + "example": "u3h6gn4w24pqc8ya679inrhjwh1rybth6a7thurqhnpf2", + "description": "A 45 character code" + } + }, + "required": [ + "code" + ], + "example": { + "code": "u3h6gn4w24pqc8ya679inrhjwh1rybth6a7thurqhnpf2" + } + } + } + } + }, + "tags": [ + "Teams" + ], + "x-full-url": "https://api.stack-auth.com/api/v1/team-invitations/accept/check-code", + "responses": { + "200": { + "description": "Successful response", + "content": { + "application/json": { + "schema": { + "type": "object", + "properties": { + "is_code_valid": { + "type": "boolean" + } + }, + "required": [ + "is_code_valid" + ] + } + } + } + } + } + } + }, + "/team-invitations/accept/details": { + "post": { + "summary": "Get team invitation details", + "description": "Get additional information about a team invitation code", + "parameters": [], + "requestBody": { + "required": true, + "content": { + "application/json": { + "schema": { + "type": "object", + "properties": { + "code": { + "type": "string", + "example": "u3h6gn4w24pqc8ya679inrhjwh1rybth6a7thurqhnpf2", + "description": "A 45 character code" + } + }, + "required": [ + "code" + ], + "example": { + "code": "u3h6gn4w24pqc8ya679inrhjwh1rybth6a7thurqhnpf2" + } + } + } + } + }, + "tags": [ + "Teams" + ], + "x-full-url": "https://api.stack-auth.com/api/v1/team-invitations/accept/details", + "responses": { + "200": { + "description": "Successful response", + "content": { + "application/json": { + "schema": { + "type": "object", + "properties": { + "team_id": { + "type": "string" + }, + "team_display_name": { + "type": "string" + } + }, + "required": [ + "team_id", + "team_display_name" + ] + } + } + } + } + } + } + }, + "/team-invitations/send-code": { + "post": { + "summary": "Send an email to invite a user to a team", + "description": "The user receiving this email can join the team by clicking on the link in the email. If the user does not have an account yet, they will be prompted to create one.", + "parameters": [], + "requestBody": { + "required": true, + "content": { + "application/json": { + "schema": { + "type": "object", + "properties": { + "team_id": { + "type": "string", + "example": "ad962777-8244-496a-b6a2-e0c6a449c79e", + "description": "The unique identifier of the team" + }, + "email": { + "type": "string", + "example": "johndoe@example.com", + "description": "The email of the user to invite." + }, + "callback_url": { + "type": "string", + "example": "https://example.com/handler/team-invitation", + "description": "The base callback URL to construct an invite link with. A query parameter `code` with the verification code will be appended to it. The page should then make a request to the `/team-invitations/accept` endpoint." + } + }, + "required": [ + "team_id", + "email", + "callback_url" + ], + "example": { + "team_id": "ad962777-8244-496a-b6a2-e0c6a449c79e", + "email": "johndoe@example.com", + "callback_url": "https://example.com/handler/team-invitation" + } + } + } + } + }, + "tags": [ + "Teams" + ], + "x-full-url": "https://api.stack-auth.com/api/v1/team-invitations/send-code", + "responses": { + "200": { + "description": "Successful response", + "content": { + "application/json": { + "schema": { + "type": "object", + "properties": { + "success": { + "type": "boolean" + }, + "id": { + "type": "string" + } + }, + "required": [ + "success", + "id" + ] + } + } + } + } + } + } + }, + "/team-invitations/{id}": { + "delete": { + "summary": "Delete a team invitation", + "description": "", + "parameters": [ + { + "name": "team_id", + "in": "query", + "schema": { + "type": "string", + "description": "The team ID to list invitations for. Required unless user_id is provided." + }, + "description": "The team ID to list invitations for. Required unless user_id is provided.", + "required": false + }, + { + "name": "id", + "in": "path", + "schema": { + "type": "string" + }, + "required": true + } + ], + "tags": [ + "Teams" + ], + "x-full-url": "https://api.stack-auth.com/api/v1/team-invitations/{id}", + "responses": { + "200": { + "description": "Successful response", + "content": { + "application/json": { + "schema": { + "type": "object", + "properties": { + "success": { + "type": "boolean", + "description": "Always equal to true.", + "example": true + } + }, + "required": [ + "success" + ] + } + } + } + } + } + } + }, + "/team-invitations/{id}/accept": { + "post": { + "summary": "Accept a team invitation by ID", + "description": "Accepts a team invitation for the specified user. The user must have a verified email matching the invitation's recipient email. This marks the invitation as used and adds the user to the team.", + "parameters": [ + { + "name": "user_id", + "in": "query", + "schema": { + "type": "string", + "example": "3241a285-8329-4d69-8f3d-316e08cf140c", + "description": "The ID of the user, or the special value `me` for the currently authenticated user" + }, + "description": "The ID of the user, or the special value `me` for the currently authenticated user", + "required": true + }, + { + "name": "id", + "in": "path", + "schema": { + "type": "string" + }, + "required": true + } + ], + "tags": [ + "Teams" + ], + "x-full-url": "https://api.stack-auth.com/api/v1/team-invitations/{id}/accept", + "responses": { + "200": { + "description": "Successful response", + "content": { + "application/json": { + "schema": { + "type": "object", + "properties": {} + } + } + } + } + } + } + }, + "/team-member-profiles": { + "get": { + "summary": "List team members profiles", + "description": "List team members profiles and filter by team ID and user ID", + "parameters": [ + { + "name": "user_id", + "in": "query", + "schema": { + "type": "string" + }, + "required": false + }, + { + "name": "team_id", + "in": "query", + "schema": { + "type": "string" + }, + "required": false + } + ], + "tags": [ + "Teams" + ], + "x-full-url": "https://api.stack-auth.com/api/v1/team-member-profiles", + "responses": { + "200": { + "description": "Successful response", + "content": { + "application/json": { + "schema": { + "type": "object", + "properties": { + "items": { + "type": "array", + "items": { + "type": "object", + "properties": { + "user": { + "type": "object", + "properties": { + "id": { + "type": "string", + "example": "3241a285-8329-4d69-8f3d-316e08cf140c", + "description": "The unique identifier of the user" + }, + "primary_email": { + "type": "string", + "example": "johndoe@example.com", + "description": "Primary email" + }, + "primary_email_verified": { + "type": "boolean", + "example": true, + "description": "Whether the primary email has been verified to belong to this user" + }, + "primary_email_auth_enabled": { + "type": "boolean", + "example": true, + "description": "Whether the primary email is used for authentication. If this is set to `false`, the user will not be able to sign in with the primary email with password or OTP" + }, + "display_name": { + "type": "string", + "example": "John Doe", + "description": "Human-readable user display name. This is not a unique identifier." + }, + "selected_team": { + "type": "object", + "properties": { + "created_at_millis": { + "type": "number", + "example": 1630000000000, + "description": "The time the team was created (the number of milliseconds since epoch, January 1, 1970, UTC)" + }, + "server_metadata": { + "type": "object", + "example": { + "key": "value" + }, + "description": "Server metadata. Used as a data store, only accessible from the server side. You can store secret information related to the team here." + }, + "id": { + "type": "string", + "example": "ad962777-8244-496a-b6a2-e0c6a449c79e", + "description": "The unique identifier of the team" + }, + "display_name": { + "type": "string", + "example": "My Team", + "description": "Human-readable team display name. This is not a unique identifier." + }, + "profile_image_url": { + "type": "string", + "example": "https://example.com/image.jpg", + "description": "URL of the profile image for team. Can be a Base64 encoded image. Must be smaller than 100KB. Please compress and crop to a square before passing in." + }, + "client_metadata": { + "type": "object", + "example": { + "key": "value" + }, + "description": "Client metadata. Used as a data store, accessible from the client side. Do not store information that should not be exposed to the client." + }, + "client_read_only_metadata": { + "type": "object", + "example": { + "key": "value" + }, + "description": "Client read-only, server-writable metadata. Used as a data store, accessible from the client side. Do not store information that should not be exposed to the client. The client can read this data, but cannot modify it. This is useful for things like subscription status." + } + }, + "required": [ + "created_at_millis", + "id", + "display_name" + ] + }, + "selected_team_id": { + "type": "string", + "example": "team-id", + "description": "ID of the team currently selected by the user" + }, + "profile_image_url": { + "type": "string", + "example": "https://example.com/image.jpg", + "description": "URL of the profile image for user. Can be a Base64 encoded image. Must be smaller than 100KB. Please compress and crop to a square before passing in." + }, + "signed_up_at_millis": { + "type": "number", + "example": 1630000000000, + "description": "The time the user signed up (identify) => `(the number of milliseconds since epoch, January 1, 1970, UTC)`" + }, + "client_metadata": { + "type": "object", + "example": { + "key": "value" + }, + "description": "Client metadata. Used as a data store, accessible from the client side. Do not store information that should not be exposed to the client." + }, + "client_read_only_metadata": { + "type": "object", + "example": { + "key": "value" + }, + "description": "Client read-only, server-writable metadata. Used as a data store, accessible from the client side. Do not store information that should not be exposed to the client. The client can read this data, but cannot modify it. This is useful for things like subscription status." + }, + "server_metadata": { + "type": "object", + "example": { + "key": "value" + }, + "description": "Server metadata. Used as a data store, only accessible from the server side. You can store secret information related to the user here." + }, + "last_active_at_millis": { + "type": "number", + "example": 1630000000000, + "description": "The time the user was last active (identify) => `(the number of milliseconds since epoch, January 1, 1970, UTC)`" + }, + "is_anonymous": { + "type": "boolean" + }, + "is_restricted": { + "type": "boolean", + "example": false, + "description": "Whether the user is in restricted state (has signed up but not completed onboarding requirements)" + }, + "restricted_reason": { + "type": "object", + "properties": { + "type": { + "type": "string" + } + }, + "required": [ + "type" + ], + "example": null, + "description": "The reason why the user is restricted (e.g., type: \"email_not_verified\", \"anonymous\", or \"restricted_by_administrator\"), null if not restricted" + }, + "restricted_by_admin": { + "type": "boolean", + "example": false, + "description": "Whether the user is restricted by an administrator. Can be set manually or by sign-up rules." + }, + "restricted_by_admin_reason": { + "type": "string", + "example": null, + "description": "Public reason shown to the user explaining why they are restricted. Optional." + }, + "restricted_by_admin_private_details": { + "type": "string", + "example": null, + "description": "Private details about the restriction (e.g., which sign-up rule triggered). Only visible to server access and above." + }, + "country_code": { + "type": "string", + "example": "US", + "description": "Best-effort ISO country code captured at sign-up time from request geo headers." + }, + "risk_scores": { + "type": "object", + "properties": { + "sign_up": { + "type": "object", + "properties": { + "bot": { + "type": "number" + }, + "free_trial_abuse": { + "type": "number" + } + }, + "required": [ + "bot", + "free_trial_abuse" + ] + } + }, + "required": [ + "sign_up" + ], + "example": { + "sign_up": { + "bot": 0, + "free_trial_abuse": 0 + } + }, + "description": "User risk scores used for sign-up risk evaluation." + } + }, + "required": [ + "id", + "primary_email_verified", + "primary_email_auth_enabled", + "signed_up_at_millis", + "last_active_at_millis", + "is_anonymous", + "is_restricted", + "restricted_by_admin", + "risk_scores" + ] + }, + "team_id": { + "type": "string", + "example": "ad962777-8244-496a-b6a2-e0c6a449c79e", + "description": "The unique identifier of the team" + }, + "user_id": { + "type": "string", + "example": "3241a285-8329-4d69-8f3d-316e08cf140c", + "description": "The unique identifier of the user" + }, + "display_name": { + "type": "string", + "example": "John Doe", + "description": "Human-readable team member display name. This is not a unique identifier. Note that this is separate from the display_name of the user." + }, + "profile_image_url": { + "type": "string", + "example": "https://example.com/image.jpg", + "description": "URL of the profile image for team member. Can be a Base64 encoded image. Must be smaller than 100KB. Please compress and crop to a square before passing in." + } + }, + "required": [ + "user", + "team_id", + "user_id" + ] + } + }, + "pagination": { + "type": "object", + "properties": { + "next_cursor": { + "type": "string", + "example": "b3d396b8-c574-4c80-97b3-50031675ceb2", + "description": "The cursor to fetch the next page of results. null if there is no next page." + } + }, + "required": [] + } + }, + "required": [ + "items" + ] + } + } + } + } + } + } + }, + "/team-member-profiles/{team_id}/{user_id}": { + "get": { + "summary": "Get a team member profile", + "description": "Get a team member profile by user ID", + "parameters": [ + { + "name": "team_id", + "in": "path", + "schema": { + "type": "string" + }, + "required": true + }, + { + "name": "user_id", + "in": "path", + "schema": { + "type": "string", + "example": "3241a285-8329-4d69-8f3d-316e08cf140c", + "description": "The ID of the user, or the special value `me` for the currently authenticated user" + }, + "description": "The ID of the user, or the special value `me` for the currently authenticated user", + "required": true + } + ], + "tags": [ + "Teams" + ], + "x-full-url": "https://api.stack-auth.com/api/v1/team-member-profiles/{team_id}/{user_id}", + "responses": { + "200": { + "description": "Successful response", + "content": { + "application/json": { + "schema": { + "type": "object", + "properties": { + "user": { + "type": "object", + "properties": { + "id": { + "type": "string", + "example": "3241a285-8329-4d69-8f3d-316e08cf140c", + "description": "The unique identifier of the user" + }, + "primary_email": { + "type": "string", + "example": "johndoe@example.com", + "description": "Primary email" + }, + "primary_email_verified": { + "type": "boolean", + "example": true, + "description": "Whether the primary email has been verified to belong to this user" + }, + "primary_email_auth_enabled": { + "type": "boolean", + "example": true, + "description": "Whether the primary email is used for authentication. If this is set to `false`, the user will not be able to sign in with the primary email with password or OTP" + }, + "display_name": { + "type": "string", + "example": "John Doe", + "description": "Human-readable user display name. This is not a unique identifier." + }, + "selected_team": { + "type": "object", + "properties": { + "created_at_millis": { + "type": "number", + "example": 1630000000000, + "description": "The time the team was created (the number of milliseconds since epoch, January 1, 1970, UTC)" + }, + "server_metadata": { + "type": "object", + "example": { + "key": "value" + }, + "description": "Server metadata. Used as a data store, only accessible from the server side. You can store secret information related to the team here." + }, + "id": { + "type": "string", + "example": "ad962777-8244-496a-b6a2-e0c6a449c79e", + "description": "The unique identifier of the team" + }, + "display_name": { + "type": "string", + "example": "My Team", + "description": "Human-readable team display name. This is not a unique identifier." + }, + "profile_image_url": { + "type": "string", + "example": "https://example.com/image.jpg", + "description": "URL of the profile image for team. Can be a Base64 encoded image. Must be smaller than 100KB. Please compress and crop to a square before passing in." + }, + "client_metadata": { + "type": "object", + "example": { + "key": "value" + }, + "description": "Client metadata. Used as a data store, accessible from the client side. Do not store information that should not be exposed to the client." + }, + "client_read_only_metadata": { + "type": "object", + "example": { + "key": "value" + }, + "description": "Client read-only, server-writable metadata. Used as a data store, accessible from the client side. Do not store information that should not be exposed to the client. The client can read this data, but cannot modify it. This is useful for things like subscription status." + } + }, + "required": [ + "created_at_millis", + "id", + "display_name" + ] + }, + "selected_team_id": { + "type": "string", + "example": "team-id", + "description": "ID of the team currently selected by the user" + }, + "profile_image_url": { + "type": "string", + "example": "https://example.com/image.jpg", + "description": "URL of the profile image for user. Can be a Base64 encoded image. Must be smaller than 100KB. Please compress and crop to a square before passing in." + }, + "signed_up_at_millis": { + "type": "number", + "example": 1630000000000, + "description": "The time the user signed up (identify) => `(the number of milliseconds since epoch, January 1, 1970, UTC)`" + }, + "client_metadata": { + "type": "object", + "example": { + "key": "value" + }, + "description": "Client metadata. Used as a data store, accessible from the client side. Do not store information that should not be exposed to the client." + }, + "client_read_only_metadata": { + "type": "object", + "example": { + "key": "value" + }, + "description": "Client read-only, server-writable metadata. Used as a data store, accessible from the client side. Do not store information that should not be exposed to the client. The client can read this data, but cannot modify it. This is useful for things like subscription status." + }, + "server_metadata": { + "type": "object", + "example": { + "key": "value" + }, + "description": "Server metadata. Used as a data store, only accessible from the server side. You can store secret information related to the user here." + }, + "last_active_at_millis": { + "type": "number", + "example": 1630000000000, + "description": "The time the user was last active (identify) => `(the number of milliseconds since epoch, January 1, 1970, UTC)`" + }, + "is_anonymous": { + "type": "boolean" + }, + "is_restricted": { + "type": "boolean", + "example": false, + "description": "Whether the user is in restricted state (has signed up but not completed onboarding requirements)" + }, + "restricted_reason": { + "type": "object", + "properties": { + "type": { + "type": "string" + } + }, + "required": [ + "type" + ], + "example": null, + "description": "The reason why the user is restricted (e.g., type: \"email_not_verified\", \"anonymous\", or \"restricted_by_administrator\"), null if not restricted" + }, + "restricted_by_admin": { + "type": "boolean", + "example": false, + "description": "Whether the user is restricted by an administrator. Can be set manually or by sign-up rules." + }, + "restricted_by_admin_reason": { + "type": "string", + "example": null, + "description": "Public reason shown to the user explaining why they are restricted. Optional." + }, + "restricted_by_admin_private_details": { + "type": "string", + "example": null, + "description": "Private details about the restriction (e.g., which sign-up rule triggered). Only visible to server access and above." + }, + "country_code": { + "type": "string", + "example": "US", + "description": "Best-effort ISO country code captured at sign-up time from request geo headers." + }, + "risk_scores": { + "type": "object", + "properties": { + "sign_up": { + "type": "object", + "properties": { + "bot": { + "type": "number" + }, + "free_trial_abuse": { + "type": "number" + } + }, + "required": [ + "bot", + "free_trial_abuse" + ] + } + }, + "required": [ + "sign_up" + ], + "example": { + "sign_up": { + "bot": 0, + "free_trial_abuse": 0 + } + }, + "description": "User risk scores used for sign-up risk evaluation." + } + }, + "required": [ + "id", + "primary_email_verified", + "primary_email_auth_enabled", + "signed_up_at_millis", + "last_active_at_millis", + "is_anonymous", + "is_restricted", + "restricted_by_admin", + "risk_scores" + ] + }, + "team_id": { + "type": "string", + "example": "ad962777-8244-496a-b6a2-e0c6a449c79e", + "description": "The unique identifier of the team" + }, + "user_id": { + "type": "string", + "example": "3241a285-8329-4d69-8f3d-316e08cf140c", + "description": "The unique identifier of the user" + }, + "display_name": { + "type": "string", + "example": "John Doe", + "description": "Human-readable team member display name. This is not a unique identifier. Note that this is separate from the display_name of the user." + }, + "profile_image_url": { + "type": "string", + "example": "https://example.com/image.jpg", + "description": "URL of the profile image for team member. Can be a Base64 encoded image. Must be smaller than 100KB. Please compress and crop to a square before passing in." + } + }, + "required": [ + "user", + "team_id", + "user_id" + ] + } + } + } + } + } + }, + "patch": { + "summary": "Update a team member profile", + "description": "Update a team member profile by user ID", + "parameters": [ + { + "name": "team_id", + "in": "path", + "schema": { + "type": "string" + }, + "required": true + }, + { + "name": "user_id", + "in": "path", + "schema": { + "type": "string", + "example": "3241a285-8329-4d69-8f3d-316e08cf140c", + "description": "The ID of the user, or the special value `me` for the currently authenticated user" + }, + "description": "The ID of the user, or the special value `me` for the currently authenticated user", + "required": true + } + ], + "requestBody": { + "required": true, + "content": { + "application/json": { + "schema": { + "type": "object", + "properties": { + "display_name": { + "type": "string", + "example": "John Doe", + "description": "Human-readable team member display name. This is not a unique identifier. Note that this is separate from the display_name of the user." + }, + "profile_image_url": { + "type": "string", + "example": "https://example.com/image.jpg", + "description": "URL of the profile image for team member. Can be a Base64 encoded image. Must be smaller than 100KB. Please compress and crop to a square before passing in." + } + }, + "example": { + "display_name": "John Doe", + "profile_image_url": "https://example.com/image.jpg" + } + } + } + } + }, + "tags": [ + "Teams" + ], + "x-full-url": "https://api.stack-auth.com/api/v1/team-member-profiles/{team_id}/{user_id}", + "responses": { + "200": { + "description": "Successful response", + "content": { + "application/json": { + "schema": { + "type": "object", + "properties": { + "user": { + "type": "object", + "properties": { + "id": { + "type": "string", + "example": "3241a285-8329-4d69-8f3d-316e08cf140c", + "description": "The unique identifier of the user" + }, + "primary_email": { + "type": "string", + "example": "johndoe@example.com", + "description": "Primary email" + }, + "primary_email_verified": { + "type": "boolean", + "example": true, + "description": "Whether the primary email has been verified to belong to this user" + }, + "primary_email_auth_enabled": { + "type": "boolean", + "example": true, + "description": "Whether the primary email is used for authentication. If this is set to `false`, the user will not be able to sign in with the primary email with password or OTP" + }, + "display_name": { + "type": "string", + "example": "John Doe", + "description": "Human-readable user display name. This is not a unique identifier." + }, + "selected_team": { + "type": "object", + "properties": { + "created_at_millis": { + "type": "number", + "example": 1630000000000, + "description": "The time the team was created (the number of milliseconds since epoch, January 1, 1970, UTC)" + }, + "server_metadata": { + "type": "object", + "example": { + "key": "value" + }, + "description": "Server metadata. Used as a data store, only accessible from the server side. You can store secret information related to the team here." + }, + "id": { + "type": "string", + "example": "ad962777-8244-496a-b6a2-e0c6a449c79e", + "description": "The unique identifier of the team" + }, + "display_name": { + "type": "string", + "example": "My Team", + "description": "Human-readable team display name. This is not a unique identifier." + }, + "profile_image_url": { + "type": "string", + "example": "https://example.com/image.jpg", + "description": "URL of the profile image for team. Can be a Base64 encoded image. Must be smaller than 100KB. Please compress and crop to a square before passing in." + }, + "client_metadata": { + "type": "object", + "example": { + "key": "value" + }, + "description": "Client metadata. Used as a data store, accessible from the client side. Do not store information that should not be exposed to the client." + }, + "client_read_only_metadata": { + "type": "object", + "example": { + "key": "value" + }, + "description": "Client read-only, server-writable metadata. Used as a data store, accessible from the client side. Do not store information that should not be exposed to the client. The client can read this data, but cannot modify it. This is useful for things like subscription status." + } + }, + "required": [ + "created_at_millis", + "id", + "display_name" + ] + }, + "selected_team_id": { + "type": "string", + "example": "team-id", + "description": "ID of the team currently selected by the user" + }, + "profile_image_url": { + "type": "string", + "example": "https://example.com/image.jpg", + "description": "URL of the profile image for user. Can be a Base64 encoded image. Must be smaller than 100KB. Please compress and crop to a square before passing in." + }, + "signed_up_at_millis": { + "type": "number", + "example": 1630000000000, + "description": "The time the user signed up (identify) => `(the number of milliseconds since epoch, January 1, 1970, UTC)`" + }, + "client_metadata": { + "type": "object", + "example": { + "key": "value" + }, + "description": "Client metadata. Used as a data store, accessible from the client side. Do not store information that should not be exposed to the client." + }, + "client_read_only_metadata": { + "type": "object", + "example": { + "key": "value" + }, + "description": "Client read-only, server-writable metadata. Used as a data store, accessible from the client side. Do not store information that should not be exposed to the client. The client can read this data, but cannot modify it. This is useful for things like subscription status." + }, + "server_metadata": { + "type": "object", + "example": { + "key": "value" + }, + "description": "Server metadata. Used as a data store, only accessible from the server side. You can store secret information related to the user here." + }, + "last_active_at_millis": { + "type": "number", + "example": 1630000000000, + "description": "The time the user was last active (identify) => `(the number of milliseconds since epoch, January 1, 1970, UTC)`" + }, + "is_anonymous": { + "type": "boolean" + }, + "is_restricted": { + "type": "boolean", + "example": false, + "description": "Whether the user is in restricted state (has signed up but not completed onboarding requirements)" + }, + "restricted_reason": { + "type": "object", + "properties": { + "type": { + "type": "string" + } + }, + "required": [ + "type" + ], + "example": null, + "description": "The reason why the user is restricted (e.g., type: \"email_not_verified\", \"anonymous\", or \"restricted_by_administrator\"), null if not restricted" + }, + "restricted_by_admin": { + "type": "boolean", + "example": false, + "description": "Whether the user is restricted by an administrator. Can be set manually or by sign-up rules." + }, + "restricted_by_admin_reason": { + "type": "string", + "example": null, + "description": "Public reason shown to the user explaining why they are restricted. Optional." + }, + "restricted_by_admin_private_details": { + "type": "string", + "example": null, + "description": "Private details about the restriction (e.g., which sign-up rule triggered). Only visible to server access and above." + }, + "country_code": { + "type": "string", + "example": "US", + "description": "Best-effort ISO country code captured at sign-up time from request geo headers." + }, + "risk_scores": { + "type": "object", + "properties": { + "sign_up": { + "type": "object", + "properties": { + "bot": { + "type": "number" + }, + "free_trial_abuse": { + "type": "number" + } + }, + "required": [ + "bot", + "free_trial_abuse" + ] + } + }, + "required": [ + "sign_up" + ], + "example": { + "sign_up": { + "bot": 0, + "free_trial_abuse": 0 + } + }, + "description": "User risk scores used for sign-up risk evaluation." + } + }, + "required": [ + "id", + "primary_email_verified", + "primary_email_auth_enabled", + "signed_up_at_millis", + "last_active_at_millis", + "is_anonymous", + "is_restricted", + "restricted_by_admin", + "risk_scores" + ] + }, + "team_id": { + "type": "string", + "example": "ad962777-8244-496a-b6a2-e0c6a449c79e", + "description": "The unique identifier of the team" + }, + "user_id": { + "type": "string", + "example": "3241a285-8329-4d69-8f3d-316e08cf140c", + "description": "The unique identifier of the user" + }, + "display_name": { + "type": "string", + "example": "John Doe", + "description": "Human-readable team member display name. This is not a unique identifier. Note that this is separate from the display_name of the user." + }, + "profile_image_url": { + "type": "string", + "example": "https://example.com/image.jpg", + "description": "URL of the profile image for team member. Can be a Base64 encoded image. Must be smaller than 100KB. Please compress and crop to a square before passing in." + } + }, + "required": [ + "user", + "team_id", + "user_id" + ] + } + } + } + } + } + } + }, + "/team-memberships/{team_id}/{user_id}": { + "post": { + "summary": "Add a user to a team", + "description": "", + "parameters": [ + { + "name": "team_id", + "in": "path", + "schema": { + "type": "string" + }, + "required": false + }, + { + "name": "user_id", + "in": "path", + "schema": { + "type": "string", + "example": "3241a285-8329-4d69-8f3d-316e08cf140c", + "description": "The ID of the user, or the special value `me` for the currently authenticated user" + }, + "description": "The ID of the user, or the special value `me` for the currently authenticated user", + "required": false + } + ], + "requestBody": { + "required": true, + "content": { + "application/json": { + "schema": { + "type": "object", + "properties": {}, + "example": {} + } + } + } + }, + "tags": [ + "Teams" + ], + "x-full-url": "https://api.stack-auth.com/api/v1/team-memberships/{team_id}/{user_id}", + "responses": { + "201": { + "description": "Successful response", + "content": { + "application/json": { + "schema": { + "type": "object", + "properties": { + "team_id": { + "type": "string" + }, + "user_id": { + "type": "string" + } + }, + "required": [ + "team_id", + "user_id" + ] + } + } + } + } + } + }, + "delete": { + "summary": "Remove a user from a team", + "description": "", + "parameters": [ + { + "name": "team_id", + "in": "path", + "schema": { + "type": "string" + }, + "required": true + }, + { + "name": "user_id", + "in": "path", + "schema": { + "type": "string", + "example": "3241a285-8329-4d69-8f3d-316e08cf140c", + "description": "The ID of the user, or the special value `me` for the currently authenticated user" + }, + "description": "The ID of the user, or the special value `me` for the currently authenticated user", + "required": true + } + ], + "tags": [ + "Teams" + ], + "x-full-url": "https://api.stack-auth.com/api/v1/team-memberships/{team_id}/{user_id}", + "responses": { + "200": { + "description": "Successful response", + "content": { + "application/json": { + "schema": { + "type": "object", + "properties": { + "success": { + "type": "boolean", + "description": "Always equal to true.", + "example": true + } + }, + "required": [ + "success" + ] + } + } + } + } + } + } + }, + "/teams": { + "get": { + "summary": "List teams", + "description": "List all the teams in the project.", + "parameters": [ + { + "name": "user_id", + "in": "query", + "schema": { + "type": "string", + "example": "me", + "description": "Filter for the teams that the user is a member of. Can be either `me` or an ID. Must be `me` in the client API" + }, + "description": "Filter for the teams that the user is a member of. Can be either `me` or an ID. Must be `me` in the client API", + "required": false + } + ], + "tags": [ + "Teams" + ], + "x-full-url": "https://api.stack-auth.com/api/v1/teams", + "responses": { + "200": { + "description": "Successful response", + "content": { + "application/json": { + "schema": { + "type": "object", + "properties": { + "items": { + "type": "array", + "items": { + "type": "object", + "properties": { + "created_at_millis": { + "type": "number", + "example": 1630000000000, + "description": "The time the team was created (the number of milliseconds since epoch, January 1, 1970, UTC)" + }, + "server_metadata": { + "type": "object", + "example": { + "key": "value" + }, + "description": "Server metadata. Used as a data store, only accessible from the server side. You can store secret information related to the team here." + }, + "id": { + "type": "string", + "example": "ad962777-8244-496a-b6a2-e0c6a449c79e", + "description": "The unique identifier of the team" + }, + "display_name": { + "type": "string", + "example": "My Team", + "description": "Human-readable team display name. This is not a unique identifier." + }, + "profile_image_url": { + "type": "string", + "example": "https://example.com/image.jpg", + "description": "URL of the profile image for team. Can be a Base64 encoded image. Must be smaller than 100KB. Please compress and crop to a square before passing in." + }, + "client_metadata": { + "type": "object", + "example": { + "key": "value" + }, + "description": "Client metadata. Used as a data store, accessible from the client side. Do not store information that should not be exposed to the client." + }, + "client_read_only_metadata": { + "type": "object", + "example": { + "key": "value" + }, + "description": "Client read-only, server-writable metadata. Used as a data store, accessible from the client side. Do not store information that should not be exposed to the client. The client can read this data, but cannot modify it. This is useful for things like subscription status." + } + }, + "required": [ + "created_at_millis", + "id", + "display_name" + ] + } + }, + "pagination": { + "type": "object", + "properties": { + "next_cursor": { + "type": "string", + "example": "b3d396b8-c574-4c80-97b3-50031675ceb2", + "description": "The cursor to fetch the next page of results. null if there is no next page." + } + }, + "required": [] + } + }, + "required": [ + "items" + ] + } + } + } + } + } + }, + "post": { + "summary": "Create a team", + "description": "Create a new team and optionally add the current user as a member.", + "parameters": [], + "requestBody": { + "required": true, + "content": { + "application/json": { + "schema": { + "type": "object", + "properties": { + "display_name": { + "type": "string", + "example": "My Team", + "description": "Human-readable team display name. This is not a unique identifier." + }, + "creator_user_id": { + "type": "string", + "example": "me", + "description": "The ID of the creator of the team. If not specified, the user will not be added to the team. Can be either \"me\" or the ID of the user. Only used on the client side." + }, + "client_read_only_metadata": { + "type": "object", + "example": { + "key": "value" + }, + "description": "Client read-only, server-writable metadata. Used as a data store, accessible from the client side. Do not store information that should not be exposed to the client. The client can read this data, but cannot modify it. This is useful for things like subscription status." + }, + "server_metadata": { + "type": "object", + "example": { + "key": "value" + }, + "description": "Server metadata. Used as a data store, only accessible from the server side. You can store secret information related to the team here." + }, + "profile_image_url": { + "type": "string", + "example": "https://example.com/image.jpg", + "description": "URL of the profile image for team. Can be a Base64 encoded image. Must be smaller than 100KB. Please compress and crop to a square before passing in." + }, + "client_metadata": { + "type": "object", + "example": { + "key": "value" + }, + "description": "Client metadata. Used as a data store, accessible from the client side. Do not store information that should not be exposed to the client." + } + }, + "required": [ + "display_name" + ], + "example": { + "display_name": "My Team", + "creator_user_id": "me", + "client_read_only_metadata": { + "key": "value" + }, + "server_metadata": { + "key": "value" + }, + "profile_image_url": "https://example.com/image.jpg", + "client_metadata": { + "key": "value" + } + } + } + } + } + }, + "tags": [ + "Teams" + ], + "x-full-url": "https://api.stack-auth.com/api/v1/teams", + "responses": { + "201": { + "description": "Successful response", + "content": { + "application/json": { + "schema": { + "type": "object", + "properties": { + "created_at_millis": { + "type": "number", + "example": 1630000000000, + "description": "The time the team was created (the number of milliseconds since epoch, January 1, 1970, UTC)" + }, + "server_metadata": { + "type": "object", + "example": { + "key": "value" + }, + "description": "Server metadata. Used as a data store, only accessible from the server side. You can store secret information related to the team here." + }, + "id": { + "type": "string", + "example": "ad962777-8244-496a-b6a2-e0c6a449c79e", + "description": "The unique identifier of the team" + }, + "display_name": { + "type": "string", + "example": "My Team", + "description": "Human-readable team display name. This is not a unique identifier." + }, + "profile_image_url": { + "type": "string", + "example": "https://example.com/image.jpg", + "description": "URL of the profile image for team. Can be a Base64 encoded image. Must be smaller than 100KB. Please compress and crop to a square before passing in." + }, + "client_metadata": { + "type": "object", + "example": { + "key": "value" + }, + "description": "Client metadata. Used as a data store, accessible from the client side. Do not store information that should not be exposed to the client." + }, + "client_read_only_metadata": { + "type": "object", + "example": { + "key": "value" + }, + "description": "Client read-only, server-writable metadata. Used as a data store, accessible from the client side. Do not store information that should not be exposed to the client. The client can read this data, but cannot modify it. This is useful for things like subscription status." + } + }, + "required": [ + "created_at_millis", + "id", + "display_name" + ] + } + } + } + } + } + } + }, + "/teams/{team_id}": { + "get": { + "summary": "Get a team", + "description": "Get a team by ID.", + "parameters": [ + { + "name": "team_id", + "in": "path", + "schema": { + "type": "string" + }, + "required": true + } + ], + "tags": [ + "Teams" + ], + "x-full-url": "https://api.stack-auth.com/api/v1/teams/{team_id}", + "responses": { + "200": { + "description": "Successful response", + "content": { + "application/json": { + "schema": { + "type": "object", + "properties": { + "created_at_millis": { + "type": "number", + "example": 1630000000000, + "description": "The time the team was created (the number of milliseconds since epoch, January 1, 1970, UTC)" + }, + "server_metadata": { + "type": "object", + "example": { + "key": "value" + }, + "description": "Server metadata. Used as a data store, only accessible from the server side. You can store secret information related to the team here." + }, + "id": { + "type": "string", + "example": "ad962777-8244-496a-b6a2-e0c6a449c79e", + "description": "The unique identifier of the team" + }, + "display_name": { + "type": "string", + "example": "My Team", + "description": "Human-readable team display name. This is not a unique identifier." + }, + "profile_image_url": { + "type": "string", + "example": "https://example.com/image.jpg", + "description": "URL of the profile image for team. Can be a Base64 encoded image. Must be smaller than 100KB. Please compress and crop to a square before passing in." + }, + "client_metadata": { + "type": "object", + "example": { + "key": "value" + }, + "description": "Client metadata. Used as a data store, accessible from the client side. Do not store information that should not be exposed to the client." + }, + "client_read_only_metadata": { + "type": "object", + "example": { + "key": "value" + }, + "description": "Client read-only, server-writable metadata. Used as a data store, accessible from the client side. Do not store information that should not be exposed to the client. The client can read this data, but cannot modify it. This is useful for things like subscription status." + } + }, + "required": [ + "created_at_millis", + "id", + "display_name" + ] + } + } + } + } + } + }, + "delete": { + "summary": "Delete a team", + "description": "Delete a team by ID.", + "parameters": [ + { + "name": "team_id", + "in": "path", + "schema": { + "type": "string" + }, + "required": true + } + ], + "tags": [ + "Teams" + ], + "x-full-url": "https://api.stack-auth.com/api/v1/teams/{team_id}", + "responses": { + "200": { + "description": "Successful response", + "content": { + "application/json": { + "schema": { + "type": "object", + "properties": { + "success": { + "type": "boolean", + "description": "Always equal to true.", + "example": true + } + }, + "required": [ + "success" + ] + } + } + } + } + } + }, + "patch": { + "summary": "Update a team", + "description": "Update the team information by ID.", + "parameters": [ + { + "name": "team_id", + "in": "path", + "schema": { + "type": "string" + }, + "required": true + } + ], + "requestBody": { + "required": true, + "content": { + "application/json": { + "schema": { + "type": "object", + "properties": { + "client_read_only_metadata": { + "type": "object", + "example": { + "key": "value" + }, + "description": "Client read-only, server-writable metadata. Used as a data store, accessible from the client side. Do not store information that should not be exposed to the client. The client can read this data, but cannot modify it. This is useful for things like subscription status." + }, + "server_metadata": { + "type": "object", + "example": { + "key": "value" + }, + "description": "Server metadata. Used as a data store, only accessible from the server side. You can store secret information related to the team here." + }, + "display_name": { + "type": "string", + "example": "My Team", + "description": "Human-readable team display name. This is not a unique identifier." + }, + "profile_image_url": { + "type": "string", + "example": "https://example.com/image.jpg", + "description": "URL of the profile image for team. Can be a Base64 encoded image. Must be smaller than 100KB. Please compress and crop to a square before passing in." + }, + "client_metadata": { + "type": "object", + "example": { + "key": "value" + }, + "description": "Client metadata. Used as a data store, accessible from the client side. Do not store information that should not be exposed to the client." + } + }, + "example": { + "client_read_only_metadata": { + "key": "value" + }, + "server_metadata": { + "key": "value" + }, + "display_name": "My Team", + "profile_image_url": "https://example.com/image.jpg", + "client_metadata": { + "key": "value" + } + } + } + } + } + }, + "tags": [ + "Teams" + ], + "x-full-url": "https://api.stack-auth.com/api/v1/teams/{team_id}", + "responses": { + "200": { + "description": "Successful response", + "content": { + "application/json": { + "schema": { + "type": "object", + "properties": { + "created_at_millis": { + "type": "number", + "example": 1630000000000, + "description": "The time the team was created (the number of milliseconds since epoch, January 1, 1970, UTC)" + }, + "server_metadata": { + "type": "object", + "example": { + "key": "value" + }, + "description": "Server metadata. Used as a data store, only accessible from the server side. You can store secret information related to the team here." + }, + "id": { + "type": "string", + "example": "ad962777-8244-496a-b6a2-e0c6a449c79e", + "description": "The unique identifier of the team" + }, + "display_name": { + "type": "string", + "example": "My Team", + "description": "Human-readable team display name. This is not a unique identifier." + }, + "profile_image_url": { + "type": "string", + "example": "https://example.com/image.jpg", + "description": "URL of the profile image for team. Can be a Base64 encoded image. Must be smaller than 100KB. Please compress and crop to a square before passing in." + }, + "client_metadata": { + "type": "object", + "example": { + "key": "value" + }, + "description": "Client metadata. Used as a data store, accessible from the client side. Do not store information that should not be exposed to the client." + }, + "client_read_only_metadata": { + "type": "object", + "example": { + "key": "value" + }, + "description": "Client read-only, server-writable metadata. Used as a data store, accessible from the client side. Do not store information that should not be exposed to the client. The client can read this data, but cannot modify it. This is useful for things like subscription status." + } + }, + "required": [ + "created_at_millis", + "id", + "display_name" + ] + } + } + } + } + } + } + }, + "/users": { + "get": { + "summary": "List users", + "description": "Lists all the users in the project. By default, only fully onboarded users are returned. Restricted users (those who haven't completed onboarding requirements like email verification) are included if `include_restricted` is set to `true`. Anonymous users are included if `include_anonymous` is set to `true` (which also includes restricted users).", + "parameters": [ + { + "name": "team_id", + "in": "query", + "schema": { + "type": "string", + "description": "Only return users who are members of the given team" + }, + "description": "Only return users who are members of the given team", + "required": false + }, + { + "name": "limit", + "in": "query", + "schema": { + "type": "number", + "description": "The maximum number of items to return" + }, + "description": "The maximum number of items to return", + "required": false + }, + { + "name": "cursor", + "in": "query", + "schema": { + "type": "string", + "description": "The cursor to start the result set from." + }, + "description": "The cursor to start the result set from.", + "required": false + }, + { + "name": "order_by", + "in": "query", + "schema": { + "type": "string", + "description": "The field to sort the results by. Defaults to signed_up_at" + }, + "description": "The field to sort the results by. Defaults to signed_up_at", + "required": false + }, + { + "name": "desc", + "in": "query", + "schema": { + "type": "string", + "description": "Whether to sort the results in descending order. Defaults to false" + }, + "description": "Whether to sort the results in descending order. Defaults to false", + "required": false + }, + { + "name": "query", + "in": "query", + "schema": { + "type": "string", + "description": "A search query to filter the results by. This is a free-text search that is applied to the user's id (exact-match only), display name and primary email." + }, + "description": "A search query to filter the results by. This is a free-text search that is applied to the user's id (exact-match only), display name and primary email.", + "required": false + }, + { + "name": "include_anonymous", + "in": "query", + "schema": { + "type": "string", + "description": "Whether to include anonymous users in the results. When true, also includes restricted users. Defaults to false" + }, + "description": "Whether to include anonymous users in the results. When true, also includes restricted users. Defaults to false", + "required": false + }, + { + "name": "only_anonymous", + "in": "query", + "schema": { + "type": "string", + "description": "Whether to return only anonymous users. When true, implies include_anonymous=true. Defaults to false" + }, + "description": "Whether to return only anonymous users. When true, implies include_anonymous=true. Defaults to false", + "required": false + }, + { + "name": "include_restricted", + "in": "query", + "schema": { + "type": "string", + "description": "Whether to include restricted users in the results. Defaults to false" + }, + "description": "Whether to include restricted users in the results. Defaults to false", + "required": false + } + ], + "tags": [ + "Users" + ], + "x-full-url": "https://api.stack-auth.com/api/v1/users", + "responses": { + "200": { + "description": "Successful response", + "content": { + "application/json": { + "schema": { + "type": "object", + "properties": { + "items": { + "type": "array", + "items": { + "type": "object", + "properties": { + "id": { + "type": "string", + "example": "3241a285-8329-4d69-8f3d-316e08cf140c", + "description": "The unique identifier of the user" + }, + "primary_email": { + "type": "string", + "example": "johndoe@example.com", + "description": "Primary email" + }, + "primary_email_verified": { + "type": "boolean", + "example": true, + "description": "Whether the primary email has been verified to belong to this user" + }, + "primary_email_auth_enabled": { + "type": "boolean", + "example": true, + "description": "Whether the primary email is used for authentication. If this is set to `false`, the user will not be able to sign in with the primary email with password or OTP" + }, + "display_name": { + "type": "string", + "example": "John Doe", + "description": "Human-readable user display name. This is not a unique identifier." + }, + "selected_team": { + "type": "object", + "properties": { + "created_at_millis": { + "type": "number", + "example": 1630000000000, + "description": "The time the team was created (the number of milliseconds since epoch, January 1, 1970, UTC)" + }, + "server_metadata": { + "type": "object", + "example": { + "key": "value" + }, + "description": "Server metadata. Used as a data store, only accessible from the server side. You can store secret information related to the team here." + }, + "id": { + "type": "string", + "example": "ad962777-8244-496a-b6a2-e0c6a449c79e", + "description": "The unique identifier of the team" + }, + "display_name": { + "type": "string", + "example": "My Team", + "description": "Human-readable team display name. This is not a unique identifier." + }, + "profile_image_url": { + "type": "string", + "example": "https://example.com/image.jpg", + "description": "URL of the profile image for team. Can be a Base64 encoded image. Must be smaller than 100KB. Please compress and crop to a square before passing in." + }, + "client_metadata": { + "type": "object", + "example": { + "key": "value" + }, + "description": "Client metadata. Used as a data store, accessible from the client side. Do not store information that should not be exposed to the client." + }, + "client_read_only_metadata": { + "type": "object", + "example": { + "key": "value" + }, + "description": "Client read-only, server-writable metadata. Used as a data store, accessible from the client side. Do not store information that should not be exposed to the client. The client can read this data, but cannot modify it. This is useful for things like subscription status." + } + }, + "required": [ + "created_at_millis", + "id", + "display_name" + ] + }, + "selected_team_id": { + "type": "string", + "example": "team-id", + "description": "ID of the team currently selected by the user" + }, + "profile_image_url": { + "type": "string", + "example": "https://example.com/image.jpg", + "description": "URL of the profile image for user. Can be a Base64 encoded image. Must be smaller than 100KB. Please compress and crop to a square before passing in." + }, + "signed_up_at_millis": { + "type": "number", + "example": 1630000000000, + "description": "The time the user signed up (identify) => `(the number of milliseconds since epoch, January 1, 1970, UTC)`" + }, + "client_metadata": { + "type": "object", + "example": { + "key": "value" + }, + "description": "Client metadata. Used as a data store, accessible from the client side. Do not store information that should not be exposed to the client." + }, + "client_read_only_metadata": { + "type": "object", + "example": { + "key": "value" + }, + "description": "Client read-only, server-writable metadata. Used as a data store, accessible from the client side. Do not store information that should not be exposed to the client. The client can read this data, but cannot modify it. This is useful for things like subscription status." + }, + "server_metadata": { + "type": "object", + "example": { + "key": "value" + }, + "description": "Server metadata. Used as a data store, only accessible from the server side. You can store secret information related to the user here." + }, + "last_active_at_millis": { + "type": "number", + "example": 1630000000000, + "description": "The time the user was last active (identify) => `(the number of milliseconds since epoch, January 1, 1970, UTC)`" + }, + "is_anonymous": { + "type": "boolean" + }, + "is_restricted": { + "type": "boolean", + "example": false, + "description": "Whether the user is in restricted state (has signed up but not completed onboarding requirements)" + }, + "restricted_reason": { + "type": "object", + "properties": { + "type": { + "type": "string" + } + }, + "required": [ + "type" + ], + "example": null, + "description": "The reason why the user is restricted (e.g., type: \"email_not_verified\", \"anonymous\", or \"restricted_by_administrator\"), null if not restricted" + }, + "restricted_by_admin": { + "type": "boolean", + "example": false, + "description": "Whether the user is restricted by an administrator. Can be set manually or by sign-up rules." + }, + "restricted_by_admin_reason": { + "type": "string", + "example": null, + "description": "Public reason shown to the user explaining why they are restricted. Optional." + }, + "restricted_by_admin_private_details": { + "type": "string", + "example": null, + "description": "Private details about the restriction (e.g., which sign-up rule triggered). Only visible to server access and above." + }, + "country_code": { + "type": "string", + "example": "US", + "description": "Best-effort ISO country code captured at sign-up time from request geo headers." + }, + "risk_scores": { + "type": "object", + "properties": { + "sign_up": { + "type": "object", + "properties": { + "bot": { + "type": "number" + }, + "free_trial_abuse": { + "type": "number" + } + }, + "required": [ + "bot", + "free_trial_abuse" + ] + } + }, + "required": [ + "sign_up" + ], + "example": { + "sign_up": { + "bot": 0, + "free_trial_abuse": 0 + } + }, + "description": "User risk scores used for sign-up risk evaluation." + } + }, + "required": [ + "id", + "primary_email_verified", + "primary_email_auth_enabled", + "signed_up_at_millis", + "last_active_at_millis", + "is_anonymous", + "is_restricted", + "restricted_by_admin", + "risk_scores" + ] + } + }, + "pagination": { + "type": "object", + "properties": { + "next_cursor": { + "type": "string", + "example": "b3d396b8-c574-4c80-97b3-50031675ceb2", + "description": "The cursor to fetch the next page of results. null if there is no next page." + } + }, + "required": [] + } + }, + "required": [ + "items" + ] + } + } + } + } + } + }, + "post": { + "summary": "Create user", + "description": "Creates a new user. E-mail authentication is always enabled, and no password is set, meaning the only way to authenticate the newly created user is through magic link.", + "parameters": [], + "requestBody": { + "required": true, + "content": { + "application/json": { + "schema": { + "type": "object", + "properties": { + "is_anonymous": { + "type": "boolean" + }, + "display_name": { + "type": "string", + "example": "John Doe", + "description": "Human-readable user display name. This is not a unique identifier." + }, + "profile_image_url": { + "type": "string", + "example": "https://example.com/image.jpg", + "description": "URL of the profile image for user. Can be a Base64 encoded image. Must be smaller than 100KB. Please compress and crop to a square before passing in." + }, + "client_metadata": { + "type": "object", + "example": { + "key": "value" + }, + "description": "Client metadata. Used as a data store, accessible from the client side. Do not store information that should not be exposed to the client." + }, + "client_read_only_metadata": { + "type": "object", + "example": { + "key": "value" + }, + "description": "Client read-only, server-writable metadata. Used as a data store, accessible from the client side. Do not store information that should not be exposed to the client. The client can read this data, but cannot modify it. This is useful for things like subscription status." + }, + "server_metadata": { + "type": "object", + "example": { + "key": "value" + }, + "description": "Server metadata. Used as a data store, only accessible from the server side. You can store secret information related to the user here." + }, + "primary_email": { + "type": "string", + "example": "johndoe@example.com", + "description": "Primary email" + }, + "primary_email_verified": { + "type": "boolean", + "example": true, + "description": "Whether the primary email has been verified to belong to this user" + }, + "primary_email_auth_enabled": { + "type": "boolean", + "example": true, + "description": "Whether the primary email is used for authentication. If this is set to `false`, the user will not be able to sign in with the primary email with password or OTP" + }, + "password": { + "type": "string", + "example": "my-new-password", + "description": "Sets the user's password. Doing so revokes all current sessions." + }, + "password_hash": { + "type": "string", + "description": "If `password` is not given, sets the user's password hash to the given string in Modular Crypt Format (ex.: `$2a$10$VIhIOofSMqGdGlL4wzE//e.77dAQGqNtF/1dT7bqCrVtQuInWy2qi`). Doing so revokes all current sessions." + }, + "totp_secret_base64": { + "type": "string", + "example": "dG90cC1zZWNyZXQ=", + "description": "Enables 2FA and sets a TOTP secret for the user. Set to null to disable 2FA." + }, + "restricted_by_admin": { + "type": "boolean", + "example": false, + "description": "Whether the user is restricted by an administrator. Can be set manually or by sign-up rules." + }, + "restricted_by_admin_reason": { + "type": "string", + "example": null, + "description": "Public reason shown to the user explaining why they are restricted. Optional." + }, + "restricted_by_admin_private_details": { + "type": "string", + "example": null, + "description": "Private details about the restriction (e.g., which sign-up rule triggered). Only visible to server access and above." + }, + "country_code": { + "type": "string", + "example": "US", + "description": "Best-effort ISO country code captured at sign-up time from request geo headers." + }, + "risk_scores": { + "type": "object", + "properties": { + "sign_up": { + "type": "object", + "properties": { + "bot": { + "type": "number" + }, + "free_trial_abuse": { + "type": "number" + } + }, + "required": [ + "bot", + "free_trial_abuse" + ] + } + }, + "required": [ + "sign_up" + ] + } + }, + "example": { + "display_name": "John Doe", + "profile_image_url": "https://example.com/image.jpg", + "client_metadata": { + "key": "value" + }, + "client_read_only_metadata": { + "key": "value" + }, + "server_metadata": { + "key": "value" + }, + "primary_email": "johndoe@example.com", + "primary_email_verified": true, + "primary_email_auth_enabled": true, + "password": "my-new-password", + "totp_secret_base64": "dG90cC1zZWNyZXQ=", + "restricted_by_admin": false, + "restricted_by_admin_reason": null, + "restricted_by_admin_private_details": null, + "country_code": "US" + } + } + } + } + }, + "tags": [ + "Users" + ], + "x-full-url": "https://api.stack-auth.com/api/v1/users", + "responses": { + "201": { + "description": "Successful response", + "content": { + "application/json": { + "schema": { + "type": "object", + "properties": { + "id": { + "type": "string", + "example": "3241a285-8329-4d69-8f3d-316e08cf140c", + "description": "The unique identifier of the user" + }, + "primary_email": { + "type": "string", + "example": "johndoe@example.com", + "description": "Primary email" + }, + "primary_email_verified": { + "type": "boolean", + "example": true, + "description": "Whether the primary email has been verified to belong to this user" + }, + "primary_email_auth_enabled": { + "type": "boolean", + "example": true, + "description": "Whether the primary email is used for authentication. If this is set to `false`, the user will not be able to sign in with the primary email with password or OTP" + }, + "display_name": { + "type": "string", + "example": "John Doe", + "description": "Human-readable user display name. This is not a unique identifier." + }, + "selected_team": { + "type": "object", + "properties": { + "created_at_millis": { + "type": "number", + "example": 1630000000000, + "description": "The time the team was created (the number of milliseconds since epoch, January 1, 1970, UTC)" + }, + "server_metadata": { + "type": "object", + "example": { + "key": "value" + }, + "description": "Server metadata. Used as a data store, only accessible from the server side. You can store secret information related to the team here." + }, + "id": { + "type": "string", + "example": "ad962777-8244-496a-b6a2-e0c6a449c79e", + "description": "The unique identifier of the team" + }, + "display_name": { + "type": "string", + "example": "My Team", + "description": "Human-readable team display name. This is not a unique identifier." + }, + "profile_image_url": { + "type": "string", + "example": "https://example.com/image.jpg", + "description": "URL of the profile image for team. Can be a Base64 encoded image. Must be smaller than 100KB. Please compress and crop to a square before passing in." + }, + "client_metadata": { + "type": "object", + "example": { + "key": "value" + }, + "description": "Client metadata. Used as a data store, accessible from the client side. Do not store information that should not be exposed to the client." + }, + "client_read_only_metadata": { + "type": "object", + "example": { + "key": "value" + }, + "description": "Client read-only, server-writable metadata. Used as a data store, accessible from the client side. Do not store information that should not be exposed to the client. The client can read this data, but cannot modify it. This is useful for things like subscription status." + } + }, + "required": [ + "created_at_millis", + "id", + "display_name" + ] + }, + "selected_team_id": { + "type": "string", + "example": "team-id", + "description": "ID of the team currently selected by the user" + }, + "profile_image_url": { + "type": "string", + "example": "https://example.com/image.jpg", + "description": "URL of the profile image for user. Can be a Base64 encoded image. Must be smaller than 100KB. Please compress and crop to a square before passing in." + }, + "signed_up_at_millis": { + "type": "number", + "example": 1630000000000, + "description": "The time the user signed up (identify) => `(the number of milliseconds since epoch, January 1, 1970, UTC)`" + }, + "client_metadata": { + "type": "object", + "example": { + "key": "value" + }, + "description": "Client metadata. Used as a data store, accessible from the client side. Do not store information that should not be exposed to the client." + }, + "client_read_only_metadata": { + "type": "object", + "example": { + "key": "value" + }, + "description": "Client read-only, server-writable metadata. Used as a data store, accessible from the client side. Do not store information that should not be exposed to the client. The client can read this data, but cannot modify it. This is useful for things like subscription status." + }, + "server_metadata": { + "type": "object", + "example": { + "key": "value" + }, + "description": "Server metadata. Used as a data store, only accessible from the server side. You can store secret information related to the user here." + }, + "last_active_at_millis": { + "type": "number", + "example": 1630000000000, + "description": "The time the user was last active (identify) => `(the number of milliseconds since epoch, January 1, 1970, UTC)`" + }, + "is_anonymous": { + "type": "boolean" + }, + "is_restricted": { + "type": "boolean", + "example": false, + "description": "Whether the user is in restricted state (has signed up but not completed onboarding requirements)" + }, + "restricted_reason": { + "type": "object", + "properties": { + "type": { + "type": "string" + } + }, + "required": [ + "type" + ], + "example": null, + "description": "The reason why the user is restricted (e.g., type: \"email_not_verified\", \"anonymous\", or \"restricted_by_administrator\"), null if not restricted" + }, + "restricted_by_admin": { + "type": "boolean", + "example": false, + "description": "Whether the user is restricted by an administrator. Can be set manually or by sign-up rules." + }, + "restricted_by_admin_reason": { + "type": "string", + "example": null, + "description": "Public reason shown to the user explaining why they are restricted. Optional." + }, + "restricted_by_admin_private_details": { + "type": "string", + "example": null, + "description": "Private details about the restriction (e.g., which sign-up rule triggered). Only visible to server access and above." + }, + "country_code": { + "type": "string", + "example": "US", + "description": "Best-effort ISO country code captured at sign-up time from request geo headers." + }, + "risk_scores": { + "type": "object", + "properties": { + "sign_up": { + "type": "object", + "properties": { + "bot": { + "type": "number" + }, + "free_trial_abuse": { + "type": "number" + } + }, + "required": [ + "bot", + "free_trial_abuse" + ] + } + }, + "required": [ + "sign_up" + ], + "example": { + "sign_up": { + "bot": 0, + "free_trial_abuse": 0 + } + }, + "description": "User risk scores used for sign-up risk evaluation." + } + }, + "required": [ + "id", + "primary_email_verified", + "primary_email_auth_enabled", + "signed_up_at_millis", + "last_active_at_millis", + "is_anonymous", + "is_restricted", + "restricted_by_admin", + "risk_scores" + ] + } + } + } + } + } + } + }, + "/users/me": { + "get": { + "summary": "Get current user", + "description": "Gets the currently authenticated user.", + "parameters": [], + "tags": [ + "Users" + ], + "x-full-url": "https://api.stack-auth.com/api/v1/users/me", + "responses": { + "200": { + "description": "Successful response", + "content": { + "application/json": { + "schema": { + "type": "object", + "properties": { + "id": { + "type": "string", + "example": "3241a285-8329-4d69-8f3d-316e08cf140c", + "description": "The unique identifier of the user" + }, + "primary_email": { + "type": "string", + "example": "johndoe@example.com", + "description": "Primary email" + }, + "primary_email_verified": { + "type": "boolean", + "example": true, + "description": "Whether the primary email has been verified to belong to this user" + }, + "primary_email_auth_enabled": { + "type": "boolean", + "example": true, + "description": "Whether the primary email is used for authentication. If this is set to `false`, the user will not be able to sign in with the primary email with password or OTP" + }, + "display_name": { + "type": "string", + "example": "John Doe", + "description": "Human-readable user display name. This is not a unique identifier." + }, + "selected_team": { + "type": "object", + "properties": { + "created_at_millis": { + "type": "number", + "example": 1630000000000, + "description": "The time the team was created (the number of milliseconds since epoch, January 1, 1970, UTC)" + }, + "server_metadata": { + "type": "object", + "example": { + "key": "value" + }, + "description": "Server metadata. Used as a data store, only accessible from the server side. You can store secret information related to the team here." + }, + "id": { + "type": "string", + "example": "ad962777-8244-496a-b6a2-e0c6a449c79e", + "description": "The unique identifier of the team" + }, + "display_name": { + "type": "string", + "example": "My Team", + "description": "Human-readable team display name. This is not a unique identifier." + }, + "profile_image_url": { + "type": "string", + "example": "https://example.com/image.jpg", + "description": "URL of the profile image for team. Can be a Base64 encoded image. Must be smaller than 100KB. Please compress and crop to a square before passing in." + }, + "client_metadata": { + "type": "object", + "example": { + "key": "value" + }, + "description": "Client metadata. Used as a data store, accessible from the client side. Do not store information that should not be exposed to the client." + }, + "client_read_only_metadata": { + "type": "object", + "example": { + "key": "value" + }, + "description": "Client read-only, server-writable metadata. Used as a data store, accessible from the client side. Do not store information that should not be exposed to the client. The client can read this data, but cannot modify it. This is useful for things like subscription status." + } + }, + "required": [ + "created_at_millis", + "id", + "display_name" + ] + }, + "selected_team_id": { + "type": "string", + "example": "team-id", + "description": "ID of the team currently selected by the user" + }, + "profile_image_url": { + "type": "string", + "example": "https://example.com/image.jpg", + "description": "URL of the profile image for user. Can be a Base64 encoded image. Must be smaller than 100KB. Please compress and crop to a square before passing in." + }, + "signed_up_at_millis": { + "type": "number", + "example": 1630000000000, + "description": "The time the user signed up (identify) => `(the number of milliseconds since epoch, January 1, 1970, UTC)`" + }, + "client_metadata": { + "type": "object", + "example": { + "key": "value" + }, + "description": "Client metadata. Used as a data store, accessible from the client side. Do not store information that should not be exposed to the client." + }, + "client_read_only_metadata": { + "type": "object", + "example": { + "key": "value" + }, + "description": "Client read-only, server-writable metadata. Used as a data store, accessible from the client side. Do not store information that should not be exposed to the client. The client can read this data, but cannot modify it. This is useful for things like subscription status." + }, + "server_metadata": { + "type": "object", + "example": { + "key": "value" + }, + "description": "Server metadata. Used as a data store, only accessible from the server side. You can store secret information related to the user here." + }, + "last_active_at_millis": { + "type": "number", + "example": 1630000000000, + "description": "The time the user was last active (identify) => `(the number of milliseconds since epoch, January 1, 1970, UTC)`" + }, + "is_anonymous": { + "type": "boolean" + }, + "is_restricted": { + "type": "boolean", + "example": false, + "description": "Whether the user is in restricted state (has signed up but not completed onboarding requirements)" + }, + "restricted_reason": { + "type": "object", + "properties": { + "type": { + "type": "string" + } + }, + "required": [ + "type" + ], + "example": null, + "description": "The reason why the user is restricted (e.g., type: \"email_not_verified\", \"anonymous\", or \"restricted_by_administrator\"), null if not restricted" + }, + "restricted_by_admin": { + "type": "boolean", + "example": false, + "description": "Whether the user is restricted by an administrator. Can be set manually or by sign-up rules." + }, + "restricted_by_admin_reason": { + "type": "string", + "example": null, + "description": "Public reason shown to the user explaining why they are restricted. Optional." + }, + "restricted_by_admin_private_details": { + "type": "string", + "example": null, + "description": "Private details about the restriction (e.g., which sign-up rule triggered). Only visible to server access and above." + }, + "country_code": { + "type": "string", + "example": "US", + "description": "Best-effort ISO country code captured at sign-up time from request geo headers." + }, + "risk_scores": { + "type": "object", + "properties": { + "sign_up": { + "type": "object", + "properties": { + "bot": { + "type": "number" + }, + "free_trial_abuse": { + "type": "number" + } + }, + "required": [ + "bot", + "free_trial_abuse" + ] + } + }, + "required": [ + "sign_up" + ], + "example": { + "sign_up": { + "bot": 0, + "free_trial_abuse": 0 + } + }, + "description": "User risk scores used for sign-up risk evaluation." + } + }, + "required": [ + "id", + "primary_email_verified", + "primary_email_auth_enabled", + "signed_up_at_millis", + "last_active_at_millis", + "is_anonymous", + "is_restricted", + "restricted_by_admin", + "risk_scores" + ] + } + } + } + } + } + }, + "delete": { + "summary": "Delete current user", + "description": "Deletes the currently authenticated user. Use this with caution.", + "parameters": [], + "tags": [ + "Users" + ], + "x-full-url": "https://api.stack-auth.com/api/v1/users/me", + "responses": { + "200": { + "description": "Successful response", + "content": { + "application/json": { + "schema": { + "type": "object", + "properties": { + "success": { + "type": "boolean", + "description": "Always equal to true.", + "example": true + } + }, + "required": [ + "success" + ] + } + } + } + } + } + }, + "patch": { + "summary": "Update current user", + "description": "Updates the currently authenticated user. Only the values provided will be updated.", + "parameters": [], + "requestBody": { + "required": true, + "content": { + "application/json": { + "schema": { + "type": "object", + "properties": { + "display_name": { + "type": "string", + "example": "John Doe", + "description": "Human-readable user display name. This is not a unique identifier." + }, + "profile_image_url": { + "type": "string", + "example": "https://example.com/image.jpg", + "description": "URL of the profile image for user. Can be a Base64 encoded image. Must be smaller than 100KB. Please compress and crop to a square before passing in." + }, + "client_metadata": { + "type": "object", + "example": { + "key": "value" + }, + "description": "Client metadata. Used as a data store, accessible from the client side. Do not store information that should not be exposed to the client." + }, + "client_read_only_metadata": { + "type": "object", + "example": { + "key": "value" + }, + "description": "Client read-only, server-writable metadata. Used as a data store, accessible from the client side. Do not store information that should not be exposed to the client. The client can read this data, but cannot modify it. This is useful for things like subscription status." + }, + "server_metadata": { + "type": "object", + "example": { + "key": "value" + }, + "description": "Server metadata. Used as a data store, only accessible from the server side. You can store secret information related to the user here." + }, + "primary_email": { + "type": "string", + "example": "johndoe@example.com", + "description": "Primary email" + }, + "primary_email_verified": { + "type": "boolean", + "example": true, + "description": "Whether the primary email has been verified to belong to this user" + }, + "primary_email_auth_enabled": { + "type": "boolean", + "example": true, + "description": "Whether the primary email is used for authentication. If this is set to `false`, the user will not be able to sign in with the primary email with password or OTP" + }, + "password": { + "type": "string", + "example": "my-new-password", + "description": "Sets the user's password. Doing so revokes all current sessions." + }, + "password_hash": { + "type": "string", + "description": "If `password` is not given, sets the user's password hash to the given string in Modular Crypt Format (ex.: `$2a$10$VIhIOofSMqGdGlL4wzE//e.77dAQGqNtF/1dT7bqCrVtQuInWy2qi`). Doing so revokes all current sessions." + }, + "totp_secret_base64": { + "type": "string", + "example": "dG90cC1zZWNyZXQ=", + "description": "Enables 2FA and sets a TOTP secret for the user. Set to null to disable 2FA." + }, + "selected_team_id": { + "type": "string", + "example": "team-id", + "description": "ID of the team currently selected by the user" + }, + "is_anonymous": { + "type": "boolean" + }, + "restricted_by_admin": { + "type": "boolean", + "example": false, + "description": "Whether the user is restricted by an administrator. Can be set manually or by sign-up rules." + }, + "restricted_by_admin_reason": { + "type": "string", + "example": null, + "description": "Public reason shown to the user explaining why they are restricted. Optional." + }, + "restricted_by_admin_private_details": { + "type": "string", + "example": null, + "description": "Private details about the restriction (e.g., which sign-up rule triggered). Only visible to server access and above." + }, + "country_code": { + "type": "string", + "example": "US", + "description": "Best-effort ISO country code captured at sign-up time from request geo headers." + }, + "risk_scores": { + "type": "object", + "properties": { + "sign_up": { + "type": "object", + "properties": { + "bot": { + "type": "number" + }, + "free_trial_abuse": { + "type": "number" + } + }, + "required": [ + "bot", + "free_trial_abuse" + ] + } + }, + "required": [ + "sign_up" + ] + } + }, + "example": { + "display_name": "John Doe", + "profile_image_url": "https://example.com/image.jpg", + "client_metadata": { + "key": "value" + }, + "client_read_only_metadata": { + "key": "value" + }, + "server_metadata": { + "key": "value" + }, + "primary_email": "johndoe@example.com", + "primary_email_verified": true, + "primary_email_auth_enabled": true, + "password": "my-new-password", + "totp_secret_base64": "dG90cC1zZWNyZXQ=", + "selected_team_id": "team-id", + "restricted_by_admin": false, + "restricted_by_admin_reason": null, + "restricted_by_admin_private_details": null, + "country_code": "US" + } + } + } + } + }, + "tags": [ + "Users" + ], + "x-full-url": "https://api.stack-auth.com/api/v1/users/me", + "responses": { + "200": { + "description": "Successful response", + "content": { + "application/json": { + "schema": { + "type": "object", + "properties": { + "id": { + "type": "string", + "example": "3241a285-8329-4d69-8f3d-316e08cf140c", + "description": "The unique identifier of the user" + }, + "primary_email": { + "type": "string", + "example": "johndoe@example.com", + "description": "Primary email" + }, + "primary_email_verified": { + "type": "boolean", + "example": true, + "description": "Whether the primary email has been verified to belong to this user" + }, + "primary_email_auth_enabled": { + "type": "boolean", + "example": true, + "description": "Whether the primary email is used for authentication. If this is set to `false`, the user will not be able to sign in with the primary email with password or OTP" + }, + "display_name": { + "type": "string", + "example": "John Doe", + "description": "Human-readable user display name. This is not a unique identifier." + }, + "selected_team": { + "type": "object", + "properties": { + "created_at_millis": { + "type": "number", + "example": 1630000000000, + "description": "The time the team was created (the number of milliseconds since epoch, January 1, 1970, UTC)" + }, + "server_metadata": { + "type": "object", + "example": { + "key": "value" + }, + "description": "Server metadata. Used as a data store, only accessible from the server side. You can store secret information related to the team here." + }, + "id": { + "type": "string", + "example": "ad962777-8244-496a-b6a2-e0c6a449c79e", + "description": "The unique identifier of the team" + }, + "display_name": { + "type": "string", + "example": "My Team", + "description": "Human-readable team display name. This is not a unique identifier." + }, + "profile_image_url": { + "type": "string", + "example": "https://example.com/image.jpg", + "description": "URL of the profile image for team. Can be a Base64 encoded image. Must be smaller than 100KB. Please compress and crop to a square before passing in." + }, + "client_metadata": { + "type": "object", + "example": { + "key": "value" + }, + "description": "Client metadata. Used as a data store, accessible from the client side. Do not store information that should not be exposed to the client." + }, + "client_read_only_metadata": { + "type": "object", + "example": { + "key": "value" + }, + "description": "Client read-only, server-writable metadata. Used as a data store, accessible from the client side. Do not store information that should not be exposed to the client. The client can read this data, but cannot modify it. This is useful for things like subscription status." + } + }, + "required": [ + "created_at_millis", + "id", + "display_name" + ] + }, + "selected_team_id": { + "type": "string", + "example": "team-id", + "description": "ID of the team currently selected by the user" + }, + "profile_image_url": { + "type": "string", + "example": "https://example.com/image.jpg", + "description": "URL of the profile image for user. Can be a Base64 encoded image. Must be smaller than 100KB. Please compress and crop to a square before passing in." + }, + "signed_up_at_millis": { + "type": "number", + "example": 1630000000000, + "description": "The time the user signed up (identify) => `(the number of milliseconds since epoch, January 1, 1970, UTC)`" + }, + "client_metadata": { + "type": "object", + "example": { + "key": "value" + }, + "description": "Client metadata. Used as a data store, accessible from the client side. Do not store information that should not be exposed to the client." + }, + "client_read_only_metadata": { + "type": "object", + "example": { + "key": "value" + }, + "description": "Client read-only, server-writable metadata. Used as a data store, accessible from the client side. Do not store information that should not be exposed to the client. The client can read this data, but cannot modify it. This is useful for things like subscription status." + }, + "server_metadata": { + "type": "object", + "example": { + "key": "value" + }, + "description": "Server metadata. Used as a data store, only accessible from the server side. You can store secret information related to the user here." + }, + "last_active_at_millis": { + "type": "number", + "example": 1630000000000, + "description": "The time the user was last active (identify) => `(the number of milliseconds since epoch, January 1, 1970, UTC)`" + }, + "is_anonymous": { + "type": "boolean" + }, + "is_restricted": { + "type": "boolean", + "example": false, + "description": "Whether the user is in restricted state (has signed up but not completed onboarding requirements)" + }, + "restricted_reason": { + "type": "object", + "properties": { + "type": { + "type": "string" + } + }, + "required": [ + "type" + ], + "example": null, + "description": "The reason why the user is restricted (e.g., type: \"email_not_verified\", \"anonymous\", or \"restricted_by_administrator\"), null if not restricted" + }, + "restricted_by_admin": { + "type": "boolean", + "example": false, + "description": "Whether the user is restricted by an administrator. Can be set manually or by sign-up rules." + }, + "restricted_by_admin_reason": { + "type": "string", + "example": null, + "description": "Public reason shown to the user explaining why they are restricted. Optional." + }, + "restricted_by_admin_private_details": { + "type": "string", + "example": null, + "description": "Private details about the restriction (e.g., which sign-up rule triggered). Only visible to server access and above." + }, + "country_code": { + "type": "string", + "example": "US", + "description": "Best-effort ISO country code captured at sign-up time from request geo headers." + }, + "risk_scores": { + "type": "object", + "properties": { + "sign_up": { + "type": "object", + "properties": { + "bot": { + "type": "number" + }, + "free_trial_abuse": { + "type": "number" + } + }, + "required": [ + "bot", + "free_trial_abuse" + ] + } + }, + "required": [ + "sign_up" + ], + "example": { + "sign_up": { + "bot": 0, + "free_trial_abuse": 0 + } + }, + "description": "User risk scores used for sign-up risk evaluation." + } + }, + "required": [ + "id", + "primary_email_verified", + "primary_email_auth_enabled", + "signed_up_at_millis", + "last_active_at_millis", + "is_anonymous", + "is_restricted", + "restricted_by_admin", + "risk_scores" + ] + } + } + } + } + } + } + }, + "/users/{user_id}": { + "get": { + "summary": "Get user", + "description": "Gets a user by user ID.", + "parameters": [ + { + "name": "user_id", + "in": "path", + "schema": { + "type": "string", + "example": "3241a285-8329-4d69-8f3d-316e08cf140c", + "description": "The ID of the user, or the special value `me` for the currently authenticated user" + }, + "description": "The ID of the user, or the special value `me` for the currently authenticated user", + "required": true + } + ], + "tags": [ + "Users" + ], + "x-full-url": "https://api.stack-auth.com/api/v1/users/{user_id}", + "responses": { + "200": { + "description": "Successful response", + "content": { + "application/json": { + "schema": { + "type": "object", + "properties": { + "id": { + "type": "string", + "example": "3241a285-8329-4d69-8f3d-316e08cf140c", + "description": "The unique identifier of the user" + }, + "primary_email": { + "type": "string", + "example": "johndoe@example.com", + "description": "Primary email" + }, + "primary_email_verified": { + "type": "boolean", + "example": true, + "description": "Whether the primary email has been verified to belong to this user" + }, + "primary_email_auth_enabled": { + "type": "boolean", + "example": true, + "description": "Whether the primary email is used for authentication. If this is set to `false`, the user will not be able to sign in with the primary email with password or OTP" + }, + "display_name": { + "type": "string", + "example": "John Doe", + "description": "Human-readable user display name. This is not a unique identifier." + }, + "selected_team": { + "type": "object", + "properties": { + "created_at_millis": { + "type": "number", + "example": 1630000000000, + "description": "The time the team was created (the number of milliseconds since epoch, January 1, 1970, UTC)" + }, + "server_metadata": { + "type": "object", + "example": { + "key": "value" + }, + "description": "Server metadata. Used as a data store, only accessible from the server side. You can store secret information related to the team here." + }, + "id": { + "type": "string", + "example": "ad962777-8244-496a-b6a2-e0c6a449c79e", + "description": "The unique identifier of the team" + }, + "display_name": { + "type": "string", + "example": "My Team", + "description": "Human-readable team display name. This is not a unique identifier." + }, + "profile_image_url": { + "type": "string", + "example": "https://example.com/image.jpg", + "description": "URL of the profile image for team. Can be a Base64 encoded image. Must be smaller than 100KB. Please compress and crop to a square before passing in." + }, + "client_metadata": { + "type": "object", + "example": { + "key": "value" + }, + "description": "Client metadata. Used as a data store, accessible from the client side. Do not store information that should not be exposed to the client." + }, + "client_read_only_metadata": { + "type": "object", + "example": { + "key": "value" + }, + "description": "Client read-only, server-writable metadata. Used as a data store, accessible from the client side. Do not store information that should not be exposed to the client. The client can read this data, but cannot modify it. This is useful for things like subscription status." + } + }, + "required": [ + "created_at_millis", + "id", + "display_name" + ] + }, + "selected_team_id": { + "type": "string", + "example": "team-id", + "description": "ID of the team currently selected by the user" + }, + "profile_image_url": { + "type": "string", + "example": "https://example.com/image.jpg", + "description": "URL of the profile image for user. Can be a Base64 encoded image. Must be smaller than 100KB. Please compress and crop to a square before passing in." + }, + "signed_up_at_millis": { + "type": "number", + "example": 1630000000000, + "description": "The time the user signed up (identify) => `(the number of milliseconds since epoch, January 1, 1970, UTC)`" + }, + "client_metadata": { + "type": "object", + "example": { + "key": "value" + }, + "description": "Client metadata. Used as a data store, accessible from the client side. Do not store information that should not be exposed to the client." + }, + "client_read_only_metadata": { + "type": "object", + "example": { + "key": "value" + }, + "description": "Client read-only, server-writable metadata. Used as a data store, accessible from the client side. Do not store information that should not be exposed to the client. The client can read this data, but cannot modify it. This is useful for things like subscription status." + }, + "server_metadata": { + "type": "object", + "example": { + "key": "value" + }, + "description": "Server metadata. Used as a data store, only accessible from the server side. You can store secret information related to the user here." + }, + "last_active_at_millis": { + "type": "number", + "example": 1630000000000, + "description": "The time the user was last active (identify) => `(the number of milliseconds since epoch, January 1, 1970, UTC)`" + }, + "is_anonymous": { + "type": "boolean" + }, + "is_restricted": { + "type": "boolean", + "example": false, + "description": "Whether the user is in restricted state (has signed up but not completed onboarding requirements)" + }, + "restricted_reason": { + "type": "object", + "properties": { + "type": { + "type": "string" + } + }, + "required": [ + "type" + ], + "example": null, + "description": "The reason why the user is restricted (e.g., type: \"email_not_verified\", \"anonymous\", or \"restricted_by_administrator\"), null if not restricted" + }, + "restricted_by_admin": { + "type": "boolean", + "example": false, + "description": "Whether the user is restricted by an administrator. Can be set manually or by sign-up rules." + }, + "restricted_by_admin_reason": { + "type": "string", + "example": null, + "description": "Public reason shown to the user explaining why they are restricted. Optional." + }, + "restricted_by_admin_private_details": { + "type": "string", + "example": null, + "description": "Private details about the restriction (e.g., which sign-up rule triggered). Only visible to server access and above." + }, + "country_code": { + "type": "string", + "example": "US", + "description": "Best-effort ISO country code captured at sign-up time from request geo headers." + }, + "risk_scores": { + "type": "object", + "properties": { + "sign_up": { + "type": "object", + "properties": { + "bot": { + "type": "number" + }, + "free_trial_abuse": { + "type": "number" + } + }, + "required": [ + "bot", + "free_trial_abuse" + ] + } + }, + "required": [ + "sign_up" + ], + "example": { + "sign_up": { + "bot": 0, + "free_trial_abuse": 0 + } + }, + "description": "User risk scores used for sign-up risk evaluation." + } + }, + "required": [ + "id", + "primary_email_verified", + "primary_email_auth_enabled", + "signed_up_at_millis", + "last_active_at_millis", + "is_anonymous", + "is_restricted", + "restricted_by_admin", + "risk_scores" + ] + } + } + } + } + } + }, + "delete": { + "summary": "Delete user", + "description": "Deletes a user. Use this with caution.", + "parameters": [ + { + "name": "user_id", + "in": "path", + "schema": { + "type": "string", + "example": "3241a285-8329-4d69-8f3d-316e08cf140c", + "description": "The ID of the user, or the special value `me` for the currently authenticated user" + }, + "description": "The ID of the user, or the special value `me` for the currently authenticated user", + "required": true + } + ], + "tags": [ + "Users" + ], + "x-full-url": "https://api.stack-auth.com/api/v1/users/{user_id}", + "responses": { + "200": { + "description": "Successful response", + "content": { + "application/json": { + "schema": { + "type": "object", + "properties": { + "success": { + "type": "boolean", + "description": "Always equal to true.", + "example": true + } + }, + "required": [ + "success" + ] + } + } + } + } + } + }, + "patch": { + "summary": "Update user", + "description": "Updates a user. Only the values provided will be updated.", + "parameters": [ + { + "name": "user_id", + "in": "path", + "schema": { + "type": "string", + "example": "3241a285-8329-4d69-8f3d-316e08cf140c", + "description": "The ID of the user, or the special value `me` for the currently authenticated user" + }, + "description": "The ID of the user, or the special value `me` for the currently authenticated user", + "required": true + } + ], + "requestBody": { + "required": true, + "content": { + "application/json": { + "schema": { + "type": "object", + "properties": { + "display_name": { + "type": "string", + "example": "John Doe", + "description": "Human-readable user display name. This is not a unique identifier." + }, + "profile_image_url": { + "type": "string", + "example": "https://example.com/image.jpg", + "description": "URL of the profile image for user. Can be a Base64 encoded image. Must be smaller than 100KB. Please compress and crop to a square before passing in." + }, + "client_metadata": { + "type": "object", + "example": { + "key": "value" + }, + "description": "Client metadata. Used as a data store, accessible from the client side. Do not store information that should not be exposed to the client." + }, + "client_read_only_metadata": { + "type": "object", + "example": { + "key": "value" + }, + "description": "Client read-only, server-writable metadata. Used as a data store, accessible from the client side. Do not store information that should not be exposed to the client. The client can read this data, but cannot modify it. This is useful for things like subscription status." + }, + "server_metadata": { + "type": "object", + "example": { + "key": "value" + }, + "description": "Server metadata. Used as a data store, only accessible from the server side. You can store secret information related to the user here." + }, + "primary_email": { + "type": "string", + "example": "johndoe@example.com", + "description": "Primary email" + }, + "primary_email_verified": { + "type": "boolean", + "example": true, + "description": "Whether the primary email has been verified to belong to this user" + }, + "primary_email_auth_enabled": { + "type": "boolean", + "example": true, + "description": "Whether the primary email is used for authentication. If this is set to `false`, the user will not be able to sign in with the primary email with password or OTP" + }, + "password": { + "type": "string", + "example": "my-new-password", + "description": "Sets the user's password. Doing so revokes all current sessions." + }, + "password_hash": { + "type": "string", + "description": "If `password` is not given, sets the user's password hash to the given string in Modular Crypt Format (ex.: `$2a$10$VIhIOofSMqGdGlL4wzE//e.77dAQGqNtF/1dT7bqCrVtQuInWy2qi`). Doing so revokes all current sessions." + }, + "totp_secret_base64": { + "type": "string", + "example": "dG90cC1zZWNyZXQ=", + "description": "Enables 2FA and sets a TOTP secret for the user. Set to null to disable 2FA." + }, + "selected_team_id": { + "type": "string", + "example": "team-id", + "description": "ID of the team currently selected by the user" + }, + "is_anonymous": { + "type": "boolean" + }, + "restricted_by_admin": { + "type": "boolean", + "example": false, + "description": "Whether the user is restricted by an administrator. Can be set manually or by sign-up rules." + }, + "restricted_by_admin_reason": { + "type": "string", + "example": null, + "description": "Public reason shown to the user explaining why they are restricted. Optional." + }, + "restricted_by_admin_private_details": { + "type": "string", + "example": null, + "description": "Private details about the restriction (e.g., which sign-up rule triggered). Only visible to server access and above." + }, + "country_code": { + "type": "string", + "example": "US", + "description": "Best-effort ISO country code captured at sign-up time from request geo headers." + }, + "risk_scores": { + "type": "object", + "properties": { + "sign_up": { + "type": "object", + "properties": { + "bot": { + "type": "number" + }, + "free_trial_abuse": { + "type": "number" + } + }, + "required": [ + "bot", + "free_trial_abuse" + ] + } + }, + "required": [ + "sign_up" + ] + } + }, + "example": { + "display_name": "John Doe", + "profile_image_url": "https://example.com/image.jpg", + "client_metadata": { + "key": "value" + }, + "client_read_only_metadata": { + "key": "value" + }, + "server_metadata": { + "key": "value" + }, + "primary_email": "johndoe@example.com", + "primary_email_verified": true, + "primary_email_auth_enabled": true, + "password": "my-new-password", + "totp_secret_base64": "dG90cC1zZWNyZXQ=", + "selected_team_id": "team-id", + "restricted_by_admin": false, + "restricted_by_admin_reason": null, + "restricted_by_admin_private_details": null, + "country_code": "US" + } + } + } + } + }, + "tags": [ + "Users" + ], + "x-full-url": "https://api.stack-auth.com/api/v1/users/{user_id}", + "responses": { + "200": { + "description": "Successful response", + "content": { + "application/json": { + "schema": { + "type": "object", + "properties": { + "id": { + "type": "string", + "example": "3241a285-8329-4d69-8f3d-316e08cf140c", + "description": "The unique identifier of the user" + }, + "primary_email": { + "type": "string", + "example": "johndoe@example.com", + "description": "Primary email" + }, + "primary_email_verified": { + "type": "boolean", + "example": true, + "description": "Whether the primary email has been verified to belong to this user" + }, + "primary_email_auth_enabled": { + "type": "boolean", + "example": true, + "description": "Whether the primary email is used for authentication. If this is set to `false`, the user will not be able to sign in with the primary email with password or OTP" + }, + "display_name": { + "type": "string", + "example": "John Doe", + "description": "Human-readable user display name. This is not a unique identifier." + }, + "selected_team": { + "type": "object", + "properties": { + "created_at_millis": { + "type": "number", + "example": 1630000000000, + "description": "The time the team was created (the number of milliseconds since epoch, January 1, 1970, UTC)" + }, + "server_metadata": { + "type": "object", + "example": { + "key": "value" + }, + "description": "Server metadata. Used as a data store, only accessible from the server side. You can store secret information related to the team here." + }, + "id": { + "type": "string", + "example": "ad962777-8244-496a-b6a2-e0c6a449c79e", + "description": "The unique identifier of the team" + }, + "display_name": { + "type": "string", + "example": "My Team", + "description": "Human-readable team display name. This is not a unique identifier." + }, + "profile_image_url": { + "type": "string", + "example": "https://example.com/image.jpg", + "description": "URL of the profile image for team. Can be a Base64 encoded image. Must be smaller than 100KB. Please compress and crop to a square before passing in." + }, + "client_metadata": { + "type": "object", + "example": { + "key": "value" + }, + "description": "Client metadata. Used as a data store, accessible from the client side. Do not store information that should not be exposed to the client." + }, + "client_read_only_metadata": { + "type": "object", + "example": { + "key": "value" + }, + "description": "Client read-only, server-writable metadata. Used as a data store, accessible from the client side. Do not store information that should not be exposed to the client. The client can read this data, but cannot modify it. This is useful for things like subscription status." + } + }, + "required": [ + "created_at_millis", + "id", + "display_name" + ] + }, + "selected_team_id": { + "type": "string", + "example": "team-id", + "description": "ID of the team currently selected by the user" + }, + "profile_image_url": { + "type": "string", + "example": "https://example.com/image.jpg", + "description": "URL of the profile image for user. Can be a Base64 encoded image. Must be smaller than 100KB. Please compress and crop to a square before passing in." + }, + "signed_up_at_millis": { + "type": "number", + "example": 1630000000000, + "description": "The time the user signed up (identify) => `(the number of milliseconds since epoch, January 1, 1970, UTC)`" + }, + "client_metadata": { + "type": "object", + "example": { + "key": "value" + }, + "description": "Client metadata. Used as a data store, accessible from the client side. Do not store information that should not be exposed to the client." + }, + "client_read_only_metadata": { + "type": "object", + "example": { + "key": "value" + }, + "description": "Client read-only, server-writable metadata. Used as a data store, accessible from the client side. Do not store information that should not be exposed to the client. The client can read this data, but cannot modify it. This is useful for things like subscription status." + }, + "server_metadata": { + "type": "object", + "example": { + "key": "value" + }, + "description": "Server metadata. Used as a data store, only accessible from the server side. You can store secret information related to the user here." + }, + "last_active_at_millis": { + "type": "number", + "example": 1630000000000, + "description": "The time the user was last active (identify) => `(the number of milliseconds since epoch, January 1, 1970, UTC)`" + }, + "is_anonymous": { + "type": "boolean" + }, + "is_restricted": { + "type": "boolean", + "example": false, + "description": "Whether the user is in restricted state (has signed up but not completed onboarding requirements)" + }, + "restricted_reason": { + "type": "object", + "properties": { + "type": { + "type": "string" + } + }, + "required": [ + "type" + ], + "example": null, + "description": "The reason why the user is restricted (e.g., type: \"email_not_verified\", \"anonymous\", or \"restricted_by_administrator\"), null if not restricted" + }, + "restricted_by_admin": { + "type": "boolean", + "example": false, + "description": "Whether the user is restricted by an administrator. Can be set manually or by sign-up rules." + }, + "restricted_by_admin_reason": { + "type": "string", + "example": null, + "description": "Public reason shown to the user explaining why they are restricted. Optional." + }, + "restricted_by_admin_private_details": { + "type": "string", + "example": null, + "description": "Private details about the restriction (e.g., which sign-up rule triggered). Only visible to server access and above." + }, + "country_code": { + "type": "string", + "example": "US", + "description": "Best-effort ISO country code captured at sign-up time from request geo headers." + }, + "risk_scores": { + "type": "object", + "properties": { + "sign_up": { + "type": "object", + "properties": { + "bot": { + "type": "number" + }, + "free_trial_abuse": { + "type": "number" + } + }, + "required": [ + "bot", + "free_trial_abuse" + ] + } + }, + "required": [ + "sign_up" + ], + "example": { + "sign_up": { + "bot": 0, + "free_trial_abuse": 0 + } + }, + "description": "User risk scores used for sign-up risk evaluation." + } + }, + "required": [ + "id", + "primary_email_verified", + "primary_email_auth_enabled", + "signed_up_at_millis", + "last_active_at_millis", + "is_anonymous", + "is_restricted", + "restricted_by_admin", + "risk_scores" + ] + } + } + } + } + } + } + } + } +} \ No newline at end of file diff --git a/docs-mintlify/openapi/webhooks.json b/docs-mintlify/openapi/webhooks.json new file mode 100644 index 0000000000..9d882ae4af --- /dev/null +++ b/docs-mintlify/openapi/webhooks.json @@ -0,0 +1,1100 @@ +{ + "openapi": "3.1.0", + "info": { + "title": "Stack Webhooks API", + "version": "1.0.0" + }, + "webhooks": { + "user.created": { + "post": { + "summary": "user.created", + "description": "This event is triggered when a user is created.", + "parameters": [], + "requestBody": { + "required": true, + "content": { + "application/json": { + "schema": { + "type": "object", + "properties": { + "type": { + "type": "string", + "example": "user.created", + "description": "user.created" + }, + "data": { + "type": "object", + "properties": { + "id": { + "type": "string", + "example": "3241a285-8329-4d69-8f3d-316e08cf140c", + "description": "The unique identifier of the user" + }, + "primary_email": { + "type": "string", + "example": "johndoe@example.com", + "description": "Primary email" + }, + "primary_email_verified": { + "type": "boolean", + "example": true, + "description": "Whether the primary email has been verified to belong to this user" + }, + "primary_email_auth_enabled": { + "type": "boolean", + "example": true, + "description": "Whether the primary email is used for authentication. If this is set to `false`, the user will not be able to sign in with the primary email with password or OTP" + }, + "display_name": { + "type": "string", + "example": "John Doe", + "description": "Human-readable user display name. This is not a unique identifier." + }, + "selected_team": { + "type": "object", + "properties": { + "created_at_millis": { + "type": "number", + "example": 1630000000000, + "description": "The time the team was created (the number of milliseconds since epoch, January 1, 1970, UTC)" + }, + "server_metadata": { + "type": "object", + "example": { + "key": "value" + }, + "description": "Server metadata. Used as a data store, only accessible from the server side. You can store secret information related to the team here." + }, + "id": { + "type": "string", + "example": "ad962777-8244-496a-b6a2-e0c6a449c79e", + "description": "The unique identifier of the team" + }, + "display_name": { + "type": "string", + "example": "My Team", + "description": "Human-readable team display name. This is not a unique identifier." + }, + "profile_image_url": { + "type": "string", + "example": "https://example.com/image.jpg", + "description": "URL of the profile image for team. Can be a Base64 encoded image. Must be smaller than 100KB. Please compress and crop to a square before passing in." + }, + "client_metadata": { + "type": "object", + "example": { + "key": "value" + }, + "description": "Client metadata. Used as a data store, accessible from the client side. Do not store information that should not be exposed to the client." + }, + "client_read_only_metadata": { + "type": "object", + "example": { + "key": "value" + }, + "description": "Client read-only, server-writable metadata. Used as a data store, accessible from the client side. Do not store information that should not be exposed to the client. The client can read this data, but cannot modify it. This is useful for things like subscription status." + } + }, + "required": [ + "created_at_millis", + "id", + "display_name" + ] + }, + "selected_team_id": { + "type": "string", + "example": "team-id", + "description": "ID of the team currently selected by the user" + }, + "profile_image_url": { + "type": "string", + "example": "https://example.com/image.jpg", + "description": "URL of the profile image for user. Can be a Base64 encoded image. Must be smaller than 100KB. Please compress and crop to a square before passing in." + }, + "signed_up_at_millis": { + "type": "number", + "example": 1630000000000, + "description": "The time the user signed up (identify) => `(the number of milliseconds since epoch, January 1, 1970, UTC)`" + }, + "client_metadata": { + "type": "object", + "example": { + "key": "value" + }, + "description": "Client metadata. Used as a data store, accessible from the client side. Do not store information that should not be exposed to the client." + }, + "client_read_only_metadata": { + "type": "object", + "example": { + "key": "value" + }, + "description": "Client read-only, server-writable metadata. Used as a data store, accessible from the client side. Do not store information that should not be exposed to the client. The client can read this data, but cannot modify it. This is useful for things like subscription status." + }, + "server_metadata": { + "type": "object", + "example": { + "key": "value" + }, + "description": "Server metadata. Used as a data store, only accessible from the server side. You can store secret information related to the user here." + }, + "last_active_at_millis": { + "type": "number", + "example": 1630000000000, + "description": "The time the user was last active (identify) => `(the number of milliseconds since epoch, January 1, 1970, UTC)`" + }, + "is_anonymous": { + "type": "boolean" + }, + "is_restricted": { + "type": "boolean", + "example": false, + "description": "Whether the user is in restricted state (has signed up but not completed onboarding requirements)" + }, + "restricted_reason": { + "type": "object", + "properties": { + "type": { + "type": "string" + } + }, + "required": [ + "type" + ], + "example": null, + "description": "The reason why the user is restricted (e.g., type: \"email_not_verified\", \"anonymous\", or \"restricted_by_administrator\"), null if not restricted" + }, + "restricted_by_admin": { + "type": "boolean", + "example": false, + "description": "Whether the user is restricted by an administrator. Can be set manually or by sign-up rules." + }, + "restricted_by_admin_reason": { + "type": "string", + "example": null, + "description": "Public reason shown to the user explaining why they are restricted. Optional." + }, + "restricted_by_admin_private_details": { + "type": "string", + "example": null, + "description": "Private details about the restriction (e.g., which sign-up rule triggered). Only visible to server access and above." + }, + "country_code": { + "type": "string", + "example": "US", + "description": "Best-effort ISO country code captured at sign-up time from request geo headers." + }, + "risk_scores": { + "type": "object", + "properties": { + "sign_up": { + "type": "object", + "properties": { + "bot": { + "type": "number" + }, + "free_trial_abuse": { + "type": "number" + } + }, + "required": [ + "bot", + "free_trial_abuse" + ] + } + }, + "required": [ + "sign_up" + ], + "example": { + "sign_up": { + "bot": 0, + "free_trial_abuse": 0 + } + }, + "description": "User risk scores used for sign-up risk evaluation." + } + }, + "required": [ + "id", + "primary_email_verified", + "primary_email_auth_enabled", + "signed_up_at_millis", + "last_active_at_millis", + "is_anonymous", + "is_restricted", + "restricted_by_admin", + "risk_scores" + ] + } + }, + "required": [ + "type", + "data" + ], + "example": { + "type": "user.created" + } + } + } + } + }, + "tags": [ + "Users" + ], + "x-full-url": "https://api.stack-auth.com/api/v1/webhooks/user.created", + "responses": { + "200": { + "description": "Successful response", + "content": { + "application/json": { + "schema": {} + } + } + } + }, + "operationId": "user.created" + } + }, + "user.updated": { + "post": { + "summary": "user.updated", + "description": "This event is triggered when a user is updated.", + "parameters": [], + "requestBody": { + "required": true, + "content": { + "application/json": { + "schema": { + "type": "object", + "properties": { + "type": { + "type": "string", + "example": "user.updated", + "description": "user.updated" + }, + "data": { + "type": "object", + "properties": { + "id": { + "type": "string", + "example": "3241a285-8329-4d69-8f3d-316e08cf140c", + "description": "The unique identifier of the user" + }, + "primary_email": { + "type": "string", + "example": "johndoe@example.com", + "description": "Primary email" + }, + "primary_email_verified": { + "type": "boolean", + "example": true, + "description": "Whether the primary email has been verified to belong to this user" + }, + "primary_email_auth_enabled": { + "type": "boolean", + "example": true, + "description": "Whether the primary email is used for authentication. If this is set to `false`, the user will not be able to sign in with the primary email with password or OTP" + }, + "display_name": { + "type": "string", + "example": "John Doe", + "description": "Human-readable user display name. This is not a unique identifier." + }, + "selected_team": { + "type": "object", + "properties": { + "created_at_millis": { + "type": "number", + "example": 1630000000000, + "description": "The time the team was created (the number of milliseconds since epoch, January 1, 1970, UTC)" + }, + "server_metadata": { + "type": "object", + "example": { + "key": "value" + }, + "description": "Server metadata. Used as a data store, only accessible from the server side. You can store secret information related to the team here." + }, + "id": { + "type": "string", + "example": "ad962777-8244-496a-b6a2-e0c6a449c79e", + "description": "The unique identifier of the team" + }, + "display_name": { + "type": "string", + "example": "My Team", + "description": "Human-readable team display name. This is not a unique identifier." + }, + "profile_image_url": { + "type": "string", + "example": "https://example.com/image.jpg", + "description": "URL of the profile image for team. Can be a Base64 encoded image. Must be smaller than 100KB. Please compress and crop to a square before passing in." + }, + "client_metadata": { + "type": "object", + "example": { + "key": "value" + }, + "description": "Client metadata. Used as a data store, accessible from the client side. Do not store information that should not be exposed to the client." + }, + "client_read_only_metadata": { + "type": "object", + "example": { + "key": "value" + }, + "description": "Client read-only, server-writable metadata. Used as a data store, accessible from the client side. Do not store information that should not be exposed to the client. The client can read this data, but cannot modify it. This is useful for things like subscription status." + } + }, + "required": [ + "created_at_millis", + "id", + "display_name" + ] + }, + "selected_team_id": { + "type": "string", + "example": "team-id", + "description": "ID of the team currently selected by the user" + }, + "profile_image_url": { + "type": "string", + "example": "https://example.com/image.jpg", + "description": "URL of the profile image for user. Can be a Base64 encoded image. Must be smaller than 100KB. Please compress and crop to a square before passing in." + }, + "signed_up_at_millis": { + "type": "number", + "example": 1630000000000, + "description": "The time the user signed up (identify) => `(the number of milliseconds since epoch, January 1, 1970, UTC)`" + }, + "client_metadata": { + "type": "object", + "example": { + "key": "value" + }, + "description": "Client metadata. Used as a data store, accessible from the client side. Do not store information that should not be exposed to the client." + }, + "client_read_only_metadata": { + "type": "object", + "example": { + "key": "value" + }, + "description": "Client read-only, server-writable metadata. Used as a data store, accessible from the client side. Do not store information that should not be exposed to the client. The client can read this data, but cannot modify it. This is useful for things like subscription status." + }, + "server_metadata": { + "type": "object", + "example": { + "key": "value" + }, + "description": "Server metadata. Used as a data store, only accessible from the server side. You can store secret information related to the user here." + }, + "last_active_at_millis": { + "type": "number", + "example": 1630000000000, + "description": "The time the user was last active (identify) => `(the number of milliseconds since epoch, January 1, 1970, UTC)`" + }, + "is_anonymous": { + "type": "boolean" + }, + "is_restricted": { + "type": "boolean", + "example": false, + "description": "Whether the user is in restricted state (has signed up but not completed onboarding requirements)" + }, + "restricted_reason": { + "type": "object", + "properties": { + "type": { + "type": "string" + } + }, + "required": [ + "type" + ], + "example": null, + "description": "The reason why the user is restricted (e.g., type: \"email_not_verified\", \"anonymous\", or \"restricted_by_administrator\"), null if not restricted" + }, + "restricted_by_admin": { + "type": "boolean", + "example": false, + "description": "Whether the user is restricted by an administrator. Can be set manually or by sign-up rules." + }, + "restricted_by_admin_reason": { + "type": "string", + "example": null, + "description": "Public reason shown to the user explaining why they are restricted. Optional." + }, + "restricted_by_admin_private_details": { + "type": "string", + "example": null, + "description": "Private details about the restriction (e.g., which sign-up rule triggered). Only visible to server access and above." + }, + "country_code": { + "type": "string", + "example": "US", + "description": "Best-effort ISO country code captured at sign-up time from request geo headers." + }, + "risk_scores": { + "type": "object", + "properties": { + "sign_up": { + "type": "object", + "properties": { + "bot": { + "type": "number" + }, + "free_trial_abuse": { + "type": "number" + } + }, + "required": [ + "bot", + "free_trial_abuse" + ] + } + }, + "required": [ + "sign_up" + ], + "example": { + "sign_up": { + "bot": 0, + "free_trial_abuse": 0 + } + }, + "description": "User risk scores used for sign-up risk evaluation." + } + }, + "required": [ + "id", + "primary_email_verified", + "primary_email_auth_enabled", + "signed_up_at_millis", + "last_active_at_millis", + "is_anonymous", + "is_restricted", + "restricted_by_admin", + "risk_scores" + ] + } + }, + "required": [ + "type", + "data" + ], + "example": { + "type": "user.updated" + } + } + } + } + }, + "tags": [ + "Users" + ], + "x-full-url": "https://api.stack-auth.com/api/v1/webhooks/user.updated", + "responses": { + "200": { + "description": "Successful response", + "content": { + "application/json": { + "schema": {} + } + } + } + }, + "operationId": "user.updated" + } + }, + "user.deleted": { + "post": { + "summary": "user.deleted", + "description": "This event is triggered when a user is deleted.", + "parameters": [], + "requestBody": { + "required": true, + "content": { + "application/json": { + "schema": { + "type": "object", + "properties": { + "type": { + "type": "string", + "example": "user.deleted", + "description": "user.deleted" + }, + "data": { + "type": "object", + "properties": { + "id": { + "type": "string", + "example": "3241a285-8329-4d69-8f3d-316e08cf140c", + "description": "The unique identifier of the user" + }, + "teams": { + "type": "array", + "items": { + "type": "object", + "properties": { + "id": { + "type": "string" + } + }, + "required": [ + "id" + ] + } + } + }, + "required": [ + "id", + "teams" + ] + } + }, + "required": [ + "type", + "data" + ], + "example": { + "type": "user.deleted" + } + } + } + } + }, + "tags": [ + "Users" + ], + "x-full-url": "https://api.stack-auth.com/api/v1/webhooks/user.deleted", + "responses": { + "200": { + "description": "Successful response", + "content": { + "application/json": { + "schema": {} + } + } + } + }, + "operationId": "user.deleted" + } + }, + "team.created": { + "post": { + "summary": "team.created", + "description": "This event is triggered when a team is created.", + "parameters": [], + "requestBody": { + "required": true, + "content": { + "application/json": { + "schema": { + "type": "object", + "properties": { + "type": { + "type": "string", + "example": "team.created", + "description": "team.created" + }, + "data": { + "type": "object", + "properties": { + "created_at_millis": { + "type": "number", + "example": 1630000000000, + "description": "The time the team was created (the number of milliseconds since epoch, January 1, 1970, UTC)" + }, + "server_metadata": { + "type": "object", + "example": { + "key": "value" + }, + "description": "Server metadata. Used as a data store, only accessible from the server side. You can store secret information related to the team here." + }, + "id": { + "type": "string", + "example": "ad962777-8244-496a-b6a2-e0c6a449c79e", + "description": "The unique identifier of the team" + }, + "display_name": { + "type": "string", + "example": "My Team", + "description": "Human-readable team display name. This is not a unique identifier." + }, + "profile_image_url": { + "type": "string", + "example": "https://example.com/image.jpg", + "description": "URL of the profile image for team. Can be a Base64 encoded image. Must be smaller than 100KB. Please compress and crop to a square before passing in." + }, + "client_metadata": { + "type": "object", + "example": { + "key": "value" + }, + "description": "Client metadata. Used as a data store, accessible from the client side. Do not store information that should not be exposed to the client." + }, + "client_read_only_metadata": { + "type": "object", + "example": { + "key": "value" + }, + "description": "Client read-only, server-writable metadata. Used as a data store, accessible from the client side. Do not store information that should not be exposed to the client. The client can read this data, but cannot modify it. This is useful for things like subscription status." + } + }, + "required": [ + "created_at_millis", + "id", + "display_name" + ] + } + }, + "required": [ + "type", + "data" + ], + "example": { + "type": "team.created" + } + } + } + } + }, + "tags": [ + "Teams" + ], + "x-full-url": "https://api.stack-auth.com/api/v1/webhooks/team.created", + "responses": { + "200": { + "description": "Successful response", + "content": { + "application/json": { + "schema": {} + } + } + } + }, + "operationId": "team.created" + } + }, + "team.updated": { + "post": { + "summary": "team.updated", + "description": "This event is triggered when a team is updated.", + "parameters": [], + "requestBody": { + "required": true, + "content": { + "application/json": { + "schema": { + "type": "object", + "properties": { + "type": { + "type": "string", + "example": "team.updated", + "description": "team.updated" + }, + "data": { + "type": "object", + "properties": { + "created_at_millis": { + "type": "number", + "example": 1630000000000, + "description": "The time the team was created (the number of milliseconds since epoch, January 1, 1970, UTC)" + }, + "server_metadata": { + "type": "object", + "example": { + "key": "value" + }, + "description": "Server metadata. Used as a data store, only accessible from the server side. You can store secret information related to the team here." + }, + "id": { + "type": "string", + "example": "ad962777-8244-496a-b6a2-e0c6a449c79e", + "description": "The unique identifier of the team" + }, + "display_name": { + "type": "string", + "example": "My Team", + "description": "Human-readable team display name. This is not a unique identifier." + }, + "profile_image_url": { + "type": "string", + "example": "https://example.com/image.jpg", + "description": "URL of the profile image for team. Can be a Base64 encoded image. Must be smaller than 100KB. Please compress and crop to a square before passing in." + }, + "client_metadata": { + "type": "object", + "example": { + "key": "value" + }, + "description": "Client metadata. Used as a data store, accessible from the client side. Do not store information that should not be exposed to the client." + }, + "client_read_only_metadata": { + "type": "object", + "example": { + "key": "value" + }, + "description": "Client read-only, server-writable metadata. Used as a data store, accessible from the client side. Do not store information that should not be exposed to the client. The client can read this data, but cannot modify it. This is useful for things like subscription status." + } + }, + "required": [ + "created_at_millis", + "id", + "display_name" + ] + } + }, + "required": [ + "type", + "data" + ], + "example": { + "type": "team.updated" + } + } + } + } + }, + "tags": [ + "Teams" + ], + "x-full-url": "https://api.stack-auth.com/api/v1/webhooks/team.updated", + "responses": { + "200": { + "description": "Successful response", + "content": { + "application/json": { + "schema": {} + } + } + } + }, + "operationId": "team.updated" + } + }, + "team.deleted": { + "post": { + "summary": "team.deleted", + "description": "This event is triggered when a team is deleted.", + "parameters": [], + "requestBody": { + "required": true, + "content": { + "application/json": { + "schema": { + "type": "object", + "properties": { + "type": { + "type": "string", + "example": "team.deleted", + "description": "team.deleted" + }, + "data": { + "type": "object", + "properties": { + "id": { + "type": "string", + "example": "3241a285-8329-4d69-8f3d-316e08cf140c", + "description": "The unique identifier of the user" + } + }, + "required": [ + "id" + ] + } + }, + "required": [ + "type", + "data" + ], + "example": { + "type": "team.deleted" + } + } + } + } + }, + "tags": [ + "Teams" + ], + "x-full-url": "https://api.stack-auth.com/api/v1/webhooks/team.deleted", + "responses": { + "200": { + "description": "Successful response", + "content": { + "application/json": { + "schema": {} + } + } + } + }, + "operationId": "team.deleted" + } + }, + "team_membership.created": { + "post": { + "summary": "team_membership.created", + "description": "This event is triggered when a user is added to a team.", + "parameters": [], + "requestBody": { + "required": true, + "content": { + "application/json": { + "schema": { + "type": "object", + "properties": { + "type": { + "type": "string", + "example": "team_membership.created", + "description": "team_membership.created" + }, + "data": { + "type": "object", + "properties": { + "team_id": { + "type": "string" + }, + "user_id": { + "type": "string" + } + }, + "required": [ + "team_id", + "user_id" + ] + } + }, + "required": [ + "type", + "data" + ], + "example": { + "type": "team_membership.created" + } + } + } + } + }, + "tags": [ + "Teams" + ], + "x-full-url": "https://api.stack-auth.com/api/v1/webhooks/team_membership.created", + "responses": { + "200": { + "description": "Successful response", + "content": { + "application/json": { + "schema": {} + } + } + } + }, + "operationId": "team_membership.created" + } + }, + "team_membership.deleted": { + "post": { + "summary": "team_membership.deleted", + "description": "This event is triggered when a user is removed from a team.", + "parameters": [], + "requestBody": { + "required": true, + "content": { + "application/json": { + "schema": { + "type": "object", + "properties": { + "type": { + "type": "string", + "example": "team_membership.deleted", + "description": "team_membership.deleted" + }, + "data": { + "type": "object", + "properties": { + "team_id": { + "type": "string" + }, + "user_id": { + "type": "string" + } + }, + "required": [ + "team_id", + "user_id" + ] + } + }, + "required": [ + "type", + "data" + ], + "example": { + "type": "team_membership.deleted" + } + } + } + } + }, + "tags": [ + "Teams" + ], + "x-full-url": "https://api.stack-auth.com/api/v1/webhooks/team_membership.deleted", + "responses": { + "200": { + "description": "Successful response", + "content": { + "application/json": { + "schema": {} + } + } + } + }, + "operationId": "team_membership.deleted" + } + }, + "team_permission.created": { + "post": { + "summary": "team_permission.created", + "description": "This event is triggered when a team permission is created.", + "parameters": [], + "requestBody": { + "required": true, + "content": { + "application/json": { + "schema": { + "type": "object", + "properties": { + "type": { + "type": "string", + "example": "team_permission.created", + "description": "team_permission.created" + }, + "data": { + "type": "object", + "properties": { + "id": { + "type": "string", + "example": "read_secret_info", + "description": "The permission ID used to uniquely identify a permission. Can either be a custom permission with lowercase letters, numbers, `:`, and `_` characters, or one of the system permissions: `$update_team`, `$delete_team`, `$read_members`, `$remove_members`, `$invite_members`, `$manage_api_keys`" + }, + "user_id": { + "type": "string", + "example": "3241a285-8329-4d69-8f3d-316e08cf140c", + "description": "The unique identifier of the user" + }, + "team_id": { + "type": "string", + "example": "ad962777-8244-496a-b6a2-e0c6a449c79e", + "description": "The unique identifier of the team" + } + }, + "required": [ + "id", + "user_id", + "team_id" + ] + } + }, + "required": [ + "type", + "data" + ], + "example": { + "type": "team_permission.created" + } + } + } + } + }, + "tags": [ + "Teams" + ], + "x-full-url": "https://api.stack-auth.com/api/v1/webhooks/team_permission.created", + "responses": { + "200": { + "description": "Successful response", + "content": { + "application/json": { + "schema": {} + } + } + } + }, + "operationId": "team_permission.created" + } + }, + "team_permission.deleted": { + "post": { + "summary": "team_permission.deleted", + "description": "This event is triggered when a team permission is deleted.", + "parameters": [], + "requestBody": { + "required": true, + "content": { + "application/json": { + "schema": { + "type": "object", + "properties": { + "type": { + "type": "string", + "example": "team_permission.deleted", + "description": "team_permission.deleted" + }, + "data": { + "type": "object", + "properties": { + "id": { + "type": "string", + "example": "read_secret_info", + "description": "The permission ID used to uniquely identify a permission. Can either be a custom permission with lowercase letters, numbers, `:`, and `_` characters, or one of the system permissions: `$update_team`, `$delete_team`, `$read_members`, `$remove_members`, `$invite_members`, `$manage_api_keys`" + }, + "user_id": { + "type": "string", + "example": "3241a285-8329-4d69-8f3d-316e08cf140c", + "description": "The unique identifier of the user" + }, + "team_id": { + "type": "string", + "example": "ad962777-8244-496a-b6a2-e0c6a449c79e", + "description": "The unique identifier of the team" + } + }, + "required": [ + "id", + "user_id", + "team_id" + ] + } + }, + "required": [ + "type", + "data" + ], + "example": { + "type": "team_permission.deleted" + } + } + } + } + }, + "tags": [ + "Teams" + ], + "x-full-url": "https://api.stack-auth.com/api/v1/webhooks/team_permission.deleted", + "responses": { + "200": { + "description": "Successful response", + "content": { + "application/json": { + "schema": {} + } + } + } + }, + "operationId": "team_permission.deleted" + } + } + } +} \ No newline at end of file diff --git a/docs-mintlify/sdk/types/user.mdx b/docs-mintlify/sdk/types/user.mdx index 390020bf04..774076befc 100644 --- a/docs-mintlify/sdk/types/user.mdx +++ b/docs-mintlify/sdk/types/user.mdx @@ -81,6 +81,8 @@ Use `useUser()` to get `CurrentUser` (client). Use `stackServerApp.getUser()` to delete(): Promise; //$stack-link-to:#currentuserdelete toClientJson(): CurrentUserCrud["Client"]["Read"]; //$stack-link-to:#currentusertoclientjson + getAuthorizationHeader(): Promise; //$stack-link-to:#currentusergetauthorizationheader + useAuthorizationHeader(): string | null; //$stack-link-to:#currentuseruseauthorizationheader getAuthHeaders(): Promise>; //$stack-link-to:#currentusergetauthheaders useAuthHeaders(): Record; //$stack-link-to:#currentuseruseauthheaders getAccessToken(): Promise; //$stack-link-to:#currentusergetaccesstoken @@ -667,10 +669,52 @@ Use `useUser()` to get `CurrentUser` (client). Use `stackServerApp.getUser()` to ## Authentication + + + + Returns the HTTP `Authorization` header value in `Bearer stackauth_...` format for authenticated requests. + Returns `null` if the user is not signed in. + + + + + + + ```typescript + declare function getAuthorizationHeader(): Promise; + ``` + + + + + + + + + + React hook that returns the HTTP `Authorization` header value in `Bearer stackauth_...` format. + Returns `null` if the user is not signed in. + + + + + + + ```typescript + declare function useAuthorizationHeader(): string | null; + ``` + + + + + + - Returns headers for cross-origin authenticated requests. + **Deprecated:** Use `getAuthorizationHeader()` instead. + + Returns legacy `x-stack-auth` headers for cross-origin authenticated requests. @@ -689,7 +733,9 @@ Use `useUser()` to get `CurrentUser` (client). Use `stackServerApp.getUser()` to - React hook that returns authentication headers for cross-origin requests. + **Deprecated:** Use `useAuthorizationHeader()` instead. + + React hook that returns legacy `x-stack-auth` headers for cross-origin requests. diff --git a/docs-mintlify/snippets/docs-apps-home-grid.jsx b/docs-mintlify/snippets/docs-apps-home-grid.jsx index 989e3be1e1..2339423c91 100644 --- a/docs-mintlify/snippets/docs-apps-home-grid.jsx +++ b/docs-mintlify/snippets/docs-apps-home-grid.jsx @@ -96,122 +96,6 @@ export const DocsAppsHomeGrid = () => { } }; - if (typeof document !== "undefined" && typeof window !== "undefined") { - window.requestAnimationFrame(() => { - const navigationItems = document.querySelector("#navigation-items"); - if (navigationItems == null) { - return; - } - - const sidebarHeaders = navigationItems.querySelectorAll(".sidebar-group-header"); - const appsHeader = Array.from(sidebarHeaders).find((header) => header.textContent?.trim() === "Apps"); - if (appsHeader == null) { - return; - } - - const appsGroupContainer = appsHeader.parentElement; - const appsList = appsGroupContainer?.querySelector("ul"); - if (appsGroupContainer == null || appsList == null) { - return; - } - const existingHeaderSearch = appsHeader.querySelector("[data-apps-sidebar-search='true']"); - if (existingHeaderSearch != null) { - existingHeaderSearch.remove(); - } - const legacySearchContainers = appsGroupContainer.querySelectorAll("div[data-apps-sidebar-search='true']"); - for (const legacySearchContainer of legacySearchContainers) { - legacySearchContainer.remove(); - } - const existingEmptyStates = appsGroupContainer.querySelectorAll("[data-apps-sidebar-empty='true']"); - for (const existingEmptyState of existingEmptyStates) { - existingEmptyState.remove(); - } - - const searchInput = document.createElement("input"); - searchInput.type = "text"; - searchInput.placeholder = "Filter..."; - searchInput.setAttribute("aria-label", "Filter apps in sidebar"); - searchInput.style.width = "120px"; - searchInput.style.height = "24px"; - searchInput.style.borderRadius = "7px"; - searchInput.style.padding = "0 8px"; - searchInput.style.fontSize = "11px"; - searchInput.style.lineHeight = "1"; - searchInput.style.outline = "none"; - searchInput.style.transition = "border-color 150ms ease, background-color 150ms ease, color 150ms ease"; - searchInput.style.fontWeight = "500"; - searchInput.style.marginLeft = "auto"; - searchInput.style.flexShrink = "0"; - - const emptyState = document.createElement("div"); - emptyState.setAttribute("data-apps-sidebar-empty", "true"); - emptyState.style.display = "none"; - emptyState.style.padding = "2px 0 8px 16px"; - emptyState.style.fontSize = "12px"; - emptyState.style.lineHeight = "1.3"; - - const emptyStatePrefix = document.createElement("span"); - emptyStatePrefix.textContent = "No more results. "; - emptyState.appendChild(emptyStatePrefix); - - const clearFilterButton = document.createElement("button"); - clearFilterButton.type = "button"; - clearFilterButton.textContent = "Clear filter"; - clearFilterButton.style.border = "none"; - clearFilterButton.style.padding = "0"; - clearFilterButton.style.background = "transparent"; - clearFilterButton.style.fontSize = "12px"; - clearFilterButton.style.fontWeight = "600"; - clearFilterButton.style.cursor = "pointer"; - clearFilterButton.style.textDecoration = "underline"; - clearFilterButton.style.textUnderlineOffset = "2px"; - emptyState.appendChild(clearFilterButton); - - const applyTheme = () => { - const isDark = document.documentElement.classList.contains("dark"); - searchInput.style.background = isDark ? "rgba(17,24,39,0.72)" : "rgba(248,250,252,0.98)"; - searchInput.style.color = isDark ? "#e5e7eb" : "#111827"; - searchInput.style.border = isDark ? "1px solid rgba(75,85,99,0.9)" : "1px solid rgba(203,213,225,0.95)"; - emptyState.style.color = isDark ? "rgba(203,213,225,0.86)" : "rgba(55,65,81,0.9)"; - clearFilterButton.style.color = isDark ? "#8fb7ff" : "#295fbe"; - }; - - const filterSidebarApps = () => { - const query = searchInput.value.trim().toLowerCase(); - const appRows = Array.from(appsList.children); - let visibleCount = 0; - for (const row of appRows) { - const searchableElement = row.querySelector("a, button") ?? row; - const rowText = searchableElement.textContent?.replace(/\s+/g, " ").trim().toLowerCase() ?? ""; - const isVisible = query.length === 0 || rowText.includes(query); - row.style.display = isVisible ? "" : "none"; - if (isVisible) { - visibleCount += 1; - } - } - emptyState.style.display = query.length > 0 && visibleCount === 0 ? "block" : "none"; - }; - - clearFilterButton.addEventListener("click", () => { - searchInput.value = ""; - filterSidebarApps(); - searchInput.focus(); - }); - searchInput.addEventListener("input", filterSidebarApps); - applyTheme(); - const classObserver = new MutationObserver(applyTheme); - classObserver.observe(document.documentElement, { attributes: true, attributeFilter: ["class"] }); - - appsHeader.style.display = "flex"; - appsHeader.style.alignItems = "center"; - appsHeader.style.gap = "8px"; - appsHeader.style.paddingRight = "12px"; - searchInput.setAttribute("data-apps-sidebar-search", "true"); - appsHeader.appendChild(searchInput); - appsGroupContainer.insertBefore(emptyState, appsList); - }); - } - return (
diff --git a/docs-mintlify/snippets/home-prompt-island.jsx b/docs-mintlify/snippets/home-prompt-island.jsx index 943b460a76..095afae9c1 100644 --- a/docs-mintlify/snippets/home-prompt-island.jsx +++ b/docs-mintlify/snippets/home-prompt-island.jsx @@ -1,66 +1,15 @@ -export const HomePromptIsland = () => { - const agentSetupPromptPlaceholder = `You are my coding agent. - -Set up Stack Auth in this project. -- Install and configure Stack Auth -- Create initial authentication routes -- Add sign-in and sign-up UI -- Verify local development setup - -Return the exact files changed and next steps.`; - - const onCopy = async (event) => { - const button = event.currentTarget; - await navigator.clipboard.writeText(agentSetupPromptPlaceholder); - button.textContent = "Copied"; - window.setTimeout(() => { - button.textContent = "Copy prompt"; - }, 1300); - }; - - return ( -
-

- Agent-first setup -

- -

- Start with a single prompt. -

-

- Set up Stack Auth by copying the prompt below into your favorite coding agent. -

- -
-