GraphQL API Reference
Queries and mutations for jobs, calendar events, charges, invoices, transactions, and users. Since introspection is enabled on the playground, this page focuses on practical usage patterns — the playground is the authoritative source for the full schema.
Open GraphQL Playground →Querying Jobs
The jobs query is the primary way to fetch job data. It supports filtering, pagination, sorting, and lazy-loading of related data via the resolve parameter.
query ($filter: JobsFilter, $skip: Int, $limit: Int, $sort: String, $resolve: [String]) {
jobs(
filter: $filter
skip: $skip
limit: $limit
sort: $sort
resolve: $resolve
) {
total
skipped
limited
jobs {
id
code
stage
state
currency
total
createdAt
}
}
} ?zone=your-zone-id. Without a zone, the query uses the zone resolved from your auth context.
Job Fields
Key fields on the Job type. Use the playground to explore the complete schema.
| Field | Type | Description |
|---|---|---|
| id | String | UUID — use for all CRUD operations and references. |
| code | String | Human-readable identifier in the format XXXX-XXX-XXX. The first 4 characters indicate the zone. Use id for programmatic operations. |
| stage | String | Workflow stage: "lead" | "estimate" | "booking" | "invoice" | "cancelled" |
| state | String | "open" | "closed" | "archived" | "deleted" |
| total | Int | Sum of all charges in cents, including taxes and discounts. |
| taxTotal | Int | Total taxes in cents. |
| paidTotal | Int | Amount paid in cents. |
| pendingTotal | Int | Outstanding balance in cents. |
| damageTotal | Int | Damage charges in cents. |
| discountTotal | Int | Total discounts in cents. |
| discountedSubTotal | Int | Sub-total after discounts, in cents. |
| currency | String | ISO 4217 currency code, e.g. "USD", "CAD". |
| createdAt | Int | Unix timestamp (seconds) when the job was created. |
| updatedAt | Int | Unix timestamp (seconds) of last update. |
| archivedAt | Int | Unix timestamp when archived, or null. |
| closedAt | Int | Unix timestamp when closed, or null. |
| timeline | String | Preferred move date in YYYY-MM-DD format. |
| users | Array | Customer, crew, and agent assignments. Requires resolve: ["users"]. |
| locations | Array | Origin, destination, and dock locations. Requires resolve: ["locations"]. |
| discounts | Array | Applied discounts. Requires resolve: ["discounts"]. |
Filtering & Pagination
skip
Number of records to skip. Default: 0. Use with limit for pagination.
limit
Max records to return. Default: 50. Use total in the response to calculate pages.
sort
Format: "field:asc" or "field:desc". Default: "createdAt:desc". Supports: createdAt, updatedAt, id, stage, closedAt, currency.
Filter fields
| Filter field | Description |
|---|---|
| jobIds | Array of job UUIDs. Returns only jobs with these IDs. |
| code | Job short code, e.g. "TLED-GVQ-XZN". |
| stage | Filter by stage: "lead", "estimate", "booking", "invoice", "cancelled". |
| state | Filter by state: "open", "closed", "archived", "deleted". |
| search | Full-text search across customer name, email, phone, job stage, and job code. |
| userSearch | Find all jobs for a specific user. Pass { userId, role } — role options: "customer", "Crew Member", "Crew Lead". |
| zoneDir | Zone direction: "lte" (self + descendants), "gte" (self + ancestors), "eq" (exact zone only). Default: "lte". |
| createdAfter | Unix timestamp (seconds). Returns jobs created after this time. |
| createdBefore | Unix timestamp (seconds). Returns jobs created before this time. |
User search example
// Variables:
{
"filter": {
"userSearch": {
"userId": "354dfbd0-8d1b-11ed-9001-89ed3e4c1f5d",
"role": "customer"
}
},
"limit": 20,
"sort": "createdAt:desc"
} Resolve — Lazy-loaded Fields
For performance, the users, locations, and discounts fields on jobs are not populated by default. Querying them without resolve always returns null. Pass the field names you want populated in the resolve array:
// Variables:
{
"resolve": ["users", "locations", "discounts"]
}
// Query:
query ($resolve: [String]) {
jobs(resolve: $resolve) {
jobs {
users {
user {
givenName
familyName
email
phone
}
role
}
locations {
location {
addressLineOne
city
countryJurisdiction
areaCode
coordinates { latitude longitude }
}
locationType
}
}
}
} resolve entirely and fetch related data separately by ID.
Creating Jobs
The createJob mutation creates a new job. The only required field is stage.
Minimal example
mutation {
createJob(stage: "lead") {
id
code
}
} With an existing customer
mutation {
createJob(
stage: "lead"
users: [
{
userId: "354dfbd0-8d1b-11ed-9001-89ed3e4c1f5d"
role: "customer"
}
]
) {
id
code
}
} For creating jobs with full lead data (name, phone, address, move date), use the Intake API — it handles customer deduplication, geocoding, and zone routing automatically.
Updating Jobs
The updateJobs mutation accepts an array of update inputs — you can update multiple jobs in one request. The only required field is jobId.
mutation ($updateJobs: [UpdateJobInput]) {
updateJobs(updateJobs: $updateJobs) {
isSuccess
}
}
// Variables:
{
"updateJobs": [
{
"jobId": "7af1bc10-e356-11ef-8bf8-7dd6e69e92c7",
"stage": "booking",
"timeline": "2026-09-15"
}
]
} Adding and removing users
{
"updateJobs": [
{
"jobId": "7af1bc10-...",
"addUsers": [
{ "userId": "user-uuid", "role": "customer" }
],
"removeUsers": ["other-user-uuid"]
}
]
} Adding and removing locations
{
"updateJobs": [
{
"jobId": "7af1bc10-...",
"addLocations": [
{
"locationId": "location-uuid",
"locationType": "start" // "start" | "end" | "dock"
}
],
"removeLocations": ["other-location-uuid"]
}
]
} Charges
All charges are associated with a calendar event. Create the event first, then add charges to the job referencing that event's ID.
Add charge from an existing product
{
"updateJobs": [
{
"jobId": "7af1bc10-...",
"newCharges": {
"charges": [
{
"eventId": "event-uuid",
"productId": "product-uuid",
"quantity": 1
}
],
"userId": "customer-user-uuid"
}
}
]
} Add a custom charge (no product ID needed)
{
"updateJobs": [
{
"jobId": "7af1bc10-...",
"newCharges": {
"charges": [
{
"eventId": "event-uuid",
"productName": "Long distance surcharge",
"currency": "USD",
"amount": 15000, // in cents = $150.00
"quantity": 1
}
]
}
}
]
} Remove charges
{
"updateJobs": [
{
"jobId": "7af1bc10-...",
"removeCharges": ["charge-uuid-1", "charge-uuid-2"]
}
]
} Calendar Events
Calendar events represent appointments, moves, estimates, and invoiceable service windows. Many operations (charges, invoices) require an event ID. Events have a type and a status lifecycle.
Create an event
mutation ($calendarEvents: [createCalendarEventInput]!) {
createCalendarEvent(calendarEvents: $calendarEvents) {
events { id }
}
}
// Variables:
{
"calendarEvents": [
{
"title": "Move day",
"type": "move",
"jobId": "7af1bc10-...",
"status": "required",
"start": 1756396800, // Unix timestamp (seconds)
"end": 1756411200
}
]
} | Event type | Use case |
|---|---|
| move | A scheduled moving appointment |
| estimating | An on-site or virtual estimate appointment |
| virtualEstimate | A virtual (video/phone) estimate — triggers virtual estimate flow |
| storage | A storage-related service event |
Update an event (mark as completed, set times)
mutation ($edit: editCalendarEventInput!, $ids: [String!]) {
editCalendarEvent(edit: $edit, ids: $ids)
}
// Variables:
{
"ids": ["event-uuid"],
"edit": {
"status": "completed",
"start": 1756396800,
"end": 1756411200
}
} Remove an event
mutation ($ids: [String!]!) {
removeCalendarEvent(ids: $ids)
}
// Variables:
{ "ids": ["event-uuid"] } Invoices
Invoices are created from one or more calendar events. Only events that are both scheduled (have start and end times) and in completed status can be invoiced.
mutation ($invoices: [CreateInvoiceInput!]!) {
createInvoice(invoices: $invoices) {
invoices { id }
}
}
// Variables:
{
"invoices": [
{
"eventIds": ["event-uuid-1", "event-uuid-2"]
}
]
} The returned invoice id is needed when creating transactions (payments).
Transactions
Transactions represent payments, refunds, and deposits. Before creating a transaction, query the available payment types on the zone.
Step 1 — Query payment types
query {
getConfigValues(keys: ["payment-type.*"]) {
id
value // JSON string containing name, enabled, etc.
}
} Step 2 — Create a transaction
mutation ($amount: Int!, $customerId: String!, $jobId: String!,
$invoiceId: String, $type: TransactionType!,
$paymentTypeId: String!, $stage: TransactionStage,
$metadata: Metadata, $disableSendReceipt: Boolean) {
createTransaction(
amount: $amount
customerId: $customerId
jobId: $jobId
invoiceId: $invoiceId
type: $type
paymentTypeId: $paymentTypeId
stage: $stage
metadata: $metadata
disableSendReceipt: $disableSendReceipt
) {
transaction { id }
}
}
// Variables:
{
"amount": 35000, // in cents = $350.00
"jobId": "7af1bc10-...",
"customerId": "customer-user-uuid",
"invoiceId": "invoice-uuid", // required for "payment" and "refund"
"type": "payment", // "payment" | "refund" | "deposit"
"stage": "paid",
"paymentTypeId": "payment-type-config-id",
"disableSendReceipt": false,
"metadata": { "origin": "my-integration" }
} •
payment — requires an invoiceId•
refund — requires an invoiceId•
deposit — does not require an invoiceId Config Values
Zone configuration drives many aspects of MoveRight's behavior — business hours, payment types, branding, autodialer settings, and more. You can read config values via the getConfigValues query.
// Get all payment types for the zone
query {
getConfigValues(keys: ["payment-type.*"]) {
id
value // JSON string — parse to get name, enabled, etc.
}
}
// Get a specific config value
query {
getConfigValues(keys: ["branding.companyName"]) {
id
value
}
} The keys input supports wildcards via *. The value field is always a JSON string — parse it to get the actual value.
Explore the full schema
Introspection is enabled. The playground is the authoritative reference for every available type, field, query, and mutation.
Open GraphQL Playground →