Visa rules and application processing for the Horn of Africa
Ethiopia, Somalia, Djibouti and Kenya. Ask whether a traveller needs a visa and get an answer you can defend — every verdict carries the statutory instrument behind it.
What it answers
Not “is a visa required” as a boolean, but the question an airline actually asks: does this passenger, with this passport, on this itinerary, need a visa? A nationality lookup alone cannot express a transit exemption or a residence-permit exemption, which is why the request body is a person and a journey.
curl -X POST https://api.haavisa.com/v1/check \
-H "Authorization: Bearer $HAAVISA_API_KEY" \
-H "Content-Type: application/json" \
-d '{
"nationality_iso3": "SOM",
"destination_iso3": "KEN",
"transit_airside": true
}'{
"verdict": "exempt",
"visa_required": false,
"notes": ["Passengers in transit arriving and leaving on the same aircraft, or
transferring, who do not leave airport precincts."],
"citation": "Kenya Citizenship and Immigration (Amendment) Rules, 2025 (s.48, Act No. 12 of 2011)",
"matched_rule_id": "ken.transit.airside",
"sources": [{ "url": "https://etakenya.go.ke/general-information", "accessed": "2026-10-01" }]
}The same passport leaving the airport is eta_required. That difference is the product.
Three things that shape every answer
Every answer is cited
A verdict without a source is an argument. Each one names the statutory instrument and when we last verified it, so a disputed answer is traceable in minutes.
Unknown is a real answer
Where we hold no verified rule, the API returns unknown and a null visa_required. It never guesses. Treat it as “check manually”, never as “no visa needed”.
Tenants are isolated
One key, one tenant, one rate budget. Records belonging to another tenant are not merely forbidden but invisible — they answer 404, not 403.
Three ways in
The API is the product. The other two exist because a partner’s traveller should not have to leave the partner’s website.
REST API
168 operationsEverything. Airlines typically use POST /v1/check for boarding; OTAs use the application lifecycle.
Embeddable widget
hv_pub_ keysA drop-in requirement check for a travel agent's site. Renders in a shadow root, so it cannot be broken by page CSS.
TypeScript SDK
@haavisa/sdkTypes generated from this site's OpenAPI document, plus typed errors and retries.
Start with the quickstart, or read how eligibility works before you build on it.