Your agent holds a slot while the user decides, then confirms or releases it. Floyd gives you atomic holds, 409 conflict detection, and idempotent retries. You write conversation logic - Floyd prevents double-bookings.
{
"serviceId": "svc_consult",
"resourceId": "rsc_advisor_1",
"startTime": "2026-03-01T09:00:00Z",
"endTime": "2026-03-01T09:30:00Z"
}→ 201
{
"id": "bkg_abc123",
"status": "hold",
"expiresAt": "2026-03-01T09:05:00Z"
}Hold a slot while the user decides. Conflicts return 409. Abandoned holds auto-expire.
Every mutation accepts an Idempotency-Key. Retries return the original response.
Row-level locking ensures one hold per slot. Concurrent agents get a 409.
Everything you need to handle real-world booking complexity out of the box.
Hold a slot with a configurable TTL, then confirm or let expire. Matches the natural rhythm of agent conversations where users take time to decide.
PostgreSQL row-level locking ensures one hold per time range. Concurrent agents get a 409 with the conflicting allocation - branch to alternatives programmatically.
Every mutation accepts an Idempotency-Key. Agent frameworks retry freely - Floyd returns the original response, no duplicates.
Business hours, buffer times, lead time, grid alignment, and duration constraints are all enforced by the policy. Your agent code stays simple.
Policy updates create new versions. In-flight bookings reference their original version - no inconsistent behavior during rollouts.
Subscribe to booking.confirmed, booking.canceled, and booking.expired. HMAC-SHA256 signed payloads with exponential backoff retries.
3 API calls. Hold, confirm, done.
POST /v1/services/{id}/availability/slots
{
"startTime": "2026-03-01T00:00:00Z",
"endTime": "2026-03-01T23:59:59Z",
"durationMs": 1800000
}→ { "slots": [{ "startTime": "09:00", "endTime": "09:30" }, ...] }Returns slots satisfying all policy constraints.
POST /v1/bookings
{
"serviceId": "svc_consultation",
"resourceId": "rsc_advisor_1",
"startTime": "2026-03-01T09:00:00Z",
"endTime": "2026-03-01T09:30:00Z"
}→ { "id": "bkg_abc123", "status": "hold", "expiresAt": "..." }Row-level lock acquired. Concurrent requests get 409.
POST /v1/bookings/bkg_abc123/confirm→ { "id": "bkg_abc123", "status": "confirmed" }booking.confirmed event fires to your handler.
Holds expire automatically after a TTL. Conflicts are handled at the database level.