en
Team & Fleet›Add a technician

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. 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 + coordinates from the body.

Arguments

Idempotency-Keystringheaderoptional
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 body returns 422 IDEMPOTENCY_KEY_REUSE.
▾addressobjectbodyoptional
Home address (the day-start point when start_location_type=home).
citystringbodyoptional
City / locality.
countrystringbodyoptional
Country (free-form or ISO code).
formattedstringbodyoptional
Full display string; when set it wins over the discrete parts for display.
linestringbodyoptional
Street line 1.
line2stringbodyoptional
Street line 2 (unit, suite).
postal_codestringbodyoptional
Postal / ZIP code.
statestringbodyoptional
State / province / region.
assignment_tierenumbodyoptional
Crew tier the matching engine assigns by: lead (can head a job), buddy (crew helper), float (excluded from auto crew-assign).
buddy_idsarray<string>bodyoptional
Buddies of this technician (set when creating a lead). Optional; max 50 technician ids.
business_group_idstringbodyrequired
Role group for the new member. Discover IDs via GET /permission/groups (Owner/Administrator groups are rejected in sandbox mode).
emailstringbodyoptional
Email address. At least one of phone/email is required (identity resolution key).
full_namestringbodyrequired
The person's full display name. Required; max 255 chars.
job_titlestringbodyoptional
Display title (e.g. "Senior HVAC Technician").
join_datestringbodyoptional
First working day (YYYY-MM-DD).
lead_idsarray<string>bodyoptional
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.
notifybooleanbodyoptional
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. Set false for bulk imports so seeding a roster does not text everybody at once.
phonestringbodyoptional
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 to guess the country from. At least one of phone/email is required (identity resolution key).
service_area_idsarray<string>bodyoptional
Service areas to assign the technician to. Optional; max 50. Discover via GET /service-areas.
start_location_latnumberbodyoptional
Explicit day-start latitude in decimal degrees (-90..90); when set it wins over the address geocode.
start_location_longnumberbodyoptional
Explicit day-start longitude in decimal degrees (-180..180); when set it wins over the address geocode.
start_location_typeenumbodyoptional
Where the technician starts their day: home (their address) or office (the business location). Drives the engine's travel estimates.
POST/v1/technicians
curl -X POST "https://api.crisphive.com/v1/technicians" \
  -H "Authorization: Bearer chsk_test_4eC8xQ9mZ2pL7Ka0rT" \
  -H "Content-Type: application/json" \
  -d '{
  "address": {
    "city": "San Francisco",
    "country": "US",
    "formatted": "123 Market Street, San Francisco, CA 94103",
    "line": "123 Market Street",
    "line2": "Suite 200",
    "postal_code": "94103",
    "state": "CA"
  },
  "assignment_tier": "lead",
  "buddy_ids": [
    "9b2f6c3e-1a4d-4f0a-8f2e-7c5d1b3a9e01"
  ],
  "business_group_id": "9b2f6c3e-1a4d-4f0a-8f2e-7c5d1b3a9e01",
  "email": "jane.doe@example.com",
  "full_name": "Jane Cooper",
  "job_title": "Sample title",
  "join_date": "2026-07-02",
  "lead_ids": [
    "9b2f6c3e-1a4d-4f0a-8f2e-7c5d1b3a9e01"
  ],
  "notify": true,
  "phone": "+14155550142",
  "service_area_ids": [
    "9b2f6c3e-1a4d-4f0a-8f2e-7c5d1b3a9e01"
  ],
  "start_location_lat": 1,
  "start_location_long": 1,
  "start_location_type": "home"
}'
Request body
{
"address": {
"city": ,
"country": ,
"formatted": ,
"line": ,
"line2": ,
"postal_code": ,
"state":
},
"assignment_tier": ,
"buddy_ids": [
],
"business_group_id": ,
"email": ,
"full_name": ,
"job_title": ,
"join_date": ,
"lead_ids": [
],
"notify": ,
"phone": ,
"service_area_ids": [
],
"start_location_lat": ,
"start_location_long": ,
"start_location_type":
}

Responses