{
  "info": {
    "_postman_id": "tcv2-admin-002",
    "name": "Teamcast v2 — Tenant Admin APIs",
    "description": "Recruiter and workspace-admin API surface for Teamcast v2.\n\nCovers: Auth, Jobs, Interviews (lifecycle + plan + assessment + recording + orchestration + delivery), Candidate Access, Rubrics, Role Configs, Admin (users / roles / permissions), API Keys, Workspace OAuth Apps, Notifications, Webhook Config, and Health.\n\n**Quick start:**\n1. Import this collection + the `Teamcast v2 — Local Dev` environment.\n2. Run **Login** — `jwtToken` and `tenantId` are auto-saved.\n3. Run requests in numbered order for the golden interview path.\n\n**Auth:** Bearer JWT (`{{jwtToken}}`). Exceptions noted per-folder.",
    "schema": "https://schema.getpostman.com/json/collection/v2.1.0/collection.json"
  },
  "auth": {
    "type": "bearer",
    "bearer": [
      {
        "key": "token",
        "value": "{{jwtToken}}",
        "type": "string"
      }
    ]
  },
  "variable": [
    {
      "key": "baseUrl",
      "value": "http://localhost:4100/api/v2",
      "type": "string"
    }
  ],
  "item": [
    {
      "name": "1. Authentication",
      "description": "Login, signup, OTP verification, and password reset. Public endpoints do not require a token.",
      "item": [
        {
          "name": "Login",
          "request": {
            "auth": {
              "type": "noauth"
            },
            "method": "POST",
            "header": [
              {
                "key": "Content-Type",
                "value": "application/json"
              }
            ],
            "body": {
              "mode": "raw",
              "raw": "{\n  \"email\":    \"{{adminEmail}}\",\n  \"password\": \"{{adminPassword}}\"\n}",
              "options": {
                "raw": {
                  "language": "json"
                }
              }
            },
            "url": {
              "raw": "{{baseUrl}}/auth/login",
              "host": [
                "{{baseUrl}}"
              ],
              "path": [
                "auth",
                "login"
              ]
            },
            "description": "Password login. Returns a JWT + refresh token. Rate-limited."
          },
          "event": [
            {
              "listen": "test",
              "script": {
                "type": "text/javascript",
                "exec": [
                  "if (pm.response.code === 200) {",
                  "  const r = pm.response.json();",
                  "  if (r.accessToken)  pm.environment.set('jwtToken',  r.accessToken);",
                  "  if (r.user?.tenantId) pm.environment.set('tenantId', r.user.tenantId);",
                  "  pm.test('Has access token', () => pm.expect(r.accessToken).to.be.a('string'));",
                  "  console.log('tenantId:', r.user?.tenantId);",
                  "}"
                ]
              }
            }
          ]
        },
        {
          "name": "Signup (create workspace)",
          "request": {
            "auth": {
              "type": "noauth"
            },
            "method": "POST",
            "header": [
              {
                "key": "Content-Type",
                "value": "application/json"
              }
            ],
            "body": {
              "mode": "raw",
              "raw": "{\n  \"name\":          \"Demo Workspace\",\n  \"email\":         \"founder@acme.ai\",\n  \"password\":      \"SecurePass123!\",\n  \"company_name\":  \"Acme Corp\"\n}",
              "options": {
                "raw": {
                  "language": "json"
                }
              }
            },
            "url": {
              "raw": "{{baseUrl}}/auth/signup",
              "host": [
                "{{baseUrl}}"
              ],
              "path": [
                "auth",
                "signup"
              ]
            },
            "description": "Self-serve workspace creation. Sends an OTP verification email. Rate-limited."
          }
        },
        {
          "name": "Send OTP Verification Email",
          "request": {
            "auth": {
              "type": "noauth"
            },
            "method": "POST",
            "header": [
              {
                "key": "Content-Type",
                "value": "application/json"
              }
            ],
            "body": {
              "mode": "raw",
              "raw": "{ \"email\": \"founder@acme.ai\" }",
              "options": {
                "raw": {
                  "language": "json"
                }
              }
            },
            "url": {
              "raw": "{{baseUrl}}/auth/send-otp-verification",
              "host": [
                "{{baseUrl}}"
              ],
              "path": [
                "auth",
                "send-otp-verification"
              ]
            },
            "description": "Resend the 6-digit email-verification OTP. Public, rate-limited."
          }
        },
        {
          "name": "Verify OTP",
          "request": {
            "auth": {
              "type": "noauth"
            },
            "method": "POST",
            "header": [
              {
                "key": "Content-Type",
                "value": "application/json"
              }
            ],
            "body": {
              "mode": "raw",
              "raw": "{ \"email\": \"founder@acme.ai\", \"otp\": \"123456\" }",
              "options": {
                "raw": {
                  "language": "json"
                }
              }
            },
            "url": {
              "raw": "{{baseUrl}}/auth/verify-otp",
              "host": [
                "{{baseUrl}}"
              ],
              "path": [
                "auth",
                "verify-otp"
              ]
            }
          }
        },
        {
          "name": "Send Password Reset Email",
          "request": {
            "auth": {
              "type": "noauth"
            },
            "method": "POST",
            "header": [
              {
                "key": "Content-Type",
                "value": "application/json"
              }
            ],
            "body": {
              "mode": "raw",
              "raw": "{ \"email\": \"{{adminEmail}}\" }",
              "options": {
                "raw": {
                  "language": "json"
                }
              }
            },
            "url": {
              "raw": "{{baseUrl}}/auth/send-reset-password-token",
              "host": [
                "{{baseUrl}}"
              ],
              "path": [
                "auth",
                "send-reset-password-token"
              ]
            }
          }
        },
        {
          "name": "Reset Password",
          "request": {
            "auth": {
              "type": "noauth"
            },
            "method": "POST",
            "header": [
              {
                "key": "Content-Type",
                "value": "application/json"
              }
            ],
            "body": {
              "mode": "raw",
              "raw": "{ \"password\": \"NewSecurePass123!\" }",
              "options": {
                "raw": {
                  "language": "json"
                }
              }
            },
            "url": {
              "raw": "{{baseUrl}}/auth/reset-password/:token",
              "host": [
                "{{baseUrl}}"
              ],
              "path": [
                "auth",
                "reset-password",
                ":token"
              ],
              "variable": [
                {
                  "key": "token",
                  "value": "<reset-token-from-email>"
                }
              ]
            }
          }
        },
        {
          "name": "Get My Profile",
          "request": {
            "method": "GET",
            "header": [],
            "url": {
              "raw": "{{baseUrl}}/auth/me",
              "host": [
                "{{baseUrl}}"
              ],
              "path": [
                "auth",
                "me"
              ]
            },
            "description": "Returns the current user's profile, assigned roles, and effective RBAC permissions."
          }
        },
        {
          "name": "Dev Token (dev only)",
          "request": {
            "method": "POST",
            "header": [
              {
                "key": "Content-Type",
                "value": "application/json"
              }
            ],
            "body": {
              "mode": "raw",
              "raw": "{ \"userId\": \"{{userId}}\" }",
              "options": {
                "raw": {
                  "language": "json"
                }
              }
            },
            "url": {
              "raw": "{{baseUrl}}/auth/dev-token",
              "host": [
                "{{baseUrl}}"
              ],
              "path": [
                "auth",
                "dev-token"
              ]
            },
            "description": "Mint a JWT for any userId without a password. Disabled in production. Useful for local testing."
          }
        }
      ]
    },
    {
      "name": "2. Jobs",
      "description": "Job definition management, AI-assisted JD tools, and candidate intake.",
      "item": [
        {
          "name": "Create Job",
          "request": {
            "method": "POST",
            "header": [
              {
                "key": "Content-Type",
                "value": "application/json"
              }
            ],
            "body": {
              "mode": "raw",
              "raw": "{\n  \"title\":        \"Senior Backend Engineer\",\n  \"seniority\":    \"SENIOR\",\n  \"role_family\":  \"engineering\",\n  \"description\":  \"We are looking for a senior engineer to lead our platform team...\",\n  \"company_blurb\": \"Acme Corp builds next-generation SaaS infrastructure.\",\n  \"skills\":       [\"TypeScript\", \"PostgreSQL\", \"AWS\", \"Distributed Systems\"],\n  \"positions\":    2,\n  \"salary_min\":   120000,\n  \"salary_max\":   160000,\n  \"currency\":     \"USD\"\n}",
              "options": {
                "raw": {
                  "language": "json"
                }
              }
            },
            "url": {
              "raw": "{{baseUrl}}/jobs",
              "host": [
                "{{baseUrl}}"
              ],
              "path": [
                "jobs"
              ]
            }
          },
          "event": [
            {
              "listen": "test",
              "script": {
                "type": "text/javascript",
                "exec": [
                  "if ([200, 201].includes(pm.response.code)) {",
                  "  const r = pm.response.json();",
                  "  if (r.id) pm.environment.set('jobId', r.id);",
                  "  console.log('jobId:', r.id);",
                  "}"
                ]
              }
            }
          ]
        },
        {
          "name": "List Jobs",
          "request": {
            "method": "GET",
            "header": [],
            "url": {
              "raw": "{{baseUrl}}/jobs?page=1&limit=20&status=active",
              "host": [
                "{{baseUrl}}"
              ],
              "path": [
                "jobs"
              ],
              "query": [
                {
                  "key": "page",
                  "value": "1"
                },
                {
                  "key": "limit",
                  "value": "20"
                },
                {
                  "key": "status",
                  "value": "active",
                  "description": "active | paused | closed"
                }
              ]
            }
          }
        },
        {
          "name": "Get Job by ID",
          "request": {
            "method": "GET",
            "header": [],
            "url": {
              "raw": "{{baseUrl}}/jobs/{{jobId}}",
              "host": [
                "{{baseUrl}}"
              ],
              "path": [
                "jobs",
                "{{jobId}}"
              ]
            },
            "description": "Returns JD, competency list, and full candidate pipeline for this job."
          }
        },
        {
          "name": "Edit Job",
          "request": {
            "method": "PATCH",
            "header": [
              {
                "key": "Content-Type",
                "value": "application/json"
              }
            ],
            "body": {
              "mode": "raw",
              "raw": "{\n  \"title\":     \"Principal Backend Engineer\",\n  \"positions\": 3,\n  \"salary_min\": 140000,\n  \"salary_max\": 180000\n}",
              "options": {
                "raw": {
                  "language": "json"
                }
              }
            },
            "url": {
              "raw": "{{baseUrl}}/jobs/{{jobId}}",
              "host": [
                "{{baseUrl}}"
              ],
              "path": [
                "jobs",
                "{{jobId}}"
              ]
            }
          }
        },
        {
          "name": "Generate Job Description (AI)",
          "request": {
            "method": "POST",
            "header": [
              {
                "key": "Content-Type",
                "value": "application/json"
              }
            ],
            "body": {
              "mode": "raw",
              "raw": "{\n  \"title\":       \"Senior Backend Engineer\",\n  \"seniority\":   \"SENIOR\",\n  \"role_family\": \"engineering\",\n  \"skills\":      [\"TypeScript\", \"PostgreSQL\", \"AWS\"],\n  \"company_name\": \"Acme Corp\",\n  \"tone\":        \"professional\"\n}",
              "options": {
                "raw": {
                  "language": "json"
                }
              }
            },
            "url": {
              "raw": "{{baseUrl}}/jobs/generate-description",
              "host": [
                "{{baseUrl}}"
              ],
              "path": [
                "jobs",
                "generate-description"
              ]
            },
            "description": "AI-drafts a JD from structured inputs. Returns text only — does NOT save a job record."
          }
        },
        {
          "name": "Extract Skills from JD (AI)",
          "request": {
            "method": "POST",
            "header": [
              {
                "key": "Content-Type",
                "value": "application/json"
              }
            ],
            "body": {
              "mode": "raw",
              "raw": "{\n  \"job_description\": \"We are looking for a senior engineer with 5+ years of TypeScript, strong PostgreSQL skills, and experience designing distributed systems on AWS...\"\n}",
              "options": {
                "raw": {
                  "language": "json"
                }
              }
            },
            "url": {
              "raw": "{{baseUrl}}/jobs/extract-skills",
              "host": [
                "{{baseUrl}}"
              ],
              "path": [
                "jobs",
                "extract-skills"
              ]
            },
            "description": "Extracts structured skills list from a free-text JD. Returns skill array — does NOT save anything."
          }
        },
        {
          "name": "Resume Match",
          "request": {
            "method": "POST",
            "header": [
              {
                "key": "Content-Type",
                "value": "application/json"
              }
            ],
            "body": {
              "mode": "raw",
              "raw": "{\n  \"resume_text\": \"John Doe — 7 years TypeScript, 5 years PostgreSQL, AWS Solutions Architect...\"\n}",
              "options": {
                "raw": {
                  "language": "json"
                }
              }
            },
            "url": {
              "raw": "{{baseUrl}}/jobs/{{jobId}}/resume-match",
              "host": [
                "{{baseUrl}}"
              ],
              "path": [
                "jobs",
                "{{jobId}}",
                "resume-match"
              ]
            },
            "description": "Scores a resume against the job's competencies. Returns a coverage tier. Does NOT save anything."
          }
        },
        {
          "name": "Add Candidate to Job",
          "request": {
            "method": "POST",
            "header": [
              {
                "key": "Content-Type",
                "value": "application/json"
              }
            ],
            "body": {
              "mode": "raw",
              "raw": "{\n  \"name\":         \"Jane Smith\",\n  \"email\":        \"jane.smith@example.com\",\n  \"resume_text\":  \"Jane Smith — 6 years TypeScript, AWS, System Design...\",\n  \"source\":       \"linkedin\"\n}",
              "options": {
                "raw": {
                  "language": "json"
                }
              }
            },
            "url": {
              "raw": "{{baseUrl}}/jobs/{{jobId}}/candidates",
              "host": [
                "{{baseUrl}}"
              ],
              "path": [
                "jobs",
                "{{jobId}}",
                "candidates"
              ]
            },
            "description": "Creates a candidate record and generates their interview plan. Auto-saves `interviewId`."
          },
          "event": [
            {
              "listen": "test",
              "script": {
                "type": "text/javascript",
                "exec": [
                  "if ([200, 201].includes(pm.response.code)) {",
                  "  const r = pm.response.json();",
                  "  if (r.interview?.id) pm.environment.set('interviewId', r.interview.id);",
                  "  if (r.interviewId)   pm.environment.set('interviewId', r.interviewId);",
                  "  console.log('interviewId:', r.interview?.id || r.interviewId);",
                  "}"
                ]
              }
            }
          ]
        },
        {
          "name": "Get Role Families",
          "request": {
            "method": "GET",
            "header": [],
            "url": {
              "raw": "{{baseUrl}}/jobs/role-families",
              "host": [
                "{{baseUrl}}"
              ],
              "path": [
                "jobs",
                "role-families"
              ]
            },
            "description": "Lookup list for the JD creation wizard. Returns available role family keys and labels."
          }
        }
      ]
    },
    {
      "name": "3. Interviews",
      "description": "Core interview lifecycle management. FSM states: DRAFT → PLAN_GENERATING → PLAN_PENDING → PLAN_APPROVED → INVITED → IN_PROGRESS → ASSESSMENT_PENDING → ASSESSMENT_READY → COMPLETED.",
      "item": [
        {
          "name": "Create Interview",
          "request": {
            "method": "POST",
            "header": [
              {
                "key": "Content-Type",
                "value": "application/json"
              }
            ],
            "body": {
              "mode": "raw",
              "raw": "{\n  \"jobId\":            \"{{jobId}}\",\n  \"candidate_name\":   \"John Doe\",\n  \"candidate_email\":  \"john.doe@example.com\",\n  \"duration_minutes\": 45\n}",
              "options": {
                "raw": {
                  "language": "json"
                }
              }
            },
            "url": {
              "raw": "{{baseUrl}}/interviews",
              "host": [
                "{{baseUrl}}"
              ],
              "path": [
                "interviews"
              ]
            }
          },
          "event": [
            {
              "listen": "test",
              "script": {
                "type": "text/javascript",
                "exec": [
                  "if ([200, 201].includes(pm.response.code)) {",
                  "  const r = pm.response.json();",
                  "  if (r.id) pm.environment.set('interviewId', r.id);",
                  "  console.log('interviewId:', r.id, '| state:', r.state);",
                  "}"
                ]
              }
            }
          ]
        },
        {
          "name": "List Interviews",
          "request": {
            "method": "GET",
            "header": [],
            "url": {
              "raw": "{{baseUrl}}/interviews?page=1&limit=20",
              "host": [
                "{{baseUrl}}"
              ],
              "path": [
                "interviews"
              ],
              "query": [
                {
                  "key": "page",
                  "value": "1"
                },
                {
                  "key": "limit",
                  "value": "20"
                },
                {
                  "key": "status",
                  "value": "",
                  "disabled": true,
                  "description": "Filter by FSM state e.g. PLAN_PENDING"
                }
              ]
            }
          }
        },
        {
          "name": "Get Interview by ID",
          "request": {
            "method": "GET",
            "header": [],
            "url": {
              "raw": "{{baseUrl}}/interviews/{{interviewId}}",
              "host": [
                "{{baseUrl}}"
              ],
              "path": [
                "interviews",
                "{{interviewId}}"
              ]
            }
          }
        },
        {
          "name": "Get Interview Counts",
          "request": {
            "method": "GET",
            "header": [],
            "url": {
              "raw": "{{baseUrl}}/interviews/inviter-breakdown",
              "host": [
                "{{baseUrl}}"
              ],
              "path": [
                "interviews",
                "inviter-breakdown"
              ]
            },
            "description": "Per-user created/invited counts. Admin only."
          }
        },
        {
          "name": "Drive FSM Transition — Approve Plan",
          "request": {
            "method": "POST",
            "header": [
              {
                "key": "Content-Type",
                "value": "application/json"
              }
            ],
            "body": {
              "mode": "raw",
              "raw": "{ \"to\": \"PLAN_APPROVED\", \"comment\": \"Looks good — solid competency coverage.\" }",
              "options": {
                "raw": {
                  "language": "json"
                }
              }
            },
            "url": {
              "raw": "{{baseUrl}}/interviews/{{interviewId}}/transitions",
              "host": [
                "{{baseUrl}}"
              ],
              "path": [
                "interviews",
                "{{interviewId}}",
                "transitions"
              ]
            },
            "description": "Drive the interview FSM. Valid `to` values depend on current state. Common transitions: PLAN_APPROVED, PLAN_REJECTED, COMPLETED."
          }
        },
        {
          "name": "Drive FSM Transition — Reject Plan",
          "request": {
            "method": "POST",
            "header": [
              {
                "key": "Content-Type",
                "value": "application/json"
              }
            ],
            "body": {
              "mode": "raw",
              "raw": "{ \"to\": \"PLAN_REJECTED\", \"comment\": \"Role requirements changed.\" }",
              "options": {
                "raw": {
                  "language": "json"
                }
              }
            },
            "url": {
              "raw": "{{baseUrl}}/interviews/{{interviewId}}/transitions",
              "host": [
                "{{baseUrl}}"
              ],
              "path": [
                "interviews",
                "{{interviewId}}",
                "transitions"
              ]
            }
          }
        },
        {
          "name": "Set Recruiter Triage Decision",
          "request": {
            "method": "PATCH",
            "header": [
              {
                "key": "Content-Type",
                "value": "application/json"
              }
            ],
            "body": {
              "mode": "raw",
              "raw": "{ \"decision\": \"advance\", \"notes\": \"Strong system design answers.\" }",
              "options": {
                "raw": {
                  "language": "json"
                }
              }
            },
            "url": {
              "raw": "{{baseUrl}}/interviews/{{interviewId}}/decision",
              "host": [
                "{{baseUrl}}"
              ],
              "path": [
                "interviews",
                "{{interviewId}}",
                "decision"
              ]
            },
            "description": "Valid decisions: advance | reject | undecided | hold | null (clear). Does not change FSM state."
          }
        },
        {
          "name": "Reinvite Candidate",
          "request": {
            "method": "POST",
            "header": [
              {
                "key": "Content-Type",
                "value": "application/json"
              }
            ],
            "body": {
              "mode": "raw",
              "raw": "{ \"reason\": \"Previous link expired.\" }",
              "options": {
                "raw": {
                  "language": "json"
                }
              }
            },
            "url": {
              "raw": "{{baseUrl}}/interviews/{{interviewId}}/reinvite",
              "host": [
                "{{baseUrl}}"
              ],
              "path": [
                "interviews",
                "{{interviewId}}",
                "reinvite"
              ]
            },
            "description": "Resets the candidate join link and re-sends the invite email."
          }
        },
        {
          "name": "Get LiveKit Monitor Token (Recruiter)",
          "request": {
            "method": "GET",
            "header": [],
            "url": {
              "raw": "{{baseUrl}}/interviews/{{interviewId}}/livekit-monitor-token",
              "host": [
                "{{baseUrl}}"
              ],
              "path": [
                "interviews",
                "{{interviewId}}",
                "livekit-monitor-token"
              ]
            },
            "description": "Issues a subscribe-only LiveKit token so a recruiter can listen in live without being heard by the candidate."
          }
        }
      ]
    },
    {
      "name": "4. Interview Plan (HITL-1)",
      "description": "Interview plan CRUD and versioned edit history. The plan is generated automatically — recruiters review and optionally apply typed edits before approval.",
      "item": [
        {
          "name": "Get Plan",
          "request": {
            "method": "GET",
            "header": [],
            "url": {
              "raw": "{{baseUrl}}/interviews/{{interviewId}}/plan",
              "host": [
                "{{baseUrl}}"
              ],
              "path": [
                "interviews",
                "{{interviewId}}",
                "plan"
              ]
            },
            "description": "Returns the current plan. Returns 404 while state = PLAN_GENERATING."
          }
        },
        {
          "name": "Apply Plan Edits",
          "request": {
            "method": "POST",
            "header": [
              {
                "key": "Content-Type",
                "value": "application/json"
              }
            ],
            "body": {
              "mode": "raw",
              "raw": "{\n  \"edits\": [\n    { \"op\": \"replace\", \"path\": \"/title\",    \"value\": \"Updated Interview Plan\" },\n    { \"op\": \"add\",     \"path\": \"/sections/-\", \"value\": { \"topic\": \"System Design\", \"duration_minutes\": 15 } }\n  ]\n}",
              "options": {
                "raw": {
                  "language": "json"
                }
              }
            },
            "url": {
              "raw": "{{baseUrl}}/interviews/{{interviewId}}/plan/edits",
              "host": [
                "{{baseUrl}}"
              ],
              "path": [
                "interviews",
                "{{interviewId}}",
                "plan",
                "edits"
              ]
            },
            "description": "Apply typed JSON-patch-style edits to the plan. Only allowed at PLAN_PENDING state."
          }
        },
        {
          "name": "Get Plan Version History",
          "request": {
            "method": "GET",
            "header": [],
            "url": {
              "raw": "{{baseUrl}}/interviews/{{interviewId}}/plan/versions",
              "host": [
                "{{baseUrl}}"
              ],
              "path": [
                "interviews",
                "{{interviewId}}",
                "plan",
                "versions"
              ]
            },
            "description": "Audit trail of all plan versions including who made each change and when."
          }
        }
      ]
    },
    {
      "name": "5. Interview Orchestration",
      "description": "Trigger AI generation of the interview plan and question scripts.",
      "item": [
        {
          "name": "Generate Interview Plan",
          "request": {
            "method": "POST",
            "header": [
              {
                "key": "Content-Type",
                "value": "application/json"
              }
            ],
            "body": {
              "mode": "raw",
              "raw": "{}",
              "options": {
                "raw": {
                  "language": "json"
                }
              }
            },
            "url": {
              "raw": "{{baseUrl}}/interviews/{{interviewId}}/generate-plan",
              "host": [
                "{{baseUrl}}"
              ],
              "path": [
                "interviews",
                "{{interviewId}}",
                "generate-plan"
              ]
            },
            "description": "Triggers the plan generation pipeline from the role profile + JD. Fire-and-forget — poll GET /plan for completion."
          }
        },
        {
          "name": "Formulate Question Scripts",
          "request": {
            "method": "POST",
            "header": [
              {
                "key": "Content-Type",
                "value": "application/json"
              }
            ],
            "body": {
              "mode": "raw",
              "raw": "{}",
              "options": {
                "raw": {
                  "language": "json"
                }
              }
            },
            "url": {
              "raw": "{{baseUrl}}/interviews/{{interviewId}}/formulate-questions",
              "host": [
                "{{baseUrl}}"
              ],
              "path": [
                "interviews",
                "{{interviewId}}",
                "formulate-questions"
              ]
            },
            "description": "Generates the Maya question scripts from the approved plan. Called after PLAN_APPROVED."
          }
        }
      ]
    },
    {
      "name": "6. Interview Assessment",
      "description": "Assessment deliverable read, re-scoring, and review. Scoring is deterministic — no LLM in the scoring path.",
      "item": [
        {
          "name": "Get Assessment",
          "request": {
            "method": "GET",
            "header": [],
            "url": {
              "raw": "{{baseUrl}}/interviews/{{interviewId}}/assessment",
              "host": [
                "{{baseUrl}}"
              ],
              "path": [
                "interviews",
                "{{interviewId}}",
                "assessment"
              ]
            },
            "description": "Available once state ≥ ASSESSMENT_READY. Returns overall_coverage (sufficient/partial/insufficient) + full competency breakdown. No numeric hire/no-hire labels."
          }
        },
        {
          "name": "Re-trigger Assessment Scoring",
          "request": {
            "method": "POST",
            "header": [
              {
                "key": "Content-Type",
                "value": "application/json"
              }
            ],
            "body": {
              "mode": "raw",
              "raw": "{}",
              "options": {
                "raw": {
                  "language": "json"
                }
              }
            },
            "url": {
              "raw": "{{baseUrl}}/interviews/{{interviewId}}/assessment/rescore",
              "host": [
                "{{baseUrl}}"
              ],
              "path": [
                "interviews",
                "{{interviewId}}",
                "assessment",
                "rescore"
              ]
            },
            "description": "Re-runs the measurement pipeline on the existing transcript. Returns 202 — fire-and-forget. Use when stuck on ASSESSMENT_PENDING."
          }
        }
      ]
    },
    {
      "name": "7. Interview Recording",
      "description": "Playback and byte-level streaming of interview recordings.",
      "item": [
        {
          "name": "Get Recording Manifest",
          "request": {
            "method": "GET",
            "header": [],
            "url": {
              "raw": "{{baseUrl}}/interviews/{{interviewId}}/recording",
              "host": [
                "{{baseUrl}}"
              ],
              "path": [
                "interviews",
                "{{interviewId}}",
                "recording"
              ]
            },
            "description": "Returns a playback manifest with short-TTL signed stream URLs. Re-fetch when URLs expire (~15 min)."
          }
        },
        {
          "name": "Stream Recording (byte range)",
          "request": {
            "method": "GET",
            "header": [
              {
                "key": "Range",
                "value": "bytes=0-1048576",
                "description": "Optional Range header for partial content"
              }
            ],
            "url": {
              "raw": "{{baseUrl}}/interviews/{{interviewId}}/recording/stream/:key",
              "host": [
                "{{baseUrl}}"
              ],
              "path": [
                "interviews",
                "{{interviewId}}",
                "recording",
                "stream",
                ":key"
              ],
              "variable": [
                {
                  "key": "key",
                  "value": "<chunk-key-from-manifest>"
                }
              ]
            },
            "description": "Public endpoint gated by a signed key from the manifest. Supports HTTP Range for seekable playback."
          }
        }
      ]
    },
    {
      "name": "8. Interview Delivery",
      "description": "Push assessment results to an external ATS webhook.",
      "item": [
        {
          "name": "Deliver Assessment to ATS",
          "request": {
            "method": "POST",
            "header": [
              {
                "key": "Content-Type",
                "value": "application/json"
              }
            ],
            "body": {
              "mode": "raw",
              "raw": "{}",
              "options": {
                "raw": {
                  "language": "json"
                }
              }
            },
            "url": {
              "raw": "{{baseUrl}}/interviews/{{interviewId}}/deliver",
              "host": [
                "{{baseUrl}}"
              ],
              "path": [
                "interviews",
                "{{interviewId}}",
                "deliver"
              ]
            },
            "description": "Pushes the assessment payload to the tenant's configured webhook URL. Returns 202 — fire-and-forget."
          }
        }
      ]
    },
    {
      "name": "9. Candidate Access (Recruiter-side)",
      "description": "Manage candidate join links. The candidate-facing authentication flow (verify, start, etc.) is in the Integration APIs collection.",
      "item": [
        {
          "name": "Issue Candidate Invite Link",
          "request": {
            "method": "POST",
            "header": [
              {
                "key": "Content-Type",
                "value": "application/json"
              }
            ],
            "body": {
              "mode": "raw",
              "raw": "{\n  \"ttl_seconds\": 259200,\n  \"base_url\":    \"https://app.teamcast.ai\"\n}",
              "options": {
                "raw": {
                  "language": "json"
                }
              }
            },
            "url": {
              "raw": "{{baseUrl}}/candidate-access",
              "host": [
                "{{baseUrl}}"
              ],
              "path": [
                "candidate-access"
              ]
            },
            "description": "Generates a magic-link join URL. Share with the candidate. `ttl_seconds` defaults to 72h."
          },
          "event": [
            {
              "listen": "test",
              "script": {
                "type": "text/javascript",
                "exec": [
                  "if (pm.response.code === 200 || pm.response.code === 201) {",
                  "  const r = pm.response.json();",
                  "  if (r.joinLink) {",
                  "    const parts = r.joinLink.split('/');",
                  "    const token = parts[parts.length - 1];",
                  "    pm.environment.set('candidateToken', token);",
                  "    console.log('joinLink:', r.joinLink);",
                  "  }",
                  "}"
                ]
              }
            }
          ]
        },
        {
          "name": "Email Invite Link",
          "request": {
            "method": "POST",
            "header": [
              {
                "key": "Content-Type",
                "value": "application/json"
              }
            ],
            "body": {
              "mode": "raw",
              "raw": "{\n  \"interviewId\": \"{{interviewId}}\",\n  \"email\":       \"candidate@example.com\"\n}",
              "options": {
                "raw": {
                  "language": "json"
                }
              }
            },
            "url": {
              "raw": "{{baseUrl}}/candidate-access/email-invite",
              "host": [
                "{{baseUrl}}"
              ],
              "path": [
                "candidate-access",
                "email-invite"
              ]
            },
            "description": "Emails an already-issued join link to the candidate."
          }
        },
        {
          "name": "Revoke Access Link",
          "request": {
            "method": "POST",
            "header": [
              {
                "key": "Content-Type",
                "value": "application/json"
              }
            ],
            "body": {
              "mode": "raw",
              "raw": "{ \"reason\": \"Candidate withdrew application.\" }",
              "options": {
                "raw": {
                  "language": "json"
                }
              }
            },
            "url": {
              "raw": "{{baseUrl}}/candidate-access/:id/revoke",
              "host": [
                "{{baseUrl}}"
              ],
              "path": [
                "candidate-access",
                ":id",
                "revoke"
              ],
              "variable": [
                {
                  "key": "id",
                  "value": "{{interviewId}}"
                }
              ]
            }
          }
        }
      ]
    },
    {
      "name": "10. Rubrics (HITL-0)",
      "description": "JD-driven competency rubrics. Generated once per role, signed off before interviews begin.",
      "item": [
        {
          "name": "Generate Draft Rubric",
          "request": {
            "method": "POST",
            "header": [
              {
                "key": "Content-Type",
                "value": "application/json"
              }
            ],
            "body": {
              "mode": "raw",
              "raw": "{\n  \"job_description\": \"We are building a next-generation platform and need a senior engineer...\",\n  \"role_family\":     \"engineering\",\n  \"seniority\":       \"SENIOR\"\n}",
              "options": {
                "raw": {
                  "language": "json"
                }
              }
            },
            "url": {
              "raw": "{{baseUrl}}/rubrics/generate",
              "host": [
                "{{baseUrl}}"
              ],
              "path": [
                "rubrics",
                "generate"
              ]
            },
            "description": "AI-generates a DRAFT rubric from a JD. The draft starts in DRAFT state and must be bias-screened then signed off."
          },
          "event": [
            {
              "listen": "test",
              "script": {
                "type": "text/javascript",
                "exec": [
                  "if ([200, 201].includes(pm.response.code)) {",
                  "  const r = pm.response.json();",
                  "  if (r.id) pm.environment.set('rubricId', r.id);",
                  "}"
                ]
              }
            }
          ]
        },
        {
          "name": "Get Competency Library",
          "request": {
            "method": "GET",
            "header": [],
            "url": {
              "raw": "{{baseUrl}}/rubrics/library",
              "host": [
                "{{baseUrl}}"
              ],
              "path": [
                "rubrics",
                "library"
              ]
            },
            "description": "Returns the vetted competency ontology from the reference schema."
          }
        },
        {
          "name": "Get Rubric",
          "request": {
            "method": "GET",
            "header": [],
            "url": {
              "raw": "{{baseUrl}}/rubrics/{{rubricId}}",
              "host": [
                "{{baseUrl}}"
              ],
              "path": [
                "rubrics",
                "{{rubricId}}"
              ],
              "query": [
                {
                  "key": "version",
                  "value": "",
                  "disabled": true,
                  "description": "Optional version number for point-in-time read"
                }
              ]
            }
          }
        },
        {
          "name": "Transition Rubric Lifecycle — Bias Screen",
          "request": {
            "method": "POST",
            "header": [
              {
                "key": "Content-Type",
                "value": "application/json"
              }
            ],
            "body": {
              "mode": "raw",
              "raw": "{ \"action\": \"bias_screened\", \"notes\": \"No biased language found.\" }",
              "options": {
                "raw": {
                  "language": "json"
                }
              }
            },
            "url": {
              "raw": "{{baseUrl}}/rubrics/{{rubricId}}/transition",
              "host": [
                "{{baseUrl}}"
              ],
              "path": [
                "rubrics",
                "{{rubricId}}",
                "transition"
              ]
            },
            "description": "Valid actions: bias_screened → signed_off → frozen. A frozen rubric cannot be edited."
          }
        },
        {
          "name": "Transition Rubric Lifecycle — Sign Off",
          "request": {
            "method": "POST",
            "header": [
              {
                "key": "Content-Type",
                "value": "application/json"
              }
            ],
            "body": {
              "mode": "raw",
              "raw": "{ \"action\": \"signed_off\", \"notes\": \"Approved by hiring manager.\" }",
              "options": {
                "raw": {
                  "language": "json"
                }
              }
            },
            "url": {
              "raw": "{{baseUrl}}/rubrics/{{rubricId}}/transition",
              "host": [
                "{{baseUrl}}"
              ],
              "path": [
                "rubrics",
                "{{rubricId}}",
                "transition"
              ]
            }
          }
        }
      ]
    },
    {
      "name": "11. Role Configs (HITL-0)",
      "description": "Reusable role profiles that seed interview plans for a given position/seniority combination.",
      "item": [
        {
          "name": "Save Role Config",
          "request": {
            "method": "POST",
            "header": [
              {
                "key": "Content-Type",
                "value": "application/json"
              }
            ],
            "body": {
              "mode": "raw",
              "raw": "{\n  \"title\":       \"Senior Backend Engineer\",\n  \"seniority\":   \"SENIOR\",\n  \"role_family\": \"engineering\",\n  \"competencies\": [\n    { \"key\": \"typescript_mastery\",     \"weight\": 0.35 },\n    { \"key\": \"distributed_systems\",   \"weight\": 0.30 },\n    { \"key\": \"database_design\",       \"weight\": 0.20 },\n    { \"key\": \"system_observability\",  \"weight\": 0.15 }\n  ]\n}",
              "options": {
                "raw": {
                  "language": "json"
                }
              }
            },
            "url": {
              "raw": "{{baseUrl}}/role-configs",
              "host": [
                "{{baseUrl}}"
              ],
              "path": [
                "role-configs"
              ]
            }
          },
          "event": [
            {
              "listen": "test",
              "script": {
                "type": "text/javascript",
                "exec": [
                  "if ([200, 201].includes(pm.response.code)) {",
                  "  const r = pm.response.json();",
                  "  if (r.id) pm.environment.set('roleConfigId', r.id);",
                  "}"
                ]
              }
            }
          ]
        },
        {
          "name": "List Role Configs",
          "request": {
            "method": "GET",
            "header": [],
            "url": {
              "raw": "{{baseUrl}}/role-configs",
              "host": [
                "{{baseUrl}}"
              ],
              "path": [
                "role-configs"
              ]
            }
          }
        },
        {
          "name": "Get Role Config",
          "request": {
            "method": "GET",
            "header": [],
            "url": {
              "raw": "{{baseUrl}}/role-configs/{{roleConfigId}}",
              "host": [
                "{{baseUrl}}"
              ],
              "path": [
                "role-configs",
                "{{roleConfigId}}"
              ]
            }
          }
        }
      ]
    },
    {
      "name": "12. Admin — Users, Roles & Permissions",
      "description": "Workspace user management and RBAC. Requires admin-level permissions.",
      "item": [
        {
          "name": "Bootstrap Tenant (public)",
          "request": {
            "auth": {
              "type": "noauth"
            },
            "method": "POST",
            "header": [
              {
                "key": "Content-Type",
                "value": "application/json"
              },
              {
                "key": "x-bootstrap-secret",
                "value": "<BOOTSTRAP_SECRET_FROM_ENV>"
              }
            ],
            "body": {
              "mode": "raw",
              "raw": "{\n  \"name\":       \"Acme Corp\",\n  \"slug\":       \"acme-corp\",\n  \"adminEmail\": \"admin@acme.ai\",\n  \"adminPassword\": \"Admin123!\"\n}",
              "options": {
                "raw": {
                  "language": "json"
                }
              }
            },
            "url": {
              "raw": "{{baseUrl}}/admin/tenants",
              "host": [
                "{{baseUrl}}"
              ],
              "path": [
                "admin",
                "tenants"
              ]
            },
            "description": "One-time tenant bootstrap. Requires the `x-bootstrap-secret` header (not a JWT). Used during onboarding."
          }
        },
        {
          "name": "List Workspace Users",
          "request": {
            "method": "GET",
            "header": [],
            "url": {
              "raw": "{{baseUrl}}/admin/users?page=1&limit=20",
              "host": [
                "{{baseUrl}}"
              ],
              "path": [
                "admin",
                "users"
              ],
              "query": [
                {
                  "key": "page",
                  "value": "1"
                },
                {
                  "key": "limit",
                  "value": "20"
                },
                {
                  "key": "search",
                  "value": "",
                  "disabled": true
                }
              ]
            }
          }
        },
        {
          "name": "Create Workspace User",
          "request": {
            "method": "POST",
            "header": [
              {
                "key": "Content-Type",
                "value": "application/json"
              }
            ],
            "body": {
              "mode": "raw",
              "raw": "{\n  \"name\":     \"Alice Recruiter\",\n  \"email\":    \"alice@acme.ai\",\n  \"password\": \"Recruiter123!\"\n}",
              "options": {
                "raw": {
                  "language": "json"
                }
              }
            },
            "url": {
              "raw": "{{baseUrl}}/admin/users",
              "host": [
                "{{baseUrl}}"
              ],
              "path": [
                "admin",
                "users"
              ]
            }
          },
          "event": [
            {
              "listen": "test",
              "script": {
                "type": "text/javascript",
                "exec": [
                  "if ([200, 201].includes(pm.response.code)) {",
                  "  const r = pm.response.json();",
                  "  if (r.id) pm.environment.set('userId', r.id);",
                  "}"
                ]
              }
            }
          ]
        },
        {
          "name": "List Workspace Roles",
          "request": {
            "method": "GET",
            "header": [],
            "url": {
              "raw": "{{baseUrl}}/admin/roles",
              "host": [
                "{{baseUrl}}"
              ],
              "path": [
                "admin",
                "roles"
              ]
            }
          }
        },
        {
          "name": "List All Permissions",
          "request": {
            "method": "GET",
            "header": [],
            "url": {
              "raw": "{{baseUrl}}/admin/permissions",
              "host": [
                "{{baseUrl}}"
              ],
              "path": [
                "admin",
                "permissions"
              ]
            },
            "description": "Global permission catalog. Use these keys when creating custom roles."
          }
        },
        {
          "name": "Create Custom Role",
          "request": {
            "method": "POST",
            "header": [
              {
                "key": "Content-Type",
                "value": "application/json"
              }
            ],
            "body": {
              "mode": "raw",
              "raw": "{\n  \"name\":        \"Interviewer\",\n  \"description\": \"Can view interviews and assessments but cannot create or approve.\"\n}",
              "options": {
                "raw": {
                  "language": "json"
                }
              }
            },
            "url": {
              "raw": "{{baseUrl}}/admin/roles",
              "host": [
                "{{baseUrl}}"
              ],
              "path": [
                "admin",
                "roles"
              ]
            }
          },
          "event": [
            {
              "listen": "test",
              "script": {
                "type": "text/javascript",
                "exec": [
                  "if ([200, 201].includes(pm.response.code)) {",
                  "  const r = pm.response.json();",
                  "  if (r.id) pm.environment.set('roleId', r.id);",
                  "}"
                ]
              }
            }
          ]
        },
        {
          "name": "Grant Permission to Role",
          "request": {
            "method": "POST",
            "header": [
              {
                "key": "Content-Type",
                "value": "application/json"
              }
            ],
            "body": {
              "mode": "raw",
              "raw": "{ \"permissionKey\": \"interview:read\" }",
              "options": {
                "raw": {
                  "language": "json"
                }
              }
            },
            "url": {
              "raw": "{{baseUrl}}/admin/roles/{{roleId}}/grant",
              "host": [
                "{{baseUrl}}"
              ],
              "path": [
                "admin",
                "roles",
                "{{roleId}}",
                "grant"
              ]
            }
          }
        },
        {
          "name": "Assign Role to User",
          "request": {
            "method": "POST",
            "header": [
              {
                "key": "Content-Type",
                "value": "application/json"
              }
            ],
            "body": {
              "mode": "raw",
              "raw": "{ \"roleId\": \"{{roleId}}\" }",
              "options": {
                "raw": {
                  "language": "json"
                }
              }
            },
            "url": {
              "raw": "{{baseUrl}}/admin/users/{{userId}}/assign-role",
              "host": [
                "{{baseUrl}}"
              ],
              "path": [
                "admin",
                "users",
                "{{userId}}",
                "assign-role"
              ]
            }
          }
        },
        {
          "name": "Remove Role from User",
          "request": {
            "method": "DELETE",
            "header": [],
            "url": {
              "raw": "{{baseUrl}}/admin/users/{{userId}}/roles/{{roleId}}",
              "host": [
                "{{baseUrl}}"
              ],
              "path": [
                "admin",
                "users",
                "{{userId}}",
                "roles",
                "{{roleId}}"
              ]
            }
          }
        },
        {
          "name": "Remove Permission from Role",
          "request": {
            "method": "DELETE",
            "header": [],
            "url": {
              "raw": "{{baseUrl}}/admin/roles/{{roleId}}/permissions/:permKey",
              "host": [
                "{{baseUrl}}"
              ],
              "path": [
                "admin",
                "roles",
                "{{roleId}}",
                "permissions",
                ":permKey"
              ],
              "variable": [
                {
                  "key": "permKey",
                  "value": "interview:read"
                }
              ]
            }
          }
        }
      ]
    },
    {
      "name": "13. API Keys",
      "description": "Manage integration API keys for server-to-server ATS/HRIS access.",
      "item": [
        {
          "name": "Create API Key",
          "request": {
            "method": "POST",
            "header": [
              {
                "key": "Content-Type",
                "value": "application/json"
              }
            ],
            "body": {
              "mode": "raw",
              "raw": "{\n  \"name\":        \"ATS Integration Key\",\n  \"permissions\": [\"interview:create\", \"interview:read\", \"interview:approve\", \"interview:update\", \"interview:delete\"],\n  \"expiresAt\":   null\n}",
              "options": {
                "raw": {
                  "language": "json"
                }
              }
            },
            "url": {
              "raw": "{{baseUrl}}/api-keys",
              "host": [
                "{{baseUrl}}"
              ],
              "path": [
                "api-keys"
              ]
            },
            "description": "The raw key (`sk_live_...`) is returned ONCE and never stored server-side. Save it immediately."
          },
          "event": [
            {
              "listen": "test",
              "script": {
                "type": "text/javascript",
                "exec": [
                  "if ([200, 201].includes(pm.response.code)) {",
                  "  const r = pm.response.json();",
                  "  if (r.id)  pm.environment.set('apiKeyId', r.id);",
                  "  if (r.key) { pm.environment.set('apiKey', r.key); console.log('Save this key NOW (shown once):', r.key); }",
                  "}"
                ]
              }
            }
          ]
        },
        {
          "name": "List API Keys",
          "request": {
            "method": "GET",
            "header": [],
            "url": {
              "raw": "{{baseUrl}}/api-keys",
              "host": [
                "{{baseUrl}}"
              ],
              "path": [
                "api-keys"
              ]
            },
            "description": "Returns all keys with names and masked prefixes. The raw key is never returned after creation."
          }
        },
        {
          "name": "Update API Key",
          "request": {
            "method": "PATCH",
            "header": [
              {
                "key": "Content-Type",
                "value": "application/json"
              }
            ],
            "body": {
              "mode": "raw",
              "raw": "{ \"name\": \"Greenhouse Integration Key\" }",
              "options": {
                "raw": {
                  "language": "json"
                }
              }
            },
            "url": {
              "raw": "{{baseUrl}}/api-keys/{{apiKeyId}}",
              "host": [
                "{{baseUrl}}"
              ],
              "path": [
                "api-keys",
                "{{apiKeyId}}"
              ]
            }
          }
        },
        {
          "name": "Revoke API Key",
          "request": {
            "method": "DELETE",
            "header": [],
            "url": {
              "raw": "{{baseUrl}}/api-keys/{{apiKeyId}}",
              "host": [
                "{{baseUrl}}"
              ],
              "path": [
                "api-keys",
                "{{apiKeyId}}"
              ]
            }
          }
        }
      ]
    },
    {
      "name": "14. Workspace OAuth Apps",
      "description": "Register and manage OAuth 2.1 applications for your workspace.",
      "item": [
        {
          "name": "List OAuth Apps",
          "request": {
            "method": "GET",
            "header": [],
            "url": {
              "raw": "{{baseUrl}}/workspace/oauth-clients",
              "host": [
                "{{baseUrl}}"
              ],
              "path": [
                "workspace",
                "oauth-clients"
              ]
            }
          }
        },
        {
          "name": "Register OAuth App",
          "request": {
            "method": "POST",
            "header": [
              {
                "key": "Content-Type",
                "value": "application/json"
              }
            ],
            "body": {
              "mode": "raw",
              "raw": "{\n  \"name\":          \"My ATS Integration\",\n  \"redirect_uris\": [\"https://my-ats.example.com/oauth/callback\"],\n  \"scopes\":        [\"interview:read\", \"interview:create\", \"interview:approve\"],\n  \"grant_types\":   [\"authorization_code\", \"refresh_token\"],\n  \"is_public\":     false\n}",
              "options": {
                "raw": {
                  "language": "json"
                }
              }
            },
            "url": {
              "raw": "{{baseUrl}}/workspace/oauth-clients",
              "host": [
                "{{baseUrl}}"
              ],
              "path": [
                "workspace",
                "oauth-clients"
              ]
            },
            "description": "Registers a new OAuth app. `client_secret` is shown ONCE in the response."
          },
          "event": [
            {
              "listen": "test",
              "script": {
                "type": "text/javascript",
                "exec": [
                  "if ([200, 201].includes(pm.response.code)) {",
                  "  const r = pm.response.json();",
                  "  if (r.client_id)     pm.environment.set('oauthClientId', r.client_id);",
                  "  if (r.client_secret) { pm.environment.set('oauthClientSecret', r.client_secret); console.log('Save client_secret now:', r.client_secret); }",
                  "}"
                ]
              }
            }
          ]
        },
        {
          "name": "Delete OAuth App",
          "request": {
            "method": "DELETE",
            "header": [],
            "url": {
              "raw": "{{baseUrl}}/workspace/oauth-clients/{{oauthClientId}}",
              "host": [
                "{{baseUrl}}"
              ],
              "path": [
                "workspace",
                "oauth-clients",
                "{{oauthClientId}}"
              ]
            },
            "description": "Deletes the app and cascades revocation of all issued tokens."
          }
        }
      ]
    },
    {
      "name": "16. Notifications",
      "description": "In-app notification management.",
      "item": [
        {
          "name": "Get My Notifications",
          "request": {
            "method": "GET",
            "header": [],
            "url": {
              "raw": "{{baseUrl}}/notifications?page=1&limit=20",
              "host": [
                "{{baseUrl}}"
              ],
              "path": [
                "notifications"
              ],
              "query": [
                {
                  "key": "page",
                  "value": "1"
                },
                {
                  "key": "limit",
                  "value": "20"
                }
              ]
            },
            "description": "Returns paginated notifications + unread count."
          },
          "event": [
            {
              "listen": "test",
              "script": {
                "type": "text/javascript",
                "exec": [
                  "if (pm.response.code === 200) {",
                  "  const r = pm.response.json();",
                  "  const first = r.data?.[0] || r.items?.[0] || r[0];",
                  "  if (first?.id) pm.environment.set('notificationId', first.id);",
                  "}"
                ]
              }
            }
          ]
        },
        {
          "name": "Mark Notification Read",
          "request": {
            "method": "POST",
            "header": [],
            "url": {
              "raw": "{{baseUrl}}/notifications/{{notificationId}}/read",
              "host": [
                "{{baseUrl}}"
              ],
              "path": [
                "notifications",
                "{{notificationId}}",
                "read"
              ]
            }
          }
        },
        {
          "name": "Mark All Notifications Read",
          "request": {
            "method": "POST",
            "header": [],
            "url": {
              "raw": "{{baseUrl}}/notifications/read-all",
              "host": [
                "{{baseUrl}}"
              ],
              "path": [
                "notifications",
                "read-all"
              ]
            }
          }
        }
      ]
    },
    {
      "name": "18. Webhook Config",
      "description": "Configure the outbound webhook for your tenant. Teamcast signs every delivery with HMAC-SHA256.",
      "item": [
        {
          "name": "Get Webhook Config",
          "request": {
            "method": "GET",
            "header": [],
            "url": {
              "raw": "{{baseUrl}}/me/webhook-config",
              "host": [
                "{{baseUrl}}"
              ],
              "path": [
                "me",
                "webhook-config"
              ]
            },
            "description": "Returns the webhook config with the secret masked."
          }
        },
        {
          "name": "Create / Update Webhook Config",
          "request": {
            "method": "PUT",
            "header": [
              {
                "key": "Content-Type",
                "value": "application/json"
              }
            ],
            "body": {
              "mode": "raw",
              "raw": "{\n  \"callback_url\": \"https://your-ats.example.com/teamcast/webhook\",\n  \"events\": [\n    \"interview.info_needed\",\n    \"interview.plan_generated\",\n    \"interview.approved\",\n    \"interview.assessment_ready\",\n    \"interview.completed\",\n    \"interview.rejected\",\n    \"interview.cancelled\"\n  ],\n  \"is_active\": true\n}",
              "options": {
                "raw": {
                  "language": "json"
                }
              }
            },
            "url": {
              "raw": "{{baseUrl}}/me/webhook-config",
              "host": [
                "{{baseUrl}}"
              ],
              "path": [
                "me",
                "webhook-config"
              ]
            },
            "description": "Omit `secret` to auto-generate one (HMAC-SHA256). The full secret is shown ONCE in the initial response — store it immediately."
          }
        },
        {
          "name": "Delete Webhook Config",
          "request": {
            "method": "DELETE",
            "header": [],
            "url": {
              "raw": "{{baseUrl}}/me/webhook-config",
              "host": [
                "{{baseUrl}}"
              ],
              "path": [
                "me",
                "webhook-config"
              ]
            }
          }
        }
      ]
    },
    {
      "name": "23. Health",
      "description": "Liveness and readiness probes. No /api/v2 prefix.",
      "auth": {
        "type": "noauth"
      },
      "item": [
        {
          "name": "Liveness",
          "request": {
            "auth": {
              "type": "noauth"
            },
            "method": "GET",
            "header": [],
            "url": {
              "raw": "http://localhost:4100/health/live",
              "host": [
                "http://localhost:4100"
              ],
              "path": [
                "health",
                "live"
              ]
            },
            "description": "Returns 200 if the process is up. No dependency checks."
          }
        },
        {
          "name": "Readiness",
          "request": {
            "auth": {
              "type": "noauth"
            },
            "method": "GET",
            "header": [],
            "url": {
              "raw": "http://localhost:4100/health/ready",
              "host": [
                "http://localhost:4100"
              ],
              "path": [
                "health",
                "ready"
              ]
            },
            "description": "Returns 200 if the service is ready to accept traffic (DB connectivity check included)."
          }
        }
      ]
    }
  ]
}
