Documentation menu

QR Codes API

The QR API has one endpoint: it creates up to 20 trackable QR codes in a single request. Each QR is backed by a new short link, and its image is served from a hosted MASK URL you can download or embed. There is no list, update, or delete endpoint, and the API does not set colors, size, error correction, or a logo — style QR codes in the dashboard instead.

Authentication and limits

Send your API key as a bearer token. Keys belong to one workspace, and every QR created here belongs to that workspace.

RequirementDetail
AuthorizationBearer mk_...
links:writeThe scope this endpoint checks. Creating a QR also creates a short link, so it is a link write. A key without it returns 403.
PlanThe API is a Growth feature. Keys stop working if the workspace returns to the free plan.
Rate limit60 requests per minute per key. Over the limit returns 429 with the rate-limit headers.

Create QR codes

Send between 1 and 20 destinations. For each one MASK creates a short link and a QR code pointing at it, and returns the hosted image URL. The request is processed item by item, so a response can contain both created and skipped entries.

POST/api/v1/qr

Request body

FieldTypeRequiredDescription
itemsobject[]Yes1 to 20 entries. More than 20 is a 400.
items[].urlstringYesThe destination the QR resolves to. Must be http or https.
items[].namestringNoInternal label for the QR, up to 120 characters. Defaults to API QR.
Request
curl -X POST https://mask.pk/api/v1/qr \
  -H "Authorization: Bearer mk_live_abc123def456" \
  -H "Content-Type: application/json" \
  -d '{
    "items": [
      { "url": "https://example.com/menu", "name": "Table tent" },
      { "url": "https://example.com/offer" }
    ]
  }'
Response: 201 Created
{
  "data": {
    "created": [
      {
        "url": "https://example.com/menu",
        "qrId": "clx8qr9a0001",
        "slug": "a1b2c3",
        "imageUrl": "https://mask.pk/api/qr/clx8qr9a0001/image"
      },
      {
        "url": "https://example.com/offer",
        "qrId": "clx8qr9a0002",
        "slug": "d4e5f6",
        "imageUrl": "https://mask.pk/api/qr/clx8qr9a0002/image"
      }
    ],
    "skipped": []
  }
}

Response fields

FieldTypeDescription
created[].urlstringThe destination you sent, echoed back so you can match rows to your input
created[].qrIdstringId of the new QR code
created[].slugstringSlug of the short link created behind the QR, on the default domain
created[].imageUrlstringHosted image for this QR. See The QR image.
skipped[].urlstringA destination no QR was created for
skipped[].reasonstringWhy it was skipped. See the table below.

Partial success

A request where some items succeed and others do not still returns 201. Read data.skipped on every response rather than treating a 201 as all-or-nothing. Skipped items are not retried for you and consume no quota.

ReasonMeaning
Plan limit reachedThe batch ran past the remaining QR or link allowance. Earlier items in the same request were created.
Bio page URL not allowedThe destination is a MASK bio page. Create a QR for that page from the dashboard instead.
Failed to createThe link or QR could not be written. Safe to retry that item on its own.
Response: 201 Created — partial
{
  "data": {
    "created": [
      {
        "url": "https://example.com/menu",
        "qrId": "clx8qr9a0001",
        "slug": "a1b2c3",
        "imageUrl": "https://mask.pk/api/qr/clx8qr9a0001/image"
      }
    ],
    "skipped": [
      { "url": "https://example.com/offer", "reason": "Plan limit reached" }
    ]
  }
}

Quota

Each QR consumes one QR code and one short link from your plan, because the QR is created together with the link it resolves through. The batch is capped by whichever of the two allowances runs out first: if you have room for 3 more links and 10 more QR codes, a batch of 5 creates 3 and skips 2. When neither has room, the whole request returns 403 and nothing is created.

The QR image

The imageUrl in the response is the image for that QR. It is a public URL and takes no API key, so you can put it straight into a template, an email, or a print job.

GET/api/qr/:qrId/image
ParameterTypeDescription
formatstringsvg (default) or png. PNG is rendered at 512px; use SVG for print, where it scales to any size.
Download as PNG
curl "https://mask.pk/api/qr/clx8qr9a0001/image?format=png" -o qr-code.png
Download as SVG
curl "https://mask.pk/api/qr/clx8qr9a0001/image?format=svg" -o qr-code.svg

The image encodes the MASK scan address for that QR, not the destination itself. That is what makes the code trackable: scans resolve through MASK, and you can repoint the short link later without reprinting.

Errors

Every failure returns a single error string. These are request-level failures; a problem with one item in an otherwise valid batch appears in data.skipped instead.

StatusMeaning
400The body is malformed: no items, an empty array, more than 20 entries, a name over 120 characters, or a URL that is not http/https
401Missing, revoked, expired, or non-paid API key
403Insufficient scope when the key lacks links:write, or QR or link quota reached for this plan. when there is no room for even one QR
429Rate limit exceeded
500Unexpected server error