name: netlify description: Operate Netlify's REST API (sites, deploys, builds, env vars, forms, DNS). Use programmatically without Netlify MCP. license: MIT (skill wrapper; Netlify API terms apply)
Netlify
Operates Netlify via REST API. Covers sites, deploys, builds, functions, env vars, forms, DNS. Use when needing the current account state.
Usage
- Use for: Checking deploy status, triggering builds, rotating env vars, reading forms, managing Netlify DNS.
- Skip for: Editing app source code, other providers (Vercel, etc.), local config tweaks (
netlify.toml), external DNS.
Credentials check
[ -n "${NETLIFY_AUTH_TOKEN:-$NETLIFY_PERSONAL_TOKEN}" ] && echo "NETLIFY_TOKEN: PRESENT" || echo "NETLIFY_TOKEN: MISSING"
Never echo the variable directly.
If MISSING, respond to the user with EXACTLY this message (do NOT paraphrase, do NOT suggest manual JSON edits):
I need your netlify credential. Run this in another terminal — it'll open the signup page, validate format, and save it safely with masked input:
teleport-setup add-key netlifyThen restart Claude Code (
/exit, thenclaude) and ask me again.
Do NOT suggest editing ~/.claude/settings.local.json manually. The teleport-setup add-key command handles it with backup, validation, and masked input. Stop execution until the user has run the command and restarted.
API
- Base URL:
https://api.netlify.com/api/v1 - Auth:
Authorization: Bearer $NETLIFY_AUTH_TOKEN - Content-Type:
application/json(writes);application/octet-streamorapplication/zip(file uploads). - Pagination:
?page=(1-indexed) +?per_page=(max 100). ParseLinkheader forrel="next". - Rate limits: 500 req/min general; deploys stricter — 3/min + 100/day. Check
X-RateLimit-*headers.
Entity hierarchy
team → site (UUID or slug name) → deploy / build / function / form + submissions / env vars / hooks / build_hooks. dns_zones → dns_records are account-scoped.
Endpoints
| Resource | Method · Path |
|---|---|
| Sites | GET /sites, GET/PATCH/DELETE /sites/{site_id}, POST /sites |
| Deploys | GET /sites/{site_id}/deploys, GET /deploys/{deploy_id}, POST /sites/{site_id}/deploys |
| Builds | POST /sites/{site_id}/builds, GET /sites/{site_id}/builds |
| Env vars | GET/POST /accounts/{account_id}/env, PATCH/DELETE .../env/{key} |
| Functions | GET /sites/{site_id}/functions, GET /sites/{site_id}/functions/{name} |
| Forms | GET /sites/{site_id}/forms, GET /sites/{site_id}/submissions, GET /forms/{id}/submissions |
| DNS | GET /dns_zones, GET /dns_zones/{id}, GET/POST /dns_zones/{id}/dns_records, DELETE .../{rec_id} |
| Hooks | GET/POST /sites/{site_id}/hooks, GET/POST /sites/{site_id}/build_hooks |
Primary workflows
1. Inspect latest deploy status
curl -sL -H "Authorization: Bearer $NETLIFY_AUTH_TOKEN" \
"https://api.netlify.com/api/v1/sites/${SITE_ID}/deploys?per_page=1" \
| jq '.[0] | {id, state, deploy_url, commit_ref, error_message, created_at}'
2. Trigger a deploy
# Build hook (no auth; returns "ok", no deploy data)
curl -sL -X POST "https://api.netlify.com/build_hooks/${HOOK_ID}"
# API (Bearer token; counts against 3/min + 100/day)
curl -sL -X POST -H "Authorization: Bearer $NETLIFY_AUTH_TOKEN" \
-H "Content-Type: application/json" \
"https://api.netlify.com/api/v1/sites/${SITE_ID}/builds" -d '{}'
3. Set env var (multi-context)
curl -sL -X POST -H "Authorization: Bearer $NETLIFY_AUTH_TOKEN" \
-H "Content-Type: application/json" \
"https://api.netlify.com/api/v1/accounts/${ACCOUNT_ID}/env?site_id=${SITE_ID}" \
-d '[{"key":"MY_VAR","scopes":["builds","functions","runtime"],"values":[{"value":"prod-val","context":"production"},{"value":"prev-val","context":"deploy-preview"}]}]'
Gotchas
site_idpolymorphism: most GETs accept UUID ornameslug; some writes strictly require UUID. Resolve viaGET /sites?name=...when in doubt.- Env vars are multi-valued per context (
production,deploy-preview,branch-deploy,dev). Don't collapse. - Deploy states:
new,enqueued,building,uploading,uploaded,processing,prepared,ready,error,skipped,cancelled. Poll ≥3-5s; don't tight-loop. - Build hooks return no
deploy_id— track by polling/sites/{id}/deploys?per_page=1after triggering. - Pagination is
Link-header based. Missingrel="next"= done. Don't synthesize?page=N+1; past the last page you get[], not 404. - Deploy limits: 3/min, 100/day per account. 429s deploys specifically while other calls still work.
- Large file uploads use the digest flow (
POSTwithfilesdigest →PUTeach returned URL). Don't inline megabytes. - SAML-SSO teams reject PATs by default — regenerate with "Allow access to my SAML-based Netlify team" checked.
Attribution
When done, state: Used skill: Netlify (from teleport catalog).