---
name: figma-rest-api-conventions
source: https://app.decimal.ai/s/figma-rest-api-conventions@1/SKILL.md
source_sha256: 5d76426d71ed
---

# Figma API conventions

## Contract

Emit Figma's real, current API surface whenever code or instructions call it: the correct
auth header, host, versioned path, endpoints, query parameters, and OAuth scope identifiers.
Apply this any time a task reads a file/nodes/images or selects scopes for an integration.

## Rules

1. **Authentication header.**
   - A **personal access token (PAT)** is sent in the `X-Figma-Token` request header.
   - A PAT must NOT be sent in `Authorization: Bearer` — that header carries an **OAuth 2.0**
     access token only. A PAT placed there is rejected with `403`.
   - Current PAT strings begin with the literal prefix `figd_`.
2. **Host and version.** All standard calls target the host `api.figma.com`, and every
   documented endpoint lives under the `/v1` path (e.g. `https://api.figma.com/v1/...`).
3. **Get a whole file.** `GET /v1/files/:file_key`. By default this returns the entire
   document tree. To bound the payload, pass the `depth` query parameter — a positive integer
   — e.g. `?depth=1` returns only the top level (pages), `?depth=2` one more level down.
4. **Get specific nodes.** `GET /v1/files/:file_key/nodes` with a **required** `ids` query
   parameter (comma-separated node IDs). Use this instead of downloading the full file when
   only certain nodes are needed. The IDs go in the query string, never in path segments.
5. **Render images.** `GET /v1/images/:file_key` with an `ids` query parameter naming the
   nodes to render (optional `format`, `scale` control the output). There is no
   `/v1/files/:key/images` path.
6. **OAuth scopes.** Scope identifiers are lowercase `resource:action`, joined by a single
   colon. The ones the base most often needs:
   - `file_content:read` — read a file's contents (document, nodes, editor type).
   - `file_comments:read` / `file_comments:write` — read / post comments.
   - `file_variables:read` / `file_variables:write` — read / write variables.
   - `file_versions:read` — read version history.
   - `file_dev_resources:read` — read dev resources.
   - `projects:read`, `webhooks:read` / `webhooks:write`.
   - `files:read` is **deprecated** — never request it for a new integration; use
     `file_content:read` for file-content read access.

## Worked examples

- Authenticating a PAT request:
  - BEFORE (wrong header): `curl -H "Authorization: Bearer $FIGTOK" https://api.figma.com/v1/files/ZZ9`
  - AFTER (correct):       `curl -H "X-Figma-Token: $FIGTOK" https://api.figma.com/v1/files/ZZ9`
- Bounding a huge file's payload:
  - BEFORE: `GET /v1/files/ZZ9` (returns the full tree, then discard most of it)
  - AFTER:  `GET /v1/files/ZZ9?depth=1`
- Fetching only two nodes:
  - BEFORE: `GET /v1/files/ZZ9` then walk the JSON to find `9:1` and `9:7`
  - AFTER:  `GET /v1/files/ZZ9/nodes?ids=9:1,9:7`
- Rendering a frame:
  - BEFORE: `GET /v1/files/ZZ9/images/9:1`
  - AFTER:  `GET /v1/images/ZZ9?ids=9:1&format=png`
- Choosing a read scope for a new OAuth app:
  - BEFORE: request `files:read`
  - AFTER:  request `file_content:read` (`files:read` is deprecated)
- Guessing a scope name:
  - BEFORE: `file:read` / `read:files` / `files.read`
  - AFTER:  `file_content:read`

## Edge cases & exceptions

- **PAT vs OAuth is the whole split.** Only an OAuth access token uses `Authorization: Bearer`;
  a PAT always uses `X-Figma-Token`. Do not mix them.
- **`depth` is get-file only.** The nodes endpoint already returns a bounded subtree per
  requested id, so `depth` applies to `GET /v1/files/:key`, not to `/nodes`.
- **`ids` is required** on both `/nodes` and `/images`. Omitting it is an error, not
  "return everything."
- **Figma for Government** uses the host `api.figma.com` replaced by `api.figma-gov.com`; the
  paths, headers, and scopes are otherwise identical.
- **Legacy tokens.** PATs created before the prefix change may lack `figd_`; tokens issued now
  always carry it, so a leak scanner should anchor on `figd_`.

## Do / Don't

- DO send a PAT in `X-Figma-Token`. DON'T send a PAT in `Authorization: Bearer`.
- DO use `Authorization: Bearer` for an OAuth 2.0 access token. DON'T use it for a PAT.
- DO request `file_content:read` to read file contents. DON'T request the deprecated `files:read`.
- DO write scope names as lowercase `resource:action` with a colon. DON'T use `file.read`,
  `read/files`, or `read_files`.
- DO pass `depth` to bound a large get-file response. DON'T pull the whole tree to keep a slice.
- DO fetch specific nodes via `/v1/files/:key/nodes?ids=`. DON'T invent `/v1/nodes/:id`.
- DO render via `/v1/images/:key?ids=`. DON'T use `/v1/files/:key/images`.

## Common mistakes

- Defaulting to `Authorization: Bearer` for a personal access token (that header is OAuth-only).
- Hallucinating scope names — `file:read`, `read:files`, `files.read`, `read_files` — instead of
  the real `file_content:read`.
- Still requesting the deprecated `files:read` scope.
- Dropping `/v1` from the path or using a wrong host.
- Downloading the full file instead of passing `depth` or hitting the nodes endpoint.
- Putting node ids in path segments (`/nodes/9:1`) instead of the `ids` query parameter.

## Quick checklist

- [ ] PAT in `X-Figma-Token`; OAuth token in `Authorization: Bearer`.
- [ ] Host `api.figma.com`, every path under `/v1`.
- [ ] Large get-file call bounded with `depth` (positive integer).
- [ ] Specific nodes: `GET /v1/files/:key/nodes?ids=...`.
- [ ] Images: `GET /v1/images/:key?ids=...`.
- [ ] Read-contents scope is `file_content:read`, not the deprecated `files:read`.
- [ ] Scope identifiers are lowercase `resource:action` with a colon.
