hospitable-api
Hospitable.com Public API (v2) Skill
π Source Files β Read These First
Before writing any code, the agent MUST read the following files:
| File | Purpose |
|---|---|
types.ts |
All TypeScript interfaces and enums for API entities |
client.ts |
Ready-to-use typed HTTP client β always use this, never raw fetch() |
Agent rules:
- Do NOT redefine types. Import from
types.ts. - Do NOT write custom fetch wrappers. Use
client.ts. - Do NOT manually implement pagination loops. Use the built-in
listAll()helpers. - Always pass
crypto.randomUUID()as theidempotencyKeyfor allPOST/PATCH/PUTcalls.
π Authentication & Setup
- Base URL:
https://public.api.hospitable.com/v2 - Auth: OAuth 2.0 or Personal Access Token (PAT)
- Required headers on every request:
Authorization: Bearer <ACCESS_TOKEN> Accept: application/json Content-Type: application/json - Environment variable:
HOSPITABLE_ACCESS_TOKENin.env - Timezone: All dates are UTC / ISO 8601
- IDs: All entity IDs are UUIDs, not integers
π¦ Pagination
All list endpoints return:
{
"data": [...],
"meta": { "current_page": 1, "last_page": 5, "per_page": 25, "total": 98 },
"links": { "next": "https://...", "prev": null }
}
- Always read from
.dataβ never assume a flat array - Use
listAll()helpers inclient.tsto auto-paginate (per_page=100) - Single-resource endpoints return
{ "data": { ... } }
See types.ts β PaginatedResponse<T>, SingleResponse<T>
π Including Related Resources (?include=)
Embed related entities in one call to avoid N+1 requests.
| Resource | Available includes |
|---|---|
properties |
listings, images, tags, user |
reservations |
guest, listing, property, checkins, transactions, conversation, financials |
inquiries |
property, guest |
conversations |
guest, reservation |
reviews |
reservation, guest |
client.ts methods accept an include: string[] parameter β pass the desired relationships.
π Rate Limits & Idempotency
Rate Limiting β inspect response headers:
X-RateLimit-Remaining: requests left; stop if 0X-RateLimit-Reset: Unix timestamp when window resets- Client throws automatically on
429
Idempotency β required on all POST, PATCH, PUT:
import { randomUUID } from "crypto";
client.reservations.create(payload, randomUUID());
π οΈ Complete Resource Reference
1. User
See types.ts β User, BillingInfo
GET /v2/user?include=billing β SingleResponse<User>
2. Properties
See types.ts β Property, Address, Capacity, PropertyImage, Listing, Quote
GET /v2/properties β PaginatedResponse<Property>
GET /v2/properties/search?q=... β PaginatedResponse<Property>
GET /v2/properties/{uuid} β SingleResponse<Property>
GET /v2/properties/{uuid}/images β PaginatedResponse<PropertyImage>
GET /v2/properties/{uuid}/quote?check_in=...&check_out=...&guests=...
POST /v2/properties/{uuid}/tags body: { tag: string }
3. Calendar
See types.ts β CalendarDay, CalendarUpdateItem, CalendarDayStatus
GET /v2/properties/{uuid}/calendar?start_date=YYYY-MM-DD&end_date=YYYY-MM-DD
PATCH /v2/properties/{uuid}/calendar body: { days: CalendarUpdateItem[] }
Per-day fields: status (available|unavailable|booked), price, min_stay, check_in_allowed, check_out_allowed
4. Inquiries
Pre-booking inquiries. See types.ts β Inquiry, InquiryStatus
GET /v2/inquiries β PaginatedResponse<Inquiry>
GET /v2/inquiries/{uuid} β SingleResponse<Inquiry>
POST /v2/inquiries/{uuid}/messages
Statuses: pending, pre_approved, declined, expired, withdrawn
5. Reservations
See types.ts β Reservation, ReservationStatus, Platform, GuestCounts, ReservationFinancials
GET /v2/reservations β PaginatedResponse<Reservation>
GET /v2/reservations/{uuid} β SingleResponse<Reservation>
POST /v2/reservations Create manual reservation
PATCH /v2/reservations/{uuid} Update manual reservation
POST /v2/reservations/{uuid}/cancel Cancel manual reservation
Status lifecycle:
inquiry β request β pending verification β accepted
(may also become: cancelled, declined, withdrawn, expired, checkpoint, request for payment)
Financials (use ?include=financials):
accommodation, cleaning_fee, linen_fee, management_fee, resort_fee, pet_fee, pass_through_taxes, other_fees[]{amount,label}
Common list filters: property_id, status, check_in_start, check_in_end
6. Messaging
See types.ts β Message, MessageAttachment, SendMessagePayload
GET /v2/reservations/{uuid}/messages β PaginatedResponse<Message>
POST /v2/reservations/{uuid}/messages body: { body: string }
POST /v2/inquiries/{uuid}/messages body: { body: string }
Message fields: body, content_type, sender_type (host/guest/system), attachments[]{type, url}
7. Conversations (Inbox)
See types.ts β Conversation
GET /v2/conversations β PaginatedResponse<Conversation>
Note: To send messages, use reservation or inquiry messaging endpoints above.
8. Transactions
Booking-level payment events. See types.ts β Transaction
GET /v2/transactions β PaginatedResponse<Transaction>
GET /v2/transactions/{uuid} β SingleResponse<Transaction>
9. Payouts
Host disbursements. See types.ts β Payout
GET /v2/payouts β PaginatedResponse<Payout>
GET /v2/payouts/{uuid} β SingleResponse<Payout>
10. Reviews
See types.ts β Review, ReviewRatings, ReviewPublic, ReviewPrivate, RespondToReviewPayload
GET /v2/reviews β PaginatedResponse<Review>
GET /v2/reviews/{uuid} β SingleResponse<Review>
POST /v2/reviews/{uuid}/response body: { response: string }
Ratings (1β5): cleanliness, communication, check_in, accuracy, location, value
11. Enrichable Shortcodes
Dynamic placeholders for automated messages (e.g. {{wifi_password}}).
See types.ts β EnrichableShortcode, SetEnrichableShortcodePayload
GET /v2/shortcodes β PaginatedResponse<EnrichableShortcode>
GET /v2/shortcodes/{key} β SingleResponse<EnrichableShortcode>
PUT /v2/shortcodes/{key} body: { value: string }
Pass ?property_id={uuid} to scope to a specific property; omit for account-level default.
πͺ Webhooks
All webhook topics in WebhookTopic:
| Topic | Triggered when |
|---|---|
reservation.created |
New booking received |
reservation.changed |
Booking details updated |
reservation.status_changed |
Status transition (e.g. pending β accepted) |
message.create |
New message from host or guest |
message.updated |
Message edited |
inquiry.created |
New pre-booking inquiry |
review.created |
Guest leaves a review |
property.created |
New property added |
property.deleted |
Property removed |
property.merged |
Two properties merged into one |
integration.disconnected |
OTA channel integration broke |
Envelope (types.ts β WebhookEvent<T>):
{ "id": "<ULID>", "action": "reservation.status_changed", "data": {...}, "version": "1.0", "created": "..." }
Security (types.ts β WebhookSecurityInfo):
- Verify the
Signatureheader on every request - Whitelist inbound IP
38.80.170.0/24
π¨βπ» Workflow Examples
List all accepted reservations with financials
import { createClient } from "./client";
const client = createClient(process.env.HOSPITABLE_ACCESS_TOKEN!);
const reservations = await client.reservations.listAll({
status: "accepted",
include: "guest,financials",
});
for (const r of reservations) {
console.log(r.guest?.first_name, r.financials?.total, r.financials?.currency);
}
Create a manual reservation
import { createClient } from "./client";
import { randomUUID } from "crypto";
const client = createClient(process.env.HOSPITABLE_ACCESS_TOKEN!);
const { data } = await client.reservations.create(
{
property_id: "<uuid>",
check_in: "2025-07-01",
check_out: "2025-07-07",
guests_count: 2,
guest: { first_name: "Jane", last_name: "Doe", email: "jane@example.com" },
total_price: 1200,
currency: "USD",
},
randomUUID(),
);
console.log(data.id, data.status); // β "accepted"
Block calendar dates
await client.calendar.update(
"<property-uuid>",
[
{ date: "2025-12-24", status: "unavailable" },
{ date: "2025-12-25", status: "unavailable" },
],
randomUUID(),
);
Respond to a guest review
await client.reviews.respond(
"<review-uuid>",
{
response:
"Thank you for your kind words! We look forward to hosting you again.",
},
randomUUID(),
);
Set a property-level WiFi shortcode
await client.shortcodes.set(
"wifi_password",
{ value: "BeachHouse2025!" },
randomUUID(),
"<property-uuid>",
);
Handle incoming webhook
import type { WebhookEvent, Reservation } from "./types";
async function handleWebhook(event: WebhookEvent<Reservation>) {
if (event.action === "reservation.status_changed") {
console.log("Status changed:", event.data.id, "β", event.data.status);
}
if (event.action === "property.merged") {
// event.data contains the surviving property
}
}
π Official Documentation
- Introduction: https://developer.hospitable.com/docs/public-api-docs/d862b3ee512e6-introduction
- Authentication: https://developer.hospitable.com/docs/public-api-docs/xpyjv51qyelmp-authentication
- Enums & Statuses: https://developer.hospitable.com/docs/public-api-docs/g5sgfn6j7b0aw-reservation-statuses
- Calendar Restriction: https://developer.hospitable.com/docs/public-api-docs/hriol5oneuh9u-calendar-restriction
- Including Resources: https://developer.hospitable.com/docs/public-api-docs/465fd4d45e4b3-including-resources
- Webhooks: https://developer.hospitable.com/docs/public-api-docs/k4ctofvqu0w8g-hospitable-api-v2-webhooks