Gambrel for developers

Read a company's live openings, and put a booking on their schedule from their own website. Five endpoints, one key, no SDK.

This API belongs to one company. A key is issued by a Gambrel account and can only ever see that account's data. There is no way to name another company in a URL, and no key that spans several.

Getting a key

The owner or an admin makes it on their Gambrel dashboard, under Developer keys. Give it a name that says what it is for — "Website booking form" — and choose what it can do:

ScopeWhat it can do
readRead the company, its openings, its jobs and its customers.
writeAll of the above, and create bookings.

The key is shown once, at the moment it is made. It is stored as a hash, so nobody — including the shop and including us — can look it up afterwards. Lose it and you make another one.

A key is a system, not a person. It keeps working when the person who created it leaves the company, and revoking it removes nobody's login. That is deliberate: a website should not stop taking bookings because of an HR event.

Sending it

Every request carries the key as a bearer token. Nothing goes in a query string — a key in a URL ends up in server logs and browser history.

curl https://getgambrel.com/api/v1/company \
  -H "Authorization: Bearer gmb_your_key_here"

Answers are JSON. A refusal carries an error field written in plain words — it is meant to be read by a person, and can be shown to one.

{ "error": "This key is read-only. Make a key with write access if you need to create bookings." }

Limits

600 requests an hour per key. Over that you get 429. The limit is per key rather than per address, because a website calls from one server and a per-address limit would be either useless or an outage you caused yourself.

Endpoints

GET/api/v1/company

Who the key belongs to — name, phone, time zone, trades, the ZIP codes they drive to, their arrival windows, and the booking URL you can link or embed.

GET/api/v1/availability?start=&end=

Openings between two dates, YYYY-MM-DD. These are the same openings the company's own booking page shows, from the same call — if the shop runs a CRM, they come from the CRM live, so a booked-out afternoon disappears here the moment it does there.

{
  "days": [
    { "date": "2026-09-14", "weekday": "Monday", "display": "Sep 14",
      "slots": [ { "id": "w1", "label": "8:00 AM - 11:00 AM",
                   "start": "08:00", "end": "11:00", "capacity": 2 } ] }
  ],
  "lastBookableDay": "2026-09-28"
}
POST/api/v1/bookings needs a write key

Puts a real job on the schedule. This is the same code path the company's own booking page uses, so a booking from your form and one made on the page are identical — same confirmation email to the customer, same alert to the office, same job in their CRM if they run one.

curl -X POST https://getgambrel.com/api/v1/bookings \
  -H "Authorization: Bearer gmb_your_key_here" \
  -H "Content-Type: application/json" \
  -d '{
    "service": "Water heater",
    "description": "No hot water since this morning",
    "day": "2026-09-14",
    "slot": "w1",
    "source": "website",
    "contact": {
      "name": "Nadine Ellery",
      "phone": "9405550142",
      "email": "nadine@example.com",
      "street": "12 Pine St",
      "city": "Springtown",
      "state": "TX",
      "zip": "76082"
    }
  }'

Answers with a reference a person can read out on the phone, and the link the customer uses to move or cancel without ringing anybody:

{
  "ok": true,
  "reference": "GB-4F2A91C0",
  "bookingId": "…",
  "manageUrl": "https://getgambrel.com/booking/…"
}

What it refuses, and why

You'll getWhen
400No name or phone; a phone that isn't ten digits; no full service address; no five-digit ZIP.
400 out_of_areaThe address is outside the ZIP codes that company drives to. Your form is not a way around their service area — a job they can't reach is a wasted morning for somebody.
409That day is past the end of their booking window, or the same customer already has that exact appointment. A duplicate returns the booking they already have rather than making a second one.
429Too many bookings from one connection in an hour.
GET/api/v1/bookings?limit=

Recent jobs, newest first, up to 200. Each carries its reference, status, customer, address, arrival window and source — which is how you tell a website booking from one taken on the phone.

GET/api/v1/customers?q=

The company's customers, optionally filtered by a search term.

Two things worth knowing

The version in the path is a promise

/api/v1 will not change shape under you. The endpoints the Gambrel screens use are not this API and are not stable — they change whenever a screen does. Build against /api/v1 and nothing else.

Bookings are not the only way in

If all you need is for a homeowner to book, the company's own booking page is already built, already mobile, and already handles photos, rescheduling and cancellation. Link to it or embed it in an iframe — it is the one Gambrel page allowed to be framed, for exactly this reason. Reach for the API when you need something that page cannot do.