• Documentation
  • Introduction
    • The member journey
  • Training
    • Create a program
    • Courses and sections
    • Lessons, media and publication
    • Milestones and paths
    • Tasks and deliverables
    • Cohorts and groups
  • Student & Community
    • Joining a school
    • Learning and resuming
    • Submitting and revising work
    • Calendar and lives
    • Spaces and questions
    • Reading progress
  • Coaching
    • Roles and assignments
    • Member context and work queue
    • Reviews and feedback
    • Sessions and interventions
    • Cohort cockpit and live operations
  • Leads & Qualification
    • People, leads and applications
    • Contacts and import
    • Qualification forms
    • Application triage
  • Setting & Booking
    • Setter scope
    • Sales availability
    • Share a booking link
    • Prospect booking
    • Agenda and booking management
    • Prepare a call and share its meeting link
  • Closing, Offers & Payments
    • Closer scope
    • Compose an offer
    • Share a nominal payment link
    • Buyer checkout and access
    • Instalments
    • Offline payment
    • Track payment and access failures
    • Stripe school account
  • Administration & Integrations
    • Organization roles and domains
    • API keys and tenant binding
    • Webhooks
    • Payment setup
  • API quickstart
  • API reference
    • Connect with MCP
    • Enrollments
      • GETGet the enrollment timeline
      • GETGet the coaching briefing
      • POSTPause an enrollment
      • POSTResume an enrollment
      • POSTExtend a deadline
      • POSTTransfer an enrollment
      • POSTClose an enrollment
      • POSTSubmit an outcome measure
      • GETList outcome measures
      • GETList deadline extensions
      • DELETECancel a deadline extension
      • GETList enrollments
      • POSTEnroll a person
    • Cohorts
      • GETGet the cohort cockpit
      • GETList the enrollments behind a cockpit signal
      • PATCHConfigure a cohort
      • POSTMove a cohort to another phase
      • POSTCreate a cohort
      • POSTChange a cohort's status
    • Coaching sessions
      • GETList coaching sessions
      • GETGet a coaching session
      • POSTRecord a coaching session
      • POSTAppend coaching session entries
    • Interventions
      • GETList interventions
      • POSTPlan an intervention
      • POSTClose an intervention
    • Live sessions
      • PATCHRecord live attendance
      • GETList live attendance
      • GETRead one enrollment's attendance
      • GETList live sessions
      • POSTSchedule a live session
      • PATCHUpdate a live session
      • POSTCancel a live session
      • GETGet live session
    • Programs
      • GETList programs
      • POSTCreate a program
      • GETRead a program
      • PATCHUpdate a program
      • POSTArchive a program
      • POSTRestore a program
    • Courses
      • GETList the courses of a program
      • POSTCreate a course
      • PATCHUpdate a course
      • POSTRename a course
      • POSTArchive a course
      • POSTReorder the courses of a program
      • POSTUpload a course cover
    • Sections
      • GETList the sections of a course
      • POSTCreate a section
      • POSTRename a section
      • POSTDissolve a section
      • POSTReorder the sections of a course
      • POSTMove a lesson into a section
      • DELETETake a lesson out of its section
    • Lessons
      • GETList the lessons of a program
      • POSTCreate a lesson
      • GETRead a lesson
      • PATCHUpdate a lesson
      • POSTPublish a lesson
      • POSTArchive a lesson
      • POSTMove a lesson to another course
      • POSTReorder the lessons of a program
      • POSTAttach a resource
      • DELETEDetach a resource
      • POSTReorder the resources of a lesson
      • POSTUpload a lesson resource
      • POSTUpload a lesson video
      • GETRead a lesson by its identifier
      • PATCHUpdate a lesson by its identifier
      • GETRead the discussion of a lesson
      • POSTComment on a lesson
    • Milestones
      • GETList the milestones of a program
      • POSTCreate a milestone
      • PATCHUpdate a milestone
      • POSTArchive a milestone
      • POSTReorder the milestones of a program
      • GETList the contributions of a milestone
      • POSTAttach a contribution
      • DELETEDetach a contribution
    • People
      • POSTImport people
      • POSTLink a duplicate person
      • DELETEUnlink a duplicate person
    • Delivery analytics
      • GETGet delivery analytics
    • Sales availability
      • GETRead sales availability
      • GETPreview sales slots
      • PUTReplace sales availability
      • GETList eligible sales closers
    • Community
      • POSTUpload an attachment
      • POSTAttach to a thread
      • POSTCreate a space
      • POSTPost a thread
      • POSTReply to a thread
      • POSTLink a thread
      • GETList spaces
      • GETRead a thread
      • GETSearch the community
    • Offer payments
      • POSTPause automatic charging
      • DELETEResume automatic charging
      • POSTCharge an instalment now
      • GETGet collections dashboard
    • Member tasks
      • POSTCreate a member task
      • GETList the tasks of a milestone
      • PUTUpdate a member task
      • POSTArchive a member task
      • POSTReorder the tasks of a milestone
      • GETRead a task
      • GETList program tasks
    • Deliverables
      • POSTCreate a deliverable
      • GETList the deliverables of a task
      • GETGet a deliverable
      • PUTUpdate a deliverable
      • POSTArchive a deliverable
    • Groups
      • GETList groups
      • POSTCreate a group
      • GETGet a group
      • PATCHUpdate a group
      • POSTAdd a Group membership
      • DELETERemove a Group membership
    • Paths
      • GETList program paths
      • POSTCreate a path
      • GETGet a path
      • PATCHVersion or promote a path
    • Webhooks
      • GETList webhook subscriptions
      • POSTCreate a webhook subscription
      • GETGet a webhook subscription
      • PATCHUpdate a webhook subscription
      • DELETEDelete a webhook subscription
      • POSTVerify a webhook subscription
      • POSTRotate a webhook secret
      • POSTPause or reactivate a webhook subscription
      • GETList webhook deliveries
      • GETGet a webhook delivery
      • POSTReplay a webhook delivery
    • Media
      • GETList media
      • POSTUpload a media
      • PATCHRename a media
      • DELETEDelete a media
    • Bookings
      • GETList the open slots of a booking link
      • POSTSave a booking lead
      • POSTBook a call for a prospect
      • GETGet booking details
      • GETList bookings
      • GETGet booking
      • PATCHUpdate booking details
      • GETGet booking agenda
      • GETGet closer meeting link
      • GETList person bookings
      • PUTSet closer meeting link
      • GETList booking links
      • POSTSend a booking email
      • GETRead booking follow-up
      • POSTCreate booking link
      • GETGet booking link
      • PUTRecord booking attendance
      • GETRead booking reminder settings
      • PATCHUpdate booking link
      • POSTReschedule booking
      • PUTSet booking reminder settings
      • POSTCancel booking
      • GETList booking reassignment candidates
      • POSTReassign booking
      • GETList booking reschedule slots
      • GETList booking reassignment slots
    • My learning
      • GETList my enrollments
      • GETGet my learning context
      • GETList my lessons
      • GETGet one of my lessons
      • GETList my agenda
      • GETGet my lesson note
      • PUTSave my lesson note
      • DELETEDelete my lesson note
      • GETList my lesson notes
      • GETGet my lesson's agent section
      • GETList my tasks
      • GETRead my submission
      • POSTOpen my submission draft
      • PUTSave my submission draft
      • POSTSubmit my work
      • POSTResubmit my work
    • Forms
      • GETList forms
      • POSTCreate a form
      • GETGet a form
      • PATCHUpdate form identity
      • DELETEDelete a form
      • PUTSave form definition
      • PUTSet form theme
      • PUTSet form qualification
      • PUTSet submission mode
      • PUTOpen or close a form
      • POSTPublish a form
      • POSTUnpublish a form
      • GETList form responses
      • GETGet a form response
      • GETRead form statistics
      • POSTRetry response qualification
      • GETRead form definition
      • GETRead form theme
      • GETRead form qualification
      • GETRead form submission-settings
      • GETRead form identity fields
      • PUTSet form identity fields
    • Calendar connections
      • GETList calendar connections
      • GETRead a calendar connection
      • POSTRequest calendar consent
      • GETList writable calendars
      • PUTSelect a calendar
      • DELETEDisconnect a calendar
    • Offers
      • GETList offers
      • POSTCreate an offer
      • GETGet an offer
      • PATCHUpdate an offer
      • GETGet composer options
    • Responsibilities
      • GETList responsibilities
      • POSTAssign a responsibility
      • DELETERemove a responsibility
    • Submission reviews
      • GETList submission reviews
      • GETRead a submission review
      • POSTTake a submission in review
      • POSTDecide a submission review
    • Closers
      • GETList closer invitations
      • POSTInvite a closer
      • POSTResend a closer invitation
      • DELETECancel a closer invitation
      • GETRead commercial responsibility
      • PUTAssign commercial responsibility
      • GETRead my sales availability
      • PUTUpdate my sales availability
      • GETRead my closer setup
    • Personal preparation
      • GETRead my work profile
      • PATCHUpdate my work profile
      • GETRead my preparation
    • Video library
      • GETList video resources
      • GETGet a video resource
      • POSTPublish a video resource
      • PATCHUpdate a video resource
      • POSTUnpublish a video resource
      • POSTRepublish a video resource
    • Video questions
      • POSTAsk a question
      • GETList my questions
      • GETGet my question
      • GETList received questions
      • PATCHAssign a question
      • POSTAnswer a question
      • POSTCancel a question
  1. Documentation
  2. API reference
  3. Sales availability
  4. Replace sales availability
