QR Atelier API · v1

API reference

Turn a design, the JSON the studio saves in design files, into its QR code, drawn as SVG by the studio’s engine. No key or account. Classic codes aren’t scan-tested on the server: test them with a scanner, or open the design in the studio.

Base URL
https://qratelier.app (Production)https://qr.cfstcyr.com (Production, the earlier address)
OpenAPI
/api/v1/openapi.json

POST/api/v1/codes

Make a QR code from a design

A classic design gives its classic code, byte for byte the studio’s. A picture design gives the automatic pick, scan-tested on the server. The answer is the SVG itself, or JSON with the SVG and the symbol’s details when Accept prefers application/json. The checks run in this order: preflight, method, rate limit, content type, body size, body, code.

Try it

POST https://qratelier.app/api/v1/codes

Design

https:// is added when no scheme is given.

Sent as written.

Sends this request from your browser to this site.

curl -sS -X POST 'https://qratelier.app/api/v1/codes' \
  -H 'content-type: application/json' \
  -H 'accept: image/svg+xml' \
  --data-binary '{
  "design": {
    "contentType": "url",
    "contentValues": {
      "url": {
        "url": "https://example.com"
      }
    }
  }
}' \
  -o code.svg

Response

Nothing sent yet.

Request

The design file envelope, at most 1,048,576 bytes. app and version are optional: a minimal call is just { "design": { ... } }.

application/json

