---
title: "Job status"
method: POST
path: "/api/v1/status"
---

# Job status

`POST /api/v1/status`

## Request

- Base URL: `https://commontape.com`
- URL: `https://commontape.com/api/v1/status`
- Auth: HTTP bearer

The authoritative state of one of your jobs, and everything needed to act on it. Read it any time: it never changes the job. Before the owner says yes they see the customer's first name and initial, the ZIP and town, the job and the time. After a yes (booked or done) they also see the full name, phone, address and access instructions. A job that never reached the owner, or that ended without a yes, shows nothing of the customer. Agents never get the customer's details back.

## Request body

- object
  - `transaction_id` string, uuid, required

## Response `200`

Success

- object
  - `transaction_id` string, uuid, required
  - `state` 'quote_incomplete' | 'quoted' | 'held' | 'pending_approval' | 'booked' | 'completed' | 'declined' | 'cancelled' | 'supplier_cancelled' | 'expired', required: One of ten states, each with one meaning. quote_incomplete: Not priced yet: the job needs more facts. needs says which. Nothing is held. Allowed: quote. quoted: An exact price for one exact job version, until expires_at. Nothing is held: the time is not reserved yet. Allowed: hold, quote. held: A time is reserved for this job until hold_expires_at. Book it, or cancel to let it go. Allowed: book, cancel. pending_approval: Asked to book; the owner must say yes by approval.deadline. The time stays reserved while waiting. No answer by then and the job expires and the time is released. Allowed: status, cancel. booked: The owner is committed to do this job at this price and time. Allowed: status, quote, modify, cancel. completed: The job was done. completion.source says who marked it: the owner (merchant) or CommonTape after the window ended (system). Allowed: status. declined: The owner said no. decline.reason says why; decline.next_available is the next open time when there is one. Allowed: status, quote. cancelled: Called off by the agent. The time was released. Allowed: status, quote. supplier_cancelled: Called off by the owner after it was booked. The job can be quoted again elsewhere from job. Allowed: status, quote. expired: Ran out of time: the quote passed expires_at, or the hold or the owner's answer passed its deadline. The time was released. Allowed: status, quote.
  - `allowed_actions` string[], required: The operations you may call on this job now. Anything else is refused (INVALID_STATE, ALREADY_BOOKED, ALREADY_CANCELLED).
  - `next_actions` string[], required: The suggested next steps, from a fixed list.
  - `job_version` integer, nullable: The job's version. Every change to the job is a new version; old versions, their quotes and prices are kept, never written over.
  - `job` object: The current version of the job: service, priced inputs, must_have, nice_to_have, must_not, special_requests, scope, word list version. Send it again to quote the same job elsewhere.
  - `price` object, nullable
    - `amount` number
    - `currency` string
  - `quote` object, nullable
    - `quote_id` string, uuid
    - `quoted_at` string, date-time
    - `expires_at` string, date-time
    - `availability_checked_at` string, date-time: When the open windows were read. Windows change: a later hold can still find a slot gone (CAPACITY_FULL).
  - `window` object, nullable
    - `start` string, date-time
    - `end` string, date-time
  - `hold_expires_at` string, date-time, nullable
  - `notices` object[]: The push notices sent for this job to your key's notify_url (empty without one): the event, delivered / trying / failed, tries so far, when.
    - `event` 'job.declined' | 'job.called_off' | 'job.booked' | 'job.expired'
    - `state` 'delivered' | 'trying' | 'failed'
    - `attempts` integer
    - `at` string, date-time, nullable
  - `alternatives` object[]: Only on a dead end reached in the last 24 hours: declined (other times here, not the declined one, and other businesses), expired (other times here and, for a job that came from a search, other businesses), cancelled because the business stopped taking jobs, or supplier_cancelled (other businesses only). Kept up to 60 seconds: polling inside the same minute reads the same list and tokens (alternatives_worked_out_at); a list with a token near its end is worked out again. Ready alternatives for the same job, worked out on every answer by the same judge as search: up to 3 other times at this business and up to 3 other businesses. An alternative never misses a must-have, never offers a must-not and never adds back a task the customer left out; a nice-to-have it misses is named in why. Each is priced for its own window (its day and hour charges): hold its quote_token with its allocation_id as it is.
    - `kind` 'same_business_other_time' | 'other_business_same_job', required
    - `slug` string, required
    - `display_name` string, required
    - `service_key` string, required
    - `allocation_id` string, uuid, required
    - `window_start` string, date-time, required
    - `window_end` string, date-time, required
    - `job_hours` integer, nullable: How long this job takes on site, in whole hours: hourly services the hours asked (rounded up); other services the booking length plus the business's bigger-homes hours when the home meets its rule. For a business that builds its open times from its working hours (discover capacity.jobs_at_once), every offered time is exactly this long.
    - `job_people` integer, nullable: How many cleaners this job takes: an hourly price's people, the business's usual crew (crew.min), more when the home meets its crew rule (crew.rule), at least 2 for a must-not crew.solo or must-have crew.two_or_more, 3 for crew.three_or_more. Counted against capacity.cleaners. null while the quote is incomplete.
    - `price` object, required
      - `amount` number
      - `currency` string
    - `quote_token` string, required
    - `expires_at` string, date-time, required
    - `booking_authority` object, nullable
    - `why` string[], required: Fixed codes: other_time, other_business, nice_to_have_missed:<word>, needs_owner_approval.
  - `alternatives_note` 'timed_out' | 'none_found': Why alternatives is empty: none fit every must, or they could not be worked out within 4 seconds (the refusal is never delayed for them).
  - `if_changed` object[]: Businesses that could do this job if the customer gave up ONE thing (up to 2). None of them can be held or booked from this item: it carries no quote_token and no allocation_id. Ask the customer; if they agree, search again without change.word (that is a new job). A must-have the business said it does not offer, or a must-not that is its only option, is the only kind of change listed; never something the business has not answered, what it takes (the home), a condition of the home, or a second change. You can still quote such a business by name, but do not book it with the job unchanged without the customer's yes.
    - `slug` string, required
    - `display_name` string, required
    - `service_key` string, required
    - `change` object, required: The one thing the customer would give up: a word out of must_have or out of must_not, with the business's own reason.
      - `from` 'must_have' | 'must_not'
      - `word` string
      - `code` string
      - `label` string
    - `price_if_changed` object, required: The changed job's search price at this business: the same number a search without change.word shows. Not the price at earliest_window_start when the business charges for days or hours.
      - `amount` number
      - `currency` string
    - `earliest_window_start` string, date-time, nullable, required
    - `nice_to_have_missed` string[], required
    - `needs_owner_approval` boolean, required: The changed job would wait for the owner's yes there.
    - `next_step` 'ask_customer_then_search', required
  - `if_changed_note` 'timed_out' | 'none_found': Why if_changed is empty: no business is one change away, or they could not be worked out within the 4 seconds (the ready alternatives are kept).
  - `alternatives_worked_out_at` string, date-time: When the alternatives on this answer were worked out (status keeps them up to 60 seconds).
  - `approval` object: Whether the owner's yes is needed and where it stands. While waiting the time stays reserved (capacity_held). At the deadline with no answer: expired: the job ends and the reserved time is released.
    - `state` 'not_needed' | 'waiting' | 'approved' | 'declined' | 'expired' | 'withdrawn'
    - `needs` object[]: What needs the owner's yes, each with why. ask_first_limit: the home is above a size the owner asked to see first, does not give that size, or the owner is not sure of that limit; text says which in plain words.
      - `key` string
      - `text` string
      - `reason` 'ask_first_task' | 'ask_first_condition' | 'ask_first_limit' | 'special_request'
    - `asked_at` string, date-time, nullable
    - `deadline` string, date-time, nullable
    - `at_deadline` string
    - `capacity_held` boolean
    - `reasons` string[]: Why the owner's yes was asked: booking_authority's reasons when it was asked. Empty when not asked.
  - `commitment` object, nullable: Who committed the booking. null until booked. CommonTape never reports a customer confirmation it did not see: your booking call is your assertion for your customer.
    - `supplier` 'rule' | 'merchant_action': rule: booked on its own under the owner's booking setting (rule_version). merchant_action: the owner said yes.
    - `customer` 'agent_assertion'
    - `rule_version` integer, nullable
    - `owner_may_call_off` boolean: The owner can still call the job off; status then says supplier_cancelled.
  - `decline` object, nullable: A no is a business answer, not a failure: next_actions says how to go on (another time from next_available, another business, or a changed request).
    - `reason` 'too_busy' | 'too_far' | 'no_crew' | 'unspecified' | 'home_too_large' | 'condition_not_taken' | 'special_request_not_possible' | 'task_not_offered': The owner's own word.
    - `code` 'unsupported_request' | 'insufficient_staff' | 'schedule_conflict' | 'property_too_large' | 'condition_not_accepted' | 'outside_service_area' | 'unable_to_meet_special_request' | 'merchant_declined_other': The canonical code for the owner's answer.
    - `next_actions` string[]
    - `next_available` object, nullable
  - `completion` object, nullable
    - `source` 'merchant' | 'system': merchant: the owner marked it done. system: CommonTape marked it 24 hours after the window ended.
    - `at` string, date-time
  - `cancellation` object, nullable: How the job was cancelled. null unless cancelled or supplier_cancelled. CommonTape takes no cancellation fee; any charge is between the customer and the business.
    - `by` 'agent' | 'business' | 'system': agent: you (for the customer). business: the owner called it off. system: CommonTape (the business stopped taking jobs).
    - `at` string, date-time
    - `reason` object
      - `code` 'customer_changed_plans' | 'customer_booked_elsewhere' | 'booked_in_error' | 'customer_other' | 'insufficient_staff' | 'schedule_conflict' | 'illness_or_emergency' | 'merchant_cancelled_other' | 'business_unavailable' | 'not_given'
      - `label` string
    - `from_state` string, nullable
    - `fee` unknown
    - `policy` object
      - `code` 'no_fee'
      - `text` string
    - `capacity_released` boolean: The time was given back in the same step.
  - `receipt` object, nullable: What was booked, from the record: a business editing its prices, limits or name later never changes it. text is a short plain confirmation to show your customer (the business's own clock, no ids). null for a job with no time yet.
    - `transaction_id` string, uuid
    - `business` object
      - `slug` string
      - `display_name` string
    - `service` object
      - `key` string
      - `name` string
    - `window` object, nullable
      - `start` string, date-time
      - `end` string, date-time
      - `time_zone` string: The business's time zone (IANA).
    - `price` object, nullable
      - `amount` number
      - `currency` string
    - `home` string, nullable
    - `scope` object: Labels, never keys.
      - `included` string[]
      - `extras` string[]
      - `not_doing` string[]
      - `conditions` string[]
      - `approved_requests` string[]
    - `cancel` object
      - `allowed` boolean
      - `fee` unknown
      - `how` string
    - `change` object
      - `allowed` boolean
      - `how` string
    - `state` string
    - `text` string
  - `recovery` object: Only on supplier_cancelled. On a job the business called off (supplier_cancelled): job is the booked job (its current version, as searched; send it to search again), alternatives are other businesses for it (within a day of the call-off), worked out on every answer. Never the customer's details.
    - `job` object
    - `alternatives` object[]: Ready alternatives for the same job, worked out on every answer by the same judge as search: up to 3 other times at this business and up to 3 other businesses. An alternative never misses a must-have, never offers a must-not and never adds back a task the customer left out; a nice-to-have it misses is named in why. Each is priced for its own window (its day and hour charges): hold its quote_token with its allocation_id as it is.
      - `kind` 'same_business_other_time' | 'other_business_same_job', required
      - `slug` string, required
      - `display_name` string, required
      - `service_key` string, required
      - `allocation_id` string, uuid, required
      - `window_start` string, date-time, required
      - `window_end` string, date-time, required
      - `job_hours` integer, nullable: How long this job takes on site, in whole hours: hourly services the hours asked (rounded up); other services the booking length plus the business's bigger-homes hours when the home meets its rule. For a business that builds its open times from its working hours (discover capacity.jobs_at_once), every offered time is exactly this long.
      - `job_people` integer, nullable: How many cleaners this job takes: an hourly price's people, the business's usual crew (crew.min), more when the home meets its crew rule (crew.rule), at least 2 for a must-not crew.solo or must-have crew.two_or_more, 3 for crew.three_or_more. Counted against capacity.cleaners. null while the quote is incomplete.
      - `price` object, required
        - `amount` number
        - `currency` string
      - `quote_token` string, required
      - `expires_at` string, date-time, required
      - `booking_authority` object, nullable
      - `why` string[], required: Fixed codes: other_time, other_business, nice_to_have_missed:<word>, needs_owner_approval.
    - `alternatives_note` 'timed_out' | 'none_found': Why alternatives is empty: none fit every must, or they could not be worked out within 4 seconds (the refusal is never delayed for them).
    - `next_step` 'search_again_with_job'
  - `versions` object: The versions this was priced under: the business's passport (what it does), eligibility (where, what homes, hours), pricing, booking authority (1: the owner says yes to every job that needs it) and the word list. Each version's content is kept, so the price can be worked out again.
    - `passport` integer
    - `eligibility` integer
    - `pricing` integer
    - `booking_authority` integer
    - `taxonomy` integer
  - `principal` object: Who this job is for: your agent key, and whether the customer's details are on record (never the details).
    - `agent` string, nullable
    - `customer_on_record` boolean
  - `service_key` string
  - `inputs` object: The job as held: the priced inputs, plus scope (the rooms it covers) when one was stated.
  - `quote_amount` number, nullable
  - `quote_currency` string
  - `capacity_allocation_id` string, uuid, nullable
  - `taxonomy_version` integer, required: The word list version this was made under (GET /api/v1/taxonomy/house_cleaning returns the current one). A job made before reads as 4.

## Other responses

- `default`: Error

---

[API](https://skmtc.dev/commontape/apis/commontape-agent-api.md) · [All operations](https://skmtc.dev/commontape/apis/commontape-agent-api/llms.txt) · [OpenAPI document](https://skmtc.dev/commontape/apis/commontape-agent-api/revisions/714820e6cc4d?raw)
