OnSched API 3.7.4 - external calendar sync cache fix
by ReadMe GitHub ActionAvailability
GET /v3/availability?syncExternal=true: Availability cache invalidation now runs only after external calendar changes commit, and the request skips cached availability if sync cannot complete cleanly. This prevents stale cached slots from being returned after Google or Outlook busy blocks are synced into OnSched.
OnSched API 3.7.3 - capacity fallback fix
by ReadMe GitHub ActionAvailability
GET /v3/availabilityandPOST /v3/appointment/hold: Default Service or ResourcebookingsPerSlot: 1now acts as fallback capacity instead of capping the other entity's higher same-slot capacity. For example, a Resource withbookingsPerSlot: 2can accept a second concurrent hold even when the linked Service is left at its defaultbookingsPerSlot: 1.
OnSched API 3.7.2 - controller error status and correctness fixes
by ReadMe GitHub ActionAPI
Controller Error Statuses
- API controllers now use typed error responses for invalid payloads, missing records, external integration failures, and unsupported external calendar states.
POST /v3/customer: Duplicate customer email attempts now return409 Conflictinstead of a generic server error.
Appointment Lifecycle And Audit
PUT /v3/appointment/{id}/cancel: Cancels now require write access to the authenticated company appointment and no longer allow a request scoped to one company to cancel another company's appointment.PUT /v3/appointment/{id}/reschedule: Successful reschedule audit events are keyed to the new appointment ID soGET /v3/appointment/{newId}/auditreturns the success event.GET /v3/appointments: Date-onlyfrom/tofilters now use the shared resource timezone whenresourceIdsare supplied without alocationIdand all matching resources share one timezone.
External Calendars
GET/PUT/DELETE/regenerateAuthUrlon/v3/resource/{id}/externalCalendar/{externalCalendarId}: The path resource must belong to the authenticated company, and the external calendar must belong to that resource.GET /v3/resource/{id}/externalCalendars/list: Pending OAuth shells are ignored when inferring the connected provider, and connected rows with refresh tokens are preferred.DELETE /v3/resource/{id}/externalCalendar/{externalCalendarId}: Disconnecting a provider removes only sibling calendar rows that share the revoked refresh token instead of removing unrelated provider connections on the same resource.
OnSched API 3.7.1 — migration weekly availability and external calendar list
by ReadMe GitHub ActionAPI
V1 migration weekly availability
POST /v3/migration/sync: When a V1 resource uses allocation mode, migration now still copies the resource's V1availabilityinto V3weeklyAvailabilityfor profile and team display reads. Allocation rows remain the source for booking availability. Recreate failures mid-sync roll back weekly schedule replacement.
External calendar list
GET /v3/resource/{id}/externalCalendars/list: Whenprovideris omitted, the API infers Google or Outlook from the resource's connected external calendar. Omittingproviderstill requires exactly one connected provider; otherwise the request fails as before.
OnSched API & dashboard 3.7.0 — booking limits, quotas, and allocation capacity
by ReadMe GitHub ActionPublic docs: Booking limits, Weekly allocations.
Booking limits and service quotas
The platform now enforces configured limits consistently across GET /v3/availability, hold, reserve, book, and reschedule when a customer is known.
Per-customer caps
bookingLimit(service or resource) — caps active appointments (BK+IN; notRS) per customer.maxBookingLimit/maxResourceBookingLimit(service) — lifetime caps per customer; rescheduled-away (RE) rows do not count.- Expired
INholds are ignored when counting active caps (aligned with availability SQL). - Limits are checked on reschedule, including metadata-only updates.
Service-wide daily quotas
dailyBookingLimitCount— hides slots on days when the service has reached its booking count cap.dailyBookingLimitMinutes— hides slots when remaining same-day minute headroom is less than the candidate appointment duration.PUT /bookre-runs slot validation when confirming a reserved (RS) appointment so exhausted daily quotas cannot be bypassed.
Hold and book alignment
allowPaddingOverflowandignoreExternalEventschosen at hold or reserve are preserved when the appointment is booked.0or omitted = unlimited for numeric limit fields unless noted otherwise.
Weekly allocation same-slot capacity
Corrected weekly allocation capacity semantics for service+resource pair scope:
bookingsPerSloton weekly allocations applies only when bothServiceIdandResourceIdscope the allocation.- Availability, hold, and book treat pair-scoped
bookingsPerSlotas concurrent capacity at the same instant; other slots in the week are unaffected. - Weekly allocation routes do not support weekly booking quota fields.
- Same-slot capacity uses one unit of load per booking (a third consumer is rejected when capacity is
2).
Availability reliability
COMBINEDhold validation requires every requested resource to be free at the slot (aligned withGET /v3/availabilitycapacity checks).- Redis availability cache is cleared when appointments are cancelled and when service or resource settings that affect slot generation change (for example
dailyBookingLimitCount,duration,bookingsPerSlot).
Dashboard
- Service, Resource, and Allocation forms group booking limit fields into labeled sections with inline helper copy that distinguishes same-slot capacity, service daily quotas, and per-customer caps.
- Unlimited fields display No limit when the API value is
0. - Service info exposes customer limit dropdowns for
bookingLimit,maxBookingLimit, andmaxResourceBookingLimit. - Resource info exposes
bookingLimitfor the current service. - Weekly allocations scoped to a resource show the
bookingsPerSlotsame-slot capacity field when editing service allocation rows.
Calendar event templates
by ReadMe GitHub ActionDashboard
- Calendar templates: The Notification Templates page now includes a Calendar Templates pane with a Google/Outlook Event template.
- Synced event content: The template Subject controls the Google/Outlook calendar event title, and the Body controls the event details. Calendar templates use the same merge variables and helpers as notification templates.
External calendar busy-only sync and migration blocks
by ReadMe GitHub ActionAPI
- External calendars: Free/transparent provider events (for example Google Working Location or Outlook showAs: free) are not ingested and do not create
Unavailabilityrows. GET /v3/unavailability: Optional row fieldsexternal_transparency,external_event_type,external_busyfor intervals from external calendar sync (null for other sources).POST /v3/migration/sync: Imports v1 resource blocks (/setup/v1/resources/:id/blocks) as v3 recurring blocks per resource, withlegacyIdwhen the v1 block id is present.
Unavailability calendar rebuild & recurring-block timezones
Public docs: Unavailability blocks, Recurring blocks.
Unavailability calendar (GET /v3/unavailability)
GET /v3/unavailability)- Responses are one row per concrete interval, tagged with
source(weekly,recurring,appointment,holiday,block) and the affectedentity_type/entity_id. Rows are not merged. - The
roundRobinquery parameter is removed (previously unused for distinct merged modes). ServiceIdis optional; scope still requires at least one ofLocationIds,ResourceIds, orServiceId.GET /v3/unavailability/calendaris deprecated and returns the same payload asGET /v3/unavailability— migrate callers to the canonical path.
Stored blocks
DELETE /v3/unavailability/blocks/:idremoves an out-of-office (OOF) block by id (company ownership enforced). Use native flows for appointment-linked rows.
Recurring blocks
- Rules persist
ianawith wall-clockstartTime/endTime; expansions respect DST and fractional UTC offsets. Availability and calendar queries share this interpretation.
Integrators
- Update any UI that assumed merged
start_time/end_timeonly, or that passedroundRobin. - Expect snake_case fields on calendar rows (
start_time,entity_type, …).
Dashboard — recurring unavailability on Availability tabs
See also Recurring blocks.
Merchant dashboard
On the Availability tab for locations, services, and resources, you can now manage recurring unavailable periods in addition to one-off blocks:
- List recurring rules with schedule summary, wall-clock time window, timezone, and active date range.
- Add or edit a rule (name, frequency, interval, start/end dates, times, weekday selection for weekly/biweekly, day-of-month for monthly; yearly repeats on the month and day of the start date).
- Delete a rule with confirmation.
Behavior matches the existing /v3/unavailability/recurringBlock APIs (structured recurrence, not RFC 5545 RRULE strings). One-off blocks are still saved with the main Save action; recurring rules save immediately from the recurring-block dialog.
V1 → V3 migration sync expands service field coverage
Guide: Migrating from V1.
Migration
POST /v3/migration/sync now persists the full set of mappable Service fields when creating V3 services from V1, instead of only name, description, duration, weekly availability, and the schedule-vs-allocation type. Migrated services now also retain:
- Duration options:
durationSelect,durationMin,durationMax,durationInterval. - Book-ahead window:
bookAheadUnit,bookAheadValue,bookInAdvance. - Capacity and limits:
bookingLimit,bookingInterval,padding,bookingsPerSlot(from V1maxCapacity),dailyBookingLimitCount,dailyBookingLimitMinutes,maxBookingLimit,maxResourceBookingLimit. - Fees:
feeAmount,feeTaxable,cancellationFeeAmount,cancellationFeeTaxable,nonRefundable. - Other:
imageUrl,showOnline,roundRobin(V1 integer mapped to V3NONE/RANDOM/BALANCED/COMBINED), and custom fields (field1–field10).
Type → availabilityType mapping (unchanged, now documented)
The mapping from V1 type to V3 availabilityType is unchanged but worth restating: V1 type=1 (Appointment) maps to V3 availabilityType=schedule; V1 type=2 (Event) maps to V3 availabilityType=allocation.
Re-running migration
Existing migrated tenants can backfill these fields by re-running POST /v3/migration/sync. The migration is idempotent on legacyId, so previously migrated services that already exist in V3 will be skipped — to pick up the expanded coverage on those rows, delete the V3 service (or update it manually) before re-syncing.
Fields still not migrated
Some V1 fields remain unmapped because V3 has no equivalent column or the concept has been retired (serviceGroupId/serviceGroupName, calendarId/calendarResourceGroupId, mediaPageUrl, defaultService, consumerPadding, maxGroupSize). For those, use native /v3/* endpoints to configure the equivalent V3 behavior after migration.
Allocation legacy IDs and mapping
Guides: Weekly allocations, Single allocations.
Mapping
GET /v3/mapping/idsacceptsallocationId(V1 allocation ID). The response value is always a JSON array of matching V3 UUIDs (weekly and/or single allocation rows). Scalar keys (locationId,serviceId, etc.) remain a single UUID ornull.
Allocations
POST /v3/singleAllocation/setSingleAllocationsandPOST /v3/weeklyAllocation/setWeeklyAllocationsaccept an optionallegacyIdon each allocation item so migrated data can retain the V1 identifier.
Existing Stage tenants can repopulate legacyId by re-running the V1 migration sync (or an allocation-only sync) so allocations are recreated from V1 with IDs attached.
OnSched API & dashboard 3.4.3 — multi-resource email template variables
by ReadMe GitHub ActionMulti-resource template variables
- Use case — Appointments that book more than one resource (e.g. couples or multi-provider sessions) can now show all resource names in custom email and SMS bodies, not only the first.
{{appointment.resources}}— Comma-separated names of every resource on the appointment.{{#each resources}}...{{/each}}— Repeat a fragment once per resource. Inside the block, use bare keys like{{name}}or{{email}}for the current row; outer paths like{{appointment.time}}still work. Nested{{#each}}blocks are not supported in this release.{{resources.0.name}},{{resources.1.name}}, … — Optional indexed access when you want fixed slots in the copy.- Backward compatibility —
{{resource.name}},{{appointment.resource}}, and{{customer.resource}}still refer to the first resource only, so existing templates do not change unless you edit them.
See the Notification guide for full merge syntax and examples.
