Skip to main content

QR Tiger API Integration (Option 1)

Technology Decision Required

This document describes Option 1: QR Tiger API (cloud service with ongoing costs). Before implementing Epic 2, evaluate whether this is the best option.

Alternative: QRCoder (free open-source .NET library with zero costs and no rate limits)

See QR Generation Research & Decision for evaluation questions and comparison.

QR code generation system using QR Tiger cloud API for creating scannable QR codes that link to audio playback pages.

QR TIGER API ENDPOINT

Epic 2 Feature

QR code generation is implemented in Epic 2 and builds upon the audio generation system from Epic 1.

Note: This document assumes QR Tiger API is chosen. If QRCoder is selected instead, implementation will be simpler, faster, and cost-free.


Overview

Epic 2 adds QR code generation to the existing text-to-speech submission flow. When audio is generated (Epic 1), a QR code is automatically created that links to the audio playback page.

What Changed from Epic 1

Epic 1 (Audio Only):

User Input → ElevenLabs → Audio File → S3 → Playback Link

Epic 2 (Audio + QR Code):

User Input → ElevenLabs → Audio File → S3 → Playback Link → QR Tiger → QR Code → S3

New Capabilities:

  • QR code generation for each audio submission
  • QR code images stored in S3
  • QR code URLs returned in API responses
  • Downloadable QR codes for physical distribution

QR Tiger API Configuration

API Details

API Credentials

Configure the following environment variables:

QRTIGER_API_KEY=your_api_key_here
QRTIGER_API_URL=https://api.qrtiger.com/v1/qr

QR Code Generation

Generate QR Code Endpoint

API Call: POST https://api.qrtiger.com/v1/qr

Headers:

Authorization: Bearer {QRTIGER_API_KEY}
Content-Type: application/json

Request Body:

{
"url": "https://micdots.com/play/welcome-audio-qr-service-1706882400123",
"size": 500,
"format": "png",
"errorCorrection": "H"
}

Request Parameters:

ParameterTypeRequiredDescription
urlstringYesThe playback URL to encode in the QR code
sizenumberNoQR code dimensions in pixels (default: 500)
formatstringYesOutput format: "png" (only PNG supported)
errorCorrectionstringNoError correction level: "L", "M", "Q", "H" (default: "H")

Error Correction Levels:

  • L (Low): 7% damage tolerance
  • M (Medium): 15% damage tolerance
  • Q (Quartile): 25% damage tolerance
  • H (High): 30% damage tolerance (recommended for printing)

Response: 200 OK

{
"success": true,
"data": {
"qrCodeUrl": "https://qrtiger.com/qr/abc123def456.png",
"qrCodeId": "abc123def456",
"size": 500,
"format": "png",
"expires": null
}
}

Error Response: 400 Bad Request

{
"success": false,
"error": {
"code": "INVALID_URL",
"message": "The provided URL is invalid or unreachable"
}
}

Error Response: 401 Unauthorized

{
"success": false,
"error": {
"code": "INVALID_API_KEY",
"message": "Invalid or expired API key"
}
}

Error Response: 429 Too Many Requests

{
"success": false,
"error": {
"code": "RATE_LIMIT_EXCEEDED",
"message": "API rate limit exceeded. Please try again later."
}
}

Integration with Text-to-Speech API

Updated Processing Flow (Epic 2)

The text-to-speech submission API (POST /api/v1/text-to-speech) is extended in Epic 2 to include QR code generation:

Epic 1 Flow (Audio Only):

  1. Validate text length and voice ID
  2. Populate clientId and createdBy from JWT token
  3. Generate unique slug
  4. Generate audio via ElevenLabs
  5. Upload audio to S3
  6. Save submission record
  7. Return audio URL and playback link

Epic 2 Flow (Audio + QR Code) - Added Steps:

  1. Validate text length and voice ID
  2. Populate clientId and createdBy from JWT token
  3. Generate unique slug
  4. Generate audio via ElevenLabs
  5. Upload audio to S3
  6. 🆕 [NEW] Generate QR code via QR Tiger API (points to playback URL)
  7. 🆕 [NEW] Upload QR code image to S3
  8. Save submission record with QR code URL
  9. Return audio URL, playback link, and QR code URL

