> ## Documentation Index
> Fetch the complete documentation index at: https://docs.printools.io/llms.txt
> Use this file to discover all available pages before exploring further.

# Create a job

> Requires the scope jobs.write.

Required scopes: `jobs.write`.


## OpenAPI

````yaml POST /v1/jobs
openapi: 3.1.0
info:
  title: PRINTOOLS API
  version: 1.0.0
  description: >-
    The PRINTOOLS public REST API. This document is generated from the live
    route table and service GraphQL SDL; do not edit it by hand.


    Every 2xx response has {status, message, data}. Every non-2xx response has
    {error, message, status: false}.


    Tenant credential: send X-API-Key only. It is bound to one shop.
    X-PrintTools-Organization-Id is optional for that credential and, if sent,
    must match its shop.


    Partner credential: send X-API-Key, X-API-Secret, Authorization: Bearer
    <Cognito access token>, and X-PrintTools-Organization-Id. The OAuth flow is
    documented at https://app.printools.io/api/index.html#partner-auth.


    Read live limits from GET /v1/reference/limits. Field shapes are projected
    from operation declarations; local endpoints have explicit handler-derived
    schemas.
servers:
  - url: https://api.printools.io
    description: Production
security: []
externalDocs:
  description: Getting started, OAuth and webhook guidance
  url: https://app.printools.io/api/index.html
paths:
  /v1/jobs:
    post:
      tags:
        - jobs
      summary: Create a job.
      description: Requires the scope jobs.write.
      operationId: post_v1_jobs
      parameters:
        - name: X-PrintTools-Organization-Id
          in: header
          required: false
          schema:
            type: string
            format: uuid
          description: >-
            Tenant credential: optional and, when sent, must equal the shop
            bound to the key. Partner credential: required; it selects an
            organisation the user previously authorised.
        - name: Idempotency-Key
          in: header
          required: false
          schema:
            type: string
            minLength: 1
            maxLength: 200
          description: >-
            Optional client-generated key for write retries. Reusing it with a
            different request returns 409; a replay includes
            Idempotency-Replayed: true.
      requestBody:
        required: true
        content:
          application/json:
            schema:
              type: object
              description: >-
                Blank-job creation (createJob). All optional; status defaults to
                'Draft'.
              properties:
                jobName:
                  type: string
                status:
                  type: string
                customerId:
                  type: string
                contactId:
                  type: string
                reference:
                  type: string
                jobNotes:
                  type: string
            examples:
              example:
                summary: Replace example values with a request for your shop.
                value:
                  jobName: example
                  status: example
                  customerId: example
                  contactId: example
                  reference: example
      responses:
        '201':
          description: Successful response.
          headers:
            Idempotency-Replayed:
              description: >-
                Present and true when this response was replayed from a prior
                Idempotency-Key request.
              schema:
                type: string
                enum:
                  - 'true'
          content:
            application/json:
              schema:
                allOf:
                  - $ref: '#/components/schemas/Success'
                  - type: object
                    properties:
                      data:
                        $ref: '#/components/schemas/Output_Job'
        '400':
          description: >-
            Validation or request-shape error. Correct the request before
            retrying.
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/Error'
        '401':
          description: Credential authentication failed.
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/Error'
          headers:
            WWW-Authenticate:
              schema:
                type: string
                example: ApiKey
        '403':
          description: >-
            The credential lacks a required scope, or its actor lacks
            permission.
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/Error'
        '404':
          description: The resource or endpoint was not found.
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/Error'
        '409':
          description: >-
            Conflict, including idempotency-key reuse or an in-flight idempotent
            request.
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/Error'
        '413':
          description: The JSON request body exceeds the published size limit.
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/Error'
        '429':
          description: Rate limited. Retry after the returned delay.
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/Error'
          headers:
            Retry-After:
              description: Whole seconds to wait.
              schema:
                type: integer
                minimum: 0
        '500':
          description: An unexpected server error. A retry can be appropriate.
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/Error'
      security:
        - tenantApiKey: []
        - partnerApiKey: []
          partnerApiSecret: []
          partnerBearer: []
      x-codeSamples:
        - lang: curl
          label: Tenant credential
          source: |-
            curl --request POST 'https://api.printools.io/v1/jobs' \
              --header 'X-API-Key: $PRINTOOLS_API_KEY' \
              --header 'Content-Type: application/json' \
              --data '{"jobName":"example","status":"example","customerId":"example","contactId":"example","reference":"example"}'
