QR Hero Developer Docs

REST API

API reference

Base URL: https://api.qrhero.com/v1. Authenticate with Authorization: Bearer <token> and Accept: application/json. All requests are scoped to the token's organization.

Machine-readable spec: https://docs.qrhero.com/api/openapi.json (OpenAPI 3.1 with typed schemas). See also token abilities.

Status

GET /v1/status status.read

Health check and token context

Returns API version, organization context, plan API limits, and the current token metadata.

Ability
Any valid token on an API-enabled plan

Example response

{
    "status": "ok",
    "version": "v1",
    "organization": {
        "ulid": "01HXYZORGULID000000000001",
        "name": "Acme Marketing",
        "slug": "acme-marketing"
    },
    "plan": {
        "code": "professional",
        "name": "Professional (annual)"
    },
    "api": {
        "rate_limit_per_min": 120,
        "calls_included_month": 50000,
        "calls_used_month": 1240
    },
    "token": {
        "name": "CI automation",
        "abilities": [
            "codes.view",
            "codes.create",
            "mcp.access"
        ]
    }
}

Response schema

Field Type Required Description
status string required
version string required
organization object required
plan ref | null optional
api object required
token object required

Code samples

curl -sS "https://api.qrhero.com/v1/status" \
  -H "Authorization: Bearer YOUR_QRHERO_TOKEN" \
  -H "Accept: application/json"
const response = await fetch('https://api.qrhero.com/v1/status', {
  method: 'GET',
  headers: {
    Authorization: 'Bearer YOUR_QRHERO_TOKEN',
    Accept: 'application/json',
  },
});

const data = await response.json();
console.log(data);
import requests

url = 'https://api.qrhero.com/v1/status'
headers = {
    'Authorization': 'Bearer YOUR_QRHERO_TOKEN',
    'Accept': 'application/json',
}

response = requests.get(url, headers=headers)
response.raise_for_status()
print(response.json())
<?php

$client = new GuzzleHttp\Client();

$response = $client->request('GET', 'https://api.qrhero.com/v1/status', [
    'headers' => [
        'Authorization' => 'Bearer YOUR_QRHERO_TOKEN',
        'Accept' => 'application/json',
    ],
]);

$data = json_decode($response->getBody()->getContents(), true);
print_r($data);
using var client = new HttpClient();
client.DefaultRequestHeaders.Authorization =
    new AuthenticationHeaderValue("Bearer", "YOUR_QRHERO_TOKEN");
client.DefaultRequestHeaders.Accept.Add(
    new MediaTypeWithQualityHeaderValue("application/json"));

var response = await client.GetAsync("https://api.qrhero.com/v1/status");
response.EnsureSuccessStatusCode();

var json = await response.Content.ReadAsStringAsync();
Console.WriteLine(json);

Organization

GET /v1/organization organization.read

Read organization profile

Returns safe organization fields (name, locale, currency, plan). Billing identifiers are excluded.

Ability
Any valid token on an API-enabled plan

Example response

{
    "data": {
        "ulid": "01HXYZORGULID000000000001",
        "name": "Acme Marketing",
        "slug": "acme-marketing",
        "locale": "en",
        "currency": "EUR",
        "plan": {
            "code": "professional",
            "name": "Professional (annual)"
        },
        "created_at": "2026-01-15T10:00:00+00:00",
        "updated_at": "2026-07-01T08:30:00+00:00"
    }
}

Response schema

Field Type Required Description
data Organization required

Code samples

curl -sS "https://api.qrhero.com/v1/organization" \
  -H "Authorization: Bearer YOUR_QRHERO_TOKEN" \
  -H "Accept: application/json"
const response = await fetch('https://api.qrhero.com/v1/organization', {
  method: 'GET',
  headers: {
    Authorization: 'Bearer YOUR_QRHERO_TOKEN',
    Accept: 'application/json',
  },
});

const data = await response.json();
console.log(data);
import requests

url = 'https://api.qrhero.com/v1/organization'
headers = {
    'Authorization': 'Bearer YOUR_QRHERO_TOKEN',
    'Accept': 'application/json',
}

response = requests.get(url, headers=headers)
response.raise_for_status()
print(response.json())
<?php

$client = new GuzzleHttp\Client();

$response = $client->request('GET', 'https://api.qrhero.com/v1/organization', [
    'headers' => [
        'Authorization' => 'Bearer YOUR_QRHERO_TOKEN',
        'Accept' => 'application/json',
    ],
]);

$data = json_decode($response->getBody()->getContents(), true);
print_r($data);
using var client = new HttpClient();
client.DefaultRequestHeaders.Authorization =
    new AuthenticationHeaderValue("Bearer", "YOUR_QRHERO_TOKEN");
client.DefaultRequestHeaders.Accept.Add(
    new MediaTypeWithQualityHeaderValue("application/json"));

var response = await client.GetAsync("https://api.qrhero.com/v1/organization");
response.EnsureSuccessStatusCode();

var json = await response.Content.ReadAsStringAsync();
Console.WriteLine(json);

Analytics

GET /v1/analytics analytics.read

Read scan analytics

Hierarchical analytics payload for the organization, a brand, or a single code.

Ability
analytics.view

Query parameters

  • range — 7, 30, or 90 (days, default 30)
  • dimension — country | device | referrer | language
  • brand_ulid — Optional brand scope
  • code_ulid — Optional code scope

Example response

{
    "data": {
        "scope_level": "organization",
        "range_days": 30,
        "totals": {
            "scans": 1240,
            "uniques": 890,
            "unique_rate": 0.718
        },
        "time_series": [
            {
                "date": "2026-06-07",
                "scans": 42
            },
            {
                "date": "2026-06-08",
                "scans": 38
            }
        ],
        "dimension": "country",
        "dimension_label": "Country",
        "dimension_breakdown": [
            {
                "label": "DK",
                "scans": 520,
                "uniques": 410
            },
            {
                "label": "DE",
                "scans": 310,
                "uniques": 240
            }
        ],
        "child_breakdown": [
            {
                "key": "01HXYZCODEULID000000000001",
                "label": "Launch 2026",
                "scans": 620,
                "uniques": 480
            }
        ]
    }
}

Response schema

Field Type Required Description
data AnalyticsPayload required

Code samples

curl -sS "https://api.qrhero.com/v1/analytics?range=30&dimension=country&brand_ulid=01HXYZBRANDULID00000000001&code_ulid=01HXYZCODEULID000000000001" \
  -H "Authorization: Bearer YOUR_QRHERO_TOKEN" \
  -H "Accept: application/json"
const response = await fetch('https://api.qrhero.com/v1/analytics?range=30&dimension=country&brand_ulid=01HXYZBRANDULID00000000001&code_ulid=01HXYZCODEULID000000000001', {
  method: 'GET',
  headers: {
    Authorization: 'Bearer YOUR_QRHERO_TOKEN',
    Accept: 'application/json',
  },
});

const data = await response.json();
console.log(data);
import requests

url = 'https://api.qrhero.com/v1/analytics?range=30&dimension=country&brand_ulid=01HXYZBRANDULID00000000001&code_ulid=01HXYZCODEULID000000000001'
headers = {
    'Authorization': 'Bearer YOUR_QRHERO_TOKEN',
    'Accept': 'application/json',
}

response = requests.get(url, headers=headers)
response.raise_for_status()
print(response.json())
<?php

$client = new GuzzleHttp\Client();

$response = $client->request('GET', 'https://api.qrhero.com/v1/analytics?range=30&dimension=country&brand_ulid=01HXYZBRANDULID00000000001&code_ulid=01HXYZCODEULID000000000001', [
    'headers' => [
        'Authorization' => 'Bearer YOUR_QRHERO_TOKEN',
        'Accept' => 'application/json',
    ],
]);

$data = json_decode($response->getBody()->getContents(), true);
print_r($data);
using var client = new HttpClient();
client.DefaultRequestHeaders.Authorization =
    new AuthenticationHeaderValue("Bearer", "YOUR_QRHERO_TOKEN");
client.DefaultRequestHeaders.Accept.Add(
    new MediaTypeWithQualityHeaderValue("application/json"));

var response = await client.GetAsync("https://api.qrhero.com/v1/analytics?range=30&dimension=country&brand_ulid=01HXYZBRANDULID00000000001&code_ulid=01HXYZCODEULID000000000001");
response.EnsureSuccessStatusCode();

var json = await response.Content.ReadAsStringAsync();
Console.WriteLine(json);
GET /v1/analytics/export analytics.export

Export analytics payload

Same scope filters as analytics read, plus csv_rows for programmatic export.

Ability
analytics.export

Query parameters

  • range — 7, 30, or 90 (days, default 30)
  • dimension — country | device | referrer | language
  • brand_ulid — Optional brand scope
  • code_ulid — Optional code scope

Example response

{
    "data": {
        "scope_level": "organization",
        "range_days": 30,
        "totals": {
            "scans": 1240,
            "uniques": 890,
            "unique_rate": 0.718
        },
        "time_series": [
            {
                "date": "2026-06-07",
                "scans": 42
            },
            {
                "date": "2026-06-08",
                "scans": 38
            }
        ],
        "dimension": "country",
        "dimension_label": "Country",
        "dimension_breakdown": [
            {
                "label": "DK",
                "scans": 520,
                "uniques": 410
            },
            {
                "label": "DE",
                "scans": 310,
                "uniques": 240
            }
        ],
        "child_breakdown": [
            {
                "key": "01HXYZCODEULID000000000001",
                "label": "Launch 2026",
                "scans": 620,
                "uniques": 480
            }
        ],
        "csv_rows": [
            {
                "date": "2026-06-07",
                "country": "DK",
                "scans": 42
            }
        ]
    }
}

Response schema

Field Type Required Description
data AnalyticsPayload required

Code samples

curl -sS "https://api.qrhero.com/v1/analytics/export?range=30&dimension=country&brand_ulid=01HXYZBRANDULID00000000001&code_ulid=01HXYZCODEULID000000000001" \
  -H "Authorization: Bearer YOUR_QRHERO_TOKEN" \
  -H "Accept: application/json"
const response = await fetch('https://api.qrhero.com/v1/analytics/export?range=30&dimension=country&brand_ulid=01HXYZBRANDULID00000000001&code_ulid=01HXYZCODEULID000000000001', {
  method: 'GET',
  headers: {
    Authorization: 'Bearer YOUR_QRHERO_TOKEN',
    Accept: 'application/json',
  },
});

const data = await response.json();
console.log(data);
import requests

url = 'https://api.qrhero.com/v1/analytics/export?range=30&dimension=country&brand_ulid=01HXYZBRANDULID00000000001&code_ulid=01HXYZCODEULID000000000001'
headers = {
    'Authorization': 'Bearer YOUR_QRHERO_TOKEN',
    'Accept': 'application/json',
}

