Skip to Content
Developer APIScheduler API & AI access

Scheduler API & AI access

Interactive API reference — every endpoint, every field, and a “try it” console, generated from the live contract:   Scheduler →   Payments →   Platform →

Connect your own tools, scripts, and AI assistants to BayWise Scheduler. The API lets external systems — your DMS, ERP, or custom workflows — create and track jobs, manage workshop resources, and read operations back, and lets AI assistants answer questions about your workshop.

What the Scheduler API is — and when to use it

BayWise Scheduler runs the operational side of a workshop: the vehicles in for work, the tasks on each one, and the people and bays doing the work. The API exposes that so other systems can drive it or read from it.

The real problem: one vehicle’s work, scattered across systems and people

Just like the money, a single repair’s work is spread across systems that each hold only a fragment — and the one thing nobody has is a live picture of where the car actually is right now:

SystemWhat it knows about this repairExample fields it holds
DMS / GMSThe vehicle is booked and what was requestedroNumber: RO-4821, vin: MA3…7K, requested: [brakes, oil], promisedFor: 17:00
HR / time-trackingWho’s on shift today and what they can doemployeeId: E-12, name: Ravi, skills: [brakes, suspension], clockIn: 08:55
FacilitiesThe bays and their equipmentbayId: B-2, hasLift: true
Parts systemWhat’s on order or holding the job uppartRef: PA-77, status: backorder
The workshop floorWho’s actually doing what, this minuteusually a whiteboard or someone’s memory

The DMS knows it was booked; HR knows who’s in; parts knows what’s pending — but no single system can answer “where is this car right now, who’s working on it, and will it be ready by 5?” That live operational truth is the fragment that usually lives on a whiteboard.

How the API turns the fragments into one live picture

You sync the static fragments once, then drive the live ones through one job (the vehicle’s visit):

  1. Sync resources — push technicians (with skills), bays, and the service catalog from your systems, idempotent on your externalKey so re-syncing never duplicates.
  2. Create the job — for RO-4821 / VIN MA3…7K, with the promise time.
  3. Add steps — the tasks: Diagnose brakes → Replace pads → Oil change → QC — each one assignable, sequential or parallel.
  4. Assign and schedule — put Ravi + Bay 2 on the brake steps; whoever’s free on the oil change.
  5. Track — move each step pending → in_progress → completed; the job’s derived status always reflects the active step, so the board is live.
  6. Deliver — mark the job delivered when the car leaves.
  7. Across locations — a group drives and reads every site through the same API, scoped by location.

What that gives you back

Because every fragment now hangs off one job, reading jobs and their steps answers the questions the underlying systems can’t — no separate reporting system required:

  • A live job board — where every vehicle is, who’s on it, and what’s next.
  • On-time tracking — promise time vs actual progress, so you see slippage early.
  • Resource picture — which technicians and bays are busy, plus attendance for who’s actually in.

Use the API to:

  • Read technicians, bays, and your service catalog — sync your own system’s picture of what BayWise has (creating and deleting these is done in the app, so history like attendance and past jobs is never orphaned).
  • Automate jobs — create jobs and their steps from another system, track them through to delivery, or cancel them with a governed reason.
  • Build a live board / dashboards — read jobs (including the same rich detail the in-app board shows), a location’s live occupancy summary, and attendance for real-time operational views.
  • Record attendance — clock technicians in and out from third-party time-tracking tooling.
  • Update a bay’s status — put it into or out of maintenance from a facilities system.
  • Ask an AI assistant (Claude, Cursor, and others) about your workshop — read-only.

Day-close is app-only. Closing the day is a guided, in-app workflow (freeze, carry-overs, per-job questions) that doesn’t map to a single API call — there’s no POST for it. While a location’s day is mid-close, job and step writes through the API are blocked the same way they are in the app; reads, attendance, and bay-status updates are unaffected.

If you only need one sentence: use this API to pull the scattered facts about each vehicle’s work — booking, people, bays, parts, progress — into one live picture: where every car is, who’s on it, and whether it’ll be ready on time, per location or across the group.

Core concepts

(For the business background, see the in-product concept guides on The Job, The Technician, and The Bay.)

ConceptWhat it means
JobOne vehicle’s visit to the workshop. Carries vehicle details (plate, make, model…), a priority, and a status.
StepA task within a job (e.g. “diagnose”, “replace brake pads”). Each step has its own status and can be assigned to technicians and a bay.
TechnicianA person who does the work — with skills, availability, and a work-in-progress limit.
BayA physical service bay, with its equipment and what services it can handle.
Catalog itemA standard service in your menu, identified by a stable service code.
AttendanceTechnician clock-in / clock-out, recorded in the workshop’s local time.
Day closeThe end-of-day record for a location — a guided in-app workflow, not available via the API (see above).

