FOR DEVELOPERS AND AI TOOLS

Make and change QR codes from AI apps and your own code

HueQR has an MCP server, so Claude, ChatGPT and Cursor can create dynamic QR codes, change where they go and read their scans when you ask. It also has a REST API for your own scripts and apps. Both come with Pro and Organisation and work on the same codes you see in the app.

Connect an AI app with MCP

MCP (Model Context Protocol) is how AI apps use other products for you. Add HueQR once, then ask in plain words: "make a QR code for our spring menu and file it under Harbor Yoga", "point the window poster code at the new booking page", "which of my codes got the most scans this month?"

https://hueqr.com/mcp

Claude and ChatGPT

In the app's connector settings, add a custom connector and paste the address above. You are sent to HueQR to sign in and press Allow. That is all: no key to copy. You can remove the app's access anytime in HueQR under API and MCP.

Claude Code

claude mcp add --transport http hueqr https://hueqr.com/mcp

Cursor and other tools with a config file

{
  "mcpServers": {
    "hueqr": { "url": "https://hueqr.com/mcp" }
  }
}

A tool that cannot open a sign-in page can send an API key instead, as the header Authorization: Bearer hq_live_...

What the AI app can do

  • Create a code, or up to 50 at once, in a saved brand template
  • Change where a code goes, rename it, pause it, resume it or delete it
  • Set smart rules: "send iPhones to the App Store and Android to Google Play", "show the lunch menu from 12 to 4"
  • Show a code's QR image and its scans by day, phone and city
  • List and add client workspaces, and list your domains and templates

Every link is checked for safety, exactly as in the app. A read-only connection can look but not change anything.

API keys

The account owner makes keys in the app under API and MCP. A key is shown once, so copy it then. Each key is read and write or read only, and can be limited to one client workspace. Revoking a key stops it at once.

Send the key as a bearer token on every request. Keep keys on your server: anyone holding one can change your codes.

curl https://hueqr.com/api/v1/codes \
  -H "Authorization: Bearer hq_live_..."

REST API

The base address is https://hueqr.com/api/v1. Requests and answers are JSON. Lists page with next_cursor. The same reference is available as OpenAPI 3.1.

Create a code

curl -X POST https://hueqr.com/api/v1/codes \
  -H "Authorization: Bearer hq_live_..." \
  -H "Content-Type: application/json" \
  -d '{
    "name": "Spring menu",
    "destination": "https://example.com/menu",
    "placement": "Window poster"
  }'
{
  "id": "4b1f0c1e-...",
  "name": "Spring menu",
  "type": "website",
  "status": "live",
  "destination": "https://example.com/menu",
  "short_url": "https://hueqr.com/Xk3pQ",
  "domain": "hueqr.com",
  "placement": "Window poster",
  "client_id": null,
  "created_at": "2026-11-06T09:30:00Z",
  "updated_at": "2026-11-06T09:30:00Z"
}

Change where it goes, after printing

curl -X PATCH https://hueqr.com/api/v1/codes/4b1f0c1e-... \
  -H "Authorization: Bearer hq_live_..." \
  -H "Content-Type: application/json" \
  -d '{ "destination": "https://example.com/summer-menu" }'

