API reference/POST /public/schedules/{public_scheduling_boundary_id}/booking-proposals

POST /public/schedules/{public_scheduling_boundary_id}/booking-proposals

publicoptional rc

Submit a public booking proposal through a scheduling boundary.

  • This endpoint may be called anonymously. Send an optional requester credential as Authorization: Bearer rc_... to identify the external requester.
  • For structured requests, send public_meeting_type, duration_minutes, and requested_window. For free-text requests, omit public_meeting_type and send message.

Request


POST /public/schedules/{public_scheduling_boundary_id}/booking-proposals HTTP/1.1
Content-Type: application/json

{
  "requester_contact": { "email": "guest@example.com", "name": "Jane Guest" },
  "attendees": [{ "email": "guest@example.com", "name": "Jane Guest" }],
  "public_meeting_type": "intro-call",
  "duration_minutes": 45,
  "requested_window": { "start": "2026-07-08T09:00:00Z", "end": "2026-07-08T17:00:00Z" },
  "reason": "Looking for a short intro call.",
  "message": "I need 30 minutes next week to discuss a partnership."
}
public_meeting_type
stringMust not be empty.
duration_minutes
integerMinimum 5. Maximum 480.
requested_window
objectContains start, end.
requested_window.startreq
string:date-timeUTC date-time string.
requested_window.endreq
string:date-timeUTC date-time string.
requester_contactreq
objectContains email, name.
requester_contact.emailreq
string:emailEmail address.
requester_contact.name
stringMust not be empty.
attendeesreq
object[]Up to 50 items. Contains email, name.
attendees[].emailreq
string:emailEmail address.
attendees[].name
stringMust not be empty.
reason
string
message
string

Response


Returns 200 OK with the response body below.

200 OK · example

HTTP/1.1 201 Created
Content-Type: application/json

{
  "status": "pending_requester_verification",
  "status_url": "https://openavail.com/public/booking-proposals/pat_...",
  "contact_verification_url": "https://openavail.com/public/contact-verifications/pct_.../confirm"
}

// A verified requester credential may skip contact verification when policy allows it.

Errors


CodeDescription
202Default Response
400Validation failed — body is malformed or missing required fields.
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.
429Rate limit exceeded. Per-key limits: POST /v1/availability/search → 300 req/min; POST /v1/holds, POST /v1/bookings, and /v1/bookings/{hold_id}/confirm → 120 req/min each. A global fallback of 600 req/min per IP applies to all other endpoints. Read the Retry-After header for the exact backoff in seconds.