Skip to main content

Workforce Management API

Plan and run a contact-center workforce: forecast volume, optimize staffing across every channel, generate and edit schedules, let agents bid on open shifts, route time-off and swap requests, and measure schedule adherence in real time. Base path: /api/v1/wfm Authentication: API key (X-API-Key) or session JWT. Roles: read endpoints are available to the owner, admin, developer, and viewer roles. Management write endpoints — publishing and cancelling open shifts, overtime offers, or VTO offers, awarding a bid or an overtime/VTO offer, approving or denying requests, and recomputing forecasts or shrinkage — require the owner or admin role. Agent self-serve write actions are available to all four roles, since agents act on their own records: submitting a time-off, shift-swap, or preference request (POST /wfm/requests), accepting a shift-swap as the counterparty (POST /wfm/requests/{id}/accept-swap), placing or withdrawing a bid on an open shift (POST /wfm/open-shifts/{id}/bids, POST /wfm/open-shifts/{id}/bids/{bidId}/withdraw), and claiming or withdrawing a claim on an overtime or VTO offer (POST /wfm/overtime-offers/{id}/claims, POST /wfm/overtime-offers/{id}/claims/{claimId}/withdraw, POST /wfm/vto-offers/{id}/claims, POST /wfm/vto-offers/{id}/claims/{claimId}/withdraw). These actions are scoped by agent_id, so a caller can only act on their own request, bid, or claim regardless of role. All data is scoped to the calling tenant. Validation failures return 422 with a VALIDATION_ERROR body; see Error codes.

Using the SDKs

Python (same call via the SDK’s escape hatch):
The Python SDK is core-scope — it wraps the 8 core resources (messaging, voice, contacts, campaigns, verify, numbers) and reaches everything else through the generic client.request() escape hatch above. See the Python SDK. Returns the typed ApiResponse envelope. See the SDK index at SDK quickstart.

Overview summary

Load the whole scheduling overview in one request: forecast coverage, rostered staffing, live adherence, pending requests, open shifts, unfilled overtime/VTO offers, and pending adherence exceptions for the operating day. Counts follow the same role scoping as the underlying list endpoints — non-managers see their own queue counts. Pass ?date=YYYY-MM-DD to override the operating date; omit it and the response resolves the tenant’s local operating day — the same resolution the intraday staffing and adherence panels use, so every surface agrees on which calendar day it shows. Forecast and staffing blocks are null when no forecast rows or roster exist for that day.

Forecasts

Project contact volume and average handle time, run what-if scenarios, and score past forecasts against actuals.

Staffing optimizer

Turn per-channel demand into a cross-channel staffing plan, and see the headcount you save by blending channels into shared agent pools instead of dedicating agents to one channel each. Give it per-channel demand — arrival_rate_per_second, expected_aht_seconds, concurrency (how many contacts one agent handles at once), and an optional service_level_target / service_level_target_seconds — or omit those and it reads the latest stored forecast for each channel (pass interval_start to target a specific interval). Define blended pools with pools; omit them and every channel forms one blended pool. The response returns two views — channels (the agents each channel needs on its own) and pools (the agents needed when channels share a pool, with each pool’s combined demand solved together and per-channel concurrency factored in) — plus dedicated_agents_total, blended_agents_total, agents_saved, and pooling_efficiency_pct. Each pool honours the strictest service-level target among its channels, so blending never quietly relaxes an SLA. This is a read-style compute endpoint available to the owner, admin, developer, and viewer roles; it persists nothing.

Shifts

Manage the individual shift definitions that schedules are built from.

Schedule generation

Generate a draft schedule from a forecast and staffing rules, then commit it once you have reviewed the preview.

Assignments

Assign agents to shifts and adjust a published schedule.

Open shifts

Publish unassigned shifts for agents to bid on, then award them.

Overtime offers

Publish extra capacity on an already-scheduled shift to a pool of eligible agents, let them self-serve claim it, and award it — the same publish/claim/award pattern as open shifts, but staffing up agents who are already working that day instead of filling an unassigned shift.

VTO offers

