Cursor Rules for PageGun
Add PageGun to your Cursor IDE with rule files. Cursor's AI gets full context on the PageGun API — create pages, manage docs, configure navigation, and publish without looking anything up.
Quick Setup
- Create
.cursor/rules/in your project root (if it doesn't exist) - Copy the rule files below into that folder
- Set your API key:
export PAGEGUN_API_KEY="pgk_live_your_key_here"Rule Files
We provide three rule files — use the ones you need:
| File | Purpose | When to Use |
|---|---|---|
pagegun.mdc | Core API — projects, pages, media, subroutes, navigation | Always |
pagegun-docs.mdc | Docs pages — markdown, cards, callouts, steps, code tabs | When managing documentation sites |
pagegun-blog.mdc | Blog/articles — create, publish, manage blog posts | When managing blog content |
pagegun.mdc — Core API
Covers all endpoints: projects, pages, docs, subroutes, navigation, media, settings.
Save as .cursor/rules/pagegun.mdc:
---
description: Manage PageGun sites — create pages, manage docs & navigation, upload images, publish. Use when working with PageGun API or managing web content.
globs:
alwaysApply: false
---
# PageGun API Integration
You can manage PageGun sites via the REST API. Use `curl` or `fetch` to interact with pages, docs, media, subroutes, and navigation.
## Setup
API key should be set as environment variable:
```bash
export PAGEGUN_API_KEY="pgk_live_your_key_here"
```
## Base URL
```
https://api.pagegun.com
```
All requests require `Authorization: Bearer $PAGEGUN_API_KEY` header.
All endpoints require `?project_id=xxx` query parameter.
## Endpoints
### Projects
| Method | Path | Description |
|--------|------|-------------|
| GET | /projects | List all projects |
| GET | /projects/:id | Get a project |
| PUT | /projects/:id | Update a project |
### Pages (Landing Pages, Articles)
| Method | Path | Description |
|--------|------|-------------|
| GET | /pages?project_id=xxx | List pages |
| POST | /pages | Create a page |
| GET | /pages/:id | Get a page |
| PUT | /pages/:id | Update a page |
| POST | /pages/:id/publish | Publish a page |
| POST | /pages/:id/unpublish | Unpublish a page |
### Docs
| Method | Path | Description |
|--------|------|-------------|
| GET | /docs?project_id=xxx | List docs |
| POST | /docs | Create a doc page |
| GET | /docs/:id | Get a doc (includes nav_context) |
| PUT | /docs/:id | Update a doc |
> **Important:** Create/update docs with `/docs`, but publish with `/pages/:id/publish`.
### Subroutes
| Method | Path | Description |
|--------|------|-------------|
| POST | /subroutes?project_id=xxx | Create a subroute |
| GET | /subroutes?project_id=xxx | List subroutes |
| GET | /subroutes/:slug?project_id=xxx | Get a subroute |
| PUT | /subroutes/:slug?project_id=xxx | Update subroute (nav change re-publishes sidebar) |
| DELETE | /subroutes/:slug?project_id=xxx | Delete a subroute |
| GET | /subroutes/:slug/pages?project_id=xxx | List pages in subroute |
### Media
| Method | Path | Description |
|--------|------|-------------|
| POST | /media | Upload media (form-data) |
| POST | /media | Upload from URL (JSON) |
| DELETE | /media/:id | Delete media |
### Settings
| Method | Path | Description |
|--------|------|-------------|
| GET | /projects/:id/settings | Get project settings |
| PUT | /projects/:id/settings | Update settings |
## Which Endpoint for Which Page Type?
| Type | Create | Update | Publish |
|------|--------|--------|---------|
| Landing page | `POST /pages` | `PUT /pages/:id` | `POST /pages/:id/publish` |
| Article/Blog | `POST /pages` | `PUT /pages/:id` | `POST /pages/:id/publish` |
| **Docs** | **`POST /docs`** | **`PUT /docs/:id`** | `POST /pages/:id/publish` |
| Item | `POST /pages` | `PUT /pages/:id` | `POST /pages/:id/publish` |
> **Best practice:** Always use `/docs` for documentation pages. It auto-sets `type: "docs"` and `subroute: "docs"`, validates markdown, and returns `nav_context`.
## Creating a Docs Page
```bash
curl -X POST "$BASE/docs?project_id=$PID" \
-H "Authorization: Bearer $PAGEGUN_API_KEY" \
-H "Content-Type: application/json" \
-d '{
"title": "Authentication",
"slug": "api/authentication",
"markdown_content": "# Authentication\n\nOur API uses Bearer tokens..."
}'
```
Only 3 required fields: `title`, `markdown_content`, `project_id`.
Slugs support nesting with `/` — e.g. `api/authentication`, `guides/webhooks`, `agents/best-practices`.
## Creating a Landing Page
```bash
curl -X POST "$BASE/pages" \
-H "Authorization: Bearer $PAGEGUN_API_KEY" \
-H "Content-Type: application/json" \
-d '{
"page_name": "My Page",
"slug": "my-page",
"subroute": "page",
"type": "page",
"project_id": "YOUR_PROJECT_ID",
"config": {"sections": []}
}'
```
## Managing Navigation (Subroutes)
Navigation controls the docs sidebar. Set it on a subroute — three modes available:
### Create subroute with navigation
```bash
curl -X POST "$BASE/subroutes?project_id=$PID" \
-H "Authorization: Bearer $PAGEGUN_API_KEY" \
-H "Content-Type: application/json" \
-d '{
"slug": "docs",
"name": "Documentation",
"navigation": {
"groups": [
{"group": "Getting Started", "pages": ["overview", "quickstart", "installation"]},
{"group": "API Reference", "pages": [
"api/overview",
{"group": "Endpoints", "pages": ["api/pages", "api/projects", "api/media"]}
]}
]
}
}'
```
### Navigation modes
**Groups** — Simple sidebar with collapsible groups:
```json
{"groups": [{"group": "Title", "pages": ["slug1", "slug2"]}]}
```
**Tabs** — Horizontal tab bar at top (Stripe Docs style):
```json
{"tabs": [{"tab": "Docs", "icon": "book", "groups": [...]}, {"tab": "API", "icon": "code", "groups": [...]}]}
```
**Anchors** — Sidebar top icons (Resend style):
```json
{"anchors": [{"anchor": "Docs", "icon": "book", "groups": [...]}, {"anchor": "Discord", "icon": "chat", "href": "https://..."}]}
```
### Update navigation
```bash
curl -X PUT "$BASE/subroutes/docs?project_id=$PID" \
-H "Authorization: Bearer $PAGEGUN_API_KEY" \
-H "Content-Type: application/json" \
-d '{"navigation": {"groups": [...]}}'
```
Updating navigation automatically re-publishes the sidebar to CDN.
### Group options
| Field | Type | Description |
|-------|------|-------------|
| `group` | string | Group title in sidebar |
| `icon` | string | Icon name (optional) |
| `root` | string | Page slug when clicking group title |
| `expanded` | boolean | Default expanded state |
| `pages` | array | Page slugs or nested group objects |
### Nesting
Pages array can mix slugs and sub-groups:
```json
{"group": "API", "pages": ["overview", {"group": "Pages", "pages": ["create", "get", "list"]}]}
```
### Page ordering
Array order = sidebar order. Reorder by rearranging the `pages` array.
### Unlisted pages
Pages not in the navigation tree are still accessible by URL — just hidden from the sidebar.
## Complete Workflow: Build a Docs Site
```bash
# 1. Create pages
ID1=$(curl -s -X POST "$BASE/docs?project_id=$PID" -H "Authorization: Bearer $KEY" \
-H "Content-Type: application/json" \
-d '{"title":"Overview","slug":"overview","markdown_content":"# Overview\n..."}' | jq -r .id)
ID2=$(curl -s -X POST "$BASE/docs?project_id=$PID" -H "Authorization: Bearer $KEY" \
-H "Content-Type: application/json" \
-d '{"title":"Quick Start","slug":"quickstart","markdown_content":"# Quick Start\n..."}' | jq -r .id)
# 2. Create subroute with navigation
curl -s -X POST "$BASE/subroutes?project_id=$PID" -H "Authorization: Bearer $KEY" \
-H "Content-Type: application/json" \
-d '{"slug":"docs","name":"Documentation","navigation":{"groups":[{"group":"Docs","pages":["overview","quickstart"]}]}}'
# 3. Publish pages
curl -s -X POST "$BASE/pages/$ID1/publish?project_id=$PID" -H "Authorization: Bearer $KEY"
curl -s -X POST "$BASE/pages/$ID2/publish?project_id=$PID" -H "Authorization: Bearer $KEY"
```
## Uploading Images
### From URL
```bash
curl -X POST "$BASE/media" \
-H "Authorization: Bearer $PAGEGUN_API_KEY" \
-H "Content-Type: application/json" \
-d '{"url": "https://example.com/image.png", "project_id": "xxx", "alt_text": "Screenshot"}'
```
### From file
```bash
curl -X POST "$BASE/media" \
-H "Authorization: Bearer $PAGEGUN_API_KEY" \
-F "file=@./screenshot.png" \
-F "project_id=xxx" \
-F "alt_text=Screenshot"
```
## Error Format
```json
{"statusCode": 422, "name": "validation_error", "message": "title must be a non-empty string"}
```
Common codes: 200 (OK), 201 (Created), 400 (Bad request), 401 (Unauthorized), 404 (Not found), 422 (Validation), 429 (Rate limited)
Rate limit: 100 requests per minute per API key.
## ⚠️ Safety: Read Before Write
**This API operates directly on production. There is no undo.**
1. Always `GET` first to see current content before updating
2. Show the user what you plan to change and get confirmation
3. After updating, verify before publishing
4. Never blindly overwrite
## Important Notes
- **Deletion is NOT allowed via API key** — use the dashboard
- After updating content, **always re-publish** to push changes to CDN
- Docs: create/update with `/docs`, publish with `/pages/:id/publish`
- Navigation update on subroute automatically re-publishes sidebarWhat You Can Ask Cursor (Core)
- "List all my PageGun projects"
- "Create a new docs page about webhooks"
- "Set up navigation for my docs site"
- "Add a new group to the sidebar"
- "Upload this image and use it in my page"
- "Reorder the sidebar navigation"
pagegun-docs.mdc — Documentation Pages
Covers docs-specific features: cards, callouts, steps, code tabs, nested slugs, and image handling in markdown.
Save as .cursor/rules/pagegun-docs.mdc:
---
description: Write and manage PageGun documentation pages — create docs with cards, callouts, steps, code tabs, and images. Use when working with docs-type pages on PageGun.
globs:
alwaysApply: false
---
# PageGun Docs Pages
This rule covers **docs-type pages** on PageGun — documentation sites with sidebar navigation, rich markdown, and interactive components.
## Creating Docs
Use the **Docs API** (not Pages API) for documentation:
```bash
curl -X POST "https://api.pagegun.com/docs?project_id=YOUR_PROJECT_ID" \
-H "Authorization: Bearer $PAGEGUN_API_KEY" \
-H "Content-Type: application/json" \
-d '{
"title": "Authentication",
"slug": "api/authentication",
"markdown_content": "# Authentication\n\nOur API uses Bearer tokens..."
}'
```
**Required fields:** `title`, `markdown_content`, `project_id`
**Optional fields:** `slug`, `description`, `og_image_url`, `locale`
The Docs API automatically sets `type: "docs"` and `subroute: "docs"`.
### Nested slugs
Slugs support `/` for hierarchy — use this to organize content:
```
overview → /docs/overview
quickstart → /docs/quickstart
api/authentication → /docs/api/authentication
api/pages/create → /docs/api/pages/create
guides/webhooks/setup → /docs/guides/webhooks/setup
agents/best-practices → /docs/agents/best-practices
```
No depth limit. Slug structure is independent of navigation — a page at `agents/deep/nested/page` can appear in any nav group.
### Update a doc
```bash
curl -X PUT "https://api.pagegun.com/docs/PAGE_ID?project_id=YOUR_PROJECT_ID" \
-H "Authorization: Bearer $PAGEGUN_API_KEY" \
-H "Content-Type: application/json" \
-d '{
"title": "Updated Title",
"markdown_content": "# Updated content..."
}'
```
### Publish a doc
```bash
curl -X POST "https://api.pagegun.com/pages/PAGE_ID/publish?project_id=YOUR_PROJECT_ID" \
-H "Authorization: Bearer $PAGEGUN_API_KEY"
```
> Note: Publish uses `/pages/:id/publish`, not `/docs/:id/publish`.
### Get a doc (with nav context)
```bash
curl "https://api.pagegun.com/docs/PAGE_ID?project_id=YOUR_PROJECT_ID" \
-H "Authorization: Bearer $PAGEGUN_API_KEY"
```
Returns the doc plus `nav_context` — a list of all other docs in the project. Useful for building navigation or checking what pages exist.
## Managing Navigation
After creating docs pages, set up the sidebar via subroutes:
```bash
# Create or update navigation
curl -X PUT "https://api.pagegun.com/subroutes/docs?project_id=YOUR_PROJECT_ID" \
-H "Authorization: Bearer $PAGEGUN_API_KEY" \
-H "Content-Type: application/json" \
-d '{
"navigation": {
"groups": [
{"group": "Getting Started", "pages": ["overview", "quickstart"]},
{"group": "API Reference", "pages": [
"api/overview",
{"group": "Pages", "pages": ["api/pages/create", "api/pages/get"]},
{"group": "Projects", "pages": ["api/projects/get", "api/projects/list"]}
]},
{"group": "Guides", "pages": ["guides/webhooks", "guides/custom-domains"]}
]
}
}'
```
Pages appear in sidebar in array order. Titles are resolved automatically from published pages.
## Markdown Components
Docs pages support standard markdown plus these special directives:
### Cards
Display navigation cards in a 2-column grid:
```markdown
:::cards
- title: Quick Start
href: /docs/quick-start
description: Get up and running in 5 minutes
icon: rocket
- title: API Reference
href: /docs/api
description: Complete endpoint documentation
icon: code
:::
```
**Icons:** `rocket`, `code`, `book`, `zap`, `shield`, `globe`, `settings`, `mail`, `file-text`, `database`, `key`, `webhook`, `layout`, `palette`, `search`, `terminal`, `server`, `users`, `credit-card`, `bar-chart`
### Callouts
```markdown
:::callout{type="info"}
This is an informational note.
:::
:::callout{type="warning"}
Be careful — this cannot be undone.
:::
:::callout{type="tip"}
Use project-scoped API keys for better security.
:::
```
Types: `info`, `warning`, `tip`
### Steps
````markdown
:::steps
### Create an API Key
Go to Settings → API Keys and click "Create".
### Set Your API Key
```bash
export PAGEGUN_API_KEY="pgk_live_your_key_here"
```
### Make Your First Request
```bash
curl https://api.pagegun.com/projects \
-H "Authorization: Bearer $PAGEGUN_API_KEY"
```
:::
````
### Code Tabs
````markdown
:::code-tabs
```bash
curl "https://api.pagegun.com/pages" \
-H "Authorization: Bearer $PAGEGUN_API_KEY"
```
```javascript
const res = await fetch('https://api.pagegun.com/pages', {
headers: { 'Authorization': `Bearer ${API_KEY}` },
});
```
```python
import requests
res = requests.get(
'https://api.pagegun.com/pages',
headers={'Authorization': f'Bearer {API_KEY}'},
)
```
:::
````
## Images in Docs
```bash
# Upload
curl -X POST "https://api.pagegun.com/media" \
-H "Authorization: Bearer $PAGEGUN_API_KEY" \
-F "file=@./screenshot.png" \
-F "project_id=YOUR_PROJECT_ID" \
-F "alt_text=Dashboard screenshot"
# Use in markdown

```
## Best Practices
1. **Use `/docs` API** — not `/pages` — for all documentation pages
2. **Organize with nested slugs** — `api/pages/create` not `api-pages-create`
3. **Set navigation via subroutes** — don't rely on auto-generated nav
4. **Publish after every change** — content doesn't go live until published
5. **Set `description`** — used for SEO meta tags and social cards
6. **Use directives** — cards, callouts, steps make docs more scannable
7. **Read before write** — always GET current content before updating
## ⚠️ Safety: Read Before Write
**This API operates directly on production. There is no undo.**
1. Always `GET /docs/:id` first to see current content
2. Show the user what you plan to change
3. After updating, verify before publishingpagegun-blog.mdc — Blog / Articles
Covers blog-specific workflows: creating articles with markdown, SEO fields, categories, publishing, and reading from CDN.
Save as .cursor/rules/pagegun-blog.mdc:
---
description: Manage blog articles on PageGun — create, update, publish, and read blog posts via API and CDN. Use when working with blog content, articles, or news pages.
globs:
alwaysApply: false
---
# PageGun Blog / Articles
This rule covers **article-type pages** on PageGun — blog posts with markdown content, SEO metadata, and CDN delivery.
## Article Fields
| Field | Required | Description |
|-------|----------|-------------|
| `title` | Yes | Article title |
| `slug` | Yes | URL path segment (lowercase, hyphens, 3-100 chars) |
| `subroute` | Yes | URL prefix, e.g. `"blog"` → `/blog/slug` |
| `type` | Yes | Must be `"article"` |
| `project_id` | Yes | Your project ID |
| `markdown_content` | Yes | Full article body in Markdown |
| `description` | No | SEO meta description (155 chars recommended) |
| `og_image_url` | No | Social sharing image (1200×630px recommended) |
| `categories` | No | Array of category strings, e.g. `["Tech", "Tutorial"]` |
| `og_image_url` | No | Social sharing / featured image (1200×630px). Upload via `POST /media` first |
## Create a Blog Post
```bash
curl -X POST "https://api.pagegun.com/pages" \
-H "Authorization: Bearer $PAGEGUN_API_KEY" \
-H "Content-Type: application/json" \
-d '{
"title": "How We Built Our AI Pipeline",
"slug": "how-we-built-our-ai-pipeline",
"subroute": "blog",
"type": "article",
"project_id": "YOUR_PROJECT_ID",
"description": "A behind-the-scenes look at building our AI pipeline with modern tooling.",
"og_image_url": "https://cdn.example.com/blog/ai-pipeline-og.jpg",
"markdown_content": "# How We Built Our AI Pipeline\n\nIn this post, we share our journey...\n\n## Architecture\n\nWe chose a modular approach...\n\n## Key Takeaways\n\n- Start simple\n- Iterate fast\n- Measure everything",
"config": {}
}'Publish
curl -X POST "https://api.pagegun.com/pages/PAGE_ID/publish" \
-H "Authorization: Bearer $PAGEGUN_API_KEY"After publishing, the article is available on CDN (where {subroute} matches the value you set, e.g. blog):
- Article:
https://content.pagegun.com/{project_id}/{subroute}/{slug}.enc - Nav index:
https://content.pagegun.com/{project_id}/nav.enc
Update a Blog Post
# 1. Get current content
curl -s "https://api.pagegun.com/pages/PAGE_ID" \
-H "Authorization: Bearer $PAGEGUN_API_KEY"
# 2. Update
curl -X PUT "https://api.pagegun.com/pages/PAGE_ID" \
-H "Authorization: Bearer $PAGEGUN_API_KEY" \
-H "Content-Type: application/json" \
-d '{
"title": "Updated Title",
"description": "Updated description for SEO.",
"markdown_content": "# Updated Title\n\nNew content here..."
}'
# 3. Re-publish
curl -X POST "https://api.pagegun.com/pages/PAGE_ID/publish" \
-H "Authorization: Bearer $PAGEGUN_API_KEY"Reading from CDN (Data Mode)
Blog content is encrypted on CDN. Decrypt server-side with your Content Key.
Fetch article index
const res = await fetch(
`https://content.pagegun.com/${PROJECT_ID}/nav.enc`,
{ next: { revalidate: 60 } }
);
const encrypted = await res.text();
const nav = JSON.parse(decrypt(encrypted));
const blogPosts = nav.items
.filter(item => item.subroute === 'blog') // adjust to your subroute
.sort((a, b) => new Date(b.published_at) - new Date(a.published_at));Fetch single article
const res = await fetch(
`https://content.pagegun.com/${PROJECT_ID}/${SUBROUTE}/${slug}.enc`,
{ next: { revalidate: 60 } }
);
const encrypted = await res.text();
const article = JSON.parse(decrypt(encrypted));
// article.title, article.markdown_content, article.description, etc.Decryption (Node.js)
import crypto from 'crypto';
function decrypt(encrypted) {
const [ivHex, authTagHex, ciphertext] = encrypted.split(':');
const key = Buffer.from(process.env.PAGEGUN_CONTENT_KEY, 'hex');
const decipher = crypto.createDecipheriv(
'aes-256-gcm', key, Buffer.from(ivHex, 'hex')
);
decipher.setAuthTag(Buffer.from(authTagHex, 'hex'));
let result = decipher.update(ciphertext, 'hex', 'utf8');
result += decipher.final('utf8');
return result;
}⚠️ Never expose your Content Key in client-side code. Always decrypt server-side.
Upload & Use Images
Upload an image first, then reference it in your article or as the OG image:
# Upload image
curl -X POST "https://api.pagegun.com/media" \
-H "Authorization: Bearer $PAGEGUN_API_KEY" \
-F "file=@./cover.jpg" \
-F "project_id=YOUR_PROJECT_ID" \
-F "alt_text=Blog post cover image"
# Response includes the hosted URL:
# { "url": "https://fs.pagegun.com/p/PROJECT_ID/media/abc123.webp", ... }Use the returned URL:
- As featured/OG image: set
og_image_urlwhen creating or updating the page - In markdown content:

