Skip to content

Orders and commerce ​

The commerce records describe the business side of a print job: who ordered it, what was quoted, what was sold, invoiced and shipped. They connect to production through order lines and the jobs created from them.

text
CustomerState ── ContactState, AddressState
   │
EstimateState ── EstimateLineState          (the quote)
   │ convertEstimateToOrder / acceptEstimateAndCreateJobs
OrderState ───── OrderLineState ── JobState (production)
   │
   ├── InvoiceState ── InvoiceLineState
   └── ShipmentState ── ShipmentPackageState ── ShipmentItemState

Amounts are plain numbers (Float) with a separate currency field holding an ISO 4217 code such as "EUR". Dates are ISO 8601 strings.

Customers ​

A customer (CustomerState) needs only a name. Contacts and addresses are separate records that point at it.

graphql
mutation CreateCustomer {
  createCustomer(
    input: {
      name: "Nordlicht Verlag GmbH"
      externalId: "CRM-1001"
      email: "<customer-email>"
      paymentTermsDays: 30
      creditLimit: 25000
      creditCurrency: "EUR"
    }
  ) {
    customer {
      id
    }
    errors {
      path
      message
    }
  }
}
graphql
mutation AddContactAndAddress {
  createContact(
    input: {
      customerId: "cus_01M0R2496SFANSZFKWPYW17V0J"
      firstName: "Anna"
      lastName: "Berger"
      email: "<contact-email>"
      jobTitle: "Production manager"
      isPrimary: true
    }
  ) {
    contact {
      id
    }
    errors {
      path
      message
    }
  }
  createAddress(
    input: {
      customerId: "cus_01M0R2496SFANSZFKWPYW17V0J"
      addressType: BOTH
      street1: "Hafenstrasse 12"
      postalCode: "20457"
      city: "Hamburg"
      country: "DE"
      isDefault: true
    }
  ) {
    address {
      id
    }
    errors {
      path
      message
    }
  }
}

addressType is BILLING, SHIPPING or BOTH. A customer's credit position is in creditLimit, isCreditHold and creditHoldReason, and customerAccountSummary(customerId:) summarises its account.

Orders ​

An order (OrderState) needs an orderNumber and a customerId. Its lines (OrderLineState) need a lineNumber, productName, quantity, unitPrice and lineTotal.

graphql
mutation CreateOrder {
  createOrder(
    input: {
      orderNumber: "SO-2026-0815"
      customerId: "cus_01M0R2496SFANSZFKWPYW17V0J"
      poReference: "PO-7781"
      requiredDeliveryDate: "2026-10-20T00:00:00Z"
      currency: "EUR"
    }
  ) {
    order {
      id
      status
      paymentStatus
    }
    errors {
      path
      message
    }
  }
}
graphql
mutation AddOrderLine {
  createOrderLine(
    input: {
      orderId: "ord_01M0R24E5G8H2J4K6M9N1P3Q5R"
      lineNumber: 1
      productName: "Spring catalogue, A4, 48 pp"
      quantity: 5000
      unitPrice: 1.84
      lineTotal: 9200
    }
  ) {
    orderLine {
      id
    }
    errors {
      path
      message
    }
  }
}

One call for the whole order ​

createOrderGraph creates an order, its lines and, if you need them, a new customer and billing and shipping addresses in one transaction. Either every record is created or none is. It only creates: to use an existing customer or address, set its ID on order and leave the nested input out.

graphql
mutation ImportWebShopOrder {
  createOrderGraph(
    input: {
      order: { orderNumber: "WEB-55120", status: DRAFT, currency: "EUR" }
      customer: { name: "Café Morgenrot", email: "<customer-email>" }
      shippingAddress: {
        addressType: SHIPPING
        street1: "Lindenallee 3"
        postalCode: "50968"
        city: "Köln"
        country: "DE"
      }
      lines: [
        { lineNumber: 1, productName: "Menu cards, A5", quantity: 500, unitPrice: 0.42, lineTotal: 210 }
      ]
    }
  ) {
    order {
      id
      orderNumber
    }
    customer {
      id
    }
    lines {
      id
    }
    jobs {
      id
    }
    errors {
      path
      message
    }
  }
}

When the order is created with status: CONFIRMED, lines that carry a productTemplateId are then turned into jobs and returned in jobs. This step runs after the transaction: if it fails, the reason is in errors and the order stays.

Order status ​

OrderState.status is an OrderStatus: DRAFT, CONFIRMED, IN_PRODUCTION, PARTIALLY_SHIPPED, SHIPPED, DELIVERED, COMPLETED, CANCELLED or ON_HOLD. paymentStatus is a PaymentStatus: UNPAID, PARTIALLY_PAID, PAID, OVERDUE, REFUNDED or WRITTEN_OFF.

Set the status with updateOrder(id, input: { status }), or for many orders at once with bulkUpdateOrderStatuses. Shipping updates some statuses for you (see Shipments).

