# 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 Carbon Offset QR Code ``` **SVG Format:** ```html
Carbon Offset QR Code ``` **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`