response = requests.get(url, headers=headers)
response.raise_for_status()
print(response.json())
<?php

$client = new GuzzleHttp\Client();

$response = $client->request('GET', 'https://api.qrhero.com/v1/analytics/export?range=30&dimension=country&brand_ulid=01HXYZBRANDULID00000000001&code_ulid=01HXYZCODEULID000000000001', [
    'headers' => [
        'Authorization' => 'Bearer YOUR_QRHERO_TOKEN',
        'Accept' => 'application/json',
    ],
]);

$data = json_decode($response->getBody()->getContents(), true);
print_r($data);
using var client = new HttpClient();
client.DefaultRequestHeaders.Authorization =
    new AuthenticationHeaderValue("Bearer", "YOUR_QRHERO_TOKEN");
client.DefaultRequestHeaders.Accept.Add(
    new MediaTypeWithQualityHeaderValue("application/json"));

var response = await client.GetAsync("https://api.qrhero.com/v1/analytics/export?range=30&dimension=country&brand_ulid=01HXYZBRANDULID00000000001&code_ulid=01HXYZCODEULID000000000001");
response.EnsureSuccessStatusCode();

var json = await response.Content.ReadAsStringAsync();
Console.WriteLine(json);
GET /v1/analytics/qr-codes/{code_ulid} analytics.qr_code.read

Read QR code rollup analytics

Per-code scan analytics from the qr_code_scan_daily rollup table.

Ability
analytics.view

Query parameters

  • range — 7, 30, or 90 (days, default 30)
  • dimension — country | device | referrer | language | provider

Example response

{
    "data": {
        "qr_code": {
            "ulid": "01HXYZCODEULID000000000001",
            "name": "Launch 2026",
            "slug": "acme-marketing/launch-2026"
        },
        "range_days": 30,
        "totals": {
            "scans": 620,
            "uniques": 480,
            "unique_rate": 0.774
        },
        "time_series": [
            {
                "date": "2026-06-07",
                "scans": 22
            }
        ],
        "dimension": "country",
        "dimension_label": "Country",
        "dimension_breakdown": [
            {
                "label": "DK",
                "scans": 320,
                "uniques": 260
            }
        ]
    }
}

Response schema

Field Type Required Description
data QrCodeAnalyticsPayload required

Code samples

curl -sS "https://api.qrhero.com/v1/analytics/qr-codes/01HXYZCODEULID000000000001?range=30&dimension=country" \
  -H "Authorization: Bearer YOUR_QRHERO_TOKEN" \
  -H "Accept: application/json"
const response = await fetch('https://api.qrhero.com/v1/analytics/qr-codes/01HXYZCODEULID000000000001?range=30&dimension=country', {
  method: 'GET',
  headers: {
    Authorization: 'Bearer YOUR_QRHERO_TOKEN',
    Accept: 'application/json',
  },
});

const data = await response.json();
console.log(data);
import requests

url = 'https://api.qrhero.com/v1/analytics/qr-codes/01HXYZCODEULID000000000001?range=30&dimension=country'
headers = {
    'Authorization': 'Bearer YOUR_QRHERO_TOKEN',
    'Accept': 'application/json',
}

response = requests.get(url, headers=headers)
response.raise_for_status()
print(response.json())
<?php

$client = new GuzzleHttp\Client();

$response = $client->request('GET', 'https://api.qrhero.com/v1/analytics/qr-codes/01HXYZCODEULID000000000001?range=30&dimension=country', [
    'headers' => [
        'Authorization' => 'Bearer YOUR_QRHERO_TOKEN',
        'Accept' => 'application/json',
    ],
]);

$data = json_decode($response->getBody()->getContents(), true);
print_r($data);
using var client = new HttpClient();
client.DefaultRequestHeaders.Authorization =
    new AuthenticationHeaderValue("Bearer", "YOUR_QRHERO_TOKEN");
client.DefaultRequestHeaders.Accept.Add(
    new MediaTypeWithQualityHeaderValue("application/json"));

var response = await client.GetAsync("https://api.qrhero.com/v1/analytics/qr-codes/01HXYZCODEULID000000000001?range=30&dimension=country");
response.EnsureSuccessStatusCode();

var json = await response.Content.ReadAsStringAsync();
Console.WriteLine(json);
GET /v1/analytics/qr-codes/{code_ulid}/raw-export analytics.raw_export

Export raw scan rows for a QR code

Paginated raw qr_code_scans rows. Uses a separate, stricter per-minute rate limit.

Ability
analytics.export

Query parameters

  • range — 7, 30, or 90 (days, default 30)
  • limit — Page size (default 1000, max 5000)
  • offset — Row offset for pagination (default 0)

Example response

{
    "data": {
        "qr_code": {
            "ulid": "01HXYZCODEULID000000000001",
            "slug": "acme-marketing/launch-2026"
        },
        "rows": [
            {
                "scanned_at": "2026-07-01T08:00:00+00:00",
                "country": "DK",
                "device_type": "mobile",
                "referrer": "https://google.com"
            }
        ],
        "meta": {
            "count": 1,
            "limit": 1000,
            "offset": 0,
            "has_more": false
        }
    }
}

Response schema

Field Type Required Description
data RawExportPayload required

Code samples

curl -sS "https://api.qrhero.com/v1/analytics/qr-codes/01HXYZCODEULID000000000001/raw-export?range=30&limit=1000&offset=0" \
  -H "Authorization: Bearer YOUR_QRHERO_TOKEN" \
  -H "Accept: application/json"
const response = await fetch('https://api.qrhero.com/v1/analytics/qr-codes/01HXYZCODEULID000000000001/raw-export?range=30&limit=1000&offset=0', {
  method: 'GET',
  headers: {
    Authorization: 'Bearer YOUR_QRHERO_TOKEN',
    Accept: 'application/json',
  },
});

const data = await response.json();
console.log(data);
import requests

url = 'https://api.qrhero.com/v1/analytics/qr-codes/01HXYZCODEULID000000000001/raw-export?range=30&limit=1000&offset=0'
headers = {
    'Authorization': 'Bearer YOUR_QRHERO_TOKEN',
    'Accept': 'application/json',
}

response = requests.get(url, headers=headers)
response.raise_for_status()
print(response.json())
<?php

$client = new GuzzleHttp\Client();

$response = $client->request('GET', 'https://api.qrhero.com/v1/analytics/qr-codes/01HXYZCODEULID000000000001/raw-export?range=30&limit=1000&offset=0', [
    'headers' => [
        'Authorization' => 'Bearer YOUR_QRHERO_TOKEN',
        'Accept' => 'application/json',
    ],
]);

$data = json_decode($response->getBody()->getContents(), true);
print_r($data);
using var client = new HttpClient();
client.DefaultRequestHeaders.Authorization =
    new AuthenticationHeaderValue("Bearer", "YOUR_QRHERO_TOKEN");
client.DefaultRequestHeaders.Accept.Add(
    new MediaTypeWithQualityHeaderValue("application/json"));

var response = await client.GetAsync("https://api.qrhero.com/v1/analytics/qr-codes/01HXYZCODEULID000000000001/raw-export?range=30&limit=1000&offset=0");
response.EnsureSuccessStatusCode();

var json = await response.Content.ReadAsStringAsync();
Console.WriteLine(json);

Brands

GET /v1/brands brands.list

List brands

Returns all brands in the token organization, including brand kit and settings metadata.

Ability
brands.view

Example response

{
    "data": [
        {
            "ulid": "01HXYZBRANDULID00000000001",
            "name": "Summer Campaign",
            "slug": "summer-campaign",
            "brand_kit": {
                "primary_color": "#0f3460",
                "secondary_color": "#e94560"
            },
            "settings": {
                "locale": "en"
            },
            "primary_domain": {
                "ulid": "01HXYZDOMAINULID0000000001",
                "host": "links.example.com"
            },
            "created_at": "2026-02-01T12:00:00+00:00",
            "updated_at": "2026-07-01T08:30:00+00:00"
        }
    ]
}

Response schema

Field Type Required Description
data array<mixed> required

Code samples

curl -sS "https://api.qrhero.com/v1/brands" \
  -H "Authorization: Bearer YOUR_QRHERO_TOKEN" \
  -H "Accept: application/json"
const response = await fetch('https://api.qrhero.com/v1/brands', {
  method: 'GET',
  headers: {
    Authorization: 'Bearer YOUR_QRHERO_TOKEN',
    Accept: 'application/json',
  },
});

const data = await response.json();
console.log(data);
import requests

url = 'https://api.qrhero.com/v1/brands'
headers = {
    'Authorization': 'Bearer YOUR_QRHERO_TOKEN',
    'Accept': 'application/json',
}

response = requests.get(url, headers=headers)
response.raise_for_status()
print(response.json())
<?php

$client = new GuzzleHttp\Client();

$response = $client->request('GET', 'https://api.qrhero.com/v1/brands', [
    'headers' => [
        'Authorization' => 'Bearer YOUR_QRHERO_TOKEN',
        'Accept' => 'application/json',
    ],
]);

$data = json_decode($response->getBody()->getContents(), true);
print_r($data);
using var client = new HttpClient();
client.DefaultRequestHeaders.Authorization =
    new AuthenticationHeaderValue("Bearer", "YOUR_QRHERO_TOKEN");
client.DefaultRequestHeaders.Accept.Add(
    new MediaTypeWithQualityHeaderValue("application/json"));

var response = await client.GetAsync("https://api.qrhero.com/v1/brands");
response.EnsureSuccessStatusCode();

var json = await response.Content.ReadAsStringAsync();
Console.WriteLine(json);
POST /v1/brands brands.create

Create a brand

Ability
brands.manage

Request body schema

Field Type Required Description
name string required required string
slug string optional optional alpha_dash
brand_kit object optional optional object
settings object optional optional object
primary_domain_ulid string optional optional ULID

Example response

{
    "data": {
        "ulid": "01HXYZBRANDULID00000000001",
        "name": "Summer Campaign",
        "slug": "summer-campaign",
        "brand_kit": {
            "primary_color": "#0f3460",
            "secondary_color": "#e94560"
        },
        "settings": {
            "locale": "en"
        },
        "primary_domain": {
            "ulid": "01HXYZDOMAINULID0000000001",
            "host": "links.example.com"
        },
        "created_at": "2026-02-01T12:00:00+00:00",
        "updated_at": "2026-07-01T08:30:00+00:00"
    }
}

Response schema

Field Type Required Description
data Brand required

Code samples

