BASE URLhttps://api.weather-ai.co
API Key
Developer Reference

WeatherAI API
Documentation

Real-time and forecast weather data with AI-generated summaries, SMS/USSD delivery, webhook subscriptions, and usage analytics — all behind a single REST API.

Free — 1K req/mo
Pro — 50K req/mo
Scale — 500K req/mo + SMS
Setup

Authentication

Every request must include your API key as a Bearer token. Keys are prefixed wai_ and scoped to your plan.

Generate keys from Dashboard → API Keys. Keys are SHA-256 hashed before storage — the plaintext is only shown once on creation.
HTTP Header
Authorization: Bearer wai_<your_api_key>
cURL
curl https://api.weather-ai.co/v1/weather?lat=-1.2921&lon=36.8219 \
  -H "Authorization: Bearer wai_your_key_here"
JavaScript
const res = await fetch(
  'https://api.weather-ai.co/v1/weather?lat=-1.2921&lon=36.8219',
  { headers: { Authorization: 'Bearer wai_your_key_here' } }
);
const data = await res.json();
Billing

Plans & Rate Limits

Limits reset on a 30-day rolling period from subscription date, not calendar month.

PlanRequests/moAI Requests/moForecast daysWebhooksSMS/USSDTeam seats
Free1,00020071
Pro50,00010,00014 up to 105
Scale500,000100,00016 up to 50 approval req.20
Add ?ai=false to skip Gemini AI summaries and preserve your AI quota.
Rate Limit Headers
X-RateLimit-Limit:     50000      # monthly cap
X-RateLimit-Remaining: 49987      # requests remaining
X-RateLimit-Reset:     1717977600 # unix epoch reset time
Reference

Error Codes

StatusMeaningCommon cause
401UnauthorizedMissing, malformed, or revoked API key
403ForbiddenPlan doesn't include this feature; SMS not yet enabled
429Too Many RequestsMonthly quota exceeded — check X-RateLimit-Reset
400Bad RequestMissing required parameters
500Internal ErrorServer-side issue — retry with exponential backoff
503Service UnavailableDatabase unreachable — fail-closed for SMS gates
Weather Endpoints

Weather API

Fetch current conditions and multi-day forecasts by coordinates. Gemini AI summaries included by default.

GET/v1/weather ALL PLANSCurrent conditions + forecast
Query Parameters
ParamTypeReqDescription
latfloatrequiredLatitude e.g. -1.2921
lonfloatrequiredLongitude e.g. 36.8219
daysintegeroptionalForecast days (1–7 Free, 1–14 Pro, 1–16 Scale). Default: 7
aibooleanoptionalInclude AI summary. Default: true
unitsstringoptionalmetric (°C) or imperial (°F). Default: metric
langstringoptionalLanguage code for AI summary e.g. en, sw. Default: en
⚡ TRY ITkey from top bar
GET/v1/forecast ALL PLANSAlias of /v1/weather
Convenience alias for /v1/weather. Accepts identical parameters, returns the same shape.
⚡ TRY IT
GET/v1/current ALL PLANSCurrent conditions only
Returns present-moment weather conditions. Delegates to the same handler as /v1/weather — accepts identical parameters.
ParamTypeReqDescription
latfloatrequiredLatitude e.g. -1.2921
lonfloatrequiredLongitude e.g. 36.8219
aibooleanoptionalInclude AI summary. Default: true
unitsstringoptionalmetric or imperial. Default: metric
langstringoptionalLanguage code for AI summary. Default: en
GET/v1/daily ALL PLANSDaily forecast breakdown
Day-by-day forecast. Delegates to the same handler as /v1/weather — accepts identical parameters.
ParamTypeReqDescription
latfloatrequiredLatitude e.g. -1.2921
lonfloatrequiredLongitude e.g. 36.8219
daysintegeroptionalForecast days (1–7 Free, 1–14 Pro, 1–16 Scale). Default: 7
aibooleanoptionalInclude AI summary. Default: true
unitsstringoptionalmetric or imperial. Default: metric
GET/v1/hourly ALL PLANSHourly forecast breakdown
Hour-by-hour forecast data. Delegates to the same handler as /v1/weather — accepts identical parameters.
ParamTypeReqDescription
latfloatrequiredLatitude e.g. -1.2921
lonfloatrequiredLongitude e.g. 36.8219
daysintegeroptionalForecast days (1–7 Free, 1–14 Pro, 1–16 Scale). Default: 7
aibooleanoptionalInclude AI summary. Default: true
unitsstringoptionalmetric or imperial. Default: metric
GET/v1/forecast14 PRO+14-day extended forecast
Requires Pro or Scale plan. Free-plan keys receive a 403.

