Appearance
Components and media
A component (ComponentState) is one printed part of a job: the cover, the text block, an insert. Each component belongs to one job (jobId) and carries its own quantity, print specification and artwork files. Operations and milestones can point at a component through componentId (see Job management).
Component kinds
kind is a ComponentKind:
| Value | Use for |
|---|---|
COVER | Covers |
TEXT, CONTENT, MAIN | Text block or main body |
INSERT, OUTSERT | Inserted or attached pieces |
ENDPAPER | Endpapers of a case-bound book |
DUST_JACKET | Dust jackets |
OTHER | Anything else |
Add a component
jobId, name, kind and quantity are required.
graphql
mutation AddCover {
createComponent(
input: {
jobId: "job_01M0R249JMETNBM1Z7466MXGZD"
name: "Cover"
kind: COVER
quantity: 5000
externalId: "MIS-2026-0042-COVER"
sortOrder: 1
}
) {
component {
id
}
errors {
path
message
}
}
}createComponent rejects an externalId that another component already uses.
The print specification (page count, colours, layout, media, finished size, finishing) is set through upsertComponent, which takes the same required fields plus the specification fields of UpsertComponentInput. For example, to set the page count:
graphql
mutation SetPageCount {
upsertComponent(
input: {
id: "cmp_01M0R249NQEQGR8E91ZHP09KP0"
jobId: "job_01M0R249JMETNBM1Z7466MXGZD"
name: "Text block"
kind: TEXT
quantity: 5000
totalPages: 48
}
) {
component {
id
totalPages
}
errors {
path
message
}
}
}Specification fields you leave out keep their current value; passing null clears one.
Read the print specification
graphql
query ComponentSpec {
getComponent(id: "cmp_01M0R249NQEQGR8E91ZHP09KP0") {
id
name
kind
quantity
totalPages
colors {
frontColorCount
backColorCount
front {
colors {
name
colorType
}
}
}
layout {
trimBox {
width {
millimeters
}
height {
millimeters
}
}
bleed {
top {
millimeters
}
}
}
media {
name
kind
stockType
grainDirection
weight {
gsm
}
}
desiredSubstrate {
id
name
}
}
}The specification objects are optional; a component without them returns null.
Lengths and weights
Every dimension is a Length. It keeps the value and unit it was entered with (raw, unit) and gives you conversions, so you never convert units yourself:
graphql
query SubstrateSizes {
listSubstrates(first: 10, filter: { isActive: { eq: true } }) {
edges {
node {
id
name
width {
raw
unit
millimeters
inches
}
thickness {
value(unit: UM)
}
weight {
gsm
}
}
}
}
}LengthUnit values are UM, MM, CM, IN and PT. Paper weight (PaperWeight) is exposed as gsm, or with value(unit:).
Substrates
The stock a component is printed on can be a substrate record (SubstrateState) from your material catalogue. A component has a desiredSubstrate (what was specified) and an actualSubstrate (what was used). Substrates carry the full media description: kind (SHEET or ROLL), stockType, grainDirection (ANY, LONG, SHORT), coatings, weight, thickness, size and cost data. Browse them with listSubstrates, filtering on name, externalId, kind, coating or isActive.
Artwork files
A component's files are linked through ComponentArtworkFileState. Each link points either at a file stored in CoCoCo (fileId) or at an external URL (externalUri), and has a usageRole (ComponentFileUsageRole): ARTWORK, TEMPLATE, DATA, PATH or OTHER.
Link an external PDF:
graphql
mutation AttachArtwork {
upsertComponentArtworkFile(
input: {
componentId: "cmp_01M0R249NQEQGR8E91ZHP09KP0"
externalUri: "https://<your-file-host>/jobs/0042/text.pdf"
usageRole: ARTWORK
pageRange: "1-48"
description: "Text block, print-ready"
}
) {
artworkFile {
id
usageRole
}
errors {
path
message
}
}
}List a component's files:
graphql
query ComponentFiles {
listComponentArtworkFiles(componentId: "cmp_01M0R249NQEQGR8E91ZHP09KP0") {
id
usageRole
pageRange
externalUri
file {
id
name
mimeType
status
}
}
}Pass id to upsertComponentArtworkFile to change an existing link, and use deleteComponentArtworkFile to remove one.
Uploading files to CoCoCo
To store a file in CoCoCo itself (FileState), upload it in three steps:
- Call
requestFileUploadswith the file's name, MIME type, size and FileCategory. You can link it to a job or component in the same call. Each grant returns afileIdand a pre-signeduploadUrl. - Upload the bytes to
uploadUrlbefore it expires. - Call
completeFileUploadswith thefileId. CoCoCo checks that the bytes arrived and marks the fileREADY.
Uploads need file storage to be set up for your tenant; if it is not, the errors list says so.
graphql
mutation RequestUpload {
requestFileUploads(
inputs: [
{
componentId: "cmp_01M0R249NQEQGR8E91ZHP09KP0"
name: "Text block"
originalFilename: "text.pdf"
mimeType: "application/pdf"
sizeBytes: 18234567
category: ARTWORK
usageRole: ARTWORK
}
]
) {
grants {
fileId
uploadUrl
expiresAt
}
errors {
path
message
}
}
}graphql
mutation CompleteUpload {
completeFileUploads(inputs: [{ fileId: "fil_01M0R24D3F7K9P2W5X8Z1B4N6Q" }]) {
files {
id
status
}
errors {
path
message
}
}
}Then link the file to the component with upsertComponentArtworkFile and its fileId. To download a stored file, fileDownloadUrl(id:) returns a short-lived URL.
Listing components
graphql
query JobComponents {
listComponents(
filter: { jobId: { eq: "job_01M0R249JMETNBM1Z7466MXGZD" } }
sort: [{ field: SORT_ORDER, direction: ASC }]
) {
edges {
node {
id
name
kind
quantity
}
}
}
}ComponentFilterInput filters on jobId, name, kind (as a string, for example kind: { eq: "COVER" }) and externalId. For one job, getJob { components { … } } returns the same records without paging.
Good practice
- Give every file link a clear
usageRole, so that print files, templates and variable data are not confused.