Updated Entity Schema (Epic 2)

The TextToSpeechSubmission entity now includes QR code information:

interface TextToSpeechSubmission {
id: string;
text: string;
voiceId: string;
clientId: string;
slug: string;
audioUrl: string;
qrCodeUrl: string; // 🆕 [NEW] Epic 2: S3 URL of QR code image
status: string;
characterCount: number;
processingTime: number;
createdAt: string;
createdBy: {
userId: string;
userName: string;
};
}

Updated API Response (Epic 2)

Response: 201 Created

{
"success": true,
"data": {
"id": "550e8400-e29b-41d4-a716-446655440000",
"text": "Welcome to our audio QR code service.",
"voiceId": "rachel-voice-id-123",
"clientId": "client-abc-123",
"slug": "welcome-audio-qr-service-1706882400123",
"audioUrl": "https://s3.amazonaws.com/micdots-audio/welcome-audio-qr-service-1706882400123.mp3",
"qrCodeUrl": "https://s3.amazonaws.com/micdots-qr/welcome-audio-qr-service-1706882400123.png",
"status": "completed",
"characterCount": 38,
"processingTime": 7850,
"createdAt": "2024-01-22T14:30:00Z",
"createdBy": {
"userId": "user-id-456",
"userName": "John Doe"
}
},
"links": {
"share": "https://micdots.com/play/welcome-audio-qr-service-1706882400123",
"audio": "https://s3.amazonaws.com/micdots-audio/welcome-audio-qr-service-1706882400123.mp3",
"qrCode": "https://s3.amazonaws.com/micdots-qr/welcome-audio-qr-service-1706882400123.png"
}
}

Changes from Epic 1:

  • qrCodeUrl field added to data object
  • qrCode link added to links object
  • processingTime is slightly longer (includes QR generation time)

AWS S3 Storage for QR Codes

QR code images are stored in a dedicated S3 bucket alongside audio files.

S3 Bucket Configuration

  • QR Bucket: micdots-qr
  • Region: us-east-1
  • Access: Public read
  • Format: PNG
  • File Naming: {slug}.png
    • Example: welcome-audio-qr-service-1706882400123.png
    • Same slug as audio file for consistency

Upload QR Code to S3

// After generating QR code via QR Tiger
const qrImageResponse = await fetch(qrTigerResponse.data.qrCodeUrl);
const qrImageBuffer = await qrImageResponse.arrayBuffer();

// Upload to S3
const qrKey = `${slug}.png`;
await s3.putObject({
Bucket: "micdots-qr",
Key: qrKey,
Body: qrImageBuffer,
ContentType: "image/png",
ACL: "public-read",
});

const qrCodeUrl = `https://s3.amazonaws.com/micdots-qr/${qrKey}`;

Important: The QR code filename matches the audio slug to maintain consistency across resources.


Implementation Example

Complete Epic 2 Flow

