Cribond · Developers

Cribond Channel API

Connect a channel manager or PMS (Talkguest, Hostaway, Smoobu, Guesty…) to Cribond, the Portuguese holiday-rental marketplace, and manage Cribond listings exactly like listings on your other channels: push availability, nightly rates and stay restrictions in; receive reservations out, in real time.

Base URL https://api.cribond.com/functions/v1/channel-api/v1
Version 2026-09-23 (sent back in the Cribond-Api-Version header) · Format JSON, UTF-8 · Currency EUR · Dates YYYY-MM-DD, local to the property (Europe/Lisbon)

1. Authentication

Every request carries a per-host API key: Authorization: Bearer cbk_…. The host creates the key in Cribond (Integrações) and gives it to you. A key only reaches the listings of the host who created it; the host can rotate or revoke it at any time (you then get 401). One key per host account covers all of that host's listings — including the ones they do not own but manage for other hosts as a co-host with full access, which is how a property manager runs several owners' places with a single key.

curl https://api.cribond.com/functions/v1/channel-api/v1/me \
  -H "Authorization: Bearer cbk_xxxxxxxx_…"

2. How it maps to Cribond

3. Listings & mapping

CallWhat it does
GET/meThe connection this key belongs to.
GET/listingsThe host's listings: id, external_id, title, status, base_price, weekend_price, min_nights, max_nights, max_guests, managed.
GET/listings/{id}One listing ({id} = Cribond id or slug).
PUT/listings/{id}/mapping{"external_id": "your-unit-id"} — link a listing to your unit. Unique per connection.
DELETE/listings/{id}/mappingStop managing a listing. Your closures and rates on it are removed; it returns to the host's own settings.
PATCH/listings/{id}Defaults: base_price, weekend_price, min_nights (1–30), max_nights (1–90), max_guests (1–50).

4. Availability, rates & restrictions (ARI)

PUT/listings/{id}/calendar

Send ranges; to is inclusive (a night is identified by its date). A field you omit keeps its stored value; a field sent as null is cleared. Idempotent — resend freely. Up to 500 ranges and 20,000 nights per call, up to 760 days ahead; past nights are ignored.

PUT /listings/be255e3e-…/calendar
{
  "updates": [
    { "from": "2026-10-01", "to": "2026-10-31", "price": 95, "min_nights": 2 },
    { "from": "2026-10-10", "to": "2026-10-12", "closed": true },
    { "date": "2026-10-17", "closed_to_arrival": true },
    { "from": "2026-11-01", "to": "2026-11-05", "available": false }
  ]
}
→ 200 { "listing_id": "be255e3e-…", "nights_updated": 36 }
FieldTypeMeaning
pricenumber | nullNightly price in EUR for the whole unit — exactly what the guest pays for the stay (Cribond charges guests no fee; the host pays a 5% commission).
min_nights / max_nights1–365 | nullStay length rule, applied on the arrival date.
closed (or available: false)booleanNight cannot be sold.
closed_to_arrivalbooleanNo check-in on this date.
closed_to_departurebooleanNo check-out on this date.

GET/listings/{id}/calendar?from=&to=

Read back every night (default: next 365 days): price, price_source (channel | listing_default), restrictions, available, and unavailable_reason — reservation (a Cribond booking), hold (a guest is paying right now; released within minutes if they abandon), host (blocked by the host in Cribond) or ical (another calendar the host imported). Use it to reconcile.

5. Reservations (pull)

A change feed with a monotonic cursor — nothing is ever skipped, even for changes made in the same millisecond.

