com.crisphive/mcp
NPM · @CRISPHIVE/MCP · 2 COMPONENTS
Field operations on a deterministic solver — run jobs, crews & fleet from Claude or ChatGPT.
Available components
Last scanned (3 hours ago)
Scores higher than 69% of npm servers
Category Project Management
How this component scores in each security and reliability category. Every signal is checked automatically from public evidence about the published package, including repeated runs of it in an isolated sandbox, and we only credit what we can confirm. How we score → Why this is hard to score →
Supply Chain Security98
- No malware found by supply-chain analysis.Pass
- No known CVEs affecting this package version or its production dependencies.Pass
- No install/post-install scripts declared.Pass
- 30 of 92 dependencies flagged as unhealthy. View diagnostics → Partial
Provenance & Transparency45
- Source repository is publicly reachable at the declared URL. View diagnostics → Pass
- Provenance check failed: no build-provenance attestation is published. See how to fix → View diagnostics → Fail
- Clear OSI-approved license (MIT).Pass
- Actively maintained (last published 17 days ago).Pass
- Disclosure check failed: no security disclosure policy was found in the source repository. See how to fix → Fail
Schema Quality & AI Usability62
- AI-judged instruction clarity (excellent).Pass
- Context-footprint check failed: tool/resource definitions use about 22238 tokens (~331/item across 67 items; 67 tools + 0 resources), over budget; trim descriptions and params. See how to fix → Fail
- Usage-examples check failed: none of the tools include examples. See how to fix → Fail
Stability & Change Management100
- No destabilizing schema changes in the last 30 days.Pass
Tool Coverage99
- 100% of tools have a non-trivial description (not blank, and not just the tool's name).Pass
- 96% of tool parameters carry a description.Partial
Tool Safety100
- No prompt-injection markers were found in the server instructions, tool names or descriptions we captured.Pass
- All 9 tool(s) whose name or description implies an irreversible operation declare an MCP destructiveHint annotation.Pass
- An AI judge read all 67 captured unit(s) of tool text and found none that tries to manipulate the model reading it.Pass
Capabilities100
- Implements a supported MCP spec version (2025-11-25); the latest is 2026-07-28.Pass
Every change we have recorded for this component, newest first. Security-relevant changes are always shown. ▲ marks a change for the better, ▼ a change for the worse; unmarked changes are neutral.
- 25 Oct 26 0
- Package version: 2.0.0 → 2.6.0 functional
- 24 Oct 26 0
- Stability: 0.97 → pass security
- 23 Oct 26 0
- Stability: pass → 0.97 functional
- 18 Oct 26 −1
- Tool safety: pass → unverified ▼ security
- Stability: pass → unverified ▼ security
- Tool coverage: 100 → unverified ▼ functional
- Capabilities: pass → unverified ▼ functional
- Schema quality: Schema quality not yet verified: we do not have a sandbox capture of the MCP schema this version of the package serves yet. functional
- Package version: 2.5.0 → 2.6.0 functional
- 17 Oct 26 +1
- Stability: 0.97 → pass security
- 15 Oct 26 +1
No change was recorded against any check on this day. Stability & Change Management went from 90 to 93. That category is still filling its 30-day observation window: 27 days of observed history at the previous scan, 28 at this one. The score rises as the window fills, whether or not the server changes.
- 13 Oct 26 +1
No change was recorded against any check on this day. Stability & Change Management went from 83 to 87. That category is still filling its 30-day observation window: 25 days of observed history at the previous scan, 26 at this one. The score rises as the window fills, whether or not the server changes.
- 12 Oct 26 0
- Security disclosure: unverified → fail ▼ functional
- Package version: 2.0.0 → 2.5.0 functional
Diagnostic detail from the automated scan of this channel: what the scanner observed at each step, so you can see exactly where a check passed or failed. It is informational only and never changes the trust score.
Captured 5 Nov 2026 · Analysed npm/@crisphive/mcp@2.6.0
Provenance No attestation
The registry publishes no build provenance for this version, so there is nothing to verify.
| Result | No attestation |
|---|---|
| Ecosystem | npm |
Background: How many MCP packages publish verified provenance →
Dependencies 92 packages
| Packages resolved | 92 |
|---|---|
| Stale | 30 |
| Tree resolution | Complete |
Background: SBOMs and build attestations, explained →
The tools this component advertises to a client, with an estimated token cost for each. Expand a tool to see its parameters and schema. The per-tool counts are indicative and are not scored directly; the schema's total context footprint is one signal in Schema Quality & AI Usability. A tool's description is untrusted text the model reads on every call, which is what makes this list a security surface and not just an inventory: how tool poisoning works →
bookAndConfirmJobRequest Book, schedule and confirm a job in one call ~1,465
Book, schedule and confirm a job in one call Creates the job, quotes it (job_duration_minutes, or the job type's default_duration_minutes) and confirms it at scheduled_at on the customer's behalf — the dashboard's "book for a caller" in a single request, built for voice agents and automation platforms that cannot run create → quote → slots → confirm. Customer: send `customer_id`, or `customer` (+ `address`) to match-or-create by phone/email — a caller who already exists is matched, never duplicated. Find a caller first with listCustomers?phone=. Every input is validated BEFORE anything is written (time and business timezone, future start, a duration or a job-type default, non-negative mobilization/demobilization minutes, active job type, phone format); those failures are ordinary 4xx and create nothing. ⚠️ A `technician_id` the engine cannot honour at that time is refused BEFORE anything is written: `409 JOB_REQUEST_TECH_INFEASIBLE`, no job, no customer, no webhook. Change the technician or the time and send again with a NEW Idempotency-Key: like every 4xx here the 409 is cached against its key for 24h, so the same key replays it (same body) or answers 422 IDEMPOTENCY_KEY_REUSE (changed body). This check is BEST-EFFORT — if the scheduling engine cannot be reached it is skipped and the call proceeds, so a pinned request can still come back as the 200 + `refusal` below. Handle both. ⚠️ ONE carve-out: a `p0` whose pinned technician is merely BUSY is NOT refused here. The job is created and the call answers 200 + `refusal` carrying JOB_REQUEST_P0_REQUIRES_DISPLACEMENT, because the remedy for that code is the emergency flow and listEmergencyCandidates / previewEmergencyReschedule / commitEmergencyReschedule all require `emergency_job_id` — a 409 carries no job id. Read `job_id` off the 200 and run the emergency flow; do not re-book. Every other doomed pin on a `p0` (out of area, missing skills, not a lead) still answers 409. ⚠️ A SECOND carve-out, narrower: for a…
| Name | Type | Req | Description |
|---|---|---|---|
| address | – | – | Service address. REQUIRED with `customer`. OPTIONAL with `customer_id`: when sent it is used for THIS JOB and the stored customer address is only the fallback when it is omitted — it is never written… |
| customer | – | – | A caller who may or may not exist yet: matched by phone/email against the business's customers (no duplicate is created for a known caller), created otherwise. Send this OR `customer_id`. |
| customer_id | string | – | UUID of an existing customer. Send this OR `customer`, not both. |
| demobilization_minutes | integer | – | Demobilization (teardown) minutes after the work, min 0 — same rules as mobilization_minutes. |
| description | string | – | Free-text description of the work. Optional; max 2000 chars. |
| emergency | – | – | P0 dispatch. Present only with priority p0 (or a business whose default priority is p0). See the endpoint description. |
| idempotency_key | string | – | Makes retries safe: a repeat send with the same key returns the original result instead of booking again (sent as the Idempotency-Key header) |
| job_duration_minutes | integer | – | Hands-on work minutes. Optional when the job type has a default_duration_minutes. |
| job_type_id | string | – | UUID of the job type: it classifies the job and supplies default_duration_minutes when job_duration_minutes is omitted. Optional: omitted, the business's DEFAULT job type (is_default, the seeded "Gen… |
| mobilization_minutes | integer | – | Mobilization (setup/travel-prep) minutes before the work, min 0 — same meaning as on quoteJobRequest. Optional: omitted, the job type's default_mobilization_minutes applies when job_duration_minutes… |
| priority | string | – | Scheduling priority p0–p3. Optional; omitted = the business default. |
| scheduled_at | string | – | Start time — a BUSINESS-LOCAL wall clock, same rule as confirmJobRequest: canonical `2026-09-30T10:00:00`, seconds optional, a space may replace the T; an offset is accepted only when it agrees with… |
| skill_ids | array | – | UUIDs of skills the work needs. Optional; up to 20. |
| technician_id | string | – | Force a specific lead technician (feasibility still enforced). Omit to let Crisphive pick. |
No output schema declared.
No examples provided.
commitAbsenceResolve Commit the previewed re-staffing of a technician's day ~804
Commit the previewed re-staffing of a technician's day Applies the plan returned by /absence/preview, ATOMICALLY: every assignment in one transaction (all or nothing), each job re-staffed onto its alternate at its unchanged window, its "needs attention" flag cleared, its status_version bumped. Commit VERIFIES and never re-solves — send `assignments[]` copied from `preview.resolved[]` (you may drop rows, never add or re-point them) and, to ACCEPT a priced alternative from `preview.unresolved[].alternatives[]`, the same row plus its `alternative_kind` and (for a reschedule kind) its `start_at`/`end_at`; the engine re-checks that technician at that window under exactly that relaxation. A reschedule kind rewrites `scheduled_at`, notifies the customer of the NEW TIME (`job_rescheduled`, never `tech_reassigned` on top) and fires `job_request.rescheduled`; the response row then carries `alternative_kind`, `cost`, `original_start_at`/`original_end_at` and `window_preserved: false`. Requires a time-off record covering EVERY day of the range for the technician (pending or approved); a pending one is APPROVED by the commit, because the engine's feasibility filter reads approved time-off only and without it the absent technician stays bookable everywhere else. The response mirrors the preview plus per-job `notification` evidence (dispatched | skipped + reason — what the routing WILL do, never proof of delivery), `attention_cleared`, and `time_off`. Supports Idempotency-Key. Requires job_manage AND schedule_manage (the approval is a scheduling action). See ABSENCE_RESOLVE_DESIGN.md. 409 NEXT STEPS: ABSENCE_RESOLVE_TIME_OFF_REQUIRED — the absence is not recorded well enough to commit against: `data.uncovered_dates[]` (days no eligible record touches) and `data.uncovered_jobs[]` (jobs no single eligible record spans); eligible = approved records, plus PENDING records whose span lies INSIDE the range — a pending record WIDER than the range (somebody's leave request) is never appr…
| Name | Type | Req | Description |
|---|---|---|---|
| assignments | array | yes | The placements to apply, taken from preview.resolved[]. At least one. |
| date | string | yes | First day of the absence (YYYY-MM-DD, business-local) — must match the preview. |
| idempotency_key | string | – | Unique key making retries safe: a repeat send with the same key replays the original response (header Idempotent-Replayed: true) instead of re-running the operation. Reusing a key with a different bo… |
| technician_id | string | yes | The absent technician (must match the preview). |
| until_date | string | – | Last day, inclusive (YYYY-MM-DD) — must match the preview. |
No output schema declared.
No examples provided.
commitEmergencyReschedule Commit emergency insert + cascade reschedule ~763
Commit emergency insert + cascade reschedule Applies the cascade previewed by /emergency/preview: assigns the emergency job to the technician and pushes the displaced jobs back (or, with `displacement_mode=reassign`, re-staffs them onto their previewed alternates first), atomically. Supports Idempotency-Key. The server recomputes the plan under a lock and fences each job on its status_version — if anything changed since the preview it returns 409 EMERGENCY_RESCHEDULE_PLAN_DRIFTED (re-preview). Same body as preview + optional `emergency_expected_version`. `after_hours_override=true` must match the preview it followed — it drops the non-working-day rejection (this endpoint never runs the technician's working-hours/time-off feasibility check; that only happens on /candidates), and the response carries an AFTER_HOURS warning; the committed job's activity feed also records who authorized the after-hours placement. Isolated feature (see EMERGENCY_RESCHEDULE_DESIGN.md). 409 NEXT STEPS: EMERGENCY_RESCHEDULE_PLAN_DRIFTED — the schedule changed between your preview and this commit (another booking/move won a lane); `data.drifted[]` names the job(s) whose status_version moved when the fence can attribute it (absent, never empty, when only a length mismatch is known): call /preview again, show the fresh plan, then commit. EMERGENCY_RESCHEDULE_SLOT_OCCUPIED — landing window blocked by an immovable anchor (P0/crew/multi-day); `data.conflicts[]` names it: another tech or time. Other codes — same remedies and `data` shapes as /candidates. EMERGENCY_RESCHEDULE_NO_WORKING_DAY fires on a closed day without after_hours_override and carries `data.override_available: true` — confirm with the coordinator, then retry with the flag.
| Name | Type | Req | Description |
|---|---|---|---|
| after_hours_override | boolean | – | Place this P0 outside working hours / approved time-off — you have phoned the technician and they agreed. Drops the non-working-day rejection; the response then carries an AFTER_HOURS warning. Double… |
| displacement_mode | string | – | Fate of displaced jobs: reschedule (default) or reassign — must match the preview. |
| emergency_expected_version | integer | – | Optimistic-lock fence from the previewed job (0 = fence on the server-read version). |
| emergency_job_id | string | yes | ID of the P0 job to insert. |
| expected_move_ids | array | – | ExpectedMoveIDs — the displaced job IDs the preview returned (echo BOTH data.days[].moves[].job_id AND data.reassignments[].job_id). RECOMMENDED: if the recomputed cascade would touch a different set… |
| idempotency_key | string | – | Unique key making retries safe: a repeat send with the same key replays the original response (header Idempotent-Replayed: true) instead of re-running the operation. Reusing a key with a different bo… |
| mode | string | yes | Cascade mode: overtime | next_day (must match the preview). |
| start_at | string | yes | Desired start — business-local naive datetime, no offset. Must be in the future and match the preview. |
| technician_id | string | yes | Target technician (must belong to the business). |
No output schema declared.
No examples provided.
commitJobRequestMove Commit a schedule-board job move ~615
Commit a schedule-board job move Applies the move previewed by /move/preview: places the job on the technician at the new time and pushes the displaced jobs back, atomically (per-tech advisory lock; the server recomputes the plan and fences each job on its status_version — drift since the preview returns 409 SCHEDULE_MOVE_PLAN_DRIFTED, re-preview). Same body as preview + optional `expected_version`. See SCHEDULE_BOARD_DESIGN.md. 409 NEXT STEPS: SCHEDULE_MOVE_PLAN_DRIFTED — the schedule changed since your preview (or expected_move_ids/expected_member_ids no longer match): re-preview, show the fresh plan, commit again; carries no further `data` (the fence cannot attribute the drift to one specific job). All other codes — same remedies AND `data` shapes as /move/preview.
| Name | Type | Req | Description |
|---|---|---|---|
| after_hours_override | boolean | – | AfterHoursOverride — drop the non-working-day rejection for a P0 whose technician the coordinator has already phoned. P0 only (JOB_REQUEST_AFTER_HOURS_REQUIRES_P0 otherwise), and the preview then car… |
| expected_member_ids | array | – | ExpectedMemberIDs — crew moves only: the FULL member set the preview staffed (echo data.members[].technician_id). If the commit's re-plan would staff a DIFFERENT set (a previewed replacement got book… |
| expected_move_ids | array | – | ExpectedMoveIDs — the displaced job IDs the preview returned (echo data.days[].moves[].job_id). Optional but RECOMMENDED: if the schedule changed so the commit would push a different set (e.g. a job… |
| expected_version | integer | – | ExpectedVersion — the moved job's status_version from the preview (0 = fence on the fresh plan-read value; negatives rejected). |
| id | string | yes | Job request ID (UUID or short_code) |
| idempotency_key | string | – | Unique key making retries safe: a repeat send with the same key replays the original response (header Idempotent-Replayed: true) instead of re-running the operation. Reusing a key with a different bo… |
| mode | string | yes | Cascade mode: overtime | next_day (must match the preview). |
| start_at | string | yes | New start — business-local naive datetime, no offset. Must match the preview and be in the future. |
| technician_id | string | yes | Target technician (must match the preview). |
No output schema declared.
No examples provided.
confirmJobRequest Confirm a booking on behalf of the customer ~1,262
Confirm a booking on behalf of the customer Fires the customer-actor `confirm_booking` action from the BUSINESS surface (audited as business_on_behalf). Two uses: (1) LIVE — staff confirm a slot for a customer who booked by phone; (2) SANDBOX — the customer magic-token surface is live-only (a sandbox job's link can never reach a real customer), so this is the ONLY way to drive a sandbox test job past booking (book → quote → confirm → assign → complete). Body carries the customer-chosen scheduled_at (business-local naive datetime). DECISION TABLE — every 409 this endpoint returns, and the correct NEXT STEP (branch on error_code, never on the HTTP status): • JOB_REQUEST_STAGE_CONFLICT — the job changed since you read it (NOTE: every FAILED confirm attempt also bumps status_version by design). Next: re-GET the job, retry with the fresh status_version. • JOB_REQUEST_ACTION_NOT_PENDING — the job is no longer at the confirm step (usually: already confirmed). Next: re-GET and show current status; do not retry. • JOB_REQUEST_NO_TECHNICIAN_AVAILABLE — the TIME is infeasible for everyone (outside working hours / the customer window, or nobody qualifies). Best-effort `data` breakdown: `considered` (roster size checked), `blocked_by` (histogram of blockers[0].kind → count, only kinds that actually blocked someone), `truncated` (roster larger than the check covered). Next: pick another time via booking-windows / time-segments. NOT an emergency case — displacement cannot conjure capacity. • JOB_REQUEST_TECH_INFEASIBLE — the FORCED technician cannot take the job then; `data.reason` says why (blockers[0].kind): outside_service_area | missing_required_skills | not_lead_tier | no_working_day | on_time_off | off_shift | calendar_busy | calendar_conflict | visit_too_long | occupied (they are already working then — `data.earliest_feasible_at` is when they are free) | cannot_arrive_in_time (see `data.earliest_feasible_at`, RFC3339 UTC — the first same-day time they CAN be on site → off…
| Name | Type | Req | Description |
|---|---|---|---|
| after_hours_override | boolean | – | AfterHoursOverride (BUSINESS confirm only): schedule this P0 outside the technician's working hours or approved time-off — you have phoned them and they agreed. Requires priority p0, a single-person… |
| arrival_window_minutes | integer | – | ArrivalWindowMinutes = width (phút) của arrival-window ô khách bấm ở slot-picker (chính là time_slot_step_minutes, mặc định 30). Persist để post-confirm detail render lại đúng window. Optional; bound… |
| id | string | yes | Job request ID |
| idempotency_key | string | – | Unique key making retries safe: a repeat send with the same key replays the original response (header Idempotent-Replayed: true) instead of re-running the operation. Reusing a key with a different bo… |
| scheduled_at | string | – | Chosen start time — business-local wall clock (the business_time.datetime value from the time-segments picker), converted to UTC against the job's business timezone. Seconds may be omitted and a spac… |
| status_version | integer | – | Optimistic-lock fence: the status_version from your last read. Omitted/0 = fence on the row's current version (no race protection). |
| technician_id | string | – | TechnicianID (BUSINESS confirm only — ignored on the customer surface): force-assign the job to this technician instead of the ranked auto-pick. Ranking is bypassed; feasibility (hours/time-off/geo/s… |
No output schema declared.
No examples provided.
createCustomer Create a customer ~463
Create a customer Creates a customer record — the client/account profile a job request (work order) is booked against; use it to import or sync customers from your own CRM, website lead form or intake flow. Address (street, city, postal_code, ...) and coordinates (latitude/longitude) live under the nested `address` object. service_area_id must be a valid service area UUID belonging to this business.
| Name | Type | Req | Description |
|---|---|---|---|
| address | – | – | Postal address and coordinates. |
| string | – | Email address. Optional, but at least one of phone/email is required. | |
| full_name | string | yes | Customer's full name. Required; max 255 chars. |
| idempotency_key | string | – | Unique key making retries safe: a repeat send with the same key replays the original response (header Idempotent-Replayed: true) instead of re-running the operation. Reusing a key with a different bo… |
| phone | string | – | Phone number in E.164 international format: a leading `+` and the country code, e.g. `+16135550188`. A bare national number (`6135550188`) is REJECTED with PHONE_INVALID — there is no default region… |
| preferred_technician_id | string | – | UUID of the technician this customer prefers. Must belong to this business. |
| service_area_id | string | – | UUID of the service area for this customer. Must belong to this business. |
| sms_opt_in | boolean | – | SMS consent: set true ONLY when the customer explicitly agreed to receive SMS (e.g. ticked a non-pre-checked consent box, or gave verbal/written consent you keep a record of). SMS notifications are s… |
| tier | string | – | Loyalty tier. Defaults to "regular" if omitted. |
| uid | string | – | Your external reference for this customer (your own system's ID). Optional; max 32 chars. |
No output schema declared.
No examples provided.
createJobRequest Create a job request ~476
Create a job request Books a field-operations job — the work order that enters the dispatch & scheduling pipeline. Send the customer's UUID plus requested `job_dates` (date + morning/afternoon/evening periods, ideally offered from GET /job-requests/booking-windows), optional `job_type_id` (service catalog), `skill_ids` (required technician qualifications) and a free-text description. Quoting, technician/crew assignment and completion then advance the work order through the business's workflow.
| Name | Type | Req | Description |
|---|---|---|---|
| customer_id | string | yes | UUID of an existing customer of this business to book the job for. Required. |
| description | string | – | Free-text description of the work requested. Optional; max 2000 chars. |
| idempotency_key | string | – | Unique key making retries safe: a repeat send with the same key returns the original booking instead of creating a duplicate (sent as the Idempotency-Key header) |
| job_dates | array | yes | Requested date(s) + period(s) the customer wants the job. At least one, up to 12. |
| job_type_id | string | – | UUID of the job type to classify this job. Optional: omitted, the business's DEFAULT job type (`is_default`, the seeded "General") is used, so every new job has a type and can be quoted from its defa… |
| priority | string | – | Scheduling priority. Optional; omitted bookings receive the business's default_priority setting (assignment settings, default p2). p0=emergency (interrupt-driven insert), p1=top (displaced only by p0… |
| skill_ids | array | – | UUIDs of the skills the customer desires for this job. Optional; up to 20. |
| sla_deadline | string | – | SLA deadline (business-local naive datetime, e.g. "2030-06-14T17:00:00"). Optional; ONLY valid together with priority=p1 — arms the auto-escalation clock (the job escalates to p0 as breach risk cross… |
| x_timezone | string | – | Customer IANA timezone (sent as the X-Timezone header) |
No output schema declared.
No examples provided.
createJobType Add a job type to the catalog ~560
Add a job type to the catalog Creates a kind of work customers can book, such as "Annual boiler service" or "Drain unblocking". Job types classify bookings: createJobRequest takes an optional `job_type_id` from this catalog and the job keeps the type's name as it was at booking time. `name` is the only required field and must be unique in the business (JOB_TYPE_DUPLICATE). `status` defaults to active. An inactive type stays in the catalog but cannot be chosen for new job requests; use that rather than deleting a type you may revive. Send an Idempotency-Key header (the `idempotency_key` argument over MCP) so a retried call replays the original response instead of creating a duplicate type. Optional default_duration_minutes (+ default_mobilization_minutes / default_demobilization_minutes) set how long this kind of work usually takes: quoteJobRequest uses them when it is sent no job_duration_minutes, so an automation or voice agent can schedule the job without knowing the length. A buffer needs a duration (JOB_TYPE_INVALID_DEFAULT_DURATION). This defines the catalog, not a booking. To book actual work use createJobRequest and reference the job type there.
| Name | Type | Req | Description |
|---|---|---|---|
| default_demobilization_minutes | integer | – | Default demobilization (teardown) minutes, 0–1440; used together with the default duration. Requires a default duration. Omit or 0 = no default. |
| default_duration_minutes | integer | – | Default hands-on work duration in minutes for this kind of work (1–20160). A quote that sends no job_duration_minutes uses it, which is what lets an automation or voice agent schedule a job without k… |
| default_mobilization_minutes | integer | – | Default mobilization (setup/travel-prep) minutes, 0–1440; used together with the default duration. Requires a default duration. Omit or 0 = no default. |
| idempotency_key | string | – | Unique key making retries safe: a repeat send with the same key replays the original response (header Idempotent-Replayed: true) instead of re-running the operation. Reusing a key with a different bo… |
| name | string | yes | Job-type name (required) — what the booking form shows as the kind of work. Stored as the canonical English value; per-locale names are a dashboard authoring feature. |
| status | string | – | Lifecycle status. Defaults to active; inactive types cannot be selected for new job requests. |
No output schema declared.
No examples provided.
createServiceArea Define a territory the business serves ~408
Define a territory the business serves Creates a service area: a named region used as a HARD filter when deciding who can take a job. A technician assigned to no area covering the job's address is never offered by listNearbyTechnicians, listMatchingSlots or listCrewCandidates, and never auto-assigned at confirm, whatever their skills or availability say. `name` is the only required field and must be unique (SERVICE_AREA_DUPLICATE_NAME). Coverage is matched two ways: with a `boundary` (GeoJSON polygon), a geocoded address must fall inside the polygon; without one, the area matches addresses by equality on its postal_code, city or district. A polygon is the precise option; the administrative fields are the fallback, and also what matches jobs whose address could not be geocoded. An invalid polygon is refused with SERVICE_AREA_INVALID_BOUNDARY. Creating the area does not staff it. Assign technicians with replaceTechnicianServiceAreas, or pass `service_area_ids` to createTechnician. Send an Idempotency-Key header (the `idempotency_key` argument over MCP) so a retry does not create a duplicate area.
| Name | Type | Req | Description |
|---|---|---|---|
| boundary | object | – | GeoJSON polygon boundary (optional) |
| city | string | – | City name |
| country | string | – | Country name |
| county | string | – | County name |
| description | string | – | Optional description |
| district | string | – | District name |
| idempotency_key | string | – | Unique key making retries safe: a repeat send with the same key replays the original response (header Idempotent-Replayed: true) instead of re-running the operation. Reusing a key with a different bo… |
| name | string | yes | Area name (required) |
| postal_code | string | – | Postal code |
| state_province | string | – | State / province name |
No output schema declared.
No examples provided.
createSkill Create a skill ~162
Create a skill Creates a skill under the given category. New skills are active by default. Skill names must be unique within their category.
| Name | Type | Req | Description |
|---|---|---|---|
| description | string | – | What the skill covers. Optional. |
| id | string | yes | Skill category ID (UUID) |
| idempotency_key | string | – | Unique key making retries safe: a repeat send with the same key replays the original response (header Idempotent-Replayed: true) instead of re-running the operation. Reusing a key with a different bo… |
| name | string | yes | Skill name (required). The matching engine hard-filters technicians on skills when a booking carries skill_ids. |
No output schema declared.
No examples provided.
createSkillCategory Create a skill category ~158
Create a skill category Creates a skill category for the current business. Categories group skills (e.g. "Plumbing", "Electrical"). Names must be unique within a business.
| Name | Type | Req | Description |
|---|---|---|---|
| icon | string | – | Icon slug for the dashboard's catalog tree. Optional. |
| idempotency_key | string | – | Unique key making retries safe: a repeat send with the same key replays the original response (header Idempotent-Replayed: true) instead of re-running the operation. Reusing a key with a different bo… |
| name | string | yes | Category name (required), e.g. a trade: Plumbing, Electrical, HVAC. |
No output schema declared.
No examples provided.
createTechnician Add a technician ~1,098
Add a technician Creates a technician membership under the current business. If the phone/email matches an existing user, their account is linked. Otherwise a new user identity is created. Either way the membership starts active. The new member is notified (live mode only, best-effort): an email when `email` is supplied, an SMS when `phone` is supplied, both when both — informational only, no activation step (login stays passwordless: magic link / OTP). Re-adding someone: if the person is currently SUSPENDED on this business (a dashboard action — not reachable via this API), the create REACTIVATES that existing membership (same technician id, their existing group; also notified). A technician REMOVED with deleteTechnician is a closed membership: re-adding the same email/phone links the SAME underlying person (no duplicate identity) but creates a FRESH membership with a NEW id — history stays under the old one. Owner/Administrator groups cannot be assigned via API key, and not at all in sandbox mode. `assignment_tier` (what the scheduler assigns jobs by) is ignored — stored empty, no error — for the Booking Coordinator, Administrator and Viewer roles, which are never assigned jobs; a reactivated member of those roles also comes back without a tier. Optional relations (all validated; any missing id → 404 TECHNICIAN_NOT_FOUND with `missing_ids`): `buddy_ids` sets this technician's buddy list (use when creating a lead); `lead_ids` adds this technician as a buddy of each named lead (use when creating a buddy — the buddy-side way to attach the same lead↔buddy relation); `service_area_ids` assigns the technician to those service areas. `start_location_type=office` snapshots the business address + coordinates into the technician at create time; `address`, `start_location_lat`, `start_location_long` in the body are ignored. Requires the business to have coordinates set (else 400 BUSINESS_LOCATION_MISSING). `start_location_type=home` (or empty) uses the address + coordina…
| Name | Type | Req | Description |
|---|---|---|---|
| address | – | – | Home address (the day-start point when start_location_type=home). |
| assignment_tier | string | – | Crew tier the matching engine assigns by: lead (can head a job), buddy (crew helper), float (excluded from auto crew-assign). IGNORED — stored empty, no error — when the role is Booking Coordinator,… |
| buddy_ids | array | – | Buddies of this technician (set when creating a lead). Optional; max 50 technician ids. |
| business_group_id | string | – | Role group for the new member. Optional: omitted or empty assigns the business's Technician group. To assign another group, copy its ID from the dashboard (Settings → Permissions) or from an existing… |
| string | – | Email address. At least one of phone/email is required (identity resolution key). | |
| full_name | string | yes | The person's full display name. Required; max 255 chars. |
| idempotency_key | string | – | Unique key making retries safe: a repeat send with the same key replays the original response (header Idempotent-Replayed: true) instead of re-running the operation. Reusing a key with a different bo… |
| job_title | string | – | Display title (e.g. "Senior HVAC Technician"). |
| join_date | string | – | First working day (YYYY-MM-DD). |
| lead_ids | array | – | Leads this technician is a buddy of (set when creating a buddy; the technician is appended to each lead's buddy list). Optional; max 50 technician ids. |
| notify | boolean | – | Whether to send the new member the "you have been added to {business}" message (email when an email was supplied, SMS when a phone was, both when both). Omitted or true sends it; false stays silent.… |
| phone | string | – | Phone number in E.164 international format: a leading `+` and the country code, e.g. `+16135550188`. A bare national number (`6135550188`) is REJECTED with PHONE_INVALID — there is no default region… |
| service_area_ids | array | – | Service areas to assign the technician to. Optional; max 50. Discover via GET /service-areas. |
| start_location_lat | number | – | Explicit day-start latitude in decimal degrees (-90..90); when set it wins over the address geocode. |
| start_location_long | number | – | Explicit day-start longitude in decimal degrees (-180..180); when set it wins over the address geocode. |
| start_location_type | string | – | Where the technician starts their day: home (their address) or office (the business location). Drives the engine's travel estimates. |
No output schema declared.
No examples provided.
createTechnicianTimeOff Record a technician's time off (sick day, leave) ~401
Record a technician's time off (sick day, leave) Records a time-off block for a technician. The record is created PENDING; a business staff member approves it on the dashboard — EXCEPT for the sick-call flow, where `commitAbsenceResolve` approves the pending record that covers the absence itself. `start_datetime`/`end_datetime` are RFC3339 INSTANTS with an offset (e.g. `2030-06-15T04:00:00Z` for midnight Toronto), unlike the business-local naive datetimes used by scheduling calls — a whole day off is that day's local midnight to the next in UTC. Overlapping an existing record for the same technician is refused (`TIME_OFF_OVERLAP`); list `GET /technicians/{id}/time-off` first. Creating a record immediately flags the technician's jobs in that window as needing attention on the dispatch board. Supports Idempotency-Key.
| Name | Type | Req | Description |
|---|---|---|---|
| end_datetime | string | yes | Block end — RFC3339 instant, must be after start_datetime. A whole day off runs local midnight to the next. |
| idempotency_key | string | – | Unique key making retries safe: a repeat send with the same key replays the original response (header Idempotent-Replayed: true) instead of re-running the operation. Reusing a key with a different bo… |
| reason | string | – | Free-text reason, max 500 characters (e.g. "Sick call 06:58"). |
| start_datetime | string | yes | Block start — an RFC3339 instant WITH offset (e.g. 2030-06-15T04:00:00Z = midnight Toronto EDT), not a business-local naive datetime. |
| technician_id | string | yes | The technician taking time off (must belong to the business). |
No output schema declared.
No examples provided.
createVehicle Add a vehicle to the fleet ~529
Add a vehicle to the fleet Registers a van, truck or car in the business's own fleet. Vehicles are what a confirmed job's crew travels in: at confirm, Crisphive auto-selects one vehicle for the whole crew from the lead technician's vehicles, then from unowned fleet vehicles, and blocks a vehicle already booked for an overlapping job. `name` is the only required field, so a bulk fleet import needs nothing else; brand, model, year, plate_number, current_mileage and vehicle_type (van, truck or car) can be filled in later with updateVehicle. Names and plate numbers must be unique in the business (VEHICLE_DUPLICATE_NAME / VEHICLE_DUPLICATE_PLATE). `owner_id` records who has CLAIMED the vehicle as their primary one. The owner must be a lead technician or a management role; a buddy- or float-tier profile is refused with VEHICLE_OWNER_TIER_NOT_ALLOWED, an unknown profile with VEHICLE_INVALID_OWNER. Deciding which vehicles a technician may USE is a separate relation: use replaceTechnicianVehicles for that, not this tool. Send an Idempotency-Key header (the `idempotency_key` argument over MCP) so a retried call replays the original response instead of creating a duplicate vehicle.
| Name | Type | Req | Description |
|---|---|---|---|
| brand | string | – | Manufacturer / make. Optional. |
| current_mileage | integer | – | Odometer reading. Optional; must be >= 0 when sent. |
| idempotency_key | string | – | Unique key making retries safe: a repeat send with the same key replays the original response (header Idempotent-Replayed: true) instead of re-running the operation. Reusing a key with a different bo… |
| model | string | – | Model name. Optional. |
| name | string | yes | Vehicle display name (required). The only mandatory field — a fleet import needs nothing but names to get vehicles into the system. |
| owner_id | string | – | UUID of the technician who owns (has claimed) this vehicle. Optional. The owner must be a lead technician or a management role — a buddy- or float-tier profile is refused with VEHICLE_OWNER_TIER_NOT_… |
| plate_number | string | – | License plate. Optional. |
| vehicle_type | string | – | – |
| year | integer | – | Model year. Optional. |
No output schema declared.
No examples provided.
createWebhookEndpoint Create a webhook endpoint ~473
Create a webhook endpoint Registers an HTTPS URL that Crisphive will POST events to, and immediately sends a signed verification `ping`. If your receiver answers 2xx the endpoint is created `active`; otherwise it is created `pending_verification` (receives NO events) — fix the receiver, then re-verify it from the Crisphive dashboard, or (on the public API, where verify is not exposed) delete it and create it again. Automation platforms subscribing a REST hook should filter out the `ping` event on their side. The response includes the signing `secret` ONE TIME — store it; you verify the `Crisphive-Signature` header with it and it cannot be retrieved again. `event_types` empty = every event the calling credential may READ: `customer.*` needs customers_view, `technician.*` team_view, `job_request.*` job_view, because a subscription streams that data to your URL. Naming an event the credential cannot read is refused with WEBHOOK_EVENT_NOT_PERMITTED (403, `data.event_types` + `data.required_permissions`). The endpoint is bound to the caller's current environment (live/sandbox).
| Name | Type | Req | Description |
|---|---|---|---|
| description | string | – | Optional human label shown in the dashboard. |
| event_types | array | – | Event types to receive. Empty = every event the credential may READ (customer.* needs customers_view, technician.* team_view, job_request.* job_view); naming one it cannot read is WEBHOOK_EVENT_NOT_P… |
| expires_in_days | integer | – | Signing-secret lifetime in days. Omit for the 30-day default; 1..365 to choose your own. When it lapses the endpoint stops delivering until you rotate — see POST /business/webhooks/{id}/rotate-secret. |
| idempotency_key | string | – | Unique key making retries safe: a repeat send with the same key replays the original response (header Idempotent-Replayed: true) instead of minting a second endpoint + secret. Reusing a key with a di… |
| url | string | yes | HTTPS callback URL Crisphive will POST events to. Required; absolute http(s). |
No output schema declared.
No examples provided.
deleteCustomer Delete a customer ~43
Delete a customer Soft-deletes a customer record, removing it from the active customer directory; existing bookings keep their customer snapshot.
| Name | Type | Req | Description |
|---|---|---|---|
| id | string | yes | Customer ID |
No output schema declared.
No examples provided.
deleteJobType Remove a job type from the catalog ~133
Remove a job type from the catalog Soft-deletes the entry: it disappears from the catalog and can no longer be selected for new bookings. Jobs already booked against it are unaffected and keep showing the name they were booked with. Prefer updateJobType with `status=inactive` in almost every case: it has the same effect on the booking form and is trivially reversible. Delete is for a type created in error or one that will never return. Rows the platform ships with (`is_system=true`) cannot be deleted and are refused with JOB_TYPE_SYSTEM_READ_ONLY.
| Name | Type | Req | Description |
|---|---|---|---|
| id | string | yes | Job Type ID |
No output schema declared.
No examples provided.
deleteServiceArea Stop serving a territory ~167
Stop serving a territory Soft-deletes the service area: it disappears from listServiceAreas and stops counting for coverage immediately. Technician assignments to it are left in place but no longer grant coverage. The consequence is easy to underestimate: technicians whose only coverage was this area become unmatchable for addresses inside it. Jobs already assigned keep their technician, but any re-plan (reassign, board move, confirm of a pending job, the slot picker) can find no feasible crew there. Before deleting, re-check listCrewCandidates on upcoming jobs in that territory. If you are reshaping coverage rather than withdrawing from it, edit the polygon or postal/city fields with updateServiceArea instead; that keeps the area and its technician assignments working.
| Name | Type | Req | Description |
|---|---|---|---|
| id | string | yes | Service Area ID |
No output schema declared.
No examples provided.
deleteSkill Delete a skill ~53
Delete a skill Permanently deletes a skill. Returns SKILL_HAS_MEMBERS (409) if any active technicians are still assigned — unassign all technicians first.
| Name | Type | Req | Description |
|---|---|---|---|
| id | string | yes | Skill ID (UUID) |
No output schema declared.
No examples provided.
deleteSkillCategory Delete a skill category ~59
Delete a skill category Permanently deletes a skill category. Returns SKILL_CATEGORY_NOT_EMPTY (409) if any skills still belong to the category — remove or move all skills first.
| Name | Type | Req | Description |
|---|---|---|---|
| id | string | yes | Skill category ID (UUID) |
No output schema declared.
No examples provided.
deleteTechnician Remove a technician from the business ~449
Remove a technician from the business Closes the technician's membership: the profile is set to deactive and soft-deleted, and their access to this business ends on their next request. In the same operation they are removed from every other technician's buddy list, vehicles they own are released, and any personal-calendar connection they made for this business is revoked. Fires the technician.deleted webhook. Their underlying user identity is untouched, and so are memberships at other businesses. Removal is REFUSED while the member is still staffed on an open job, as the lead or through a crew session, where open means not completed, not archived and not deleted (409 TECHNICIAN_HAS_OPEN_JOBS; nothing is written). data.open_job_count is the exact count and is always present. data.jobs lists up to 20 of them (id, short_code, current_status_key, scheduled_at when confirmed) ONLY when the caller also holds job_manage (a credential that may manage the team but not the job board gets the count alone; the key is then absent). Re-staff them first: reassign each with listCrewCandidates, re-plan whole days with previewAbsenceResolve / commitAbsenceResolve (which needs a time-off record covering those days; create one with createTechnicianTimeOff), or, from the dashboard, complete or archive the job. To cut someone's access immediately while their work is re-staffed, suspend them from the dashboard: suspension is not gated. This is a closed membership, not a pause. Re-adding the same email or phone later with createTechnician links the SAME person but opens a FRESH membership with a NEW technician id and none of the old buddy, vehicle or area links. If you expect the person back, suspend them from the dashboard instead; a suspended member is reactivated in place by createTechnician, keeping their id and group. The last active Owner cannot be removed (TECHNICIAN_LAST_OWNER). API keys the person created are NOT revoked (an HR action must not take an integration down); if an…
| Name | Type | Req | Description |
|---|---|---|---|
| id | string | yes | Technician ID |
No output schema declared.
No examples provided.
deleteTechnicianTimeOff Delete a technician's time off (e.g. back from a sick day) ~236
Delete a technician's time off (e.g. back from a sick day) Removes a time-off record, in ANY status (pending, approved, rejected or cancelled). This is the "the technician can come in after all" call: once an approved record is deleted the technician is bookable again in that window for NEW bookings and schedule moves. It does NOT move any job back — jobs that `commitAbsenceResolve` already re-assigned to other technicians stay where they are (their customers may already have been told), and a job flagged as needing attention when the record was created keeps that flag until it is moved or re-assigned. To give the technician work again, book or move jobs onto them explicitly. The record is soft-deleted (it no longer appears in `GET /technicians/{id}/time-off`); deleting it again answers `TIME_OFF_NOT_FOUND`. A sandbox (`chsk_test_`) key can only delete sandbox records — a live record id answers `TIME_OFF_NOT_FOUND`, and the reverse holds for a live key.
| Name | Type | Req | Description |
|---|---|---|---|
| id | string | yes | Time Off ID |
No output schema declared.
No examples provided.
deleteVehicle Retire a vehicle from the fleet ~151
Retire a vehicle from the fleet Soft-deletes the vehicle and, in the same transaction, removes it from every technician's vehicle list. It no longer appears in listVehicles or getVehicle and can no longer be auto-selected for a crew. Jobs that referenced it keep the stored reference but no longer display an assigned vehicle, and upcoming jobs are NOT given a replacement automatically. Reach for this only when a vehicle leaves the fleet for good (sold, written off, off-lease). For a van that is merely in the workshop, set its `status` to maintenance with updateVehicle instead, so the record stays in the fleet and can be brought straight back.
| Name | Type | Req | Description |
|---|---|---|---|
| id | string | yes | Vehicle ID |
No output schema declared.
No examples provided.
deleteWebhookEndpoint Delete a webhook endpoint ~93
Delete a webhook endpoint Unsubscribes the endpoint: no further events are delivered to it, including retries still pending. This is the "unsubscribe" half of a REST-hook trigger; call it when the automation is turned off. Endpoints are scoped to the credential's environment (live/sandbox), so a sandbox key cannot delete a live endpoint.
| Name | Type | Req | Description |
|---|---|---|---|
| id | string | yes | Webhook endpoint ID (UUID) |
No output schema declared.
No examples provided.
getCustomer Get a customer ~90
Get a customer Returns the full customer record: profile, contact details, tier and lifetime spending summary — a 360° client view for support, upsell or CRM enrichment. contact.preferred_technician includes {id, name}. contact.service_area includes {id, name}. contact.address.latitude / contact.address.longitude are null if no coordinates saved.
| Name | Type | Req | Description |
|---|---|---|---|
| id | string | yes | Customer ID (UUID) |
No output schema declared.
No examples provided.
getJobRequest Get a job request ~71
Get a job request Returns the full work order: current workflow status, quoted duration, confirmed schedule, customer contact snapshot and the assigned technician / crew — everything a dispatcher or an external field-operations system needs to track one job.
| Name | Type | Req | Description |
|---|---|---|---|
| id | string | yes | Job request ID (UUID or short_code) |
No output schema declared.
No examples provided.
getJobRequestTimeline Job timeline ~112
Job timeline Per-status progress of a job's lifecycle (e.g. booked → confirmed → on the way → arrived → completed, following the business's configured workflow) — render it as a job-tracking timeline. Each status carries its state (completed | current | upcoming), when the job entered it, and the actions fired within it. entered_at may be null for upcoming steps and for older jobs predating the backfill.
| Name | Type | Req | Description |
|---|---|---|---|
| id | string | yes | Job request ID (UUID or short_code) |
No output schema declared.
No examples provided.
getJobType Get a job type ~60
Get a job type Returns one entry of the business's service catalog (job/work-order type) with its localized display name — e.g. an HVAC tune-up, drain cleaning or electrical inspection offering.
| Name | Type | Req | Description |
|---|---|---|---|
| id | string | yes | Job Type ID |
No output schema declared.
No examples provided.
getServiceArea Get a service area ~66
Get a service area Returns one service area — a geographic coverage zone (service territory) the business operates in, with its name and geometry metadata. Reference its UUID as `service_area_id` on customer records for territory-aware dispatch.
| Name | Type | Req | Description |
|---|---|---|---|
| id | string | yes | Service Area ID |
No output schema declared.
No examples provided.
getTechnician Get a technician ~61
Get a technician Returns one technician's full profile: contact info, employment status, assignment tier, skills/qualifications, buddy (crew) relations and assigned vehicles — the dispatch-ready view of a field worker.
| Name | Type | Req | Description |
|---|---|---|---|
| id | string | yes | Technician ID |
No output schema declared.
No examples provided.
getTechnicianSchedule One technician's real schedule (sessions + time off) ~157
One technician's real schedule (sessions + time off) The technician's ACTUAL occupancy over a date range: every job session on their lane (solo/lead and crew) plus approved time-off blocks. Weekly recurring working hours come from the technician-availability endpoints — combine both for the full availability picture ("get crew availability"). from/to are business-local dates (YYYY-MM-DD, inclusive); omitted = today .. +7 days; range max 31 days.
| Name | Type | Req | Description |
|---|---|---|---|
| from | string | – | Start date (YYYY-MM-DD, business-local; default today) |
| id | string | yes | Technician ID |
| to | string | – | End date (YYYY-MM-DD, inclusive; default from+7d; max range 31 days) |
No output schema declared.
No examples provided.
getVehicle Get a vehicle ~60
Get a vehicle Returns one fleet vehicle (service van/truck): identity, plate, operational status (idle, on job, maintenance) and which technicians use it — the fleet-management view of a single asset.
| Name | Type | Req | Description |
|---|---|---|---|
| id | string | yes | Vehicle ID |
No output schema declared.
No examples provided.
listAssignableGroups List groups the caller may assign to a member ~116
List groups the caller may assign to a member Returns the role groups the CURRENT caller is allowed to hand out when creating or re-roling a team member, filtered server-side by the role-assignment ceiling (system groups: at or below the caller's own rank, inclusive; custom groups: only those whose permissions are a subset of the caller's). Build the member-create role dropdown from THIS list — the same rule is enforced on POST/PUT /business/technicians, so anything shown here is guaranteed to be accepted.
Input schema present but exposes no named parameters.
No output schema declared.
No examples provided.
listCrewCandidates Matching crew candidates for a job ~353
Matching crew candidates for a job RE-STAFFING candidates for a CONFIRMED, SCHEDULED job (not yet completed/archived) — any earlier or later stage returns 409 JOB_REQUEST_INVALID_TRANSITION. This is the pool of technicians who could REPLACE the current crew: the currently assigned lead and buddies are deliberately excluded (they are the status quo, not an option), so on a small roster an empty `leads` list is a normal answer, not an error. For pre-booking discovery ("who could take this job before it is confirmed?") use listJobRequestBookingWindows / listMatchingSlots / the time-segments grid instead. Candidates are matched and ranked by the smart-assignment engine — skills per crew slot, weekly availability, existing schedule, time off and travel are all checked; each carries a score breakdown (distance, travel, matched skills) plus the exact on-site session plan they would work. NOT a raw roster list (use GET /technicians for that). Returns the ranked feasible LEAD pool by default; pass include_buddies=true to also return per-slot buddy pools, include_vehicle=true to include the available-vehicle list. force_lead_id checks one specific technician: returns only that lead (with their crew combo) if feasible, else 409 JOB_REQUEST_NO_TECHNICIAN_AVAILABLE.
| Name | Type | Req | Description |
|---|---|---|---|
| force_lead_id | string | – | Check a specific technician as lead — returns only that lead if feasible, else 409 |
| id | string | yes | Job request ID or short_code |
| include_buddies | boolean | – | Also return buddy candidate pools |
| include_vehicle | boolean | – | Also return the available-vehicle list |
No output schema declared.
No examples provided.
listCustomers List customers ~303
List customers Returns a paginated, searchable directory of the business's customer records — the customer database (CRM) behind every booking and work order. Supports the `since`/`next_since` cursor for incremental sync into an external CRM, ERP or marketing tool.
| Name | Type | Req | Description |
|---|---|---|---|
| limit | integer | – | Page size (default 15, max 1000) |
| page | integer | – | Page number (default 1) |
| phone | string | – | EXACT caller lookup by phone in E.164 with the leading + (e.g. +16135550188). Separators are stripped, so '+1 (613) 555-0188' works; a bare national number without a country code is refused with PHON… |
| preferred_technician_id | string | – | Filter by preferred technician UUID |
| q | string | – | Fuzzy search over name, UID, phone, email |
| since | string | – | RFC3339 cursor for short-polling; echo back next_since from prior response |
| sort | string | – | Sort: created_at_desc|created_at_asc|name_asc|name_desc|uid_asc|uid_desc (default: created_at_desc) |
| status | string | – | Filter by status: active|inactive |
| tier | array | – | Filter by tier: regular|vip (repeatable) |
No output schema declared.
No examples provided.
listEmergencyCandidates Rank technicians for a P0 emergency insert ~817
Rank technicians for a P0 emergency insert Returns the technicians who could take the emergency job at the requested start, ranked FASTEST-ARRIVAL first (arrival beats route efficiency for a P0). The response also carries a historical `crew_recommendation` (median crew size on comparable completed jobs + mandatory disclaimer — AC-2). Booked technicians are still candidates — each entry carries the displacement preview (which lower-priority jobs would be pushed, per day) that committing to them would cause; total_moves=0 means a free slot. P0 jobs are never displaced; P1 only by a P0. ETA is estimated from the technician's start location (no live GPS). `after_hours_override=true` — the coordinator has phoned the technician — drops the non-working-day rejection AND each candidate's working-hours/time-off feasibility check; an affected candidate carries a per-technician TIME_OFF_OVERLAP warning instead. This is THE phone list for an after-hours insert: it ranks even on a day with no working hours once the flag is set. Feed the chosen technician_id into emergency/preview + emergency/commit. 409 NEXT STEPS: EMERGENCY_RESCHEDULE_NOT_ELIGIBLE — the job cannot be emergency-inserted; `data.failed_precondition` names which (not_quoted | archived | completed | not_p0 | smart_assign_unavailable): fix the job state or use a normal confirm. EMERGENCY_RESCHEDULE_CREW_UNSUPPORTED — crew jobs cannot use the emergency flow (v1, `data.crew_size` = lead + buddies): staff via confirm/reassign instead. EMERGENCY_RESCHEDULE_MULTIDAY_UNSUPPORTED — either a confirmed multi-day job (`data.session_count`/`data.session_dates`; use the normal reassign flow) or a single visit longer than the structural span bound, in which case `data.reason=visit_too_long` + `data.blockers[0]` (visit_minutes/max_minutes) name it — no remedy but a shorter visit. EMERGENCY_RESCHEDULE_NO_WORKING_DAY — the chosen date has no working hours (`data.business_timezone`/`data.requested_weekday`): pick a working day, or…
| Name | Type | Req | Description |
|---|---|---|---|
| after_hours_override | boolean | – | Place this P0 outside working hours / approved time-off — you have phoned the technician and they agreed. Drops the non-working-day rejection; the response then carries an AFTER_HOURS warning. Double… |
| emergency_job_id | string | – | UUID of the P0 job to place. Send this OR `job`, never both and never neither. |
| idempotency_key | string | – | Optional idempotency key (forwarded as the Idempotency-Key header). Reuse the same value when retrying so the operation runs at most once. |
| job | – | – | A job that does not exist yet — the wizard's read-only preview before anything is written. Send this OR `emergency_job_id`. |
| limit | integer | – | Max candidates to return (default 5, max 10). |
| mode | string | yes | Cascade mode each candidate's displacement preview assumes: overtime = displaced jobs stay same-day; next_day = overflow rolls to the next working day. |
| start_at | string | yes | Desired start — business-local wall clock. Seconds may be omitted and a space may replace the T; an offset is accepted only when it agrees with the business timezone (a disagreeing one is refused wit… |
No output schema declared.
No examples provided.
listJobRequestBookingWindows Booking availability ~111
Booking availability Real-time appointment availability from the scheduling engine: returns the bookable date + time-period windows given technician capacity, working hours and service-territory coverage. Call this before creating a job request and offer the customer ONLY the returned windows — it prevents unschedulable bookings.
| Name | Type | Req | Description |
|---|---|---|---|
| from | string | – | Start YYYY-MM-DD |
| to | string | – | End YYYY-MM-DD |
| x_timezone | string | yes | Customer IANA timezone (sent as the X-Timezone header) |
No output schema declared.
No examples provided.
listJobRequestChanges Poll for new & changed job requests (sync feed) ~488
Poll for new & changed job requests (sync feed) Keep an external system (your CRM, ERP or field-operations tool) in sync with bookings WITHOUT re-listing everything: returns the job requests (work orders) whose state changed (created, status transition, reschedule, soft-delete/archive) at or after the `since` cursor, ordered oldest-change-first (updated_at ASC). How to use it: (1) On your first poll OMIT `since` — the server primes the cursor at "now", returns no items and a `next_since`. (2) Store `next_since` and pass it as `since` on the next poll. (3) Apply each returned item to your store by UPSERTING on `id` (the server re-scans a ~5s safety window, so the same job may appear again — never blindly append). (4) If `has_more` is true the page filled to `limit` and more changes are already waiting — poll again immediately; otherwise wait your normal interval (e.g. 5–15s). This is NOT pagination — it is a time-keyed change feed. Use the paginated GET /job-requests for the initial bulk load, then this endpoint to stay live. Filters (status_keys, customer_id, …) narrow the feed to the slice you care about.
| Name | Type | Req | Description |
|---|---|---|---|
| customer_id | string | – | Only changes to this customer's jobs (UUID) |
| limit | integer | – | Max changes per poll (default 15, max 1000). If the page fills, has_more=true. |
| priority | string | – | Priority filter (p0|p1|p2|p3) |
| scheduled_from | string | – | Filter from (YYYY-MM-DD = start of that day in the business timezone, or RFC3339); range is [from, to) |
| scheduled_to | string | – | Filter to (YYYY-MM-DD = end of that day in the business timezone, or RFC3339), exclusive |
| since | string | – | RFC3339 cursor from the prior response's next_since. OMIT on the first poll to prime the cursor at server-now. |
| status_keys | string | – | Comma-separated status slugs — only surface changes to jobs in these statuses |
| technician_id | string | – | Only changes to jobs assigned to this technician (UUID) |
No output schema declared.
No examples provided.
listJobRequests List job requests ~416
List job requests Paginated list of the business's bookings (work orders) with dispatch-oriented filters: workflow status, customer, assigned technician, scheduled date range and free-text search over code/description. This is also the SCHEDULE query: combine technician_id + scheduled_from/scheduled_to to read one technician's agenda for a day or week (e.g. "what is Alex doing tomorrow"), or just the date range for the whole team's calendar.
| Name | Type | Req | Description |
|---|---|---|---|
| completed_from | string | – | Filter by completion time from (YYYY-MM-DD = start of that day in the business timezone, or RFC3339); range is [from, to). Counts jobs by when they were completed regardless of reschedules. |
| completed_to | string | – | Filter by completion time to (YYYY-MM-DD = end of that day in the business timezone, or RFC3339), exclusive |
| customer_id | string | – | Customer UUID |
| limit | integer | – | Page size |
| page | integer | – | Page number |
| priority | string | – | Priority filter (p0|p1|p2|p3) |
| q | string | – | Search short_code or description (case-insensitive, partial match) |
| scheduled_from | string | – | Filter from (YYYY-MM-DD = start of that day in the business timezone, or RFC3339); range is [from, to) |
| scheduled_to | string | – | Filter to (YYYY-MM-DD = end of that day in the business timezone, or RFC3339), exclusive |
| service_area_id | string | – | Service-area UUID (board zone filter) |
| sort | string | – | Sort key: created_at:desc (default) | created_at:asc | scheduled_at:asc | scheduled_at:desc | priority:asc (P0 first) | priority:desc |
| status | string | – | active (default) | archived | all |
| status_keys | string | – | Comma-separated status slugs |
| technician_id | string | – | Technician UUID |
No output schema declared.
No examples provided.
listJobTypes List job types ~91
List job types Returns the business's service catalog — the job/work-order types it offers (e.g. installation, repair, maintenance, inspection for trades like HVAC, plumbing, electrical, cleaning). Use it to discover the `job_type_id` accepted when booking a job request, or to render a services menu on your own site.
| Name | Type | Req | Description |
|---|---|---|---|
| status | string | – | Filter by status (active|inactive) |
No output schema declared.
No examples provided.
listMatchingSlots Matching time slots for a quoted job ~189
Matching time slots for a quoted job Bookable arrival-window slots for a quoted job, computed by the smart-assignment matching engine: each slot lists the technicians actually available to start then (skills, weekly availability, existing schedule, time off and travel all checked), with a per-technician match score. Use it to find and offer appointment times an agent or integration can then confirm (POST /job-requests/{id}/confirm with the slot's business_time.datetime). Same grid the end-customer's slot picker shows; slot width defaults to the business's arrival window — override via ?step_minutes (5–240). The job must be quoted first (the quote sets the visit duration the matcher schedules).
| Name | Type | Req | Description |
|---|---|---|---|
| id | string | yes | Job request ID (UUID or short_code) |
| step_minutes | integer | – | Slot step in minutes (default: business arrival window, 5–240) |
No output schema declared.
No examples provided.
listNearbyTechnicians Find nearby feasible technicians (job-less location query) ~214
Find nearby feasible technicians (job-less location query) Ranks who could serve a hypothetical visit at (lat,lng) starting `at` for `duration_minutes` — the engine applies the REAL hard filters (weekly hours, existing schedule, approved time-off, geographic service areas, optional skill floor) and returns candidates nearest-arrival first. ETA origin is each technician's start location (no live GPS). Use before creating a booking to propose realistic arrivals.
| Name | Type | Req | Description |
|---|---|---|---|
| at | string | – | Visit start (RFC3339, e.g. 2026-07-20T14:00:00Z; default now) |
| duration_minutes | integer | – | Visit length in minutes (default 60; 15–480) |
| lat | number | yes | Latitude of the service location |
| limit | integer | – | Max candidates (default 10, max 20) |
| lng | number | yes | Longitude of the service location |
| skill_ids | string | – | Comma-separated skill UUIDs to require/match |
No output schema declared.
No examples provided.
listServiceAreas List service areas ~87
List service areas Returns the business's geographic coverage: paginated service areas (service territories / coverage zones) used for routing jobs to the right teams. Discover the `service_area_id` values accepted on customer create/update here.
| Name | Type | Req | Description |
|---|---|---|---|
| limit | integer | – | Items per page (default 15, max 1000) |
| page | integer | – | Page number (default 1) |
No output schema declared.
No examples provided.
listSkillCategories List skill categories ~78
List skill categories Returns paginated skill categories — how the business groups technician qualifications by trade or specialty (e.g. HVAC, plumbing, electrical) — ordered alphabetically.
| Name | Type | Req | Description |
|---|---|---|---|
| limit | integer | – | Page size (default: 15, max: 1000) |
| page | integer | – | Page number (default: 1) |
No output schema declared.
No examples provided.
listSkills List all skills ~89
List all skills Returns the flat list of all active technician skills / qualifications for the current business — the vocabulary the dispatch engine uses for skill-based matching when assigning technicians and crews. Use it to discover the skill UUIDs accepted in `skill_ids` when creating a job request. (For a category-grouped view, use GET /skill-categories and GET /skill-categories/{id}/skills.)
Input schema present but exposes no named parameters.
No output schema declared.
No examples provided.
listSkillsByCategory List skills in a category ~113
List skills in a category Returns paginated skills (technician qualifications/certifications) belonging to the given trade/specialty category, ordered alphabetically. The `members` field on each skill is the count of active technicians currently holding it — a quick capacity check per capability.
| Name | Type | Req | Description |
|---|---|---|---|
| id | string | yes | Skill category ID (UUID) |
| limit | integer | – | Page size (default: 15, max: 1000) |
| page | integer | – | Page number (default: 1) |
No output schema declared.
No examples provided.
listTechnicians List technicians ~219
List technicians Returns the field workforce roster: paginated technicians (field workers / engineers) with status, assignment tier (lead, buddy, float), skills and crew relations — the people the dispatch engine schedules onto jobs. Discover the `preferred_technician_id` accepted on customer records here. Supports the `since` cursor for incremental workforce sync.
| Name | Type | Req | Description |
|---|---|---|---|
| assignment_tier | string | – | Filter by assignment tier (lead, buddy, float) |
| keyword | string | – | Search by full name, email, phone, or address |
| limit | integer | – | Items per page (default 15, max 1000) |
| page | integer | – | Page number (default 1) |
| since | string | – | RFC3339 cursor for short-polling; echo back next_since from prior response |
| sort | string | – | Sort: created_at_desc|created_at_asc|name_asc|name_desc (default: created_at_desc) |
| status | string | – | Filter by status (active, onboarding, deactive) |
No output schema declared.
No examples provided.
listTechnicianSkills List skills for a technician ~127
List skills for a technician Returns paginated skills assigned to the technician. By default (`eligible_only` omitted or `true`) only active skills are returned — pass `eligible_only=false` to include inactive skills.
| Name | Type | Req | Description |
|---|---|---|---|
| eligible_only | boolean | – | true (default) = active skills only; false = all assigned skills including inactive |
| id | string | yes | Technician ID — business_user_profiles.id (UUID) |
| limit | integer | – | Page size (default: 15, max: 1000) |
| page | integer | – | Page number (default: 1) |
No output schema declared.
No examples provided.
listTechnicianTimeOff List time off for a specific technician ~214
List time off for a specific technician Returns the technician's time-off records (pending, approved, rejected, cancelled), paginated, optionally bounded by start_date/end_date (YYYY-MM-DD, inclusive overlap) and status. Read this before recording a new block (overlaps are refused) and to see whether an absence is already recorded before `commitAbsenceResolve`.
| Name | Type | Req | Description |
|---|---|---|---|
| end_date | string | – | Filter by end date (YYYY-MM-DD) |
| id | string | yes | Technician ID |
| keyword | string | – | Search reason (case-insensitive substring) |
| limit | integer | – | Items per page (default 15) |
| page | integer | – | Page number (default 1) |
| since | string | – | RFC3339 cursor for short-polling; echo back next_since from prior response |
| start_date | string | – | Filter by start date (YYYY-MM-DD) |
| status_ids | array | – | Filter by status (multi: pending|approved|rejected|cancelled) |
No output schema declared.
No examples provided.
listVehicles List vehicles ~156
List vehicles Returns the business's fleet: paginated service vehicles (vans/trucks) with operational status (idle, on job, maintenance) — the fleet inventory behind crew carpooling and job mobilization. Supports the `since` cursor for incremental fleet sync.
| Name | Type | Req | Description |
|---|---|---|---|
| keyword | string | – | Search by name, brand, model, or plate number |
| limit | integer | – | Items per page (default 15, max 1000) |
| page | integer | – | Page number (default 1) |
| since | string | – | RFC3339 cursor for short-polling; echo back next_since from prior response |
| status | string | – | Filter by status (inactive, idle, on_job, maintenance) |
No output schema declared.
No examples provided.
How do I install the com.crisphive/mcp server?
com.crisphive/mcp runs locally as an npm package, launched with npx -y @crisphive/mcp. Ready-made configuration for Claude, Cursor, VS Code, Codex and 5 more is on this page, copied from each client's own documentation.
npm · @crisphive/mcp
claude mcp add com-crisphive-mcp -- npx -y @crisphive/mcp
What is the com.crisphive/mcp server?
com.crisphive/mcp is listed in the public MCP registry as com.crisphive/mcp. Field operations on a deterministic solver, run jobs, crews & fleet from Claude or ChatGPT. This page covers its npm package (@crisphive/mcp).
Is the com.crisphive/mcp server safe to use?
com.crisphive/mcp scores 81 out of 100 on VerifyMCP. We found no known CVEs affecting it as of 5 November 2026. It declares no install or post-install scripts. That is a record of what we were able to check automatically, not an endorsement. The category breakdown on this page shows every signal behind the number, including the ones we could not confirm.
What tools does the com.crisphive/mcp server expose?
com.crisphive/mcp exposes 67 tools: bookAndConfirmJobRequest, commitAbsenceResolve, commitEmergencyReschedule, commitJobRequestMove, confirmJobRequest, and 62 more. Their descriptions and schemas cost roughly 22,238 tokens of context every time the server is loaded.
Is the com.crisphive/mcp server still maintained?
com.crisphive/mcp is still listed as active in the MCP registry. We last reached this channel on 5 November 2026. Those dates come from our own scans of the registry and the channel itself, not from anything the publisher announced.
What licence is the com.crisphive/mcp server under?
com.crisphive/mcp declares the MIT licence, which is OSI-approved. That covers the source only, and says nothing about the cost of any service it calls.