HomeBlogDocumentationPricingContact

Replace sales availability

PreviousPreview sales slotsNextList eligible sales closers
On this page
AuthorizationRequest headersRequest bodyExampleResponseResponse fieldsExample responseNotesRelatedScheduling retry contractPersonal time zones and compatibilityPublic booking horizonCloser booking horizon

PUT /api/v1/sales-availability

Replaces the complete sales availability configuration of the organization bound to the API key, in one transaction. Anything you omit is gone: an empty closers array, weekly array or exceptions array deliberately clears what was there.

Authorization

Role in the organizationThis endpoint
OWNERAllowed
ADMINAllowed
MEMBERRefused — 403
RequirementRule for this endpoint
Business roleEvery closer in the rotation holds the organization-scoped closer responsibility
Resource scopeOrganization attached to the API key
ParticipationNone
Resource stateNone — the first call creates the configuration

Request headers

HeaderRequiredDescription
x-api-keyyesAPI key created for this organization
Idempotency-KeyyesStable key for this replacement; a replay returns the first result
X-Correlation-IdnoCaller correlation id, returned or generated

Request body

FieldTypeRequiredNullableDescription
timeZonestringyesnoIANA time zone, for example Europe/Paris
durationMinutesintegeryesno30, 45, 60 or 90
bufferBeforeMinutesintegeryesno0, 5, 10, 15 or 30
bufferAfterMinutesintegeryesno0, 5, 10, 15 or 30
closersarrayyesnoUp to 100 closers; each account at most once
closers[].userIdUUIDyesnoAccount holding the organization closer responsibility
closers[].positionintegeryesnoPositive; only the order matters, positions are renumbered from 1
closers[].activebooleanyesnofalse keeps the closer in the rotation without offering slots
closers[].dailyCapacityintegeryesno1 to 100 calls per local day
closers[].weeklyarrayyesnoOne entry per weekday at most
closers[].weekly[].weekdayintegeryesno0 Sunday to 6 Saturday
closers[].weekly[].windowsarrayyesnoUp to 8 ranges
closers[].weekly[].windows[].startMinuteintegeryesno0 to 1439, local minutes from midnight
closers[].weekly[].windows[].endMinuteintegeryesno1 to 1440, after startMinute
closers[].exceptionsarrayyesnoUp to 100; one exception per date at most
closers[].exceptions[].idUUIDnonoExisting exception id, when you keep one
closers[].exceptions[].localDatestringyesnoReal calendar date, YYYY-MM-DD
closers[].exceptions[].effectstringyesnounavailable (no windows) or custom_hours (at least one window)
closers[].exceptions[].windowsarrayyesnoUp to 8 ranges, same shape as weekly windows
json
{
  "timeZone": "Europe/Paris",
  "durationMinutes": 45,
  "bufferBeforeMinutes": 15,
  "bufferAfterMinutes": 15,
  "closers": [
    {
      "userId": "11111111-1111-4111-8111-111111111111",
      "position": 1,
      "active": true,
      "dailyCapacity": 4,
      "weekly": [
        { "weekday": 1, "windows": [{ "startMinute": 540, "endMinute": 720 }] }
      ],
      "exceptions": [
        { "localDate": "2026-09-22", "effect": "unavailable", "windows": [] }
      ]
    }
  ]
}