Extended 14-day forecast endpoint. Accepts identical parameters to /v1/weather; the days parameter is capped at 14 for Pro and 16 for Scale.

ParamTypeReqDescription
latfloatrequiredLatitude e.g. -1.2921
lonfloatrequiredLongitude e.g. 36.8219
daysintegeroptionalForecast days up to 14 (Pro) or 16 (Scale). Default: 14
aibooleanoptionalInclude AI summary. Default: true
unitsstringoptionalmetric or imperial. Default: metric
langstringoptionalLanguage code for AI summary. Default: en
GET/v1/insights PRO+AI-powered weather insights
Requires Pro or Scale plan. Free-plan keys receive a 403.

Returns weather data with enhanced Gemini AI analysis — agronomic context, risk flags, and actionable recommendations alongside standard forecast fields. Delegates to the same handler as /v1/weather; AI is always enabled.

ParamTypeReqDescription
latfloatrequiredLatitude e.g. -1.2921
lonfloatrequiredLongitude e.g. 36.8219
daysintegeroptionalForecast days (plan-limited). Default: 7
unitsstringoptionalmetric or imperial. Default: metric
langstringoptionalLanguage code for AI summary. Default: en
GET/v1/weather-geo ALL PLANSWeather + IP geo-detection

Auto-detects caller location from IP when ?ip=auto. Returns weather + geo metadata in response headers.

ParamTypeReqDescription
ipstringoptionalPass auto to detect from request IP, or an explicit IP
latfloatoptionalOverride detected latitude
lonfloatoptionalOverride detected longitude
daysintegeroptionalForecast days (plan-limited)
aibooleanoptionalInclude AI summary. Default: true
Response Headers
X-Country: KE
X-Region:  Nairobi County
X-City:    Nairobi
⚡ TRY IT
GET/v1/ip-lookup PRO+Resolve IP address to geo coordinates

Resolves an IP address to latitude, longitude, city, region, country, and timezone. Pass ?ip=auto (default) to detect from the request IP, or supply any explicit IPv4/IPv6 address.

ParamTypeReqDescription
ipstringoptionalIP to resolve. Pass auto (default) to detect from request, or an explicit IPv4/IPv6 address
Response
{
  "ip":       "41.90.64.1",
  "ip_hash":  "a3f1...",
  "ip_version": "v4",
  "geo": {
    "lat":      -1.2921,
    "lon":      36.8219,
    "city":     "Nairobi",
    "region":   "Nairobi County",
    "country":  "KE",
    "timezone": "Africa/Nairobi"
  }
}
⚡ TRY IT
Account

Usage & Quota

GET/v1/usage ALL PLANSBilling period usage stats

Returns request counts, AI request counts, plan limits, and billing period start/end. No query parameters.

⚡ TRY IT
Webhooks

Webhooks PRO+

Subscribe to weather trigger events. WeatherAI POSTs to your URL when conditions are met.

POST/v1/webhooks PRO+Create a webhook subscription
Request Body (JSON)
FieldTypeReqDescription
urlstringrequiredHTTPS endpoint to receive POST payloads
latfloatrequiredLatitude of location to monitor
lonfloatrequiredLongitude of location to monitor
triggersstring[]requirede.g. ["rain","extreme_wind","frost"]
timezonestringoptionalIANA timezone. Default: UTC
Example
POST /v1/webhooks
Authorization: Bearer wai_your_key
Content-Type: application/json

{
  "url":      "https://yourapp.com/weather-hook",
  "lat":      -1.2921,
  "lon":      36.8219,
  "triggers": ["rain", "extreme_wind"],
  "timezone": "Africa/Nairobi"
}
Pro supports up to 10 webhooks. Scale supports up to 50.
GET/v1/webhooks PRO+List your webhooks

Returns all active webhook subscriptions for your account.

Response
{
  "webhooks": [
    {
      "id":        "abc123",
      "url":       "https://yourapp.com/hook",
      "lat":       -1.2921,
      "lon":       36.8219,
      "triggers":  ["rain"],
      "timezone":  "Africa/Nairobi",
      "active":    true,
      "createdAt": "2024-11-01T10:00:00Z"
    }
  ]
}
DEL/v1/webhooks/:id PRO+Delete a webhook

Permanently deletes a webhook. Returns 404 if not found or owned by another account.

cURL
curl -X DELETE https://api.weather-ai.co/v1/webhooks/abc123 \
  -H "Authorization: Bearer wai_your_key"
SMS / USSD

SMS API SCALE ONLY

Programmatic SMS delivery and farmer registration. Requires Scale plan + admin compliance approval.

