Mirror a Talki appointment
Webhooks for immediate updates, the appointment change feed for backfill and
repair. If the integration also writes bookings, idempotency and the event’s
origin are what keep it from feeding itself.
Authority
Section titled “Authority”- Talki decides whether a Talki appointment commits. Mirror the result; do not re-arbitrate it.
- Provider calendars can narrow availability, and are not the source of truth for Talki appointments.
- The Talki appointment ID is the external unique key.
Events
Section titled “Events”Subscribe to:
appointment.created: upsert the booking.appointment.updated: replace the mirrored fields for the same ID, including a restored appointment.appointment.cancelled: mark the same ID cancelled.
A reschedule on a call or through the API keeps the ID and arrives as
appointment.updated; one in the Talki app can keep the existing ID too. Handle
the event types literally.
notes is the note on the booking: what POST /v1/appointments sent as notes,
or what the assistant wrote on a booking taken on a call. It is null when there is
none.
Deleting a service sends no appointment event. Its bookings keep their ID, with
service.id null and service.name the name they were booked under: a rename
after booking does not carry over, so it can differ from the name you mirrored.
Their updated_at does not change, so an incremental walk of the
GET /v1/appointments feed does not return them again; a full walk shows them
that way. On service.deleted, clear that service’s ID on the bookings you
mirror.
Verify and deduplicate the envelope as in the call activity
guide. On API writes,
origin.credential_id names the key behind the event and
origin.idempotency_key ties it to your request, so you can either skip your own
writes or apply them as idempotent confirmations.
Backfill and recovery
Section titled “Backfill and recovery”Walk GET /v1/appointments?limit=100 from no cursor. Cancelled appointments are
in the feed and must stay in it during a sync. Upsert by ID, store every non-null
next_cursor, continue while has_more is true.
Later polls resume from the stored cursor. It comes back on the final non-empty
page because it records your position, not the existence of a next page.
updated_at is not a watermark.
Write a booking
Section titled “Write a booking”- Read the service from
GET /v1/services/{service_id}. - Query
GET /v1/availabilityfor the service, local date range, and quantity. - Choose a start and end inside a returned window.
- Send
POST /v1/appointmentswith a newIdempotency-Key.
Availability is advisory: on a booking conflict, refresh the windows and offer another time. Retry a lost or transient response with the same key and the same request, and the first result is replayed instead of booking twice.
PATCH /v1/appointments/{id} with both start_at and end_at moves a booking
and keeps its ID. A booking of one service with a duration_minutes must keep
that length or the length it has now, so a booking the owner lengthened in Talki
can move as it is. A move that keeps neither is refused with 400 invalid_parameter, as moving one edge of such a booking normally is. A booking of
several services, of a service booked by the day or night, of a deleted service or
of none is not held to a length. DELETE, with an idempotency key, cancels it: the record stays
readable with status: "cancelled" and stays in the feed.
