# External API & Data Sources ## UK Fuel Finder API (gov.uk) — PRIMARY SOURCE - Base URL: `https://api.fuel-finder.service.gov.uk/` - Auth: OAuth 2.0 client credentials (client_id + client_secret → Bearer token) - Token stored in cache with TTL matching expiry minus 60 seconds - Returns: all UK station prices + station metadata - Update frequency: stations report within 30 minutes of price change - Our polling interval: every 15 minutes via scheduler ### FuelPriceService responsibilities 1. Fetch OAuth token (cache it) 2. GET all station prices 3. Upsert `stations` table with metadata 4. Insert new rows into `station_prices` only when price has changed for that station+fuel combo 5. Call StationTaggingService to set `is_supermarket` and `brand` 6. Dispatch `PricesUpdatedEvent` for downstream processing ### Deduplication Only insert a new `station_prices` row if price differs from the most recent stored price for that `(station_id, fuel_type)` combination. Avoids row explosion on unchanged prices. ### Credentials in .env ``` FUEL_FINDER_CLIENT_ID= FUEL_FINDER_CLIENT_SECRET= FUEL_FINDER_BASE_URL=https://api.fuel-finder.service.gov.uk ``` ## Postcodes.io — postcode → lat/lng - URL: `https://api.postcodes.io/postcodes/{postcode}` - Free, no API key required - Called once on user registration / when postcode changes - Store resolved `lat` + `lng` on `users` table - Cache postcode lookups for 30 days (postcodes rarely change coordinates) ## FRED API (St. Louis Fed) — Brent crude direction - Series: `DCOILBRENTEU` (daily Brent spot price) - URL: `https://api.stlouisfed.org/fred/series/observations?series_id=DCOILBRENTEU&api_key={key}&sort_order=desc&limit=10&file_type=json` - Free API key required — stored as `FRED_API_KEY` in .env - Fetched once daily via scheduler at 7am - Stored in `brent_prices` table: `(date DATE, price_usd DECIMAL(8,2))` - Only the 5-day trend direction is used by the scoring engine ## OneSignal — push notifications - REST API: `https://oapi.onesignal.com/notifications` - App ID + REST API key stored in .env as `ONESIGNAL_APP_ID`, `ONESIGNAL_API_KEY` - Target by `player_id` (stored in `users.push_token`) - No official Laravel package needed — use Laravel HTTP client (`Http::post(...)`) - Free plan: 10,000 subscribers — sufficient for v1 ## Vonage — WhatsApp + SMS - Package: `vonage/client-core` via Composer - Credentials: `VONAGE_KEY`, `VONAGE_SECRET`, `VONAGE_WHATSAPP_FROM` in .env - WhatsApp: Messages API, utility template category (pre-approved) - SMS: SMS API, alphanumeric sender ID "FuelAlert" - All Vonage calls go through NotificationDispatchService — never call Vonage directly from components ## HTTP client Use Laravel's built-in `Http` facade for all external API calls. Always set a timeout: `Http::timeout(10)->get(...)`. Wrap in try/catch — log failures, never let a failed API call crash the scheduler.