Example

bash
curl -X PUT "$COHORTE_API_BASE_URL/api/v1/sales-availability" \
  -H "x-api-key: $COHORTE_API_KEY" \
  -H "Idempotency-Key: sales-availability-2026-09-15" \
  -H "Content-Type: application/json" \
  -d '{"timeZone":"Europe/Paris","durationMinutes":45,"bufferBeforeMinutes":15,"bufferAfterMinutes":15,"closers":[{"userId":"11111111-1111-4111-8111-111111111111","position":1,"active":true,"dailyCapacity":4,"weekly":[{"weekday":1,"windows":[{"startMinute":540,"endMinute":720}]}],"exceptions":[]}]}'

Response

  • 200 OK — the configuration as stored. replayed: true when the key was already used.
  • 400 Bad Request — missing Idempotency-Key, invalid JSON, an unknown time zone, a value outside its allowed set or bounds, a closer listed twice, a weekday or exception date repeated for one closer, ranges that overlap once buffers are applied, an exception whose windows contradict its effect, or a closer without the organization closer responsibility; code is invalid_request.
  • 401 Unauthorized — missing, unknown or expired key; code is unauthorized.
  • 403 Forbidden — the bearer is not OWNER or ADMIN; code is forbidden. A closer or setter responsibility never grants it: closers read the configuration, only the school edits it.

