Skip to content

Job management ​

A job (JobState) is one production order on the shop floor: the counterpart of a JDF job ticket. The records around it all point back at it by jobId:

text
JobState
├── ComponentState    the printed parts (cover, text block, insert …)
├── OperationState    the production steps (printing, folding, binding …)
└── MilestoneState    dates you track (proof sent, plates ready …)

Operations and milestones can also belong to a specific component through componentId. Related jobs can be collected in a job group (JobGroupState). Components are covered in Components and media, and orders and estimates that create jobs in Orders and commerce.

Job status ​

JobState.status is a JobStatus. The values are:

ValueMeaning
DRAFTJob created but not yet confirmed; the default for new jobs
RFQAwaiting cost estimation
CONFIRMEDOrder confirmed, ready for production
PREPRESSArtwork preparation and plate-making
PRESSCurrently printing
POSTPRESSFinishing operations (binding, cutting, etc.)
PACKINGPacking for shipment
SHIPPEDDispatched to customer
COMPLETEDDelivered and closed
WAITINGOn hold pending external action
CANCELLEDJob cancelled
EXCEPTIONRequires attention due to error

The status is checked against this set when you save a job.

You change the status with updateJob (below). There is no separate transition mutation.

Create a job ​

name and quantity are required. Set externalId to the job's reference in your own system so you can find it again.

graphql
mutation CreateJob {
  createJob(
    input: {
      name: "Spring catalogue 2027"
      quantity: 5000
      externalId: "MIS-2026-0042"
      jobNumber: "J-10042"
      dueAt: "2026-10-15T16:00:00Z"
      priority: 5
      tags: ["catalogue", "repeat-customer"]
      billingCustomerId: "cus_01M0R2496SFANSZFKWPYW17V0J"
      description: "A4 portrait, 48 pages plus cover"
    }
  ) {
    job {
      id
      jobNumber
      status
    }
    errors {
      path
      message
    }
  }
}

A new job starts as DRAFT unless you pass status. priority defaults to 0; a higher number sorts first when you sort by PRIORITY descending. billingCustomerId and deliveryCustomerId link the job to customers.

Read a job ​

graphql
query JobDetails {
  getJob(id: "job_01M0R249JMETNBM1Z7466MXGZD") {
    id
    jobNumber
    name
    status
    quantity
    dueAt
    scheduledStartAt
    actualStartAt
    actualEndAt
    billingCustomer {
      id
      name
    }
    components {
      id
      name
      kind
      quantity
    }
    operations {
      id
      name
      kind
      status
      sortOrder
    }
    milestones {
      id
      name
      dueAt
      isCompleted
    }
  }
}

Use getJobBy(externalId:) to look a job up by your own reference.

List and search jobs ​

listJobs takes the filters from JobFilterInput and the sort fields from JobSortField. See Core patterns for the operators.

graphql
query OpenJobsDueSoon {
  listJobs(
    first: 50
    filter: {
      status: { notIn: ["COMPLETED", "SHIPPED", "CANCELLED"] }
      dueAt: { lt: "2026-10-01T00:00:00Z" }
    }
    sort: [{ field: DUE_AT, direction: ASC }]
  ) {
    totalCount
    edges {
      node {
        id
        jobNumber
        name
        status
        dueAt
      }
    }
    pageInfo {
      hasNextPage
      endCursor
    }
  }
}

Update a job ​

updateJob changes only the fields you pass:

graphql
mutation StartPress {
  updateJob(id: "job_01M0R249JMETNBM1Z7466MXGZD", input: { status: PRESS }) {
    job {
      id
      status
      updatedAt
    }
    errors {
      path
      message
    }
  }
}

upsertJob takes the whole job (name and quantity are required) and updates the job whose id you pass, or creates one when you leave id out. It suits a sync that always sends the full record. Fields you leave out keep their current value.

To delete a job, call deleteJob(input: { id }); it returns success and errors.

Operations ​

An operation (OperationState) is one production step. jobId, name and kind (OperationKind) are required. sortOrder orders the steps, expectedDuration is the planned duration in seconds, and requestedWorkCenterId asks for a specific work center.

graphql
mutation AddPrintingStep {
  createOperation(
    input: {
      jobId: "job_01M0R249JMETNBM1Z7466MXGZD"
      componentId: "cmp_01M0R249NQEQGR8E91ZHP09KP0"
      name: "Print text block"
      kind: DIGITAL_PRINTING
      sortOrder: 10
      productionQuantity: 5000
      remarks: "Use the matte stock"
    }
  ) {
    operation {
      id
      status
    }
    errors {
      path
      message
    }
  }
}

Operations move through OperationStatus: PENDING, AVAILABLE, SETUP, RUNNING, CLEANUP, COMPLETED, FAILED, STOPPED, CANCELLED and RESTARTING. Change the status with transitionOperation. A transition that is not allowed from the current status comes back in errors.

graphql
mutation StartOperation {
  transitionOperation(input: { id: "opr_01M0R24B2Q7XK5W3N8D4F6H9TJ", status: RUNNING }) {
    operation {
      id
      status
      actualStartAt
    }
    errors {
      path
      message
    }
  }
}

List a job's operations with listOperations:

graphql
query JobOperations {
  listOperations(
    filter: { jobId: { eq: "job_01M0R249JMETNBM1Z7466MXGZD" } }
    sort: [{ field: SORT_ORDER, direction: ASC }]
  ) {
    edges {
      node {
        id
        name
        kind
        status
        requestedWorkCenter {
          name
        }
      }
    }
  }
}

Milestones ​

Milestones (MilestoneState) are dated checkpoints on a job, or on one of its components.

graphql
mutation AddMilestone {
  createMilestone(
    input: {
      jobId: "job_01M0R249JMETNBM1Z7466MXGZD"
      name: "Proof approved"
      dueAt: "2026-10-05T12:00:00Z"
      sortOrder: 1
    }
  ) {
    milestone {
      id
      isCompleted
    }
    errors {
      path
      message
    }
  }
}

Mark one done with completeMilestone(input: { id }), or cancel it with cancelMilestone(input: { id, reason }). uncompleteMilestone and uncancelMilestone undo those.

Job groups ​

A job group (JobGroupState) collects related jobs, for example all jobs of one order. Create the group, then set jobGroupId on each job with createJob or updateJob:

graphql
mutation CreateGroup {
  createJobGroup(input: { name: "Autumn campaign", tags: ["campaign"] }) {
    jobGroup {
      id
    }
    errors {
      path
      message
    }
  }
}
graphql
query GroupJobs {
  getJobGroup(id: "jgr_01M0R24C8V5N2K7T4Q9W3X6B1D") {
    name
    jobs {
      id
      name
      status
    }
  }
}

removeJobFromJobGroup(input: { jobId }) takes a job out of its group. addJobToJobGroup is different: it creates a new job from the group's product template, so it only works on groups that have one.

Following changes ​

To keep another system in step, poll the jobs you track, for example with listJobs filtered by status or externalId, and compare updatedAt. The API also has GraphQL subscriptions (dataChangeEvents, statusEvents); see GraphQL tooling before you rely on them from an integration.

Connect machines, automate workflows, and build custom apps for print production.