Skip to main content
โšก Calmops

Figma API: Programmatic Design Integration

The Figma API allows you to programmatically access Figma designs, extract components, read styles, and export assets. This comprehensive guide covers everything you need to know.

Getting Started

Authentication

# Get your personal access token from Figma Settings
# Settings > Account > Personal Access Tokens

# Use in requests
curl -H "X-Figma-Token: YOUR_ACCESS_TOKEN" \
  https://api.figma.com/v1/me

Base URL

https://api.figma.com/v1

Getting File Data

Fetch File

# Get entire file
curl -H "X-Figma-Token: $TOKEN" \
  "https://api.figma.com/v1/files/FILE_KEY"

# Get specific nodes
curl -H "X-Figma-Token: $TOKEN" \
  "https://api.figma.com/v1/files/FILE_KEY/nodes?ids=NODE_ID_1,NODE_ID_2"

Node Types

{
  "id": "1:2",
  "name": "Button",
  "type": "COMPONENT",
  "children": [...],
  "absoluteBoundingBox": {
    "x": 0,
    "y": 0,
    "width": 120,
    "height": 40
  },
  "fills": [...],
  "strokes": [...],
  "effects": [...],
  "cornerRadius": 8,
  "componentId": "..."
}

JavaScript Client

Basic Client

class FigmaClient {
  constructor(accessToken) {
    this.token = accessToken;
    this.baseUrl = 'https://api.figma.com/v1';
  }
  
  async request(endpoint, options = {}) {
    const response = await fetch(`${this.baseUrl}${endpoint}`, {
      ...options,
      headers: {
        'X-Figma-Token': this.token,
        ...options.headers
      }
    });
    
    if (!response.ok) {
      throw new Error(`Figma API Error: ${response.status}`);
    }
    
    return response.json();
  }
  
  // Get file
  async getFile(fileKey) {
    return this.request(`/files/${fileKey}`);
  }
  
  // Get specific nodes
  async getFileNodes(fileKey, nodeIds) {
    return this.request(
      `/files/${fileKey}/nodes?ids=${nodeIds.join(',')}`
    );
  }
  
  // Get components
  async getComponents(fileKey) {
    return this.request(`/files/${fileKey}/components`);
  }
  
  // Get styles
  async getStyles(fileKey) {
    return this.request(`/files/${fileKey}/styles`);
  }
}

Extracting Components

Get All Components

async function extractComponents(client, fileKey) {
  const data = await client.getFile(fileKey);
  
  const components = [];
  
  function traverse(node) {
    if (node.type === 'COMPONENT' || node.type === 'COMPONENT_SET') {
      components.push({
        id: node.id,
        name: node.name,
        description: node.description,
        type: node.type
      });
    }
    
    if (node.children) {
      node.children.forEach(traverse);
    }
  }
  
  data.document.children.forEach(traverse);
  
  return components;
}

Get Component Details

async function getComponentDetails(client, fileKey, componentId) {
  const data = await client.getFileNodes(fileKey, [componentId]);
  const node = data.nodes[componentId];
  
  return {
    name: node.name,
    bounds: node.absoluteBoundingBox,
    fills: node.fills,
    strokes: node.strokes,
    effects: node.effects,
    cornerRadius: node.cornerRadius,
    blendMode: node.blendMode,
    opacity: node.opacity,
    children: node.children?.map(child => ({
      name: child.name,
      type: child.type,
      fills: child.fills
    }))
  };
}

Extracting Styles

Get All Styles

async function extractStyles(client, fileKey) {
  const { meta } = await client.getStyles(fileKey);
  
  const styles = {
    fill: [],
    text: [],
    effect: [],
    stroke: []
  };
  
  for (const [key, style] of Object.entries(meta.styles)) {
    styles[style.styleType.toLowerCase()].push({
      id: key,
      name: style.name,
      description: style.description
    });
  }
  
  return styles;
}

Style Properties

function getStyleProperties(node) {
  return {
    fill: node.fills?.map(f => ({
      type: f.type,
      color: f.color,
      opacity: f.opacity
    })),
    stroke: node.strokes?.map(s => ({
      type: s.type,
      color: s.color
    })),
    text: node.style ? {
      fontFamily: node.style.fontFamily,
      fontSize: node.style.fontSize,
      fontWeight: node.style.fontWeight,
      lineHeightPx: node.style.lineHeightPx,
      letterSpacing: node.style.letterSpacing
    } : null,
    effect: node.effects
  };
}

Exporting Assets

Export Images