curl -sS -X POST "https://api.qrhero.com/v1/brands" \
  -H "Authorization: Bearer YOUR_QRHERO_TOKEN" \
  -H "Accept: application/json" \
  -H "Content-Type: application/json" \
  -d '{
    "name": "Automation token",
    "slug": "launch-2026",
    "brand_kit": {
        "primary_color": "#4f46e5"
    },
    "settings": {
        "locale": "en"
    },
    "primary_domain_ulid": "01HXYZDOMAINULID0000000001"
}'
const response = await fetch('https://api.qrhero.com/v1/brands', {
  method: 'POST',
  headers: {
    Authorization: 'Bearer YOUR_QRHERO_TOKEN',
    Accept: 'application/json',
    'Content-Type': 'application/json',
  },
  body: JSON.stringify({
    "name": "Automation token",
    "slug": "launch-2026",
    "brand_kit": {
        "primary_color": "#4f46e5"
    },
    "settings": {
        "locale": "en"
    },
    "primary_domain_ulid": "01HXYZDOMAINULID0000000001"
}),
});

const data = await response.json();
console.log(data);
import requests

url = 'https://api.qrhero.com/v1/brands'
headers = {
    'Authorization': 'Bearer YOUR_QRHERO_TOKEN',
    'Accept': 'application/json',
    'Content-Type': 'application/json',
}
payload = {
    "name": "Automation token",
    "slug": "launch-2026",
    "brand_kit": {
        "primary_color": "#4f46e5"
    },
    "settings": {
        "locale": "en"
    },
    "primary_domain_ulid": "01HXYZDOMAINULID0000000001"
}

response = requests.post(url, headers=headers, json=payload)
response.raise_for_status()
print(response.json())
<?php

$client = new GuzzleHttp\Client();

$response = $client->request('POST', 'https://api.qrhero.com/v1/brands', [
    'headers' => [
        'Authorization' => 'Bearer YOUR_QRHERO_TOKEN',
        'Accept' => 'application/json',
        'Content-Type' => 'application/json',
    ],
    'json' => {
    "name": "Automation token",
    "slug": "launch-2026",
    "brand_kit": {
        "primary_color": "#4f46e5"
    },
    "settings": {
        "locale": "en"
    },
    "primary_domain_ulid": "01HXYZDOMAINULID0000000001"
},
]);

$data = json_decode($response->getBody()->getContents(), true);
print_r($data);
using var client = new HttpClient();
client.DefaultRequestHeaders.Authorization =
    new AuthenticationHeaderValue("Bearer", "YOUR_QRHERO_TOKEN");
client.DefaultRequestHeaders.Accept.Add(
    new MediaTypeWithQualityHeaderValue("application/json"));

var content = new StringContent(
    '{"name":"Automation token","slug":"launch-2026","brand_kit":{"primary_color":"#4f46e5"},"settings":{"locale":"en"},"primary_domain_ulid":"01HXYZDOMAINULID0000000001"}',
    Encoding.UTF8,
    "application/json");

var response = await client.POSTAsync("https://api.qrhero.com/v1/brands", content);
response.EnsureSuccessStatusCode();

var json = await response.Content.ReadAsStringAsync();
Console.WriteLine(json);
PATCH /v1/brands/{brand_ulid} brands.update

Update a brand

Partial update of brand fields. Omitted keys are left unchanged.

Ability
brands.manage

Request body schema

Field Type Required Description
name string optional optional string
slug string optional optional alpha_dash
brand_kit object optional optional object
settings object optional optional object
primary_domain_ulid string optional optional ULID

Example response

{
    "data": {
        "ulid": "01HXYZBRANDULID00000000001",
        "name": "Summer Campaign",
        "slug": "summer-campaign",
        "brand_kit": {
            "primary_color": "#0f3460",
            "secondary_color": "#e94560"
        },
        "settings": {
            "locale": "en"
        },
        "primary_domain": {
            "ulid": "01HXYZDOMAINULID0000000001",
            "host": "links.example.com"
        },
        "created_at": "2026-02-01T12:00:00+00:00",
        "updated_at": "2026-07-01T08:30:00+00:00"
    }
}

Response schema

Field Type Required Description
data Brand required

Code samples

curl -sS -X PATCH "https://api.qrhero.com/v1/brands/01HXYZBRANDULID00000000001" \
  -H "Authorization: Bearer YOUR_QRHERO_TOKEN" \
  -H "Accept: application/json" \
  -H "Content-Type: application/json" \
  -d '{
    "name": "Automation token",
    "slug": "launch-2026",
    "brand_kit": {
        "primary_color": "#4f46e5"
    },
    "settings": {
        "locale": "en"
    },
    "primary_domain_ulid": "01HXYZDOMAINULID0000000001"
}'
const response = await fetch('https://api.qrhero.com/v1/brands/01HXYZBRANDULID00000000001', {
  method: 'PATCH',
  headers: {
    Authorization: 'Bearer YOUR_QRHERO_TOKEN',
    Accept: 'application/json',
    'Content-Type': 'application/json',
  },
  body: JSON.stringify({
    "name": "Automation token",
    "slug": "launch-2026",
    "brand_kit": {
        "primary_color": "#4f46e5"
    },
    "settings": {
        "locale": "en"
    },
    "primary_domain_ulid": "01HXYZDOMAINULID0000000001"
}),
});

const data = await response.json();
console.log(data);
import requests

url = 'https://api.qrhero.com/v1/brands/01HXYZBRANDULID00000000001'
headers = {
    'Authorization': 'Bearer YOUR_QRHERO_TOKEN',
    'Accept': 'application/json',
    'Content-Type': 'application/json',
}
payload = {
    "name": "Automation token",
    "slug": "launch-2026",
    "brand_kit": {
        "primary_color": "#4f46e5"
    },
    "settings": {
        "locale": "en"
    },
    "primary_domain_ulid": "01HXYZDOMAINULID0000000001"
}

response = requests.patch(url, headers=headers, json=payload)
response.raise_for_status()
print(response.json())
<?php

$client = new GuzzleHttp\Client();

$response = $client->request('PATCH', 'https://api.qrhero.com/v1/brands/01HXYZBRANDULID00000000001', [
    'headers' => [
        'Authorization' => 'Bearer YOUR_QRHERO_TOKEN',
        'Accept' => 'application/json',
        'Content-Type' => 'application/json',
    ],
    'json' => {
    "name": "Automation token",
    "slug": "launch-2026",
    "brand_kit": {
        "primary_color": "#4f46e5"
    },
    "settings": {
        "locale": "en"
    },
    "primary_domain_ulid": "01HXYZDOMAINULID0000000001"
},
]);

$data = json_decode($response->getBody()->getContents(), true);
print_r($data);
using var client = new HttpClient();
client.DefaultRequestHeaders.Authorization =
    new AuthenticationHeaderValue("Bearer", "YOUR_QRHERO_TOKEN");
client.DefaultRequestHeaders.Accept.Add(
    new MediaTypeWithQualityHeaderValue("application/json"));

var content = new StringContent(
    '{"name":"Automation token","slug":"launch-2026","brand_kit":{"primary_color":"#4f46e5"},"settings":{"locale":"en"},"primary_domain_ulid":"01HXYZDOMAINULID0000000001"}',
    Encoding.UTF8,
    "application/json");

var response = await client.PATCHAsync("https://api.qrhero.com/v1/brands/01HXYZBRANDULID00000000001", content);
response.EnsureSuccessStatusCode();

var json = await response.Content.ReadAsStringAsync();
Console.WriteLine(json);

Domains

GET /v1/domains domains.list

List domains

Includes shared fallback hosts and organization custom domains.

Ability
domains.view

Example response

{
    "data": [
        {
            "ulid": "01HXYZDOMAINULID0000000001",
            "host": "links.example.com",
            "type": "custom",
            "status": "active",
            "ssl_status": "active",
            "is_primary": true,
            "is_shared": false,
            "verified_at": "2026-02-01T12:05:00+00:00",
            "verification": {
                "txt_record_name": "_qrhero-verify.links.example.com",
                "txt_record_value": "qrhero-verify=abc123",
                "cname_target": "qr.qrhero.link"
            },
            "created_at": "2026-02-01T12:00:00+00:00",
            "updated_at": "2026-07-01T08:30:00+00:00"
        }
    ]
}

Response schema

Field Type Required Description
data array<mixed> required

Code samples

curl -sS "https://api.qrhero.com/v1/domains" \
  -H "Authorization: Bearer YOUR_QRHERO_TOKEN" \
  -H "Accept: application/json"
const response = await fetch('https://api.qrhero.com/v1/domains', {
  method: 'GET',
  headers: {
    Authorization: 'Bearer YOUR_QRHERO_TOKEN',
    Accept: 'application/json',
  },
});

const data = await response.json();
console.log(data);
import requests

url = 'https://api.qrhero.com/v1/domains'
headers = {
    'Authorization': 'Bearer YOUR_QRHERO_TOKEN',
    'Accept': 'application/json',
}

response = requests.get(url, headers=headers)
response.raise_for_status()
print(response.json())
<?php

$client = new GuzzleHttp\Client();

$response = $client->request('GET', 'https://api.qrhero.com/v1/domains', [
    'headers' => [
        'Authorization' => 'Bearer YOUR_QRHERO_TOKEN',
        'Accept' => 'application/json',
    ],
]);

$data = json_decode($response->getBody()->getContents(), true);
print_r($data);
using var client = new HttpClient();
client.DefaultRequestHeaders.Authorization =
    new AuthenticationHeaderValue("Bearer", "YOUR_QRHERO_TOKEN");
client.DefaultRequestHeaders.Accept.Add(
    new MediaTypeWithQualityHeaderValue("application/json"));

var response = await client.GetAsync("https://api.qrhero.com/v1/domains");
response.EnsureSuccessStatusCode();

var json = await response.Content.ReadAsStringAsync();
Console.WriteLine(json);
POST /v1/domains domains.create

Add a custom domain

Ability
domains.manage

Request body schema

Field Type Required Description
host string required required hostname (e.g. links.example.com)
verify boolean optional optional boolean — attempt immediate TXT verification

Example response

{
    "data": {
        "ulid": "01HXYZDOMAINULID0000000001",
        "host": "links.example.com",
        "type": "custom",
        "status": "active",
        "ssl_status": "active",
        "is_primary": true,
        "is_shared": false,
        "verified_at": "2026-02-01T12:05:00+00:00",
        "verification": {
            "txt_record_name": "_qrhero-verify.links.example.com",
            "txt_record_value": "qrhero-verify=abc123",
            "cname_target": "qr.qrhero.link"
        },
        "created_at": "2026-02-01T12:00:00+00:00",
        "updated_at": "2026-07-01T08:30:00+00:00"
    }
}

Response schema

Field Type Required Description
data Domain required

Code samples