Technicians, bays, and the catalog are created and removed in the app only — the API reads them and, for technicians and bays, updates their operational status. This keeps a technician’s attendance history or a bay’s job history from ever being orphaned by an API-side delete. Catalog items can be created/updated via the API — see the sync pattern below.

Getting a key

  1. In BayWise, open Settings → Developer.
  2. Choose the permissions the key should have (you can only grant what your own role allows).
  3. Optionally scope the key to a single location and set an expiry.
  4. Click Create API key. The full key is shown once — copy and store it safely.

Who can do this: Account Owners and Org Admins (anyone with developer access). On the free plan, API access is an upgrade.

Using the API

Send your key as a bearer token (Authorization: Bearer …) to the BayWise API base URL. The full request/response details, every field, and a “try it” console are in the Scheduler API reference ; a ready-to-import Postman collection is linked from the Developer tab.

A few rules worth knowing up front:

  • Retries are safe. Send an idempotency key when creating — repeating the same key never double-records.
  • No silent overwrites. Updates require the record’s current last-updated time, so two systems can’t clobber each other’s changes (you’ll get a conflict if you’re out of date).
  • Lists are paginated. Job lists return a cursor; pass it back to get the next page.
  • Times are workshop-local. Attendance uses the location’s local time, not your server’s.
  • Every response has a request id you can quote to support.

The sync pattern (DMS → BayWise)

For jobs, send a create with your own externalKey (e.g. the RO number) on every sync. The endpoint is idempotent on that key: the first call creates the job, and later calls with the same key return the existing one instead of duplicating — so you can safely re-POST the same RO every time your system polls, without tracking BayWise’s own ID.

Example — sync a repair order:

POST /v1/scheduler/jobs Authorization: Bearer bw_live_… Idempotency-Key: dms-ro-4821 Content-Type: application/json { "locationId": "loc-uuid", "externalKey": "RO-4821", "vehiclePlate": "ABC 123", "vehicleMake": "Toyota", "vehicleModel": "Camry", "promiseTime": "2026-06-28T17:00:00+04:00" }

First call → 201 Created (new job). Every subsequent call with the same externalKey → 200 with the same job. Nothing duplicates — this is what lets a key rotation or a re-run of your sync job stay safe.

Technicians and bays are managed in the app; the API only reads them and updates operational status:

PATCH /v1/scheduler/bays/{bayId} Authorization: Bearer bw_live_… Content-Type: application/json { "updatedAt": "2026-06-28T09:00:00Z", "status": "maintenance" }

A typical flow

1. Sync resources — push technicians, bays, and catalog from your DMS (once on startup, then incrementally).

2. Create a job:

POST /v1/scheduler/jobs Idempotency-Key: dms-ro-4821 { "locationId": "loc-uuid", "vehiclePlate": "ABC 123", "vehicleMake": "Toyota", "vehicleModel": "Camry", "promiseTime": "2026-06-28T17:00:00+04:00", "priority": "normal", "source": "phone", "arrivalTime": null }

RO numbers

Every job carries a jobNumber — the repair order’s human-readable identity, and what shop staff read off the board. Omit it and BayWise assigns the location’s next number (RO-2026-0143, sequential per location per year), so an RO is never left unidentified. Send your own to keep your numbering:

POST /v1/scheduler/jobs { "locationId": "loc-uuid", "vehiclePlate": "ABC 123", "jobNumber": "INV-8821" }

Numbers must be unique within a location — a clash returns 422 with field: "jobNumber", not a server error. PATCH can re-number an RO but cannot blank it: an RO always keeps an identity.

jobNumber is not externalKey. They solve different problems and you will usually want both:

jobNumberexternalKey
What it isThe RO’s number, shown to shop staffYour system’s own id for the RO
Who sees itAdvisors and technicians, on the boardNobody — it is a lookup handle
UniquenessPer locationPer your integration
If you re-send itNothing special — it is just a fieldThe same job is returned, never a duplicate

Arrival time — omit vs. null

