Building QR code functionality shouldn't mean starting from scratch. The Linkbreakers API transforms complex QR code operations into simple HTTP requests that integrate seamlessly with any technology stack.
Whether you're automating marketing campaigns, building customer-facing tools, or integrating QR codes into existing products, our REST API provides the building blocks you need. Think of it as having Linkbreakers' full feature set available as programmable components.
Every API endpoint returns consistent JSON responses with comprehensive error handling. Authentication uses standard bearer tokens. Rate limits are generous enough for production workloads while preventing abuse.
Most constructions of Linkbreakers can be built via the Linkbreakers API. Full documentation is available at https://linkbreakers.com/help/api
Authentication and workspace tokens
Before making API calls, you'll need a workspace token that identifies your account and provides access to your resources. These tokens act like API keys but with better security and audit capabilities.
Creating your first token
Navigate to Workspace tokens in your dashboard. Click "Create Token" and provide a descriptive name that identifies its purpose.
Common token names include:
- "Production integration" for live systems
- "Development testing" for local development
- "Marketing automation" for specific campaign tools
- "Staging environment" for pre-production testing
The platform generates a JWT token that appears only once during creation. Store this token securely - you can't retrieve it again after the creation dialog closes.
Token authentication
Include your token in the Authorization header for every API request:
curl -H "Authorization: Bearer YOUR_JWT_TOKEN" \
-H "Content-Type: application/json" \
https://api.linkbreakers.com/v1/links
Tokens remain valid indefinitely unless explicitly revoked. However, you can monitor usage and revoke tokens through the dashboard if they're compromised or no longer needed.
Security best practices
Store tokens as environment variables rather than hardcoding them in source code. Use different tokens for different environments to limit blast radius if one gets compromised.
For production systems, consider rotating tokens periodically even if not compromised. The dashboard tracks token usage so you can verify expected activity patterns.
Creating and managing links
Links are the foundation of Linkbreakers functionality. Every QR code, short URL, or interactive workflow starts with a link resource that defines the destination and behavior.
Basic link creation
Create a simple link with just a destination URL:
const response = await fetch('https://api.linkbreakers.com/v1/links', {
method: 'POST',
headers: {
'Authorization': 'Bearer YOUR_JWT_TOKEN',
'Content-Type': 'application/json'
},
body: JSON.stringify({
destination: 'https://example.com/landing-page',
name: 'Product Launch Campaign'
})
});
const { link } = await response.json();
console.log(`Created link: ${link.entrypoint}`);
This creates a link with an auto-generated shortlink that redirects to your destination. The response includes the complete link object with generated fields like entrypoint and qrcode_signed_url.
Custom shortlinks and branding
Specify custom shortlinks for memorable URLs that reinforce your brand:
const brandedLink = await fetch('https://api.linkbreakers.com/v1/links', {
method: 'POST',
headers: {
'Authorization': 'Bearer YOUR_JWT_TOKEN',
'Content-Type': 'application/json'
},
body: JSON.stringify({
destination: 'https://example.com/special-offer',
name: 'Holiday Promotion',
shortlink: 'holiday-2024',
custom_domain_id: 'your-custom-domain-uuid'
})
});
Custom shortlinks must be unique within your workspace or custom domain. The platform validates availability and returns errors for conflicts.
Advanced link configuration
Include metadata, tags, and lead scoring parameters for sophisticated campaign management:
const advancedLink = await fetch('https://api.linkbreakers.com/v1/links', {
method: 'POST',
headers: {
'Authorization': 'Bearer YOUR_JWT_TOKEN',
'Content-Type': 'application/json'
},
body: JSON.stringify({
destination: 'https://example.com/webinar-registration',
fallback_destination: 'https://example.com/webinar-info',
name: 'Q4 Webinar Series',
shortlink: 'webinar-q4',
metadata: {
campaign: 'Q4-2024',
channel: 'email',
audience: 'enterprise'
},
tags: ['webinar', 'lead-gen', 'q4-campaign'],
lead_goal_definition: 'Generate qualified leads for enterprise sales',
lead_target_definition: 'Decision makers with 100+ employees'
})
});
Metadata accepts string key-value pairs with a maximum of 50 keys. Tags help organize campaigns and enable filtered dashboard views. Lead scoring parameters train the AI to identify high-value prospects.
Link retrieval and management
Fetch existing links with optional relationship data:
// Get a specific link with related data
const linkResponse = await fetch(
`https://api.linkbreakers.com/v1/links/${linkId}?include=qrcodeDesign,tags,customDomain`,
{
headers: {
'Authorization': 'Bearer YOUR_JWT_TOKEN'
}
}
);
// List all links with pagination
const linksResponse = await fetch(
'https://api.linkbreakers.com/v1/links?page_size=50&include=qrcodeDesign',
{
headers: {
'Authorization': 'Bearer YOUR_JWT_TOKEN'
}
}
);
const { links, next_page_token } = await linksResponse.json();
The include parameter loads related resources in a single request, reducing the number of API calls needed for complete data.
Link updates use PATCH requests to modify specific fields without affecting others:
const updateResponse = await fetch(`https://api.linkbreakers.com/v1/links/${linkId}`, {
method: 'PATCH',
headers: {
'Authorization': 'Bearer YOUR_JWT_TOKEN',
'Content-Type': 'application/json'
},
body: JSON.stringify({
name: 'Updated Campaign Name',
tags: ['updated', 'active', 'priority']
})
});
QR code design customization
QR code designs control the visual appearance of generated codes, from colors and shapes to logos and export formats. The design system separates visual styling from link functionality.
Creating custom designs
Generate QR code designs with specific branding requirements:
// Upload logo as base64 for central image
const logoBase64 = await fileToBase64(logoFile);
const designResponse = await fetch('https://api.linkbreakers.com/v1/qrcode-designs', {
method: 'POST',
headers: {
'Authorization': 'Bearer YOUR_JWT_TOKEN',
'Content-Type': 'application/json'
},
body: JSON.stringify({
output_file_format: 'OUTPUT_FILE_FORMAT_PNG',
width: 500,
height: 500,
central_image_data: logoBase64,
central_image_size: 0.3,
dots_options: {
color: '#2563eb',
type: 'rounded'
},
corners_square_options: {
color: '#1e40af',
type: 'extra-rounded'
},
background_options: {
color: '#ffffff'
},
shape: 'SHAPE_SQUARE',
error_correction_level: 'M',
hide_background_dots: true
})
});
const { qrcode_design } = await designResponse.json();
Design options provide granular control over every visual element. Color options support hex codes or gradient definitions. Shape options include traditional squares or modern circular modules.
Gradient and advanced styling
Create sophisticated designs with gradient fills and custom styling:
const gradientDesign = {
dots_options: {
gradient: JSON.stringify({
type: 'linear',
rotation: 45,
colorStops: [
{ offset: 0, color: '#3b82f6' },
{ offset: 1, color: '#8b5cf6' }
]
}),
type: 'dots'
},
corners_square_options: {
color: '#1e293b',
type: 'square'
},
background_options: {
gradient: JSON.stringify({
type: 'radial',
colorStops: [
{ offset: 0, color: '#f8fafc' },
{ offset: 1, color: '#e2e8f0' }
]
})
}
};
Gradient definitions use the qr-code-styling library format for maximum compatibility. This enables sophisticated visual effects while maintaining scanning reliability.
Design templates and reusability
Create reusable design templates for consistent branding across campaigns:
// Create a template design
const templateDesign = await fetch('https://api.linkbreakers.com/v1/qrcode-designs', {
method: 'POST',
headers: {
'Authorization': 'Bearer YOUR_JWT_TOKEN',
'Content-Type': 'application/json'
},
body: JSON.stringify({
// ... design specifications
})
});
// Apply template to new link
const linkWithTemplate = await fetch('https://api.linkbreakers.com/v1/links', {
method: 'POST',
headers: {
'Authorization': 'Bearer YOUR_JWT_TOKEN',
'Content-Type': 'application/json'
},
body: JSON.stringify({
destination: 'https://example.com',
name: 'Branded Campaign',
qrcode_design_id: templateDesign.qrcode_design.id
})
});
Design templates enable brand consistency across different team members and campaigns. Update template designs to refresh all associated QR codes simultaneously.
Analytics and event tracking
Event data provides insights into QR code performance, visitor behavior, and campaign effectiveness. The events API enables both real-time monitoring and historical analysis.
Retrieving event data
Query events with flexible filtering options:
const eventsResponse = await fetch(
'https://api.linkbreakers.com/v1/events/list?' +
new URLSearchParams({
start_date: '2024-01-01T00:00:00Z',
end_date: '2024-01-31T23:59:59Z',
link_id: 'specific-link-uuid',
page_size: '100',
include: 'visitor,device,link,leadScore'
}),
{
headers: {
'Authorization': 'Bearer YOUR_JWT_TOKEN'
}
}
);
const { events, total_count, has_more, next_page_token } = await eventsResponse.json();
Events include comprehensive metadata about each scan: device information, geographic location, visitor profiles, and lead scores. Filter by date ranges, specific links, or other criteria.
CSV export for reporting
Export large datasets for analysis in spreadsheet applications or business intelligence tools:
const csvResponse = await fetch(
'https://api.linkbreakers.com/v1/events/list?' +
new URLSearchParams({
start_date: '2024-01-01T00:00:00Z',
end_date: '2024-01-31T23:59:59Z',
response_format: 'RESPONSE_FORMAT_CSV'
}),
{
headers: {
'Authorization': 'Bearer YOUR_JWT_TOKEN'
}
}
);
const csvData = await csvResponse.text();
// Save to file or process directly
CSV exports include all event fields with human-readable headers. Large exports use pagination to manage memory usage and transfer times.
Real-time event processing
For real-time analytics or automation, consider using webhooks instead of polling the events API. Webhooks deliver events as they occur with lower latency. Learn more about comprehensive analytics capabilities and how to integrate with your existing tech stack.
Advanced integrations and automation
Bulk operations for scale
Create multiple links efficiently using concurrent requests:
const destinations = [
'https://example.com/product1',
'https://example.com/product2',
'https://example.com/product3'
];
const linkPromises = destinations.map(async (destination, index) => {
return fetch('https://api.linkbreakers.com/v1/links', {
method: 'POST',
headers: {
'Authorization': 'Bearer YOUR_JWT_TOKEN',
'Content-Type': 'application/json'
},
body: JSON.stringify({
destination,
name: `Product ${index + 1} Campaign`,
tags: ['bulk-created', 'product-campaign']
})
});
});
const responses = await Promise.all(linkPromises);
const links = await Promise.all(
responses.map(response => response.json())
);
Rate limits accommodate reasonable bulk operations. For very large batches, implement exponential backoff and respect rate limit headers.
Dynamic personalization
Generate personalized QR codes based on customer data or campaign parameters:
const customers = [
{ id: 'cust1', name: 'Acme Corp', tier: 'enterprise' },
{ id: 'cust2', name: 'Beta LLC', tier: 'professional' }
];
const personalizedLinks = await Promise.all(
customers.map(async customer => {
return fetch('https://api.linkbreakers.com/v1/links', {
method: 'POST',
headers: {
'Authorization': 'Bearer YOUR_JWT_TOKEN',
'Content-Type': 'application/json'
},
body: JSON.stringify({
destination: `https://example.com/welcome?customer=${customer.id}`,
name: `Welcome - ${customer.name}`,
shortlink: `welcome-${customer.id}`,
metadata: {
customer_id: customer.id,
customer_name: customer.name,
tier: customer.tier
},
tags: ['personalized', customer.tier]
})
});
})
);
Personalized campaigns increase engagement by delivering relevant experiences. Use metadata fields to track personalization parameters for analysis.
Integration with marketing automation
Connect Linkbreakers with existing marketing tools using webhook notifications:
// Configure webhook endpoint to receive events
const webhookResponse = await fetch('https://api.linkbreakers.com/v1/webhooks', {
method: 'POST',
headers: {
'Authorization': 'Bearer YOUR_JWT_TOKEN',
'Content-Type': 'application/json'
},
body: JSON.stringify({
url: 'https://your-system.com/linkbreakers-webhook',
events: ['link.scanned', 'form.submitted'],
active: true
})
});
// Process webhook events in your system
app.post('/linkbreakers-webhook', (req, res) => {
const { event_type, data } = req.body;
switch (event_type) {
case 'link.scanned':
// Trigger marketing automation
await addToEmailSequence(data.visitor.email);
break;
case 'form.submitted':
// Add to CRM
await createCRMLead(data.form_responses);
break;
}
res.status(200).send('OK');
});
Webhooks enable real-time integration with CRM systems, email platforms, and analytics tools. Configure multiple webhooks for different event types or destinations.
Error handling and best practices
Comprehensive error responses
The API returns structured error information for troubleshooting:
try {
const response = await fetch('https://api.linkbreakers.com/v1/links', {
method: 'POST',
headers: {
'Authorization': 'Bearer YOUR_JWT_TOKEN',
'Content-Type': 'application/json'
},
body: JSON.stringify({
destination: 'invalid-url'
})
});
if (!response.ok) {
const errorData = await response.json();
console.error('API Error:', errorData.message);
console.error('Error Code:', errorData.code);
console.error('Details:', errorData.details);
}
} catch (error) {
console.error('Network Error:', error.message);
}
Error responses include HTTP status codes, error messages, and contextual details. Common error codes include validation failures (400), authentication issues (401), and rate limits (429).
Rate limiting and retry logic
Implement exponential backoff for resilient integrations:
async function apiCallWithRetry(url, options, maxRetries = 3) {
for (let attempt = 0; attempt <= maxRetries; attempt++) {
try {
const response = await fetch(url, options);
if (response.status === 429) {
// Rate limited - wait and retry
const retryAfter = response.headers.get('Retry-After') || Math.pow(2, attempt);
await new Promise(resolve => setTimeout(resolve, retryAfter * 1000));
continue;
}
return response;
} catch (error) {
if (attempt === maxRetries) throw error;
// Exponential backoff for network errors
await new Promise(resolve =>
setTimeout(resolve, Math.pow(2, attempt) * 1000)
);
}
}
}
Rate limits are per-workspace and reset every minute. Respect Retry-After headers for optimal performance. Most applications won't hit rate limits with normal usage patterns.
Validation and data integrity
Validate data before API calls to catch issues early:
function validateLinkData(linkData) {
const errors = [];
if (!linkData.destination) {
errors.push('Destination is required');
} else if (!isValidURL(linkData.destination)) {
errors.push('Destination must be a valid URL');
}
if (linkData.metadata && Object.keys(linkData.metadata).length > 50) {
errors.push('Maximum 50 metadata keys allowed');
}
if (linkData.shortlink && !/^[a-zA-Z0-9_-]+$/.test(linkData.shortlink)) {
errors.push('Shortlink contains invalid characters');
}
return errors;
}
// Use before API calls
const validationErrors = validateLinkData(linkData);
if (validationErrors.length > 0) {
console.error('Validation errors:', validationErrors);
return;
}
Client-side validation prevents unnecessary API calls and provides immediate feedback. However, always handle server-side validation errors as the authoritative source.
Code examples for popular frameworks
Node.js with Express
const express = require('express');
const fetch = require('node-fetch');
const app = express();
app.use(express.json());
const LINKBREAKERS_TOKEN = process.env.LINKBREAKERS_TOKEN;
const API_BASE = 'https://api.linkbreakers.com/v1';
// Create QR code endpoint
app.post('/create-qr', async (req, res) => {
try {
const { destination, name } = req.body;
const response = await fetch(`${API_BASE}/links`, {
method: 'POST',
headers: {
'Authorization': `Bearer ${LINKBREAKERS_TOKEN}`,
'Content-Type': 'application/json'
},
body: JSON.stringify({ destination, name })
});
if (!response.ok) {
throw new Error(`API error: ${response.status}`);
}
const { link } = await response.json();
res.json({
qr_url: link.qrcode_signed_url,
short_url: link.entrypoint
});
} catch (error) {
res.status(500).json({ error: error.message });
}
});
Python with Flask
import requests
import os
from flask import Flask, request, jsonify
app = Flask(__name__)
LINKBREAKERS_TOKEN = os.environ['LINKBREAKERS_TOKEN']
API_BASE = 'https://api.linkbreakers.com/v1'
@app.route('/create-qr', methods=['POST'])
def create_qr():
try:
data = request.json
response = requests.post(
f'{API_BASE}/links',
headers={
'Authorization': f'Bearer {LINKBREAKERS_TOKEN}',
'Content-Type': 'application/json'
},
json={
'destination': data['destination'],
'name': data['name']
}
)
response.raise_for_status()
link = response.json()['link']
return jsonify({
'qr_url': link['qrcode_signed_url'],
'short_url': link['entrypoint']
})
except requests.exceptions.RequestException as e:
return jsonify({'error': str(e)}), 500
React frontend integration
import { useState } from 'react';
function QRCodeGenerator() {
const [formData, setFormData] = useState({ destination: '', name: '' });
const [qrCode, setQrCode] = useState(null);
const [loading, setLoading] = useState(false);
const handleSubmit = async (e) => {
e.preventDefault();
setLoading(true);
try {
const response = await fetch('/api/create-qr', {
method: 'POST',
headers: { 'Content-Type': 'application/json' },
body: JSON.stringify(formData)
});
if (!response.ok) throw new Error('Failed to create QR code');
const result = await response.json();
setQrCode(result);
} catch (error) {
console.error('Error:', error);
} finally {
setLoading(false);
}
};
return (
<form onSubmit={handleSubmit}>
<input
type="url"
placeholder="Destination URL"
value={formData.destination}
onChange={(e) => setFormData({...formData, destination: e.target.value})}
required
/>
<input
type="text"
placeholder="Campaign Name"
value={formData.name}
onChange={(e) => setFormData({...formData, name: e.target.value})}
required
/>
<button type="submit" disabled={loading}>
{loading ? 'Creating...' : 'Create QR Code'}
</button>
{qrCode && (
<div>
<img src={qrCode.qr_url} alt="Generated QR Code" />
<p>Short URL: <a href={qrCode.short_url}>{qrCode.short_url}</a></p>
</div>
)}
</form>
);
}
Testing and development workflow
API testing with curl
Test endpoints quickly using curl commands:
# Create a test link
curl -X POST https://api.linkbreakers.com/v1/links \
-H "Authorization: Bearer YOUR_TOKEN" \
-H "Content-Type: application/json" \
-d '{
"destination": "https://example.com",
"name": "Test Link"
}'
# Get link details
curl -H "Authorization: Bearer YOUR_TOKEN" \
https://api.linkbreakers.com/v1/links/LINK_UUID
# List recent events
curl -H "Authorization: Bearer YOUR_TOKEN" \
"https://api.linkbreakers.com/v1/events/list?page_size=10"
Postman collection
Create Postman collections for team API testing:
- Set up environment variables for
api_base_urlandauth_token - Create requests for common operations
- Add test scripts to validate responses
- Share collections with team members
Local development setup
Use environment variables for configuration:
// .env file
LINKBREAKERS_TOKEN=your_development_token
LINKBREAKERS_API_BASE=https://api.linkbreakers.com/v1
NODE_ENV=development
// Configuration
const config = {
token: process.env.LINKBREAKERS_TOKEN,
apiBase: process.env.LINKBREAKERS_API_BASE,
isDevelopment: process.env.NODE_ENV === 'development'
};
Separate development and production tokens to prevent accidental data mixing.
Frequently Asked Questions
What are the rate limits for the API?
The API allows 1000 requests per minute per workspace token. Rate limit headers in responses show current usage and reset times.
Can I use the API to create QR codes without links?
No, QR codes are generated as part of link creation. However, you can create links with the sole purpose of generating QR codes and ignore the shortlink functionality.
How do I handle webhook signature verification?
Webhook payloads include signatures for verification. Use the shared secret from your webhook configuration to validate incoming requests.
What happens to QR codes when I delete a link?
Deleting a link immediately stops QR code functionality. Existing QR code images continue working until their signed URLs expire, but scanning will show errors.
Can I modify QR code destinations without regenerating codes?
Yes, update link destinations through the API. Existing QR codes automatically redirect to new destinations without physical regeneration.
How do I track conversions beyond basic scans?
Use workflow integration to create custom conversion events, or connect webhook data to your analytics platform for advanced tracking. For automation scenarios, explore QR code marketing automation and Zapier integration.
Is there a sandbox environment for testing?
Use your regular workspace with test tokens and non-production destinations for safe testing. Mark test resources with tags for easy identification and cleanup.
What's the maximum file size for QR code central images?
Central images have a 3MB file size limit. Use optimized PNG or JPEG formats for best results. The API automatically handles image processing and optimization.
The Linkbreakers API transforms complex QR code operations into straightforward HTTP requests that integrate with any development workflow. Start with basic link creation, then explore advanced features like custom designs and webhook integration as your needs evolve.
Focus on building reliable error handling and respecting rate limits. The API grows with your requirements while maintaining simplicity for routine operations.
About the Author
Laurent Schaffner
Founder & Engineer at Linkbreakers
Passionate about building tools that help businesses track and optimize their digital marketing efforts. Laurent founded Linkbreakers to make QR code analytics accessible and actionable for companies of all sizes.
Related Articles
Analytics API
Access comprehensive QR code and visitor analytics through the Linkbreakers API. Learn how to retrieve campaign performance data, visitor insights, and engagement metrics programmatically for business intelligence integration.
How to integrate Linkbreakers with existing tech stack
Integrate Linkbreakers with your CRM, marketing automation, analytics platforms, and business systems through APIs, webhooks, and direct integrations. Learn best practices for seamless tech stack integration.
How to use white label in Linkbreakers? Resell our system to your own customers
Transform Linkbreakers into your own QR code platform with white label capabilities - custom domains, API integration, unlimited scaling, and complete branding control for resellers.
On this page
Need more help?
Can't find what you're looking for? Get in touch with our support team.
Contact Support