---
title: "Cancel a scheduled interview session"
method: POST
path: "/v1/interview_sessions/{interview_session_id}/actions/cancel"
tags: ["Scheduling"]
---

# Cancel a scheduled interview session

`POST /v1/interview_sessions/{interview_session_id}/actions/cancel`

## Request

- Base URL: `https://api.yardstick.team`
- URL: `https://api.yardstick.team/v1/interview_sessions/{interview_session_id}/actions/cancel`
- Auth: HTTP bearer

Cancel a scheduled interview session

**Required scopes:** `scheduling:write`

Cancels a scheduled interview round: releases the provider booking, invalidates every outstanding scheduling link for the round (an invalidated link is dead immediately, not at its TTL), cancels the synced calendar event, and — for manually scheduled rounds only — emails the candidate. Provider-booked rounds are not emailed, because the scheduler sends its own cancellation notice. **Body is optional.** `reason` (≤500 chars) is recorded on the `scheduling.session_cancelled` event and is the only place it is stored; `skip_provider: true` cancels in Yardstick without calling the scheduling provider — the retry path when the provider is failing. Unknown body fields are rejected with 400 rather than ignored. **Repeat cancels are safe:** `already_cancelled` means the round was already cancelled. The idempotent side effects (link invalidation, calendar cancel) are re-applied, but no provider call, candidate email, or `scheduling.session_cancelled` event is produced. A 409 refusal writes nothing, so it is equally safe to retry. **Check `candidate_email` on success:** `status: "email_not_sent"` means the cancel succeeded but the candidate was never told. **Idempotency:** supply `Idempotency-Key` to dedupe retries; replayed requests return the cached response. Inherits the default per-token rate limit applied by `withApi`.

**Example (curl):**

```bash
curl -X POST https://api.yardstick.team/v1/interview_sessions/is_abc123/actions/cancel \
  -H 'Authorization: Bearer ys_sk_live_…' \
  -H 'Content-Type: application/json' \
  -H 'Idempotency-Key: 7c3a…' \
  -d '{"reason":"Hiring manager unavailable"}'
```

**Example (TypeScript):**

```ts
await fetch(
  "https://api.yardstick.team/v1/interview_sessions/is_abc123/actions/cancel",
  {
    method: "POST",
    headers: {
      Authorization: `Bearer ${process.env.YS_API_KEY}`,
      "Content-Type": "application/json",
      "Idempotency-Key": crypto.randomUUID(),
    },
    body: JSON.stringify({ reason: "Hiring manager unavailable" }),
  },
).then((r) => r.json());
```

## Path parameters

- `interview_session_id` string, required

## Headers

- `Idempotency-Key` string
- `X-Request-Id` string

## Request body

- object
  - `reason` string
  - `skip_provider` boolean

## Response `200`

Round cancelled, or confirmed already cancelled. The provider booking is released, every outstanding scheduling link is invalidated, and the `candidate_email` / `suppressed` markers report the side effects.

- SchedulingCancelResponse: Success envelope for `scheduling.cancel`. The cancel itself succeeded; `candidate_email` and `suppressed` are markers annotating an otherwise successful cancel and never change the status code.
  - `outcome` 'cancelled' | 'already_cancelled', required: `already_cancelled` means the round was already cancelled. The idempotent side effects (link invalidation, calendar cancel) are re-applied, but no provider call, candidate email, or `scheduling.session_cancelled` event is produced.
  - `interview_session_id` string, required: Display id, e.g. `is_<base32>`.
  - `previous_booking_status` string, nullable, required: `booking_status` as it stood before this call wrote anything.
  - `provider_cancel` union, required: Whether the scheduling provider's booking was cancelled, and if not, why the call was skipped.
    - object
      - `status` 'made', required
      - `outcome` 'cancelled' | 'already_cancelled', required: `already_cancelled` means the provider reported the booking was already gone, confirmed by re-reading the booking's own status.
      - `provider` 'calcom' | 'calendly', required
    - object
      - `status` 'skipped', required
      - `skip_reason` 'side_effects_suppressed' | 'skip_provider_requested' | 'no_provider_booking' | 'no_external_booking' | 'session_already_cancelled', required
  - `candidate_email` union, required: Outcome of the candidate cancellation email. Sent only for manually scheduled rounds; provider-booked rounds rely on the provider's own cancellation notice.
    - object: The cancellation email was handed to the sending provider.
      - `status` 'sent' | 'drafted' | 'scheduled', required
    - object
      - `status` 'skipped', required
      - `skip_reason` 'provider_notifies_candidate' | 'link_sent_no_booking' | 'side_effects_suppressed' | 'session_already_cancelled' | 'reserved_test_recipient' | 'candidate_email_missing' | 'no_matching_rule', required
    - object: The cancel succeeded but the candidate was NOT told. Treat as actionable: the round is cancelled and the candidate still expects to attend.
      - `status` 'email_not_sent', required
      - `reason_code` string, required: Why the send failed, e.g. `sender_default_missing`. A draft row and an email-send issue are recorded for follow-up.
      - `sender_resolution_type` string, required: Which sender rule was applied: `org_shared`, `owner`, `job_hiring_manager`, or `override`.
  - `suppressed` object, nullable, required: Non-null when the session is sample data or its partition could not be determined. The local cancel still happens; the provider call and the candidate email are suppressed and no event is emitted.
    - `reason_code` 'sample_data_side_effect_suppressed', required
    - `reason` 'sample_data' | 'partition_unknown', required
  - `calendar_sync_ok` boolean, required: Whether the calendar orchestrator completed its cancel. `false` is not a failure of the cancel itself — the booking_status write has already committed — and is common, since most orgs have no calendar integration connected.

## Other responses

- `400`: Invalid request
- `401`: Authentication failure
- `403`: Permission denied (scope or feature flag)
- `404`: Resource not found. The error uses the resource-specific code and param names the exact body field or path parameter that referenced it.
- `409`: The round cannot be cancelled in its current state, or the provider rejected the cancellation. Nothing was written. Body carries `outcome`, `message`, `booking_status`, `session_status`, and `provider_failure_code`.
- `429`: Rate limited
- `500`: Internal error

---

[API](https://skmtc.dev/yardstick/apis/yardstick-public-api.md) · [All operations](https://skmtc.dev/yardstick/apis/yardstick-public-api/llms.txt) · [OpenAPI document](https://skmtc.dev/yardstick/apis/yardstick-public-api/revisions/35b5a6e88b35?raw)
