- Document QR Code Generation API with three calculation types (fuel, distance, custom) - Include PNG vs SVG format comparison table with use case recommendations - Provide usage examples in cURL, JavaScript, Python, and HTML - Document Checkout API endpoints - Add best practices, error handling, and future enhancements section - Clarify that vessel metadata in QR codes is informational only (not stored in orders) 🤖 Generated with [Claude Code](https://claude.com/claude-code) Co-Authored-By: Claude <noreply@anthropic.com>
11 KiB
Puffin Offset API Documentation
Table of Contents
QR Code Generation API
Endpoint
POST /api/qr-code/generate
Generate QR codes that encode carbon calculation parameters. The QR code directs users to the Puffin Offset calculator with pre-filled calculation data.
Request Format
The API accepts three types of calculations:
1. Fuel-Based Calculation
Calculate carbon offset based on fuel consumption:
{
"calculationType": "fuel",
"fuelAmount": 1000,
"fuelUnit": "liters",
"vessel": {
"imo": "1234567",
"name": "Sample Yacht",
"type": "Motor Yacht",
"enginePower": 2250
},
"timestamp": "2025-03-15T10:00:00Z",
"source": "marina-api"
}
Fields:
calculationType: Must be"fuel"fuelAmount: Number of fuel units consumedfuelUnit: Either"liters"or"gallons"vessel: Optional vessel metadata (for informational purposes only)timestamp: Optional ISO timestampsource: Optional identifier (e.g., "marina-api", "broker-portal")
2. Distance-Based Calculation
Calculate carbon offset based on trip distance and vessel characteristics:
{
"calculationType": "distance",
"distance": 150,
"speed": 12,
"fuelRate": 85,
"vessel": {
"imo": "1234567",
"name": "Sample Yacht",
"type": "Motor Yacht",
"enginePower": 2250
},
"timestamp": "2025-03-15T10:00:00Z",
"source": "marina-api"
}
Fields:
calculationType: Must be"distance"distance: Distance in nautical milesspeed: Average speed in knotsfuelRate: Fuel consumption rate in liters per hourvessel: Optional vessel metadatatimestamp: Optional ISO timestampsource: Optional identifier
3. Custom Amount
Direct monetary amount for carbon offsetting:
{
"calculationType": "custom",
"customAmount": 250.00,
"vessel": {
"name": "Corporate Event",
"type": "Conference"
},
"timestamp": "2025-03-15T10:00:00Z",
"source": "event-organizer"
}
Fields:
calculationType: Must be"custom"customAmount: Dollar amount (USD) for direct offset purchasevessel: Optional context informationtimestamp: Optional ISO timestampsource: Optional identifier
Response Format
The API returns both PNG and SVG formats of the QR code:
{
"success": true,
"data": {
"qrCodeDataURL": "data:image/png;base64,iVBORw0KGgoAAAANSUhEUg...",
"qrCodeSVG": "<svg xmlns=\"http://www.w3.org/2000/svg\" viewBox=\"0 0 256 256\">...</svg>",
"url": "https://puffinoffset.com/calculator?qr=eyJjYWxjdWxhdGlvblR5cGUiOi...",
"expiresAt": "2025-04-14T10:00:00.000Z"
}
}
Response Fields:
qrCodeDataURL: Base64-encoded PNG image as data URL (ready for<img>src)qrCodeSVG: SVG markup string (ready for direct HTML injection)url: The full URL that the QR code points toexpiresAt: ISO timestamp when the QR code expires (30 days from generation)
Format Comparison (PNG vs SVG)
| Feature | PNG (qrCodeDataURL) | SVG (qrCodeSVG) |
|---|---|---|
| Format | Base64-encoded PNG as data URL | SVG markup string |
| Use Case | Email, printing, basic displays | Web, scaling, professional prints |
| File Size | Larger (~5-10 KB) | Smaller (~2-4 KB) |
| Scalability | Pixelated when enlarged | Perfect at any size |
| Browser Support | Universal | Universal (all modern browsers) |
| Best For | Quick implementation, emails | Websites, responsive design, high-DPI displays |
| Embedding | <img src="{qrCodeDataURL}"> |
Direct HTML injection or <img src="data:image/svg+xml,{encoded}"> |
When to Use PNG:
- Email campaigns (better compatibility)
- Print materials with fixed sizes
- Quick prototyping
- When exact pixel dimensions are known
When to Use SVG:
- Responsive web design
- High-resolution displays (Retina, 4K)
- Professional print materials (scales to any size)
- When minimizing file size is important
- Dynamic styling with CSS
Usage Examples
cURL
curl -X POST https://puffinoffset.com/api/qr-code/generate \
-H "Content-Type: application/json" \
-d '{
"calculationType": "distance",
"distance": 150,
"speed": 12,
"fuelRate": 85,
"vessel": {
"imo": "1234567",
"name": "Sample Yacht"
}
}'
JavaScript (Fetch API)
const response = await fetch('https://puffinoffset.com/api/qr-code/generate', {
method: 'POST',
headers: {
'Content-Type': 'application/json',
},
body: JSON.stringify({
calculationType: 'fuel',
fuelAmount: 1000,
fuelUnit: 'liters',
vessel: {
name: 'Sample Yacht',
imo: '1234567'
}
})
});
const { data } = await response.json();
console.log('QR Code URL:', data.url);
// Use PNG format
document.getElementById('qr-png').src = data.qrCodeDataURL;
// Use SVG format
document.getElementById('qr-svg-container').innerHTML = data.qrCodeSVG;
Python
import requests
response = requests.post(
'https://puffinoffset.com/api/qr-code/generate',
json={
'calculationType': 'custom',
'customAmount': 250.00,
'source': 'python-client'
}
)
data = response.json()['data']
print(f"QR Code URL: {data['url']}")
print(f"Expires at: {data['expiresAt']}")
# Save PNG to file
import base64
png_data = data['qrCodeDataURL'].split(',')[1]
with open('qr-code.png', 'wb') as f:
f.write(base64.b64decode(png_data))
# Save SVG to file
with open('qr-code.svg', 'w') as f:
f.write(data['qrCodeSVG'])
HTML Embedding
PNG Format:
<!-- Direct data URL in img tag -->
<img src="data:image/png;base64,iVBORw0KGgoAAAANSUhEUg..."
alt="Carbon Offset QR Code"
style="width: 300px; height: 300px;">
SVG Format:
<!-- Direct SVG injection (recommended for web) -->
<div id="qr-container">
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 256 256">
<!-- SVG content from API -->
</svg>
</div>
<!-- Or as data URL -->
<img src="data:image/svg+xml,<svg xmlns='http://www.w3.org/2000/svg'>...</svg>"
alt="Carbon Offset QR Code"
style="width: 100%; max-width: 400px;">
Dynamic Sizing with SVG:
/* SVG automatically scales to container */
#qr-container {
width: 100%;
max-width: 500px;
margin: 0 auto;
}
#qr-container svg {
width: 100%;
height: auto;
}
Checkout API
Create Checkout Session
POST /api/checkout/create-session
Create a Stripe checkout session for carbon offset purchase.
Request Body:
{
"tons": 2.5,
"portfolioId": 123,
"pricePerTon": 20.00,
"customerEmail": "customer@example.com"
}
Response:
{
"sessionId": "cs_test_...",
"url": "https://checkout.stripe.com/...",
"orderId": "order_abc123"
}
Note: Vessel information is NOT included in checkout sessions or stored in orders. Vessel metadata in QR codes is for informational purposes only.
Get Order Details
GET /api/checkout/session/{sessionId}
Retrieve order details by Stripe session ID.
Response:
{
"order": {
"id": "order_abc123",
"tons": 2.5,
"portfolioId": 123,
"baseAmount": 5000,
"processingFee": 180,
"totalAmount": 5180,
"currency": "USD",
"status": "paid",
"wrenOrderId": "wren_xyz789",
"stripeSessionId": "cs_test_...",
"createdAt": "2025-03-15T10:00:00.000Z"
},
"session": {
"paymentStatus": "paid",
"customerEmail": "customer@example.com"
}
}
Best Practices
QR Code Generation
-
Choose the Right Format:
- Use PNG for emails, fixed-size prints, and quick prototypes
- Use SVG for websites, responsive designs, and high-quality prints
-
Include Metadata:
- Always include
sourcefield to track where QR codes originate - Include
timestampfor auditing and expiration tracking - Use descriptive
vesselnames for context
- Always include
-
Handle Expiration:
- QR codes expire after 30 days
- Check
expiresAttimestamp in response - Regenerate QR codes if needed for long-term use
-
Error Handling:
- Validate input data before sending to API
- Handle network failures gracefully
- Display user-friendly error messages
Integration Recommendations
-
Marinas & Brokers:
- Generate QR codes after trip logging
- Print QR codes on receipts or invoices
- Include vessel details for tracking
-
Event Organizers:
- Use
customcalculation type for flat-rate offsets - Generate bulk QR codes for attendee packets
- Track source with
sourcefield
- Use
-
Mobile Apps:
- Use SVG format for responsive display
- Cache QR codes locally to reduce API calls
- Implement QR code scanning for peer-to-peer sharing
Error Handling
Error Response Format
{
"success": false,
"error": "Invalid calculation type"
}
Common Errors
| Error | Cause | Solution |
|---|---|---|
| "Invalid calculation type" | calculationType not "fuel", "distance", or "custom" |
Use valid calculation type |
| "Missing required fields" | Required fields for calculation type not provided | Check calculation type requirements |
| "Invalid fuel unit" | fuelUnit not "liters" or "gallons" |
Use valid fuel unit |
| "Invalid amount" | Negative or zero values | Provide positive values |
| 500 Server Error | Server-side issue | Retry request, contact support if persistent |
HTTP Status Codes
- 200 OK: QR code generated successfully
- 400 Bad Request: Invalid request data (check error message)
- 500 Internal Server Error: Server-side error (retry or contact support)
Future Enhancements
The following features are planned for future releases:
- Authentication: API key authentication for rate limiting and analytics
- Batch Generation: Generate multiple QR codes in a single request
- Custom Branding: Add logos or custom colors to QR codes
- Analytics Dashboard: Track QR code scans and conversion rates
- Webhook Support: Receive notifications when QR codes are scanned or orders completed
Changelog
Version 1.0 (Current)
- Initial release
- Support for fuel-based, distance-based, and custom amount calculations
- PNG and SVG format outputs
- 30-day expiration
- No authentication required
Support: For questions or issues, contact support@puffinoffset.com
API Base URL: https://puffinoffset.com/api