workwing-io Schedule API
Resource scheduling, availability, and conflicts
Resource scheduling, availability, and conflicts
Every API here is available over the APIs.io API and to AI agents over MCP.
One button, every client — Claude, Cursor, VS Code and the rest.
https://apis.io/mcp
find_apisBrowse and filter every API in the catalog.get_api_artifactsOne API's artifacts, grouped by type.get_openapiThe primary OpenAPI for this API.find_similar_apisAPIs that look like this one.apis_io_searchSTART HERE — APIs, providers and tags for one query, each with its total.resolveTurn a domain, URL or GitHub org into the provider it belongs to.find_cohortsEvery scored population of providers in the catalog.curl "https://apis.io/api/v1/apis/workwing-io:workwing-io-schedule-api"
curl "https://apis.io/api/v1/apis?limit=25"
Discovery needs no key. Ratings and market analysis are Pro.
Free tier, no form to fill in. Signing in shares your email address with us — we store it to create your key and to recognise you if you sign in with another provider. See our Privacy Policy and Terms.
A second provider on the same verified email joins the account you already have.
openapi: 3.2.0
info:
title: WorkWing Schedule API
description: 'REST API for WorkWing field service management. Designed as an **integration point** for CRM, ERP, and dispatch systems. Admin configuration (webhooks, roles, job types, integrations) is managed via the web dashboard. Every resource is documented under its own section in the sidebar. ## Authentication
Send your API key as a bearer token on every request:
```
Authorization: Bearer ww_sk_live_. ```
### Scopes
An API key carries a list of `action:resource` scopes. Every operation publishes the ones it requires as `x-required-scopes`, an array on the operation object; a key must hold all of them, or the wildcard scope `*`, and one that does not is refused with `403 E_AP_1102`. The two operations that declare `security: []` need no key at all: the health check, and the integration callback, which authenticates with the signed token in its own path. ## Querying collections
List endpoints (jobs, customers, resources, and so on) accept query parameters for filtering, sorting, field selection, and pagination:
- `?status=eq.T_PENDING` - filter by exact match
- `?priority=in.(T_HIGH,T_URGENT)` - match any of several values
- `?created_at=gte.2024-01-01` - range comparisons (`gt`, `gte`, `lt`, `lte`)
- `?select=id,status,customer:customers(name)` - choose columns and embed related records. Only the resources listed here, the assignments and users they reference, and the foreign keys between them can be embedded; anything else is refused with `E_AP_6003`
- `?order=created_at.desc` - sort (append `.asc` / `.desc`)
- `?limit=25&offset=50` - paginate (maximum 1000 rows per page)
### Columns not available over the API
Some columns are never returned: `tenant_id` on every resource (a key is bound to one tenant), `internal_notes` on jobs (staff-only; it can be set with `PATCH`, and a job''s note timeline is at `GET /v1/jobs/{jobId}/notes`), and the raw PostGIS geography columns `customers.location`, `locations.location` and `resources.current_location`. Read a position from `latitude`/`longitude` on locations and `current_latitude`/`current_longitude` on resources instead. `select=*`, at the top level or inside an embed, returns every other column. Naming one of these columns in `select`, a filter or `order` is refused with `E_AP_6003`. To read, update or delete one record, address it by id: `GET`, `PATCH` or `DELETE /v1/jobs/{jobId}` (likewise customers, resources and locations). `PATCH` and `DELETE` on a collection change every row matching its filters, e.g. `PATCH /v1/jobs?status=eq.T_PENDING`; they are listed under Workflows. ### Counting and paging
Send `Prefer: count=exact` on a list request to get the total row count back in the `Content-Range` response header (`0-24/312`). `count=planned` and `count=estimated` are cheaper approximations for large tables. ## Idempotency
**Guarantee.** Within 24 hours, a write sent with a given `Idempotency-Key` is applied at most once. If you did not receive a response, retrying with the same key and the same request is always safe. **Core rule.** A key is consumed only when the write is actually applied. The key and the write commit in the same database transaction, so they succeed or fail together. Every write request (`POST`, `PATCH`, `PUT`, `DELETE`) must send an `Idempotency-Key` header. | Situation | Response | Write applied?'
version: 1.0.0
servers:
- url: https://api.workwing.io
description: Production
security:
- bearerAuth: []
tags:
- name: Schedule
description: Resource scheduling, availability, and conflicts
paths:
/v1/resources/{resourceId}/active-assignment:
get:
operationId: getResourceActiveAssignment
summary: Get active assignment
tags:
- Schedule
description: Get the current active assignment (EN_ROUTE or ON_SITE) for a resource. If it has more than one, the most recently updated is returned.
parameters:
- schema:
type: string
format: uuid
in: path
name: resourceId
required: true
security:
- bearerAuth: []
x-required-scopes:
- read:resources
responses:
'200':
description: Default Response
content:
application/json:
schema:
type: object
required:
- data
- meta
properties:
data:
type:
- object
- 'null'
description: Null when the resource is not en route to or on site at a job
required:
- id
- job_id
- resource_id
- status
- assigned_at
- acknowledged_at
- arrived_at
- job_number
- job_status
- customer_name
- scheduled_start
- scheduled_end
properties:
id:
type: string
format: uuid
job_id:
type: string
format: uuid
resource_id:
type: string
format: uuid
status:
type: string
enum:
- T_EN_ROUTE
- T_ON_SITE
assigned_at:
type:
- string
- 'null'
format: date-time
acknowledged_at:
type:
- string
- 'null'
format: date-time
arrived_at:
type:
- string
- 'null'
format: date-time
job_number:
type:
- string
- 'null'
job_status:
type: string
customer_name:
type:
- string
- 'null'
scheduled_start:
type:
- string
- 'null'
format: date-time
scheduled_end:
type:
- string
- 'null'
format: date-time
meta:
type: object
required:
- request_id
- timestamp
properties:
request_id:
type: string
timestamp:
type: string
format: date-time
/v1/resources/{resourceId}/assignments:
get:
operationId: listResourceAssignments
summary: Get resource assignments
tags:
- Schedule
description: Get all job assignments for a specific resource with job details
parameters:
- schema:
type: string
enum:
- T_ASSIGNED
- T_ACKNOWLEDGED
- T_EN_ROUTE
- T_ON_SITE
- T_COMPLETED
in: query
name: status
required: false
- schema:
type: integer
minimum: 1
maximum: 100
default: 50
in: query
name: limit
required: false
- schema:
type: integer
minimum: 0
default: 0
in: query
name: offset
required: false
- schema:
type: string
format: uuid
in: path
name: resourceId
required: true
security:
- bearerAuth: []
x-required-scopes:
- read:resources
responses:
'200':
description: Default Response
content:
application/json:
schema:
type: object
required:
- data
- meta
properties:
data:
type: array
items:
type: object
required:
- id
- job_id
- resource_id
- status
- assigned_at
- acknowledged_at
- arrived_at
- assigned_by
- created_at
- updated_at
- job_number
- job_status
- job_priority
- customer_name
properties:
id:
type: string
format: uuid
job_id:
type: string
format: uuid
resource_id:
type: string
format: uuid
status:
type: string
description: The assignment's own status, e.g. T_ASSIGNED or T_ON_SITE
assigned_at:
type:
- string
- 'null'
format: date-time
acknowledged_at:
type:
- string
- 'null'
format: date-time
arrived_at:
type:
- string
- 'null'
format: date-time
assigned_by:
type:
- string
- 'null'
format: uuid
description: The user who made the assignment
created_at:
type: string
format: date-time
updated_at:
type: string
format: date-time
job_number:
type:
- string
- 'null'
job_status:
type: string
job_priority:
type:
- string
- 'null'
customer_name:
type:
- string
- 'null'
meta:
type: object
required:
- request_id
- timestamp
properties:
request_id:
type: string
timestamp:
type: string
format: date-time
/v1/resources/{resourceId}/availability:
get:
operationId: getResourceAvailability
summary: Check resource availability
tags:
- Schedule
description: Check a resource's availability for a given date. Returns assignments for the day and an is_available flag.
parameters:
- schema:
type: string
format: date
in: query
name: date
required: true
description: Date in YYYY-MM-DD format
- schema:
type: string
in: query
name: timezone
required: false
description: IANA timezone name the day bounds are computed in (e.g. 'Europe/London'). Defaults to UTC; an invalid value falls back to UTC.
- schema:
type: string
format: uuid
in: path
name: resourceId
required: true
security:
- bearerAuth: []
x-required-scopes:
- read:resources
responses:
'200':
description: Default Response
content:
application/json:
schema:
type: object
required:
- data
- meta
properties:
data:
type: object
required:
- resource_id
- date
- is_available
- assignments
properties:
resource_id:
type: string
format: uuid
date:
type: string
format: date
description: The date asked about
is_available:
type: boolean
description: True when the resource has no unfinished job on that day
assignments:
type: array
description: The resource's unfinished jobs overlapping that day
items:
type: object
required:
- job_id
- job_number
- scheduled_start
- scheduled_end
properties:
job_id:
type: string
format: uuid
job_number:
type:
- string
- 'null'
scheduled_start:
type: string
format: date-time
scheduled_end:
type: string
format: date-time
meta:
type: object
required:
- request_id
- timestamp
properties:
request_id:
type: string
timestamp:
type: string
format: date-time
/v1/schedule/conflicts:
get:
operationId: listScheduleConflicts
summary: Check schedule conflicts
tags:
- Schedule
description: Find overlapping job assignments for a resource in a given time range
parameters:
- schema:
type: string
format: uuid
in: query
name: resource_id
required: true
- schema:
type: string
format: date-time
in: query
name: start_time
required: true
- schema:
type: string
format: date-time
in: query
name: end_time
required: true
- schema:
type: string
format: uuid
in: query
name: exclude_job_id
required: false
security:
- bearerAuth: []
x-required-scopes:
- read:jobs
responses:
'200':
description: Default Response
content:
application/json:
schema:
type: object
required:
- data
- meta
properties:
data:
type: array
items:
type: object
required:
- job_id
- job_number
- scheduled_start
- scheduled_end
- resource_id
- resource_name
properties:
job_id:
type: string
format: uuid
job_number:
type:
- string
- 'null'
scheduled_start:
type: string
format: date-time
scheduled_end:
type: string
format: date-time
resource_id:
type: string
format: uuid
resource_name:
type:
- string
- 'null'
description: The name of the user behind the resource
meta:
type: object
required:
- request_id
- timestamp
- has_conflicts
properties:
request_id:
type: string
timestamp:
type: string
format: date-time
has_conflicts:
type: boolean
components:
securitySchemes:
bearerAuth:
type: http
scheme: bearer
bearerFormat: API Key
description: 'Use your WorkWing API key (format: `ww_sk_live_<tokenId>.<secret>`). The scopes an operation requires are published on it as `x-required-scopes`.'