---
title: "Start a job (the survey container). Contact details are NOT accepted here — funnel rule. Send `Idempotency-Key` so a retry cannot create a second job."
method: POST
path: "/jobs"
---

# Start a job (the survey container). Contact details are NOT accepted here — funnel rule. Send \`Idempotency-Key\` so a retry cannot create a second job.

`POST /jobs`

## Request

- Base URL: `https://widget.reelquoteai.com/api/v1`
- URL: `https://widget.reelquoteai.com/api/v1/jobs`
- Auth: HTTP bearer

## Headers

- `Idempotency-Key` string

## Request body

- object
  - `quote_kind` 'ballpark' | 'firm': What the job is for. A firm job becomes bookable once filmed.
  - `dwelling` string: What the customer says their home is (any wording; stored beside what the video measures)
  - `move_date` string, date: YYYY-MM-DD
  - `origin` AddressInput: One end of the move, as the customer gives it.
    - `address` string: Free text as typed, or as resolved by /places/resolve
    - `unit` string: Apartment or suite. A number like 2104 lets the floor be inferred.
    - `place_id` string: From /places/resolve, when address autocomplete was used
    - `dwelling` string: apartment, condo, townhouse, house or storage — free text is normalised
  - `destination` AddressInput: One end of the move, as the customer gives it.
    - `address` string: Free text as typed, or as resolved by /places/resolve
    - `unit` string: Apartment or suite. A number like 2104 lets the floor be inferred.
    - `place_id` string: From /places/resolve, when address autocomplete was used
    - `dwelling` string: apartment, condo, townhouse, house or storage — free text is normalised

## Response `201`

Created — or, with an Idempotency-Key seen before, the original creation replayed. The inferred access profiles come straight back so a UI can ask 'elevator building?' without a second round trip.

- object
  - `job_id` string: ULID — the id for every later call
  - `status` 'created'
  - `origin` AccessProfile: One end of the move as the system holds it: what was inferred, and what the customer confirmed. Both survive, so inferred-vs-confirmed is measurable.
    - `address` string, nullable
    - `unit` string, nullable
    - `place_id` string, nullable
    - `dwelling` 'apartment' | 'condo' | 'townhouse' | 'house' | 'storage', nullable
    - `floor_inferred` integer, nullable: Read off the unit number; null when it could not be
    - `floor_confirmed` integer, nullable: What the customer confirmed via /access
    - `elevator` boolean, nullable: null = not yet answered
    - `elevator_suggested` boolean: true when the inferred floor makes an elevator likely; a UI pre-checks the box
    - `stairs_flights` integer, nullable
    - `parking_to_door_ft` integer, nullable: Carry distance from where a truck can park
    - `access_confirmed_at` string, date-time, nullable
  - `destination` AccessProfile: One end of the move as the system holds it: what was inferred, and what the customer confirmed. Both survive, so inferred-vs-confirmed is measurable.
    - `address` string, nullable
    - `unit` string, nullable
    - `place_id` string, nullable
    - `dwelling` 'apartment' | 'condo' | 'townhouse' | 'house' | 'storage', nullable
    - `floor_inferred` integer, nullable: Read off the unit number; null when it could not be
    - `floor_confirmed` integer, nullable: What the customer confirmed via /access
    - `elevator` boolean, nullable: null = not yet answered
    - `elevator_suggested` boolean: true when the inferred floor makes an elevator likely; a UI pre-checks the box
    - `stairs_flights` integer, nullable
    - `parking_to_door_ft` integer, nullable: Carry distance from where a truck can park
    - `access_confirmed_at` string, date-time, nullable

## Other responses

- `400`: `invalid_request` — A field is missing, malformed or not allowed in this state. `message` says which. `secret_key_in_url` — A secret key was sent as `?k=`. Secret keys go in the Authorization header only.
- `401`: `unauthorized` — No key, an unknown key, or a revoked key.
- `409`: `last_publishable_key` — The only live publishable key cannot be revoked — the widget stops without one. Rotate it instead. `key_already_rotated` — That key was already rotated. A key is rotated once; its replacement is the one to use and to rotate next. `webhook_paused` — That webhook endpoint is paused; turn it back on before replaying a delivery to it. `video_in_flight` — A video is already being fetched for this job (POST /jobs/{id}/video). Poll GET /jobs/{id}. `video_already_supplied` — The job already has a video and has moved past upload. Start a new job for a different walkthrough. `no_rate_card` — The mover has no active rate card, so nothing can be priced yet. `ballpark_not_bookable` — Only a firm quote from a filmed walkthrough can be booked. `already_requested` — The job is already booked or awaiting the mover, so the move date can no longer change here. Contact the mover. `idempotency_in_progress` — A request with the same Idempotency-Key is still being processed. Obey `Retry-After` (1 s) and retry with the same key.
- `422`: `idempotency_key_reused` — That Idempotency-Key was already used with a different request body. A key names one request; use a new key for a new job.
- `429`: `rate_limited` — Per-key limit (60/min publishable, 300/min secret), the mover's daily ballpark or video-analysis cap, or a visitor's daily catalog-search cap. Obey `Retry-After`. Carries `Retry-After` in seconds.

---

[API](https://skmtc.dev/reelquoteai/apis/reelquoteai-us-api.md) · [All operations](https://skmtc.dev/reelquoteai/apis/reelquoteai-us-api/llms.txt) · [OpenAPI document](https://skmtc.dev/reelquoteai/apis/reelquoteai-us-api/revisions/56c304752192?raw)