Finding orders ​

OrderFilterInput filters on orderNumber, status, paymentStatus, customerId and createdAt:

graphql
query OpenOrdersForCustomer {
  listOrders(
    first: 25
    filter: {
      customerId: { eq: "cus_01M0R2496SFANSZFKWPYW17V0J" }
      status: { in: ["CONFIRMED", "IN_PRODUCTION"] }
    }
    sort: [{ field: ORDER_DATE, direction: DESC }]
  ) {
    totalCount
    edges {
      node {
        id
        orderNumber
        status
        totalAmount
        currency
        requiredDeliveryDate
      }
    }
  }
}

orderLifecycle(orderId:) returns everything attached to one order in a single call: the order and its lines, the estimate it came from, jobs, invoices and shipments.

graphql
query OrderOverview {
  orderLifecycle(orderId: "ord_01M0R24E5G8H2J4K6M9N1P3Q5R") {
    order {
      orderNumber
      status
    }
    jobs {
      id
      name
      status
    }
    invoices {
      invoiceNumber
      status
      totalAmount
    }
    shipments {
      shipmentNumber
      status
      trackingNumber
    }
    errors {
      path
      message
    }
  }
}

From order to production ​

Link an existing job to an order line by setting jobId on the line with updateOrderLine. To create jobs from an order's lines, call createJobsFromOrder, one entry per line:

graphql
mutation JobsFromOrder {
  createJobsFromOrder(
    input: {
      orderId: "ord_01M0R24E5G8H2J4K6M9N1P3Q5R"
      jobs: [{ orderLineId: "oln_01M0R24F7J9K3M5N8P1Q4R6S2T", jobName: "Spring catalogue", priority: 5 }]
    }
  ) {
    jobs {
      id
      name
      status
    }
    errors {
      path
      message
    }
  }
}

Estimates ​

An estimate (EstimateState) is a quote. Its EstimateStatus is DRAFT, SENT, ACCEPTED, REJECTED, EXPIRED or REVISED. reviseEstimate creates a new revision of an estimate that has not been accepted.

Two mutations turn an estimate into an order. Both refuse an estimate that is rejected, expired or already converted:

  • convertEstimateToOrder creates the order and its lines from the estimate.
  • acceptEstimateAndCreateJobs also creates the jobs, with their components and operations, and returns them all.
graphql
mutation AcceptQuote {
  acceptEstimateAndCreateJobs(input: { estimateId: "est_01M0R24G9K2M4N6P8Q1R3S5T7V", orderNumber: "SO-2026-0816" }) {
    order {
      id
      status
    }
    jobs {
      id
      name
    }
    updatedEstimate {
      status
    }
    errors {
      path
      message
    }
  }
}

Invoices ​

invoiceOrder creates an invoice (InvoiceState) with its lines from an order:

graphql
mutation InvoiceOrder {
  invoiceOrder(
    input: { orderId: "ord_01M0R24E5G8H2J4K6M9N1P3Q5R", invoiceNumber: "INV-2026-0311", paymentTerms: "30 days net" }
  ) {
    invoice {
      id
      status
      totalAmount
      currency
    }
    errors {
      path
      message
    }
  }
}

An invoice has a kind (InvoiceKind: INVOICE, CREDIT_NOTE, PROFORMA) and a status (InvoiceStatus). Payment details (paidAmount, paymentMethod, paymentReference) live on the invoice. You can also create invoices directly with createInvoice.

Shipments ​

A shipment (ShipmentState) holds packages, and each package holds items that point at a job, component or order line. dispatchShipment creates the shipment, its packages and items in one call:

graphql
mutation Dispatch {
  dispatchShipment(
    input: {
      orderId: "ord_01M0R24E5G8H2J4K6M9N1P3Q5R"
      trackingNumber: "00340434161234567890"
      packages: [
        {
          weight: 18.5
          items: [{ orderLineId: "oln_01M0R24F7J9K3M5N8P1Q4R6S2T", quantity: 2500, description: "Box 1 of 2" }]
        }
      ]
    }
  ) {
    shipment {
      id
      status
    }
    errors {
      path
      message
    }
  }
}

A dispatched shipment starts as PICKED_UP. If its order was CONFIRMED or IN_PRODUCTION, the order moves to PARTIALLY_SHIPPED.

Report carrier progress with updateShipmentTracking. The status must be a valid next step from the current one (ShipmentStatus); when it reaches DELIVERED, the linked order moves to DELIVERED as well.

graphql
mutation Delivered {
  updateShipmentTracking(
    input: { shipmentId: "shp_01M0R24H2M4N6P8Q1R3S5T7V9W", status: DELIVERED, deliveredAt: "2026-10-19T10:42:00Z" }
  ) {
    shipment {
      status
      deliveredAt
    }
    order {
      status
    }
    errors {
      path
      message
    }
  }
}

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