- name
- docs
- description
- Write, extend, and validate Flexprice documentation pages in Mintlify MDX format. Use this skill whenever the user asks to write a new doc, add a section to existing docs, create a guide, document a feature, or update the Flexprice docs site. Trigger when the user mentions "write a doc", "add docs", "documentation for", "create a guide", "update the docs", "add to docs", "document this feature", "threshold notifications", "alerts doc", or any request to produce or modify an .mdx file in the docs repo. This skill knows the Mintlify MDX component set, the docs.json navigation schema, the repo layout, the editorial voice, validation commands, and the dev server setup.
# Flexprice Docs — Writing and Validation Skill
Write new documentation pages and validate them against the live Mintlify build. Always follow the existing style of the repo — read nearby docs before writing to match tone and component usage.
---
## Repo Layout
```
flexprice-docs/
├── docs/ ← All documentation pages (.mdx)
│ ├── customers/ ← Customer-related docs
│ ├── wallet/ ← Wallet docs
│ ├── product-catalogue/ ← Plans, Features, Coupons
│ ├── subscriptions/ ← Subscription workflows
│ ├── webhook/ ← Webhook reference
│ ├── event-ingestion/ ← Event & metering docs
│ └── ...
├── integrations/ ← Integrations tab: one folder per provider, plus introduction.mdx landing page
├── images/docs/ ← Screenshots referenced from docs
├── images/integrations/logos/ ← Brand SVG icons for the integrations landing page
├── docs.json ← Navigation config (Mintlify v2)
└── .claude/skills/ ← This skills directory (docs-writing/scripts/brand_icon.py builds integration icons)
```
The docs site is at `https://docs.flexprice.io`. The `docs.json` at repo root controls all navigation.
---
## Step-by-Step: Writing a New Doc
### 1. Read Before Writing
Always read at least two nearby docs before writing — pick pages in the same section or covering similar topics. This ensures consistent tone, component choices, and structure.
```bash
# E.g. if writing a wallet doc:
cat docs/wallet/auto-top-up.mdx
cat docs/wallet/low-balance-alert.mdx
```
Also check `docs/webhook/webhooks.mdx` if the doc involves webhooks, and `docs/wallet/low-balance-alert.mdx` for alert-related docs.
### 2. Pick the Right File Location
| Topic | Directory |
|-------|-----------|
| Customer management | `docs/customers/` |
| Wallet features | `docs/wallet/` |
| Plans, Features, Coupons | `docs/product-catalogue/` |
| Subscription workflows | `docs/subscriptions/` |
| Integrations | `integrations/<provider>/` |
| Sending usage events (API, idempotency, volume, backfill) | `docs/core-concepts/usage-events/` |
| Webhooks, event debugging and monitoring | `docs/webhook/` or `docs/event-ingestion/` |
| Core Concepts pages (one guided page per concept) | `docs/core-concepts/` |
| Alerts & notifications | `docs/customers/` (customer-scoped) or nearest feature section |
### 3. Frontmatter
Every `.mdx` file starts with:
```mdx
---
title: "Page Title"
description: "One sentence describing what this page covers."
---
```
- `title`: Short noun phrase, title case
- `description`: Shown in search results and page meta — one sentence, no period
### 4. Opening Paragraph
Start with a plain prose paragraph (no heading) that explains what the feature is and why it matters. Keep it to 2–4 sentences. Do not repeat the `description` verbatim.
### 5. Benefits List (Optional)
For feature docs, a bold-bullet benefits list after the opening paragraph is conventional:
```mdx
**Benefits:**
- **Proactive management** — Description of why this matters
- **Granular control** — Description
- **Flexible conditions** — Description
```
### 6. Section Structure
Use `##` for top-level sections and `###` for subsections. Never use `#` (reserved for the page title) or go deeper than `###` in most docs.
---
## Mintlify MDX Components
### Callouts
```mdx
<Note>
Informational note — use for helpful context or clarifications.
</Note>
<Info>
Similar to Note but for more prominent informational content.
</Info>
<Warning>
Use for gotchas, required conditions, or things that will break if ignored.
</Warning>
<Check>
Use for best practices, recommendations, or "do this" guidance.
</Check>
```
### Steps (for configuration workflows)
```mdx
<Steps>
<Step title="Navigate to the feature">
Instructions here.
</Step>
<Step title="Configure settings">
More instructions.
</Step>
</Steps>
```
### Code Blocks
Single language:
```mdx
```json
{ "key": "value" }
```
```
Multiple languages side by side:
```mdx
<CodeGroup>
```bash cURL
curl ...
```
```javascript JavaScript
fetch(...)
```
```python Python
import requests
```
</CodeGroup>
```
### Tables
```mdx
| Column | Column |
|--------|--------|
| Value | Value |
```
Pipe-align all columns. Use bold (`**text**`) in first column when listing settings or fields.
### Cards and Links
```mdx
<Card icon="book-open" horizontal={true} href="/docs/..." title="Related Doc Title" />
```
Use `horizontal={true}` for inline card links at the bottom of a page.
### Frames (screenshots)
```mdx
<Frame>

</Frame>
```
Only include `<Frame>` blocks when actual screenshots exist in the repo at the referenced path. **Do not include placeholder image references** — broken image links will fail the `mint broken-links` check.
---
## Webhook Payload Sections
When documenting a feature that emits webhooks, follow this structure:
```mdx
### Webhook Payload
**Event type:** `event.name.here`
```json
{
"event_type": "event.name.here",
"alert_type": "descriptor",
"alert_status": "warning",
...
}
```
### Webhook Fields
| Field | Description |
|-------|-------------|
| `field_name` | What it contains |
| `nested.field` | Description |
```
Model new webhook events on existing ones — see `docs/wallet/low-balance-alert.mdx` (event: `wallet.alert`). For usage-based alerts, follow the `customer.usage.alert` / `feature.usage.alert` pattern established in `docs/customers/threshold-notifications.mdx`.
---
## Navigation: docs.json
After writing a new file, **always add it to `docs.json`**.
The navigation lives in `navigation.tabs[0].groups` (the Documentation tab). Each top-level group is a section heading, in this order: Start Here, Usage Metering, Pricing and Packaging, Entitlements, Customers, Subscriptions, Credits and Wallets, Enterprise Billing, Invoicing and Taxes, Payments and Checkout, Reporting and Data, Self-hosting, Platform and Security. Start Here holds the Core Concepts group (landing page `docs/core-concepts/overview` as its root): one opinionated guidance page per concept, in the order the data flows (Usage Events, Features, Plans and Prices, Customers, Subscriptions, Invoices), each linking to the detail pages in the topic sections. Usage Events is itself a nested group (root `docs/core-concepts/send-usage-events`) that holds every page about sending events, in `docs/core-concepts/usage-events/`. Inside a section, topics are collapsible sub-groups (Usage Metering holds Features, Flexprice Collector, Debug and Monitor, AI Cost Tracking). Billing recipes and pricing teardowns belong in the Cookbooks tab, not in Documentation. Structure:
```json
{
"group": "Section Name",
"pages": [
"docs/path/to/page",
{
"group": "Sub-group Name",
"pages": [
"docs/path/to/nested-page"
]
}
]
}
```
**Rules:**
- Flat page paths are relative to repo root, no `.mdx` extension
- No `icon` on any header tab or any group, top-level or nested. The only navigation icons are on the global anchors (Support, Community, Website)
- A sub-group holds 3 to 6 pages. Never leave more than 6 pages in one flat list: give a topic with several pages its own nested sub-group (Plans and Packaging holds Plans, Addons, Groups). Aggregation Types, one page per type, is the only exception
- Never create a sub-group for a single page; a lone page sits directly in its section
- Always add new pages immediately after the most relevant existing page in the same sub-group
- Never add a new top-level section without asking first
---
## Integrations Tab
The header tab named **Integrations** follows the layout Lago uses for its integrations docs. Keep this structure when adding or moving an integration.
### Sidebar structure
The tab has one top-level group, `Integrations`, and everything sits inside it:
```
Integrations <- single top-level group, no icon
integrations/introduction <- landing page, always first
Payments <- category sub-group, no icon
Stripe <- provider sub-group, no icon
integrations/stripe/connection-setup
integrations/stripe/...
Razorpay, Paddle, Nomod, Moyasar, Whop, Chargebee
Accounting
QuickBooks, Zoho Books, Tabs
Marketplaces
integrations/marketplace-integration/overview
AWS, GCP, Azure
```
**Rules:**
- A provider is a sub-group named after the product, inside exactly one category sub-group. Never add a provider as a top-level group.
- The first page in every provider group is `connection-setup`. Feature pages (`payment-links`, `customer-sync`, `invoice-sync`, `integration-workflow`) follow in workflow order.
- Categories today are Payments, Accounting, and Marketplaces. A provider that collects payment for invoices belongs in Payments even if it also syncs catalog or customer data (Chargebee is the example). Add a new category only when a provider fits none of them, and add it to the landing page in the same change.
- Page paths stay under `integrations/<provider>/`. Moving a page between categories changes only `docs.json`, never the file path, so no redirects are needed.
### Landing page: `integrations/introduction.mdx`
Every provider in the sidebar has one card on the landing page, in a `## <Category> integrations` section that mirrors the sidebar categories. A new provider is not done until its card exists.
Card template (one line per card, the icon is a file path):
```mdx
<Card title="Provider" icon="/images/integrations/logos/provider.svg" href="/integrations/provider/connection-setup">
One sentence naming what the connection syncs or collects.
</Card>
```
**Icon rules:**
- Icons are brand SVG files stored in `images/integrations/logos/<slug>.svg` and referenced by path in the `icon` prop. Never use Font Awesome names, `<img>` tags, or inline `<svg>` JSX on this page. Use the vendor's real mark (vendor site, press kit, or Simple Icons). Do not draw or approximate a logo.
- File format: a 32x32 frame, `<rect rx="8">`, with the mark scaled to 16 to 20 px and centred. The frame is light grey `#F3F4F6` with the coloured mark, unless the vendor's own icon is a white mark on a brand colour (Stripe, QuickBooks, Paddle), in which case use that colour as the frame.
- Generate the file with the helper instead of hand-editing: `python3 .claude/skills/docs-writing/scripts/brand_icon.py logo.svg <slug> -o images/integrations/logos/<slug>.svg [--bg #HEX] [--size 18] [--fill #HEX]`. It strips XML headers, style blocks, and class attributes, prefixes ids with the slug, frames the mark, and refuses to write anything malformed. Run a large source through `npx --yes svgo -p 1 --multipass` first if it is over about 20 KB.
- Slugs are lowercase with hyphens and match the card title: `zoho-books`, `aws-marketplace`.
- Card text follows the editorial voice: present tense, no marketing adjectives, one sentence.
### Page frontmatter
Integration pages use `title` and `description`. The marketplace pages (`integrations/marketplace-integration/**`) also carry `tag: 'Beta'`, which renders as a badge next to the page name in the sidebar; keep it on every marketplace page, including new ones. Do not add a `tag` to other integration pages unless product explicitly asks for a badge.
---
## Validation Commands
Run these **before opening a PR**. Both use Node 22 (mintlify does not support Node 25+).
### Check for broken links
```bash
PATH="/opt/homebrew/opt/node@22/bin:$PATH" \
/opt/homebrew/opt/node@22/bin/node \
/opt/homebrew/lib/node_modules/mint/index.js \
broken-links
```
- **Pass**: no broken links in your new file — proceed to PR
- **Fail**: fix every broken link reported in your file; pre-existing broken links in other files are not your responsibility
- The most common cause: referencing a screenshot path in `<Frame>` that doesn't exist in `images/`
### Validate build structure
```bash
PATH="/opt/homebrew/opt/node@22/bin:$PATH" \
/opt/homebrew/opt/node@22/bin/node \
/opt/homebrew/lib/node_modules/mint/index.js \
validate
```
- Confirms `docs.json` is valid, all referenced pages exist, and no structural errors
- Pre-existing warning: `Invalid import path react in /components/Callout.tsx` — this is a known upstream issue, ignore it
### Dev server (visual check)
```bash
PATH="/opt/homebrew/opt/node@22/bin:$PATH" \
/opt/homebrew/opt/node@22/bin/node \
/opt/homebrew/lib/node_modules/mint/index.js \
dev --port 3333
```
The `.claude/launch.json` in this repo is configured to use this exact path. Use `preview_start` with the `"docs"` configuration.
**Node version note:** The system has Node 25 as default (`/opt/homebrew/bin/node`), which is unsupported by mintlify. Always prefix with `PATH="/opt/homebrew/opt/node@22/bin:$PATH"` or use the absolute node@22 binary path.
---
## Editorial Voice
| Do | Don't |
|----|-------|
| "Wallet balance alerts fire when…" | "We've added exciting new alerts that…" |
| "Configure thresholds per wallet" | "Powerful per-wallet configuration" |
| "Set `alert_enabled: true` to activate" | "Simply toggle the switch to enable" |
| Present tense: "Alerts trigger on…" | Future: "Alerts will trigger on…" |
| Second-person: "You can configure…" | First-person: "We allow you to…" |
- **No em dashes**: never use `—` in docs content. Split the sentence, or use a comma, colon, or parentheses instead. Applies to prose, callouts, tables, and bullet lists.
- **No marketing adjectives**: skip "powerful", "flexible", "seamless", "robust", "easy"
- **Name the mechanism**: say what the API field or UI element is called
- **One idea per sentence**: split compound sentences
- **No trailing summaries**: don't end with "In summary, …" or "By using X, you can…"
---
## Checklist Before Opening a PR
- [ ] File is in the right directory (`docs/<section>/`)
- [ ] Frontmatter has `title` and `description`
- [ ] Page is added to `docs.json` in the correct group
- [ ] No em dashes: `grep -n "—" docs/path/to/page.mdx` returns nothing
Auf GitHub ansehen