DocsAPI ReferenceHTML to Figma

HTML to Figma

Convert an HTML document into a Figma-importable file via a single HTTPS request, authenticated with an Open API Key.

You’ll need an API key
This endpoint is authenticated with an Open API Key (prefix sk_). Your key is shown once; store it somewhere safe.
Create an API key →

Quick start

  1. Go to the API Keys dashboard and click Create API Key.
  2. Copy the full key (starts with sk_) — it is displayed only once.
  3. Send your first request:
curl -X POST https://api.copyto.design/v1/open/html_to_figma \
  -H "Authorization: Bearer sk_your_key_here" \
  -H "Content-Type: application/json" \
  -d '{"html":"<h1 style=\"color:#2563eb\">Hello, Figma</h1>"}'

The response body is the converted Figma file payload (see Response).

Endpoint

POST https://api.copyto.design/v1/open/html_to_figma

Only POST is supported. Content-Type must be application/json.

Authentication

Pass your Open API Key in the Authorization header:

Authorization: Bearer sk_...

Important notes:

  • An Open API Key is only accepted on this endpoint. Using it against any other path returns 403 endpoint not accessible with api key.
  • Session tokens issued by the copyto.design web app are a different credential and are not interchangeable with sk_ keys in your integrations.
  • Deleting a key from the dashboard removes it from your list immediately, but the underlying token stays valid until its natural expiry. Rotate keys if you believe one is compromised.

Request body

At minimum, provide either html or url.

{
  "html": "<!doctype html><html>...</html>",
  "url": "https://example.com",
  "baseUrl": "https://cdn.example.com",
  "options": {
    "viewportWidth": 1440,
    "viewportHeight": 900,
    "deviceScaleFactor": 1,
    "waitUntil": "networkidle",
    "waitForSelector": ".hero",
    "timeoutMs": 15000
  }
}

Fields

FieldTypeRequiredDescription
htmlstringconditionalSingle-file HTML document. Required if url is not provided.
urlstringconditionalPublic URL to fetch and convert. Required if html is not provided.
baseUrlstringoptionalBase URL used to resolve relative assets in html. Ignored when url is provided.
options.viewportWidthnumberoptionalViewport width in CSS pixels. Default 1440.
options.viewportHeightnumberoptionalViewport height. Omit to auto-size to the rendered document height.
options.deviceScaleFactornumberoptionalDevice pixel ratio. Default 1.
options.waitUntilstringoptionalNavigation wait condition: load, domcontentloaded, or networkidle.
options.waitForSelectorstringoptionalCSS selector to wait for before capturing.
options.timeoutMsnumberoptionalGlobal timeout in milliseconds. Default 15000.

Response

A successful request returns 200 OK with a JSON string body — the base64-encoded Figma Kiwi (.fig) binary produced by the converter. Write it to a file and open it in Figma, or feed it into the Copy to Design Figma plugin.

HTTP/1.1 200 OK
Content-Type: application/json

"AAECAwQF...Base64EncodedFigBinary..."

Examples

cURL

curl -X POST https://api.copyto.design/v1/open/html_to_figma \
  -H "Authorization: Bearer sk_your_key_here" \
  -H "Content-Type: application/json" \
  -d '{
    "html": "<!doctype html><html><body><h1>Hello</h1></body></html>",
    "options": { "viewportWidth": 1280 }
  }' \
  -o output.fig.b64

JavaScript (fetch)

const res = await fetch('https://api.copyto.design/v1/open/html_to_figma', {
  method: 'POST',
  headers: {
    Authorization: `Bearer ${process.env.COPYTO_API_KEY}`,
    'Content-Type': 'application/json',
  },
  body: JSON.stringify({
    html: '<!doctype html><html><body><h1>Hello</h1></body></html>',
    options: { viewportWidth: 1280 },
  }),
});
 
if (!res.ok) {
  throw new Error(`convert failed: ${res.status} ${await res.text()}`);
}
 
const base64Fig = await res.json();
await fs.promises.writeFile('output.fig', Buffer.from(base64Fig, 'base64'));

Python (requests)

import base64
import os
import requests
 
resp = requests.post(
    'https://api.copyto.design/v1/open/html_to_figma',
    headers={
        'Authorization': f"Bearer {os.environ['COPYTO_API_KEY']}",
        'Content-Type': 'application/json',
    },
    json={
        'url': 'https://example.com',
        'options': {'waitUntil': 'networkidle'},
    },
    timeout=60,
)
resp.raise_for_status()
 
with open('output.fig', 'wb') as f:
    f.write(base64.b64decode(resp.json()))

Errors

All error responses use the standard { code, message } envelope.

HTTPWhen
401Authorization header missing, malformed, or the sk_ key is invalid / expired.
403Valid sk_ key used on a path that is not listed as an open endpoint.
402Your plan’s monthly conversion quota is exhausted (sorry, you have used up all your credit). Upgrade from Pricing to continue.
429Per-IP rate limit hit. Back off and retry with exponential delay.
500Upstream conversion failure. Retry once; if it persists, contact support.

Usage and limits

  • Quota is counted against the copy_to_design product on the key owner’s account. Calls via sk_ keys consume the same monthly balance as calls from the web app.
  • Requests are rate-limited per source IP. For production workloads, keep requests serial or add a modest concurrency cap.
  • Payload size is bounded by your current plan (2 MB on Free, 20 MB on paid plans).

Next steps


© 2026 $copyto.design. Transform any design to Figma.