Add comprehensive API documentation for QR Code Generation API
All checks were successful
Build and Push Docker Images / docker (push) Successful in 22s

- 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>
This commit is contained in:
Matt 2025-11-03 21:58:14 +01:00
parent 9cdf7b0786
commit 48022f38d4

417
API_DOCUMENTATION.md Normal file
View File

@ -0,0 +1,417 @@
# 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": "<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 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** | `<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
```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
<!-- 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:**
```html
<!-- 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:**
```css
/* 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:**
```json
{
"tons": 2.5,
"portfolioId": 123,
"pricePerTon": 20.00,
"customerEmail": "customer@example.com"
}
```
**Response:**
```json
{
"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:**
```json
{
"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
1. **Choose the Right Format:**
- Use **PNG** for emails, fixed-size prints, and quick prototypes
- Use **SVG** for websites, responsive designs, and high-quality prints
2. **Include Metadata:**
- Always include `source` field to track where QR codes originate
- Include `timestamp` for auditing and expiration tracking
- Use descriptive `vessel` names for context
3. **Handle Expiration:**
- QR codes expire after 30 days
- Check `expiresAt` timestamp in response
- Regenerate QR codes if needed for long-term use
4. **Error Handling:**
- Validate input data before sending to API
- Handle network failures gracefully
- Display user-friendly error messages
### Integration Recommendations
1. **Marinas & Brokers:**
- Generate QR codes after trip logging
- Print QR codes on receipts or invoices
- Include vessel details for tracking
2. **Event Organizers:**
- Use `custom` calculation type for flat-rate offsets
- Generate bulk QR codes for attendee packets
- Track source with `source` field
3. **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
```json
{
"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:
1. **Authentication:** API key authentication for rate limiting and analytics
2. **Batch Generation:** Generate multiple QR codes in a single request
3. **Custom Branding:** Add logos or custom colors to QR codes
4. **Analytics Dashboard:** Track QR code scans and conversion rates
5. **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](mailto:support@puffinoffset.com)
**API Base URL:** `https://puffinoffset.com/api`