curl -sS -X POST "https://api.qrhero.com/v1/domains" \
  -H "Authorization: Bearer YOUR_QRHERO_TOKEN" \
  -H "Accept: application/json" \
  -H "Content-Type: application/json" \
  -d '{
    "host": "links.example.com",
    "verify": true
}'
const response = await fetch('https://api.qrhero.com/v1/domains', {
  method: 'POST',
  headers: {
    Authorization: 'Bearer YOUR_QRHERO_TOKEN',
    Accept: 'application/json',
    'Content-Type': 'application/json',
  },
  body: JSON.stringify({
    "host": "links.example.com",
    "verify": true
}),
});

const data = await response.json();
console.log(data);
import requests

url = 'https://api.qrhero.com/v1/domains'
headers = {
    'Authorization': 'Bearer YOUR_QRHERO_TOKEN',
    'Accept': 'application/json',
    'Content-Type': 'application/json',
}
payload = {
    "host": "links.example.com",
    "verify": true
}

response = requests.post(url, headers=headers, json=payload)
response.raise_for_status()
print(response.json())
<?php

$client = new GuzzleHttp\Client();

$response = $client->request('POST', 'https://api.qrhero.com/v1/domains', [
    'headers' => [
        'Authorization' => 'Bearer YOUR_QRHERO_TOKEN',
        'Accept' => 'application/json',
        'Content-Type' => 'application/json',
    ],
    'json' => {
    "host": "links.example.com",
    "verify": true
},
]);

$data = json_decode($response->getBody()->getContents(), true);
print_r($data);
using var client = new HttpClient();
client.DefaultRequestHeaders.Authorization =
    new AuthenticationHeaderValue("Bearer", "YOUR_QRHERO_TOKEN");
client.DefaultRequestHeaders.Accept.Add(
    new MediaTypeWithQualityHeaderValue("application/json"));

var content = new StringContent(
    '{"host":"links.example.com","verify":true}',
    Encoding.UTF8,
    "application/json");

var response = await client.POSTAsync("https://api.qrhero.com/v1/domains", content);
response.EnsureSuccessStatusCode();

var json = await response.Content.ReadAsStringAsync();
Console.WriteLine(json);
PATCH /v1/domains/{domain_ulid} domains.update

Verify or update a domain

Ability
domains.manage

Request body schema

Field Type Required Description
verify boolean optional optional boolean — re-check TXT ownership
refresh_ssl boolean optional optional boolean
is_primary boolean optional optional boolean

Example response

{
    "data": {
        "ulid": "01HXYZDOMAINULID0000000001",
        "host": "links.example.com",
        "type": "custom",
        "status": "active",
        "ssl_status": "active",
        "is_primary": true,
        "is_shared": false,
        "verified_at": "2026-02-01T12:05:00+00:00",
        "verification": {
            "txt_record_name": "_qrhero-verify.links.example.com",
            "txt_record_value": "qrhero-verify=abc123",
            "cname_target": "qr.qrhero.link"
        },
        "created_at": "2026-02-01T12:00:00+00:00",
        "updated_at": "2026-07-01T08:30:00+00:00"
    }
}

Response schema

Field Type Required Description
data Domain required

Code samples

curl -sS -X PATCH "https://api.qrhero.com/v1/domains/01HXYZDOMAINULID0000000001" \
  -H "Authorization: Bearer YOUR_QRHERO_TOKEN" \
  -H "Accept: application/json" \
  -H "Content-Type: application/json" \
  -d '{
    "verify": true,
    "refresh_ssl": true,
    "is_primary": true
}'
const response = await fetch('https://api.qrhero.com/v1/domains/01HXYZDOMAINULID0000000001', {
  method: 'PATCH',
  headers: {
    Authorization: 'Bearer YOUR_QRHERO_TOKEN',
    Accept: 'application/json',
    'Content-Type': 'application/json',
  },
  body: JSON.stringify({
    "verify": true,
    "refresh_ssl": true,
    "is_primary": true
}),
});

const data = await response.json();
console.log(data);
import requests

url = 'https://api.qrhero.com/v1/domains/01HXYZDOMAINULID0000000001'
headers = {
    'Authorization': 'Bearer YOUR_QRHERO_TOKEN',
    'Accept': 'application/json',
    'Content-Type': 'application/json',
}
payload = {
    "verify": true,
    "refresh_ssl": true,
    "is_primary": true
}

response = requests.patch(url, headers=headers, json=payload)
response.raise_for_status()
print(response.json())
<?php

$client = new GuzzleHttp\Client();

$response = $client->request('PATCH', 'https://api.qrhero.com/v1/domains/01HXYZDOMAINULID0000000001', [
    'headers' => [
        'Authorization' => 'Bearer YOUR_QRHERO_TOKEN',
        'Accept' => 'application/json',
        'Content-Type' => 'application/json',
    ],
    'json' => {
    "verify": true,
    "refresh_ssl": true,
    "is_primary": true
},
]);

$data = json_decode($response->getBody()->getContents(), true);
print_r($data);
using var client = new HttpClient();
client.DefaultRequestHeaders.Authorization =
    new AuthenticationHeaderValue("Bearer", "YOUR_QRHERO_TOKEN");
client.DefaultRequestHeaders.Accept.Add(
    new MediaTypeWithQualityHeaderValue("application/json"));

var content = new StringContent(
    '{"verify":true,"refresh_ssl":true,"is_primary":true}',
    Encoding.UTF8,
    "application/json");

var response = await client.PATCHAsync("https://api.qrhero.com/v1/domains/01HXYZDOMAINULID0000000001", content);
response.EnsureSuccessStatusCode();

var json = await response.Content.ReadAsStringAsync();
Console.WriteLine(json);

QR codes

GET /v1/qr-codes codes.list

List QR codes

Returns all QR codes in the organization with destination, status, and public URL metadata.

Ability
codes.view

Example response

{
    "data": [
        {
            "ulid": "01HXYZCODEULID000000000001",
            "name": "Launch 2026",
            "slug": "acme-marketing/launch-2026",
            "type": "url",
            "status": "active",
            "public_url": "https://links.example.com/acme-marketing/launch-2026",
            "destination": "https://example.com/launch",
            "routing": {
                "rules": []
            },
            "schedule": {
                "enabled": false
            },
            "password": false,
            "date_begin": null,
            "expire_at": null,
            "redirect_cap": null,
            "redirects_count": 142,
            "utm_params": null,
            "device_routing": null,
            "language_routing": null,
            "tracking_pixels": null,
            "custom_js": null,
            "landing_config": null,
            "prelander_enabled": false,
            "prelander_seconds": null,
            "prelander_message": null,
            "brand": {
                "ulid": "01HXYZBRANDULID00000000001",
                "name": "Summer Campaign"
            },
            "domain": {
                "ulid": "01HXYZDOMAINULID0000000001",
                "host": "links.example.com"
            },
            "style": {
                "ulid": "01HXYZSTYLEULID00000000001",
                "name": "Brand default"
            },
            "created_at": "2026-03-01T09:00:00+00:00",
            "updated_at": "2026-07-01T08:30:00+00:00"
        }
    ]
}

Response schema

Field Type Required Description
data array<mixed> required

Code samples

curl -sS "https://api.qrhero.com/v1/qr-codes" \
  -H "Authorization: Bearer YOUR_QRHERO_TOKEN" \
  -H "Accept: application/json"
const response = await fetch('https://api.qrhero.com/v1/qr-codes', {
  method: 'GET',
  headers: {
    Authorization: 'Bearer YOUR_QRHERO_TOKEN',
    Accept: 'application/json',
  },
});

const data = await response.json();
console.log(data);
import requests

url = 'https://api.qrhero.com/v1/qr-codes'
headers = {
    'Authorization': 'Bearer YOUR_QRHERO_TOKEN',
    'Accept': 'application/json',
}

response = requests.get(url, headers=headers)
response.raise_for_status()
print(response.json())
<?php

$client = new GuzzleHttp\Client();

$response = $client->request('GET', 'https://api.qrhero.com/v1/qr-codes', [
    'headers' => [
        'Authorization' => 'Bearer YOUR_QRHERO_TOKEN',
        'Accept' => 'application/json',
    ],
]);

$data = json_decode($response->getBody()->getContents(), true);
print_r($data);
using var client = new HttpClient();
client.DefaultRequestHeaders.Authorization =
    new AuthenticationHeaderValue("Bearer", "YOUR_QRHERO_TOKEN");
client.DefaultRequestHeaders.Accept.Add(
    new MediaTypeWithQualityHeaderValue("application/json"));

var response = await client.GetAsync("https://api.qrhero.com/v1/qr-codes");
response.EnsureSuccessStatusCode();

var json = await response.Content.ReadAsStringAsync();
Console.WriteLine(json);
GET /v1/qr-codes/{code_ulid} codes.read

Read a QR code

Returns a single QR code with routing, schedule, and style references.

Ability
codes.view

Example response

{
    "data": {
        "ulid": "01HXYZCODEULID000000000001",
        "name": "Launch 2026",
        "slug": "acme-marketing/launch-2026",
        "type": "url",
        "status": "active",
        "public_url": "https://links.example.com/acme-marketing/launch-2026",
        "destination": "https://example.com/launch",
        "routing": {
            "rules": []
        },
        "schedule": {
            "enabled": false
        },
        "password": false,
        "date_begin": null,
        "expire_at": null,
        "redirect_cap": null,
        "redirects_count": 142,
        "utm_params": null,
        "device_routing": null,
        "language_routing": null,
        "tracking_pixels": null,
        "custom_js": null,
        "landing_config": null,
        "prelander_enabled": false,
        "prelander_seconds": null,
        "prelander_message": null,
        "brand": {
            "ulid": "01HXYZBRANDULID00000000001",
            "name": "Summer Campaign"
        },
        "domain": {
            "ulid": "01HXYZDOMAINULID0000000001",
            "host": "links.example.com"
        },
        "style": {
            "ulid": "01HXYZSTYLEULID00000000001",
            "name": "Brand default"
        },
        "created_at": "2026-03-01T09:00:00+00:00",
        "updated_at": "2026-07-01T08:30:00+00:00"
    }
}

Response schema

Field Type Required Description
data QrCode required

Code samples

curl -sS "https://api.qrhero.com/v1/qr-codes/01HXYZCODEULID000000000001" \
  -H "Authorization: Bearer YOUR_QRHERO_TOKEN" \
  -H "Accept: application/json"
const response = await fetch('https://api.qrhero.com/v1/qr-codes/01HXYZCODEULID000000000001', {
  method: 'GET',
  headers: {
    Authorization: 'Bearer YOUR_QRHERO_TOKEN',
    Accept: 'application/json',
  },
});

const data = await response.json();
console.log(data);
import requests

url = 'https://api.qrhero.com/v1/qr-codes/01HXYZCODEULID000000000001'
headers = {
    'Authorization': 'Bearer YOUR_QRHERO_TOKEN',
    'Accept': 'application/json',
}

