API referenceJobs

Jobs

Create, schedule, and update jobs using the Zoop MCP tool catalog.

A job is the core unit of work in Zoop — a visit, task, or project you perform for a customer. This page covers the five API tools that let you list, fetch, create, update, and cancel jobs.

Jobs move through four statuses: unscheduledscheduleddone (or cancelled at any point). See the status machine section for the full rules.

Required scopes

Every API call in Zoop needs a scope — a permission that says what the token is allowed to do. You set scopes when you create an API key or start an OAuth flow.

OperationScope needed
Read jobsread:jobs
Create, update, or cancel jobswrite:jobs

write:jobs does not imply read:jobs. Grant both if your integration needs to read and write jobs. See Scopes for the full scope catalog.

User actor requirement

Some tools require a user actor — a token that is tied to a specific Zoop user (either an OAuth access token or a user-bound API key). This is different from a tenant key (prefix zoop_tk_), which belongs to the account as a whole and has no user identity attached.

jobs.create, jobs.update, and jobs.cancel require a user actor. If you call them with a tenant key, you will get an invalid_input error. See API keys to understand the difference and pick the right token type.


Tools

jobs.list

Returns one page of jobs for the tenant. Results are sorted by scheduled_start ascending (jobs with no start time come last), then by created_at descending. Each page holds up to 20 jobs.

Scope: read:jobs

query
status

Filter by status. One of unscheduled, scheduled, done, or cancelled.

query
customerId

Return only jobs for this customer.

query
seriesId

Return only jobs that belong to this recurring series.

query
from

Return jobs whose scheduled_start is at or after this timestamp.

query
to

Return jobs whose scheduled_start is at or before this timestamp.

query
q

Case-insensitive substring match against the job title.

query
page

1-based page number.

Response fields:

data

Array of job summary objects. Each row includes id, title, status, scheduled_start, scheduled_end, customer_id, series_id, flat_price, a nested customer object (id, display_name), and a nested assignments array (user_id).

count

Total number of jobs matching the filters (across all pages).

page

The current page number.

limit

The page size (always 20).


jobs.get

Fetches the full record for a single job by its ID. The response includes line items, team assignments, and up to 50 media previews (photos and videos attached to the job).

Scope: read:jobs

body
id

The job ID.

Returns a not_found error if the job ID does not exist in this tenant.

Response fields:

id
UUID.
tenant_id
The tenant this job belongs to.
customer_id
The linked customer, or null.
series_id
The recurring series this job belongs to, or null for one-off jobs.
quote_id
The source quote, if the job was created from one.
title
Job title.
description
Optional long-form description.
flat_price
A fixed price override. When set, this amount replaces the sum of line items for billing — useful when you want to charge a flat rate regardless of what's on the job.
status
One of unscheduled, scheduled, done, cancelled.
scheduled_start
ISO 8601 datetime. Null for unscheduled jobs.
scheduled_end
ISO 8601 datetime. Optional end time.
completed_at
ISO 8601 datetime. Stamped automatically when status is set to done.
created_by
User ID of the creator.
created_at
ISO 8601 datetime.
updated_at
ISO 8601 datetime.
job_line_items

Line items. Each has id, catalog_item_id (UUID or null), description, unit_price, quantity, total, and sort_order.

job_assignments

Users assigned to the job. Each has user_id, assigned_by, and assigned_at.

job_media

Up to 50 media previews. Each has id, job_id, storage_path, kind (photo or video), filename, size_bytes, caption, uploaded_by, and uploaded_at.

customer

Thin customer summary: id and display_name.


jobs.create

Creates a new job. Requires a user actor (see user actor requirement above).

Scope: write:jobs

body
title

Job title. 1–200 characters.

body
customer_id

Link the job to a customer. Omit or pass null to leave it unlinked.

body
description

Optional notes or work description. Max 5,000 characters.

body
flat_price

Optional flat price override. Must be zero or greater. When set, this replaces the sum of line items for billing.

body
scheduled_start

When the job starts. Providing this automatically sets status to scheduled. Omitting it leaves the job unscheduled. Use ISO 8601 format, for example 2026-06-16T09:00:00Z.

body
scheduled_end

Optional end time. Has no effect on status.

body
line_items

Line items to attach. Each object must include:

  • description (string, 1–500 characters)
  • unit_price (number, non-negative)
  • quantity (number, positive)
  • catalog_item_id (UUID, optional — link to a pricebook item)
  • sort_order (integer, optional — defaults to array index)
body
assigned_user_ids

Team members to assign to this job. Every ID must belong to your tenant — if even one ID is invalid, the entire request fails with invalid_input.

Returns the newly created job row. The shape matches jobs.get, except the nested job_line_items, job_assignments, and job_media arrays are not included.