CodeRequest

  • app"qr-atelier"

    Written by Save design file, so a design file posts as is.

  • versioninteger 1–4default 4

    The design version, as in design files: 1 for files written before design version 3, then the design version itself. Older designs are migrated.

  • designDesignrequired

    A design as saved by the studio. It needs a known contentType and a contentValues object; every other field falls back to its default when missing or invalid.

    • contentType"url" | "text" | "wifi" | "vcard" | "email" | "phone" | "sms" | "event" | "location" | "crypto" | "epc" | "whatsapp" | "telegram" | "app" | "paypal"required

      What the code holds. Only contentValues[contentType] is encoded.

    • contentValuesobjectrequired

      The values of each content type, keyed by type.

      • urlobject

        Open a website

        • urlstringrequireddefault ""

          https:// is added when no scheme is given.

      • textobject

        Plain text

        • textstringrequireddefault ""
      • wifiobject

        Join a Wi-Fi network

        • ssidstringrequireddefault ""
        • encryption"WPA" | "WEP" | "nopass"default "WPA"
        • hiddenbooleandefault false
        • passwordstring (password)requireddefault ""
      • vcardobject

        Save a contact card (vCard or MeCard)

        • firstNamestringdefault ""
        • lastNamestringdefault ""
        • organizationstringdefault ""

          A card needs a name, an organization, or both.

        • titlestringdefault ""
        • mobilestringdefault ""
        • workPhonestringdefault ""
        • emailstringdefault ""
        • websitestringdefault ""
        • streetstringdefault ""
        • citystringdefault ""
        • regionstringdefault ""
        • postcodestringdefault ""
        • countrystringdefault ""
        • notestringdefault ""
        • format"vcard" | "mecard"default "vcard"

          MeCard is shorter, and some older Android phones read it better. It has no job title.

      • emailobject

        Compose an email

        • tostringrequireddefault ""
        • subjectstringdefault ""
        • bodystringdefault ""
      • phoneobject

        Call a number

        • phonestringrequireddefault ""

          Include the country code so it works abroad.

      • smsobject

        Send a text message

        • phonestringrequireddefault ""
        • messagestringdefault ""
      • eventobject

        Add an event to a calendar

        • titlestringrequireddefault ""
        • locationstringdefault ""
        • startstringrequireddefault ""
        • endstringdefault ""
        • allDaybooleandefault false

          Only the dates are used.

        • timeZone"floating" | "utc"default "floating"

          With Fixed, people in other time zones see it converted to their local time.

        • reminder"none" | "start" | "10m" | "30m" | "1h" | "1d"default "none"
        • descriptionstringdefault ""
      • locationobject

        Show a place on a map

        • format"geo" | "google" | "apple"default "geo"

          Google Maps and Apple Maps links also open on a computer, and can search an address.

        • addressstringdefault ""

          Or enter exact coordinates below.

        • latstringdefault ""
        • lngstringdefault ""
        • labelstringdefault ""
      • cryptoobject

        Request a Bitcoin or Ethereum payment

        • currency"bitcoin" | "ethereum"default "bitcoin"
        • addressstringrequireddefault ""
        • amountstringdefault ""
        • labelstringdefault ""
      • epcobject

        SEPA credit transfer (EPC / GiroCode)

        • namestringrequireddefault ""
        • ibanstringrequireddefault ""
        • bicstringdefault ""
        • amountstringdefault ""
        • referencestringdefault ""

          Up to 140 characters. A valid RF creditor reference is sent as a creditor reference, anything else as a message.

      • whatsappobject

        Open a WhatsApp chat with a number

        • phonestringrequireddefault ""

          With the country code: WhatsApp needs the full international number.

        • messagestringdefault ""
      • telegramobject

        Open a Telegram chat with a username

        • usernamestringrequireddefault ""

          A public username, or paste a t.me link.

      • appobject

        Open an app on the App Store or Google Play

        • store"apple" | "google"default "apple"
        • appleIdstringrequireddefault ""

          The number after “id” in the app’s App Store link, or paste the link.

        • packagestringrequireddefault ""

          The id= part of the app’s Google Play link, or paste the link.

      • paypalobject

        Ask for a payment on PayPal.me

        • usernamestringrequireddefault ""

          The name after paypal.me/, or paste your link (then enter its amount below).

        • amountstringdefault ""
        • currency"account" | "AUD" | "BRL" | "CAD" | "CHF" | "CZK" | "DKK" | "EUR" | "GBP" | "HKD" | "HUF" | "JPY" | "MXN" | "NOK" | "NZD" | "PLN" | "SEK" | "SGD" | "TWD" | "USD"default "account"
    • mode"classic" | "image"default "classic"

      classic, or image for a picture code (needs picture).

    • ecl"L" | "M" | "Q" | "H"default "M"

      Error correction level. A logo can raise it: the answer is the smallest level that still reads under the logo.

    • styleobject

      Colours, dot and eye shapes, quiet zone, logo and frame, as in the studio.

      • foregroundobject | object | object
        • variant 1object
          • type"solid"
          • colorstringdefault "#111111"
        • variant 2object
          • type"linear" | "radial"
          • fromstringdefault "#000000"
          • tostringdefault "#000000"
          • anglenumber
        • variant 3object
          • type"palette"
          • colorsarray
          • arrangement"scatter" | "diagonal" | "radial" | "picture"default "scatter"
      • backgroundobject | object
        • variant 1object
          • type"solid"
          • colorstringdefault "#ffffff"
        • variant 2object
          • type"linear" | "radial"
          • fromstringdefault "#000000"
          • tostringdefault "#000000"
          • anglenumber
      • transparentBackgroundbooleandefault false
      • dotShape"square" | "dots" | "rounded" | "extra-rounded" | "classy" | "diamond" | "star" | "heart" | "vertical" | "horizontal" | "tiny" | "custom"default "square"
      • dotScalenumber
      • eyeFrameShape"square" | "rounded" | "extra-rounded" | "circle" | "leaf" | "dots" | "custom"default "square"
      • eyeBallShape"square" | "rounded" | "circle" | "leaf" | "diamond" | "custom"default "square"
      • customShapesobject
        • dotany | null
        • eyeFrameany | null
        • eyeBallany | null
      • eyeFrameColorstring | null
      • eyeBallColorstring | null
      • marginnumber
      • cornerRadiusnumber
      • logoobject
        • srcstring | null
        • sizenumber
        • clearBehindbooleandefault true
        • paddingnumber
        • shape"square" | "rounded" | "circle"default "rounded"
        • iconobject | object | null
      • frameobject
        • style"none" | "banner-bottom" | "banner-top" | "box" | "ticket"default "none"
        • textstring
        • colorstringdefault "#111111"
        • textColorstringdefault "#ffffff"
      • imageMode"modules" | "halftone" | "photo"default "modules"
      • colorSource"style" | "picture"default "style"
      • detail"off" | "subject"default "subject"
      • halftoneDither"ordered" | "diffusion" | "atkinson" | "threshold"default "ordered"
      • shape"square" | "circle"default "square"
      • ringFillbooleandefault true
    • pictureobject | null

      Picture mode: a base64 data: URL, at most 768 px and 524,288 bytes; invalid_picture lists the formats read.

      • variant 1object
        • namestring
        • srcstring
        • placementobject | null
          • variant 1object
            • xnumber
            • ynumber
            • scalenumber
            • rotationnumber
            • flipbooleandefault false
        • toneobject | null
          • variant 1object
            • brightnessnumber
            • contrastnumber
            • midtonesnumber
            • smoothnumber
        • maskobject | null
          • variant 1object
            • wnumber
            • hnumber
            • datastring
        • textobject | null
          • variant 1object
            • valuestring
            • font"sans" | "serif" | "rounded" | "mono" | "display"default "sans"
            • solidbooleandefault true
    • pictureSettingsobject

      Picture mode: strength, invert, background, lock, clearance and detail (at most 6 versions).

      • strengthnumber
      • detailnumber
      • clearancenumber
      • invertbooleandefault false
      • background"light" | "dark"default "light"
      • lockobject | null
        • variant 1object
          • ecl"L" | "M" | "Q" | "H"
          • versioninteger 1–40
          • maskinteger 0–7 | null
    • variantIndexnumber | null
    • retouchobject | null

      Ignored: retouches belong to a variant picked in the studio.

      • variant 1object
        • keystring
        • cellsarray
