1. What you can book
The API offers the same services as our public booking pages. We turn those on and off
in our own admin panel, so this list can change —
call GET /api/v1/services and drive your booking off the response rather
than hard-coding it. As of right now:
| Service key | What it is | Length | Appointments |
|---|---|---|---|
test_short |
Short-Term Radon Test — 2–7 day test. Device placed on visit 1, retrieved on visit 2. Two visits will be auto-created. | 60 min | Two: a placement slot, then a pickup slot at least 48 h later. |
quote |
On-Site Quote — In-home mitigation assessment used to price the job. | 60 min | One. |
A service that isn't listed returns 400 service_not_bookable. Each entry tells you what it
needs: requires_pickup means it is a two-appointment job (we place a radon device and come
back for it later), so the request carries a second pickup slot at least 48 h after the
first.
mitigation) cannot be booked through the API.A mitigation install is scheduled from a signed quote, not booked directly. Book the "quote" service instead — after the customer signs their quote they receive a link to choose an install date.
2. One calendar, not two
Every availability answer and every booking goes through the same scheduling engine as our public booking page and our office CRM. A slot you book is blocked for everyone else the instant it is created, and the appointment appears on the crew's schedule with the same records a phone booking produces. There is no separate "API calendar" to fall out of sync — double-booking across channels is not possible.
3. Authentication
Every request carries a key issued to your organisation:
Authorization: Bearer rk_live_xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx
X-API-Key: <key> is accepted as an alternative. Keys are scoped to one company account and carry scopes:
| Scope | Allows |
|---|---|
availability:read | /services, /availability |
bookings:write | Create and cancel bookings |
bookings:read | Read back bookings your key created |
A key is shown once, when it is created. Store it as a secret; it is not recoverable, and a leaked key should be revoked and replaced.
4. Rate limits
| Limit | Default | On exceed |
|---|---|---|
| Requests per minute, per key | 60 | 429, code rate_limited, with Retry-After |
| Bookings per day, per key | 25 | 429, code booking_limit_reached |
Both are per-key and can be raised on request. Every response carries
X-RateLimit-Limit, X-RateLimit-Remaining and X-RateLimit-Reset.
5. The booking flow
Three calls: discover the services, read availability, book a slot.
GET /api/v1/services
Durations, bookable weekdays and the exact required fields per service. Read it rather than hard-coding — the company edits these in the CRM.
curl -H "Authorization: Bearer $KEY" \ https://radoncrm.com/api/v1/services
GET /api/v1/availability?service=&from=&to=
Real open start times, per day. status is available, fully_booked,
closed (with a reason, e.g. a crew holiday) or past. Max 62 days per call.
curl -H "Authorization: Bearer $KEY" \ "https://radoncrm.com/api/v1/availability?service=test_short&from=2026-10-01&to=2026-10-14"
{
"service": "test_short",
"timezone": "America/Edmonton",
"duration_minutes": 60,
"days": [
{ "date": "2026-10-01", "status": "available",
"slots": [ { "start": "09:30", "label": "9:30 AM" }, { "start": "10:00", "label": "10:00 AM" } ] },
{ "date": "2026-10-04", "status": "closed", "reason": "We are closed on Sundays.", "slots": [] }
]
}POST /api/v1/bookings
Creates a confirmed appointment, not a lead. The customer receives the same confirmation email they would get from our own booking page.
curl -X POST https://radoncrm.com/api/v1/bookings \
-H "Authorization: Bearer $KEY" \
-H "Content-Type: application/json" \
-H "Idempotency-Key: my-booking-8f21" \
-d '{
"service": "test_short",
"customer": { "name": "Jane Doe", "email": "jane@example.com", "phone": "403-555-0142" },
"property": { "address": "123 Maple Rd SW", "city": "Calgary", "postal_code": "T2V 1N4" },
"slot": { "date": "2026-10-01", "start": "10:00" },
"pickup": { "date": "2026-10-03", "start": "10:00" },
"external_ref": "agent-run-771"
}'{
"ok": true,
"booking": {
"reference": "J1352",
"service": "test_short",
"status": "scheduled",
"timezone": "America/Edmonton",
"appointment": { "date": "2026-10-01", "start": "10:00", "end": "11:00" },
"pickup": { "date": "2026-10-03", "start": "10:00", "end": "11:00" }
}
}Idempotency-Key. A retried request with the same key returns the
original booking instead of creating a second appointment — the single most common way an automated
client double-books a customer.
Required fields
All services need customer.name, customer.email, customer.phone,
property.address, property.city and slot.
A service with requires_pickup (the radon test — a kit is placed, then collected) also needs a
pickup slot at least 48 hours after placement.
Address and city are not optional: the appointment is a site visit.
Managing a booking
| Call | Does |
|---|---|
GET/api/v1/bookings/{reference} | Current state, including live job status. |
POST/api/v1/bookings/{reference}/cancel | Cancels and frees the slot. Not allowed once the work is completed or invoiced. |
6. Errors
Errors carry a customer-safe error sentence and a stable code to branch on.
| Status | code | Meaning |
|---|---|---|
| 400 | invalid_request | Validation failed. error names the field; fields lists it. |
| 401 | unauthorized / key_revoked | Missing, invalid or revoked key. |
| 403 | insufficient_scope | The key lacks the scope for that call. |
| 404 | unknown_service / not_found | No such service or booking. |
| 400 | service_not_bookable | That service isn't bookable through the API — error says what to do instead. |
| 409 | slot_unavailable | Taken between your availability read and the write. Re-read and retry another slot. |
| 409 | not_cancellable | Work already completed or invoiced. |
| 429 | rate_limited / booking_limit_reached | Slow down, or ask for a higher limit. |
7. Terms for automated clients
Third-party software, including AI agents acting for a customer, may read availability and create bookings with a valid API key.
Permitted
- Booking on behalf of an end customer who has asked for the appointment and whose contact details you are authorised to share.
- Booking any service the company has made available for online booking — the list is returned by GET /services and is the same set offered on the public booking pages.
- Reading availability to show a customer real open times.
- Cancelling a booking your own key created.
Not permitted
- Speculative or held bookings you intend to cancel — every booking occupies a real crew slot.
- Bulk-scraping availability outside the published rate limit.
- Sharing a key across unrelated businesses; keys identify one partner and can be revoked individually.
- Booking with contact details the customer has not consented to share.
Bookings create a customer, property and job record in the CRM. Customer data is processed to deliver the service and is subject to the company's privacy policy. A key may be revoked at any time; a revoked key returns HTTP 401 with code "key_revoked".
8. Getting a key
Contact eman@byeradon.ca or call (403) 801-8989 with your organisation name and what you are building. Keys are issued from the CRM under Settings → API Access and can be revoked at any time.