async function generateTextToSpeechWithQR(
text: string,
voiceId: string,
clientId: string
) {
// Step 1: Generate unique slug
const slug = generateSlugFromText(text); // e.g., "welcome-audio-1706882400123"

// Step 2: Generate audio (Epic 1)
const audioBuffer = await elevenLabsAPI.generateSpeech(text, voiceId);

// Step 3: Upload audio to S3
const audioKey = `${slug}.mp3`;
await s3.putObject({
Bucket: "micdots-audio",
Key: audioKey,
Body: audioBuffer,
ContentType: "audio/mpeg",
ACL: "public-read",
});

const audioUrl = `https://s3.amazonaws.com/micdots-audio/${audioKey}`;
const playbackUrl = `https://micdots.com/play/${slug}`;

// Step 4: Generate QR code (Epic 2)
const qrResponse = await fetch("https://api.qrtiger.com/v1/qr", {
method: "POST",
headers: {
Authorization: `Bearer ${process.env.QRTIGER_API_KEY}`,
"Content-Type": "application/json",
},
body: JSON.stringify({
url: playbackUrl,
size: 500,
format: "png",
errorCorrection: "H",
}),
});

const qrData = await qrResponse.json();

// Step 5: Download QR code image from QR Tiger
const qrImageResponse = await fetch(qrData.data.qrCodeUrl);
const qrImageBuffer = await qrImageResponse.arrayBuffer();

// Step 6: Upload QR code to S3
const qrKey = `${slug}.png`;
await s3.putObject({
Bucket: "micdots-qr",
Key: qrKey,
Body: qrImageBuffer,
ContentType: "image/png",
ACL: "public-read",
});

const qrCodeUrl = `https://s3.amazonaws.com/micdots-qr/${qrKey}`;

// Step 7: Save to database
const submission = await database.createSubmission({
text,
voiceId,
clientId,
slug,
audioUrl,
qrCodeUrl, // New in Epic 2
status: "completed",
});

return {
success: true,
data: submission,
links: {
share: playbackUrl,
audio: audioUrl,
qrCode: qrCodeUrl,
},
};
}

Integration Flow Diagram

Epic 2 Complete Flow

Key Changes Highlighted:

  • Blue section: Epic 1 flow (audio generation)
  • Red section: Epic 2 additions (QR code generation)

Error Handling

QR Tiger API Errors

Scenario 1: QR Tiger API is unavailable

try {
const qrResponse = await generateQRCode(playbackUrl);
} catch (error) {
// Log error but don't fail the entire submission
console.error("QR code generation failed:", error);

// Save submission without QR code
await database.createSubmission({
...submissionData,
qrCodeUrl: null, // No QR code available
status: "completed_without_qr",
});

// Return partial success
return {
success: true,
data: submission,
warnings: [
"QR code generation failed. Audio is available but QR code could not be created.",
],
};
}

Scenario 2: QR code generation times out

  • Set timeout for QR Tiger API calls (e.g., 10 seconds)
  • If timeout occurs, proceed without QR code
  • Implement retry mechanism with exponential backoff

Scenario 3: Invalid playback URL

  • Validate playback URL format before sending to QR Tiger
  • Ensure URL is reachable and returns 200 OK
  • Use URL validation library

QR Code Specifications

Technical Requirements

  • Size: 500x500px (optimized for printing)
  • Format: PNG with transparent background
  • Error Correction: High (H) - 30% damage tolerance
  • DPI: 300 DPI minimum for print quality
  • Content: Playback URL only (e.g., https://micdots.com/play/{slug})

Quality Guidelines

For Physical Printing:

  • Minimum size: 2cm x 2cm (0.8" x 0.8")
  • Recommended size: 3-5cm x 3-5cm (1.2"-2" x 1.2"-2")
  • Maintain high contrast (dark QR on light background)
  • Test scanning before mass printing

For Digital Use:

  • Display at least 200x200px on screen
  • Ensure sufficient contrast for screens
  • Test on multiple devices

Testing

Manual Testing Checklist

QR Code Generation:

  • QR code is generated for each submission
  • QR code URL is returned in API response
  • QR code image is accessible via S3 URL
  • QR code filename matches audio slug

QR Code Functionality:

  • QR code scans correctly on iOS devices
  • QR code scans correctly on Android devices
  • QR code redirects to correct playback page
  • QR code works after printing (print test)
  • Damaged QR code still works (30% error correction)

Integration:

  • Audio and QR generation succeed together
  • If QR generation fails, audio still works
  • Processing time is acceptable (less than 10 seconds)
  • QR code download button works on result page

Test QR Code Generation

# Test QR Tiger API directly
curl -X POST "https://api.qrtiger.com/v1/qr" \
-H "Authorization: Bearer {your-api-key}" \
-H "Content-Type: application/json" \
-d '{
"url": "https://micdots.com/play/test-slug-123",
"size": 500,
"format": "png",
"errorCorrection": "H"
}'

Performance Considerations

Processing Time

