API docs
Short, trackable redirect URLs with per-scan analytics, platform-specific overrides, geo targeting, and webhook delivery — editable after the QR code has already been printed.
To use your own domain (e.g. links.yourbrand.com) instead of our default short domain, point it at us and register it before setting custom_domain on a link.
Add a CNAME record at your DNS provider
Type: CNAME
Name: links (or your chosen subdomain)
Value: r.qrcode-genie.com
TTL: Auto / 3600Register it from your dashboard or the API
See POST /v1/user/settings/custom-domains below — registration fails until your DNS resolves correctly.
Set custom_domain on your link
Once registered, include custom_domain on create or update.
Available on plans with custom domain access — manage yours from /dashboard/settings#custom-domains.
/v1/qr/dynamicCreates a short, trackable redirect URL. Dynamic links support per-platform overrides (iOS/Android), geo-targeting, expiration, and webhook delivery on every scan.
store webhook_secret alongside your webhook handler, the same way you would an API key.
custom_domain requires DNS setup pointing at us before it will resolve — see Custom domains below before setting this field.
Example response · 201
{
"short_key": "bX9a2",
"short_url": "https://qrcode-genie.com/bX9a2",
"destination_url": "https://destinationsite.com",
"total_hits": 120,
"title": "Q3 Marketing Campaign Poster QR",
"tags": [
"marketing",
"q3-campaign"
],
"expires_at": null,
"is_active": true,
"created_at": "2026-06-26T03:00:00Z",
"updated_at": "2026-06-26T03:00:00Z",
"custom_domain": null,
"ios_url": null,
"android_url": null,
"fallback_url": null,
"webhook_url": null,
"webhook_secret": "whsec_mY6zR0pX3qK2wV1b9fD8jL7tN4_sE5A8x",
"geo_targeting": null,
"qr_config": null
}Stored only in this browser's local storage — never sent anywhere but the API itself.
curl -X POST "https://api.qrcode-genie.com/v1/qr/dynamic" \
-H "X-QRGenie-Api-Key: <your_api_key>" \
-H "Content-Type: application/json" \
-d '{"destination_url":"https://destinationsite.com","title":"Q3 Marketing Campaign Poster QR","tags":["marketing","q3-campaign","retail-flyer"]}'/v1/qr/dynamic/{short_key}Retrieves the data for a user owned dynamic link.
Parameters
short_keystringrequiredThe link's short key.
Example response · 200
{
"short_key": "bX9a2",
"short_url": "https://r.qrcode-genie.com/bX9a2",
"destination_url": "https://destinationsite.com",
"total_hits": 120,
"title": "Q3 Marketing Campaign Poster QR",
"tags": [
"marketing",
"q3-campaign"
],
"expires_at": null,
"is_active": true,
"created_at": "2026-06-26T03:00:00Z",
"updated_at": "2026-06-26T03:00:00Z",
"custom_domain": null,
"ios_url": null,
"android_url": null,
"fallback_url": null,
"webhook_url": null,
"webhook_secret": "whsec_mY6zR0pX3qK2wV1b9fD8jL7tN4_sE5A8x",
"geo_targeting": null,
"qr_config": null
}Stored only in this browser's local storage — never sent anywhere but the API itself.
curl -X GET "https://api.qrcode-genie.com/v1/qr/dynamic/bX9a2" \
-H "X-QRGenie-Api-Key: <your_api_key>"/v1/qr/dynamic/{short_key}Partially updates a link. Only fields you include are changed — omitted fields are left as-is. Submitting an empty geo_targeting object clears existing overrides.
Parameters
short_keystringrequiredThe link's short key.
only edits to (destination_url, custom_domain, is_active, expires_at, ios_url, android_url, fallback_url, geo_targeting) count towards the link_edits quota.
Example response · 200
{
"short_key": "bX9a2",
"short_url": "https://r.qrcode-genie.com/bX9a2",
"destination_url": "https://destinationsite.com",
"total_hits": 120,
"title": "Q3 Marketing Campaign Poster QR",
"tags": [
"marketing",
"q3-campaign"
],
"expires_at": null,
"is_active": true,
"created_at": "2026-06-26T03:00:00Z",
"updated_at": "2026-06-26T03:00:00Z",
"custom_domain": null,
"ios_url": null,
"android_url": null,
"fallback_url": null,
"webhook_url": null,
"webhook_secret": "whsec_mY6zR0pX3qK2wV1b9fD8jL7tN4_sE5A8x",
"geo_targeting": null,
"qr_config": null
}Stored only in this browser's local storage — never sent anywhere but the API itself.
curl -X PATCH "https://api.qrcode-genie.com/v1/qr/dynamic/bX9a2" \
-H "X-QRGenie-Api-Key: <your_api_key>" \
-H "Content-Type: application/json" \
-d '{"title":"Updated Campaign Label Name","is_active":true}'/v1/qr/dynamic/{short_key}Permanently removes the link and its associated analytics data. This cannot be undone.
Parameters
short_keystringrequiredThe link's short key.
link deletions count towards the link_edits quota.
Example response · 200
{
"status": "success",
"message": "Link bX9a2 and all associated logs were permanently removed from the system infrastructure.",
"short_key": "bX9a2"
}Stored only in this browser's local storage — never sent anywhere but the API itself.
curl -X DELETE "https://api.qrcode-genie.com/v1/qr/dynamic/bX9a2" \
-H "X-QRGenie-Api-Key: <your_api_key>"/v1/qr/dynamic/{short_key}/statsReturns aggregate scan metrics, geographic/device/OS breakdowns, and the 20 most recent scan events for a link.
Parameters
short_keystringrequiredThe link's short key.
recent_hits is capped at the 20 most recent events. Use export-stream for full historical data.
Both the breakdown history and how far back recent activity reaches are clamped to your plan's retention_window_days — this is a real ceiling enforced server-side, not just a display limit.
ip_address, gps_location, isp, language, and version on recent_hits are only populated plans that include it — other plans receive null for these fields, as shown in the example above.
Example response · 200
{
"short_key": "bX9a2",
"short_url": "https://r.qrcode-genie.com/bX9a2",
"destination_url": "https://destinationsite.com",
"total_hits": 120,
"title": "Q3 Marketing Campaign Poster QR",
"tags": [
"marketing",
"q3-campaign"
],
"expires_at": null,
"is_active": true,
"created_at": "2026-06-26T03:00:00Z",
"updated_at": "2026-06-26T03:00:00Z",
"custom_domain": null,
"ios_url": null,
"android_url": null,
"fallback_url": null,
"webhook_url": null,
"webhook_secret": "whsec_mY6zR0pX3qK2wV1b9fD8jL7tN4_sE5A8x",
"geo_targeting": null,
"qr_config": null,
"metrics": {
"total_calculated_hits": 1420,
"retention_window_days": 90
},
"breakdowns": {
"countries": {
"US": 840,
"DE": 120,
"UNKNOWN": 15
},
"cities": {
"New York": 210
},
"operating_systems": {
"iOS": 620,
"Android": 410,
"Windows": 90
},
"devices": {
"mobile": 1030,
"desktop": 110,
"tablet": 40
},
"browsers": {
"Safari": 500,
"Chrome": 700
},
"referrers": {
"https://t.co": 90
}
},
"recent_hits": [
{
"country": "US",
"city": "New York",
"device_type": "mobile",
"os": "iOS",
"browser": "Safari",
"referrer": "https://t.co",
"timestamp": "2026-06-26T04:15:30Z",
"ip_address": null,
"gps_location": null,
"isp": null,
"language": null,
"version": null
}
]
}Stored only in this browser's local storage — never sent anywhere but the API itself.
curl -X GET "https://api.qrcode-genie.com/v1/qr/dynamic/bX9a2/stats" \
-H "X-QRGenie-Api-Key: <your_api_key>"/v1/qr/dynamic/{short_key}/time-seriesReturns day-by-day scan counts over a configurable rolling window, with empty days zero-filled.
Parameters
short_keystringrequiredThe link's short key.
daysintegeroptionalRequested window size in days (7–365). Silently capped to your plan's retention_window_days if you ask for more than your plan retains.
range_days reflects what was actually returned, which may be less than the days you requested — check it against retention_window_days if you need to know whether your request got clamped.
Example response · 200
{
"short_key": "bX9a2",
"short_url": "https://r.qrcode-genie.com/bX9a2",
"destination_url": "https://destinationsite.com",
"total_hits": 120,
"title": "Q3 Marketing Campaign Poster QR",
"tags": [
"marketing",
"q3-campaign"
],
"expires_at": null,
"is_active": true,
"created_at": "2026-06-26T03:00:00Z",
"updated_at": "2026-06-26T03:00:00Z",
"custom_domain": null,
"ios_url": null,
"android_url": null,
"fallback_url": null,
"webhook_url": null,
"webhook_secret": "whsec_mY6zR0pX3qK2wV1b9fD8jL7tN4_sE5A8x",
"geo_targeting": null,
"qr_config": null,
"range_days": 30,
"retention_window_days": 90,
"start_date": "2026-05-27",
"end_date": "2026-06-26",
"timeline": {
"2026-06-24": 45,
"2026-06-25": 52,
"2026-06-26": 12
}
}Stored only in this browser's local storage — never sent anywhere but the API itself.
curl -X GET "https://api.qrcode-genie.com/v1/qr/dynamic/bX9a2/time-series?days=30" \
-H "X-QRGenie-Api-Key: <your_api_key>"