GET/reservations?after=0&limit=100Reservations created or changed after the cursor, oldest first. Keep next_after and pass it back; loop while has_more. Optional listing_id.
GET/reservations/{id}One reservation, current state.
{
  "id": "55086fee-…", "code": "CB-55086FEE",
  "status": "confirmed",                 // or "cancelled"
  "stay_status": "upcoming",             // "checked_in" | "checked_out"
  "listing": { "id": "be255e3e-…", "external_id": "TG-123", "slug": "…", "title": "…" },
  "arrival": "2026-10-20", "departure": "2026-10-23", "nights": 3,
  "guests": { "total": 2 },
  "guest": { "name": "Ana Silva", "email": "ana@…", "phone": "+351…" },
  "guest_identity": null,
  "currency": "EUR",
  "amounts": {
    "accommodation": 285.00,             // stay price after host-funded discounts
    "discount": 0,
    "host_payout": 270.75,               // what the host receives (stay − commission)
    "guest_service_fee": 0,              // the guest pays no Cribond fee
    "host_commission": 14.25,            // Cribond's 5%, paid by the host (payments included)
    "security_deposit": 0,               // refundable, held by Cribond
    "total_paid_by_guest": 285.00,
    "tourist_tax_collected": false
  },
  "payment": { "collected_by": "cribond", "status": "paid", "host_paid_out_at": null },
  "cancellation": null,                  // or { cancelled_at, cancelled_by, reason, refund_amount }
  "confirmed_at": "…", "created_at": "…", "sequence": 812
}

Poll every 1–5 minutes as a safety net even when you use webhooks.

6. Webhooks (push)

Register an HTTPS endpoint with PUT/webhook {"url": "https://…"} (DELETE to remove, POST/webhook/test to receive a ping). Cribond POSTs within seconds of every change:

reservation.createdA reservation was paid and confirmed — close those nights on your other channels.
reservation.modifiedDates or party size changed.
reservation.cancelledCancelled — reopen the nights.
POST https://your-endpoint
Cribond-Signature: t=1790083940,v1=5f1c…      // HMAC-SHA256
Cribond-Event-Id: evt_1042
Cribond-Event-Type: reservation.created

{ "id": "evt_1042", "type": "reservation.created", "created_at": "…",
  "api_version": "2026-09-23", "data": { "reservation": { … } } }

Verify every delivery: compute HMAC-SHA256(webhook_secret, t + "." + raw_body) in hex and compare with v1 (constant-time); reject timestamps older than 5 minutes. The webhook_secret (whsec_…) is given to the host with the API key.

// Node.js
const [t, v1] = header.split(",").map(p => p.split("=")[1]);
const expected = crypto.createHmac("sha256", secret).update(t + "." + rawBody).digest("hex");
const ok = crypto.timingSafeEqual(Buffer.from(v1), Buffer.from(expected)) && Date.now()/1000 - t < 300;

Answer 2xx within 10 seconds. Anything else is retried after 1, 2, 5, 15, 30 min, 1, 2, 4, 8 and 12 h, then marked failed (the host can resend from Cribond). Deliveries can arrive more than once — de-duplicate on id. The payload always carries the reservation's current state, so a late created for a stay already cancelled says "status": "cancelled".

7. Errors & limits

{ "error": { "code": "invalid_date", "message": "updates[0]: from/to must be YYYY-MM-DD." } }
401unauthorized — missing, wrong or revoked key.
404not_found — unknown endpoint, or a listing/reservation that is not this host's.
409Conflict, e.g. external_id_taken.
422Validation (invalid_date, invalid_price, invalid_restriction, …).
429More than 6,000 calls/hour for one connection. Honour Retry-After; batch ranges instead of one call per night.
5xxRetry with exponential backoff. All writes are idempotent.

8. Guests, invoicing & SEF/AIMA

9. Recommended integration flow

  1. Host creates a key in Cribond → pastes it into your product.
  2. GET /listings → the host picks which unit is which → PUT /listings/{id}/mapping.
  3. Full sync: PUT /listings/{id}/calendar with the next 12–24 months (prices, restrictions, closures — including nights booked on other channels).
  4. PUT /webhook, then GET /reservations?after=0 once to import history; store next_after.
  5. From then on: push every ARI change as it happens (deltas are fine); react to webhooks; poll /reservations every few minutes as a safety net.

10. Partnership & support

Building a Cribond connection for your platform? We give you a sandbox host account and help test before you go live: support@cribond.com. Hosts whose channel manager does not support Cribond yet can sync calendars over iCal in the meantime.