AI agents and group scheduling API design
Group Scheduling API Concurrency: Stop Calendar Races Before the Event Write
The slot was free when the agent proposed it. That sentence is where duplicate bookings begin. A customer says yes at 10:04. A required engineer accepts another meeting at 10:05. The organizer approves at 10:06. The event write succeeds but the response times out. Then two workers retry. Calendar Tetris has become a distributed-systems problem with human inboxes attached.
Build a compare-and-commit booking path in eight steps
Use one sixty-minute cross-company kickoff with four required people, one optional observer, Google and Microsoft calendars, and one required participant who supplies availability without connecting a calendar. Generate a valid proposal, change a required calendar before approval, deliver approval twice, and time out the first event-write response.
- 1
Freeze an authorized meeting-intent revision
Storemeeting_request_id, revision, authenticated organizer, purpose, duration, bounded date window, deadline, IANA time zone, required and optional people, approved substitutes, working-hour rules, preferences, outreach policy, approval mode, organizer calendar, and allowed event actions. Every availability read, reply, proposal, and booking command must point to this revision.- Required attendance, consent, and date boundaries cannot change through a slot approval.
- Preferences are scored only after hard constraints pass.
- Booking, rescheduling, and cancellation authority remain separate.
- 2
Build a versioned availability evidence set
Read approved Google and Microsoft free/busy for connected calendars. Store provider, account, retrieval time, requested interval, source cursor or change marker when available, response error, IANA zone, and a hash or internal version for the normalized busy set. Do not copy event titles, descriptions, or unrelated attendees into the scheduling record.- Missing access and provider errors are unknown, not free.
- Every required participant has evidence with an explicit freshness rule.
- The same normalized input produces the same evidence version.
- 3
Join conversational availability without pretending it is live sync
For an unconnected participant, send a consent-safe request with purpose, duration, bounded date range, local-time wording, response deadline, reminder cap, and opt-out path. Parse bounded windows, corrections, decline, and zone into typed evidence tied to sender, channel message ID, meeting revision, received time, and declared expiry.- A duplicate reply is suppressed by message and request identity.
- Ambiguous dates or zones produce one narrow clarification instead of a guess.
- A correction invalidates every proposal derived from the superseded windows.
- 4
Issue proposals as expiring evidence leases
Intersect all required people, then rank optional attendance and preferences. Create aproposal_idcontaining meeting revision, exact slot, attendee roles, evidence versions, generated time, expiry, approval requirement, and status. The proposal is a claim that the evidence supported the slot at generation time. It is not a calendar hold and not a booking.- The approval surface shows proposal expiry and the source meeting revision.
- A later calendar change or participant correction can revoke the lease.
- No-overlap returns the smallest duration, date, attendee, or preference decision.
- 5
Re-read required availability at the commit boundary
After approval and immediately before side effects, fetch current required free/busy and check reply evidence expiry. Compare the normalized evidence versions with those behind the proposal. If the proposed interval is still free and policy permits freshness-only changes elsewhere, continue. If the interval or any hard rule changed, invalidate the proposal and recompute.- An approval never overrides a new required conflict.
- Optional changes follow declared policy and stay visible in the final attendee decision.
- The preflight result and comparison reason are persisted with the booking attempt.
- 6
Acquire one commit right and write idempotently
Use a short meeting-level commit lease or transactional state transition so only one worker can move the approved proposal intobooking_in_progress. Send one stable idempotency key derived from meeting request, revision, and proposal. Persist provider request correlation before the call and provider event identifiers as soon as they are known.- Repeated approval, queue delivery, or tool invocation returns the same operation.
- A lock expiry cannot authorize a second write while the first outcome is unknown.
- The event body is rebuilt from authorized durable state, not model memory.
- 7
Reconcile uncertainty before retrying
A timeout means unknown, not failed. Search by stored provider correlation, organizer calendar, idempotency marker, attendee set, and bounded time. If the event exists, attach it to the operation and continue verification. If absence is proven, retry under the same key. If provider state is conflicting, stop with a bounded recovery task instead of creating another event.- Transport errors and provider rejections have different reason codes.
- Retries preserve meeting revision, actor, approval, and side-effect history.
- An operator can resolve uncertain state without reading private event content.
- 8
Verify invitations and emit the concurrency trace
Read back the canonical event and verify final URL-independent provider identity, slot, IANA zone, organizer, every required participant, optional-attendee decision, and invitation state. Trace evidence reads, version comparison, proposal expiry, approval, lock owner, write attempt, timeout, reconciliation, duplicate suppression, and completion. Finish only with one verified booking or a bounded exception.- A successful HTTP response alone is not booking proof.
- The final result explains whether a proposal changed because of freshness, policy, or provider state.
- The calling agent receives one terminal outcome it can act on safely.
Free at read time is not free at commit time
Calendar providers can return current availability, changes, and event writes. They do not give your cross-company workflow one distributed transaction across every calendar and human reply. Time passes between proposal and approval. That gap is the race window.
The practical answer is not to lock everyone’s calendar for every proposal. It is to make evidence versions and expiry explicit, keep the proposal cheap to invalidate, and run a fresh required-attendee check at the side-effect boundary.
A tentative hold moves the race; it does not erase it
A hold can reduce collisions when every calendar owner has authorized it. It also creates new work: disclosure, expiry, cleanup, decline handling, duplicate suppression, and the risk that a tentative event looks confirmed. External participants may not permit a hold at all.
Use holds as one policy-controlled tool, not as your concurrency model. The durable model is still meeting revision, evidence set, proposal lease, commit right, idempotent write, reconciliation, and read-back proof.
Links, polls, sync, and draft-only assistants stop before compare-and-commit
A booking link can check configured host availability when an invitee selects. A poll records votes. A sync utility reports conflicts. An AI assistant can send ‘does Tuesday still work?’ A calendar API can read and write. None by itself owns the hard meeting from required people and missing availability through approval, fresh preflight, safe booking, invitations, and recovery.
Scheduling execution carries the authorized intent across those boundaries. That is the layer WonderCal is moving toward: an agent should not return a stale slot or a drafted message. It should return a verified booking or a precise exception.
Run the approval-race acceptance test
Generate a proposal from current Google, Microsoft, and conversational evidence. Add a conflict to one required calendar, correct the unconnected participant’s window, approve the original proposal twice, let two workers race, and time out the provider response after it may have created the event.
Pass when stale versions invalidate the old proposal, valid unchanged replies survive, only one worker owns commit, the uncertain event is reconciled, and one invitation is verified. Fail when approval is treated as proof of current availability or a timeout triggers a blind second write.
Compare booking approaches at the race window
The critical moment sits between ‘this slot works’ and ‘everyone is invited.’ Compare which method owns freshness, concurrency, uncertain writes, and final proof.
| Decision vector | Read availability, then write an event | Booking link, poll, or custom holds | WonderCal execution direction |
|---|---|---|---|
| Execution completion | Covers provider reads and writes while proposal state, approval, and recovery remain application work. | Can complete a configured selection or reduce collisions; wider participant coordination may remain human-owned. | Target path carries one authorized proposal through fresh preflight and verified invitations. |
| Cross-company reach | Depends on calendar access the application has across providers and tenants. | Shared surfaces reach external people, with hold and response state joined separately. | Designed for required and optional people across Google, Microsoft, and unconnected calendars. |
| Optional-sync fallback | A calendar read cannot supply availability for a participant who declines connection. | Poll or form responses can fill gaps, but expiry and correction handling still need state. | Target model versions bounded conversational windows beside connected free/busy. |
| Recovery and observability | The team must add evidence versions, locks, idempotency, reconciliation, and read-back verification. | Depends on the selected product plus custom glue around holds, timeouts, and changed calendars. | Target release should expose proposal evidence, commit ownership, retries, provider state, and final proof. |
| Time to ship | Fast for a demo and incomplete once approval latency and uncertain writes enter the path. | Useful for stable meeting shapes; hard-meeting edge cases still define the integration burden. | Worth adopting when the live contract removes race-handling code without hiding booking state. |
Execution completion
Read availability, then write an event
Covers provider reads and writes while proposal state, approval, and recovery remain application work.
Booking link, poll, or custom holds
Can complete a configured selection or reduce collisions; wider participant coordination may remain human-owned.
WonderCal execution direction
Target path carries one authorized proposal through fresh preflight and verified invitations.
Cross-company reach
Read availability, then write an event
Depends on calendar access the application has across providers and tenants.
Booking link, poll, or custom holds
Shared surfaces reach external people, with hold and response state joined separately.
WonderCal execution direction
Designed for required and optional people across Google, Microsoft, and unconnected calendars.
Optional-sync fallback
Read availability, then write an event
A calendar read cannot supply availability for a participant who declines connection.
Booking link, poll, or custom holds
Poll or form responses can fill gaps, but expiry and correction handling still need state.
WonderCal execution direction
Target model versions bounded conversational windows beside connected free/busy.
Recovery and observability
Read availability, then write an event
The team must add evidence versions, locks, idempotency, reconciliation, and read-back verification.
Booking link, poll, or custom holds
Depends on the selected product plus custom glue around holds, timeouts, and changed calendars.
WonderCal execution direction
Target release should expose proposal evidence, commit ownership, retries, provider state, and final proof.
Time to ship
Read availability, then write an event
Fast for a demo and incomplete once approval latency and uncertain writes enter the path.
Booking link, poll, or custom holds
Useful for stable meeting shapes; hard-meeting edge cases still define the integration burden.
WonderCal execution direction
Worth adopting when the live contract removes race-handling code without hiding booking state.
Frequently asked questions
What is a calendar race condition in a group scheduling API?
Should a scheduling API place tentative holds on every proposed slot?
How do idempotency and concurrency control differ?
How should an AI scheduling agent handle an event-write timeout?
Where can developers review WonderCal’s group scheduling direction?
Primary sources
- Google Calendar API: Synchronize resources efficiently — official incremental synchronization, sync-token, and expired-token behavior
- Microsoft Graph: Delta query for calendar events — official Microsoft event-change tracking for a calendar view
- Google Calendar API: Freebusy query — official Google availability request, response, time-zone, and error fields
- Microsoft Graph: calendar getSchedule — official Microsoft availability operation, permissions, and time-zone behavior
- RFC 9110: Idempotent methods — HTTP idempotency semantics used as the base for safe command replay
- RFC 9457: Problem Details for HTTP APIs — standard machine-readable API error format for bounded recovery information
Close the race window before booking
Test WonderCal and your own integration with a stale proposal, duplicate approval, two workers, an uncertain provider write, and one required outcome: a single verified invitation.
Review WonderCal for AI agents