Athena Bedbank API
RESTful API for accessing Athena's consolidated hotel inventory. Search hotels, check availability, and create bookings programmatically.
Content API
Hotel listings, descriptions, photos, amenities, and room types. Cacheable — content changes infrequently.
p99 < 200ms
Cache API
Pre-computed availability and pricing. Fast responses from batch-updated data. Do not cache responses client-side.
p99 < 100ms
Booking API
Create, retrieve, modify, and cancel bookings. Live availability check on every create request.
p99 < 1,000ms
Base URLs
Production
Live
https://api.athena-bedbank.com/v1
Sandbox
Test
https://api-sandbox.athena-bedbank.com/v1
Conventions
Currency
All monetary values are in integer cents (e.g. 10000 = €100.00). Never floating point.
Dates
All dates in YYYY-MM-DD format. All timestamps in ISO 8601 with UTC timezone.
Pagination
List endpoints use page + page_size parameters. Response wraps data in { data, total, page, page_size }.
Idempotency
Pass Idempotency-Key header on POST /v1/bookings to safely retry without duplicate bookings.
Authentication
All requests require an API key passed in the X-Api-Key header.
⚠️ Key Security
Never expose your API key in client-side code, public repositories, or logs. The key grants full access to your account's billable API usage.
Request Example
# All requests require X-Api-Key header
curl -X GET \
https://api.athena-bedbank.com/v1/hotels \
-H "X-Api-Key: bed_live_your_key_here" \
-H "Accept: application/json"
Key Types
| Prefix | Environment | Behavior |
bed_live_… | Production | Real hotel inventory · Metered & billed · Rate limited by tier |
bed_test_… | Sandbox | Fixture data only (Meridian Hotels) · No billing · No rate limit |
Validate Your Key
POST /v1/session/validate
// Response:
{
"customer_id": "22222222-0000-0000-0000-000000000001",
"customer_name": "SunTours Travel Group",
"environment": "production",
"tier": "Tier2",
"rate_limit_rps": 200
}
Error Handling
All errors return a consistent JSON body with a machine-readable code and human-readable message.
// Error response shape
{
"code": "room_unavailable",
"message": "Room mh-r4521 is no longer available for Jun 15–18.",
"details": {
"hotel_id": "mh-a1b2c3d4",
"room_id": "mh-r4521"
}
}
| HTTP Status | Code | Meaning |
| 200 | — | Success |
| 400 | invalid_parameter | Missing or malformed request parameter |
| 401 | invalid_api_key | Key missing, invalid, or revoked |
| 403 | permission_denied | API product not enabled for this key |
| 404 | not_found | Hotel, room, or booking not found |
| 409 | room_unavailable | Room no longer available (race condition on booking) |
| 409 | cancellation_expired | Cancellation deadline passed |
| 422 | business_rule_violation | Min-stay, invalid board type, date logic error |
| 429 | rate_limit_exceeded | Request rate exceeded — check Retry-After header |
| 503 | account_suspended | Account suspended or balance depleted |
Rate Limiting
Rate limits are enforced per API key using a sliding window algorithm (1-second window).
| Tier | Requests/sec | Daily Limit | Typical Use |
| Sandbox | 10 | 10,000 | Testing only |
| Tier 1 | 50 | 500,000 | Small OTA |
| Tier 2 | 200 | 5,000,000 | Mid-size OTA |
| Tier 3 | 1,000 | Unlimited | Large OTA / Enterprise |
Rate Limit Headers
# Response headers on every request:
X-RateLimit-Limit: 200 # requests/sec for this key
X-RateLimit-Remaining: 187 # remaining in current window
X-RateLimit-Reset: 1717156800 # Unix timestamp for window reset
# On 429:
Retry-After: 1 # seconds to wait before retrying
Retry Pattern
// Recommended retry with exponential backoff:
async function apiRequest(url, options, attempt = 0) {
const res = await fetch(url, options);
if (res.status === 429) {
const wait = parseInt(res.headers.get('Retry-After') || '1');
await sleep(wait * 1000 * Math.pow(2, attempt));
return apiRequest(url, options, attempt + 1);
}
return res;
}
Sandbox & Testing
The sandbox environment uses your bed_test_ key and returns fixture data (Meridian Hotels group). No real bookings, no billing.
Sandbox Base URL
https://api-sandbox.athena-bedbank.com/v1
Fixture Hotels
| Hotel ID | Name | City | Stars |
mh-meridian-001 | Meridian Grand Istanbul | Istanbul, TR | ⭐⭐⭐⭐⭐ |
mh-meridian-002 | Meridian Boutique Ankara | Ankara, TR | ⭐⭐⭐⭐ |
mh-meridian-003 | Meridian Beach Antalya | Antalya, TR | ⭐⭐⭐⭐⭐ |
mh-meridian-004 | Meridian City Rome | Rome, IT | ⭐⭐⭐⭐ |
mh-meridian-005 | Meridian Luxury Paris | Paris, FR | ⭐⭐⭐⭐⭐ |
Sandbox Booking Behavior
- ✅
POST /v1/bookings returns a realistic confirmation response
- ✅
DELETE /v1/bookings/{ref} simulates cancellation
- ❌ No real hotel systems are contacted
- ❌ No metering — sandbox usage is not billed
- ❌ Sandbox bookings do not appear in Customer Portal billing
Content API
Access hotel content: descriptions, photos, amenities, and room types. Content is updated periodically — you may cache responses for up to 24 hours.
Caching guidance: Content responses may be cached client-side for up to 24 hours. Use the updated_since parameter for delta synchronization.
GET/v1/hotels
List hotels with filters
GET/v1/hotels/{id}
Full hotel detail
GET/v1/hotels/{id}/rooms
Hotel room types
GET
/v1/hotels
Returns a paginated list of hotels. Filter by country, city, category, or star rating. Use updated_since for incremental sync.
Query Parameters
| Parameter | Type | Description |
country_code | string | ISO 3166-1 alpha-2 (e.g. TR) |
city | string | City name (partial match supported) |
min_stars | number | Minimum star rating (1.0–5.0) |
category | string | hotel · apartment · hostel · resort |
q | string | Full-text search on name and description |
updated_since | datetime | ISO 8601 — return only hotels updated after this timestamp (delta sync) |
page | integer | Page number, default 1 |
page_size | integer | Results per page, default 100, max 1000 |
Example
curl -X GET \
"https://api.athena-bedbank.com/v1/hotels?country_code=TR&min_stars=4&page_size=50" \
-H "X-Api-Key: bed_live_your_key"
Response
{
"data": [
{
"id": "mh-a1b2c3d4",
"name": "Swissotel The Bosphorus",
"country_code": "TR",
"city": "Istanbul",
"latitude": 41.0422,
"longitude": 29.0073,
"star_rating": 5.0,
"category": "hotel"
}
],
"total": 1842,
"page": 1,
"page_size": 50
}
GET
/v1/hotels/{id}
Returns full hotel details including description, amenities, photos, and room types. Specify lang for localized content.
Path Parameters
| Parameter | Type | Description |
id required | UUID | Hotel ID from /v1/hotels list |
lang | string | Content language: en (default) · tr · de · fr · es · ar |
// GET /v1/hotels/mh-a1b2c3d4?lang=en
{
"id": "mh-a1b2c3d4",
"name": "Swissotel The Bosphorus",
"description": "A landmark luxury hotel overlooking the Bosphorus strait...",
"amenities": ["wifi", "pool", "spa", "gym", "restaurant", "bar"],
"photos": [
{ "url": "https://cdn.athena-bedbank.com/hotels/mh-a1b2c3d4/01.jpg", "caption": "Exterior" },
{ "url": "https://cdn.athena-bedbank.com/hotels/mh-a1b2c3d4/02.jpg", "caption": "Pool" }
],
"rooms": [
{ "id": "mh-r4521", "name": "Deluxe Room City View", "max_occupancy": 2 },
{ "id": "mh-r4522", "name": "Suite Bosphorus View", "max_occupancy": 3 }
]
}
Cache API
Pre-computed availability and pricing data. Designed for high-volume search operations.
⚠️ Do not cache responses: Despite the name, Cache API responses must not be stored client-side. Pricing and availability change frequently. Always fetch fresh data per user search.
GET
/v1/availability
Returns availability and pricing for up to 50 hotels for a given date range. p99 target: 100ms.
Query Parameters
| Parameter | Type | Description |
hotel_ids required | string | Comma-separated hotel UUIDs, max 50 |
check_in required | date | YYYY-MM-DD |
check_out required | date | YYYY-MM-DD (must be after check_in) |
adults required | integer | Number of adults (1–8) |
currency | string | ISO 4217 currency code, default EUR |
// Response — array of availability results per hotel
[
{
"hotel_id": "mh-a1b2c3d4",
"hotel_name": "Swissotel The Bosphorus",
"check_in": "2026-06-15",
"check_out": "2026-06-18",
"nights": 3,
"rooms": [
{
"room_id": "mh-r4521",
"room_name": "Deluxe Room City View",
"board": "BB",
"currency": "EUR",
"net_rate_cents": 18000,
"total_cents": 54000,
"available": true,
"cancellation_policy": "Free cancellation until 48h before check-in"
}
]
}
]
Booking API
Create, retrieve, modify, and cancel bookings. Every create request performs a live availability check.
⚠️ Expect 409 Conflicts: Because we check live availability at booking time, another customer may have booked the same room between your availability query and booking request. Always handle 409 room_unavailable by re-querying availability and presenting alternatives.
POST
/v1/bookings
Create a booking. Live availability is checked at request time. Pass Idempotency-Key to safely retry without duplicating bookings.
Request Body
| Field | Type | Description |
hotel_id required | UUID | Hotel ID |
room_id required | UUID | Room type ID from availability response |
check_in required | date | YYYY-MM-DD |
check_out required | date | YYYY-MM-DD |
board required | string | RO · BB · HB · FB · AI |
guests required | array | At least one adult guest with first_name, last_name, type |
customer_reference required | string | Your own booking reference (stored for reconciliation) |
special_requests | string | Optional free-text requests for the hotel |
// Request
curl -X POST https://api.athena-bedbank.com/v1/bookings \
-H "X-Api-Key: bed_live_your_key" \
-H "Content-Type: application/json" \
-H "Idempotency-Key: bkg-suntours-20260615-001" \
-d '{
"hotel_id": "mh-a1b2c3d4",
"room_id": "mh-r4521",
"check_in": "2026-06-15",
"check_out": "2026-06-18",
"board": "BB",
"customer_reference": "ST-BKG-4821",
"guests": [
{ "first_name": "Maria", "last_name": "Garcia", "type": "adult" },
{ "first_name": "Carlos", "last_name": "Garcia", "type": "adult" }
]
}'
// 201 Created
{
"id": "bk-x9y8z7w6",
"reference": "ATH-2026-88421",
"hotel_name": "Swissotel The Bosphorus",
"room_name": "Deluxe Room City View",
"check_in": "2026-06-15",
"check_out": "2026-06-18",
"nights": 3,
"board": "BB",
"total_cents": 54000,
"currency": "EUR",
"status": "confirmed",
"cancellation_deadline": "2026-06-13T23:59:59Z"
}
Quick Start
From zero to your first booking in 5 steps.
Step 1 — Validate your key
curl -X POST https://api-sandbox.athena-bedbank.com/v1/session/validate \
-H "X-Api-Key: bed_test_your_sandbox_key"
Step 2 — List hotels
curl "https://api-sandbox.athena-bedbank.com/v1/hotels?country_code=TR&page_size=10" \
-H "X-Api-Key: bed_test_your_sandbox_key"
Step 3 — Check availability
curl "https://api-sandbox.athena-bedbank.com/v1/availability?hotel_ids=mh-meridian-001&check_in=2026-07-01&check_out=2026-07-04&adults=2" \
-H "X-Api-Key: bed_test_your_sandbox_key"
Step 4 — Create a booking
curl -X POST https://api-sandbox.athena-bedbank.com/v1/bookings \
-H "X-Api-Key: bed_test_your_sandbox_key" \
-H "Content-Type: application/json" \
-d '{"hotel_id":"mh-meridian-001","room_id":"mh-r-m001","check_in":"2026-07-01","check_out":"2026-07-04","board":"BB","customer_reference":"TEST-001","guests":[{"first_name":"Test","last_name":"User","type":"adult"}]}'
Step 5 — Complete certification
Once all sandbox test cases pass in your Customer Portal, contact
support@athena-bedbank.com to request production access. Your account manager will issue a
bed_live_ key within 1 business day.
Handling 409 Conflicts
A 409 on POST /v1/bookings means the room was booked by another customer between your availability check and booking request. This is normal in a multi-tenant marketplace.
// Recommended flow:
async function bookWithRetry(params) {
// 1. Check availability
const avail = await getAvailability(params);
const room = avail[0].rooms.find(r => r.available);
if (!room) return { error: 'no_rooms' };
// 2. Attempt booking
const res = await createBooking({ ...params, room_id: room.room_id });
// 3. Handle 409 — re-query and show alternatives
if (res.status === 409) {
const freshAvail = await getAvailability(params);
return { alternatives: freshAvail[0].rooms.filter(r => r.available) };
}
return res.json();
}
GET/v1/hotels/{id}/rooms
Returns all room types for a given hotel.
// GET /v1/hotels/mh-a1b2c3d4/rooms
[
{
"id": "mh-r4521",
"name": "Deluxe Room City View",
"bed_configuration": "1 King Bed",
"max_occupancy": 2
},
{
"id": "mh-r4522",
"name": "Suite Bosphorus View",
"bed_configuration": "1 King Bed + Living Area",
"max_occupancy": 3
}
]
POST/v1/availability/batch
Query availability for multiple hotel/date combinations in a single request. Max 100 queries per call.
{
"queries": [
{ "hotel_ids": ["mh-a1b2c3d4"], "check_in": "2026-06-15", "check_out": "2026-06-18", "adults": 2 },
{ "hotel_ids": ["mh-e5f6g7h8"], "check_in": "2026-06-20", "check_out": "2026-06-23", "adults": 2 }
]
}
GET/v1/rates
Returns detailed nightly rate breakdown for a specific hotel/room/date combination.
// GET /v1/rates?hotel_id=mh-a1b2c3d4&room_id=mh-r4521&check_in=2026-06-15&check_out=2026-06-18
{
"hotel_id": "mh-a1b2c3d4",
"room_id": "mh-r4521",
"net_rate_cents": 18000,
"total_cents": 54000,
"currency": "EUR",
"available": true,
"night_breakdown": [
{ "date": "2026-06-15", "rate_cents": 17000 },
{ "date": "2026-06-16", "rate_cents": 18000 },
{ "date": "2026-06-17", "rate_cents": 19000 }
]
}
GET/v1/bookings/{ref}
Retrieve a booking by its Athena reference number.
// GET /v1/bookings/ATH-2026-88421
{
"id": "bk-x9y8z7w6",
"reference": "ATH-2026-88421",
"status": "confirmed",
"check_in": "2026-06-15",
"check_out": "2026-06-18",
"total_cents": 54000,
"cancellation_deadline": "2026-06-13T23:59:59Z"
}
DELETE/v1/bookings/{ref}
Cancel a booking. Returns 409 if the cancellation deadline has passed.
// 200 OK — cancellation confirmed
{
"reference": "ATH-2026-88421",
"status": "cancelled",
"refund_cents": 54000,
"cancelled_at": "2026-06-12T09:31:00Z"
}
// 409 — past deadline
{ "code": "cancellation_expired", "message": "Cancellation deadline was Jun 13 23:59 UTC" }