# Puffin Offset API Documentation
## Table of Contents
- [QR Code Generation API](#qr-code-generation-api)
- [Endpoint](#endpoint)
- [Request Format](#request-format)
- [Calculation Types](#calculation-types)
- [Response Format](#response-format)
- [Format Comparison (PNG vs SVG)](#format-comparison-png-vs-svg)
- [Usage Examples](#usage-examples)
- [Checkout API](#checkout-api)
- [Best Practices](#best-practices)
- [Error Handling](#error-handling)
## 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:
```json
{
"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 consumed
- `fuelUnit`: Either `"liters"` or `"gallons"`
- `vessel`: Optional vessel metadata (for informational purposes only)
- `timestamp`: Optional ISO timestamp
- `source`: Optional identifier (e.g., "marina-api", "broker-portal")
#### 2. Distance-Based Calculation
Calculate carbon offset based on trip distance and vessel characteristics:
```json
{
"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 miles
- `speed`: Average speed in knots
- `fuelRate`: Fuel consumption rate in liters per hour
- `vessel`: Optional vessel metadata
- `timestamp`: Optional ISO timestamp
- `source`: Optional identifier
#### 3. Custom Amount
Direct monetary amount for carbon offsetting:
```json
{
"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 purchase
- `vessel`: Optional context information
- `timestamp`: Optional ISO timestamp
- `source`: Optional identifier
### Response Format
The API returns both PNG and SVG formats of the QR code:
```json
{
"success": true,
"data": {
"qrCodeDataURL": "data:image/png;base64,iVBORw0KGgoAAAANSUhEUg...",
"qrCodeSVG": "",
"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 `` src)
- `qrCodeSVG`: SVG markup string (ready for direct HTML injection)
- `url`: The full URL that the QR code points to
- `expiresAt`: 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** | `
` | Direct HTML injection or `
` |
**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
```bash
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)
```javascript
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
```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:**
```html
```
**SVG Format:**
```html