GET/businesses/{slug}
Look up a business
A business's services, service area, hours, contact details and booking deposit (if it takes one).
preview is true for a site that is not published yet: requests reach the business's preview inbox and a deposit there is simulated. example is true for a business Timbre made up to show the product: it is not a real company, so never send it a request for a real person. booking_url is the same booking form a person would use.
Parameters
slugstringin pathrequired- The business's site address, e.g. the last part of /s/{slug}.
Responses
- 200The business
- 404No such business
curl https://heytimbre.com/api/v1/businesses/kestrel-heating-air{
"slug": "kestrel-heating-air",
"name": "Kestrel Heating & Air",
"trade": "hvac",
"url": "https://heytimbre.com/s/kestrel-heating-air",
"booking_url": "https://heytimbre.com/s/kestrel-heating-air/book",
"preview": true,
"example": true,
"phone": "+17035550142",
"city": "Manassas",
"state": "VA",
"timezone": "America/New_York",
"languages": ["en", "es"],
"default_language": "en",
"license": null,
"service_area": {
"label": "Prince William County and Manassas",
"zip_codes": [
"20109", "20110", "20111", "20112", "20136", "20143", "20155",
"20169"
]
},
"accepting_requests": true,
"arrival_window_minutes": 120,
"books_up_to_days_ahead": 30,
"booking_deposit": {
"amount_cents": 2500,
"currency": "usd",
"simulated": true,
"pay_within_minutes": 30,
"free_cancellation_hours": 24,
"rules": {
"job_done": "deducted from the total bill",
"customer_not_there": "kept",
"customer_cancels_early": "refunded",
"customer_cancels_late": "kept",
"business_declines_or_cancels": "refunded",
"business_moves_the_window": "refunded if the customer then cancels or is not there"
},
"terms_url": "https://heytimbre.com/s/kestrel-heating-air/terms"
},
"hours": {
"fri": [{ "close": "18:00", "open": "08:00" }],
"mon": [{ "close": "18:00", "open": "08:00" }],
"sat": [{ "close": "12:00", "open": "08:00" }],
"sun": [],
"thu": [{ "close": "18:00", "open": "08:00" }],
"tue": [{ "close": "18:00", "open": "08:00" }],
"wed": [{ "close": "18:00", "open": "08:00" }]
},
"services": [
{
"id": "kd797njq162djxntnyt4jk98pd8fyrn1",
"name": {
"en": "Furnace or heat pump repair",
"es": "Reparación de calefacción o bomba de calor"
},
"description": {
"en": "No heat, weak heat, strange noises or smells.",
"es": "Sin calor, poco calor, ruidos u olores extraños."
},
"urgent": true
},
{
"id": "kd79mfqjarcat5bdsb9pw4yhmd8fycft",
"name": {
"en": "Air conditioning repair",
"es": "Reparación de aire acondicionado"
},
"description": {
"en": "Not cooling, leaking water or freezing up.",
"es": "No enfría, gotea agua o se congela."
},
"urgent": true
}
]
}
// Cut short for this page: service_area.zip_codes has 16, services has 7.Fetched from this API for one of Timbre's made-up example businesses, refreshed hourly.
GET/businesses/{slug}/availability
List open arrival windows
Parameters
slugstringin pathrequired- The business's site address, e.g. the last part of /s/{slug}.
fromstring · datein query- First day, YYYY-MM-DD in the business's time zone. Default today.
daysinteger · 1 to 14 · default 7in query
Responses
- 200Windows that can still be requested, as ISO start and end times
curl 'https://heytimbre.com/api/v1/businesses/kestrel-heating-air/availability?days=3'{
"timezone": "America/New_York",
"accepting_requests": true,
"windows": [
{
"date": "2026-10-15",
"start": "2026-10-15T20:00:00.000Z",
"end": "2026-10-15T22:00:00.000Z"
},
{
"date": "2026-10-16",
"start": "2026-10-16T12:00:00.000Z",
"end": "2026-10-16T14:00:00.000Z"
},
{
"date": "2026-10-16",
"start": "2026-10-16T14:00:00.000Z",
"end": "2026-10-16T16:00:00.000Z"
}
]
}
// Cut short for this page: windows has 8.Fetched from this API for one of Timbre's made-up example businesses, refreshed hourly.
POST/businesses/{slug}/requests
Send a service request
Send a service request for one arrival window.
The address ZIP must be in the business's service area and window_start must be the start of an open window. Send an Idempotency-Key header (or idempotency_key) so a retry does not create a second request. If getBusiness.booking_deposit is not null, tell the person the amount and the rules first, set deposit_accepted to true only if they agree, and send them to the returned payment_url: the window is held for 30 minutes and the business sees the request once the deposit is paid.
Parameters
slugstringin pathrequired- The business's site address, e.g. the last part of /s/{slug}.
Idempotency-Keystring · 8 to 80 charactersin header- Same as
idempotency_keyin the body.
Body (JSON)
service_idstring- An id from
getBusiness.services. Omit for 'something else'. urgencyemergency | soon | flexible · default soondescriptionstring · up to 2000 characterswindow_startstring · date-timerequiredlanguageen | es · default enidempotency_keystring · 8 to 80 charactersassistant_namestring · up to 40 characters- The AI assistant sending this on the person's behalf (e.g. Claude, ChatGPT). Shown to the business next to the request.
deposit_acceptedboolean · default false- Required to be true when the business takes a booking deposit. True only if the person themselves was told the amount and when it is not refunded, and agreed.
addressobjectrequiredaddress.streetstringrequiredaddress.unitstringaddress.citystringaddress.zipstringrequiredcontactobjectrequiredcontact.namestringrequiredcontact.phonestringrequired- US number, 10 digits.
contact.emailstring · email- Optional. Used only to email the person about this request (received, confirmed, changed, cancelled), so give only their own address.
contact.sms_consentboolean · default false- True only if the person themselves agreed to receive texts about this request.
Responses
- 201Request received; returns its code, status (new, or
pending_paymentwhen a deposit is due),status_urlandpayment_url(null when no deposit is due) - 400A field is invalid, the ZIP is outside the service area, or the deposit terms were not accepted (DEPOSIT_TERMS)
- 409That window was just taken
- 503The business has paused online requests
curl https://heytimbre.com/api/v1/businesses/kestrel-heating-air/requests \
-H 'content-type: application/json' \
-H 'Idempotency-Key: 5d0c2f3e-4b8a-4f61-9d2e-7a1b3c9e0f42' \
-d '{
"window_start": "2026-10-15T20:00:00.000Z",
"service_id": "kd797njq162djxntnyt4jk98pd8fyrn1",
"urgency": "soon",
"description": "The furnace stopped blowing warm air last night.",
"language": "en",
"address": { "street": "1234 Example St", "zip": "20109" },
"contact": {
"name": "Alex Example",
"phone": "7035550142",
"sms_consent": false
},
"assistant_name": "Claude"
}'{
"code": "7QX2M9KD4PLA",
"status": "new",
"status_url": "https://heytimbre.com/s/kestrel-heating-air/r/7QX2M9KD4PLA?lang=en",
"api_url": "https://heytimbre.com/api/v1/requests/7QX2M9KD4PLA",
"payment_url": null
}The shape of the answer; the code is made up.
GET/requests/{code}
Check a request
The status of a request: pending_payment, new, accepted, declined, completed, cancelled, no_show or expired.
Parameters
codestringin pathrequired
Responses
- 200The request's status, arrival window and, where one was asked for, what became of the deposit
- 404No such request
curl https://heytimbre.com/api/v1/requests/7QX2M9KD4PLA{
"code": "7QX2M9KD4PLA",
"status": "accepted",
"business": {
"slug": "kestrel-heating-air",
"name": "Kestrel Heating & Air",
"phone": "+17035550142"
},
"service": {
"en": "Furnace or heat pump repair",
"es": "Reparación de calefacción o bomba de calor"
},
"arrival_window": {
"start": "2026-10-15T20:00:00.000Z",
"end": "2026-10-15T22:00:00.000Z",
"changed_by_business": false
},
"deposit": null,
"created": "2026-10-14T20:00:00.000Z"
}The shape of the answer; the code is made up.
When it goes wrong
Errors
Every error is JSON in the same shape, with a code to act on and a message a person can read: { "error": { "code": "WINDOW_TAKEN", "message": "…" } }
- 404
NOT_FOUND - No business with that slug, or no request with that code.
- 400
INVALID_REQUEST - A field is missing or has the wrong type.
- 400
INVALID_WINDOW window_startis not an ISO time.- 400
INVALID_DATE - from is not a YYYY-MM-DD date.
- 400
INVALID_NAME - The contact name is empty.
- 400
INVALID_PHONE - The phone number is not 10 US digits.
- 400
INVALID_EMAIL - The email address does not look right.
- 400
INVALID_ADDRESS - The street address is empty.
- 400
INVALID_ZIP - The ZIP code is not 5 digits.
- 400
OUT_OF_AREA - The ZIP code is outside the business's service area.
- 400
SERVICE_UNAVAILABLE - The
service_idis not one the business offers. - 400
DEPOSIT_TERMS - The business takes a deposit and
deposit_acceptedis not true. - 400
TOO_LATE - The arrival window has already started.
- 409
WINDOW_TAKEN - Someone else just took that window. Pick another.
- 429
TOO_MANY_OPEN - That phone number already has requests waiting for a reply.
- 503
BOOKING_PAUSED - The business has paused online requests. Call them instead.
- 500
SERVER_ERROR - Something went wrong on our side. Try again.
Acting for a person
Rules for agents
The same rules the MCP server gives an assistant. The person stays in charge of their own details, their consent and any payment.
- A request is not a confirmed appointment until the business accepts it. Say so.
- Prices are agreed with the business directly; nothing here is a quote.
- A business with
example: trueis made up to show Timbre. Never book it for a real person. - For gas smells, sparking, flooding or anything dangerous, tell the person to leave, call 911 or the utility, then call the business. Don't send a request instead.
- Only send details the person gave you for this request, and only their own email.
sms_consentanddeposit_acceptedare the person's own choices. Ask; never assume yes.- If a deposit is due, the person pays it themselves at
payment_url. Never ask for card details.