Error reference
Consolidated taxonomy of the error shapes you can receive. HTTP status on the left, canonical body on the right.
Authentication
| HTTP | Body | Cause |
|---|---|---|
| 401 | {"message": "API key missing"} | No Authorization / X-API-Key header. |
| 401 | {"message": "Invalid API key"} | Hash mismatch, revoked, or expired. |
| 404 | — | Cross-tenant resource or missing. 404 never 403. |
Validation
Standard Laravel-shaped 422s:
json
{
"message": "The pickup location field is required. (and 2 more errors)",
"errors": {
"pickup_location": ["The pickup location field is required when pickup lat is not present."],
"pickup_date": ["The pickup date field is required."]
}
}
Coupons
| HTTP | Body |
|---|---|
| 404 | {"error": "coupon_not_found"} |
| 422 | {"error": "coupon_not_valid"} |
| 422 | {"error": "coupon_brand_or_rate_mismatch"} |
| 422 | {"error": "coupon_country_mismatch"} |
| 422 | {"error": "coupon_days_out_of_range"} |
| 422 | {"error": "coupon_validation_failed", "reason": "..."} |
Upstream GDS errors
When the provider rejects a request, GreenFlow surfaces the message verbatim inside error.message. These are 422s, not 5xx — the provider said no, your payload was syntactically fine.
json
{ "error": { "message": "RATE NOT AVAILABLE FOR THIS CAR CLASS" } }
Intra-meta states (non-HTTP)
Inside meta.{vendor}.reason in /fleet/list responses, per-brand entries carry a reason key when the brand contributed zero vehicles. These are not HTTP errors: the response is 200, but one or more brands are silent for this query.
| reason | Notes |
|---|---|
| no_offices_for_pickup | Office code doesn't apply to this brand. |
| no_offices_for_pickup_within_radius | No office found in pickup_radius_km for lat/lng search. |
| circuit_open | Adapter circuit breaker is open. |
| provider_error | Exception parsing the provider response. See errors.{vendor}. |
| provider_returned_empty | Provider returned zero vehicles. |