Developer Portal
Connect your channel manager, PMS, or booking platform with RoomsHatch. Our REST API lets you sync properties, manage availability, update rates, and process bookings programmatically.
Channel Managers
Sync availability and rates across multiple OTAs and direct booking channels.
Suppliers & Partners
Submit properties, services, and experiences directly into the RoomsHatch marketplace.
PMS Integrations
Automate booking management, guest data, and calendar sync with your property management system.
Getting Started
- 1Register — Create a RoomsHatch account if you don't have one yet.
- 2Apply for a test key — Submit an application describing your integration use case.
- 3Integrate — Use your test API key to build and test your integration against our sandbox.
- 4Go live — Apply for a live key when you're ready for production.
API Reference
v1REST API for channel managers, PMS integrations, and external systems to sync properties, availability, rates, and bookings with RoomsHatch.
Base URL: https://yourdomain.com/api/v1
Content Type: application/json
Rate Limit: 100 requests per minute per API key
Authentication
All API requests require an API key passed in the X-API-Key header. Apply for a key through our application form. Test keys use the prefix rh_test_ and live keys use rh_live_.
curl -H "X-API-Key: rh_live_abc123..." \ https://yourdomain.com/api/v1/properties
Available Permissions
read:propertiesList and view properties
write:availabilityUpdate availability/blocked dates
read:availabilityQuery availability
write:ratesUpdate pricing
read:ratesQuery pricing
read:experiencesList and view experiences
write:experiencesManage experience schedules
read:servicesList and view services
write:servicesManage service schedules
read:bookingsList and view bookings
write:bookingsCreate and update bookings
*Full access (all permissions)
Properties
/api/v1/propertiesread:propertiesList all properties (listings + hotels) accessible by this API key.
Query Parameters
page integer Page number (default: 1) limit integer Results per page (default: 50, max: 100)
Response
{
"data": [
{
"id": "clx...",
"type": "listing",
"title": "Beachfront Villa",
"listingType": "BOOKABLE",
"city": "Zanzibar",
"country": "Tanzania",
"currency": "USD",
"pricePerNight": 150,
"maxGuests": 6,
"bedrooms": 3,
"bathrooms": 2,
"createdAt": "2026-01-15T00:00:00.000Z"
},
{
"id": "clx...",
"type": "hotel",
"title": "Grand Hotel",
"city": "Nairobi",
"country": "Kenya",
"currency": "USD",
"starRating": 4,
"roomTypes": [
{ "id": "clx...", "name": "Deluxe", "totalRooms": 10, "pricePerNight": 200 }
],
"createdAt": "2026-02-01T00:00:00.000Z"
}
],
"meta": { "page": 1, "limit": 50, "total": 12 }
}Example
curl -H "X-API-Key: rh_live_xxx" \ "https://yourdomain.com/api/v1/properties?page=1&limit=10"
/api/v1/properties/:idread:propertiesGet full details for a single property (listing or hotel) including room types for hotels.
Response
{
"data": {
"id": "clx...",
"type": "listing",
"title": "Beachfront Villa",
"description": "A beautiful villa...",
"listingType": "BOOKABLE",
"city": "Zanzibar",
"country": "Tanzania",
"address": "123 Beach Rd",
"latitude": -6.16,
"longitude": 39.19,
"currency": "USD",
"pricePerNight": 150,
"weekendPrice": 180,
"maxGuests": 6,
"bedrooms": 3,
"bathrooms": 2,
"instantBooking": true,
"createdAt": "2026-01-15T...",
"updatedAt": "2026-04-10T..."
}
}Example
curl -H "X-API-Key: rh_live_xxx" \ https://yourdomain.com/api/v1/properties/clx123
Availability
/api/v1/properties/:id/availabilityread:availabilityQuery availability for a property within a date range. For hotels, returns per-room-type blocked counts.
Query Parameters
from string (required) Start date (YYYY-MM-DD) to string (required) End date (YYYY-MM-DD)
Response
// Listing response:
{
"data": [
{ "date": "2026-05-01", "isBlocked": false, "note": null, "source": null },
{ "date": "2026-05-02", "isBlocked": true, "note": "External booking", "source": "ical_import:clx..." }
]
}
// Hotel response:
{
"data": [
{
"roomTypeId": "clx...",
"roomTypeName": "Deluxe",
"totalRooms": 10,
"dates": [
{ "date": "2026-05-01", "blockedCount": 2, "note": null, "source": null }
]
}
]
}Example
curl -H "X-API-Key: rh_live_xxx" \ "https://yourdomain.com/api/v1/properties/clx123/availability?from=2026-05-01&to=2026-05-31"
/api/v1/properties/:id/availabilitywrite:availabilityUpdate availability (block/unblock dates). For hotels, include roomTypeId. Max 365 dates per request.
Request Body
// Listing:
{
"dates": [
{ "date": "2026-05-15", "isBlocked": true, "note": "Maintenance" },
{ "date": "2026-05-16", "isBlocked": true, "note": "Maintenance" }
]
}
// Hotel:
{
"dates": [
{ "date": "2026-05-15", "roomTypeId": "clx...", "blockedCount": 3, "note": "Group block" }
]
}Response
{
"data": [
{ "date": "2026-05-15", "isBlocked": true },
{ "date": "2026-05-16", "isBlocked": true }
]
}Example
curl -X PUT -H "X-API-Key: rh_live_xxx" \
-H "Content-Type: application/json" \
-d '{"dates":[{"date":"2026-05-15","isBlocked":true}]}' \
https://yourdomain.com/api/v1/properties/clx123/availabilityRates
/api/v1/properties/:id/ratesread:ratesQuery pricing for a property within a date range. Returns base rates, pricing rules (listings), or room type rates (hotels).
Query Parameters
from string (required) Start date (YYYY-MM-DD) to string (required) End date (YYYY-MM-DD)
Response
// Listing:
{
"data": {
"basePrice": 150,
"weekendPrice": 180,
"currency": "USD",
"pricingRules": [
{
"id": "clx...",
"name": "High Season",
"startDate": "2026-06-01",
"endDate": "2026-08-31",
"pricePerNight": 220,
"minNights": 3
}
]
}
}
// Hotel:
{
"data": {
"currency": "USD",
"breakfastPrice": 15,
"roomTypes": [
{
"id": "clx...",
"name": "Deluxe",
"pricePerNight": 200,
"weekendPrice": 240,
"customDatePrices": [
{ "date": "2026-05-20", "price": 280 }
]
}
]
}
}Example
curl -H "X-API-Key: rh_live_xxx" \ "https://yourdomain.com/api/v1/properties/clx123/rates?from=2026-05-01&to=2026-05-31"
/api/v1/properties/:id/rateswrite:ratesUpdate per-date prices for hotel room types. For listings, use pricing rules via the dashboard. Max 365 dates per request.
Request Body
{
"dates": [
{ "date": "2026-05-20", "roomTypeId": "clx...", "price": 280 },
{ "date": "2026-05-21", "roomTypeId": "clx...", "price": 280 }
]
}Response
{
"data": [
{ "date": "2026-05-20", "roomTypeId": "clx...", "price": 280 },
{ "date": "2026-05-21", "roomTypeId": "clx...", "price": 280 }
]
}Example
curl -X PUT -H "X-API-Key: rh_live_xxx" \
-H "Content-Type: application/json" \
-d '{"dates":[{"date":"2026-05-20","roomTypeId":"clx...","price":280}]}' \
https://yourdomain.com/api/v1/properties/clx123/ratesExperiences
/api/v1/experiencesread:experiencesList all experiences accessible by this API key. Returns pricing tiers and category info.
Query Parameters
page integer Page number (default: 1) limit integer Results per page (default: 50, max: 100)
Response
{
"data": [
{
"id": "clx...",
"title": "Zanzibar Spice Tour",
"experienceType": "EXCURSION",
"category": { "id": "clx...", "name": "Food & Drink", "slug": "food-drink" },
"city": "Zanzibar",
"country": "Tanzania",
"currency": "USD",
"durationMinutes": 180,
"minParticipants": 1,
"maxParticipants": 12,
"skillLevel": "ALL_LEVELS",
"pricingTiers": [
{ "minSize": 1, "maxSize": 4, "pricePerPerson": 45, "isPrivate": false, "flatRate": null }
],
"createdAt": "2026-03-01T..."
}
],
"meta": { "page": 1, "limit": 50, "total": 8 }
}Example
curl -H "X-API-Key: rh_live_xxx" \ "https://yourdomain.com/api/v1/experiences?page=1&limit=10"
/api/v1/experiences/:idread:experiencesGet full details for an experience including images, pricing tiers, itinerary, traveler types, and accessibility features.
Response
{
"data": {
"id": "clx...",
"title": "Zanzibar Spice Tour",
"description": "Explore the famous spice farms...",
"experienceType": "EXCURSION",
"category": { "id": "clx...", "name": "Food & Drink", "slug": "food-drink" },
"city": "Zanzibar",
"country": "Tanzania",
"address": "Spice Farm Road",
"meetingPoint": "Hotel lobby pickup",
"latitude": -6.16,
"longitude": 39.19,
"currency": "USD",
"durationMinutes": 180,
"languages": ["English", "Swahili"],
"skillLevel": "ALL_LEVELS",
"minParticipants": 1,
"maxParticipants": 12,
"included": ["Transport", "Lunch", "Guide"],
"excluded": ["Drinks"],
"toBring": ["Sunscreen", "Camera"],
"itinerary": [
{ "step": 1, "time": "09:00", "description": "Hotel pickup" },
{ "step": 2, "time": "09:30", "description": "Arrive at spice farm" }
],
"images": [{ "id": "clx...", "url": "https://...", "alt": "Spice farm", "order": 0 }],
"pricingTiers": [
{ "id": "clx...", "minSize": 1, "maxSize": 4, "pricePerPerson": 45, "isPrivate": false, "flatRate": null },
{ "id": "clx...", "minSize": 5, "maxSize": 12, "pricePerPerson": 35, "isPrivate": false, "flatRate": null }
],
"travelerTypes": [{ "name": "Families", "slug": "families" }],
"accessibilityFeatures": [{ "name": "Wheelchair Access", "slug": "wheelchair-access", "category": "mobility" }],
"createdAt": "2026-03-01T...",
"updatedAt": "2026-04-10T..."
}
}Example
curl -H "X-API-Key: rh_live_xxx" \ https://yourdomain.com/api/v1/experiences/clx123
/api/v1/experiences/:id/schedulesread:experiencesList available time slots for an experience within a date range. Returns capacity and current booking counts.
Query Parameters
from string (required) Start date (YYYY-MM-DD) to string (required) End date (YYYY-MM-DD)
Response
{
"data": [
{
"id": "clx...",
"date": "2026-05-15",
"startTime": "09:00",
"endTime": "12:00",
"capacity": 12,
"isBlocked": false,
"booked": 4,
"recurrence": "WEEKLY"
}
]
}Example
curl -H "X-API-Key: rh_live_xxx" \ "https://yourdomain.com/api/v1/experiences/clx123/schedules?from=2026-05-01&to=2026-05-31"
/api/v1/experiences/:id/scheduleswrite:experiencesCreate or update schedule slots for an experience. Upserts by date + startTime. Max 365 entries per request.
Request Body
{
"schedules": [
{
"date": "2026-05-20",
"startTime": "09:00",
"endTime": "12:00",
"capacity": 12,
"isBlocked": false
},
{
"date": "2026-05-21",
"startTime": "14:00",
"endTime": "17:00",
"capacity": 8,
"isBlocked": false
}
]
}Response
{
"data": [
{ "id": "clx...", "date": "2026-05-20", "startTime": "09:00", "endTime": "12:00", "isBlocked": false },
{ "id": "clx...", "date": "2026-05-21", "startTime": "14:00", "endTime": "17:00", "isBlocked": false }
]
}Example
curl -X PUT -H "X-API-Key: rh_live_xxx" \
-H "Content-Type: application/json" \
-d '{"schedules":[{"date":"2026-05-20","startTime":"09:00","endTime":"12:00","capacity":12}]}' \
https://yourdomain.com/api/v1/experiences/clx123/schedulesServices
/api/v1/servicesread:servicesList all services accessible by this API key. Returns packages and base pricing tiers.
Query Parameters
page integer Page number (default: 1) limit integer Results per page (default: 50, max: 100)
Response
{
"data": [
{
"id": "clx...",
"title": "Deep Tissue Massage",
"category": { "id": "clx...", "name": "Wellness", "slug": "wellness" },
"city": "Nairobi",
"country": "Kenya",
"currency": "USD",
"durationMinutes": 60,
"serviceLocation": "In-studio",
"minParticipants": 1,
"maxParticipants": 4,
"skillLevel": "ALL_LEVELS",
"packages": [
{ "id": "clx...", "name": "Premium Package", "durationMinutes": 90 }
],
"pricingTiers": [
{ "minSize": 1, "maxSize": 2, "pricePerPerson": 80, "isPrivate": false, "flatRate": null }
],
"createdAt": "2026-02-15T..."
}
],
"meta": { "page": 1, "limit": 50, "total": 15 }
}Example
curl -H "X-API-Key: rh_live_xxx" \ "https://yourdomain.com/api/v1/services?page=1&limit=10"
/api/v1/services/:idread:servicesGet full details for a service including packages with their own pricing tiers, images, and highlights.
Response
{
"data": {
"id": "clx...",
"title": "Deep Tissue Massage",
"description": "Professional therapeutic massage...",
"category": { "id": "clx...", "name": "Wellness", "slug": "wellness" },
"city": "Nairobi",
"country": "Kenya",
"address": "123 Spa Street",
"serviceLocation": "In-studio",
"latitude": -1.29,
"longitude": 36.82,
"currency": "USD",
"durationMinutes": 60,
"languages": ["English"],
"skillLevel": "ALL_LEVELS",
"minParticipants": 1,
"maxParticipants": 4,
"included": ["Towels", "Oils"],
"excluded": ["Tips"],
"toBring": ["Comfortable clothing"],
"highlights": ["Certified therapists", "Organic products"],
"images": [{ "id": "clx...", "url": "https://...", "alt": "Spa room", "order": 0 }],
"pricingTiers": [
{ "id": "clx...", "minSize": 1, "maxSize": 2, "pricePerPerson": 80, "isPrivate": false, "flatRate": null }
],
"packages": [
{
"id": "clx...",
"name": "Premium Package",
"description": "Includes aromatherapy...",
"image": "https://...",
"durationMinutes": 90,
"pricingTiers": [
{ "id": "clx...", "minSize": 1, "maxSize": 2, "pricePerPerson": 120, "isPrivate": false, "flatRate": null }
]
}
],
"createdAt": "2026-02-15T...",
"updatedAt": "2026-04-10T..."
}
}Example
curl -H "X-API-Key: rh_live_xxx" \ https://yourdomain.com/api/v1/services/clx123
/api/v1/services/:id/schedulesread:servicesList available time slots for a service within a date range. Optionally filter by packageId.
Query Parameters
from string (required) Start date (YYYY-MM-DD) to string (required) End date (YYYY-MM-DD) packageId string (optional) Filter by package ID
Response
{
"data": [
{
"id": "clx...",
"date": "2026-05-15",
"startTime": "10:00",
"endTime": "11:00",
"capacity": 4,
"isBlocked": false,
"booked": 1,
"package": { "id": "clx...", "name": "Premium Package" },
"recurrence": "WEEKLY"
}
]
}Example
curl -H "X-API-Key: rh_live_xxx" \ "https://yourdomain.com/api/v1/services/clx123/schedules?from=2026-05-01&to=2026-05-31"
/api/v1/services/:id/scheduleswrite:servicesCreate or update schedule slots for a service. Optionally include packageId per entry. Upserts by serviceId + packageId + date + startTime. Max 365 entries.
Request Body
{
"schedules": [
{
"date": "2026-05-20",
"startTime": "10:00",
"endTime": "11:00",
"capacity": 4,
"packageId": "clx...",
"isBlocked": false
}
]
}Response
{
"data": [
{ "id": "clx...", "date": "2026-05-20", "startTime": "10:00", "endTime": "11:00", "isBlocked": false }
]
}Example
curl -X PUT -H "X-API-Key: rh_live_xxx" \
-H "Content-Type: application/json" \
-d '{"schedules":[{"date":"2026-05-20","startTime":"10:00","endTime":"11:00","packageId":"clx..."}]}' \
https://yourdomain.com/api/v1/services/clx123/schedulesBookings
/api/v1/bookingsread:bookingsList bookings across all properties. Filter by status, property, or type.
Query Parameters
page integer Page number (default: 1) limit integer Results per page (default: 50, max: 100) status string Filter by status: PENDING, CONFIRMED, CANCELLED, COMPLETED propertyId string Filter by property ID type string Filter by type: listing, hotel
Response
{
"data": [
{
"id": "clx...",
"type": "listing",
"bookingNumber": "RH-2026-00123",
"propertyId": "clx...",
"propertyTitle": "Beachfront Villa",
"checkIn": "2026-06-01",
"checkOut": "2026-06-05",
"numberOfNights": 4,
"adults": 2,
"children": 0,
"totalAmount": 600,
"currency": "USD",
"status": "CONFIRMED",
"paymentStatus": "PAID",
"bookingSource": "api",
"externalId": "ext-123",
"createdAt": "2026-04-19T..."
}
],
"meta": { "page": 1, "limit": 50, "total": 42 }
}Example
curl -H "X-API-Key: rh_live_xxx" \ "https://yourdomain.com/api/v1/bookings?status=CONFIRMED&type=listing"
/api/v1/bookingswrite:bookingsCreate a new booking from an external system. Bookings created via API are automatically confirmed with payment marked as paid.
Request Body
{
"propertyId": "clx...",
"type": "listing",
"checkIn": "2026-06-01",
"checkOut": "2026-06-05",
"adults": 2,
"children": 0,
"infants": 0,
"pets": 0,
"guestName": "John Doe",
"guestEmail": "john@example.com",
"specialRequests": "Late check-in",
"externalId": "channex-booking-456",
"totalAmount": 600
}
// For hotels, also include:
// "roomTypeId": "clx..."Response
{
"data": {
"id": "clx...",
"bookingNumber": "RH-2026-00456",
"status": "CONFIRMED",
"createdAt": "2026-04-19T..."
}
}Example
curl -X POST -H "X-API-Key: rh_live_xxx" \
-H "Content-Type: application/json" \
-d '{"propertyId":"clx...","type":"listing","checkIn":"2026-06-01","checkOut":"2026-06-05","adults":2,"guestName":"John Doe"}' \
https://yourdomain.com/api/v1/bookings/api/v1/bookings/:idread:bookingsGet full details for a single booking including guest info, pricing breakdown, and payment status.
Response
{
"data": {
"id": "clx...",
"type": "listing",
"bookingNumber": "RH-2026-00123",
"propertyId": "clx...",
"propertyTitle": "Beachfront Villa",
"guest": { "name": "John Doe", "email": "john@example.com" },
"checkIn": "2026-06-01",
"checkOut": "2026-06-05",
"numberOfNights": 4,
"adults": 2,
"children": 0,
"basePrice": 600,
"cleaningFee": 50,
"serviceFee": 30,
"taxAmount": 68,
"totalAmount": 748,
"currency": "USD",
"status": "CONFIRMED",
"paymentStatus": "PAID",
"bookingSource": "api",
"externalId": "channex-booking-456",
"createdAt": "2026-04-19T...",
"updatedAt": "2026-04-19T..."
}
}Example
curl -H "X-API-Key: rh_live_xxx" \ https://yourdomain.com/api/v1/bookings/clx123
/api/v1/bookings/:idwrite:bookingsUpdate a booking's status (confirm or cancel) or link an external ID.
Request Body
{
"status": "CANCELLED",
"externalId": "ext-updated-id"
}Response
{
"data": {
"id": "clx...",
"bookingNumber": "RH-2026-00123",
"status": "CANCELLED",
"updatedAt": "2026-04-19T..."
}
}Example
curl -X PATCH -H "X-API-Key: rh_live_xxx" \
-H "Content-Type: application/json" \
-d '{"status":"CANCELLED"}' \
https://yourdomain.com/api/v1/bookings/clx123Webhooks
Register webhook endpoints to receive real-time notifications when bookings are created, confirmed, or cancelled. Webhooks are tied to API keys and can subscribe to specific event types.
Event Types
booking.createdA new booking was created
booking.confirmedA booking was confirmed
booking.cancelledA booking was cancelled
availability.updatedAvailability was changed
Payload Format
POST https://your-webhook-url.com/webhook
Content-Type: application/json
X-Webhook-Signature: <HMAC-SHA256 hex digest>
X-Webhook-Event: booking.created
{
"event": "booking.created",
"data": {
"bookingId": "clx...",
"bookingNumber": "RH-2026-00123",
"propertyId": "clx...",
"type": "listing",
"checkIn": "2026-06-01",
"checkOut": "2026-06-05"
},
"timestamp": "2026-04-19T12:00:00.000Z"
}Signature Verification
Each webhook request includes an X-Webhook-Signature header containing an HMAC-SHA256 hex digest of the raw request body, signed with your webhook secret.
// Node.js verification example
const crypto = require('crypto');
function verifyWebhook(body, signature, secret) {
const expected = crypto
.createHmac('sha256', secret)
.update(body)
.digest('hex');
return signature === expected;
}Error Codes
All errors follow a standard format. The HTTP status code indicates the error category.
{
"error": {
"code": "NOT_FOUND",
"message": "Property not found"
}
}| Status | Code | Description |
|---|---|---|
| 400 | BAD_REQUEST | Invalid request body or parameters |
| 401 | UNAUTHORIZED | Missing or invalid API key |
| 403 | FORBIDDEN | API key lacks the required permission |
| 404 | NOT_FOUND | Resource not found or not accessible |
| 429 | RATE_LIMITED | Too many requests (100/min limit) |
| 501 | NOT_IMPLEMENTED | Feature not available for this resource type |