Publish voluntary time-off (early release / unpaid time off) on an already-scheduled shift to a pool of eligible agents, let them self-serve claim it, and award it — the surplus-direction mirror of overtime offers: instead of staffing up agents who are already working, an award releases the winning agents’ existing schedule assignment for that shift and date.

Requests

Handle agent time-off, shift-swap, and preference requests through an approval workflow.

Agent skills

Maintain the per-agent skill registry that schedule generation matches against each shift’s required_skills list — an agent is only proposed for a generated assignment when their registry skills cover the shift’s requirements. On the dashboard this registry is the Skills tab under Voice → Scheduling; here is the API surface behind it. Skills are free-form tenant-defined text (up to 64 characters, the same bound as a shift’s required_skills entries) and proficiency runs from 1 (novice) to 5 (expert). The write endpoints are owner/admin; reads are available to all roles. Because the upsert is keyed on the composite (agent_id, skill) pair, re-rating an agent’s proficiency is a single PUT — no read-then-write race.

Adherence

Measure how closely agents follow their scheduled activities, per agent, per team, and intraday.

Adherence exceptions

Record and review exceptions that should not count against an agent’s adherence.

Real-time adherence

Stream live adherence events and read current breaches.

Shrinkage

Compute and read shrinkage (the share of paid time agents are not handling contacts).

Timekeeping (timesheets & payroll)

Worked-hours read model derived from the adherence-event log: one row per (agent, operating date) classifying worked seconds into regular vs overtime and paid vs unpaid break, with the first clock-in and last clock-out timestamps. The export is a pay-period CSV feed you can hand to your payroll system. Operating dates resolve in the requested IANA timezone (?timezone=, default UTC).
GET /wfm/timesheets follows the standard read policy — any non-elevated seat is scoped to its own row only. The payroll export is a bulk egress and is restricted to the owner and admin roles; other callers receive 403 INSUFFICIENT_PERMISSIONS. When the row cap truncates a response the truncated flag (JSON) or X-Export-Truncated header (CSV) is set.

Agent insights

Surface wellness and attrition signals to support staffing decisions.
GET /wfm/agent-flight-risk is an exception to the read policy above: it is restricted to the owner and admin roles. A developer or viewer caller receives 403 INSUFFICIENT_PERMISSIONS. GET /wfm/agent-wellness follows the standard read policy and is available to all four roles.

Worked examples

Five curl + response pairs trace one operator flow end to end: size staffing, test a scenario, generate and publish a schedule, fill a gap with an open shift, and clear the resulting time-off request. All calls below assume ORBIT_API_KEY holds a tenant API key.

1. Staffing: optimize across channels

Send explicit per-channel demand — voice and chat — and define one blended pool. The arrival_rate_per_second you pass is contacts per second, so divide your interval volume by the interval length in seconds (for example, 90 voice contacts in a 30-minute interval ÷ 1800 s).
200:
Read the totals this way: run voice and chat as dedicated queues and you need 19 agents; blend them into one shared pool and you need 17 — the blend saves two heads (10.5%). 422: omit channels and pass no stored forecast — or send a non-positive expected_aht_seconds — and the optimizer returns 422 VALIDATION_ERROR when it cannot derive demand.

2. Forecasts: what-if sizing

Size a scenario without persisting it. Pass an explicit arrival_rate_per_second, or omit it and the endpoint reads the most recent forecast for that channel.
200:
422: channel, scheduled_agents, and expected_aht_seconds are required; a missing field or a non-positive expected_aht_seconds returns 422 VALIDATION_ERROR with per-field details.

3. Schedules: generate a draft, then commit it

Generate builds a draft from stored forecasts, shift templates, and agent skills. It persists nothing — review the preview, then commit the assignments you keep.
200 (two entries from a much longer assignments/coverage list omitted with ...):
If summary.eligible_supply_exhausted is true, the generator ran out of agents who carry the required skills — a commit cannot cover what the draft could not propose. Then commit the assignments you keep (commit respects the preview — pass back whichever of the generated assignments you accept):
201:
skipped > 0 means an assignment already existed for that agent/shift/date — commit is idempotent, never duplicating an existing booking. 422: from_date after to_date returns 422 INVALID_RANGE; a span over 35 days returns 422 RANGE_TOO_LARGE; an unknown shift_id at commit time returns 422 SHIFT_NOT_FOUND.

