---
title: "Encode content as a QR code"
method: POST
path: "/api/qr"
tags: ["QR Codes"]
---

# Encode content as a QR code

`POST /api/qr`

## Request

- Base URL: `https://www.flyn.to`
- URL: `https://www.flyn.to/api/qr`
- Auth: HTTP bearer

Stateless QR encoder for seven content types: url, text, wifi, vcard, email, phone and sms. Nothing is stored or tracked.

**Auth:** API key (`Bearer flyn_sk_live_...`) or an MCP OAuth access token (`Bearer flyn_mcp_at_...`). The dashboard session cookie is not accepted.

**Plan:** url, text and wifi with PNG and the default colours on every plan. vcard, email, phone, sms, SVG and custom colours need Pro, Lifetime or Team (a member of a paying owner's workspace has the effective plan `team`); Free gets 403 `UPGRADE_REQUIRED`.

**Rate limit:** 60 requests per 60 s per client IP, fixed window, in memory per server instance, checked before authentication.

## Request body

- QrRequest: Set `type` and the fields that type needs. Non-string field values are ignored. Free plans may use url, text and wifi with PNG and the default colours; vcard, email, phone, sms, SVG and custom colours need Pro.
  - `type` 'url' | 'text' | 'wifi' | 'vcard' | 'email' | 'phone' | 'sms': Content type. vcard, email, phone and sms are **Pro** (checked before field validation).
  - `url` string: Required for type url. Trimmed and encoded as sent: no URL validation, no safety scan, no scan marker.
  - `text` string: Required for type text. Not trimmed; whitespace only fails with "Nothing to encode.".
  - `wifiSsid` string: Required for type wifi.
  - `wifiPass` string: Wi-Fi password; left out when wifiEnc is nopass.
  - `wifiEnc` 'WPA' | 'WEP' | 'nopass': WPA3 networks use WPA.
  - `wifiHidden` boolean: Only literal true marks the network hidden.
  - `vcName` string: Required for type vcard.
  - `vcOrg` string
  - `vcPhone` string: A number without a leading + adds a warning.
  - `vcEmail` string
  - `vcUrl` string
  - `email` string: Required for type email.
  - `emailSubject` string
  - `emailBody` string
  - `phone` string: Required for type phone. Characters other than digits and + are stripped; no leading + adds a warning.
  - `smsPhone` string: Required for type sms. Characters other than digits and + are stripped.
  - `smsBody` string
  - `format` 'png' | 'svg': Case-sensitive. svg is **Pro**.
  - `size` union: Target width in px (number or numeric string). Clamped to 64..2048; the output snaps down to whole modules.
    - number
    - string
  - `margin` union: Quiet zone in modules, clamped to 4..32.
    - number
    - string
  - `level` 'L' | 'M' | 'Q' | 'H': Error correction; upper-cased first.
  - `fg` string: Foreground colour. Anything but the default is **Pro**; equal to bg is 400.
  - `bg` string: Background colour. Anything but the default is **Pro**.

## Response `200`

The rendered QR code.

- QrResponse
  - `type` 'url' | 'text' | 'wifi' | 'vcard' | 'email' | 'phone' | 'sms', required
  - `label` string, required: Short human label for the content.
  - `payload` string, required: The exact string encoded in the QR code.
  - `qrDataUrl` string, required
  - `svg` string: Present only when format=svg.
  - `qr` QrApplied, required: The render options actually applied. `size` is the real pixel width after snapping to whole modules.
    - `size` integer, required
    - `margin` integer, required
    - `level` 'L' | 'M' | 'Q' | 'H', required
    - `fg` string, required
    - `bg` string, required
    - `format` 'png' | 'svg', required
    - `moduleSize` integer, required: Pixels per module.
    - `symbolModules` integer, required: Modules per side of the QR symbol, quiet zone excluded.
  - `warnings` string[]: Present when a phone, sms or vcard number has no leading +.

## Other responses

- `400`: Body, type, field or option errors. Messages include "Body must be valid JSON.", "type must be one of: url, text, wifi, vcard, email, phone, sms.", "wifiEnc must be one of: WPA, WEP, nopass. WPA3 networks use WPA.", "A wifi QR code needs \"wifiSsid\".", render option errors, and "That is too much data for a QR code (...)".
- `401`: Missing header, wrong prefix, unknown or revoked key, expired key, or an invalid MCP OAuth token. Messages: "Missing or invalid API key. Use: Authorization: Bearer flyn_sk_live_...", "Invalid or revoked API key", "API key has expired", "Invalid or expired OAuth token".
- `403`: A Pro content type, SVG or custom colours on Free (code `UPGRADE_REQUIRED`), or a suspended account.
- `429`: More than 60 requests in the window. Counted per client IP. Retry-After gives the seconds until the window resets.
- `500`: Unexpected render error.

---

[API](https://skmtc.dev/flyn/apis/flyn-api.md) · [All operations](https://skmtc.dev/flyn/apis/flyn-api/llms.txt) · [OpenAPI document](https://skmtc.dev/flyn/apis/flyn-api/revisions/977962a98ccb?raw)
