---
title: "Full job state: status, inventory, quote, access, terms, move_date."
method: GET
path: "/jobs/{id}"
---

# Full job state: status, inventory, quote, access, terms, move_date.

`GET /jobs/{id}`

## Request

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

## Path parameters

- `id` string, required

## Response `200`

The job. Poll this while status is queued/processing (every few seconds is fine); the first read after `complete` computes and stores the firm quote.

- Job: Full job state — what the widget polls. Before analysis, inventory is empty and quote is null (or a ballpark).
  - `job_id` string, required: ULID
  - `status` 'created' | 'uploading' | 'uploaded' | 'queued' | 'processing' | 'complete' | 'quoted' | 'booked_requested' | 'booked' | 'declined' | 'error', required: Funnel order. **created** — The job exists. Nothing uploaded yet. **uploading** — An upload URL was issued; the video is on its way. **uploaded** — A chunked upload was assembled (a single PUT skips this state). **queued** — POST /submit accepted; waiting its turn to be analysed. **processing** — The walkthrough is being analysed. Poll GET /jobs/{id}; typically 1–4 minutes. **complete** — Inventory ready. The firm quote is computed on the first read. **quoted** — A firm, bookable quote exists (set by the first GET after complete). **booked_requested** — The customer asked to book; the mover has not answered yet. **booked** — The mover confirmed the booking. **declined** — The mover turned the request down. `decline_reason` may say why. **error** — Analysis failed. `error` carries a message; upload again or contact the mover.
  - `quote_kind` 'ballpark' | 'firm', required: What the job was started for; a firm job gets a bookable quote once filmed.
  - `move_date` string, date, nullable: YYYY-MM-DD
  - `inventory` Inventory, required
    - `item_count` integer, required: Rows
    - `total_quantity` integer: Units across all rows
    - `total_cuft` number, required: Priced volume: excluded rows contribute nothing
    - `total_weight_lbs` number
    - `estimated_boxes` integer, nullable: Medium boxes the analysis estimated from closets and cupboards; also present as a box row
    - `access_notes` string, nullable: Stairs, elevators, long carries seen or heard in the video
    - `video_quality_issues` string, nullable: Rooms skipped, closed closets, poor light — or 'None'
    - `approved_at` string, date-time, nullable: Customer sign-off; cleared whenever the inventory is edited
    - `customer_notes` string, nullable
    - `rooms` Room[], required
      - `room` string
      - `items` InventoryItem[]
        - `id` string, required: Row id. Pass it back to POST /jobs/{id}/items to edit this row.
        - `item_key` string, required: Catalog key (GET /catalog). `misc` when nothing on the catalog fit.
        - `name` string, required: As detected in the video, or as the catalog names a customer-added row
        - `quantity` integer, required
        - `cubic_feet` number, required: Per unit, copied from the catalog at analysis time
        - `weight_lbs` number: Per unit, copied from the catalog at analysis time
        - `fragile` boolean
        - `requires_disassembly` boolean
        - `two_person` boolean
        - `special_handling` boolean
        - `excluded` boolean, required: true = staying / not moving. Kept on the record with its volume unpriced; never deleted.
        - `confidence` number, nullable: 0–1 from the analysis; null on customer-added rows
        - `notes` string, nullable: From the narration or the customer
        - `source` 'ai' | 'customer_added', required: Who put the row here.
    - `packing` object, nullable: Display-only packing-materials estimate derived from this inventory (boxes by size, tape, paper). Quantities, not prices.
    - `gaps` Gaps
      - `prompts` GapPrompt[]: Recomputed from the CURRENT inventory on every read — fixing a gap removes its prompt. Empty is the common, good case.
        - `code` string: Stable code, e.g. bedrooms_missing
        - `severity` 'warn' | 'info'
        - `title` string
        - `message` string: Customer-voiced, e.g. 'only 1 of 3 bedrooms is in the video'
      - `acknowledged_at` string, date-time, nullable: When the customer said 'nothing is missing' via POST /jobs/{id}/gaps
  - `access` object, required
    - `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
    - `flags` string[]: Where what the customer said and what the video shows disagree
  - `quote` Quote: A priced quote. bookable=false means a ballpark range; only bookable quotes can be booked. The key kind decides the view. A publishable key — it sits in the mover's page source — receives the customer view: each line's label, amount, hours, crew and miles, the overage rate, the assumptions and the inputs. A secret key also receives the rate behind each line, applied_rules, subtotal_cents, minimum_charge_cents, rate_card_id, rate_card_name and engine_version.
    - `kind` 'ballpark' | 'firm', required
    - `bookable` boolean, required: true only for a firm quote built from a filmed inventory. Gate any booking action on this flag, never on kind.
    - `currency` string, required: ISO 4217
    - `units` string: Measurement system for volumes and distances
    - `crew` integer, required: Movers on the job
    - `labour_hours` number, required: Billable hours at the home(s)
    - `overage` object: Disclosed on every quote: what an hour past the estimate costs.
      - `label` string
      - `hourly_cents` integer: Rate for time beyond the estimate, in integer cents. Currency travels beside it — never assume USD.
      - `same_as_hourly` boolean
    - `buckets` object, required: The price, line by line.
      - `labour` Bucket: One line of the price: a label and an amount. Labour lines also carry hours and crew; truck legs carry miles.
        - `label` string: Plain-language line name
        - `cents` integer: This line, in integer cents. Currency travels beside it — never assume USD.
      - `move_leg_time` Bucket: One line of the price: a label and an amount. Labour lines also carry hours and crew; truck legs carry miles.
        - `label` string: Plain-language line name
        - `cents` integer: This line, in integer cents. Currency travels beside it — never assume USD.
      - `deadhead_leg_time` Bucket: One line of the price: a label and an amount. Labour lines also carry hours and crew; truck legs carry miles.
        - `label` string: Plain-language line name
        - `cents` integer: This line, in integer cents. Currency travels beside it — never assume USD.
      - `truck_move_leg` Bucket: One line of the price: a label and an amount. Labour lines also carry hours and crew; truck legs carry miles.
        - `label` string: Plain-language line name
        - `cents` integer: This line, in integer cents. Currency travels beside it — never assume USD.
      - `truck_deadhead_leg` Bucket: One line of the price: a label and an amount. Labour lines also carry hours and crew; truck legs carry miles.
        - `label` string: Plain-language line name
        - `cents` integer: This line, in integer cents. Currency travels beside it — never assume USD.
      - `travel_flat` Bucket: One line of the price: a label and an amount. Labour lines also carry hours and crew; truck legs carry miles.
        - `label` string: Plain-language line name
        - `cents` integer: This line, in integer cents. Currency travels beside it — never assume USD.
      - `access_origin` Bucket: One line of the price: a label and an amount. Labour lines also carry hours and crew; truck legs carry miles.
        - `label` string: Plain-language line name
        - `cents` integer: This line, in integer cents. Currency travels beside it — never assume USD.
      - `access_destination` Bucket: One line of the price: a label and an amount. Labour lines also carry hours and crew; truck legs carry miles.
        - `label` string: Plain-language line name
        - `cents` integer: This line, in integer cents. Currency travels beside it — never assume USD.
    - `applied_rules` object[]: Date and seasonal rules that fired, in order. Empty when none did.
      - `rule` string: Rule name from the mover's rate card, e.g. weekend, month_end
      - `mult` number, nullable: Multiplier, when the rule is one
      - `add_cents` integer, nullable: Flat addition, when the rule is one, in integer cents. Currency travels beside it — never assume USD.
      - `delta_cents` integer: What the rule changed the total by, in integer cents. Currency travels beside it — never assume USD.
    - `subtotal_cents` integer: Before date rules and the minimum charge, in integer cents. Currency travels beside it — never assume USD.
    - `minimum_charge_cents` integer: The mover's floor, in integer cents. Currency travels beside it — never assume USD.
    - `minimum_charge_applied` boolean: true when the floor lifted the total
    - `total_cents` integer, nullable, required: The price. null on a ballpark — use low_cents / high_cents, in integer cents. Currency travels beside it — never assume USD.
    - `low_cents` integer: Ballpark only: low end of the range, in integer cents. Currency travels beside it — never assume USD.
    - `high_cents` integer: Ballpark only: high end of the range, in integer cents. Currency travels beside it — never assume USD.
    - `inputs` object: What the price was computed from — pinned on the job, so a later rate-card change can never reprice history. A ballpark adds the home size (dwelling) and its volume range (cuft_low, cuft_high).
      - `cuft` number: Volume priced
      - `weight_lbs` integer
      - `distance_miles` number, nullable
      - `duration_minutes` number, nullable: Routed drive time, when a route was found
      - `move_date` string, date, nullable: YYYY-MM-DD
    - `assumptions` string[], required: Plain-language caveats. Show these to the human.
    - `rate_card_id` string: The mover's rate card this was priced from
    - `rate_card_name` string
    - `engine_version` string: Pricing engine version
  - `steps` PriceSteps: How far the inventory can move before the price does — the honest answer to 'what if I add the piano'.
    - `up` object, nullable: The nearest price break in one direction; null when none is close.
      - `cuft_delta` number: Cubic feet added (up) or removed (down) before the price changes
      - `total_cents` integer: The price at that point, in integer cents. Currency travels beside it — never assume USD.
      - `crew` integer
      - `labour_hours` number
    - `down` object, nullable: The nearest price break in one direction; null when none is close.
      - `cuft_delta` number: Cubic feet added (up) or removed (down) before the price changes
      - `total_cents` integer: The price at that point, in integer cents. Currency travels beside it — never assume USD.
      - `crew` integer
      - `labour_hours` number
  - `contact` Contact, required: What this customer gave for this job — so a resume on another device does not ask twice. Never anything the mover added.
    - `email` string, nullable
    - `name` string, nullable
    - `phone` string, nullable
  - `terms` Terms, required
    - `included` string, nullable: What the mover includes, in their words
    - `terms` string, nullable: The mover's terms, in their words
    - `frozen` boolean: false = live text; true = the snapshot the customer accepted at booking
    - `accepted_at` string, date-time, nullable: Only on a frozen copy
  - `decline_reason` string, nullable: Only when status is declined and the mover gave one
  - `error` string, nullable: Only when status is error

## Other responses

- `401`: `unauthorized` — No key, an unknown key, or a revoked key.
- `404`: `not_found` — No such job for this key, or no such endpoint.
- `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)