Every endpoint

  • GET/codes

    List codes, newest first

    QUERY

    limit
    1 to 100, default 25.
    cursor
    next_cursor from the last page.
    client_id
    Only one client's codes.
    status
    live, paused or blocked.
    type
    Only one type of code.
    q
    Only names containing this text.

    RETURNS { data: Code[], next_cursor }

  • POST/codesWRITE KEY

    Create a code

    BODY

    name
    A name to recognise the code by. Required.
    type
    What it opens: website, vcard, wifi, text, links, email, sms, phone. Default website.
    destination
    Website codes: the link it sends people to.
    placement
    Where it will be printed, to compare placements in analytics.
    client_id
    File it under this client workspace. It then uses the client's domain.
    domain
    A connected domain for the short link. Default: the client's domain, else hueqr.com.
    template_id
    Use a saved brand template's design. Default: plain black.
    design
    Or send a design object (colors, shapes) to style it directly.
    content
    Non-website types: the Wi-Fi details, text, links, email, SMS or phone number.
    utm
    true to add UTM tags to the destination.
    rules
    Website codes: smart rules to set up with the code, in the same shape as PUT /codes/{id}/rules.

    RETURNS The new Code, with its short_url.

  • POST/codes/bulkWRITE KEY

    Create up to 100 codes

    BODY

    codes
    A list of codes, each with the same fields as POST /codes.

    RETURNS { created, failed, results: [{ index, ok, code | error }] }

  • GET/codes/{id}

    Get one code

    RETURNS Code

  • PATCH/codes/{id}WRITE KEY

    Change a code

    BODY

    destination
    A new link. Printed codes keep working.
    name
    A new name.
    placement
    A new placement.
    status
    live or paused.
    client_id
    Move it to a client, or null for none.

    RETURNS The updated Code.

  • DELETE/codes/{id}WRITE KEY

    Delete a code

    RETURNS { id, deleted: true }. Anything printed with it stops working.

  • GET/codes/{id}/qr

    Get the QR image

    QUERY

    format
    svg, png, pdf, eps. Default svg.
    size
    PNG width in pixels, 128 to 4096. Default 1024.

    RETURNS The image file, in the code's saved design.

  • GET/codes/{id}/scans

    Get scan analytics

    QUERY

    days
    1 to 90, default 30.

    RETURNS { scans, unique_scanners, previous_period_scans, by_day, devices, cities }

  • GET/codes/{id}/rules

    Get smart rules

    RETURNS { code_id, default_destination, timezone, rules: [{ id, conditions, destination, enabled, description }] }

  • PUT/codes/{id}/rulesWRITE KEY

    Set smart rules

    BODY

    rules
    The full list, in order: the first enabled rule that matches a scan wins. Each is { conditions: [...], destination, enabled }. An empty list removes every rule.

    RETURNS The rules as saved. Website codes only.

  • GET/places

    Find place ids for location rules

    QUERY

    q
    The start of a country, region or city name.

    RETURNS { data: [{ id, name, in, level }] }

  • GET/clients

    List client workspaces

    RETURNS { data: Client[] }

  • POST/clientsWRITE KEY

    Add a client workspace

    BODY

    name
    The client's name. Required.
    website
    Their website, for brand match.
    domain
    A connected domain for their codes.

    RETURNS The new Client.

  • GET/domains

    List domains

    RETURNS { data: [{ hostname, status, default }] }

  • GET/templates

    List brand templates

    RETURNS { data: [{ id, name }] }

  • GET/usage

    Get plan usage

    RETURNS { plan, codes, scans_this_month, clients, requests_per_minute }

Smart rules

Smart rules send some scans somewhere else: by device, place, time of day, weekday, phone language, date or how many scans the code has had. They are checked in order and the first one that is on and matches wins. A scan that matches no rule goes to the code's main destination. A code can have up to 20 rules, on website codes only.

PUT /codes/{id}/rules replaces the whole list, so to change one rule, read the list, change it and send it all back. An empty list removes every rule.

curl -X PUT https://hueqr.com/api/v1/codes/4b1f0c1e-.../rules \
  -H "Authorization: Bearer hq_live_..." \
  -H "Content-Type: application/json" \
  -d '{
    "rules": [
      {
        "conditions": [{ "type": "device", "device": "ios" }],
        "destination": "https://apps.apple.com/app/id123"
      },
      {
        "conditions": [
          { "type": "weekday", "days": ["sat", "sun"] },
          { "type": "time", "from": "10:00", "to": "15:00" }
        ],
        "destination": "https://example.com/brunch"
      }
    ]
  }'

Every condition on a rule has to match, and a rule uses each type once at most. Times, weekdays and dates are read in your account's timezone, which the rules come back with.

device
{ "type": "device", "device": "ios" | "android" | "desktop" }
location
{ "type": "location", "places": ["US", "CA-ON", "CA-ON/toronto"] } with place ids from the places search. Countries are exact; regions and cities are approximate.
time
{ "type": "time", "from": "12:00", "to": "16:00" } in the account's timezone. A window may pass midnight.
weekday
{ "type": "weekday", "days": ["sat", "sun"] }
language
{ "type": "language", "languages": ["es", "pt"] } matched against the phone's first language.
dates
{ "type": "dates", "from": "2026-12-01", "to": "2026-12-31" } inclusive; either end may be left out.
scans
{ "type": "scans", "first": 100 } for the first 100 scans, or { "type": "scans", "after": 100 } from then on.

Location rules use place ids. Find them with GET /places?q=toronto, which answers with ids like CA-ON/toronto. Every rule's link gets the same safety check as the code's own.

Errors and limits

An error is always { "error": { "code", "message" } } with a matching status. The message is written for a person, so it is safe to show.

StatusCodeWhat it means
400invalid_requestA field is missing or has a value that is not allowed.
401unauthorizedNo key, or a key that is wrong or revoked.
403plan_requiredThe account is not on Pro or Organisation.
403read_only_keyA read-only key tried to change something.
404not_foundNo code, client or template with that id on this account.
422invalid_codeThe code could not be made as sent. The message says why.
400invalid_rulesA smart rule is not complete or not valid. The message names the rule and says why.
422link_blockedThe link was flagged as unsafe, so it was refused.
422code_limitThe batch would go over the plan's number of codes.
429rate_limitedToo many requests in a minute. Wait and try again.

Each key can make 60 requests a minute on Pro, and 300, 600, 1,200 on Organisation 500, 1,000, 2,500. The API and the MCP server never sit in the path of a scan, so a busy script cannot slow your codes down.

Not in the API yet: PDF codes are made in the app. Tell us what you need at hello@hueqr.com.