API reference/POST /v1/holds

POST /v1/holds

requires akidempotentaudited decision

Create an explicit candidate or window hold.

Request


candidate hold request

POST /v1/holds HTTP/1.1
Authorization: Bearer ak_01HX7QQM…
Content-Type: application/json

{
  "meeting_class": "recruiting_interview",
  "hold_scope": "…",
  "candidate": { "start": "2026-06-01T14:00:00Z", "end": "2026-06-01T14:45:00Z" },
  "owner_email": "alex@acme.com",
  "calendar_type": "work"
}

window hold request

POST /v1/holds HTTP/1.1
Authorization: Bearer ak_01HX7QQM…
Content-Type: application/json

{
  "meeting_class": "recruiting_interview",
  "hold_scope": "…",
  "duration_minutes": 45,
  "window": { "start": "2026-06-01T14:00:00Z", "end": "2026-06-01T14:45:00Z" },
  "owner_email": "alex@acme.com",
  "calendar_type": "work"
}

candidate hold body

owner_email
string:emailEmail address.
calendar_type
string
meeting_classreq
string
hold_scopereq
"candidate"
candidatereq
objectContains start, end.
candidate.startreq
string:date-timeUTC date-time string.
candidate.endreq
string:date-timeUTC date-time string.

window hold body

owner_email
string:emailEmail address.
calendar_type
string
meeting_classreq
string
hold_scopereq
"window"
duration_minutesreq
integerMinimum 5. Maximum 480.
windowreq
objectContains start, end.
window.startreq
string:date-timeUTC date-time string.
window.endreq
string:date-timeUTC date-time string.

Response


Returns 200 OK with the response body below. Successful booking arbitration writes an audit row you can query through the audit log.

200 OK · example

HTTP/1.1 200 OK
Content-Type: application/json

{
  "hold_id":               "cb16c8e0-4a2f-4d89-b123-9f1c8e7d4a21",
  "hold_scope":            "candidate",
  "held_window": {
    "start": "2026-06-10T10:00:00Z",
    "end":   "2026-06-10T10:45:00Z"
  },
  "expires_at":            "2026-06-10T09:05:00Z",
  "expires_in_seconds":    295,
  "resolved_calendar_type": "work"
}

// Use expires_in_seconds for TTL checks — expires_at is UTC and
// will appear wrong when compared against a local timezone string.

Errors


CodeDescription
400Validation failed — body is malformed or missing required fields.
401Missing or invalid API key. Send the raw key as a Bearer token in the Authorization header.
403Agent does not hold the permission scope required for this call (e.g. preempt on a higher-priority class).
404Calendar owner or booking id not found.
409Conflict — the requested slot was already committed at higher priority. Inspect alternatives[] in the response body.
422Validation error — the request body is structurally valid but semantically rejected. Common causes: earliest_start is in the past (PAST_TIME), the window is shorter than the requested duration (WINDOW_TOO_NARROW), the chosen slot is outside the hold window (SLOT_OUTSIDE_HOLD), or an idempotency key was reused with a different body (IDEMPOTENCY_CONFLICT). The error code field names the specific cause.