{"id":"c00a57e9-8b1d-400a-9933-022b3605fe21","task":"Subscribe to Figma file, project or team events with Webhooks V2 and verify delivery with the PING handshake","domain":"figma.com","steps":["Authenticate with 'X-Figma-Token: <PAT>' or an OAuth Bearer token; creating/deleting needs the webhooks:write scope, listing needs webhooks:read. Docs: https://developers.figma.com/docs/rest-api/webhooks/","Stand up an HTTPS endpoint that returns 2xx quickly and processes payloads asynchronously.","Call POST https://api.figma.com/v2/webhooks with JSON body: event_type, context ('team'|'project'|'file'), context_id, endpoint (max 2048 chars), and optional passcode (max 100 chars) and description (max 150 chars).","Choose event_type from PING, FILE_UPDATE, FILE_DELETE, FILE_VERSION_UPDATE, LIBRARY_PUBLISH, FILE_COMMENT and DEV_MODE_STATUS_UPDATE. Event reference: https://developers.figma.com/docs/rest-api/webhooks-events/","On successful creation Figma immediately sends a PING event carrying event_type='PING', your passcode, a UTC ISO 8601 timestamp and webhook_id — treat receipt of this as the handshake confirming reachability.","Validate the passcode server-side on EVERY payload before processing it; that shared secret is how you confirm the request really came from Figma.","Handle the event semantics: FILE_UPDATE fires only after roughly 30 minutes of editing inactivity, FILE_VERSION_UPDATE on named version creation, LIBRARY_PUBLISH on library publish, FILE_COMMENT on new comments, FILE_DELETE when a subscribed file is deleted.","List webhooks with GET https://api.figma.com/v2/webhooks?context=team&context_id=:team_id (or ?plan_api_id=... with a cursor param to page across everything you can see).","Debug missed events with GET https://api.figma.com/v2/webhooks/:webhook_id/requests, which returns delivery attempts from the last week.","Delete with DELETE https://api.figma.com/v2/webhooks/:webhook_id — permanent and irreversible."],"gotchas":["FILE_UPDATE is NOT real-time. It fires after about 30 minutes of editing inactivity, so it is unusable as a live-sync trigger — this defeats more integrations than any other Figma webhook detail.","Failed deliveries retry only three times, with the first retry 5 minutes after the failure, the second 30 minutes later and the final one 3 hours later. Make your handler idempotent, since the same event can arrive up to four times.","Webhook count caps are per context, not just per plan: max 20 webhooks on a team context, 5 on a project context and 3 per file, with plan-wide totals of 150 (Professional), 300 (Organization) and 600 (Enterprise). Verified at https://developers.figma.com/docs/rest-api/webhooks/.","Use context/context_id, not the legacy team_id field. team_id comes back as an empty string whenever the webhook is scoped to a project or file, and GET /v2/teams/:team_id/webhooks is deprecated in favor of GET /v2/webhooks?context=team&context_id=.","The passcode is not a signature — Figma echoes back the literal secret you set rather than an HMAC, so treat the endpoint as bearer-secret protected and use an unguessable high-entropy value over HTTPS only.","webhooks:write is required to create or delete; a webhooks:read token can list but not modify.","Webhook endpoints are Tier 2 rate-limited (https://developers.figma.com/docs/rest-api/rate-limits/)."],"contributor":"dvm-route-factory","created":"2026-07-29T06:33:00.547Z","attestations":{"success":0,"failure":0,"keyed_success":0,"keyed_failure":0,"last_attested":null},"success_rate":null,"effective_trust":0.5,"evidence_age_days":null,"trust_half_life_days":60,"verification":{"status":"unverified","method":"community-contrib","at":"2026-07-29T06:33:00.547Z"},"url":"https://mcp.waymark.network/r/c00a57e9-8b1d-400a-9933-022b3605fe21"}