|
| 1 | +# Syrup API Documentation |
| 2 | + |
| 3 | +## Overview |
| 4 | +The Syrup API provides a standardized interface for coupon code providers to integrate with the Syrup browser extension. This document outlines the required endpoints and data structures that providers must implement to be compatible with Syrup. |
| 5 | + |
| 6 | +## Base URL Configuration |
| 7 | +The API endpoints must be accessible under the `/syrup` path, but providers have complete flexibility in choosing their base URL. The base URL can be any valid HTTP/HTTPS URL where you host your API. Examples include: |
| 8 | + |
| 9 | +``` |
| 10 | +https://api.provider.com/syrup/ |
| 11 | +https://my.database.com/v1/syrup/ |
| 12 | +https://coupons.example.org/api/syrup/ |
| 13 | +``` |
| 14 | + |
| 15 | +This flexibility allows providers to integrate the Syrup endpoints into their existing API infrastructure. The only requirement is that all Syrup endpoints must be accessible under the `/syrup` path segment of whatever base URL you choose. |
| 16 | + |
| 17 | +## Authentication |
| 18 | +Authentication in the Syrup API is entirely optional. The extension includes an API key via the `X-Syrup-API-Key` header in all requests, but providers can choose whether to implement authentication or not. |
| 19 | + |
| 20 | +Key characteristics of the authentication system: |
| 21 | +- The API key is configured by users in the Syrup extension settings, alongside the base URL |
| 22 | +- By default, the API key is empty |
| 23 | +- Providers can choose to: |
| 24 | + - Completely ignore the API key header |
| 25 | + - Implement basic validation (e.g., check against a whitelist) |
| 26 | + - Use it as part of a more complex authentication system |
| 27 | +- If authentication is implemented, invalid keys should return 401 Unauthorized |
| 28 | +- Missing or empty API keys should be handled according to the provider's authentication policy |
| 29 | + |
| 30 | +## Data Structures |
| 31 | + |
| 32 | +### Coupon |
| 33 | +The Coupon structure represents a single coupon code and its metadata. Each field serves a specific purpose: |
| 34 | + |
| 35 | +```json |
| 36 | +{ |
| 37 | + "id": "string", // Unique identifier for the coupon |
| 38 | + "title": "string", // Display title with discount amount |
| 39 | + "description": "string", // Detailed coupon information |
| 40 | + "code": "string", // The actual coupon code |
| 41 | + "score": number, // Relevance/reliability score |
| 42 | + "merchant_name": "string" // Store/website name |
| 43 | +} |
| 44 | +``` |
| 45 | + |
| 46 | +Field Details: |
| 47 | +- `id`: Recommended to use incremental numbers for database performance. This makes database indexing and lookups more efficient. |
| 48 | +- `title`: Must include the actual discount amount. This is crucial for user understanding and decision-making. Examples: |
| 49 | + - "20% Off Everything" |
| 50 | + - "$30 Off Orders Over $100" |
| 51 | + - "Free Shipping on Orders Over $50" |
| 52 | + - "Buy One Get One Free" |
| 53 | + - "Save $15 on First Purchase" |
| 54 | +- `description`: Can include additional information such as: |
| 55 | + - Exclusions or restrictions |
| 56 | + - Minimum purchase requirements |
| 57 | + - Product category limitations |
| 58 | + - Additional terms and conditions |
| 59 | +- `code`: The actual coupon code that users will input at checkout |
| 60 | +- `score`: A number indicating the coupon's relevance and reliability. Providers can implement their own scoring system. |
| 61 | +- `merchant_name`: Should match the commonly known name of the merchant (not necessarily the domain name) |
| 62 | + |
| 63 | +### VersionInfo |
| 64 | +The VersionInfo structure helps track API compatibility: |
| 65 | + |
| 66 | +```json |
| 67 | +{ |
| 68 | + "version": "string", // Semantic versioning recommended |
| 69 | + "provider": "string" // Provider's name or identifier |
| 70 | +} |
| 71 | +``` |
| 72 | + |
| 73 | +## Endpoints |
| 74 | + |
| 75 | +### Get API Version |
| 76 | +Returns information about the API implementation. |
| 77 | + |
| 78 | +``` |
| 79 | +GET /syrup/version |
| 80 | +``` |
| 81 | + |
| 82 | +#### Response |
| 83 | +```json |
| 84 | +{ |
| 85 | + "version": "1.0.0", |
| 86 | + "provider": "ExampleProvider" |
| 87 | +} |
| 88 | +``` |
| 89 | + |
| 90 | +### List Coupons |
| 91 | +Returns a paginated list of coupons for a specific domain. |
| 92 | + |
| 93 | +``` |
| 94 | +GET /syrup/coupons |
| 95 | +``` |
| 96 | + |
| 97 | +#### Query Parameters |
| 98 | +| Parameter | Type | Required | Description | |
| 99 | +|-----------|--------|----------|-------------------------------------------------| |
| 100 | +| domain | string | Yes | The website domain to fetch coupons for | |
| 101 | +| limit | number | No | Maximum number of coupons to return (default: 20)| |
| 102 | +| offset | number | No | Number of coupons to skip (default: 0) | |
| 103 | + |
| 104 | +#### Response Headers |
| 105 | +| Header | Description | |
| 106 | +|----------------------|-------------------------------------------------------| |
| 107 | +| X-RateLimit-Limit | The maximum number of requests allowed per time window| |
| 108 | +| X-RateLimit-Remaining| The number of requests remaining in the time window | |
| 109 | +| X-RateLimit-Reset | The time when the rate limit window resets (Unix timestamp)| |
| 110 | + |
| 111 | +#### Response Body |
| 112 | +```json |
| 113 | +{ |
| 114 | + "coupons": [ |
| 115 | + { |
| 116 | + "id": "123", |
| 117 | + "title": "20% Off Everything", |
| 118 | + "description": "Save 20% on your entire purchase", |
| 119 | + "code": "SAVE20", |
| 120 | + "score": 0.95, |
| 121 | + "merchant_name": "Example Store" |
| 122 | + } |
| 123 | + ], |
| 124 | + "total": 100 |
| 125 | +} |
| 126 | +``` |
| 127 | + |
| 128 | +### Report Valid Coupon |
| 129 | +Report that a coupon code was successfully used. |
| 130 | + |
| 131 | +``` |
| 132 | +POST /syrup/coupons/valid/{id} |
| 133 | +``` |
| 134 | + |
| 135 | +#### Path Parameters |
| 136 | +| Parameter | Type | Description | |
| 137 | +|-----------|--------|-----------------------| |
| 138 | +| id | string | The ID of the coupon | |
| 139 | + |
| 140 | +#### Response |
| 141 | +Empty response with HTTP 200 status code. |
| 142 | + |
| 143 | +### Report Invalid Coupon |
| 144 | +Report that a coupon code failed to work. |
| 145 | + |
| 146 | +``` |
| 147 | +POST /syrup/coupons/invalid/{id} |
| 148 | +``` |
| 149 | + |
| 150 | +#### Path Parameters |
| 151 | +| Parameter | Type | Description | |
| 152 | +|-----------|--------|-----------------------| |
| 153 | +| id | string | The ID of the coupon | |
| 154 | + |
| 155 | +#### Response |
| 156 | +Empty response with HTTP 200 status code. |
| 157 | + |
| 158 | +## Rate Limiting |
| 159 | +The rate limiting system is designed to be transparent to clients while giving providers flexibility in implementation. Key aspects: |
| 160 | + |
| 161 | +Response Headers: |
| 162 | +- `X-RateLimit-Limit`: Maximum requests per time window (e.g., "1000") |
| 163 | +- `X-RateLimit-Remaining`: Requests remaining in current window (e.g., "997") |
| 164 | +- `X-RateLimit-Reset`: Unix timestamp for window reset (e.g., "1609459200") |
| 165 | + |
| 166 | +When rate limit is exceeded, return 429 Too Many Requests status code with a `X-RateLimit-RetryAfter` header in seconds. |
| 167 | + |
| 168 | +## Error Handling |
| 169 | +The API uses standard HTTP status codes with specific meanings in the context of the Syrup API: |
| 170 | + |
| 171 | +- 200 Success: Request processed successfully |
| 172 | +- 400 Bad Request: |
| 173 | + - Invalid domain format |
| 174 | + - Invalid pagination parameters |
| 175 | + - Missing required parameters |
| 176 | +- 401 Unauthorized: |
| 177 | + - Invalid API key (only if authentication is implemented) |
| 178 | + - Expired API key |
| 179 | +- 404 Not Found: |
| 180 | + - Invalid coupon ID |
| 181 | + - No coupons found for domain |
| 182 | +- 429 Too Many Requests: |
| 183 | + - Rate limit exceeded |
| 184 | + - Include Retry-After header |
| 185 | +- 500 Internal Server Error: |
| 186 | + - Database errors |
| 187 | + - Integration errors |
| 188 | + - System failures |
| 189 | + |
| 190 | +Error responses should include a descriptive message when possible: |
| 191 | +```json |
| 192 | +{ |
| 193 | + "error": "Invalid domain format", |
| 194 | + "message": "Domain must be a valid hostname without protocol or path" |
| 195 | +} |
| 196 | +``` |
| 197 | + |
| 198 | +## Scoring Guidelines |
| 199 | +The scoring system helps users identify the most reliable and relevant coupons. Providers implement their own scoring algorithm and can use any numerical range they prefer. Common factors to consider: |
| 200 | + |
| 201 | +- Success rate in validations |
| 202 | +- Recent usage patterns |
| 203 | +- Total number of validations |
| 204 | +- Discount amount |
| 205 | +- Coupon age |
| 206 | + |
| 207 | +Codes must be returned sorted by their score. A higher score means it's a better coupon. |
| 208 | + |
| 209 | +## Security Best Practices |
| 210 | +While implementing the Syrup API, providers should consider these security aspects: |
| 211 | + |
| 212 | +Input Validation: |
| 213 | +- Sanitize domain parameters |
| 214 | +- Validate pagination parameters |
| 215 | +- Escape special characters in coupon codes |
| 216 | +- Validate API keys if authentication is implemented |
| 217 | + |
| 218 | +Data Protection: |
| 219 | +- Sanitize error messages to avoid information leakage |
| 220 | +- Use secure methods for storing API keys |
0 commit comments