jobs.update

Partially updates a job. Only the fields you send are changed — you do not need to resend the whole record. Requires a user actor (see user actor requirement above).

Scope: write:jobs

body
id

The job to update.

body
title

New title. 1–200 characters.

body
customer_id

Change or unlink the customer.

body
description

Updated description. Max 5,000 characters.

body
flat_price

Updated flat price. Pass null to clear it.

body
status

Explicit status change. One of unscheduled, scheduled, done, or cancelled. Setting done stamps completed_at with the current time. Setting any other status clears completed_at.

body
scheduled_start

Update or clear the start time. You do not need to set status separately — Zoop derives it for you: an unscheduled job that gets a start time becomes scheduled; a scheduled job whose start time is cleared becomes unscheduled. Jobs already in done or cancelled are not affected by this auto-derive.

body
scheduled_end

Update or clear the end time.

body
line_items

When supplied, replaces the entire line-item list. Same shape as jobs.create. Omit this field to leave existing line items untouched — there is no way to edit a single line item in isolation.

body
assigned_user_ids

When supplied, replaces the entire assignment list. Omit this field to leave existing assignments untouched.

Returns the updated job row.


jobs.cancel

Cancels a job by setting its status to cancelled. The job record is preserved in full — history, line items, and assignments all stay intact. Requires a user actor (see user actor requirement above).

Scope: write:jobs

body
id

The job to cancel.

Cancellation is not permanent — but it is one-way via this tool. To reopen a cancelled job, call jobs.update with status="unscheduled" or status="scheduled".

Returns the updated job row with status: "cancelled".


Example: create a scheduled job

This example creates a job for a customer and assigns it to a team member. Replace the UUIDs with real IDs from your tenant — you can get a customer ID from customers.list and a user ID from your Zoop account settings.

curl -X POST https://app.zoop.example/api/mcp \
  -H "Authorization: Bearer YOUR_ACCESS_TOKEN" \
  -H "Content-Type: application/json" \
  -d '{
    "jsonrpc": "2.0",
    "id": 1,
    "method": "tools/call",
    "params": {
      "name": "jobs.create",
      "arguments": {
        "title": "Replace kitchen faucet",
        "customer_id": "a1b2c3d4-e5f6-7890-abcd-ef1234567890",
        "description": "Customer reported dripping cold side. Bring 1/2-inch compression fittings.",
        "scheduled_start": "2026-06-16T09:00:00Z",
        "scheduled_end": "2026-06-16T11:00:00Z",
        "assigned_user_ids": ["f9e8d7c6-b5a4-3210-fedc-ba9876543210"],
        "line_items": [
          {
            "description": "Labor — faucet replacement",
            "unit_price": 95.00,
            "quantity": 2
          },
          {
            "description": "Kitchen faucet (customer-supplied)",
            "unit_price": 0,
            "quantity": 1
          }
        ]
      }
    }
  }'

What happens:

Status is derived automatically

Because scheduled_start is set, Zoop sets status to scheduled. You do not need to pass status explicitly.

Assignments are validated

Each user_id in assigned_user_ids is checked against the tenant's membership list. A single invalid ID fails the entire request with invalid_input.

Job row is returned

The response contains the persisted job row, including the server-assigned id and created_at.


Status machine

Jobs move through four statuses. Zoop sets status for you in many cases — you rarely need to set it explicitly.

StatusMeaning
unscheduledCreated without a start time, or the start time was cleared.
scheduledHas a scheduled_start. Set automatically when you provide a start time.
doneWork complete. completed_at is stamped the moment you set this status.
cancelledSet via jobs.cancel or by passing status="cancelled" to jobs.update.

Neither done nor cancelled locks the job permanently. You can reopen a done or cancelled job by patching status back to scheduled or unscheduled.


Error reference

Error kindCommon causeWhat to do
invalid_inputMissing title, a non-UUID value in assigned_user_ids, an assigned user who is not a member of your tenant, or a tenant-key token used on a write tool.Check the fields in the error message. Confirm user IDs belong to your tenant. If you are using a zoop_tk_ token, switch to a user-bound token.
not_foundThe job ID does not exist in this tenant.Verify the ID with jobs.list or check that you are using the right tenant's credentials.
insufficient_scopeThe token is missing read:jobs or write:jobs.Re-issue the token with the required scopes. See Scopes.

See Errors for the full error shape and HTTP status codes.


  • Job series — create and manage recurring job templates.
  • Invoices — turn a completed job into an invoice.
  • Quotes — jobs can be created from approved quotes.
  • Catalog items — link line items to your pricebook.
  • Scopes — full scope catalog and token requirements.