Docs: Update apps documentation#1483
Conversation
|
The latest updates on your projects. Learn more about Vercel for GitHub.
|
📝 WalkthroughWalkthroughThis PR comprehensively updates Stack Auth documentation across multiple dashboard apps: reorganizing navigation to group Emails/Payments/Analytics, relocating Fraud Protection to Authentication, adding new guides for Analytics queries/replays/tables and Emails/Payments workflows, extensively rewriting API Keys and Teams guides, and expanding RBAC/Data Vault/Webhooks documentation. ChangesMulti-App Documentation Update
Estimated code review effort🎯 3 (Moderate) | ⏱️ ~25 minutes Suggested reviewers
Poem
🚥 Pre-merge checks | ✅ 4 | ❌ 1❌ Failed checks (1 inconclusive)
✅ Passed checks (4 passed)
✏️ Tip: You can configure your own custom pre-merge checks in the settings. ✨ Finishing Touches📝 Generate docstrings
🧪 Generate unit tests (beta)
Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out. Comment |
Greptile SummaryThis PR expands the apps documentation significantly, splitting single-page overviews for Analytics, Emails, and Payments into dedicated sub-pages, relocating Fraud Protection under Authentication, and enriching several existing pages (RBAC, Teams, Webhooks, API Keys, Data Vault) with dashboard walkthroughs and additional SDK examples.
Confidence Score: 3/5Not safe to merge as-is — The teams overview page has a duplicate YAML frontmatter block in the middle of the file body (lines 419–423) and ~230 lines of the original file content re-appearing after the new section. Mintlify will render those docs-mintlify/guides/apps/teams/overview.mdx — the old frontmatter and old body content starting at line 419 need to be removed. Important Files Changed
Flowchart%%{init: {'theme': 'neutral'}}%%
flowchart TD
A[Apps Home Grid] --> B[Authentication]
A --> C[Emails]
A --> D[Payments]
A --> E[Analytics]
A --> F[Teams]
A --> G[Fraud Protection]
A --> H[RBAC]
A --> I[API Keys]
A --> J[Data Vault]
A --> K[Webhooks]
B --> B1[fraud-protection NEW]
B --> B2[sign-up-rules]
C --> C1[Overview]
C --> C2[Sent NEW]
C --> C3[Drafts NEW]
C --> C4[Templates NEW]
C --> C5[Email Settings NEW]
D --> D1[Overview]
D --> D2[Product Lines NEW]
D --> D3[Products and Items NEW]
D --> D4[Customers NEW]
D --> D5[Transactions NEW]
D --> D6[Settings NEW]
E --> E1[Overview]
E --> E2[Tables NEW]
E --> E3[Queries NEW]
E --> E4[Replays NEW]
G -->|redirect| B1
style B1 fill:#d4edda
style C2 fill:#d4edda
style C3 fill:#d4edda
style C4 fill:#d4edda
style C5 fill:#d4edda
style D2 fill:#d4edda
style D3 fill:#d4edda
style D4 fill:#d4edda
style D5 fill:#d4edda
style D6 fill:#d4edda
style E2 fill:#d4edda
style E3 fill:#d4edda
style E4 fill:#d4edda
Prompt To Fix All With AIFix the following 2 code review issues. Work through them one at a time, proposing concise fixes.
---
### Issue 1 of 2
docs-mintlify/guides/apps/teams/overview.mdx:419-427
**Duplicate frontmatter block and duplicated old content**
The PR prepended new content before the existing file but did not remove the original file's frontmatter. Lines 419–423 contain a raw `---` YAML block in the middle of the document body:
In MDX, frontmatter is only parsed when it appears at the very start of the file. A second `---` block in the body is treated as literal content: Mintlify will render it as two horizontal rules with raw YAML text between them, breaking the page visually. Additionally, the old file content (Concepts, Dashboard pages, all SDK code examples, etc.) is still present from line 424 to the end of the file, meaning all of that section is now duplicated. Lines 419 through the end (~235 lines) should be removed.
### Issue 2 of 2
docs-mintlify/guides/apps/payments/customers.mdx:108-114
The `consumeCredits` helper returns `credits.quantity` immediately after calling `tryDecreaseQuantity`. If the SDK does not mutate the object in place, this will return the pre-decrease balance, making the `remaining` field stale in the documentation example. The safer pattern is to subtract explicitly or refetch, and the same issue appears in the identical snippet in `products-and-items.mdx`.
```suggestion
const success = await credits.tryDecreaseQuantity(amount);
if (!success) {
throw new Error("Insufficient credits");
}
return { remaining: credits.quantity - amount };
```
Reviews (1): Last reviewed commit: "Merge branch 'dev' into docs/apps_update..." | Re-trigger Greptile |
| --- | ||
| title: "Teams" | ||
| description: "Manage teams and team members" | ||
| sidebarTitle: "Overview" | ||
| --- | ||
|
|
||
| Teams provide a structured way to group users and manage their permissions. Users can belong to multiple teams simultaneously, allowing them to represent departments, B2B customers, or projects. | ||
|
|
||
| The server can perform all operations on a team, but the client can only carry out some actions if the user has the necessary permissions. This applies to all actions that can be performed on a server/client-side `User` object and a `Team` object. |
There was a problem hiding this comment.
Duplicate frontmatter block and duplicated old content
The PR prepended new content before the existing file but did not remove the original file's frontmatter. Lines 419–423 contain a raw --- YAML block in the middle of the document body:
In MDX, frontmatter is only parsed when it appears at the very start of the file. A second --- block in the body is treated as literal content: Mintlify will render it as two horizontal rules with raw YAML text between them, breaking the page visually. Additionally, the old file content (Concepts, Dashboard pages, all SDK code examples, etc.) is still present from line 424 to the end of the file, meaning all of that section is now duplicated. Lines 419 through the end (~235 lines) should be removed.
Prompt To Fix With AI
This is a comment left during a code review.
Path: docs-mintlify/guides/apps/teams/overview.mdx
Line: 419-427
Comment:
**Duplicate frontmatter block and duplicated old content**
The PR prepended new content before the existing file but did not remove the original file's frontmatter. Lines 419–423 contain a raw `---` YAML block in the middle of the document body:
In MDX, frontmatter is only parsed when it appears at the very start of the file. A second `---` block in the body is treated as literal content: Mintlify will render it as two horizontal rules with raw YAML text between them, breaking the page visually. Additionally, the old file content (Concepts, Dashboard pages, all SDK code examples, etc.) is still present from line 424 to the end of the file, meaning all of that section is now duplicated. Lines 419 through the end (~235 lines) should be removed.
How can I resolve this? If you propose a fix, please make it concise.| const success = await credits.tryDecreaseQuantity(amount); | ||
|
|
||
| if (!success) { | ||
| throw new Error("Insufficient credits"); | ||
| } | ||
|
|
||
| return { remaining: credits.quantity }; |
There was a problem hiding this comment.
The
consumeCredits helper returns credits.quantity immediately after calling tryDecreaseQuantity. If the SDK does not mutate the object in place, this will return the pre-decrease balance, making the remaining field stale in the documentation example. The safer pattern is to subtract explicitly or refetch, and the same issue appears in the identical snippet in products-and-items.mdx.
| const success = await credits.tryDecreaseQuantity(amount); | |
| if (!success) { | |
| throw new Error("Insufficient credits"); | |
| } | |
| return { remaining: credits.quantity }; | |
| const success = await credits.tryDecreaseQuantity(amount); | |
| if (!success) { | |
| throw new Error("Insufficient credits"); | |
| } | |
| return { remaining: credits.quantity - amount }; |
Prompt To Fix With AI
This is a comment left during a code review.
Path: docs-mintlify/guides/apps/payments/customers.mdx
Line: 108-114
Comment:
The `consumeCredits` helper returns `credits.quantity` immediately after calling `tryDecreaseQuantity`. If the SDK does not mutate the object in place, this will return the pre-decrease balance, making the `remaining` field stale in the documentation example. The safer pattern is to subtract explicitly or refetch, and the same issue appears in the identical snippet in `products-and-items.mdx`.
```suggestion
const success = await credits.tryDecreaseQuantity(amount);
if (!success) {
throw new Error("Insufficient credits");
}
return { remaining: credits.quantity - amount };
```
How can I resolve this? If you propose a fix, please make it concise.There was a problem hiding this comment.
6 issues found across 26 files
Prompt for AI agents (unresolved issues)
Check if these issues are valid — if so, understand the root cause of each and fix them. If appropriate, use sub-agents to investigate and fix each issue separately.
<file name="docs-mintlify/guides/apps/teams/overview.mdx">
<violation number="1" location="docs-mintlify/guides/apps/teams/overview.mdx:419">
P1: Duplicate frontmatter block and old content left in the file. The new documentation was added but the old content was not removed, resulting in a broken MDX file with two frontmatter blocks and duplicated sections. The second `---` block and everything after it should be deleted.</violation>
</file>
<file name="docs-mintlify/guides/apps/emails/drafts.mdx">
<violation number="1" location="docs-mintlify/guides/apps/emails/drafts.mdx:79">
P2: Fix the recipient example so it shows one valid branch; the current snippet is invalid and conflicts with the documented API shape.</violation>
</file>
<file name="docs-mintlify/guides/apps/payments/product-lines.mdx">
<violation number="1" location="docs-mintlify/guides/apps/payments/product-lines.mdx:130">
P2: This code example is misleading — `useTeam` is a hook (must be in a synchronous component body) but is immediately followed by a top-level `await`, which requires an async context. Unlike the `UpgradeButton` example above which correctly places the `await` inside an event handler, this snippet looks like it could be pasted directly into a component body, but it won't work. Consider wrapping it in an event handler or adding a comment indicating this must be inside an async callback.</violation>
</file>
<file name="docs-mintlify/guides/apps/rbac/overview.mdx">
<violation number="1" location="docs-mintlify/guides/apps/rbac/overview.mdx:309">
P2: The code example contradicts the section's purpose. "Listing All Project Permissions" should show the default recursive call (which includes inherited permissions), but the example uses `{ recursive: false }` which only returns direct grants. The equivalent team permissions section correctly uses the default. Consider removing `{ recursive: false }` from the primary example and instead mentioning it as an alternative, as done in the team permissions section.</violation>
</file>
<file name="docs-mintlify/guides/apps/payments/settings.mdx">
<violation number="1" location="docs-mintlify/guides/apps/payments/settings.mdx:106">
P2: Undefined variable `setupIntentId` in code example — should likely be `setupIntent.id` based on the variable created on the preceding line. Developers copy-pasting this snippet will get a reference error.</violation>
</file>
<file name="docs-mintlify/guides/apps/payments/products-and-items.mdx">
<violation number="1" location="docs-mintlify/guides/apps/payments/products-and-items.mdx:240">
P2: The `credits.quantity` returned here likely reflects the stale pre-decrease value. The E2E tests re-fetch the item after `tryDecreaseQuantity` to get the updated balance, suggesting the original object's `quantity` is not mutated. Consider re-fetching or computing the expected remaining balance.</violation>
</file>
Tip: instead of fixing issues one by one fix them all with cubic
Tip: cubic can generate docs of your entire codebase and keep them up to date. Try it here.
Re-trigger cubic
| ``` | ||
|
|
||
| Deleting a team removes all memberships for that team. Make sure your app treats deleted team IDs as invalid and refreshes any team switchers after deletion. | ||
| --- |
There was a problem hiding this comment.
P1: Duplicate frontmatter block and old content left in the file. The new documentation was added but the old content was not removed, resulting in a broken MDX file with two frontmatter blocks and duplicated sections. The second --- block and everything after it should be deleted.
Prompt for AI agents
Check if this issue is valid — if so, understand the root cause and fix it. At docs-mintlify/guides/apps/teams/overview.mdx, line 419:
<comment>Duplicate frontmatter block and old content left in the file. The new documentation was added but the old content was not removed, resulting in a broken MDX file with two frontmatter blocks and duplicated sections. The second `---` block and everything after it should be deleted.</comment>
<file context>
@@ -4,6 +4,424 @@ description: "Manage teams and team members"
+```
+
+Deleting a team removes all memberships for that team. Make sure your app treats deleted team IDs as invalid and refreshes any team switchers after deletion.
+---
+title: "Teams"
+description: "Manage teams and team members"
</file context>
| ```typescript | ||
| await stackServerApp.sendEmail({ | ||
| draftId, | ||
| // either: |
There was a problem hiding this comment.
P2: Fix the recipient example so it shows one valid branch; the current snippet is invalid and conflicts with the documented API shape.
Prompt for AI agents
Check if this issue is valid — if so, understand the root cause and fix it. At docs-mintlify/guides/apps/emails/drafts.mdx, line 79:
<comment>Fix the recipient example so it shows one valid branch; the current snippet is invalid and conflicts with the documented API shape.</comment>
<file context>
@@ -0,0 +1,110 @@
+```typescript
+await stackServerApp.sendEmail({
+ draftId,
+ // either:
+ userIds: [...],
+ // or:
</file context>
| Team plans work the same way when you call the methods on a team object: | ||
|
|
||
| ```typescript | ||
| const team = user.useTeam(teamId); |
There was a problem hiding this comment.
P2: This code example is misleading — useTeam is a hook (must be in a synchronous component body) but is immediately followed by a top-level await, which requires an async context. Unlike the UpgradeButton example above which correctly places the await inside an event handler, this snippet looks like it could be pasted directly into a component body, but it won't work. Consider wrapping it in an event handler or adding a comment indicating this must be inside an async callback.
Prompt for AI agents
Check if this issue is valid — if so, understand the root cause and fix it. At docs-mintlify/guides/apps/payments/product-lines.mdx, line 130:
<comment>This code example is misleading — `useTeam` is a hook (must be in a synchronous component body) but is immediately followed by a top-level `await`, which requires an async context. Unlike the `UpgradeButton` example above which correctly places the `await` inside an event handler, this snippet looks like it could be pasted directly into a component body, but it won't work. Consider wrapping it in an event handler or adding a comment indicating this must be inside an async callback.</comment>
<file context>
@@ -0,0 +1,135 @@
+Team plans work the same way when you call the methods on a team object:
+
+```typescript
+const team = user.useTeam(teamId);
+await team.switchSubscription({
+ fromProductId: "prod_team_pro",
</file context>
| export function DisplayGlobalPermissions() { | ||
| const user = useUser({ or: 'redirect' }); | ||
| const permissions = user.usePermissions(); | ||
| const permissions = user.usePermissions({ recursive: false }); |
There was a problem hiding this comment.
P2: The code example contradicts the section's purpose. "Listing All Project Permissions" should show the default recursive call (which includes inherited permissions), but the example uses { recursive: false } which only returns direct grants. The equivalent team permissions section correctly uses the default. Consider removing { recursive: false } from the primary example and instead mentioning it as an alternative, as done in the team permissions section.
Prompt for AI agents
Check if this issue is valid — if so, understand the root cause and fix it. At docs-mintlify/guides/apps/rbac/overview.mdx, line 309:
<comment>The code example contradicts the section's purpose. "Listing All Project Permissions" should show the default recursive call (which includes inherited permissions), but the example uses `{ recursive: false }` which only returns direct grants. The equivalent team permissions section correctly uses the default. Consider removing `{ recursive: false }` from the primary example and instead mentioning it as an alternative, as done in the team permissions section.</comment>
<file context>
@@ -198,7 +306,7 @@ To get a list of all global permissions a user has, use the `listPermissions` me
export function DisplayGlobalPermissions() {
const user = useUser({ or: 'redirect' });
- const permissions = user.usePermissions();
+ const permissions = user.usePermissions({ recursive: false });
return (
</file context>
| const permissions = user.usePermissions({ recursive: false }); | |
| const permissions = user.usePermissions(); |
|
|
||
| // After the user completes Stripe's card form: | ||
| const paymentMethod = await user.setDefaultPaymentMethodFromSetupIntent( | ||
| setupIntentId |
There was a problem hiding this comment.
P2: Undefined variable setupIntentId in code example — should likely be setupIntent.id based on the variable created on the preceding line. Developers copy-pasting this snippet will get a reference error.
Prompt for AI agents
Check if this issue is valid — if so, understand the root cause and fix it. At docs-mintlify/guides/apps/payments/settings.mdx, line 106:
<comment>Undefined variable `setupIntentId` in code example — should likely be `setupIntent.id` based on the variable created on the preceding line. Developers copy-pasting this snippet will get a reference error.</comment>
<file context>
@@ -0,0 +1,126 @@
+
+// After the user completes Stripe's card form:
+const paymentMethod = await user.setDefaultPaymentMethodFromSetupIntent(
+ setupIntentId
+);
+// paymentMethod contains: id, brand, last4, exp_month, exp_year
</file context>
| throw new Error("Insufficient credits"); | ||
| } | ||
|
|
||
| return { remaining: credits.quantity }; |
There was a problem hiding this comment.
P2: The credits.quantity returned here likely reflects the stale pre-decrease value. The E2E tests re-fetch the item after tryDecreaseQuantity to get the updated balance, suggesting the original object's quantity is not mutated. Consider re-fetching or computing the expected remaining balance.
Prompt for AI agents
Check if this issue is valid — if so, understand the root cause and fix it. At docs-mintlify/guides/apps/payments/products-and-items.mdx, line 240:
<comment>The `credits.quantity` returned here likely reflects the stale pre-decrease value. The E2E tests re-fetch the item after `tryDecreaseQuantity` to get the updated balance, suggesting the original object's `quantity` is not mutated. Consider re-fetching or computing the expected remaining balance.</comment>
<file context>
@@ -0,0 +1,244 @@
+ throw new Error("Insufficient credits");
+ }
+
+ return { remaining: credits.quantity };
+}
+```
</file context>
There was a problem hiding this comment.
Actionable comments posted: 4
Caution
Some comments are outside the diff and can’t be posted inline due to platform limitations.
⚠️ Outside diff range comments (1)
docs-mintlify/guides/apps/emails/overview.mdx (1)
133-142:⚠️ Potential issue | 🟡 Minor | ⚡ Quick winIncomplete type definition for
SendEmailOptions.The type definition is missing several fields that are documented in the "Full options" example above (lines 109-128):
allUsers?: boolean(alternative touserIds)draftId?: string(alternative content source)scheduledAt?: Date(for scheduling emails)📝 Proposed fix to complete the type definition
type SendEmailOptions = { - userIds: string[]; // users to send to + userIds?: string[]; // users to send to + allUsers?: boolean; // or send to all users themeId?: string | null | false; // theme override subject?: string; // subject line notificationCategoryName?: string; // preference category html?: string; // raw HTML body templateId?: string; // template ID + draftId?: string; // draft ID variables?: Record<string, any>; // template variables + scheduledAt?: Date; // schedule delivery };🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the rest with a brief reason, keep changes minimal, and validate. In `@docs-mintlify/guides/apps/emails/overview.mdx` around lines 133 - 142, The SendEmailOptions type is missing documented fields—add the optional properties allUsers?: boolean, draftId?: string, and scheduledAt?: Date to the SendEmailOptions definition so it matches the "Full options" example; update any related usages of SendEmailOptions (e.g., where SendEmailOptions is constructed or validated) to accept and propagate these new fields (preserving existing semantics for userIds, themeId, templateId, html, variables, subject, and notificationCategoryName).
🧹 Nitpick comments (2)
docs-mintlify/guides/apps/rbac/overview.mdx (1)
371-376: ⚡ Quick winAdd null check for team parameter in direct permissions example.
The example at line 375 uses
teamwithout verifying it exists. This should match the pattern from earlier examples that handle the null case.♻️ Proposed fix
```tsx // Includes inherited permissions -const allPermissions = await user.listPermissions(team); +const team = await stackServerApp.getTeam('some-team-id'); +const allPermissions = team ? await user.listPermissions(team) : []; // Direct assignments only -const directPermissions = await user.listPermissions(team, { recursive: false }); +const directPermissions = team ? await user.listPermissions(team, { recursive: false }) : [];</details> <details> <summary>🤖 Prompt for AI Agents</summary>Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.In
@docs-mintlify/guides/apps/rbac/overview.mdxaround lines 371 - 376, The
examples call user.listPermissions with team without null-checks; update the
snippet to fetch the team via stackServerApp.getTeam('some-team-id') and guard
both calls so they only run when team is truthy, returning empty arrays
otherwise (i.e., set allPermissions = team ? await user.listPermissions(team) :
[] and directPermissions = team ? await user.listPermissions(team, { recursive:
false }) : []), referencing user.listPermissions, stackServerApp.getTeam, team,
allPermissions and directPermissions to locate the changes.</details> </blockquote></details> <details> <summary>docs-mintlify/guides/apps/analytics/overview.mdx (1)</summary><blockquote> `73-76`: _💤 Low value_ **Consider varying sentence structure for better flow.** Items 2-4 all begin with "Use" which creates a repetitive pattern. While the parallel structure is clear, varying the sentence starts slightly improves readability. <details> <summary>✨ Suggested rewording for variety</summary> ```diff 1. **Use Tables for quick triage** — pick a table from the sidebar and scan recent rows. Use AI search for one-off "what just happened?" questions. -2. **Use Queries for repeatable analysis** — save important SQL in folders with descriptions, and scope queries with `WHERE` / `LIMIT` so they stay within result and timeout limits. -3. **Use Replays for behavioral debugging** — start from an event pattern in Tables / Queries, then jump to matching session replays to see what users actually did. +2. **Save reusable SQL in Queries** — organize important queries in folders with descriptions, and scope them with `WHERE` / `LIMIT` to stay within result and timeout limits. +3. **Debug behavior with Replays** — start from an event pattern in Tables / Queries, then jump to matching session replays to see what users actually did. 4. **Keep replay privacy defaults on** — leave `maskAllInputs` enabled unless you have an explicit need for unmasked input recording and a data-handling policy to match.🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the rest with a brief reason, keep changes minimal, and validate. In `@docs-mintlify/guides/apps/analytics/overview.mdx` around lines 73 - 76, The three consecutive list entries ("2. Use Queries for repeatable analysis", "3. Use Replays for behavioral debugging", "4. Keep replay privacy defaults on") are repetitive because they all start with "Use"; modify the leading verbs/phrasing to vary sentence openings while preserving meaning and guidance—e.g., change "Use Queries..." to "Run or Save Queries for repeatable analysis", "Use Replays..." to "Open Replays for behavioral debugging", and "Keep replay privacy defaults on" to "Keep replay privacy defaults enabled" or "Leave replay privacy defaults on"; ensure each item still references the same concepts (Queries, Replays, maskAllInputs) and keeps the tips about WHERE/LIMIT, jumping from Tables/Queries to session replays, and leaving maskAllInputs enabled.
🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.
Inline comments:
In `@docs-mintlify/guides/apps/api-keys/overview.mdx`:
- Around line 1008-1032: The snippet performing server-side API key validation
uses requests.post and requests.get without timeouts and parses JSON from
responses (check.json(), user_resp.json()) without verifying status codes;
update the requests.post and requests.get calls to include a reasonable timeout
parameter (e.g., timeout=5) and add status_code checks for both responses before
calling .json() (handle non-200 responses by returning a JsonResponse error),
and ensure any exceptions from requests (e.g., requests.Timeout,
requests.RequestException) are caught and translated into an appropriate
JsonResponse; refer to the requests.post/requests.get calls and the variables
check, api_key_obj, user_resp, and user when making these changes.
In `@docs-mintlify/guides/apps/authentication/fraud-protection.mdx`:
- Line 25: The Turnstile override values are documented with inconsistent
capitalization — once as `ok` / `invalid` / `error` and elsewhere as `OK` /
`Invalid` / `Error`; pick the correct casing that matches the dashboard UI
(either all lowercase or capitalized) and update all occurrences so they match,
e.g., change the instance that reads `ok` / `invalid` / `error` to `OK` /
`Invalid` / `Error` (or vice versa), ensuring every mention of the "Turnstile
override" in this guide uses the same casing.
In `@docs-mintlify/guides/apps/rbac/overview.mdx`:
- Around line 174-177: In DisplayUserPermissions, guard against a null team
before calling user.usePermissions: after obtaining user via useUser and team
via user.useTeam, check if team is null (or falsy) and return or render a
fallback/loading/permission-empty state instead of calling
user.usePermissions(team); ensure any code that depends on permissions only runs
when team is non-null so calls to usePermissions and subsequent rendering are
safe.
In `@docs-mintlify/guides/apps/teams/overview.mdx`:
- Around line 419-423: Remove the duplicate MDX frontmatter block that repeats
the existing title/description/sidebarTitle metadata (the block containing
title: "Teams", description: "Manage teams and team members", sidebarTitle:
"Overview"); keep only the original frontmatter at the top of the file and
delete the second frontmatter block so there is a single metadata block in the
MDX file.
---
Outside diff comments:
In `@docs-mintlify/guides/apps/emails/overview.mdx`:
- Around line 133-142: The SendEmailOptions type is missing documented
fields—add the optional properties allUsers?: boolean, draftId?: string, and
scheduledAt?: Date to the SendEmailOptions definition so it matches the "Full
options" example; update any related usages of SendEmailOptions (e.g., where
SendEmailOptions is constructed or validated) to accept and propagate these new
fields (preserving existing semantics for userIds, themeId, templateId, html,
variables, subject, and notificationCategoryName).
---
Nitpick comments:
In `@docs-mintlify/guides/apps/analytics/overview.mdx`:
- Around line 73-76: The three consecutive list entries ("2. Use Queries for
repeatable analysis", "3. Use Replays for behavioral debugging", "4. Keep replay
privacy defaults on") are repetitive because they all start with "Use"; modify
the leading verbs/phrasing to vary sentence openings while preserving meaning
and guidance—e.g., change "Use Queries..." to "Run or Save Queries for
repeatable analysis", "Use Replays..." to "Open Replays for behavioral
debugging", and "Keep replay privacy defaults on" to "Keep replay privacy
defaults enabled" or "Leave replay privacy defaults on"; ensure each item still
references the same concepts (Queries, Replays, maskAllInputs) and keeps the
tips about WHERE/LIMIT, jumping from Tables/Queries to session replays, and
leaving maskAllInputs enabled.
In `@docs-mintlify/guides/apps/rbac/overview.mdx`:
- Around line 371-376: The examples call user.listPermissions with team without
null-checks; update the snippet to fetch the team via
stackServerApp.getTeam('some-team-id') and guard both calls so they only run
when team is truthy, returning empty arrays otherwise (i.e., set allPermissions
= team ? await user.listPermissions(team) : [] and directPermissions = team ?
await user.listPermissions(team, { recursive: false }) : []), referencing
user.listPermissions, stackServerApp.getTeam, team, allPermissions and
directPermissions to locate the changes.
🪄 Autofix (Beta)
Fix all unresolved CodeRabbit comments on this PR:
- Push a commit to this branch (recommended)
- Create a new PR with the fixes
ℹ️ Review info
⚙️ Run configuration
Configuration used: defaults
Review profile: CHILL
Plan: Pro
Run ID: 34bf6545-ce72-4a95-a91d-5cc3f3604d4a
📒 Files selected for processing (26)
docs-mintlify/docs.jsondocs-mintlify/guides/apps/analytics/overview.mdxdocs-mintlify/guides/apps/analytics/queries.mdxdocs-mintlify/guides/apps/analytics/replays.mdxdocs-mintlify/guides/apps/analytics/tables.mdxdocs-mintlify/guides/apps/api-keys/overview.mdxdocs-mintlify/guides/apps/authentication/fraud-protection.mdxdocs-mintlify/guides/apps/authentication/sign-up-rules.mdxdocs-mintlify/guides/apps/data-vault/overview.mdxdocs-mintlify/guides/apps/emails/drafts.mdxdocs-mintlify/guides/apps/emails/email-settings.mdxdocs-mintlify/guides/apps/emails/overview.mdxdocs-mintlify/guides/apps/emails/sent.mdxdocs-mintlify/guides/apps/emails/templates.mdxdocs-mintlify/guides/apps/fraud-protection/overview.mdxdocs-mintlify/guides/apps/payments/customers.mdxdocs-mintlify/guides/apps/payments/overview.mdxdocs-mintlify/guides/apps/payments/product-lines.mdxdocs-mintlify/guides/apps/payments/products-and-items.mdxdocs-mintlify/guides/apps/payments/settings.mdxdocs-mintlify/guides/apps/payments/transactions.mdxdocs-mintlify/guides/apps/rbac/overview.mdxdocs-mintlify/guides/apps/teams/overview.mdxdocs-mintlify/guides/apps/teams/team-selection.mdxdocs-mintlify/guides/apps/webhooks/overview.mdxdocs-mintlify/snippets/docs-apps-home-grid.jsx
💤 Files with no reviewable changes (1)
- docs-mintlify/guides/apps/fraud-protection/overview.mdx
| check = requests.post( | ||
| 'https://api.stack-auth.com/api/v1/user-api-keys/check', | ||
| headers={ | ||
| 'x-stack-access-type': 'client', | ||
| 'x-stack-access-type': 'server', | ||
| 'x-stack-project-id': stack_project_id, | ||
| 'x-stack-publishable-client-key': stack_publishable_client_key, | ||
| 'x-stack-access-token': access_token, | ||
| 'x-stack-secret-server-key': stack_secret_server_key, | ||
| }, | ||
| json={ | ||
| 'revoked': True, | ||
| } | ||
| json={'api_key': api_key}, | ||
| ) | ||
|
|
||
| if response.status_code != 200: | ||
| raise Exception(f"Failed to revoke API key: {response.text}") | ||
| if check.status_code != 200: | ||
| return JsonResponse({'error': 'Invalid API key'}, status=401) | ||
|
|
||
| return JsonResponse({'message': 'API key revoked successfully'}) | ||
| api_key_obj = check.json() | ||
| # Fetch the owning user | ||
| user_resp = requests.get( | ||
| f'https://api.stack-auth.com/api/v1/users/{api_key_obj["user_id"]}', | ||
| headers={ | ||
| 'x-stack-access-type': 'server', | ||
| 'x-stack-project-id': stack_project_id, | ||
| 'x-stack-secret-server-key': stack_secret_server_key, | ||
| }, | ||
| ) | ||
| user = user_resp.json() | ||
| return JsonResponse({'userId': user['id'], 'displayName': user.get('display_name')}) |
There was a problem hiding this comment.
🧩 Analysis chain
🏁 Script executed:
#!/bin/bash
# Verify Python snippets in this file that call requests without timeout
rg -n "requests\.(get|post|patch)\(" docs-mintlify/guides/apps/api-keys/overview.mdx -A6 -B2Repository: hexclave/stack-auth
Length of output: 12088
🏁 Script executed:
#!/bin/bash
set -euo pipefail
FILE="docs-mintlify/guides/apps/api-keys/overview.mdx"
echo "---- snippet 1000-1120 ----"
sed -n '1000,1120p' "$FILE"
echo "---- snippet 1120-1135 (context) ----"
sed -n '1120,1135p' "$FILE"
echo "---- find other server check blocks nearby (1000-1130) ----"
rg -n "Check the API key via server API" "$FILE" -nRepository: hexclave/stack-auth
Length of output: 5382
Add timeouts and upstream status checks to server-side API key validation snippets
requests.post(...) / requests.get(...) calls in the “Check the API key via server API” examples lack timeout, and user_resp.json() is parsed without checking user_resp.status_code, so upstream failures can hang or produce incorrect payloads.
Suggested patch pattern (apply similarly to all three snippets)
- check = requests.post(
+ check = requests.post(
'https://api.stack-auth.com/api/v1/user-api-keys/check',
headers={ ... },
json={'api_key': api_key},
+ timeout=10,
)
if check.status_code != 200:
return JsonResponse({'error': 'Invalid API key'}, status=401)
api_key_obj = check.json()
user_resp = requests.get(
f'https://api.stack-auth.com/api/v1/users/{api_key_obj["user_id"]}',
headers={ ... },
+ timeout=10,
)
+ if user_resp.status_code != 200:
+ return JsonResponse({'error': 'Failed to fetch API key owner'}, status=502)
user = user_resp.json()📝 Committable suggestion
‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.
| check = requests.post( | |
| 'https://api.stack-auth.com/api/v1/user-api-keys/check', | |
| headers={ | |
| 'x-stack-access-type': 'client', | |
| 'x-stack-access-type': 'server', | |
| 'x-stack-project-id': stack_project_id, | |
| 'x-stack-publishable-client-key': stack_publishable_client_key, | |
| 'x-stack-access-token': access_token, | |
| 'x-stack-secret-server-key': stack_secret_server_key, | |
| }, | |
| json={ | |
| 'revoked': True, | |
| } | |
| json={'api_key': api_key}, | |
| ) | |
| if response.status_code != 200: | |
| raise Exception(f"Failed to revoke API key: {response.text}") | |
| if check.status_code != 200: | |
| return JsonResponse({'error': 'Invalid API key'}, status=401) | |
| return JsonResponse({'message': 'API key revoked successfully'}) | |
| api_key_obj = check.json() | |
| # Fetch the owning user | |
| user_resp = requests.get( | |
| f'https://api.stack-auth.com/api/v1/users/{api_key_obj["user_id"]}', | |
| headers={ | |
| 'x-stack-access-type': 'server', | |
| 'x-stack-project-id': stack_project_id, | |
| 'x-stack-secret-server-key': stack_secret_server_key, | |
| }, | |
| ) | |
| user = user_resp.json() | |
| return JsonResponse({'userId': user['id'], 'displayName': user.get('display_name')}) | |
| check = requests.post( | |
| 'https://api.stack-auth.com/api/v1/user-api-keys/check', | |
| headers={ | |
| 'x-stack-access-type': 'server', | |
| 'x-stack-project-id': stack_project_id, | |
| 'x-stack-secret-server-key': stack_secret_server_key, | |
| }, | |
| json={'api_key': api_key}, | |
| timeout=10, | |
| ) | |
| if check.status_code != 200: | |
| return JsonResponse({'error': 'Invalid API key'}, status=401) | |
| api_key_obj = check.json() | |
| # Fetch the owning user | |
| user_resp = requests.get( | |
| f'https://api.stack-auth.com/api/v1/users/{api_key_obj["user_id"]}', | |
| headers={ | |
| 'x-stack-access-type': 'server', | |
| 'x-stack-project-id': stack_project_id, | |
| 'x-stack-secret-server-key': stack_secret_server_key, | |
| }, | |
| timeout=10, | |
| ) | |
| if user_resp.status_code != 200: | |
| return JsonResponse({'error': 'Failed to fetch API key owner'}, status=502) | |
| user = user_resp.json() | |
| return JsonResponse({'userId': user['id'], 'displayName': user.get('display_name')}) |
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.
In `@docs-mintlify/guides/apps/api-keys/overview.mdx` around lines 1008 - 1032,
The snippet performing server-side API key validation uses requests.post and
requests.get without timeouts and parses JSON from responses (check.json(),
user_resp.json()) without verifying status codes; update the requests.post and
requests.get calls to include a reasonable timeout parameter (e.g., timeout=5)
and add status_code checks for both responses before calling .json() (handle
non-200 responses by returning a JsonResponse error), and ensure any exceptions
from requests (e.g., requests.Timeout, requests.RequestException) are caught and
translated into an appropriate JsonResponse; refer to the
requests.post/requests.get calls and the variables check, api_key_obj,
user_resp, and user when making these changes.
| | `riskScores.bot` | number (0-100) | `equals`, `not_equals`, `greater_than`, `greater_or_equal`, `less_than`, `less_or_equal` | Confidence that the sign-up is automated. Higher = more likely a bot. Stack Auth uses signals like the Cloudflare Turnstile verdict to compute this score. | | ||
| | `riskScores.free_trial_abuse` | number (0-100) | same as `riskScores.bot` | Confidence that the user is attempting to abuse a free-trial / new-account incentive (multi-accounting, disposable infra, etc.). | | ||
|
|
||
| The rule tester additionally exposes a **Turnstile** override (`ok` / `invalid` / `error`) so you can simulate how a given Turnstile verdict affects the resulting bot score. |
There was a problem hiding this comment.
Inconsistent capitalization for Turnstile override values.
Line 25 documents Turnstile override values as lowercase (ok / invalid / error), while Line 67 shows them capitalized (OK / Invalid / Error). These describe the same UI element and should use consistent casing throughout the documentation.
Proposed fix
Choose one capitalization style and apply it consistently. If the dashboard UI uses capitalized values, update Line 25:
-The rule tester additionally exposes a **Turnstile** override (`ok` / `invalid` / `error`) so you can simulate how a given Turnstile verdict affects the resulting bot score.
+The rule tester additionally exposes a **Turnstile** override (`OK` / `Invalid` / `Error`) so you can simulate how a given Turnstile verdict affects the resulting bot score.Or if the UI uses lowercase, update Line 67:
-- **Turnstile** - `Default (real result)` / `OK` / `Invalid` / `Error`. Default uses whatever the live engine would compute.
+- **Turnstile** - `Default (real result)` / `ok` / `invalid` / `error`. Default uses whatever the live engine would compute.Also applies to: 67-67
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.
In `@docs-mintlify/guides/apps/authentication/fraud-protection.mdx` at line 25,
The Turnstile override values are documented with inconsistent capitalization —
once as `ok` / `invalid` / `error` and elsewhere as `OK` / `Invalid` / `Error`;
pick the correct casing that matches the dashboard UI (either all lowercase or
capitalized) and update all occurrences so they match, e.g., change the instance
that reads `ok` / `invalid` / `error` to `OK` / `Invalid` / `Error` (or vice
versa), ensuring every mention of the "Turnstile override" in this guide uses
the same casing.
| export function DisplayUserPermissions() { | ||
| const user = useUser({ or: 'redirect' }); | ||
| const permissions = user.usePermissions(); | ||
| const team = user.useTeam('some-team-id'); | ||
| const permissions = user.usePermissions(team); |
There was a problem hiding this comment.
Add null check for team before listing permissions.
The client example passes team to usePermissions without checking if it's null first. Since user.useTeam() can return null when the user is not a member, this could cause a runtime error.
🛡️ Proposed fix
export function DisplayUserPermissions() {
const user = useUser({ or: 'redirect' });
const team = user.useTeam('some-team-id');
- const permissions = user.usePermissions(team);
+ const permissions = user.usePermissions(team ?? undefined);
return (
<div>
- {permissions.map(permission => (
+ {team && permissions.map(permission => (
<div key={permission.id}>{permission.id}</div>
))}
</div>
);
}🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.
In `@docs-mintlify/guides/apps/rbac/overview.mdx` around lines 174 - 177, In
DisplayUserPermissions, guard against a null team before calling
user.usePermissions: after obtaining user via useUser and team via user.useTeam,
check if team is null (or falsy) and return or render a
fallback/loading/permission-empty state instead of calling
user.usePermissions(team); ensure any code that depends on permissions only runs
when team is non-null so calls to usePermissions and subsequent rendering are
safe.
| --- | ||
| title: "Teams" | ||
| description: "Manage teams and team members" | ||
| sidebarTitle: "Overview" | ||
| --- |
There was a problem hiding this comment.
Remove duplicate frontmatter block.
The frontmatter block at lines 419-423 is a duplicate of lines 1-5. MDX files should only have one frontmatter block at the beginning of the file.
🐛 Proposed fix
Remove lines 419-423 entirely.
----
-title: "Teams"
-description: "Manage teams and team members"
-sidebarTitle: "Overview"
----📝 Committable suggestion
‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.
| --- | |
| title: "Teams" | |
| description: "Manage teams and team members" | |
| sidebarTitle: "Overview" | |
| --- |
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.
In `@docs-mintlify/guides/apps/teams/overview.mdx` around lines 419 - 423, Remove
the duplicate MDX frontmatter block that repeats the existing
title/description/sidebarTitle metadata (the block containing title: "Teams",
description: "Manage teams and team members", sidebarTitle: "Overview"); keep
only the original frontmatter at the top of the file and delete the second
frontmatter block so there is a single metadata block in the MDX file.
Summary
This PR expands the Apps documentation to more completely reflect what users can do in the Stack dashboard, with clearer page structure for the larger apps and more complete dashboard + SDK coverage for the rest.
What Changed
SelectedTeamSwitcherusage and App Router examples.docs.jsonand the apps home grid so the navigation reflects the new app documentation structure.Notes For Reviewers
project_permission.createdandproject_permission.deletedas emitted events, but those currently do not have generated webhook reference pages.Test Plan
Summary by cubic
Reorganized Apps docs with new, task-focused pages across Analytics, Emails, Payments, Teams, RBAC, API Keys, Data Vault, and Webhooks. Moved Fraud Protection under Authentication and updated navigation for clarity.
New Features
SelectedTeamSwitcherusage from@stackframe/stack.Refactors
docs.jsonto group Emails, split Analytics pages, and link Authentication → Fraud Protection; removed legacy Fraud Protection doc./guides/apps/authentication/fraud-protection.Written for commit 2fa6216. Summary will update on new commits. Review in cubic
Summary by CodeRabbit