API coverage
cyber-figma is a curated wrapper, not a 1:1 mirror of the
Figma REST API. This page tracks what is
implemented, group by group.
Coverage is measured against Figma’s own OpenAPI specification, v0.41.0, retrieved 2026-08-11. That spec is labelled beta by Figma; where it and the prose docs disagree, the prose docs win.
Legend
Section titled “Legend”| Status | Meaning |
|---|---|
| ✅ | Fully covered — every operation in the group is reachable |
| 🟡 | Partially covered |
| ✅ | Planned — not implemented yet |
| 🚫 | Out of scope — deliberately not wrapped |
Every operation is reachable from both the CLI and the MCP server, with one exception noted below. They share the same core, so nothing is CLI-only by accident.
Surface size
Section titled “Surface size”The API is 53 HTTP operations: 50 in the OpenAPI spec, plus the Discovery endpoint (documented but absent from the spec), plus 2 OAuth token endpoints. Of the 50 spec operations, 11 mutate and 39 are read-only.
Nothing in the REST API creates or deletes files, projects, teams, pages, or nodes. The write surface is deliberately narrow: comments, reactions, webhooks, variables, and dev resources. Any “edit the design” capability lives in the Plugin API, not here.
Coverage by endpoint group
Section titled “Coverage by endpoint group”| Endpoint group | Ops | Status | CLI namespace | Rate tier | Plan gate |
|---|---|---|---|---|---|
| Files | 6 | ✅ | file |
1–3 | — |
| Projects | 3 | ✅ | project |
2–3 | — |
| Comments | 3 | ✅ | comment |
2 | — |
| Comment Reactions | 3 | ✅ | comment |
2 | — |
| Users | 1 | ✅ | user |
3 | — |
| Components, Component Sets, Styles | 9 | ✅ | component, component-set, style |
3 | — |
| Webhooks v2 | 7 | ✅ | webhook |
2 | — |
| Variables | 3 | ✅ | variable |
2–3 | Enterprise |
| Dev Resources | 4 | ✅ | dev-resource |
2 | — |
| Library Analytics | 6 | ✅ | analytics |
3 | Enterprise |
| Activity Logs | 1 | ✅ | activity-log |
3 | Enterprise, org admin |
| Developer Logs | 1 | ✅ | developer-log |
3 | Enterprise + Governance+ |
| AI Usage | 1 | ✅ | ai-usage |
3 | Enterprise, org admin |
| Discovery | 1 | ✅ | discovery |
2 | Enterprise + Governance+ |
| Payments | 1 | ✅ | payment |
3 | — |
| oEmbed | 1 | ✅ | oembed |
— | — |
| OAuth token endpoints | 2 | 🚫 Deferred | — | — | — |
| SCIM | — | 🚫 Out of scope | — | — | Organization+ |
Each CLI namespace is documented in the command reference, and its tools in the tool reference. Plan gates and rate tiers are explained on Plans and limits.
Operation-level inventory
Section titled “Operation-level inventory”Six read-only operations.
| Operation | Endpoint | Tier | Status |
|---|---|---|---|
| Get file JSON | GET /v1/files/{file_key} |
1 | ✅ |
| Get JSON for specific nodes | GET /v1/files/{file_key}/nodes |
1 | ✅ |
| Render images of nodes | GET /v1/images/{file_key} |
1 | ✅ |
| Get image fills | GET /v1/files/{file_key}/images |
2 | ✅ |
| Get file metadata | GET /v1/files/{file_key}/meta |
3 | ✅ |
| Get version history | GET /v1/files/{file_key}/versions |
2 | ✅ |
Things a wrapper has to get right here:
GET filereturns the whole document tree with no pagination. Large files commonly answer400or500on timeout, sodepthandidshave to be used aggressively — and a default that fetches everything is a bug, not a convenience.GET file metais Tier 3 whileGET fileis Tier 1, so metadata-first listing flows are roughly 15× cheaper.- Rendered image URLs expire after 30 days; image-fill URLs expire after no more than 14 days.
- On
GET images, anullvalue in theimagesmap means that node failed to render, not that the request failed. Every requested node ID appears as a key regardless, so anullmust never be retried as an error. editorTypeonGET file metahas a wider enum than onGET file(figma | figjam | slides | buzz | sites | makeversusfigma | figjam). They are not the same type.
Projects
Section titled “Projects”| Operation | Endpoint | Tier | Status |
|---|---|---|---|
| Get projects in a team | GET /v1/teams/{team_id}/projects |
2 | ✅ |
| Get project metadata | GET /v1/projects/{project_id}/meta |
3 | ✅ |
| Get files in a project | GET /v1/projects/{project_id}/files |
2 | ✅ |
There is no endpoint to discover a team ID from a token — Figma says so explicitly. The
ID must be read out of the team page URL, which is why FIGMA_TEAM_ID exists.
Comments
Section titled “Comments”| Operation | Endpoint | Status |
|---|---|---|
| Get comments in a file | GET /v1/files/{file_key}/comments |
✅ |
| Add a comment ✏️ | POST /v1/files/{file_key}/comments |
✅ |
| Delete a comment ✏️ | DELETE /v1/files/{file_key}/comments/{comment_id} |
✅ |
Replies must target a root comment — you cannot reply to a reply. Only the author may
delete a comment. Writing comments requires file_comments:write, which plan access
tokens cannot use.
Comment Reactions
Section titled “Comment Reactions”| Operation | Endpoint | Status |
|---|---|---|
| Get reactions | GET /v1/files/{file_key}/comments/{comment_id}/reactions |
✅ |
| Add a reaction ✏️ | POST /v1/files/{file_key}/comments/{comment_id}/reactions |
✅ |
| Delete a reaction ✏️ | DELETE /v1/files/{file_key}/comments/{comment_id}/reactions |
✅ |
emoji is an emoji shortcode (:heart:, :+1::skin-tone-2:), and on the DELETE it
is a required query parameter rather than a path segment. Only the person who made a
reaction may remove it.
| Operation | Endpoint | Status |
|---|---|---|
| Get the current user | GET /v1/me |
✅ |
The email field appears only on this endpoint. It is the natural “verify my
credentials” command, but plan access tokens cannot call it, so a connection check must
fall back to something else in that mode.
Components, Component Sets, and Styles
Section titled “Components, Component Sets, and Styles”Three parallel families with identical shapes — nine operations, all read-only, all Tier 3.
| Resource | Team-scoped (paginated) | File-scoped | By key |
|---|---|---|---|
| Components | GET /v1/teams/{team_id}/components |
GET /v1/files/{file_key}/components |
GET /v1/components/{key} |
| Component Sets | GET /v1/teams/{team_id}/component_sets |
GET /v1/files/{file_key}/component_sets |
GET /v1/component_sets/{key} |
| Styles | GET /v1/teams/{team_id}/styles |
GET /v1/files/{file_key}/styles |
GET /v1/styles/{key} |
They return only published library content, not every component in a file. The file-scoped variants require a main file key, not a branch key, because branches cannot publish.
Webhooks v2
Section titled “Webhooks v2”The only family not on /v1/. Four reads, three writes.
| Operation | Endpoint | Status |
|---|---|---|
| Get webhooks by context or plan | GET /v2/webhooks |
✅ |
| Create a webhook ✏️ | POST /v2/webhooks |
✅ |
| Get a webhook | GET /v2/webhooks/{webhook_id} |
✅ |
| Update a webhook ✏️ | PUT /v2/webhooks/{webhook_id} |
✅ |
| Delete a webhook ✏️ | DELETE /v2/webhooks/{webhook_id} |
✅ |
| Get webhook requests | GET /v2/webhooks/{webhook_id}/requests |
✅ |
| Get team webhooks — deprecated | GET /v2/teams/{team_id}/webhooks |
✅ |
The deprecated team-scoped list is superseded by GET /v2/webhooks?context=team&context_id=….
It is surfaced as webhook list-team so an existing script keeps working, and it is the one
operation with no MCP tool: an agent should never be steered onto a superseded endpoint.
Event types: PING, FILE_UPDATE, FILE_VERSION_UPDATE, FILE_DELETE,
LIBRARY_PUBLISH, FILE_COMMENT, DEV_MODE_STATUS_UPDATE. A PUT does not accept
context / context_id, so a webhook cannot be re-targeted. Figma retries a failed
delivery 3 times with exponential backoff — at 5 minutes, 30 minutes, and 3 hours — and
does not auto-deactivate persistently failing endpoints. There is no UI for webhooks; the
API is the only management surface.
Variables
Section titled “Variables”Enterprise-only.
| Operation | Endpoint | Tier | Status |
|---|---|---|---|
| Get local variables | GET /v1/files/{file_key}/variables/local |
2 | ✅ |
| Get published variables | GET /v1/files/{file_key}/variables/published |
2 | ✅ |
| Create / modify / delete ✏️ | POST /v1/files/{file_key}/variables |
3 | ✅ |
GET local is the only place to read mode values; the published endpoint omits modes.
The bulk write applies its arrays in a fixed order — collections, then modes, then
variables, then mode values — and returns a tempIdToRealId map.
Limits: 40 modes per collection, mode names ≤ 40 characters, 5000 variables per collection.
Dev Resources
Section titled “Dev Resources”| Operation | Endpoint | Status |
|---|---|---|
| Get dev resources | GET /v1/files/{file_key}/dev_resources |
✅ |
| Bulk create ✏️ | POST /v1/dev_resources |
✅ |
| Bulk update ✏️ | PUT /v1/dev_resources |
✅ |
| Delete a dev resource ✏️ | DELETE /v1/files/{file_key}/dev_resources/{dev_resource_id} |
✅ |
Unlike variables, components, and styles, dev resources do not need to be published — they are live immediately.
Library Analytics
Section titled “Library Analytics”Six read-only endpoints under GET /v1/analytics/libraries/{file_key}/…, all
Enterprise-only.
| Path suffix | group_by (required) |
Date range? |
|---|---|---|
/component/actions |
component | team |
✅ |
/component/usages |
component | file |
❌ |
/style/actions |
style | team |
✅ |
/style/usages |
style | file |
❌ |
/variable/actions |
variable | team |
✅ |
/variable/usages |
variable | file |
❌ |
The …/actions endpoints are time series and take start_date / end_date; the
…/usages endpoints are a snapshot and take no date range at all. Data is recalculated
daily at 00:00 UTC, so polling more often is wasted. Rows the requesting user cannot
see are name-obfuscated rather than dropped — they appear as Team not visible /
File not visible, and must not be aggregated as a single real entity.
Activity Logs
Section titled “Activity Logs”| Operation | Endpoint | Status |
|---|---|---|
| Get activity logs | GET /v1/activity_logs |
✅ |
Enterprise-only, org admins only. Requires org OAuth 2 with org:activity_log_read, or
a plan access token — the spec does not list personal access tokens for this endpoint.
Developer Logs
Section titled “Developer Logs”| Operation | Endpoint | Status |
|---|---|---|
| Get developer logs | POST /v1/developer_logs |
✅ |
A POST that reads — filters go in the body, not the query string. It is not a
mutation. Enterprise + Governance+, org admins only, plan access token only. Records are
retained 30 days only, and the logs cover both REST API and MCP server requests.
AI Usage
Section titled “AI Usage”| Operation | Endpoint | Status |
|---|---|---|
| Get daily AI usage | GET /v1/ai_usage/daily |
✅ |
Enterprise-only, org admins, plan access token only. start_date must be on or after
2025-12-01 and no more than 366 days before today. A user_email matching no Figma user
returns 400, not an empty list. Data lags real time by 5–6 hours, so current-day
figures are unreliable.
Discovery
Section titled “Discovery”| Operation | Endpoint | Status |
|---|---|---|
| Get text events | GET /v1/discovery |
✅ |
Enterprise + Governance+, org admins only, OAuth 2 only. It is a two-stage API: the
endpoint returns S3 download links keyed by hour, and you then fetch the JSON blobs.
start_date must be at least 1 hour in the past, and end_date cannot be more than
24 hours after it. Its error table is its own: 429 is documented as “more than 20 per
second”.
Payments
Section titled “Payments”| Operation | Endpoint | Status |
|---|---|---|
| Validate a purchase | GET /v1/payments |
✅ |
Personal access token only — the docs state plainly that the Payments REST API does not support OAuth 2, and the spec lists no plan-token support either. You can only query resources you own.
oEmbed
Section titled “oEmbed”| Operation | Endpoint | Status |
|---|---|---|
| Get an oEmbed response | GET /v1/oembed |
✅ |
Follows the oEmbed 1.0 spec. Requires file_metadata:read and is
not usable with a plan access token. Distinctively, it is the only endpoint in the spec
that can return 501 Not Implemented.
OAuth token endpoints
Section titled “OAuth token endpoints”GET https://www.figma.com/oauth, POST /v1/oauth/token, and POST /v1/oauth/refresh are
part of the HTTP surface but are not in the OpenAPI spec. cyber-figma
defers OAuth 2 — a local CLI should not carry a
callback server and an app-review lifecycle.
🚫 Out of scope. Figma’s SCIM API is explicitly “distinct from the Figma REST API” —
a different host (https://www.figma.com/scim/v2/:tenantid), different endpoints, and its
own bearer token. It manages user lifecycle, not the design surface a REST wrapper is for.
Pagination
Section titled “Pagination”Figma has no single pagination model. Six different ones are in use across the API, which is
the single biggest source of implementation drift. cyber-figma names each one and
normalizes the ends: one options shape in, one result shape out, whatever the endpoint
underneath does.
| Model | Where | Request | Response |
|---|---|---|---|
| URL cursor | Comment reactions, GET /v2/webhooks with plan_api_id |
cursor |
pagination: { prev_page?, next_page? } — complete URLs to call |
| URL page | File versions | page_size, before / after |
pagination: { prev_page?, next_page? } |
| Id cursor | Team components, component sets, styles | page_size (default 30, max 1000), before / after — mutually exclusive, opaque |
meta.cursor: { before?, after? } integers |
| Row cursor | All 6 Library Analytics endpoints | cursor |
{ rows, next_page: boolean, cursor? }, max 1000 rows/page |
| Next cursor | AI Usage | cursor, limit |
{ rows, next_cursor, has_next_page } — next_cursor is the empty string once exhausted |
| Meta cursor | Developer Logs, in the body | cursor, limit |
meta: { items, cursor, has_more } |
| None | Everything else | — | The complete set in one response |
Each list endpoint declares its model once, and the CLI flags and MCP tool parameters are
derived from that declaration. A command therefore cannot advertise a --cursor its endpoint
does not have.
Most endpoints do not paginate at all and return the complete set in one response —
including GET file, GET file nodes, GET images, GET file comments, GET team projects, GET project files, every Variables endpoint, and every Dev Resources endpoint.
On a large file or team that is a real scaling hazard, not a convenience.
GET /v1/activity_logs is its own case: it has a limit (default 1000) and reports
has_more, but no usable cursor — page it by shifting the time window.
Known spec defects
Section titled “Known spec defects”Figma’s OpenAPI specification has verified defects that a code generator will faithfully
reproduce as bugs, which is why cyber-figma does not generate its client from it.
All re-verified against v0.41.0 on 2026-08-11.
| Defect | Status in v0.41.0 | What it costs you |
|---|---|---|
Integer params typed number (#86) |
Still present, and broader than reported — 15 params across 6 endpoints | Generators serialize 30 as 30.0; Figma answers 400 "'page_size' must be a valid number, received type String". Coerce to integer at the client boundary |
GetFileNodesResponse missing err (#81) |
Still present | A spec-typed client discards a field the API returns |
err typed as always-null on GET images |
Still present | On a 400, err carries the diagnostic naming the invalid parameter — the best error detail the API gives. Type it string | null |
Analytics param named file_key vs the docs’ library_file_key (#28) |
Still present | Cosmetic; affects generated naming only |
GetFileResponse missing linkAccess (#30) |
Fixed — present in v0.41.0, though the issue is still open | None; ignore the issue |
Errors
Section titled “Errors”| Code | Meaning, and the non-obvious causes |
|---|---|
400 |
Invalid or malformed parameters — and also returned when the requested resources are too large and the request times out |
401 |
Token missing or incorrect. Notably not declared on the Files endpoints |
403 |
Valid request, refused: insufficient permissions, an HTTP rather than HTTPS request, or an expired/invalid token. So token expiry presents as 403, not 401 |
404 |
File or resource not found |
429 |
Rate limited — see Plans and limits |
500 |
Internal error, “most commonly occurs for very large image render requests” |
501 |
oEmbed only |
Documented gaps
Section titled “Documented gaps”Stated as gaps rather than guessed at:
- No file, project, or team creation or deletion, and no node editing. Not exposed by the REST API at all — that lives in the Plugin API.
- No publish endpoint. Variables written via REST must be published before other files see them, but publishing is a UI or plugin action.
- No team-ID discovery. Explicitly acknowledged by Figma.
selections:readis a documented OAuth scope with no documented endpoint that consumes it.file_code_connect:writeis referenced on the plan-access-tokens page but is absent from the published scopes table.- Activity Logs cursor pagination — the response returns a cursor with nowhere to send it back.
- The accepted emoji shortcode list lives in an external file linked from the docs, not in any schema.
- Personal access token count limits and rotation are undocumented; there is no auto-rotation.
Sources
Section titled “Sources”- Figma REST API documentation
- Figma OpenAPI specification — v0.41.0
- Errors
- Discovery endpoints
- In-repo research:
docs/research/figma-rest-api.md