QR codes
Create QR codes for links, style them, add logos and download images.
A QR code points at one of your links, so you can change where it goes later without reprinting. Scans are counted separately from other clicks.
Every path below starts with https://bgum.me/api/v1/workspaces/{workspaceId}. Send your API key in the Authorization header as described in the API overview.
| Operation | Method and path |
|---|---|
| Create a QR code | POST /qr-codes |
| List QR codes | GET /qr-codes |
| Get a QR code | GET /qr-codes/{qrId} |
| Change a QR code | PATCH /qr-codes/{qrId} |
| Archive a QR code | DELETE /qr-codes/{qrId} |
| Download a QR code image | GET /qr-codes/{qrId}/image.{format} |
| Add or replace a logo | PUT /qr-codes/{qrId}/logo |
| Remove the logo | DELETE /qr-codes/{qrId}/logo |
Create a QR code
POST /qr-codes
Creates a QR code for a link. Uses one of the organisation's monthly QR code allowance.
- Full path
/api/v1/workspaces/{workspaceId}/qr-codes- API key scope
-
qr:write - Role needed
- Manager or above
Path parameters
| Name | Type | Required | Description |
|---|---|---|---|
workspaceId |
string | Yes | Your workspace ID, from Settings → Workspace. |
Request body
JSON (Content-Type: application/json). Leave out fields you don't need.
| Name | Type | Required | Description |
|---|---|---|---|
linkId |
string | Yes | The link the code opens. |
name |
string | No | A name to recognise it by, up to 200 characters. Defaults to the link's title or back-half. |
foreground |
string | No | Hex colour of the dark squares, e.g. #15181C (Pro and above). |
background |
string | No | Hex colour of the background, e.g. #FFFFFF (Pro and above). Must be lighter than the foreground, with contrast of at least 4:1. |
errorCorrection |
string | No | Low, Medium (default), Quartile or High (Pro and above). Higher survives more damage but makes a denser code. |
quietZone |
integer | No | Blank margin in modules, 2 to 10. Default 4 (Pro and above). |
Example request
curl
curl -X POST "https://bgum.me/api/v1/workspaces/$WORKSPACE_ID/qr-codes" \
-H "Authorization: Bearer $BGL_API_KEY" \
-H "Content-Type: application/json" \
-d '{
"linkId": "ZiZihoWXe3as",
"name": "Shop window poster"
}'
JavaScript
const res = await fetch(`https://bgum.me/api/v1/workspaces/${process.env.WORKSPACE_ID}/qr-codes`, {
method: "POST",
headers: {
Authorization: `Bearer ${process.env.BGL_API_KEY}`,
"Content-Type": "application/json",
},
body: JSON.stringify({
"linkId": "ZiZihoWXe3as",
"name": "Shop window poster"
}),
});
if (!res.ok) throw new Error(`${res.status} ${await res.text()}`);
const data = await res.json();
console.log(data);
Python
import os
import requests
res = requests.post(
f"https://bgum.me/api/v1/workspaces/{os.environ['WORKSPACE_ID']}/qr-codes",
headers={
"Authorization": f"Bearer {os.environ['BGL_API_KEY']}",
},
json={
"linkId": "ZiZihoWXe3as",
"name": "Shop window poster",
},
timeout=30,
)
res.raise_for_status()
print(res.json())
Response
201 Created · application/json
JSON
{
"id": "pSchXlIk",
"name": "Shop window poster",
"linkId": "ZiZihoWXe3as",
"shortUrl": "https://bgum.me/spring-sale",
"encodedUrl": "https://bgum.me/spring-sale?qr=pSchXlIk",
"destinationUrl": "https://example.com/spring-sale",
"foreground": "#15181C",
"background": "#FFFFFF",
"errorCorrection": "Medium",
"quietZone": 4,
"version": 3,
"scans": 0,
"createdAt": "2026-10-14T22:49:36.4637149+00:00",
"archived": false,
"hasLogo": false
}
Good to know
- encodedUrl is what the code contains: the short link plus ?qr= and the code's ID, which is how scans are told apart from clicks.
Errors
| Status | Code | Meaning |
|---|---|---|
| 404 | link.not_found | No link with that ID in this workspace (or it was deleted). |
| 422 | qr.colour_invalid | A colour isn't a six-digit hex value. |
| 422 | qr.inverted | The foreground is lighter than the background. Many scanners can't read that. |
| 422 | qr.low_contrast | The colours are too close together to scan reliably (contrast below 4:1). |
| 422 | qr.quiet_zone_invalid | The margin is outside 2 to 10 modules. |
| 422 | qr.error_correction_invalid | errorCorrection isn't one of the allowed values. |
| 429 | quota.qr_exhausted | The organisation has used this month's allowance of new QR codes. The response has limit and resetsAt fields. |
| 409 | qr.id_generation_failed | We couldn't generate a unique QR code ID. |
Any request can also return the general errors: 401 for a missing or wrong key, 403 for a missing scope or plan feature, 404 for an unknown workspace and 429 when you're sending too fast.
List QR codes
GET /qr-codes
Lists the workspace's QR codes, newest first (up to 500).
- Full path
/api/v1/workspaces/{workspaceId}/qr-codes- API key scope
-
links:read - Role needed
- Viewer or above
Path parameters
| Name | Type | Required | Description |
|---|---|---|---|
workspaceId |
string | Yes | Your workspace ID, from Settings → Workspace. |
Query parameters
| Name | Type | Required | Description |
|---|---|---|---|
linkId |
string | No | Only QR codes for this link. |
includeArchived |
boolean | No | true includes archived QR codes. Default false. |
Example request
curl
curl "https://bgum.me/api/v1/workspaces/$WORKSPACE_ID/qr-codes?linkId=ZiZihoWXe3as" \
-H "Authorization: Bearer $BGL_API_KEY"
JavaScript
const res = await fetch(`https://bgum.me/api/v1/workspaces/${process.env.WORKSPACE_ID}/qr-codes?linkId=ZiZihoWXe3as`, {
headers: {
Authorization: `Bearer ${process.env.BGL_API_KEY}`,
},
});
if (!res.ok) throw new Error(`${res.status} ${await res.text()}`);
const data = await res.json();
console.log(data);
Python
import os
import requests
res = requests.get(
f"https://bgum.me/api/v1/workspaces/{os.environ['WORKSPACE_ID']}/qr-codes?linkId=ZiZihoWXe3as",
headers={
"Authorization": f"Bearer {os.environ['BGL_API_KEY']}",
},
timeout=30,
)
res.raise_for_status()
print(res.json())
Response
200 OK · application/json
JSON
{
"items": [
{
"id": "pSchXlIk",
"name": "Shop window poster",
"linkId": "ZiZihoWXe3as",
"shortUrl": "https://bgum.me/spring-sale",
"encodedUrl": "https://bgum.me/spring-sale?qr=pSchXlIk",
"destinationUrl": "https://example.com/spring-sale",
"foreground": "#15181C",
"background": "#FFFFFF",
"errorCorrection": "Medium",
"quietZone": 4,
"version": 3,
"scans": 0,
"createdAt": "2026-10-14T22:49:36.4637149+00:00",
"archived": false,
"hasLogo": false
}
]
}
Errors
Any request can also return the general errors: 401 for a missing or wrong key, 403 for a missing scope or plan feature, 404 for an unknown workspace and 429 when you're sending too fast.
Get a QR code
GET /qr-codes/{qrId}
Returns one QR code with its scan count.
- Full path
/api/v1/workspaces/{workspaceId}/qr-codes/{qrId}- API key scope
-
links:read - Role needed
- Viewer or above
Path parameters
| Name | Type | Required | Description |
|---|---|---|---|
workspaceId |
string | Yes | Your workspace ID, from Settings → Workspace. |
qrId |
string | Yes | The QR code's ID, as returned when it was created or listed. |
Example request
curl
curl "https://bgum.me/api/v1/workspaces/$WORKSPACE_ID/qr-codes/pSchXlIk" \
-H "Authorization: Bearer $BGL_API_KEY"
JavaScript
const res = await fetch(`https://bgum.me/api/v1/workspaces/${process.env.WORKSPACE_ID}/qr-codes/pSchXlIk`, {
headers: {
Authorization: `Bearer ${process.env.BGL_API_KEY}`,
},
});
if (!res.ok) throw new Error(`${res.status} ${await res.text()}`);
const data = await res.json();
console.log(data);
Python
import os
import requests
res = requests.get(
f"https://bgum.me/api/v1/workspaces/{os.environ['WORKSPACE_ID']}/qr-codes/pSchXlIk",
headers={
"Authorization": f"Bearer {os.environ['BGL_API_KEY']}",
},
timeout=30,
)
res.raise_for_status()
print(res.json())
Response
200 OK · application/json
JSON
{
"id": "pSchXlIk",
"name": "Shop window poster",
"linkId": "ZiZihoWXe3as",
"shortUrl": "https://bgum.me/spring-sale",
"encodedUrl": "https://bgum.me/spring-sale?qr=pSchXlIk",
"destinationUrl": "https://example.com/spring-sale",
"foreground": "#15181C",
"background": "#FFFFFF",
"errorCorrection": "Medium",
"quietZone": 4,
"version": 3,
"scans": 0,
"createdAt": "2026-10-14T22:49:36.4637149+00:00",
"archived": false,
"hasLogo": false
}
Errors
| Status | Code | Meaning |
|---|---|---|
| 404 | qr.not_found | No QR code with that ID in this workspace. |
Any request can also return the general errors: 401 for a missing or wrong key, 403 for a missing scope or plan feature, 404 for an unknown workspace and 429 when you're sending too fast.
Change a QR code
PATCH /qr-codes/{qrId}
Renames or restyles a QR code. Only the fields you send change. Printed copies keep working, but reprint them to match a new style.
- Full path
/api/v1/workspaces/{workspaceId}/qr-codes/{qrId}- API key scope
-
qr:write - Role needed
- Manager or above
Path parameters
| Name | Type | Required | Description |
|---|---|---|---|
workspaceId |
string | Yes | Your workspace ID, from Settings → Workspace. |
qrId |
string | Yes | The QR code's ID, as returned when it was created or listed. |
Request body
JSON (Content-Type: application/json). Leave out fields you don't need.
| Name | Type | Required | Description |
|---|---|---|---|
name |
string | No | New name. |
foreground |
string | No | Hex colour of the dark squares. |
background |
string | No | Hex colour of the background. |
errorCorrection |
string | No | Low, Medium, Quartile or High. Codes with a logo must stay High. |
quietZone |
integer | No | Margin in modules, 2 to 10. |
Example request
curl
curl -X PATCH "https://bgum.me/api/v1/workspaces/$WORKSPACE_ID/qr-codes/pSchXlIk" \
-H "Authorization: Bearer $BGL_API_KEY" \
-H "Content-Type: application/json" \
-d '{
"foreground": "#0B3D2E",
"background": "#FFFFFF"
}'
JavaScript
const res = await fetch(`https://bgum.me/api/v1/workspaces/${process.env.WORKSPACE_ID}/qr-codes/pSchXlIk`, {
method: "PATCH",
headers: {
Authorization: `Bearer ${process.env.BGL_API_KEY}`,
"Content-Type": "application/json",
},
body: JSON.stringify({
"foreground": "#0B3D2E",
"background": "#FFFFFF"
}),
});
if (!res.ok) throw new Error(`${res.status} ${await res.text()}`);
const data = await res.json();
console.log(data);
Python
import os
import requests
res = requests.patch(
f"https://bgum.me/api/v1/workspaces/{os.environ['WORKSPACE_ID']}/qr-codes/pSchXlIk",
headers={
"Authorization": f"Bearer {os.environ['BGL_API_KEY']}",
},
json={
"foreground": "#0B3D2E",
"background": "#FFFFFF",
},
timeout=30,
)
res.raise_for_status()
print(res.json())
Response
200 OK · application/json
JSON
{
"id": "pSchXlIk",
"name": "Shop window poster",
"linkId": "ZiZihoWXe3as",
"shortUrl": "https://bgum.me/spring-sale",
"encodedUrl": "https://bgum.me/spring-sale?qr=pSchXlIk",
"destinationUrl": "https://example.com/spring-sale",
"foreground": "#0B3D2E",
"background": "#FFFFFF",
"errorCorrection": "Medium",
"quietZone": 4,
"version": 3,
"scans": 0,
"createdAt": "2026-10-14T22:49:36.4637149+00:00",
"archived": false,
"hasLogo": false
}
Errors
| Status | Code | Meaning |
|---|---|---|
| 404 | qr.not_found | No QR code with that ID in this workspace. |
| 422 | qr.colour_invalid | A colour isn't a six-digit hex value. |
| 422 | qr.inverted | The foreground is lighter than the background. Many scanners can't read that. |
| 422 | qr.low_contrast | The colours are too close together to scan reliably (contrast below 4:1). |
| 422 | qr.quiet_zone_invalid | The margin is outside 2 to 10 modules. |
| 422 | qr.error_correction_invalid | errorCorrection isn't one of the allowed values. |
| 422 | qr.logo_needs_high | Codes with a logo must use High error correction. |
Any request can also return the general errors: 401 for a missing or wrong key, 403 for a missing scope or plan feature, 404 for an unknown workspace and 429 when you're sending too fast.
Archive a QR code
DELETE /qr-codes/{qrId}
Hides the QR code from lists. Printed copies keep working, because the link does.
- Full path
/api/v1/workspaces/{workspaceId}/qr-codes/{qrId}- API key scope
-
qr:write - Role needed
- Manager or above
Path parameters
| Name | Type | Required | Description |
|---|---|---|---|
workspaceId |
string | Yes | Your workspace ID, from Settings → Workspace. |
qrId |
string | Yes | The QR code's ID, as returned when it was created or listed. |
Example request
curl
curl -X DELETE "https://bgum.me/api/v1/workspaces/$WORKSPACE_ID/qr-codes/pSchXlIk" \
-H "Authorization: Bearer $BGL_API_KEY"
JavaScript
const res = await fetch(`https://bgum.me/api/v1/workspaces/${process.env.WORKSPACE_ID}/qr-codes/pSchXlIk`, {
method: "DELETE",
headers: {
Authorization: `Bearer ${process.env.BGL_API_KEY}`,
},
});
if (!res.ok) throw new Error(`${res.status} ${await res.text()}`);
// 204 No Content: nothing to read.
Python
import os
import requests
res = requests.delete(
f"https://bgum.me/api/v1/workspaces/{os.environ['WORKSPACE_ID']}/qr-codes/pSchXlIk",
headers={
"Authorization": f"Bearer {os.environ['BGL_API_KEY']}",
},
timeout=30,
)
res.raise_for_status()
# 204 No Content: nothing to read.
Response
204 No Content
Good to know
- To stop printed codes working, pause or delete the link instead.
Errors
| Status | Code | Meaning |
|---|---|---|
| 404 | qr.not_found | No QR code with that ID in this workspace. |
Any request can also return the general errors: 401 for a missing or wrong key, 403 for a missing scope or plan feature, 404 for an unknown workspace and 429 when you're sending too fast.
Download a QR code image
GET /qr-codes/{qrId}/image.{format}
Returns the QR code as a PNG, SVG or vector PDF.
- Full path
/api/v1/workspaces/{workspaceId}/qr-codes/{qrId}/image.{format}- API key scope
-
links:read - Role needed
- Viewer or above
Path parameters
| Name | Type | Required | Description |
|---|---|---|---|
workspaceId |
string | Yes | Your workspace ID, from Settings → Workspace. |
qrId |
string | Yes | The QR code's ID, as returned when it was created or listed. |
format |
string | Yes | png (300 dpi), svg (scales to any size) or pdf (vector, 50 mm square including the margin). |
Query parameters
| Name | Type | Required | Description |
|---|---|---|---|
size |
integer | No | PNG only: width in pixels, 128 to 4,096. Default 1,024. Squares are whole pixels, so the image can be slightly smaller. |
Example request
curl
curl "https://bgum.me/api/v1/workspaces/$WORKSPACE_ID/qr-codes/pSchXlIk/image.png?size=2048" \
-H "Authorization: Bearer $BGL_API_KEY" \
-o qr.png
JavaScript
const res = await fetch(`https://bgum.me/api/v1/workspaces/${process.env.WORKSPACE_ID}/qr-codes/pSchXlIk/image.png?size=2048`, {
headers: {
Authorization: `Bearer ${process.env.BGL_API_KEY}`,
},
});
if (!res.ok) throw new Error(`${res.status} ${await res.text()}`);
const file = Buffer.from(await res.arrayBuffer()); // save as qr.png
Python
import os
import requests
res = requests.get(
f"https://bgum.me/api/v1/workspaces/{os.environ['WORKSPACE_ID']}/qr-codes/pSchXlIk/image.png?size=2048",
headers={
"Authorization": f"Bearer {os.environ['BGL_API_KEY']}",
},
timeout=30,
)
res.raise_for_status()
open("qr.png", "wb").write(res.content)
Response
200 OK · image/png, image/svg+xml or application/pdf
Good to know
- An unknown format returns 404.
Errors
| Status | Code | Meaning |
|---|---|---|
| 404 | qr.not_found | No QR code with that ID in this workspace. |
Any request can also return the general errors: 401 for a missing or wrong key, 403 for a missing scope or plan feature, 404 for an unknown workspace and 429 when you're sending too fast.
Add or replace a logo
PUT /qr-codes/{qrId}/logo
Puts a PNG logo in the middle of the code (Business). The code switches to High error correction so it still scans.
- Full path
/api/v1/workspaces/{workspaceId}/qr-codes/{qrId}/logo- API key scope
-
qr:write - Role needed
- Manager or above
- Plan
- Needs qr code logos in your plan (compare plans)
Path parameters
| Name | Type | Required | Description |
|---|---|---|---|
workspaceId |
string | Yes | Your workspace ID, from Settings → Workspace. |
qrId |
string | Yes | The QR code's ID, as returned when it was created or listed. |
Request body
The file itself, sent as Content-Type: image/png.
Example request
curl
curl -X PUT "https://bgum.me/api/v1/workspaces/$WORKSPACE_ID/qr-codes/pSchXlIk/logo" \
-H "Authorization: Bearer $BGL_API_KEY" \
-H "Content-Type: image/png" \
--data-binary @logo.png
JavaScript
import { readFile } from "node:fs/promises";
const res = await fetch(`https://bgum.me/api/v1/workspaces/${process.env.WORKSPACE_ID}/qr-codes/pSchXlIk/logo`, {
method: "PUT",
headers: {
Authorization: `Bearer ${process.env.BGL_API_KEY}`,
"Content-Type": "image/png",
},
body: await readFile("logo.png"),
});
if (!res.ok) throw new Error(`${res.status} ${await res.text()}`);
const data = await res.json();
console.log(data);
Python
import os
import requests
res = requests.put(
f"https://bgum.me/api/v1/workspaces/{os.environ['WORKSPACE_ID']}/qr-codes/pSchXlIk/logo",
headers={
"Authorization": f"Bearer {os.environ['BGL_API_KEY']}",
"Content-Type": "image/png",
},
data=open("logo.png", "rb").read(),
timeout=30,
)
res.raise_for_status()
print(res.json())
Response
200 OK · application/json
JSON
{
"id": "pSchXlIk",
"name": "Shop window poster",
"linkId": "ZiZihoWXe3as",
"shortUrl": "https://bgum.me/spring-sale",
"encodedUrl": "https://bgum.me/spring-sale?qr=pSchXlIk",
"destinationUrl": "https://example.com/spring-sale",
"foreground": "#15181C",
"background": "#FFFFFF",
"errorCorrection": "High",
"quietZone": 4,
"version": 3,
"scans": 0,
"createdAt": "2026-10-14T22:49:36.4637149+00:00",
"archived": false,
"hasLogo": true
}
Good to know
- Send the PNG file itself as the request body, not as a form. Up to 256 KB; larger requests get 413.
- A square logo with a transparent background works best. Test a printed copy before a big print run.
Errors
| Status | Code | Meaning |
|---|---|---|
| 404 | qr.not_found | No QR code with that ID in this workspace. |
| 422 | qr.logo_size | The logo is empty or larger than 256 KB. |
| 422 | qr.logo_invalid | The logo isn't a PNG we can read. |
| 422 | qr.logo_small | The logo is smaller than 16 × 16 pixels. |
Any request can also return the general errors: 401 for a missing or wrong key, 403 for a missing scope or plan feature, 404 for an unknown workspace and 429 when you're sending too fast.
Remove the logo
DELETE /qr-codes/{qrId}/logo
Removes the logo. The code keeps High error correction until you change it.
- Full path
/api/v1/workspaces/{workspaceId}/qr-codes/{qrId}/logo- API key scope
-
qr:write - Role needed
- Manager or above
Path parameters
| Name | Type | Required | Description |
|---|---|---|---|
workspaceId |
string | Yes | Your workspace ID, from Settings → Workspace. |
qrId |
string | Yes | The QR code's ID, as returned when it was created or listed. |
Example request
curl
curl -X DELETE "https://bgum.me/api/v1/workspaces/$WORKSPACE_ID/qr-codes/pSchXlIk/logo" \
-H "Authorization: Bearer $BGL_API_KEY"
JavaScript
const res = await fetch(`https://bgum.me/api/v1/workspaces/${process.env.WORKSPACE_ID}/qr-codes/pSchXlIk/logo`, {
method: "DELETE",
headers: {
Authorization: `Bearer ${process.env.BGL_API_KEY}`,
},
});
if (!res.ok) throw new Error(`${res.status} ${await res.text()}`);
const data = await res.json();
console.log(data);
Python
import os
import requests
res = requests.delete(
f"https://bgum.me/api/v1/workspaces/{os.environ['WORKSPACE_ID']}/qr-codes/pSchXlIk/logo",
headers={
"Authorization": f"Bearer {os.environ['BGL_API_KEY']}",
},
timeout=30,
)
res.raise_for_status()
print(res.json())
Response
200 OK · application/json
JSON
{
"id": "pSchXlIk",
"name": "Shop window poster",
"linkId": "ZiZihoWXe3as",
"shortUrl": "https://bgum.me/spring-sale",
"encodedUrl": "https://bgum.me/spring-sale?qr=pSchXlIk",
"destinationUrl": "https://example.com/spring-sale",
"foreground": "#15181C",
"background": "#FFFFFF",
"errorCorrection": "High",
"quietZone": 4,
"version": 3,
"scans": 0,
"createdAt": "2026-10-14T22:49:36.4637149+00:00",
"archived": false,
"hasLogo": false
}
Errors
| Status | Code | Meaning |
|---|---|---|
| 404 | qr.not_found | No QR code with that ID in this workspace. |
Any request can also return the general errors: 401 for a missing or wrong key, 403 for a missing scope or plan feature, 404 for an unknown workspace and 429 when you're sending too fast.
Something missing or unclear? Tell us and we'll improve this page.