---
title: "Assign an interviewer to an interview session"
method: POST
path: "/v1/interview_sessions/{interview_session_id}/actions/assign_interviewer"
tags: ["Scheduling"]
---

# Assign an interviewer to an interview session

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

## Request

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

Assign an interviewer to an interview session

**Required scopes:** `interview_sessions:write`

Adds an organization member as an interviewer for an existing, caller-owned interview session. Requires a secret key with `interview_sessions:write`; publishable keys are denied. Re-assigning the same interviewer is an idempotent no-op and returns `reused: true`. Assigning a second interviewer is allowed, but scheduling readiness returns `INTERVIEWER_ASSIGNMENT_AMBIGUOUS` until the session has exactly one interviewer again. The response includes `user_tasks` booleans derived from the actual trigger-created rows: an `interview_session` task, plus an `application_interview` task when the application is `Scheduled` or `Interviewing`. Email notification is attempted by default; set `notify_interviewer: false` to opt out. `interviewer_email` reports a safe sent, already_sent, skipped, or email_not_sent outcome; email failure does not undo assignment. `suppressed` is non-null for sample data or unknown partition, including opt-out and self-assignment outcomes.

**Example (curl):**

```bash
curl -X POST https://api.yardstick.team/v1/interview_sessions/is_abc123/actions/assign_interviewer \
  -H 'Authorization: Bearer ys_sk_live_…' \
  -H 'Content-Type: application/json' \
  -H 'Idempotency-Key: 7c3a…' \
  -d '{"interviewer_user_id":"00000000-0000-0000-0000-000000000000"}'
```

**Example (TypeScript):**

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

## Path parameters

- `interview_session_id` string, required

## Headers

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

## Request body

- object
  - `notify_interviewer` boolean: Email the assigned interviewer by default; set false to opt out.
  - `interviewer_user_id` string, required: The org-member interviewer to assign, as the `usr_<base32>` display id from the assignable-interviewer listing or as the raw UUID.

## Response `200`

Interviewer assigned or reused. The response includes scheduling and user-task side-effect signals.

- InterviewSessionAssignInterviewerResponse: Success envelope for assigning an interviewer to an interview session.
  - `object` 'interview_session_interviewer', required
  - `interviewer_user_id` string, required: Raw UUID of the assigned interviewer.
  - `is_primary` boolean, required: Whether this interviewer is the primary assignment row.
  - `assigned_at` string, required: ISO-8601 UTC timestamp from the assignment row.
  - `interview_session_id` string, required: Display id of the interview session, e.g. `is_<base32>`.
  - `created` boolean, required: True when this call inserted the assignment row.
  - `reused` boolean, required: True when the interviewer was already assigned.
  - `scheduling_ready` boolean, required: True only when the session has exactly one interviewer.
  - `scheduling_blocker` 'INTERVIEWER_ASSIGNMENT_REQUIRED' | 'INTERVIEWER_ASSIGNMENT_AMBIGUOUS', nullable, required: Scheduling blocker derived from the current interviewer assignment rows.
  - `interviewer_email` union, required: Safe notification outcome; assignment succeeds even when email is not sent.
    - object
      - `status` 'sent' | 'already_sent', required
    - object
      - `status` 'skipped', required
      - `skip_reason` 'opted_out' | 'self_assignment' | 'side_effects_suppressed' | 'not_allowed', required
    - object
      - `status` 'email_not_sent', required
      - `reason_code` 'interviewer_email_missing' | 'send_failed' | 'notify_error', required
  - `suppressed` object, nullable, required: Non-null for sample data or unknown partition; no interview link is minted and no email is sent.
    - `reason_code` 'sample_data_side_effect_suppressed', required
    - `reason` 'sample_data' | 'partition_unknown', required
  - `user_tasks` object, required: Observed user-task trigger side effects after assignment.
    - `interview_session_task_created` boolean, required: Whether the trigger-created interview-session task exists.
    - `application_interview_task_created` boolean, required: Whether the trigger-created application-interview task exists.
  - `audit_id` string, required: Display id of the audit log row.
  - `event_id` string, required: Display id of the API event row.

## 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`: Conflict (e.g. idempotency key reuse with different body)
- `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/bef1d2eaaaa1?raw)
