You are integrating with the Dover public API.

## Source of truth
- OpenAPI spec (fetch this first, do not invent endpoints): https://app.dover.com/docs/api.json
- Human docs: https://app.dover.com/docs/api
- Markdown dump: https://app.dover.com/docs/api.md

## Auth
- Header: `Authorization: Bearer <API_KEY>`
- The key is a UUID from the Dover web app: Settings → API Key.
- Requires the ATS Premium plan. Other plans get 403 with `code: ats_premium_required`.
- Base URL: https://app.dover.com

## What the API can do today
- List active public jobs (includes hiring pipeline stages): GET /api/v1/external/jobs
- Add one candidate (multipart/form-data, optional resume PDF): POST /api/v1/external/add-candidate
- Bulk-add candidates (JSON): POST /api/v1/external/bulk-add-candidates
- List hired candidates (optional `job`, `limit`, `offset`): GET /api/v1/external/candidates
- Custom careers page — list published postings: GET /api/v1/external/job-postings
- Custom careers page — job page + application questions: GET /api/v1/external/job-postings/<built-in function id>
- Custom careers page — submit an application (resume + answers): POST /api/v1/external/job-postings/<built-in function id>/applications

## Rules
- Never invent paths, fields, or auth schemes. If unsure, GET the OpenAPI spec.
- `job_id` and `hiring_pipeline_stage_id` come from GET /api/v1/external/jobs.
- Required to add a candidate: job_id, hiring_pipeline_stage_id, candidate_first_name, candidate_last_name.
- Optional: candidate_email, candidate_linkedin_url, resume (PDF), additional_comments.
- Bulk add requires `channel` (AGENCY, REFERRAL, SOURCED, or APPLIED).
- Do not use private or sample jobs.
- When a job posting's `eeo_survey` is not null, show its questions as optional and send the answers as `eeo_answers` (`{"<question key>": ["<option key>"]}`) with the application. Never make them required.
- Careers-page endpoints only return jobs published to the Dover careers page. Submit is the inbound apply pipeline, not add-candidate. Call all three from your backend with the API key; do not put the key in the browser.
- Prefer the spec over this prompt if they disagree.

After fetching the spec, implement the smallest working client for the task I describe next.