Epic 1 (Audio Only):

  • ElevenLabs API: ~2-5 seconds
  • S3 upload: ~0.5-1 second
  • Total: ~3-6 seconds

Epic 2 (Audio + QR):

  • ElevenLabs API: ~2-5 seconds
  • Audio S3 upload: ~0.5-1 second
  • QR Tiger API: ~1-2 seconds
  • QR image download: ~0.5 second
  • QR S3 upload: ~0.5-1 second
  • Total: ~5-10 seconds

Optimization Tips

  1. Parallel Processing: Generate QR code while uploading audio to S3
  2. Caching: Cache QR Tiger API responses for duplicate URLs
  3. CDN: Use CloudFront CDN for faster QR image delivery
  4. Async Processing: Move QR generation to background job if time exceeds 10 seconds

Security Considerations

API Key Management

  • Store QR Tiger API key in environment variables (never in code)
  • Rotate API keys periodically (every 90 days)
  • Use separate API keys for dev/staging/production
  • Monitor API key usage for anomalies

QR Code Content

  • Validate all URLs before generating QR codes
  • Ensure QR codes only point to micdots.com domain
  • Prevent QR code generation for malicious URLs
  • Implement URL whitelist for QR code generation

Rate Limiting

  • Implement rate limiting for QR code generation (10/minute per user)
  • Monitor QR Tiger API usage to avoid unexpected costs
  • Cache generated QR codes to reduce API calls

Cost Considerations

QR Tiger Pricing

QR Tiger pricing varies by plan:

  • Free Plan: Limited QR codes per month
  • Paid Plans: Unlimited QR codes with higher API limits

Recommendation: Start with paid plan for production to ensure reliability.

Cost Optimization

  1. Cache QR codes: Don't regenerate for same playback URL
  2. Batch processing: Generate QR codes in batches if possible
  3. Monitor usage: Track monthly QR generation counts
  4. Implement limits: Set per-user QR generation limits


Migration from Epic 1

Database Schema Updates

Add qrCodeUrl column to submissions table:

ALTER TABLE text_to_speech_submissions
ADD COLUMN qr_code_url VARCHAR(500) NULL;

Backwards Compatibility

  • Submissions created in Epic 1 will have qrCodeUrl: null
  • Epic 2 code should handle null QR code URLs gracefully
  • Frontend should hide QR code section if URL is null

Regenerating QR Codes for Epic 1 Submissions

Optional: Create a script to generate QR codes for existing submissions:

async function backfillQRCodes() {
const submissions = await database.getSubmissionsWithoutQR();

for (const submission of submissions) {
try {
const playbackUrl = `https://micdots.com/play/${submission.slug}`;
const qrCodeUrl = await generateAndUploadQRCode(
playbackUrl,
submission.slug
);

await database.updateSubmission(submission.id, { qrCodeUrl });
console.log(`Generated QR for ${submission.slug}`);
} catch (error) {
console.error(`Failed to generate QR for ${submission.slug}:`, error);
}
}
}

Troubleshooting

QR Code Not Generating

Issue: QR Tiger API returns error Solution:

  • Check API key is valid and not expired
  • Verify API rate limits haven't been exceeded
  • Ensure playback URL is valid and accessible
  • Check QR Tiger service status

QR Code Not Scanning

Issue: Mobile devices can't scan QR code Solution:

  • Verify error correction level is set to "H"
  • Increase QR code size to at least 500x500px
  • Ensure sufficient contrast in printed version
  • Test with multiple QR code scanner apps

S3 Upload Fails

Issue: QR code image won't upload to S3 Solution:

  • Verify S3 bucket exists and has correct permissions
  • Check S3 credentials and IAM policies
  • Ensure bucket is in correct region (us-east-1)
  • Verify image buffer is not empty

Future Enhancements (Not in Epic 2)

Future Features

The following features are planned for future releases but are NOT included in Epic 2:

  • Custom QR code branding and colors
  • QR code analytics (scan tracking)
  • QR code expiration dates
  • QR code customization (logo overlay)
  • Bulk QR code generation
  • QR code templates for different use cases
  • Alternative export formats (only PNG is supported)