4. Open shifts: publish, bid, award

When coverage gaps appear, publish a shift as open instead of assigning it directly. Agents bid; the award strategy ranks the bids and the award call writes real assignments. Publish (owner/admin):
201:
Bid (agent self-serve; only owner/admin may set agent_id to bid on someone else’s behalf):
201:
Award (owner/admin — a posting with an automatic strategy like seniority, preference, or first_come can be awarded with no body; manual requires agent_ids, and passing agent_ids overrides automatic ranking either way):
200:
On award, one scheduled assignment is written per winner, winning bids flip to awarded, and every other submitted bid is rejected. 422: an unknown shift_id at publish returns 404 NOT_FOUND; a manual award with no agent_ids returns 422 AGENTS_REQUIRED; an award naming agents with no submitted bid returns 409 NO_MATCHING_BID.

5. Requests: submit time off, then approve it

Agents submit time-off requests themselves; an owner or admin approves or denies them. Submit (all roles; an agent caller’s agent_id must equal their own id):
201: the created request row:
Approve (owner/admin):
200:
For a time_off request, approval also books leave and excludes the window from adherence scoring; schedule generation treats approved time off as a hard constraint. 422: ends_at at or before starts_at returns 422 VALIDATION_ERROR; a shift_swap approved before the counterparty accepts via POST /wfm/requests/{id}/accept-swap returns 409.

6. Forecasts: recompute and score accuracy

Recompute refreshes forecast rows from the last 90 days of inbound traffic for one channel — or for every channel when you omit channel — and is the only forecast write endpoint (owner/admin). It is synchronous with a server-side wall-clock ceiling: when the ceiling trips mid-batch the response is still a 200 with partial: true, so inspect partial / outcome before treating the pass as complete.
200:
Then score how those forecasts performed against realised volume:
200:
Accuracy is 1 - MAPE computed per interval against inbound volume from messages and call_logs; ape is null when both predicted and actual volume were zero. 422: a days value outside 1–90 returns 422 VALIDATION_ERROR.

7. Overtime offers: publish, claim, award

An overtime offer fills extra capacity on an already-scheduled shift. Publish targets a pool of eligible_agent_ids — at least one is required, and only those agents may claim it. Publish (owner/admin):
201:
Claim (agent self-serve — the response echoes the caller’s own agent_id, and a non-manager passing somebody else’s agent_id gets 403 FORBIDDEN):
201:
Award (owner/admin — same ranking rules as open shifts):
200:
An award writes one schedule assignment per winner, which the adherence scoring picks up automatically. 422: an empty eligible_agent_ids array returns 422 VALIDATION_ERROR; awarding on a cancelled offer or with no claims returns 409.

8. VTO offers: publish, claim, award

A VTO (voluntary time-off) offer is the mirror of an overtime offer: publish a surplus on a shift, let already-scheduled agents claim release, and award releases the winners’ existing assignment for that shift and date. Same role gates — publish and award are owner/admin; claims are agent self-serve scoped to the caller’s agent_id. Publish (owner/admin):
201:
Claim (agent self-serve — response is scoped to the caller’s agent_id):
201:
Award (owner/admin):
200:
An award deletes the winner’s assignment for that shift and date (the release), flips the winning claims to awarded, and rejects the rest.

9. Agent skills: set, list, remove

Skills gate schedule generation — an agent is only proposed for a shift when their registered skills cover the shift’s required_skills. The upsert is keyed on (agent_id, skill), so re-rating is the same PUT. Writes are owner/admin; reads are all roles. Upsert (owner/admin):
200:
List (all roles — filter by agent_id or skill, paginate with limit + cursor):
200:
Remove (owner/admin):
422: a skill over 64 characters or a proficiency_level outside 1–5 returns 422 VALIDATION_ERROR.