async function exportImages(client, fileKey, nodeIds, options = {}) {
  const { images } = await client.request(
    `/images/${fileKey}?ids=${nodeIds.join(',')}&format=png&scale=2`
  );
  
  return images;
}

// Usage
const images = await exportImages(
  client,
  'FILE_KEY',
  ['1:2', '3:4'],
  { format: 'png', scale: 2 }
);

// Download each
for (const [nodeId, url] of Object.entries(images)) {
  const response = await fetch(url);
  const buffer = await response.arrayBuffer();
  // Save to file...
}

Export SVG

// Get SVG
const { images } = await client.request(
  `/images/${file_KEY}?ids=NODE_ID&format=svg`
);

// Save SVG content
const svgResponse = await fetch(images[NODE_ID]);
const svgContent = await svgResponse.text();

Export Code

// Get code representation
const { code } = await client.request(
  `/files/${fileKey}/nodes?ids=${nodeId}&code=true&format=html`
);

Webhooks

Register Webhook

curl -X POST "https://api.figma.com/v2/webhooks" \
  -H "X-Figma-Token: $TOKEN" \
  -H "Content-Type: application/json" \
  -d '{
    "event_type": "FILE_NODE_CHANGED",
    "client_id": "YOUR_CLIENT_ID",
    "endpoint_url": "https://your-server.com/webhook",
    "description": "Notify on file changes"
  }'

Webhook Events

  • FILE_NODE_CHANGED - Node changed
  • FILE_COMMENT - New comment
  • FILE_VERSION_UPLOADED - Version uploaded
// Webhook handler
app.post('/webhook', (req, res) => {
  const event = req.body;
  
  switch (event.event_type) {
    case 'FILE_NODE_CHANGED':
      handleNodeChange(event);
      break;
    case 'FILE_COMMENT':
      handleComment(event);
      break;
  }
  
  res.status(200).send('OK');
});

Design to Code Example

Extract Component for Code

async function componentToCode(client, fileKey, componentId) {
  const { nodes } = await client.getFileNodes(fileKey, [componentId]);
  const node = nodes[componentId];
  
  const code = {
    name: node.name,
    width: node.absoluteBoundingBox.width,
    height: node.absoluteBoundingBox.height,
    styles: {
      backgroundColor: extractFillColor(node.fills),
      borderRadius: node.cornerRadius,
      boxShadow: extractShadow(node.effects)
    },
    children: node.children?.map((child, index) => ({
      name: child.name,
      type: child.type,
      ...getElementCode(child)
    }))
  };
  
  return code;
}

function extractFillColor(fills) {
  const fill = fills?.find(f => f.type === 'SOLID');
  if (!fill) return null;
  
  const { r, g, b } = fill.color;
  const a = fill.opacity ?? 1;
  
  return `rgba(${Math.round(r*255)}, ${Math.round(g*255)}, ${Math.round(b*255)}, ${a})`;
}

Real-World Examples

Generate CSS Variables

async function generateCSSVariables(client, fileKey) {
  const styles = await extractStyles(client, fileKey);
  
  let css = ':root {\n';
  
  // Colors
  for (const [name, style] of Object.entries(styles.fill)) {
    css += `  --color-${name}: ${style.value};\n`;
  }
  
  // Typography
  css += '\n  /* Typography */\n';
  for (const [name, style] of Object.entries(styles.text)) {
    css += `  --font-${name}: ${style.value};\n`;
  }
  
  css += '}';
  
  return css;
}

Build Component Library

async function buildComponentLibrary(client, fileKey) {
  const components = await extractComponents(client, fileKey);
  const library = { components: [] };
  
  for (const component of components) {
    const details = await getComponentDetails(client, fileKey, component.id);
    
    library.components.push({
      name: component.name,
      category: extractCategory(component.name),
      props: extractProps(details),
      code: await generateReactCode(details)
    });
  }
  
  return library;
}

Rate Limits

// API Rate limits
// - GET requests: 200/minute
// - Write requests: 200/minute
// - Bulk export: 500 images/minute

const rateLimit = {
  remaining: response.headers.get('X-RateLimit-Remaining'),
  reset: response.headers.get('X-RateLimit-Reset')
};

External Resources

Conclusion

The Figma API enables powerful design automation. Key points:

  • Use Personal Access Token for authentication
  • Fetch files, components, styles programmatically
  • Export images and SVGs in various formats
  • Set up webhooks for real-time updates
  • Build design-to-code pipelines

Common use cases: design system documentation, asset exports, design-to-code, design analysis, and automation.

Comments