SMS routes require (1) Scale plan and (2) smsEnabled = true on your account — set by admin after compliance review. Submit documents via Billing panel → Request SMS Access. Until approved, calls return 403 SMS_NOT_ENABLED.
POST/v1/sms/send SCALESend an SMS message
Request Body (JSON)
FieldTypeReqDescription
tostringrequiredRecipient phone in E.164 format e.g. +254712345678
messagestringrequiredSMS body text (max 160 chars per segment)
typestringoptionalType tag for analytics. Default: general
pilotTagstringoptionalPilot programme identifier for grouping in SMS stats
Example
POST /v1/sms/send
Authorization: Bearer wai_your_key

{
  "to":      "+254712345678",
  "message": "Heavy rain expected tomorrow. Plan ahead.",
  "type":    "weather_alert"
}
POST/v1/sms/alert SCALESend a structured alert

Sends a formatted weather alert using a predefined template keyed by alertType.

FieldTypeReqDescription
tostringrequiredRecipient phone in E.164
alertTypestringrequiredrain · frost · extreme_wind · drought
dataobjectoptionalContext merged into template e.g. {"mm":45,"day":"tomorrow"}
POST/v1/sms/bomet/register SCALERegister a Bomet farmer

Registers a farmer in the Bomet Agricultural Alert System. Creates a profile and schedules daily weather SMS alerts.

FieldTypeReqDescription
phonestringrequiredFarmer's phone (E.164)
namestringrequiredFull name
locationstringoptionalVillage/ward e.g. Bomet Central
cropTypestringoptionalPrimary crop e.g. maize · tea
GET/v1/sms/stats SCALESMS usage statistics

Returns delivery stats, message counts by type, gateway usage, and opt-out rates. No parameters.

GET/v1/sms/health SCALESMS gateway health check

Connectivity status for the SMS gateway and Africa's Talking fallback.

Example Response
{
  "gateway":   "ok",
  "fallback":  "ok",
  "lastCheck": "2025-05-20T07:58:00Z",
  "latencyMs": 142
}
Agroforestry

Trees & Forestry API

Upload drone, aerial, or satellite images to automatically count tree crowns, assess canopy health, and get agronomic recommendations — powered by OpenCV computer vision and Gemini AI.

PlanAnalyses / monthCV engineOverlay imageGemini context
Free5
Pro100
ScaleUnlimited
POST/v1/trees/analyze ALL PLANSCount trees + assess canopy health from image

Upload a farm image (drone, aerial, satellite) as multipart/form-data. Returns tree count, density, health breakdown, an annotated overlay image, and Gemini-powered agronomic observations.

Form Fields
FieldTypeReqDescription
imagefilerequiredJPEG, PNG, or WEBP — max 20 MB
farmerIdstringoptionalYour farmer / plot identifier — echoed in response
countystringoptionalCounty or region — provides context for Gemini
landAcresfloatoptionalPlot size in acres — enables tree_density_per_acre
locationstringoptionalHuman-readable farm name or GPS description
notesstringoptionalExtra context for Gemini e.g. "Tea plantation, recently pruned"
cURL Example
curl -X POST https://api.weather-ai.co/v1/trees/analyze \
  -H "Authorization: Bearer wai_your_key" \
  -F "image=@/path/to/farm.jpg" \
  -F "farmerId=F-001" \
  -F "county=Bomet" \
  -F "landAcres=2.5" \
  -F "notes=Tea plantation"
Response 200
{
  "analysis_id":           "Kx8mP2qRvTnZ",
  "timestamp":             "2026-06-01T09:15:00.000Z",
  "farmer_id":             "F-001",
  "county":                "Bomet",
  "location":              "Kapkimolwa Farm, Block C",
  "land_acres":            2.5,
  "total_tree_count":      84,
  "tree_density_per_acre": 33.6,
  "confidence_score":      0.87,
  "canopy_coverage_pct":   41.2,
  "tree_health": {
    "healthy":             68,
    "needs_care":          12,
    "needs_replacement":    4
  },
  "low_confidence":        false,
  "tree_species_guess":    "Tea (Camellia sinensis)",
  "observations": [
    "Dense canopy in northern quadrant — possible over-crowding",
    "3 trees near water source show yellowing — likely waterlogging"
  ],
  "recommendations": [
    "Consider thinning northern section to improve light penetration",
    "Improve drainage around water source trees"
  ],
  "original_image_url":    "https://storage.googleapis.com/…/original.jpg",
  "overlay_image_url":     "https://storage.googleapis.com/…/overlay.jpg",
  "cv_debug": {
    "orig_resolution": "4000x3000",
    "work_resolution": "1500x1125",
    "canopy_px":       412500,
    "peaks_detected":  91,
    "after_area_filter": 84
  }
}
⚡ TRY IT — Image Upload multipart/form-data
Drop a farm image here or click to browse
JPEG · PNG · WEBP · max 20 MB
GET/v1/trees/history ALL PLANSList past analyses for your account

