TimbreDevelopers

JSON API · no key needed

Four HTTP calls. The same rules as the booking form.

Read a business, list its open arrival windows, send a service request and check on it. Nothing here goes past what a visitor can do on the business's own site.

Base URL

https://heytimbre.com/api/v1
  • OpenAPI 3.1.0
  • No key
  • CORS open
  • Safe retries

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
Request
curl https://heytimbre.com/api/v1/businesses/kestrel-heating-air
Response · live
{
  "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
Request
curl 'https://heytimbre.com/api/v1/businesses/kestrel-heating-air/availability?days=3'
Response · live
{
  "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_key in the body.

Body (JSON)

service_idstring
An id from getBusiness.services. Omit for 'something else'.
urgencyemergency | soon | flexible · default soon
descriptionstring · up to 2000 characters
window_startstring · date-timerequired
languageen | es · default en
idempotency_keystring · 8 to 80 characters
assistant_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.
addressobjectrequired
address.streetstringrequired
address.unitstring
address.citystring
address.zipstringrequired
contactobjectrequired
contact.namestringrequired
contact.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_payment when a deposit is due), status_url and payment_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
Request
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"
  }'
Response · example
{
  "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
Request
curl https://heytimbre.com/api/v1/requests/7QX2M9KD4PLA
Response · example
{
  "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": "…" } }

404NOT_FOUND
No business with that slug, or no request with that code.
400INVALID_REQUEST
A field is missing or has the wrong type.
400INVALID_WINDOW
window_start is not an ISO time.
400INVALID_DATE
from is not a YYYY-MM-DD date.
400INVALID_NAME
The contact name is empty.
400INVALID_PHONE
The phone number is not 10 US digits.
400INVALID_EMAIL
The email address does not look right.
400INVALID_ADDRESS
The street address is empty.
400INVALID_ZIP
The ZIP code is not 5 digits.
400OUT_OF_AREA
The ZIP code is outside the business's service area.
400SERVICE_UNAVAILABLE
The service_id is not one the business offers.
400DEPOSIT_TERMS
The business takes a deposit and deposit_accepted is not true.
400TOO_LATE
The arrival window has already started.
409WINDOW_TAKEN
Someone else just took that window. Pick another.
429TOO_MANY_OPEN
That phone number already has requests waiting for a reply.
503BOOKING_PAUSED
The business has paused online requests. Call them instead.
500SERVER_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: true is 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_consent and deposit_accepted are 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.