Add comprehensive API documentation for QR Code Generation API
All checks were successful
Build and Push Docker Images / docker (push) Successful in 22s
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:
parent
9cdf7b0786
commit
48022f38d4
417
API_DOCUMENTATION.md
Normal file
417
API_DOCUMENTATION.md
Normal 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`
|
||||
Loading…
x
Reference in New Issue
Block a user