From webflow-pack
Diagnoses and fixes Webflow Data API v2 errors (400, 401, 403, 404, 409, 429, 500) with causes, validation, token/scope checks for integration debugging.
How this skill is triggered — by the user, by Claude, or both
Slash command
/webflow-pack:webflow-common-errorsThis skill is limited to the following tools:
The summary Claude sees in its skill listing — used to decide when to auto-load this skill
Quick reference for the most common Webflow Data API v2 errors, their root causes,
Quick reference for the most common Webflow Data API v2 errors, their root causes, and concrete solutions. Covers every HTTP status code the API returns.
webflow-api SDK installed{ "code": "validation_error", "message": "Invalid field data" }
Common causes:
name and slug are always required for CMS items)Fix:
// Check collection schema before creating items
const collection = await webflow.collections.get(collectionId);
const requiredFields = collection.fields?.filter(f => f.isRequired);
console.log("Required fields:", requiredFields?.map(f => `${f.slug} (${f.type})`));
// Validate slug format
function isValidSlug(slug: string): boolean {
return /^[a-z0-9]+(?:-[a-z0-9]+)*$/.test(slug);
}
{ "code": "unauthorized", "message": "Not authorized" }
Common causes:
Fix:
# Verify token works
curl -s https://api.webflow.com/v2/sites \
-H "Authorization: Bearer $WEBFLOW_API_TOKEN" \
-w "\nHTTP Status: %{http_code}\n"
# Check for whitespace issues
echo -n "$WEBFLOW_API_TOKEN" | wc -c
// Programmatic token check
async function verifyToken(): Promise<boolean> {
try {
await webflow.sites.list();
return true;
} catch (err: any) {
if (err.statusCode === 401) {
console.error("Token invalid. Generate new token at developers.webflow.com");
return false;
}
throw err;
}
}
{ "code": "forbidden", "message": "Insufficient permissions" }
Common causes:
cms:read)Fix:
// Required scopes by operation
const SCOPE_MAP: Record<string, string> = {
"sites.list": "sites:read",
"sites.publish": "sites:write",
"collections.list": "cms:read",
"collections.items.createItem": "cms:write",
"pages.list": "pages:read",
"forms.list": "forms:read",
"products.list": "ecommerce:read",
"products.create": "ecommerce:write",
"orders.list": "ecommerce:read",
"orders.refund": "ecommerce:write",
};
Generate a new token with the correct scopes at https://developers.webflow.com.
{ "code": "not_found", "message": "Resource not found" }
Common causes:
site_id, collection_id, or item_idFix:
// Discovery chain: always start from sites.list()
async function discoverResources() {
const { sites } = await webflow.sites.list();
console.log("Sites:", sites?.map(s => `${s.displayName}: ${s.id}`));
for (const site of sites!) {
const { collections } = await webflow.collections.list(site.id!);
console.log(` Collections in ${site.displayName}:`);
for (const col of collections!) {
console.log(` ${col.displayName}: ${col.id}`);
}
}
}
{ "code": "conflict", "message": "Item with slug already exists" }
Common causes:
Fix:
// Check for existing slug before creating
async function createOrUpdate(collectionId: string, slug: string, fieldData: Record<string, any>) {
const { items } = await webflow.collections.items.listItems(collectionId);
const existing = items?.find(i => i.fieldData?.slug === slug);
if (existing) {
return webflow.collections.items.updateItem(collectionId, existing.id!, { fieldData });
}
return webflow.collections.items.createItem(collectionId, { fieldData: { slug, ...fieldData } });
}
HTTP/1.1 429 Too Many Requests
Retry-After: 60
Common causes:
Fix:
// The SDK auto-retries 429s with exponential backoff.
// For manual control:
async function waitForRateLimit(retryAfterSeconds: number) {
console.log(`Rate limited. Waiting ${retryAfterSeconds}s...`);
await new Promise(r => setTimeout(r, retryAfterSeconds * 1000));
}
See webflow-rate-limits for comprehensive rate limit handling.
Fix:
# 1. Check Webflow status
curl -s https://status.webflow.com/api/v2/status.json | jq '.status'
# 2. Retry with backoff (SDK handles this automatically)
# 3. If persistent, check Webflow status page and open support ticket
# Test API connectivity
curl -s -o /dev/null -w "%{http_code}" \
-H "Authorization: Bearer $WEBFLOW_API_TOKEN" \
https://api.webflow.com/v2/sites
# Check rate limit headers
curl -v -H "Authorization: Bearer $WEBFLOW_API_TOKEN" \
https://api.webflow.com/v2/sites 2>&1 | grep -i "x-ratelimit\|retry-after"
# List sites (quick token verification)
curl -s -H "Authorization: Bearer $WEBFLOW_API_TOKEN" \
https://api.webflow.com/v2/sites | jq '.sites[].displayName'
# Check Webflow platform status
curl -s https://status.webflow.com/api/v2/status.json | jq '.status.description'
import { WebflowClient } from "webflow-api";
async function resilientCall<T>(
operation: () => Promise<T>,
label: string
): Promise<T> {
try {
return await operation();
} catch (err: any) {
const status = err.statusCode || err.status;
const actionMap: Record<number, string> = {
400: "Fix request payload — check field names and types",
401: "Rotate token at developers.webflow.com",
403: "Add missing scope to token",
404: "Verify resource IDs with discovery chain",
409: "Handle duplicate — update instead of create",
429: "Wait for Retry-After header (SDK auto-retries)",
500: "Webflow server error — retry later",
};
console.error(`[${label}] HTTP ${status}: ${actionMap[status] || "Unknown error"}`);
console.error(` Message: ${err.message}`);
console.error(` Body: ${JSON.stringify(err.body)}`);
throw err;
}
}
webflow-debug-bundleFor comprehensive debugging, see webflow-debug-bundle.
npx claudepluginhub jeremylongshore/claude-code-plugins-plus-skills --plugin webflow-packExecutes Webflow API incident runbook: triages errors via curl checks on status page, HTTP codes, rate limits; activates circuit breakers, fallbacks; provides comms templates and postmortem.
Creates, edits, and optimizes skills for Claude Code, including drafting, evaluating with test prompts, iterating on performance, and improving skill descriptions for better triggering accuracy.