Skip to main content
Documentation

Staff

staff.get

Get one staff member's record, availability and live work
Read-onlyRead budget

REST

Shipping
POST /api/v1/staff/get

MCP tool

Live
staff.get

Exposed on: REST API · Shop MCP server · Claude connector · Dash (in-app copilot) · Zapier. Part of the Staff domain.

Operating contract

One person in full: their skills, their certifications with expiry dates, the recurring weekly availability they work, the time off they have booked, and the jobs currently on their plate.

availability is the roster they normally work — weekday plus hours. Somebody with NO recurring availability on file is treated as available by every scheduling path in the product rather than as unavailable, because 'we have not written their hours down' is not the same as 'they do not work'. Say which of the two you are looking at.

time_off is the approved and pending blocks that touch the near future. A PENDING block is a request nobody has answered, and planning against it as if it were free is how somebody comes back from a day off to a booked car.

certifications carry an expires_on. A lapsed certificate is not a technicality — services can be restricted to certified installers, so an expiry silently removes somebody from the shop's capacity. staff.certifications is the read that surfaces those before they bite.

jobs is the live queue, which is the honest answer to 'is this person free'.

Refuses when no staff profile in this shop has that id, which includes somebody who has left.

Who may call it

Permission
shop.manageThe caller must hold shop.manage at the ACT level. A read-only dashboard grant on the same section is refused.
Plan
Every planNo plan gate. Available on every Service VIN plan.
Retries
naturalNaturally idempotent — running it twice leaves the same world as running it once. A retrying integration needs no key.
Rate class
readCounted against the read budget — the widest of the four.

Input

FieldTypeDescription
staff_idrequiredstringuuid

The staff profile id, as returned by staff.list or jobs.staff.

Output

FieldTypeDescription
idstring

namestring

bookableboolean

role_namestring | null

login_statestring

skillsstring[]

certificationsobject[]

certifications[].codestring

certifications[].namestring

certifications[].issuerstring | null

certifications[].issued_onstring | null

certifications[].expires_onstring | null

availabilityobject[]

availability[].weekdaynumber | null

availability[].start_timestring | null

availability[].end_timestring | null

time_offobject[]

time_off[].starts_atstring | null

time_off[].ends_atstring | null

time_off[].notestring | null

jobsobject[]

jobs[].idstring

jobs[].titlestring | null

jobs[].stagestring

jobs[].scheduled_startstring | null

Examples

Built from this capability's own schema — required fields and the ones carrying a default, and nothing invented. Paste one and it validates.

curl
export SERVICEVIN_API_KEY=svk_live_…

curl -X POST https://www.servicevin.com/api/v1/staff/get \
  -H "Authorization: Bearer $SERVICEVIN_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{"staff_id":"9b2f1c6e-4a77-4d2b-9f31-0f1c9a8e5d20"}'

TypeScript (fetch)
const res = await fetch("https://www.servicevin.com/api/v1/staff/get", {
  method: "POST",
  headers: {
    Authorization: `Bearer ${process.env.SERVICEVIN_API_KEY}`,
    "Content-Type": "application/json",
  },
  body: JSON.stringify({
    "staff_id": "9b2f1c6e-4a77-4d2b-9f31-0f1c9a8e5d20"
  }),
});

// Success and failure are both envelopes. Switch on error.code, never
// on error.message — the codes are stable, the messages are for people.
const payload = await res.json();
if (!res.ok) throw new Error(payload.error.code);
const data = payload.data;

Python (requests)
import os, requests

res = requests.post(
    "https://www.servicevin.com/api/v1/staff/get",
    headers={"Authorization": f"Bearer {os.environ['SERVICEVIN_API_KEY']}"},
    json={
    "staff_id": "9b2f1c6e-4a77-4d2b-9f31-0f1c9a8e5d20"
},
    timeout=30,
)
payload = res.json()
if not res.ok:
    raise RuntimeError(payload["error"]["code"])
data = payload["data"]

MCP tools/call — https://www.servicevin.com/api/mcp
{
  "jsonrpc": "2.0",
  "id": 1,
  "method": "tools/call",
  "params": {
    "name": "staff.get",
    "arguments": {
      "staff_id": "9b2f1c6e-4a77-4d2b-9f31-0f1c9a8e5d20"
    }
  }
}

Refusals

The four gates run in this order on every surface, and the order is not arbitrary — see Authentication.

StatusCodeWhen
404not_foundThe id is unknown, or the feature is not enabled for this account. Deliberately the same answer for both.
403forbiddenThis login does not hold shop.manage.
422validation_errorAn argument was wrong. The message names the field.
429rate_limitedToo many read calls. Back off and retry.
500internal_errorSomething failed on our side. Nothing was changed.