response = requests.get(url, headers=headers)
response.raise_for_status()
print(response.json())
<?php

$client = new GuzzleHttp\Client();

$response = $client->request('GET', 'https://api.qrhero.com/v1/qr-codes/01HXYZCODEULID000000000001', [
    'headers' => [
        'Authorization' => 'Bearer YOUR_QRHERO_TOKEN',
        'Accept' => 'application/json',
    ],
]);

$data = json_decode($response->getBody()->getContents(), true);
print_r($data);
using var client = new HttpClient();
client.DefaultRequestHeaders.Authorization =
    new AuthenticationHeaderValue("Bearer", "YOUR_QRHERO_TOKEN");
client.DefaultRequestHeaders.Accept.Add(
    new MediaTypeWithQualityHeaderValue("application/json"));

var response = await client.GetAsync("https://api.qrhero.com/v1/qr-codes/01HXYZCODEULID000000000001");
response.EnsureSuccessStatusCode();

var json = await response.Content.ReadAsStringAsync();
Console.WriteLine(json);
POST /v1/qr-codes codes.create

Create a QR code

Creates a dynamic QR code on the chosen domain. The stored slug is org-slug/individual-slug.

Ability
codes.create

Request body schema

Field Type Required Description
slug string required required individual slug (stored as org-slug/slug)
destination object required required URL or { "url": "..." } object
domain_ulid string required required ULID
name string optional optional string
brand_ulid string optional optional ULID
style_ulid string optional optional ULID
redirect_cap integer optional optional integer (plan-gated)
password string optional optional string (plan-gated)
routing object optional optional routing rules object
schedule object optional optional schedule object

Example response

{
    "data": {
        "ulid": "01HXYZCODEULID000000000001",
        "name": "Launch 2026",
        "slug": "acme-marketing/launch-2026",
        "type": "url",
        "status": "active",
        "public_url": "https://links.example.com/acme-marketing/launch-2026",
        "destination": "https://example.com/launch",
        "routing": {
            "rules": []
        },
        "schedule": {
            "enabled": false
        },
        "password": false,
        "date_begin": null,
        "expire_at": null,
        "redirect_cap": null,
        "redirects_count": 142,
        "utm_params": null,
        "device_routing": null,
        "language_routing": null,
        "tracking_pixels": null,
        "custom_js": null,
        "landing_config": null,
        "prelander_enabled": false,
        "prelander_seconds": null,
        "prelander_message": null,
        "brand": {
            "ulid": "01HXYZBRANDULID00000000001",
            "name": "Summer Campaign"
        },
        "domain": {
            "ulid": "01HXYZDOMAINULID0000000001",
            "host": "links.example.com"
        },
        "style": {
            "ulid": "01HXYZSTYLEULID00000000001",
            "name": "Brand default"
        },
        "created_at": "2026-03-01T09:00:00+00:00",
        "updated_at": "2026-07-01T08:30:00+00:00"
    }
}

Response schema

Field Type Required Description
data QrCode required

Code samples

curl -sS -X POST "https://api.qrhero.com/v1/qr-codes" \
  -H "Authorization: Bearer YOUR_QRHERO_TOKEN" \
  -H "Accept: application/json" \
  -H "Content-Type: application/json" \
  -d '{
    "slug": "launch-2026",
    "destination": {
        "url": "https://example.com"
    },
    "domain_ulid": "01HXYZDOMAINULID0000000001",
    "name": "Automation token",
    "brand_ulid": "01HXYZDOMAINULID0000000001",
    "style_ulid": "01HXYZDOMAINULID0000000001",
    "redirect_cap": 100,
    "password": "example",
    "routing": {
        "rules": []
    },
    "schedule": {
        "enabled": false
    }
}'
const response = await fetch('https://api.qrhero.com/v1/qr-codes', {
  method: 'POST',
  headers: {
    Authorization: 'Bearer YOUR_QRHERO_TOKEN',
    Accept: 'application/json',
    'Content-Type': 'application/json',
  },
  body: JSON.stringify({
    "slug": "launch-2026",
    "destination": {
        "url": "https://example.com"
    },
    "domain_ulid": "01HXYZDOMAINULID0000000001",
    "name": "Automation token",
    "brand_ulid": "01HXYZDOMAINULID0000000001",
    "style_ulid": "01HXYZDOMAINULID0000000001",
    "redirect_cap": 100,
    "password": "example",
    "routing": {
        "rules": []
    },
    "schedule": {
        "enabled": false
    }
}),
});

const data = await response.json();
console.log(data);
import requests

url = 'https://api.qrhero.com/v1/qr-codes'
headers = {
    'Authorization': 'Bearer YOUR_QRHERO_TOKEN',
    'Accept': 'application/json',
    'Content-Type': 'application/json',
}
payload = {
    "slug": "launch-2026",
    "destination": {
        "url": "https://example.com"
    },
    "domain_ulid": "01HXYZDOMAINULID0000000001",
    "name": "Automation token",
    "brand_ulid": "01HXYZDOMAINULID0000000001",
    "style_ulid": "01HXYZDOMAINULID0000000001",
    "redirect_cap": 100,
    "password": "example",
    "routing": {
        "rules": []
    },
    "schedule": {
        "enabled": false
    }
}

response = requests.post(url, headers=headers, json=payload)
response.raise_for_status()
print(response.json())
<?php

$client = new GuzzleHttp\Client();

$response = $client->request('POST', 'https://api.qrhero.com/v1/qr-codes', [
    'headers' => [
        'Authorization' => 'Bearer YOUR_QRHERO_TOKEN',
        'Accept' => 'application/json',
        'Content-Type' => 'application/json',
    ],
    'json' => {
    "slug": "launch-2026",
    "destination": {
        "url": "https://example.com"
    },
    "domain_ulid": "01HXYZDOMAINULID0000000001",
    "name": "Automation token",
    "brand_ulid": "01HXYZDOMAINULID0000000001",
    "style_ulid": "01HXYZDOMAINULID0000000001",
    "redirect_cap": 100,
    "password": "example",
    "routing": {
        "rules": []
    },
    "schedule": {
        "enabled": false
    }
},
]);

$data = json_decode($response->getBody()->getContents(), true);
print_r($data);
using var client = new HttpClient();
client.DefaultRequestHeaders.Authorization =
    new AuthenticationHeaderValue("Bearer", "YOUR_QRHERO_TOKEN");
client.DefaultRequestHeaders.Accept.Add(
    new MediaTypeWithQualityHeaderValue("application/json"));

var content = new StringContent(
    '{"slug":"launch-2026","destination":{"url":"https://example.com"},"domain_ulid":"01HXYZDOMAINULID0000000001","name":"Automation token","brand_ulid":"01HXYZDOMAINULID0000000001","style_ulid":"01HXYZDOMAINULID0000000001","redirect_cap":100,"password":"example","routing":{"rules":[]},"schedule":{"enabled":false}}',
    Encoding.UTF8,
    "application/json");

var response = await client.POSTAsync("https://api.qrhero.com/v1/qr-codes", content);
response.EnsureSuccessStatusCode();

var json = await response.Content.ReadAsStringAsync();
Console.WriteLine(json);
PATCH /v1/qr-codes/{code_ulid} codes.update

Update a QR code

Partial update of code fields. Plan-gated add-ons are rejected when the feature is off.

Ability
codes.update

Request body schema

Field Type Required Description
destination object optional optional URL or object
status string optional optional status string
name string optional optional string
redirect_cap integer optional optional integer
routing object optional optional object

Example response

{
    "data": {
        "ulid": "01HXYZCODEULID000000000001",
        "name": "Launch 2026",
        "slug": "acme-marketing/launch-2026",
        "type": "url",
        "status": "active",
        "public_url": "https://links.example.com/acme-marketing/launch-2026",
        "destination": "https://example.com/launch",
        "routing": {
            "rules": []
        },
        "schedule": {
            "enabled": false
        },
        "password": false,
        "date_begin": null,
        "expire_at": null,
        "redirect_cap": null,
        "redirects_count": 142,
        "utm_params": null,
        "device_routing": null,
        "language_routing": null,
        "tracking_pixels": null,
        "custom_js": null,
        "landing_config": null,
        "prelander_enabled": false,
        "prelander_seconds": null,
        "prelander_message": null,
        "brand": {
            "ulid": "01HXYZBRANDULID00000000001",
            "name": "Summer Campaign"
        },
        "domain": {
            "ulid": "01HXYZDOMAINULID0000000001",
            "host": "links.example.com"
        },
        "style": {
            "ulid": "01HXYZSTYLEULID00000000001",
            "name": "Brand default"
        },
        "created_at": "2026-03-01T09:00:00+00:00",
        "updated_at": "2026-07-01T08:30:00+00:00"
    }
}

Response schema

Field Type Required Description
data QrCode required

Code samples

curl -sS -X PATCH "https://api.qrhero.com/v1/qr-codes/01HXYZCODEULID000000000001" \
  -H "Authorization: Bearer YOUR_QRHERO_TOKEN" \
  -H "Accept: application/json" \
  -H "Content-Type: application/json" \
  -d '{
    "destination": {
        "url": "https://example.com"
    },
    "status": "active",
    "name": "Automation token",
    "redirect_cap": 100,
    "routing": {
        "rules": []
    }
}'
const response = await fetch('https://api.qrhero.com/v1/qr-codes/01HXYZCODEULID000000000001', {
  method: 'PATCH',
  headers: {
    Authorization: 'Bearer YOUR_QRHERO_TOKEN',
    Accept: 'application/json',
    'Content-Type': 'application/json',
  },
  body: JSON.stringify({
    "destination": {
        "url": "https://example.com"
    },
    "status": "active",
    "name": "Automation token",
    "redirect_cap": 100,
    "routing": {
        "rules": []
    }
}),
});

const data = await response.json();
console.log(data);
import requests

url = 'https://api.qrhero.com/v1/qr-codes/01HXYZCODEULID000000000001'
headers = {
    'Authorization': 'Bearer YOUR_QRHERO_TOKEN',
    'Accept': 'application/json',
    'Content-Type': 'application/json',
}
payload = {
    "destination": {
        "url": "https://example.com"
    },
    "status": "active",
    "name": "Automation token",
    "redirect_cap": 100,
    "routing": {
        "rules": []
    }
}

response = requests.patch(url, headers=headers, json=payload)
response.raise_for_status()
print(response.json())
<?php

$client = new GuzzleHttp\Client();

$response = $client->request('PATCH', 'https://api.qrhero.com/v1/qr-codes/01HXYZCODEULID000000000001', [
    'headers' => [
        'Authorization' => 'Bearer YOUR_QRHERO_TOKEN',
        'Accept' => 'application/json',
        'Content-Type' => 'application/json',
    ],
    'json' => {
    "destination": {
        "url": "https://example.com"
    },
    "status": "active",
    "name": "Automation token",
    "redirect_cap": 100,
    "routing": {
        "rules": []
    }
},
]);

