Roldesk
Log In

Developers

Roldesk REST API

Read and write your workspace's field-service data over a clean, versioned REST API. Every request is authenticated with a Personal Access Token and strictly scoped to your organization.

Quickstart

Create a token under Settings → Developer (owner/admin, Professional plan), then verify it:

curl https://www.roldesk.com/api/v1/me \
  -H "Authorization: Bearer rk_live_…"

List your work orders:

curl "https://www.roldesk.com/api/v1/work-orders?limit=25" \
  -H "Authorization: Bearer rk_live_…"

Authentication

Pass your token as a Bearer credential on every request: Authorization: Bearer rk_live_…. Tokens are shown once at creation — store them securely. They can be created and revoked by an owner or admin under Settings → Developer, and are available on the Professional plan. The API is server-to-server (no cookies, no browser CORS credentials).

Scopes

Each token is granted a subset of scopes. A scope is {group}:{read|write}. A token can never exceed what your plan allows.

GroupCovers
work-ordersWork orders and their tasks, parts, labor, and completion
crmCustomers (accounts), contacts, leads
salesQuotes and invoices
contractsService contracts
assetsEquipment, parts, tools, vehicles, warehouses
projectsProjects and their links
schedulingAppointments / calendar events
preventivePreventive-maintenance schedules
teamMembers and roles (read-only)
webhooksRegister and manage webhook endpoints

Pagination

Lists are cursor-paginated. Pass limit (1–100, default 25) and starting_after (the previous response's next_cursor).

{
  "data": [ { "object": "work_order", "id": "…", … } ],
  "has_more": true,
  "next_cursor": "eyJ…"
}

Most lists also accept allow-listed filters such as status, account_id, and updated_since.

Writes, idempotency & concurrency

Creates accept an Idempotency-Key header — retrying with the same key returns the original result instead of creating a duplicate. Updates accept expected_updated_at for optimistic concurrency; a stale value returns 409.

curl -X POST https://www.roldesk.com/api/v1/customers \
  -H "Authorization: Bearer rk_live_…" \
  -H "Idempotency-Key: create-acme-2026-08" \
  -H "Content-Type: application/json" \
  -d '{"name": "Acme Corp", "email": "ops@acme.com"}'

Errors

Errors use a consistent envelope with the right HTTP status:

{ "error": { "type": "…", "code": "…", "message": "…", "param": "…" } }
400 / 422Malformed request or validation error
401Missing, invalid, revoked, or expired token
403Token lacks the required scope, or the plan doesn't include API access
404No such resource in your workspace
409Optimistic-concurrency conflict (stale expected_updated_at)
429Rate limit exceeded

Webhooks

Instead of polling, subscribe to events and we'll POST them to your server as they happen. Add an endpoint under Settings → Developer (or via the API for Zapier-style integrations), choose the events you care about, and store the signing secret we show once.

Each delivery is a JSON POST with these headers:

Roldesk-Event:      contract.renewed
Roldesk-Delivery:   <delivery id>
Roldesk-Signature:  t=<unix_ts>,v1=<hex hmac-sha256>

The body is a thin event — fetch the full object from the REST API using its id:

{ "id": "…", "type": "contract.renewed", "created": "2026-08-10T12:00:00Z",
  "data": { "object": "contract", "id": "…" } }

Verify the signature before trusting a delivery (Node):

import crypto from "crypto";

function verify(rawBody, header, secret) {
  const parts = Object.fromEntries(header.split(",").map(p => p.split("=")));
  const expected = crypto.createHmac("sha256", secret)
    .update(`${parts.t}.${rawBody}`).digest("hex");
  return crypto.timingSafeEqual(Buffer.from(parts.v1), Buffer.from(expected));
}

Failed deliveries retry with backoff (up to 6 attempts); an endpoint that keeps failing is auto-disabled. Available events:

customer.createdcustomer.updatedcustomer.deletedcontact.createdcontact.updatedcontact.deletedwork_order.createdwork_order.updatedwork_order.deletedinvoice.createdinvoice.updatedinvoice.deletedquote.createdquote.updatedquote.deletedcontract.createdcontract.updatedcontract.deletedcontract.renewedcontract.expired

Zapier & no-code: use the REST Hook pattern — your Zap subscribes with POST /api/v1/webhooks (a token with webhooks:write) and unsubscribes with DELETE /api/v1/webhooks/{id}.

Endpoint reference

MethodsPathScope
GET/work-orders · /work-orders/{id}work-orders:read
POST · PATCH · DELETE/work-orders · /work-orders/{id}work-orders:write
GET/customers · /customers/{id}crm:read
POST · PATCH · DELETE/customers · /customers/{id}crm:write
GET/contacts · /contacts/{id}crm:read
POST · PATCH · DELETE/contacts · /contacts/{id}crm:write
GET/leads · /leads/{id}crm:read
POST · PATCH · DELETE/leads · /leads/{id}crm:write
GET/invoices · /invoices/{id}sales:read
POST · PATCH · DELETE/invoices · /invoices/{id}sales:write
GET/quotes · /quotes/{id}sales:read
POST · PATCH · DELETE/quotes · /quotes/{id}sales:write
GET/contracts · /contracts/{id}contracts:read
POST · PATCH · DELETE/contracts · /contracts/{id}contracts:write
GET/projects · /projects/{id}projects:read
GET/appointments · /appointments/{id}scheduling:read
GET/preventive-schedules · …/{id}preventive:read
GET/assets/equipment · /assets/parts · /assets/tools · /assets/vehicles · /assets/warehousesassets:read
GET/members · /members/{id}team:read
GET/roles · /roles/{id}team:read
GET/webhooks · /webhooks/{id}webhooks:read
POST · DELETE/webhooks · /webhooks/{id}webhooks:write

The complete machine-readable definition lives at /api/v1/openapi.json (OpenAPI 3.1) — import it into Postman, Insomnia, or your codegen tool.

New to it? Step-by-step guides live in the Help Center — getting started, webhooks, Zapier, and common recipes.