10. Overview summary

One read that powers the scheduling dashboard: forecast coverage, rostered staffing, live adherence, pending requests, open shifts, unfilled overtime/VTO offers, and pending adherence exceptions for the operating day.
200:
The forecast and staffing blocks are null when no forecast rows or roster exist for the date. All four roles can read it; non-managers see counts scoped to themselves, same as the underlying lists.

11. Assignments: bulk-assign, inspect, remove

Assignments bind an agent to a shift on a date — the same row schedule generation commits. The bulk endpoint is the fast path for backfills; creation and deletion are owner/admin, and like schedule commit the bulk insert is idempotent via skipped counts. Bulk assign (owner/admin):
201:
Remove (owner/admin — path id, not a body):
200:
422: a bulk item missing a required field returns 422 VALIDATION_ERROR with per-item details; deleting an unknown id returns 404 NOT_FOUND.

12. Adherence exceptions: file, review, resolve

An adherence exception is a review workflow that excuses a deviation an agent had no control over — a backend outage, a pulled meeting. Approval credits the deviation back to the agent’s adherent total, so the adjusted adherence score no longer counts the excused seconds. File (all roles — a non-manager may only file on their own agent_id; owners/admins may file on behalf of anyone):
201:
Review queue — list pending exceptions (owner/admin see everyone; other roles see only their own rows):
200:
Resolve (owner/admin — approve; deny is the same shape with a different status flip, and cancel lets the requester withdraw while still pending):
200:
An approved exception marks its seconds excused: adherence scores report both the raw and the adjusted ratio, and the carve-out can never push the adjusted ratio above 1.0. 422/409: ends_at at or before starts_at returns 422 VALIDATION_ERROR; approving, denying, or cancelling a row that is no longer pending returns 409 INVALID_TRANSITION; a non-manager filing for another agent returns 403 FORBIDDEN.

13. Shrinkage: recompute, then read

Shrinkage is the share of paid time agents spend on breaks, training, meetings — anything that is not handling contacts. Recompute (owner/admin) refreshes the figures over a window; the read returns per-agent percentages. Leave rows the recompute misses only fill in on the next read. Recompute (owner/admin):
200:
Read:
200:
422: a from after to returns 422 VALIDATION_ERROR.

14. Timekeeping: read the timesheet, export payroll

Timesheets turn the adherence event log into worked-hours rows: one row per agent per operating date, split into paid worked time, paid break, unpaid break, and (beyond the daily threshold) overtime — with the day’s first clock-in and last clock-out. Any non-elevated seat is scoped to its own row only; the payroll CSV export is owner/admin. Read worked hours:
200:
Export the pay-period CSV (owner/admin; other roles receive 403 INSUFFICIENT_PERMISSIONS):
200 (text/csv, Content-Disposition: attachment):
The worked-vs-break split mirrors the standard time & attendance model: paid states (available, on call, wrap-up, training, short breaks) against unpaid meal time, with daily paid time beyond the threshold (default 8h) counted as overtime. When the row cap truncates a response, JSON sets truncated: true and the CSV sets X-Export-Truncated.

15. Agent insights: wellness and flight risk

Two reads support staffing conversations: wellness signals are available to every role, while flight-risk scores are restricted to owner/admin — a developer or viewer caller gets 403 INSUFFICIENT_PERMISSIONS. Wellness (all roles):
200:
Flight risk (owner/admin only):
200:

Endpoint parity

Every endpoint row in the tables above has at least one worked example. Sections 1–5 cover staffing, forecast what-if, schedule generate/commit, shifts (an assignment is a shift binding), open shifts, and requests; sections 6–15 complete the coverage across overview summary, forecasts (recompute + accuracy), assignments, overtime and VTO offers, agent skills, adherence exceptions, shrinkage, timekeeping, and agent insights. All parameters use the ORBIT_API_KEY preamble from the top of the page. Where a row pairs with a CodeGroup, the Node SDK example uses a typed orbit.wfm.* helper when one exists (forecasts) and the SDK’s generic orbit.request() escape hatch otherwise.

See also