$data = json_decode($response->getBody()->getContents(), true);
print_r($data);
using var client = new HttpClient();
client.DefaultRequestHeaders.Authorization =
    new AuthenticationHeaderValue("Bearer", "YOUR_QRHERO_TOKEN");
client.DefaultRequestHeaders.Accept.Add(
    new MediaTypeWithQualityHeaderValue("application/json"));

var content = new StringContent(
    '{"destination":{"url":"https://example.com"},"status":"active","name":"Automation token","redirect_cap":100,"routing":{"rules":[]}}',
    Encoding.UTF8,
    "application/json");

var response = await client.PATCHAsync("https://api.qrhero.com/v1/qr-codes/01HXYZCODEULID000000000001", content);
response.EnsureSuccessStatusCode();

var json = await response.Content.ReadAsStringAsync();
Console.WriteLine(json);
DELETE /v1/qr-codes/{code_ulid} codes.delete

Delete a QR code

Soft-deletes the code. Returns 204 No Content.

Ability
codes.delete

Code samples

curl -sS -X DELETE "https://api.qrhero.com/v1/qr-codes/01HXYZCODEULID000000000001" \
  -H "Authorization: Bearer YOUR_QRHERO_TOKEN" \
  -H "Accept: application/json"
const response = await fetch('https://api.qrhero.com/v1/qr-codes/01HXYZCODEULID000000000001', {
  method: 'DELETE',
  headers: {
    Authorization: 'Bearer YOUR_QRHERO_TOKEN',
    Accept: 'application/json',
  },
});

const data = await response.json();
console.log(data);
import requests

url = 'https://api.qrhero.com/v1/qr-codes/01HXYZCODEULID000000000001'
headers = {
    'Authorization': 'Bearer YOUR_QRHERO_TOKEN',
    'Accept': 'application/json',
}

response = requests.delete(url, headers=headers)
response.raise_for_status()
print(response.json())
<?php

$client = new GuzzleHttp\Client();

$response = $client->request('DELETE', 'https://api.qrhero.com/v1/qr-codes/01HXYZCODEULID000000000001', [
    'headers' => [
        'Authorization' => 'Bearer YOUR_QRHERO_TOKEN',
        'Accept' => 'application/json',
    ],
]);

$data = json_decode($response->getBody()->getContents(), true);
print_r($data);
using var client = new HttpClient();
client.DefaultRequestHeaders.Authorization =
    new AuthenticationHeaderValue("Bearer", "YOUR_QRHERO_TOKEN");
client.DefaultRequestHeaders.Accept.Add(
    new MediaTypeWithQualityHeaderValue("application/json"));

var response = await client.DeleteAsync("https://api.qrhero.com/v1/qr-codes/01HXYZCODEULID000000000001");
response.EnsureSuccessStatusCode();

var json = await response.Content.ReadAsStringAsync();
Console.WriteLine(json);

Bulk import

POST /v1/qr-codes/bulk codes.create

Stage a bulk QR code import

Two-phase flow: stage rows, review preview, then confirm. Returns a confirm_token.

Ability
codes.create

Request body schema

Field Type Required Description
rows array<object> required required array of row objects
defaults.domain_ulid string optional optional default domain ULID
defaults.brand_ulid string optional optional default brand ULID

Example response

{
    "data": {
        "ulid": "01HXYZIMPORTULID0000000001",
        "type": "qr_codes",
        "status": "staged",
        "source": "api",
        "awaiting_confirmation": true,
        "total_rows": 2,
        "processed_rows": 0,
        "success_count": 0,
        "failed_count": 0,
        "skipped_count": 0,
        "valid_row_count": 2,
        "progress_percent": 0,
        "preview_errors": [],
        "error_message": null,
        "has_error_report": false,
        "confirmed_at": null,
        "completed_at": null,
        "created_at": "2026-07-01T10:00:00+00:00",
        "updated_at": "2026-07-01T10:00:00+00:00"
    },
    "meta": {
        "confirm_token": "CONFIRM_TOKEN_FROM_STAGE"
    }
}

Response schema

Field Type Required Description
data BulkImport required
meta.confirm_token string required

Code samples

curl -sS -X POST "https://api.qrhero.com/v1/qr-codes/bulk" \
  -H "Authorization: Bearer YOUR_QRHERO_TOKEN" \
  -H "Accept: application/json" \
  -H "Content-Type: application/json" \
  -d '{
    "rows": [
        {
            "slug": "row-1",
            "destination": "https://example.com/1"
        }
    ],
    "defaults": {
        "domain_ulid": "01HXYZDOMAINULID0000000001",
        "brand_ulid": "01HXYZDOMAINULID0000000001"
    }
}'
const response = await fetch('https://api.qrhero.com/v1/qr-codes/bulk', {
  method: 'POST',
  headers: {
    Authorization: 'Bearer YOUR_QRHERO_TOKEN',
    Accept: 'application/json',
    'Content-Type': 'application/json',
  },
  body: JSON.stringify({
    "rows": [
        {
            "slug": "row-1",
            "destination": "https://example.com/1"
        }
    ],
    "defaults": {
        "domain_ulid": "01HXYZDOMAINULID0000000001",
        "brand_ulid": "01HXYZDOMAINULID0000000001"
    }
}),
});

const data = await response.json();
console.log(data);
import requests

url = 'https://api.qrhero.com/v1/qr-codes/bulk'
headers = {
    'Authorization': 'Bearer YOUR_QRHERO_TOKEN',
    'Accept': 'application/json',
    'Content-Type': 'application/json',
}
payload = {
    "rows": [
        {
            "slug": "row-1",
            "destination": "https://example.com/1"
        }
    ],
    "defaults": {
        "domain_ulid": "01HXYZDOMAINULID0000000001",
        "brand_ulid": "01HXYZDOMAINULID0000000001"
    }
}

response = requests.post(url, headers=headers, json=payload)
response.raise_for_status()
print(response.json())
<?php

$client = new GuzzleHttp\Client();

$response = $client->request('POST', 'https://api.qrhero.com/v1/qr-codes/bulk', [
    'headers' => [
        'Authorization' => 'Bearer YOUR_QRHERO_TOKEN',
        'Accept' => 'application/json',
        'Content-Type' => 'application/json',
    ],
    'json' => {
    "rows": [
        {
            "slug": "row-1",
            "destination": "https://example.com/1"
        }
    ],
    "defaults": {
        "domain_ulid": "01HXYZDOMAINULID0000000001",
        "brand_ulid": "01HXYZDOMAINULID0000000001"
    }
},
]);

$data = json_decode($response->getBody()->getContents(), true);
print_r($data);
using var client = new HttpClient();
client.DefaultRequestHeaders.Authorization =
    new AuthenticationHeaderValue("Bearer", "YOUR_QRHERO_TOKEN");
client.DefaultRequestHeaders.Accept.Add(
    new MediaTypeWithQualityHeaderValue("application/json"));

var content = new StringContent(
    '{"rows":[{"slug":"row-1","destination":"https://example.com/1"}],"defaults":{"domain_ulid":"01HXYZDOMAINULID0000000001","brand_ulid":"01HXYZDOMAINULID0000000001"}}',
    Encoding.UTF8,
    "application/json");

var response = await client.POSTAsync("https://api.qrhero.com/v1/qr-codes/bulk", content);
response.EnsureSuccessStatusCode();

var json = await response.Content.ReadAsStringAsync();
Console.WriteLine(json);
GET /v1/qr-codes/bulk/{import_ulid} codes.read

Read bulk import status

Returns staging preview, validation errors, and execution status for a bulk import job.

Ability
codes.view

Example response

{
    "data": {
        "ulid": "01HXYZIMPORTULID0000000001",
        "type": "qr_codes",
        "status": "awaiting_confirmation",
        "source": "api",
        "awaiting_confirmation": true,
        "total_rows": 2,
        "processed_rows": 0,
        "success_count": 0,
        "failed_count": 0,
        "skipped_count": 0,
        "valid_row_count": 2,
        "progress_percent": 0,
        "preview_errors": [],
        "error_message": null,
        "has_error_report": false,
        "confirmed_at": null,
        "completed_at": null,
        "created_at": "2026-07-01T10:00:00+00:00",
        "updated_at": "2026-07-01T10:00:00+00:00"
    }
}

Response schema

Field Type Required Description
data BulkImport required

Code samples

curl -sS "https://api.qrhero.com/v1/qr-codes/bulk/01HXYZIMPORTULID0000000001" \
  -H "Authorization: Bearer YOUR_QRHERO_TOKEN" \
  -H "Accept: application/json"
const response = await fetch('https://api.qrhero.com/v1/qr-codes/bulk/01HXYZIMPORTULID0000000001', {
  method: 'GET',
  headers: {
    Authorization: 'Bearer YOUR_QRHERO_TOKEN',
    Accept: 'application/json',
  },
});

const data = await response.json();
console.log(data);
import requests

url = 'https://api.qrhero.com/v1/qr-codes/bulk/01HXYZIMPORTULID0000000001'
headers = {
    'Authorization': 'Bearer YOUR_QRHERO_TOKEN',
    'Accept': 'application/json',
}

response = requests.get(url, headers=headers)
response.raise_for_status()
print(response.json())
<?php

$client = new GuzzleHttp\Client();

$response = $client->request('GET', 'https://api.qrhero.com/v1/qr-codes/bulk/01HXYZIMPORTULID0000000001', [
    'headers' => [
        'Authorization' => 'Bearer YOUR_QRHERO_TOKEN',
        'Accept' => 'application/json',
    ],
]);

$data = json_decode($response->getBody()->getContents(), true);
print_r($data);
using var client = new HttpClient();
client.DefaultRequestHeaders.Authorization =
    new AuthenticationHeaderValue("Bearer", "YOUR_QRHERO_TOKEN");
client.DefaultRequestHeaders.Accept.Add(
    new MediaTypeWithQualityHeaderValue("application/json"));

var response = await client.GetAsync("https://api.qrhero.com/v1/qr-codes/bulk/01HXYZIMPORTULID0000000001");
response.EnsureSuccessStatusCode();

var json = await response.Content.ReadAsStringAsync();
Console.WriteLine(json);
POST /v1/qr-codes/bulk/{import_ulid}/confirm codes.create

Confirm and execute bulk import

Ability
codes.create

Request body schema

Field Type Required Description
confirm_token string required required string from staging response

Example response