Returns a paginated list of past tree analyses for the authenticated caller, ordered newest first.

ParamTypeReqDescription
limitintegeroptionalResults per page (default 20, max 100)
cursorstringoptionalPagination cursor from previous response next_cursor
⚡ TRY IT
GET/v1/trees/quota ALL PLANSRemaining tree analysis quota this month

Returns how many tree analyses you have used and remaining for the current calendar month.

Response
{
  "plan":      "pro",
  "used":      12,
  "limit":     100,
  "remaining": 88,
  "unlimited": false,
  "resets_at": "2026-07-01T00:00:00.000Z"
}
⚡ TRY IT
POST/v1/forestry/count-trees ALL PLANSLegacy alias — identical to /v1/trees/analyze
Convenience alias for /v1/trees/analyze. Accepts the same multipart fields and returns the identical response shape. Useful if you have existing integrations pointing to /v1/forestry/count-trees.
cURL
curl -X POST https://api.weather-ai.co/v1/forestry/count-trees \
  -H "Authorization: Bearer wai_your_key" \
  -F "image=@/path/to/farm.jpg" \
  -F "farmerId=F-001" \
  -F "county=Bomet" \
  -F "landAcres=2.5"
Firebase Callable Functions

Billing Functions

These are Firebase HTTPS callable functions invoked via the Firebase SDK — not plain REST. They require an authenticated Firebase user session.

Call these via the Firebase JS SDK: httpsCallable(functions, 'functionName')(payload). They enforce Firebase Auth internally — no API key needed, but the user must be signed in.
FNcancelSubscription PRO / SCALECancel active subscription

Cancels the caller's Paystack subscription at period end (non-immediate). Verifies subscription ownership with Paystack before disabling. Takes no payload.

Response
FieldTypeDescription
successbooleanAlways true on success
messagestringHuman-readable confirmation
periodEndstring | nullISO date when access expires
Firebase SDK
import { getFunctions, httpsCallable } from 'firebase/functions';

const functions = getFunctions();
const cancel = httpsCallable(functions, 'cancelSubscription');

const result = await cancel();
// result.data = { success: true, message: "...", periodEnd: "2025-06-15" }
Error codes
CodeCause
unauthenticatedUser not signed in
failed-preconditionNo active subscription (already free)
permission-deniedSubscription doesn't match authenticated user's email
internalPaystack API error — retry
FNrequestSmsAccess SCALESubmit SMS compliance request

Submits an SMS/USSD access request for admin compliance review. Requires Scale plan. Stores the request in sms_access_requests and notifies the ops team. One pending request per user.

Payload Fields
FieldTypeReqDescription
businessNamestringrequiredLegal/trading name of the business
contactNamestringrequiredContact person full name
contactEmailstringrequiredContact email address
contactPhonestringoptionalKenyan phone number for follow-up
useCasestringrequiredDescription of SMS/USSD usage
estimatedVolumestringoptionalEstimated monthly SMS volume
docBusinessRegstringrequiredFirebase Storage URL — business registration certificate
docKraPinCertstringrequiredFirebase Storage URL — KRA PIN certificate
docDirectorIdstringrequiredFirebase Storage URL — director's national ID/passport
optInFlowDescriptionstringrequiredWritten description of end-user opt-in mechanism
Response statuses
StatusMeaning
submittedRequest created, team notified via email
already_pendingExisting pending request found — deduplicated
already_enabledSMS is already active on the account
Upload documents to Firebase Storage before calling this function. Pass the download URLs in the doc* fields. Admin manually sets users/{uid}.smsEnabled = true after review.
FNcontactSales ALL PLANSSend a sales / enterprise enquiry

Sends a sales/enterprise enquiry to support@weather-ai.co via Resend and stores the lead in sales_leads. Unauthenticated calls are permitted (pricing page use case).

Payload Fields
FieldTypeReqDescription
namestringrequiredContact person name
emailstringrequiredContact email
companystringoptionalCompany name
messagestringoptionalFree-form message
typestringoptionalsales (pricing page) or custom (billing panel upgrade). Default: sales
currentPlanstringoptionalCaller's current plan. Default: free
FNgetPaystackConfig ALL PLANSFetch Paystack public config

Returns the Paystack public key and plan pricing for the frontend to initialize the Paystack widget. The secret key is never returned.

Response shape
Response
{
  "public_key": "pk_live_...",
  "plans": {
    "pro":   { "kes": 2500, "usd": 19, "name": "Pro" },
    "scale": { "kes": 9500, "usd": 79, "name": "Scale" }
  }
}