Hosting demand is rising across key cities — list your property todayLearn More

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

  1. 1
    Register — Create a RoomsHatch account if you don't have one yet.
  2. 2
    Apply for a test key Submit an application describing your integration use case.
  3. 3
    Integrate — Use your test API key to build and test your integration against our sandbox.
  4. 4
    Go live — Apply for a live key when you're ready for production.

API Reference

v1

REST 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:properties

List and view properties

write:availability

Update availability/blocked dates

read:availability

Query availability

write:rates

Update pricing

read:rates

Query pricing

read:experiences

List and view experiences

write:experiences

Manage experience schedules

read:services

List and view services

write:services

Manage service schedules

read:bookings

List and view bookings

write:bookings

Create and update bookings

*

Full access (all permissions)

Host-scoped keys: When an API key is linked to a specific host, all queries are automatically filtered to that host's properties and bookings only.

Properties

GET/api/v1/propertiesread:properties

List 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"
GET/api/v1/properties/:idread:properties

Get 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

GET/api/v1/properties/:id/availabilityread:availability

Query 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"
PUT/api/v1/properties/:id/availabilitywrite:availability

Update 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/availability

Rates

GET/api/v1/properties/:id/ratesread:rates

Query 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"
PUT/api/v1/properties/:id/rateswrite:rates

Update 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/rates

Experiences

GET/api/v1/experiencesread:experiences

List 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"
GET/api/v1/experiences/:idread:experiences

Get 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
GET/api/v1/experiences/:id/schedulesread:experiences

List 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"
PUT/api/v1/experiences/:id/scheduleswrite:experiences

Create 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/schedules

Services

GET/api/v1/servicesread:services

List 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"
GET/api/v1/services/:idread:services

Get 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
GET/api/v1/services/:id/schedulesread:services

List 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"
PUT/api/v1/services/:id/scheduleswrite:services

Create 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/schedules

Bookings

GET/api/v1/bookingsread:bookings

List 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"
POST/api/v1/bookingswrite:bookings

Create 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
GET/api/v1/bookings/:idread:bookings

Get 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
PATCH/api/v1/bookings/:idwrite:bookings

Update 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/clx123

Webhooks

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.created

A new booking was created

booking.confirmed

A booking was confirmed

booking.cancelled

A booking was cancelled

availability.updated

Availability 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;
}
Retry policy: Failed webhook deliveries are retried up to 3 times with exponential backoff (2s, 4s). Ensure your endpoint responds with a 2xx status code within 10 seconds.

Error Codes

All errors follow a standard format. The HTTP status code indicates the error category.

{
  "error": {
    "code": "NOT_FOUND",
    "message": "Property not found"
  }
}
StatusCodeDescription
400BAD_REQUESTInvalid request body or parameters
401UNAUTHORIZEDMissing or invalid API key
403FORBIDDENAPI key lacks the required permission
404NOT_FOUNDResource not found or not accessible
429RATE_LIMITEDToo many requests (100/min limit)
501NOT_IMPLEMENTEDFeature not available for this resource type

Ready to integrate?

Apply for an API key and start building your integration today.

Apply for API Key