Example: A link
{
  "design": {
    "contentType": "url",
    "contentValues": {
      "url": {
        "url": "https://example.com"
      }
    }
  }
}
Example: A Wi-Fi network
{
  "design": {
    "contentType": "wifi",
    "contentValues": {
      "wifi": {
        "ssid": "Studio",
        "encryption": "WPA",
        "password": "correct horse",
        "hidden": false
      }
    },
    "ecl": "Q"
  }
}
Example: Colours, shapes and a frame
{
  "design": {
    "contentType": "text",
    "contentValues": {
      "text": {
        "text": "Hello from the API"
      }
    },
    "style": {
      "foreground": {
        "type": "solid",
        "color": "#006241"
      },
      "dotShape": "dots",
      "eyeFrameShape": "rounded",
      "eyeBallShape": "circle",
      "frame": {
        "style": "banner-bottom",
        "text": "Scan me",
        "color": "#006241",
        "textColor": "#ffffff"
      }
    }
  }
}
Example: A logo

The code grows until it still reads with every module under the logo flipped.

{
  "design": {
    "contentType": "url",
    "contentValues": {
      "url": {
        "url": "https://example.com"
      }
    },
    "style": {
      "logo": {
        "src": "data:image/svg+xml;base64,PHN2ZyB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciIHZpZXdCb3g9IjAgMCAxMCAxMCI+PGNpcmNsZSBjeD0iNSIgY3k9IjUiIHI9IjUiIGZpbGw9IiNmNzVjMDAiLz48L3N2Zz4="
      }
    }
  }
}

Responses

200 The code: SVG by default, JSON with Accept: application/json.

image/svg+xml

string

application/json

CodeJson

  • svgstringrequired

    The code, a standalone SVG: no external references, no scripts.

  • versioninteger 1–40required

    QR version of the symbol.

  • ecl"L" | "M" | "Q" | "H"required

    Error correction level of the symbol.

  • maskinteger 0–7required

    Mask pattern of the symbol.

  • sizeinteger ≥ 21required

    Width of the symbol, in modules.

  • verifiedbooleanrequired

    True only for a picture code that passed the server’s scan test. Classic codes are always false.

Headers
HeaderTypeDescription
x-qr-versioninteger 1–40QR version of the symbol.
x-qr-ecl"L" | "M" | "Q" | "H"Error correction level of the symbol.
x-qr-maskinteger 0–7Mask pattern of the symbol.
x-qr-verified"true" | "false"true only for a picture code that passed the server’s scan test.

Errors

StatuserrorMessage
400invalid_jsonThe body is not valid JSON.
400invalid_designThe body must be { "design": { "contentType", "contentValues", ... } } with a known content type and its values; "version" (optional) is a design version and "app" (optional) is "qr-atelier".
400unsupported_versionThis design is from a newer version of QR Atelier than this API reads: send version 4.
405method_not_allowedUse POST.
413payload_too_largeThe body is over 1,048,576 bytes: send smaller pictures or logos.
415unsupported_media_typeSend the body as JSON (Content-Type: application/json).
422invalid_contentThe content is empty or invalid for its type: check contentValues[contentType].
422content_too_longThe content is too long for any QR code at this error correction level: shorten it, or lower ecl.
422logo_too_largeThe logo covers too much of the code: no version still reads with it. Make it smaller.
422design_too_complexThis design would draw too large an SVG (a long custom module shape repeated on a large code). Use a simpler shape or shorter content.
422invalid_pictureThe picture must be a WebP, PNG or JPEG data: URL (base64) that decodes.
422picture_too_largeThe picture is over 768 px on its long side: scale it down to 768 px, the size the studio stores.
422invalid_logoIn picture mode the logo must be a WebP, PNG or JPEG data: URL (base64) of at most 1024 px, or a Lucide icon from the studio. Other SVG logos are refused: use a PNG instead.
422unsupported_renderstyle.imageMode "photo" isn’t available through the API: use "modules" or "halftone", each with style.colorSource "style" or "picture".
422picture_content_too_longPicture codes take short content: about 150, 120, 105 and 95 characters of a link at levels L, M, Q and H (versions 7, 7, 8 and 9). Shorten the content, or use a classic code.
429rate_limitedToo many requests from this address: try again in 60 seconds.
500internal_errorThe server couldn’t make this code. Try again later.
Headers some errors add
HeaderTypeDescription
allow"POST, OPTIONS"The methods the route answers.
retry-after60Seconds to wait before trying again.

Limits

LimitValueNotes
Request body1,048,576 bytesLogos are data: URLs inside the design and count toward it.
Requests per address60 requests / 60 sPer IPv4 address or IPv6 /64, counted per Cloudflare location. Refused requests count too.
Picture designs per address10 requests / 60 sAmong the requests above: picture codes cost up to two seconds of CPU.
Wait after a refusal60 sSent as Retry-After with 429.
Picture size768 pxOn its long side, the size the studio stores.
Logo size in picture mode1,024 pxOn its long side.
Picture or logo file524,288 bytesDecoded size of each file in picture mode.
Picture content lengthL: version 7, M: version 7, Q: version 8, H: version 9The QR version the content’s classic code may need, per error correction level. Longer content rarely passes the scan test and needs a classic code.
Picture detail6 versionsExtra versions the search explores; more is lowered to it.
Design version readversion 4Newer designs are refused with unsupported_version.