Read and add people, request time off, run reports and get every event as a signed webhook — the same rules as the app.
An admin makes an API key in Settings → API & webhooks: read only, or read and write. A key acts as the admin who made it, so every change goes through the same checks, notifications, workflows and audit log as the app. Only a fingerprint of the key is stored — copy it when it's shown.
curl https://staffvelo.com/api/v1/me -H "Authorization: Bearer sv_api_…"
Requests and answers are JSON. Errors are { "error": "…" } in plain words, with the usual status codes. Each key may make 600 requests every 10 minutes (then 429).
Base address: https://staffvelo.com/api/v1 (your workspace address works too).
| Method | Path | What it does |
|---|---|---|
GET | /me | The workspace and the key's access |
GET | /events | The events you can subscribe to |
GET | /people?limit&status&email | People, newest first (active, left or all) — no pay or ID fields |
GET | /people/{id} | One person |
POST | /people | Add a person: name, email, job_title, department, start_date, send_invite |
GET | /time-off?status&from&to&limit | Time off, newest first |
POST | /time-off | Request time off: employee_email (or employee_id), type, from, to, note |
GET | /reports/fields | What Custom reports can show |
POST | /reports/run | Run a report: source, columns, filters, group_by, sort |
GET | /webhooks | Your webhooks |
POST | /webhooks | Subscribe: url (https), event or events — the answer has the signing secret |
DELETE | /webhooks/{id} | Unsubscribe |
curl -X POST https://staffvelo.com/api/v1/time-off -H "Authorization: Bearer sv_api_…" -H "Content-Type: application/json" -d '{"employee_email":"arta@acme.com","type":"Holiday","from":"2026-12-22","to":"2026-12-31"}'
Add a webhook in Settings or with POST /webhooks. Staffvelo POSTs each event you chose as JSON, from the moment it happens:
{ "id": "8f1c…", "event": "timeoff.approved", "occurred_at": "2026-11-02T09:15:00Z",
"workspace": { "slug": "acme", "name": "Acme" },
"data": { "person": { "name": "Arta Berisha", "email": "…", "dept": "Engineering" },
"manager": { "name": "Amara Okafor" },
"timeoff": { "type": "Holiday", "from": "2026-12-22", "to": "2026-12-31", "days": 6 } } }
Events: employee.added, employee.left, timeoff.requested, timeoff.approved, timeoff.declined, expense.submitted, card.created, card.moved, request.created — and workflow.webhook from a workflow's “Send to a webhook” step.
Check that it really came from Staffvelo: the X-Staffvelo-Signature header is sha256= and the HMAC-SHA256 of the raw body with your webhook's secret.
const crypto = require("crypto");
const expected = "sha256=" + crypto.createHmac("sha256", process.env.STAFFVELO_WEBHOOK_SECRET).update(rawBody).digest("hex");
const ok = crypto.timingSafeEqual(Buffer.from(expected), Buffer.from(req.headers["x-staffvelo-signature"] || ""));
Answer with any 2xx within 8 seconds. Only public https addresses can receive webhooks; after 20 failures in a row a webhook switches itself off and admins see why.
Staffvelo is also an MCP server at https://<your-workspace>.staffvelo.com/mcp: ChatGPT and claude.ai connect with Sign in with Staffvelo (OAuth 2.1), and Claude Code, Cursor or VS Code with a personal access key. It's read-only and each person's AI sees only what they can see. An admin switches it on in Settings → AI agents.
No card, no sales call. Your workspace is live in under a minute.