# Update article with image
curl -X PUT "https://api.pagegun.com/pages/PAGE_ID" \
-H "Authorization: Bearer $PAGEGUN_API_KEY" \
-H "Content-Type: application/json" \
-d '{
"og_image_url": "https://fs.pagegun.com/p/PROJECT_ID/media/abc123.webp"
}'Author Attribution
📝 The
authorfield is coming soon. For now, if you need author info, include it in your markdown content:
# My Blog Post
*By Jane Smith · March 5, 2026*
Article content here...Need structured author support (name, avatar, bio)? Contact the developer.
Supported Markdown
- Headings (h1–h6)
- Bold, italic, strikethrough
- Ordered and unordered lists
- Links and images
- Code blocks with syntax highlighting
- Tables
- Blockquotes
SEO Best Practices
- Slug — use descriptive, keyword-rich slugs (
how-to-build-ai-agents) - Description — under 155 characters, include target keyword
- OG Image — 1200×630px for social sharing
- Headings — proper hierarchy (H1 → H2 → H3)
- Categories — consistent naming for filtering
What You Can Ask Cursor
- "Create a blog post about our new feature launch"
- "Update the SEO description on our latest article"
- "List all published blog posts"
- "Add categories to our existing articles"
- "Upload an image and use it as the OG image for a blog post"
## Getting Your API Key
## Getting Your API Key
1. Go to your [PageGun Dashboard](https://www.pagegun.com/dashboard)
2. Select your project
3. Go to **Settings** → **API Keys**
4. Click **Create API Key**
5. Copy and save your key — it won't be shown again
## Tips
- Explore the [API Reference](/docs/api-reference) for full endpoint details
- Check [Managing Navigation](/docs/guides/navigation) for advanced nav setups
- Use [Data Mode](/docs/api-reference/data-mode) for encrypted CDN delivery
- Set up [Webhooks](/docs/guides/webhooks) for publish/update notifications
## More Integrations
We also have an [Official PageGun Skill](/docs/agents/skill) for AI agents (OpenClaw, Claude Code, etc.) and a [TypeScript SDK](/docs/sdks/typescript) for programmatic access.