How to use the Linkbreakers API

Complete guide to integrating with the Linkbreakers API - create QR codes, manage links, customize designs, track analytics, and automate workflows programmatically.

Developer
Last updatedOctober 13, 2025

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:

Bash
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.

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.

Create a simple link with just a destination URL:

JavaScript
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.

Specify custom shortlinks for memorable URLs that reinforce your brand:

JavaScript
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.

Include metadata, tags, and lead scoring parameters for sophisticated campaign management:

JavaScript
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.

Fetch existing links with optional relationship data:

JavaScript
// 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:

JavaScript
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:

JavaScript
// 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:

JavaScript
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:

JavaScript
// 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:

JavaScript
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:

JavaScript
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.

Advanced integrations and automation

Bulk operations for scale

Create multiple links efficiently using concurrent requests:

JavaScript
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:

JavaScript
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:

JavaScript
// 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:

JavaScript
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:

JavaScript
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:

JavaScript
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.

Node.js with Express

JavaScript
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

Python
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

JavaScript
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:

Bash
# 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:

  1. Set up environment variables for api_base_url and auth_token
  2. Create requests for common operations
  3. Add test scripts to validate responses
  4. Share collections with team members

Local development setup

Use environment variables for configuration:

JavaScript
// .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.

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.

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.

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.