Response fields

The stored configuration, with the same fields as Read sales availability, plus the envelope:

FieldTypeNullableDescription
successbooleannotrue for a successful request
replayedbooleannotrue when the idempotency key replayed a replacement
data.versionintegernoNew configuration version
data.rotationCursorintegernoStable round-robin cursor, kept across replacements
data.closers[]arraynoRotation as stored, renumbered from 1, with id, name and email
correlationIdUUIDnoCorrelation id for support

Example response

json
{
  "success": true,
  "replayed": false,
  "data": {
    "organizationId": "5e0b7a61-0000-4000-8000-000000000000",
    "timeZone": "Europe/Paris",
    "durationMinutes": 45,
    "bufferBeforeMinutes": 15,
    "bufferAfterMinutes": 15,
    "rotationCursor": 3,
    "version": 8,
    "closers": [
      {
        "id": "c3f1d8a2-0000-4000-8000-000000000000",
        "userId": "11111111-1111-4111-8111-111111111111",
        "name": "Sophie Laurent",
        "email": "sophie@example.com",
        "position": 1,
        "active": true,
        "dailyCapacity": 4,
        "weekly": [
          { "weekday": 1, "windows": [{ "startMinute": 540, "endMinute": 720 }] }
        ],
        "exceptions": []
      }
    ]
  },
  "correlationId": "9d0f2c47-0000-4000-8000-000000000000"
}

Notes

  • It is a full replacement. Read the configuration first, change what you need, and send everything back.
  • Times are local wall-clock minutes in the persisted time zone; never send a fixed UTC offset.
  • organizationId is not a field: the organization comes from the key, and a value sent in the body changes nothing.
  • A replay with the same Idempotency-Key returns the original state without a second audit entry or event.
  • The replacement writes an audit entry and a sales_availability.replaced domain event. It creates no booking.

Related

  • Read sales availability
  • Preview sales slots

Scheduling retry contract

Keep one idempotency key for one normalized intention. Current authorization is checked again on retry. A different payload or resource with that key, or an older key whose intention cannot be verified, returns 409 conflict without another mutation. Inspect the original outcome before creating a new command. Identical retries do not resend notifications.

Personal time zones and compatibility

closers[].timeZone is an optional IANA string in the request and a required string in the response. Invalid zones return 400. An explicit value changes that closer’s schedule zone, preserving the submitted wall-clock minutes and exception dates. Confirmed bookings retain their instants.

When omitted, an existing closer keeps their saved zone. A newly configured closer inherits their prepared draft zone, or the school zone if no draft exists. Changing the school timeZone never resets existing personal zones. An idempotent replay returns its historical configuration, including the historical school zone for older records that predate personal zones.

Daily capacity and exceptions use each closer’s local calendar. Available slots are the sorted union of UTC instants from those calendars. Nonexistent spring DST times are skipped; repeated fall times use the later occurrence. Durations and buffers remain elapsed time and must fit within availability.

Public booking horizon

bookingHorizonDays is a nullable integer from 1 to 365. It limits the start of new public bookings (page and widget) to strictly before the current instant plus that many 24-hour days. Booking links inherit this school setting. A null value means no horizon limit. When replacing availability, omitting the field preserves the current limit; sending null clears it. Existing bookings, rescheduling, operator-created bookings and internal previews are unchanged. Historical responses without a configured limit return null.

Closer booking horizon

Each closer availability accepts optional nullable bookingHorizonDays (integer 1–365). Omission preserves the stored value; null inherits the team limit. Personal availability reads also expose teamBookingHorizonDays. The effective public booking limit is the minimum of configured team and closer limits. Candidates are evaluated independently: a restricted closer does not hide slots offered by another closer. Both null means unlimited. Existing appointments, rescheduling and operator bookings are unchanged. Prepared availability keeps this setting when adopted by an administrator. Existing rights and idempotency apply.