{
    "data": {
        "ulid": "01HXYZIMPORTULID0000000001",
        "type": "qr_codes",
        "status": "awaiting_confirmation",
        "source": "api",
        "awaiting_confirmation": true,
        "total_rows": 2,
        "processed_rows": 0,
        "success_count": 0,
        "failed_count": 0,
        "skipped_count": 0,
        "valid_row_count": 2,
        "progress_percent": 0,
        "preview_errors": [],
        "error_message": null,
        "has_error_report": false,
        "confirmed_at": null,
        "completed_at": null,
        "created_at": "2026-07-01T10:00:00+00:00",
        "updated_at": "2026-07-01T10:00:00+00:00"
    }
}

Response schema

Field Type Required Description
data BulkImport required

Code samples

curl -sS -X POST "https://api.qrhero.com/v1/qr-codes/bulk/01HXYZIMPORTULID0000000001/confirm" \
  -H "Authorization: Bearer YOUR_QRHERO_TOKEN" \
  -H "Accept: application/json" \
  -H "Content-Type: application/json" \
  -d '{
    "confirm_token": "CONFIRM_TOKEN_FROM_STAGE"
}'
const response = await fetch('https://api.qrhero.com/v1/qr-codes/bulk/01HXYZIMPORTULID0000000001/confirm', {
  method: 'POST',
  headers: {
    Authorization: 'Bearer YOUR_QRHERO_TOKEN',
    Accept: 'application/json',
    'Content-Type': 'application/json',
  },
  body: JSON.stringify({
    "confirm_token": "CONFIRM_TOKEN_FROM_STAGE"
}),
});

const data = await response.json();
console.log(data);
import requests

url = 'https://api.qrhero.com/v1/qr-codes/bulk/01HXYZIMPORTULID0000000001/confirm'
headers = {
    'Authorization': 'Bearer YOUR_QRHERO_TOKEN',
    'Accept': 'application/json',
    'Content-Type': 'application/json',
}
payload = {
    "confirm_token": "CONFIRM_TOKEN_FROM_STAGE"
}

response = requests.post(url, headers=headers, json=payload)
response.raise_for_status()
print(response.json())
<?php

$client = new GuzzleHttp\Client();

$response = $client->request('POST', 'https://api.qrhero.com/v1/qr-codes/bulk/01HXYZIMPORTULID0000000001/confirm', [
    'headers' => [
        'Authorization' => 'Bearer YOUR_QRHERO_TOKEN',
        'Accept' => 'application/json',
        'Content-Type' => 'application/json',
    ],
    'json' => {
    "confirm_token": "CONFIRM_TOKEN_FROM_STAGE"
},
]);

$data = json_decode($response->getBody()->getContents(), true);
print_r($data);
using var client = new HttpClient();
client.DefaultRequestHeaders.Authorization =
    new AuthenticationHeaderValue("Bearer", "YOUR_QRHERO_TOKEN");
client.DefaultRequestHeaders.Accept.Add(
    new MediaTypeWithQualityHeaderValue("application/json"));

var content = new StringContent(
    '{"confirm_token":"CONFIRM_TOKEN_FROM_STAGE"}',
    Encoding.UTF8,
    "application/json");

var response = await client.POSTAsync("https://api.qrhero.com/v1/qr-codes/bulk/01HXYZIMPORTULID0000000001/confirm", content);
response.EnsureSuccessStatusCode();

var json = await response.Content.ReadAsStringAsync();
Console.WriteLine(json);

QR styles

GET /v1/qr-styles styles.list

List QR styles

Returns style presets for the organization, optionally filtered by brand.

Ability
styles.manage

Query parameters

  • brand_ulid — optional filter

Example response

{
    "data": [
        {
            "ulid": "01HXYZSTYLEULID00000000001",
            "name": "Brand default",
            "config": {
                "type": "square",
                "margin": 2
            },
            "is_preset": true,
            "brand": {
                "ulid": "01HXYZBRANDULID00000000001",
                "name": "Summer Campaign"
            },
            "created_at": "2026-03-01T09:00:00+00:00",
            "updated_at": "2026-07-01T08:30:00+00:00"
        }
    ]
}

Response schema

Field Type Required Description
data array<mixed> required

Code samples

curl -sS "https://api.qrhero.com/v1/qr-styles?brand_ulid=01HXYZBRANDULID00000000001" \
  -H "Authorization: Bearer YOUR_QRHERO_TOKEN" \
  -H "Accept: application/json"
const response = await fetch('https://api.qrhero.com/v1/qr-styles?brand_ulid=01HXYZBRANDULID00000000001', {
  method: 'GET',
  headers: {
    Authorization: 'Bearer YOUR_QRHERO_TOKEN',
    Accept: 'application/json',
  },
});

const data = await response.json();
console.log(data);
import requests

url = 'https://api.qrhero.com/v1/qr-styles?brand_ulid=01HXYZBRANDULID00000000001'
headers = {
    'Authorization': 'Bearer YOUR_QRHERO_TOKEN',
    'Accept': 'application/json',
}

response = requests.get(url, headers=headers)
response.raise_for_status()
print(response.json())
<?php

$client = new GuzzleHttp\Client();

$response = $client->request('GET', 'https://api.qrhero.com/v1/qr-styles?brand_ulid=01HXYZBRANDULID00000000001', [
    'headers' => [
        'Authorization' => 'Bearer YOUR_QRHERO_TOKEN',
        'Accept' => 'application/json',
    ],
]);

$data = json_decode($response->getBody()->getContents(), true);
print_r($data);
using var client = new HttpClient();
client.DefaultRequestHeaders.Authorization =
    new AuthenticationHeaderValue("Bearer", "YOUR_QRHERO_TOKEN");
client.DefaultRequestHeaders.Accept.Add(
    new MediaTypeWithQualityHeaderValue("application/json"));

var response = await client.GetAsync("https://api.qrhero.com/v1/qr-styles?brand_ulid=01HXYZBRANDULID00000000001");
response.EnsureSuccessStatusCode();

var json = await response.Content.ReadAsStringAsync();
Console.WriteLine(json);
POST /v1/qr-styles styles.create

Create a QR style preset

Creates a reusable qr_styles.config preset for the designer and render pipeline.

Ability
styles.manage

Request body schema

Field Type Required Description
name string required required string
config object required required qr_styles.config object
brand_ulid string optional optional ULID
is_preset boolean optional optional boolean

Example response

{
    "data": {
        "ulid": "01HXYZSTYLEULID00000000001",
        "name": "Brand default",
        "config": {
            "type": "square",
            "margin": 2
        },
        "is_preset": true,
        "brand": {
            "ulid": "01HXYZBRANDULID00000000001",
            "name": "Summer Campaign"
        },
        "created_at": "2026-03-01T09:00:00+00:00",
        "updated_at": "2026-07-01T08:30:00+00:00"
    }
}

Response schema

Field Type Required Description
data QrStyle required

Code samples

curl -sS -X POST "https://api.qrhero.com/v1/qr-styles" \
  -H "Authorization: Bearer YOUR_QRHERO_TOKEN" \
  -H "Accept: application/json" \
  -H "Content-Type: application/json" \
  -d '{
    "name": "Automation token",
    "config": {
        "type": "square",
        "margin": 2
    },
    "brand_ulid": "01HXYZDOMAINULID0000000001",
    "is_preset": true
}'
const response = await fetch('https://api.qrhero.com/v1/qr-styles', {
  method: 'POST',
  headers: {
    Authorization: 'Bearer YOUR_QRHERO_TOKEN',
    Accept: 'application/json',
    'Content-Type': 'application/json',
  },
  body: JSON.stringify({
    "name": "Automation token",
    "config": {
        "type": "square",
        "margin": 2
    },
    "brand_ulid": "01HXYZDOMAINULID0000000001",
    "is_preset": true
}),
});

const data = await response.json();
console.log(data);
import requests

url = 'https://api.qrhero.com/v1/qr-styles'
headers = {
    'Authorization': 'Bearer YOUR_QRHERO_TOKEN',
    'Accept': 'application/json',
    'Content-Type': 'application/json',
}
payload = {
    "name": "Automation token",
    "config": {
        "type": "square",
        "margin": 2
    },
    "brand_ulid": "01HXYZDOMAINULID0000000001",
    "is_preset": true
}

response = requests.post(url, headers=headers, json=payload)
response.raise_for_status()
print(response.json())
<?php

$client = new GuzzleHttp\Client();

$response = $client->request('POST', 'https://api.qrhero.com/v1/qr-styles', [
    'headers' => [
        'Authorization' => 'Bearer YOUR_QRHERO_TOKEN',
        'Accept' => 'application/json',
        'Content-Type' => 'application/json',
    ],
    'json' => {
    "name": "Automation token",
    "config": {
        "type": "square",
        "margin": 2
    },
    "brand_ulid": "01HXYZDOMAINULID0000000001",
    "is_preset": true
},
]);

$data = json_decode($response->getBody()->getContents(), true);
print_r($data);
using var client = new HttpClient();
client.DefaultRequestHeaders.Authorization =
    new AuthenticationHeaderValue("Bearer", "YOUR_QRHERO_TOKEN");
client.DefaultRequestHeaders.Accept.Add(
    new MediaTypeWithQualityHeaderValue("application/json"));

var content = new StringContent(
    '{"name":"Automation token","config":{"type":"square","margin":2},"brand_ulid":"01HXYZDOMAINULID0000000001","is_preset":true}',
    Encoding.UTF8,
    "application/json");

var response = await client.POSTAsync("https://api.qrhero.com/v1/qr-styles", content);
response.EnsureSuccessStatusCode();

var json = await response.Content.ReadAsStringAsync();
Console.WriteLine(json);

Wallet

GET /v1/wallet wallet.read

Read prepaid wallet balance and ledger

Returns the organization wallet balance and paginated wallet_transactions history. Wallet top-ups and other billing writes are UI-only.

Ability
wallet.view

Query parameters

  • page — optional page number (default 1)
  • per_page — optional page size 1–100 (default 25)

Example response

{
    "data": {
        "balance": "125.50",
        "currency": "EUR",
        "low_balance_threshold": "10.00",
        "updated_at": "2026-07-01T08:30:00+00:00",
        "transactions": {
            "data": [
                {
                    "ulid": "01HXYZWTXULID000000000001",
                    "type": "debit",
                    "amount": "-0.01",
                    "balance_after": "125.50",
                    "reference_type": "api_usage",
                    "created_at": "2026-07-01T08:00:00+00:00"
                }
            ],
            "meta": {
                "current_page": 1,
                "last_page": 1,
                "per_page": 25,
                "total": 1
            }
        }
    }
}

Response schema

Field Type Required Description
data unknown required

Code samples

curl -sS "https://api.qrhero.com/v1/wallet?page=1&per_page=25" \
  -H "Authorization: Bearer YOUR_QRHERO_TOKEN" \
  -H "Accept: application/json"
