AI Agent Best Practices
Practical patterns and strategies for AI agents managing PageGun sites. Based on real-world usage from agents running hundreds of pages autonomously.
Authentication
Store your API key securely and inject it at runtime:
# Store key in a secure location
echo "PAGEGUN_API_KEY=pgk_live_xxx" > ~/.secrets/pagegun-api-key
# Load at runtime
export PAGEGUN_API_KEY=$(sed 's/.*=//' ~/.secrets/pagegun-api-key)Never hardcode API keys in agent prompts, skill files, or version-controlled files.
Project Discovery
Always start by discovering the project context before making changes:
# List all projects
PROJECTS=$(curl -s "https://api.pagegun.com/projects" \
-H "Authorization: Bearer $PAGEGUN_API_KEY")
# Find your target project
PROJECT_ID=$(echo "$PROJECTS" | jq -r '.data[] | select(.name == "My Docs") | .id')
# List pages in the project
curl -s "https://api.pagegun.com/pages?project_id=$PROJECT_ID" \
-H "Authorization: Bearer $PAGEGUN_API_KEY" | jq '.data[] | {id, title: .page_name, slug, status}'Error Handling
Retry Strategy
async function apiCallWithRetry(fn, maxRetries = 3) {
for (let i = 0; i < maxRetries; i++) {
try {
const response = await fn();
if (response.ok) return await response.json();
const error = await response.json();
// Don't retry client errors (except rate limit)
if (response.status >= 400 && response.status < 500 && response.status !== 429) {
throw new Error(`Client error: ${error.error?.message}`);
}
// Rate limited — wait and retry
if (response.status === 429) {
await sleep(2000 * (i + 1)); // Exponential backoff
continue;
}
// Server error — retry
await sleep(1000 * (i + 1));
} catch (e) {
if (i === maxRetries - 1) throw e;
await sleep(1000 * (i + 1));
}
}
}Common Errors and Solutions
| Error | Cause | Fix |
|---|---|---|
400 validation_error | Missing required field | Check page_name, slug, subroute, type |
401 unauthorized | Invalid or missing API key | Verify key starts with pgk_ |
404 not_found | Wrong page/project ID | Re-fetch the resource list |
409 conflict | Duplicate slug in same subroute | Use a unique slug |
429 rate_limited | Too many requests | Wait 1-2 seconds, use backoff |
Content Management Patterns
Idempotent Updates
When agents run repeatedly, avoid creating duplicates:
# Check if page exists before creating
EXISTING=$(curl -s "https://api.pagegun.com/pages?project_id=$PROJECT_ID" \
-H "Authorization: Bearer $PAGEGUN_API_KEY" \
| jq -r ".data[] | select(.slug == \"$SLUG\") | .id")
if [ -n "$EXISTING" ]; then
# Update existing page
curl -X PUT "https://api.pagegun.com/pages/$EXISTING" \
-H "Authorization: Bearer $PAGEGUN_API_KEY" \
-H "Content-Type: application/json" \
-d "$PAGE_DATA"
else
# Create new page
curl -X POST "https://api.pagegun.com/pages" \
-H "Authorization: Bearer $PAGEGUN_API_KEY" \
-H "Content-Type: application/json" \
-d "$PAGE_DATA"
fiBatch Operations with Rate Limiting
# Publish all pages with rate limit respect
PAGES=$(curl -s "https://api.pagegun.com/pages?project_id=$PROJECT_ID" \
-H "Authorization: Bearer $PAGEGUN_API_KEY" | jq -r '.data[].id')
for PAGE_ID in $PAGES; do
curl -s -X POST "https://api.pagegun.com/pages/$PAGE_ID/publish" \
-H "Authorization: Bearer $PAGEGUN_API_KEY"
sleep 0.7 # Stay under 100 req/min limit
doneContent from Files
Store content in local files and deploy via API:
# Deploy markdown files as docs pages
for FILE in docs-content/*.md; do
SLUG=$(head -1 "$FILE" | sed 's///')
TITLE=$(grep -m1 '^# ' "$FILE" | sed 's/^# //')
CONTENT=$(cat "$FILE" | tail -n +2) # Skip slug comment
# Create or update via API...
doneAutomation Patterns
Scheduled Content Updates
Use cron jobs to keep content fresh:
# Daily: Check for outdated content
# Weekly: Refresh dynamic pages (changelogs, status)
# On-demand: Deploy new content after writingWebhook-Driven Workflows
Set up webhooks to trigger agent actions:
{
"url": "https://your-agent.com/webhook",
"events": ["page.published", "page.unpublished"],
"secret": "whsec_..."
}Your agent can then:
- Validate published content automatically
- Update sitemaps after publishing
- Notify stakeholders of content changes
- Trigger downstream builds
Performance Tips
- Cache project/page IDs — Don't re-fetch the full list every time
- Batch publish — Publish multiple pages in sequence rather than one at a time
- Use rate limits wisely — 100 req/min is generous; sleep 0.7s between calls to be safe
- Minimize API calls — Combine discovery steps; reuse responses
Related
- Agent Skill Template — Build a PageGun skill for your agent
- Webhooks Guide — Set up event-driven workflows
- Error Reference — All error codes and solutions
- Rate Limits — API rate limit details