Hypermedia APIs — HATEOAS
Also Known As
HATEOAS
HAL
JSON:API
hypermedia
REST level 3
TL;DR
REST APIs that include links in responses — clients discover available actions from the response rather than hardcoding URLs, making APIs self-describing and evolvable.
Explanation
HATEOAS (Hypermedia as the Engine of Application State) is a REST constraint where responses include links to related resources and available actions. JSON:API and HAL (Hypertext Application Language) are standardised hypermedia formats. A payment response includes links: {self: /payments/42, refund: /payments/42/refund, receipt: /payments/42/receipt}. Benefits: clients are not hardcoded to URL structure, available actions change based on state (no refund link if already refunded), and APIs are self-documenting. In practice: rarely implemented fully; most REST APIs are not truly HATEOAS — they use stable versioned URLs instead.
Common Misconception
✗ REST requires HATEOAS — HATEOAS is Level 3 of Richardson's REST maturity model; most production REST APIs are Level 2 (resources + HTTP verbs) and work perfectly well without hypermedia links.
Why It Matters
A fully HATEOAS API can change its URL structure without breaking clients — clients follow links rather than constructing URLs, decoupling them from the API's URL design decisions.
Common Mistakes
- Hardcoding URLs in API clients instead of following links — defeats the purpose of HATEOAS.
- Including links to unavailable actions — the presence of a link implies the action is available.
- Inconsistent link relation names — use standard relations (self, next, prev) where possible.
- HATEOAS as a substitute for documentation — links are machine-readable; humans still need docs.
Code Examples
✗ Vulnerable
// Client hardcodes URL structure:
$baseUrl = 'https://api.example.com/v2';
$payment = $client->get($baseUrl . '/payments/' . $id);
$refund = $client->post($baseUrl . '/payments/' . $id . '/refund');
// Breaks if API moves to /v3/payments or changes URL structure
✓ Fixed
// HATEOAS response:
// GET /payments/42
{
"id": 42,
"amount": 99.99,
"status": "completed",
"_links": {
"self": {"href": "/payments/42"},
"refund": {"href": "/payments/42/refund", "method": "POST"},
"receipt": {"href": "/payments/42/receipt"}
}
}
// No refund link when status=refunded — client knows refund unavailable
// Client follows _links.refund — URL can change without breaking client
References
Tags
🤝 Adopt this term
£79/year · your link shown here
Added
16 Mar 2026
Edited
22 Mar 2026
Views
19
🤖 AI Guestbook educational data only
|
|
Last 30 days
Agents 0
No pings yet today
No pings yesterday
Amazonbot 6
Perplexity 3
Unknown AI 3
Ahrefs 2
Google 2
Also referenced
How they use it
crawler 14
crawler_json 1
pre-tracking 1
Related categories
⚡
DEV INTEL
Tools & Severity
🔵 Info
⚙ Fix effort: High
⚡ Quick Fix
Include a _links section in API responses with related action URLs — this lets clients discover available operations without hardcoding URLs, making your API more self-describing
📦 Applies To
any
web
api
🔗 Prerequisites
🔍 Detection Hints
API clients hardcoding URL patterns instead of following links from responses; no HATEOAS links in REST API responses
Auto-detectable:
✗ No
postman
hal-browser
⚠ Related Problems
🤖 AI Agent
Confidence: Low
False Positives: High
✗ Manual fix
Fix: High
Context: File
Tests: Update