arrivalTime records when the vehicle physically arrived at the workshop — a fact, never a plan. It is the one field on this endpoint where leaving it out and sending null mean different things:

  • Omit the field (walk-in): the server stamps its own current time as the arrival. This is the right call when the car is in front of you.
  • Send arrivalTime: null (pre-booking, as in the example above): no arrival is recorded. Use this when creating tomorrow’s booking tonight — the car isn’t there, and recording an arrival would mark it present.
  • Send a value: it is validated — an arrival in the future is rejected with a 422 (a few minutes of clock skew are tolerated).

When the pre-booked car actually arrives, record it with a PATCH:

PATCH /v1/scheduler/jobs/{jobId} { "arrivalTime": "2026-06-28T09:40:00+04:00", "updatedAt": "<last read>" }

⚠️ Do not re-send the create. If you created the job with an externalKey, re-POSTing the same key returns the existing job unchanged — the arrival in your second create is silently ignored (the call still returns 200, so it looks like it worked). The PATCH above is the only channel that records a later arrival for a deduped job.

On PATCH, the same three-way rule applies: omitting arrivalTime leaves it untouched, null clears a mistakenly-recorded arrival, and a value sets it.

3. Add steps:

POST /v1/scheduler/jobs/{jobId}/steps { "label": "Diagnose brakes", "phase": 1, "schedulingMode": "sequential", "estimatedDuration": 1800 }

4. Assign and trackPATCH /v1/scheduler/jobs/{jobId}/steps/{stepId} to set techIds, bayId, and update status (pending → in_progress → completed). Each update requires the step’s current updatedAt for concurrency safety.

5. Deliver:

POST /v1/scheduler/jobs/{jobId}/deliver

Idempotent — an already-delivered job returns its current state unchanged.

6. React in real time — instead of polling, subscribe to webhooks (job/step events) — see below.

Cancelling a job

Cancellation requires a reason from the location’s own governed list — fetch it first, then cancel:

GET /v1/scheduler/cancel-reason-tags?locationId=loc-uuid
POST /v1/scheduler/jobs/{jobId}/cancel Content-Type: application/json { "reasonTags": ["customer_declined"] }

The exact tags vary by location — this example uses a common platform default, but always resolve it from the GET call above rather than hard-coding it. An unrecognized tag is rejected with a clear error rather than silently dropped. Cancelling an already-cancelled job is idempotent — it returns the existing state.

Rich job detail and the live board

GET /v1/scheduler/jobs/{jobId} returns the job and its steps. For the same level of detail the in-app board shows for one job — planned vs actual time windows, hold/delay history, verification — use:

GET /v1/scheduler/jobs/{jobId}/detail

This also works for delivered and cancelled jobs, so it doubles as a vehicle-history lookup.

For a location-level snapshot — job counts by state and bay occupancy — use:

GET /v1/scheduler/board?locationId=loc-uuid

Workshop settings

Read the workshop configuration (operating hours, break times, bay buffer) for a location:

GET /v1/scheduler/workshop Authorization: Bearer bw_live_…

A location-scoped key returns a single object. An org-scoped key returns { "data": [...] } with one entry per location. Workshop settings are read-only via the API — edit them in Settings → Workshop in the app.

Webhooks

Subscribe to job and step events so your systems react in real time instead of polling — see Webhooks for the full event list, payload shape, and signature verification.

Current events: job.created, job.updated, job.delivered, job.cancelled, step.created, step.updated, step.completed, bay.status_changed, tech.clocked_in, tech.clocked_out.

Connecting an AI assistant (MCP)

From Settings → Developer → Connect via MCP, generate a token and copy the config into your AI client (for example, Claude Desktop → Settings → Developer → Edit Config). The assistant then acts as you and can only do what your role permits — in this version, AI access is read-only (it can answer questions about your workshop, not change it).

What the AI can read via MCP:

ToolWhat it answers
List / get jobs”Which cars are in the workshop right now?” / “What’s the status of RO-4821?”
Get job detail”What’s the full history on this job?” — planned vs actual, holds, verification; works for delivered/cancelled jobs too
Get board summary”What does the floor look like right now?” — job counts by state, bay occupancy
List cancel-reason tags”What are the valid reasons to cancel a job at this location?”
List technicians”Who’s on the roster?”
List bays”What bays do we have and what can each one handle?”
List catalog”What services are in our catalog?”
Get workshop settings”What are our operating hours?”
List attendance”Who clocked in today?”

The AI is read-only by design — it cannot create jobs, update steps, cancel a job, clock technicians in or out, or change a bay’s status. All of that requires a human using the app or a system calling the REST API directly.

Need help?

Quote the request id from any response when contacting support. Keys can be revoked any time from the Developer tab — a revoked key stops working immediately.