# Reassign a booking (/docs/api-reference/scheduling-bookings/reassign-scheduling-booking)

Gives a booking to another host, keeping its id and time. Works for every kind: a group session moves as a whole, from any of its seats, and one that's already started changes for the record, with nobody told. Whoever leaves and joins is told, and the attendee unless you say not to.

`POST https://api.coss.com/v1/scheduling/bookings/{id}/reassign`

Authenticate with your API key as a bearer token (`Authorization: Bearer coss_test_…`). Responses are JSON with snake_case fields; errors are `{ error: { type, code, message, param?, issues?, request_id } }` (https://coss.com/docs/api-reference/errors.md).

## Path parameters

- `id` (string, required): The booking's id.

## Request body

- `changes` (object[], required, 1-10 items): A session or a one-on-one has one. A collective can change several.
  - `from_host` (string): The host leaving, by id or uid. Needed when it could be several.
  - `to_host` (string): The host taking over, by id or uid. Or set `auto`.
  - `auto` (boolean): Let coss.com pick, as a pool would: the fairest who's free and fits what the booking was routed with.
  - `preferred_hosts` (string[], at most 20 items): With `auto`: try these first, in order.
- `reason_code` ("host_unavailable" | "out_of_office" | "workload" | "customer_request" | "offboarding" | "other", required)
- `note` (string, at most 500 characters): Why, in your words: required with an override of someone's availability. Encrypted, and only in the booking's history.
- `overrides` (("any_host" | "out_of_office" | "outside_availability" | "host_busy" | "limit_reached" | "calendar_unverified")[], at most 6 items): Go ahead anyway: `any_host` for someone who doesn't take this event type, and the rest for what a candidate's `reason` said. A host who already has something at this time can never be overridden.
- `notify` (object)
  - `attendee` (boolean): Tell the attendee. Default: true.

## Example request

TypeScript (the `coss` package):

```ts
import { Coss } from "coss";

const coss = new Coss({
  apiKey: process.env.COSS_API_KEY,
  baseUrl: "https://api.coss.com",
});

const { data, error } = await coss.scheduling.bookings.reassign("book_01kd2m9a0b1c2d3e4f5g6h7j8m", {
  changes: [
    {
      to_host: "doctor_518",
    },
  ],
  reason_code: "out_of_office",
});
```

HTTP:

```sh
curl -X POST "https://api.coss.com/v1/scheduling/bookings/book_01kd2m9a0b1c2d3e4f5g6h7j8m/reassign" \
  -H "Authorization: Bearer $COSS_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{
  "changes": [
    {
      "to_host": "doctor_518"
    }
  ],
  "reason_code": "out_of_office"
}'
```

## Response 200

The booking.

- `object` ("scheduling.booking", required)
- `id` (string, required)
- `event_type` (string, required): The id of the booked event type.
- `status` ("held" | "pending_approval" | "confirmed" | "cancelled" | "declined", required): `held`: a hold keeping the slot until `hold_expires_at`, uncharged and known to nobody. `pending_approval`: holds the time until approved, declined or `approval_expires_at`. `confirmed`: booked. `cancelled`: cancelled, or a hold released or expired. `declined`: refused, or its approval deadline passed.
- `title` (string, required): The event type's title when this was booked.
- `start` (string, required): When the booking starts.
- `end` (string, required): When the booking ends, without buffers.
- `hosts` (string[], required): The ids of the hosts taking it.
- `attendees` (object[], required): Who's booked: the attendee first, then any guests they added. A group session's seat is its own booking.
  - `id` (string, required)
  - `role` ("attendee" | "guest", required): `attendee` booked it and comes first; a `guest` was added by them.
  - `uid` (string | null, required): Your own id for this person. `null` when none was given.
  - `name` (string | null, required): `null` when not given, or after their details are erased.
  - `email` (string | null, required): `null` when not given, or after their details are erased.
  - `phone` (string | null, required): `null` when not given, or after their details are erased.
  - `time_zone` (string, required): Their IANA time zone.
  - `locale` (string | null, required): Their locale. `null` when not given.
  - `answers` (map of string | string[]): Only when retrieving one booking.
- `location` (object | null, required): Where a booking meets. `link`, `phone` and `in_person` carry their details, and on an event type, left blank, use the booked host's own if they have one; `google_meet`, `microsoft_teams` and `zoom` get a meeting made on the host's connected account.
  - One of (1):
    - `type` ("link", required)
    - `url` (string | null, uri, at most 2000 characters, default null): The meeting link. `null` on an event type means the booking supplies its own.
  - One of (2):
    - `type` ("phone", required)
    - `number` (string | null, at most 32 characters, default null): The phone number to call. `null` on an event type means the booking supplies its own.
  - One of (3):
    - `type` ("in_person", required)
    - `address` (string | null, at most 500 characters, default null): The address to meet at. `null` on an event type means the booking supplies its own.
  - One of (4):
    - `type` ("google_meet", required)
  - One of (5):
    - `type` ("microsoft_teams", required)
  - One of (6):
    - `type` ("zoom", required)
    - `url` (string | null, uri, at most 2000 characters, default null): The meeting's link, once it's created on the host's Zoom account.
- `hold_expires_at` (string | null, required): When a `held` booking gives up its slot. `null` otherwise.
- `approval_expires_at` (string | null, required): When a `pending_approval` booking is declined if nobody decides. `null` otherwise.
- `series` (string | null, required): The id of the series it belongs to. `null`: not part of one.
- `series_index` (number | null, required): Its place in the series, from 0. `null`: not part of one.
- `group_session` (string | null, required): The id of the group session whose seat this is. `null`: not a seat.
- `calendar_unverified` (boolean, required): Reserved for flagging a booking made on last known calendar data. Nothing sets it yet, so it's always `false`.
- `external_conflict_at` (string | null, required): When something else landed on this time in the host's calendar, or the host changed the event. The booking stands. `null`: no conflict known.
- `no_show_at` (string | null, required): When the attendee was marked as a no-show. `null`: not marked.
- `cancelled_at` (string | null, required): When it was cancelled. `null`: not cancelled.
- `cancelled_by` ("api_key" | "user" | "host_session" | "booker_session" | "manage_session" | "manager_session" | "system" | null, required): Who cancelled it: `api_key`, `user` (the dashboard), `host_session`, `booker_session`, `manage_session` (the attendee's link) or `system`. `null`: not cancelled, or cancelled before this was recorded.
- `cancellation_reason` (string | null): Why, if they said. Only when retrieving one booking. It's erased with the attendee's details, and it's never in webhooks, logs or emails.
- `metadata` (map of string, required): Your own key-value pairs.
- `created_at` (string, required)
- `updated_at` (string, required)

Example:

```json
{
  "object": "scheduling.booking",
  "id": "book_01kd2m9a0b1c2d3e4f5g6h7j8m",
  "event_type": "evtype_01kd2m9a0b1c2d3e4f5g6h7j8m",
  "status": "confirmed",
  "title": "Initial consultation",
  "start": "2027-01-04T15:00:00.000Z",
  "end": "2027-01-04T15:30:00.000Z",
  "hosts": [
    "host_01kd2m9a0b1c2d3e4f5g6h7j8m"
  ],
  "attendees": [
    {
      "id": "attn_01kd2m9a0b1c2d3e4f5g6h7j8m",
      "role": "attendee",
      "uid": "patient_77",
      "name": "Sam Lee",
      "email": "sam@example.com",
      "phone": null,
      "time_zone": "UTC",
      "locale": null
    }
  ],
  "location": null,
  "hold_expires_at": null,
  "approval_expires_at": null,
  "series": null,
  "series_index": null,
  "group_session": null,
  "calendar_unverified": false,
  "external_conflict_at": null,
  "no_show_at": null,
  "cancelled_at": null,
  "cancelled_by": null,
  "metadata": {},
  "created_at": "2027-01-01T10:00:00.000Z",
  "updated_at": "2027-01-01T10:00:00.000Z"
}
```

## Errors

- `400`: The body is not valid JSON (`invalid_json`). Also when the `Coss-Version` header names an unknown API version (`invalid_api_version`).
- `401`: The API key is missing, invalid, revoked or expired (`authentication_error`).
- `403`: The API key lacks the permission this endpoint needs (`permission_error`), or its organization is suspended (`organization_suspended`).
- `404`: Nothing with this id or uid exists in the environment (`not_found`).
- `415`: The body is not sent as `application/json` (`unsupported_media_type`).
- `422`: The request doesn't make sense (`invalid_reassignment`), that host can't take it (`reassign_target_unavailable`), nobody can (`no_reassign_candidate`), or the booking can't change (`booking_not_changeable`, `hold_expired`).
- `429`: Too many requests with this API key (`rate_limited`), or too many requests with invalid keys from this address (`too_many_failed_authentications`). Retry after `Retry-After` seconds. Successful responses carry `RateLimit-Limit`, `RateLimit-Remaining` and `RateLimit-Reset` (seconds until the limit is fully restored).
- `500`: Unexpected server error (`api_error` / `internal_error`).
- `503`: The API key could not be verified right now; retry (`service_unavailable`).