const response = await fetch('https://api.qrhero.com/v1/wallet?page=1&per_page=25', {
  method: 'GET',
  headers: {
    Authorization: 'Bearer YOUR_QRHERO_TOKEN',
    Accept: 'application/json',
  },
});

const data = await response.json();
console.log(data);
import requests

url = 'https://api.qrhero.com/v1/wallet?page=1&per_page=25'
headers = {
    'Authorization': 'Bearer YOUR_QRHERO_TOKEN',
    'Accept': 'application/json',
}

response = requests.get(url, headers=headers)
response.raise_for_status()
print(response.json())
<?php

$client = new GuzzleHttp\Client();

$response = $client->request('GET', 'https://api.qrhero.com/v1/wallet?page=1&per_page=25', [
    'headers' => [
        'Authorization' => 'Bearer YOUR_QRHERO_TOKEN',
        'Accept' => 'application/json',
    ],
]);

$data = json_decode($response->getBody()->getContents(), true);
print_r($data);
using var client = new HttpClient();
client.DefaultRequestHeaders.Authorization =
    new AuthenticationHeaderValue("Bearer", "YOUR_QRHERO_TOKEN");
client.DefaultRequestHeaders.Accept.Add(
    new MediaTypeWithQualityHeaderValue("application/json"));

var response = await client.GetAsync("https://api.qrhero.com/v1/wallet?page=1&per_page=25");
response.EnsureSuccessStatusCode();

var json = await response.Content.ReadAsStringAsync();
Console.WriteLine(json);

Tokens

GET /v1/tokens/abilities

List assignable token abilities

Returns abilities the current user may grant for this organization, plus the full catalog.

Ability
api.tokens.manage

Example response

{
    "assignable": [
        "codes.view",
        "codes.create",
        "analytics.view"
    ],
    "all": [
        "codes.view",
        "codes.create",
        "analytics.view",
        "mcp.access"
    ]
}

Response schema

Field Type Required Description
assignable array<string> required
all array<string> required

Code samples

curl -sS "https://api.qrhero.com/v1/tokens/abilities" \
  -H "Authorization: Bearer YOUR_QRHERO_TOKEN" \
  -H "Accept: application/json"
const response = await fetch('https://api.qrhero.com/v1/tokens/abilities', {
  method: 'GET',
  headers: {
    Authorization: 'Bearer YOUR_QRHERO_TOKEN',
    Accept: 'application/json',
  },
});

const data = await response.json();
console.log(data);
import requests

url = 'https://api.qrhero.com/v1/tokens/abilities'
headers = {
    'Authorization': 'Bearer YOUR_QRHERO_TOKEN',
    'Accept': 'application/json',
}

response = requests.get(url, headers=headers)
response.raise_for_status()
print(response.json())
<?php

$client = new GuzzleHttp\Client();

$response = $client->request('GET', 'https://api.qrhero.com/v1/tokens/abilities', [
    'headers' => [
        'Authorization' => 'Bearer YOUR_QRHERO_TOKEN',
        'Accept' => 'application/json',
    ],
]);

$data = json_decode($response->getBody()->getContents(), true);
print_r($data);
using var client = new HttpClient();
client.DefaultRequestHeaders.Authorization =
    new AuthenticationHeaderValue("Bearer", "YOUR_QRHERO_TOKEN");
client.DefaultRequestHeaders.Accept.Add(
    new MediaTypeWithQualityHeaderValue("application/json"));

var response = await client.GetAsync("https://api.qrhero.com/v1/tokens/abilities");
response.EnsureSuccessStatusCode();

var json = await response.Content.ReadAsStringAsync();
Console.WriteLine(json);
GET /v1/tokens

List API tokens

Lists personal access tokens for the authenticated user in the current organization.

Ability
api.tokens.manage

Example response

{
    "data": [
        {
            "id": 42,
            "name": "CI automation",
            "abilities": [
                "codes.view",
                "codes.create",
                "mcp.access"
            ],
            "last_used_at": "2026-07-01T07:55:00+00:00",
            "expires_at": "2027-12-31T23:59:59+00:00",
            "created_at": "2026-01-15T10:00:00+00:00"
        }
    ]
}

Response schema

Field Type Required Description
data array<mixed> required

Code samples

curl -sS "https://api.qrhero.com/v1/tokens" \
  -H "Authorization: Bearer YOUR_QRHERO_TOKEN" \
  -H "Accept: application/json"
const response = await fetch('https://api.qrhero.com/v1/tokens', {
  method: 'GET',
  headers: {
    Authorization: 'Bearer YOUR_QRHERO_TOKEN',
    Accept: 'application/json',
  },
});

const data = await response.json();
console.log(data);
import requests

url = 'https://api.qrhero.com/v1/tokens'
headers = {
    'Authorization': 'Bearer YOUR_QRHERO_TOKEN',
    'Accept': 'application/json',
}

response = requests.get(url, headers=headers)
response.raise_for_status()
print(response.json())
<?php

$client = new GuzzleHttp\Client();

$response = $client->request('GET', 'https://api.qrhero.com/v1/tokens', [
    'headers' => [
        'Authorization' => 'Bearer YOUR_QRHERO_TOKEN',
        'Accept' => 'application/json',
    ],
]);

$data = json_decode($response->getBody()->getContents(), true);
print_r($data);
using var client = new HttpClient();
client.DefaultRequestHeaders.Authorization =
    new AuthenticationHeaderValue("Bearer", "YOUR_QRHERO_TOKEN");
client.DefaultRequestHeaders.Accept.Add(
    new MediaTypeWithQualityHeaderValue("application/json"));

var response = await client.GetAsync("https://api.qrhero.com/v1/tokens");
response.EnsureSuccessStatusCode();

var json = await response.Content.ReadAsStringAsync();
Console.WriteLine(json);
POST /v1/tokens

Create an API token

Ability
api.tokens.manage

Request body schema

Field Type Required Description
name string required required string
abilities array<object> optional optional array (default ["*"])
expires_at string (date-time) optional optional ISO8601 datetime

Example response

{
    "token": "1|plainTextSecretShownOnce",
    "data": {
        "id": 42,
        "name": "CI automation",
        "abilities": [
            "codes.view",
            "codes.create",
            "mcp.access"
        ],
        "expires_at": "2027-12-31T23:59:59+00:00"
    }
}

Response schema

Field Type Required Description
token string required Plain-text secret shown once.
data ApiToken required

Code samples

curl -sS -X POST "https://api.qrhero.com/v1/tokens" \
  -H "Authorization: Bearer YOUR_QRHERO_TOKEN" \
  -H "Accept: application/json" \
  -H "Content-Type: application/json" \
  -d '{
    "name": "Automation token",
    "abilities": [
        "codes.view",
        "codes.create"
    ],
    "expires_at": "2027-12-31T23:59:59Z"
}'
const response = await fetch('https://api.qrhero.com/v1/tokens', {
  method: 'POST',
  headers: {
    Authorization: 'Bearer YOUR_QRHERO_TOKEN',
    Accept: 'application/json',
    'Content-Type': 'application/json',
  },
  body: JSON.stringify({
    "name": "Automation token",
    "abilities": [
        "codes.view",
        "codes.create"
    ],
    "expires_at": "2027-12-31T23:59:59Z"
}),
});

const data = await response.json();
console.log(data);
import requests

url = 'https://api.qrhero.com/v1/tokens'
headers = {
    'Authorization': 'Bearer YOUR_QRHERO_TOKEN',
    'Accept': 'application/json',
    'Content-Type': 'application/json',
}
payload = {
    "name": "Automation token",
    "abilities": [
        "codes.view",
        "codes.create"
    ],
    "expires_at": "2027-12-31T23:59:59Z"
}

response = requests.post(url, headers=headers, json=payload)
response.raise_for_status()
print(response.json())
<?php

$client = new GuzzleHttp\Client();

$response = $client->request('POST', 'https://api.qrhero.com/v1/tokens', [
    'headers' => [
        'Authorization' => 'Bearer YOUR_QRHERO_TOKEN',
        'Accept' => 'application/json',
        'Content-Type' => 'application/json',
    ],
    'json' => {
    "name": "Automation token",
    "abilities": [
        "codes.view",
        "codes.create"
    ],
    "expires_at": "2027-12-31T23:59:59Z"
},
]);

$data = json_decode($response->getBody()->getContents(), true);
print_r($data);
using var client = new HttpClient();
client.DefaultRequestHeaders.Authorization =
    new AuthenticationHeaderValue("Bearer", "YOUR_QRHERO_TOKEN");
client.DefaultRequestHeaders.Accept.Add(
    new MediaTypeWithQualityHeaderValue("application/json"));

var content = new StringContent(
    '{"name":"Automation token","abilities":["codes.view","codes.create"],"expires_at":"2027-12-31T23:59:59Z"}',
    Encoding.UTF8,
    "application/json");

var response = await client.POSTAsync("https://api.qrhero.com/v1/tokens", content);
response.EnsureSuccessStatusCode();

var json = await response.Content.ReadAsStringAsync();
Console.WriteLine(json);
DELETE /v1/tokens/{token_id}

Revoke an API token

Returns 204 No Content.

Ability
api.tokens.manage

Code samples

curl -sS -X DELETE "https://api.qrhero.com/v1/tokens/42" \
  -H "Authorization: Bearer YOUR_QRHERO_TOKEN" \
  -H "Accept: application/json"
const response = await fetch('https://api.qrhero.com/v1/tokens/42', {
  method: 'DELETE',
  headers: {
    Authorization: 'Bearer YOUR_QRHERO_TOKEN',
    Accept: 'application/json',
  },
});

const data = await response.json();
console.log(data);
import requests

url = 'https://api.qrhero.com/v1/tokens/42'
headers = {
    'Authorization': 'Bearer YOUR_QRHERO_TOKEN',
    'Accept': 'application/json',
}

response = requests.delete(url, headers=headers)
response.raise_for_status()
print(response.json())
<?php

$client = new GuzzleHttp\Client();

$response = $client->request('DELETE', 'https://api.qrhero.com/v1/tokens/42', [
    'headers' => [
        'Authorization' => 'Bearer YOUR_QRHERO_TOKEN',
        'Accept' => 'application/json',
    ],
]);

$data = json_decode($response->getBody()->getContents(), true);
print_r($data);
using var client = new HttpClient();
client.DefaultRequestHeaders.Authorization =
    new AuthenticationHeaderValue("Bearer", "YOUR_QRHERO_TOKEN");
client.DefaultRequestHeaders.Accept.Add(
    new MediaTypeWithQualityHeaderValue("application/json"));

var response = await client.DeleteAsync("https://api.qrhero.com/v1/tokens/42");
response.EnsureSuccessStatusCode();

var json = await response.Content.ReadAsStringAsync();
Console.WriteLine(json);