components:
  schemas:
    Success:
      type: object
      required:
        - status
        - message
        - data
      properties:
        status:
          type: boolean
          description: >-
            The actual resolver result. It can be false when an operation
            returns false or null without throwing.
        message:
          type: string
          example: OK
        data: {}
      description: Every 2xx response uses this envelope.
    Output_Job:
      type: object
      properties:
        id:
          type: string
        jobRef:
          type:
            - string
            - 'null'
        jobName:
          type:
            - string
            - 'null'
        status:
          type: string
        quoteId:
          type:
            - string
            - 'null'
        quoteRef:
          type:
            - string
            - 'null'
          description: >-
            The linked quote's own `quoteRef` (CB-05), resolved server-side from
            the quote

            row — never derived from `quoteId`. Null when the job has no quote,
            when

            `quoteId` points at a row that no longer exists (these link columns
            carry no

            FK) or is not visible to the caller's tenant, and when the linked
            quote's own

            ref is null. Read-only: no mutation input sets it.
        customerId:
          type:
            - string
            - 'null'
        contactId:
          type:
            - string
            - 'null'
        salesRepEmail:
          type:
            - string
            - 'null'
        reference:
          type:
            - string
            - 'null'
        priority:
          $ref: '#/components/schemas/Enum_JobPriority'
        shipPickupDate:
          type:
            - string
            - 'null'
          format: date
        productionDeadline:
          type:
            - string
            - 'null'
          format: date
        deliveryMethod:
          type:
            - string
            - 'null'
        shippingBranding:
          type:
            - string
            - 'null'
        shippingAddressId:
          type:
            - string
            - 'null'
        paymentType:
          type:
            - string
            - 'null'
        invoiceStatus:
          type: string
        lastQuoteSyncDate:
          type:
            - string
            - 'null'
          format: date-time
        quoteOutOfSync:
          type: boolean
          description: >-
            True when this job was created from a quote (`quoteId` set) AND the
            source

            quote has been edited since the last conversion/sync — i.e. the
            quote's

            `updatedAt` is newer than the job's `lastQuoteSyncDate`. The
            Converted quote

            stays editable, so this flags that the job tree has drifted from the
            quote;

            call `syncJobFromQuote` to re-clone. Always false for jobs with no
            quote.
        totalQuantity:
          type: integer
          description: >-
            READ-ONLY units of CLOTHING on the whole job (CU-86d427fpb) — the
            sum, over

            the garment lines of every group, of each line's variant quantities,
            falling

            back to the line's own `quantity` when it has no variants. Money
            lines

            (`Other`) contribute nothing: they carry no garment (JB-05).


            Computed at read time, not stored, and NOT a sum of the groups'

            `totalQuantity` — that column is written when a job is cloned from
            its quote

            and does not follow later line edits, so the two can disagree. This
            one

            always matches what the job screen totals.


            0 for a job with no lines. That is a real answer, not an absence —
            no

            mutation input sets this field.
        poStatus:
          $ref: '#/components/schemas/Enum_JobPoStatus'
          description: >-
            READ-ONLY, computed at read time from the job's linked ACTIVE
            Purchase Orders

            (cancelled/inactive POs excluded), rolled up across them (Phase
            2.5):

            NotCreated (no PO) · Created (POs exist, none sent yet) · Sent (≥1
            PO past

            approved) · Received (all POs received/completed). Not stored; no
            mutation

            sets it.
        materialsStatus:
          $ref: '#/components/schemas/Enum_JobMaterialsStatus'
          description: >-
            READ-ONLY, computed at read time from the active POs' line items
            (Phase 2.5):

            NotPurchased (no PO / no line items) · Ordered (some line items not
            yet

            received) · Received (all line items received). Not stored; no
            mutation sets it.
        scheduledStartDate:
          type:
            - string
            - 'null'
          format: date
        scheduledEndDate:
          type:
            - string
            - 'null'
          format: date
        estimatedDuration:
          type: number
        jobNotes:
          type:
            - string
            - 'null'
        clientNotes:
          type:
            - string
            - 'null'
        customFieldValues:
          description: >-
            Operator custom-field VALUES keyed by field id (definitions in
            orgSettings).
        createdAt:
          type: string
          format: date-time
        updatedAt:
          type: string
          format: date-time
        groups:
          type: array
          items:
            $ref: '#/components/schemas/Output_JobGroup'
        activity:
          type: array
          items:
            $ref: '#/components/schemas/Output_JobActivity'
      required:
        - id
        - status
        - priority
        - invoiceStatus
        - quoteOutOfSync
        - totalQuantity
        - poStatus
        - materialsStatus
        - estimatedDuration
        - customFieldValues
        - createdAt
        - updatedAt
        - groups
        - activity
    Error:
      type: object
      required:
        - error
        - message
        - status
      properties:
        error:
          type: string
          description: Stable machine-readable error code.
        message:
          type: string
        status:
          type: boolean
          const: false
      description: Every non-2xx response uses this envelope.
    Enum_JobPriority:
      type: string
      enum:
        - Normal
        - Rush
    Enum_JobPoStatus:
      type: string
      enum:
        - NotCreated
        - Created
        - Sent
        - Received
    Enum_JobMaterialsStatus:
      type: string
      enum:
        - NotPurchased
        - Ordered
        - Received
    Output_JobGroup:
      type: object
      properties:
        id:
          type: string
        jobId:
          type: string
        name:
          type: string
        totalQuantity:
          type: integer
        sortOrder:
          type: integer
        notes:
          type:
            - string
            - 'null'
        createdAt:
          type: string
          format: date-time
        updatedAt:
          type: string
          format: date-time
        lines:
          type: array
          items:
            $ref: '#/components/schemas/Output_JobLine'
        decorations:
          type: array
          items:
            $ref: '#/components/schemas/Output_JobGroupDecoration'
      required:
        - id
        - jobId
        - name
        - totalQuantity
        - sortOrder
        - createdAt
        - updatedAt
        - lines
        - decorations
    Output_JobActivity:
      type: object
      properties:
        id:
          type: string
        jobId:
          type: string
        taskId:
          type:
            - string
            - 'null'
          description: >-
            The production task this entry is about, when it is about one —
            task-scoped

            entries are links, and this is what they open. Null for job-level
            events, and

            null again once the task is deleted: the entry deliberately outlives
            the task,

            because the record of what was done to it is the point. Render a
            null-task

            entry as plain text, never as a dead link.
        activityType:
          type: string
        title:
          type: string
        description:
          type:
            - string
            - 'null'
          description: >-
            A system row's detail line, or — on a comment — the comment body
            itself.
        performedBy:
          type:
            - string
            - 'null'
          description: The actor's email. On a comment, its author.
        editedAt:
          type:
            - string
            - 'null'
          format: date-time
          description: Set once a comment has been edited. Always null on a system row.
        createdAt:
          type: string
          format: date-time
      required:
        - id
        - jobId
        - activityType
        - title
        - createdAt
    Output_JobLine:
      type: object
      properties:
        id:
          type: string
        jobGroupId:
          type: string
        lineType:
          $ref: '#/components/schemas/Enum_QuoteLineType'
        garmentCatalogueItemId:
          type:
            - string
            - 'null'
        productName:
          type: string
        productSku:
          type:
            - string
            - 'null'
        title:
          type:
            - string
            - 'null'
        description:
          type:
            - string
            - 'null'
        quantity:
          type: integer
        unitPriceExGst:
          type: number
        sortOrder:
          type: integer
        customImageUrl:
          type:
            - string
            - 'null'
          description: >-
            The image the FLOOR should look at: the Quick Mock composite carried
            over from

            `QuoteLine.customImageUrl` at conversion, or null to fall back to
            the garment's

            catalogue photo. A snapshot, deliberately — revising the mock later
            must not

            change what a job already in production is printing.
        createdAt:
          type: string
          format: date-time
        updatedAt:
          type: string
          format: date-time
        variants:
          type: array
          items:
            $ref: '#/components/schemas/Output_JobVariant'
      required:
        - id
        - jobGroupId
        - lineType
        - productName
        - quantity
        - unitPriceExGst
        - sortOrder
        - createdAt
        - updatedAt
        - variants
    Output_JobGroupDecoration:
      type: object
      properties:
        id:
          type: string
        jobGroupId:
          type: string
        decorationItemId:
          type:
            - string
            - 'null'
        method:
          anyOf:
            - $ref: '#/components/schemas/Enum_JobDecorationMethod'
            - type: 'null'
        position:
          type:
            - string
            - 'null'
        quantity:
          type:
            - integer
            - 'null'
        description:
          type:
            - string
            - 'null'
        colours:
          type: array
          items:
            $ref: '#/components/schemas/Output_DecorationColour'
          description: >-
            The inks, in the operator's order. At most one is flagged `isBase`,
            and it renders first.
        screenCount:
          type:
            - integer
            - 'null'
        screenMeshGrade:
          type:
            - string
            - 'null'
        colourCount:
          type:
            - integer
            - 'null'
        setupCost:
          type: number
          description: Present only when the credential includes the costs.read scope.
        unitCost:
          type: number
          description: Present only when the credential includes the costs.read scope.
        baseUnitCost:
          type: number
        baseSetupCost:
          type: number
        includeSetupCost:
          type: boolean
        widthCm:
          type:
            - number
            - 'null'
          description: >-
            Print dimensions in CENTIMETRES, carried across by
            `convertQuoteToJob` — the

            floor needs them (BE-04 / Q-24). See `QuoteGroupDecoration.widthCm`
            for why

            the unit is no longer millimetres.
        lengthCm:
          type:
            - number
            - 'null'
        necklineDropCm:
          type:
            - number
            - 'null'
          description: How far below the collar the print starts, in cm.
        specialInstructions:
          type:
            - string
            - 'null'
        artworkFileUrl:
          type:
            - string
            - 'null'
        separationFileUrl:
          type:
            - string
            - 'null'
        sortOrder:
          type: integer
        createdAt:
          type: string
          format: date-time
        updatedAt:
          type: string
          format: date-time
      required:
        - id
        - jobGroupId
        - colours
        - baseUnitCost
        - baseSetupCost
        - includeSetupCost
        - sortOrder
        - createdAt
        - updatedAt
    Enum_QuoteLineType:
      type: string
      enum:
        - Garment
        - Decoration
        - Service
        - Cost
        - Discount
        - Surcharge
        - Other
    Output_JobVariant:
      type: object
      properties:
        id:
          type: string
        jobLineId:
          type: string
        size:
          type:
            - string
            - 'null'
        colour:
          type:
            - string
            - 'null'
        quantity:
          type: integer
        producedQuantity:
          type: integer
        unitPriceExGst:
          type: number
        buyPrice:
          type: number
          description: Present only when the credential includes the costs.read scope.
        extraCost:
          type: number
          description: Present only when the credential includes the costs.read scope.
        sortOrder:
          type: integer
        createdAt:
          type: string
          format: date-time
        updatedAt:
          type: string
          format: date-time
      required:
        - id
        - jobLineId
        - quantity
        - producedQuantity
        - unitPriceExGst
        - sortOrder
        - createdAt
        - updatedAt
    Enum_JobDecorationMethod:
      type: string
      enum:
        - ScreenPrinting
        - Embroidery
        - DtfTransfer
        - Dtg
        - Vinyl
        - Sublimation
        - HeatTransfer
        - Outsourced
        - Other
    Output_DecorationColour:
      type: object
      properties:
        name:
          type: string
        isBase:
          type: boolean
      required:
        - name
        - isBase
  securitySchemes:
    tenantApiKey:
      type: apiKey
      in: header
      name: X-API-Key
      description: Tenant credential. This is sufficient by itself.
    partnerApiKey:
      type: apiKey
      in: header
      name: X-API-Key
      description: Partner application client ID.
    partnerApiSecret:
      type: apiKey
      in: header
      name: X-API-Secret
      description: Partner application secret.
    partnerBearer:
      type: http
      scheme: bearer
      bearerFormat: JWT
      description: Cognito access token obtained through OAuth.

````