Production files
Generate numbered factory production files, keep their views current, and set the inks, decoration methods, and Pantones they print, through the REST API or an MCP agent.
A production file is a numbered factory top sheet PDF for one or more variants of one model: views with numbered markers, a decoration table with finished sizes, placements, methods and inks, and a Pantone table for the fabric zones. The REST API and the MCP connector use the same services as the app, so a file exported through the API is numbered, stored, and listed on the model page like any other.
Access
REST requests use your workspace API key in X-API-Key. Paths below are relative to https://api.glossi.io/api/v1. MCP tools take the same arguments by name, plus an optional workspaceId. Both require a plan with API access.
IDs you will need:
- Model ID, from
GET /models. - Variant IDs, from
GET /models/:modelId/variants. A variant's ID is also the last part of its page URL in the app:/library/models/<modelId>/variants/<variantId>. IDs are GUIDs and are accepted with or without braces or dashes. - Decal ID for a library logo, and material ID for a library material.
POST /materials/pantonereturns the new material's ID.
Errors use the standard shape, { "error": { "code": "...", "message": "..." } }: 400 VALIDATION_ERROR with the reason for bad input, 404 NOT_FOUND for a model, variant, decal, material, or export that does not exist in your workspace.
Export a production file
POST /models/:modelId/production-files/export is the call most integrations want. It exports with current views: when every chosen variant's views are current, the file is built at once. When any are missing, out of date, or were captured in the other mode, those variants are captured on a cloud render instance first, and the file is built when the capture lands.
curl -X POST 'https://api.glossi.io/api/v1/models/MODEL_ID/production-files/export' \
-H "X-API-Key: $GLOSSI_API_KEY" \
-H 'Content-Type: application/json' \
-d '{
"variantIds": ["8f0c2d1e-5b7a-4c3e-9f21-0a6b3c4d5e6f", "1a2b3c4d-5e6f-4a1b-8c2d-3e4f5a6b7c8d"],
"options": { "captureMode": "flat", "includeDetailPages": true, "factoryNote": "Match navy to the approved lab dip." }
}'variantIds is required: 1 to 50 variants of the same model. options is optional (see Options).
The response is an export:
{
"id": "0d5c6a3e-2f1b-4e8a-9c7d-6b5a4f3e2d1c",
"status": "CAPTURING",
"variantIds": ["8f0c2d1e-5b7a-4c3e-9f21-0a6b3c4d5e6f", "1a2b3c4d-5e6f-4a1b-8c2d-3e4f5a6b7c8d"],
"capturingVariantIds": ["1a2b3c4d-5e6f-4a1b-8c2d-3e4f5a6b7c8d"],
"productionFile": null,
"reason": null,
"createdAt": "2026-09-25T17:02:11.412Z"
}status | HTTP | Meaning |
|---|---|---|
READY | 201 | The views were current. productionFile holds the file; id is null. |
CAPTURING | 202 | Views are being captured. Poll GET /production-file-exports/:id. A capture usually takes a couple of minutes. |
FAILED | 200 | The capture could not start or produced nothing. reason says why, for example when no project contains the model or the workspace is out of usage. |
Sending the same export again while it is capturing returns the running export instead of starting another.
A cloud capture uses the same usage as image renders: one per variant captured. It loads the model from a project that contains it, so the model must be in at least one project.
Poll an export
GET /production-file-exports/:exportId returns the same export shape. Once status is READY, productionFile is set:
{
"id": "0d5c6a3e-2f1b-4e8a-9c7d-6b5a4f3e2d1c",
"status": "READY",
"variantIds": ["8f0c2d1e-5b7a-4c3e-9f21-0a6b3c4d5e6f", "1a2b3c4d-5e6f-4a1b-8c2d-3e4f5a6b7c8d"],
"capturingVariantIds": ["1a2b3c4d-5e6f-4a1b-8c2d-3e4f5a6b7c8d"],
"productionFile": {
"id": "b3e1f0a2-7c6d-4e5f-8a9b-0c1d2e3f4a5b",
"modelId": "MODEL_ID",
"documentNumber": "PF-12",
"version": 1,
"variantIds": ["8f0c2d1e-5b7a-4c3e-9f21-0a6b3c4d5e6f", "1a2b3c4d-5e6f-4a1b-8c2d-3e4f5a6b7c8d"],
"variantNames": ["Home", "Away"],
"createdAt": "2026-09-25T17:04:03.118Z",
"createdByUserId": "user-id",
"downloadUrl": "https://..."
},
"reason": null,
"createdAt": "2026-09-25T17:02:11.412Z"
}Poll every few seconds. A variant whose capture fails still prints, flagged as not captured.
GET /models/:modelId/production-file-exports returns { "exports": [...] }: exports still capturing, plus those that failed in the last 24 hours, newest first.
Create a production file with the views there are
POST /models/:modelId/production-files builds and stores the file right away with whatever views exist, and never captures. Variants with out-of-date views print with a Views out of date notice; variants never captured print their preview image without markers or measured placements. Use it after a failed export, or when you know the views are current.
The body is the same as an export, { "variantIds": [...], "options": {...} }. The response is 201 with a production file:
{
"id": "b3e1f0a2-7c6d-4e5f-8a9b-0c1d2e3f4a5b",
"modelId": "MODEL_ID",
"documentNumber": "PF-12",
"version": 2,
"variantIds": ["8f0c2d1e-5b7a-4c3e-9f21-0a6b3c4d5e6f", "1a2b3c4d-5e6f-4a1b-8c2d-3e4f5a6b7c8d"],
"variantNames": ["Home", "Away"],
"createdAt": "2026-09-25T17:20:44.901Z",
"createdByUserId": "user-id",
"downloadUrl": "https://..."
}Document numbers are counted per workspace. Exporting the same set of variants of the same model again keeps the number and increments version; any other set takes the next number.
List and download
GET /models/:modelId/production-files returns { "productionFiles": [...] }, newest first, in the shape above. Every file is stored unchanged with the data it was built from.
downloadUrl is a signed link to the PDF, valid for one hour, served as an attachment named like PF-12 v2 - Jersey - 2 variants.pdf. List the files again for a fresh link.
Preview
POST /models/:modelId/production-files/preview takes the same body and returns { "html": "...", "warnings": [...] }: the document's HTML, marked DRAFT with no number, and a list of what is missing, such as zones with no Pantone on file. Nothing is stored and no number is used. Image links in the HTML are signed and expire.
Options
| Field | Default | Meaning |
|---|---|---|
captureMode | "flat" | "flat" shows the true material color; "lit" shows studio lighting. An export recaptures variants whose views were captured in the other mode. |
recaptureAll | false | Export only: capture every chosen variant again, even when its views are current. |
includeSideViews | true | Left and right side views on each top sheet, when the capture has them. |
includeDetailPages | true | One close-up page per logo. false stops after the top sheets. |
factoryNote | none | Up to 500 characters, printed on every top sheet. |
The options are stored with the file.
Production views
The views on a production file are captured by the studio engine. Exports capture them as needed, so most integrations never call these directly.
GET /models/:modelId/production-views returns one row per captured variant:
{
"productionViews": [
{
"variantId": "8f0c2d1e-5b7a-4c3e-9f21-0a6b3c4d5e6f",
"capturedAt": "2026-09-25T16:48:30.002Z",
"captureMode": "flat",
"stale": false
}
]
}stale is true when the variant's logos, slot placement, or materials changed after the capture. A variant with no row has never been captured.
POST /models/:modelId/production-views captures views without building a file. Body: { "variantIds": [...], "captureMode": "flat" }. variantIds: ["*"] captures every variant. captureMode defaults to "flat", the same as exports.
{ "jobId": "5e4d3c2b-1a0f-4e9d-8c7b-6a5f4e3d2c1b", "dispatched": true, "reason": null }The response is 202 when the capture was queued. When it cannot start, the response is 200 with dispatched: false and the reason. Poll GET /production-views for the new capturedAt.
Decoration method
PUT /models/:modelId/variants/:variantId/decal-slots/:slotId/decoration-method sets how the factory applies the logo in one slot on one variant.
{ "method": "Screen print" }Listed methods are Screen print, DTF (direct-to-film), Embroidery, Sublimation, Heat transfer, Tackle twill, and Other. A listed method matches regardless of case and is stored in its listed spelling. Any other text up to 60 characters is stored as written. null or an empty string clears it. The slot must hold a logo on that variant; the method stays when the logo is swapped.
The response is the slot's logo assignment:
{
"variantId": "8f0c2d1e-5b7a-4c3e-9f21-0a6b3c4d5e6f",
"slotId": "c7d8e9f0-1a2b-4c3d-8e4f-5a6b7c8d9e0f",
"decalId": "decal-id",
"imageKey": "workspaces/.../logo.png",
"width": 1200,
"height": 800,
"decorationMethod": "Screen print"
}Slot IDs come from GET /models/:modelId/decal-slots.
Logo inks
PUT /decals/:decalId/inks replaces a library logo's ink list, the colors the production file prints for it. Send either an ink list:
{
"inks": [
{ "name": "White" },
{ "name": "Navy", "pantoneCode": "281 C", "hex": "#1F2A44" }
]
}or a spec line as your team writes it:
{ "spec": "4 inches across / 3.26 in height / 2 color / white / red pms 200c" }Each ink needs a name or a pantoneCode; hex (#RRGGBB) is optional and only draws the swatch. At most 16 inks, names up to 40 characters. Codes are validated and normalized: pms 186c becomes 186 C, cool gray 11 c becomes Cool Gray 11 C, and textile codes such as 19-4052 TCX are accepted. An empty inks list clears.
A spec line is split on /, ;, or new lines. Sizes, the color count, and a decoration method are read and reported but not stored; everything else becomes an ink. White and black need no code.
{
"id": "decal-id",
"name": "Crest",
"inks": [
{ "name": "White", "pantoneCode": null, "hex": null },
{ "name": "Red", "pantoneCode": "200 C", "hex": null }
],
"spec": {
"inks": [
{ "name": "White", "pantoneCode": null, "hex": null },
{ "name": "Red", "pantoneCode": "200 C", "hex": null }
],
"colourCount": 2,
"method": null,
"widthIn": 4,
"heightIn": 3.26,
"warnings": []
}
}spec is present only when you sent one. warnings lists parts that could not be read as a Pantone code, and a stated color count that does not match the inks found.
PUT /decals/:decalId/pantone-codes with { "codes": ["186 C"] } is deprecated. It stores the codes as unnamed inks; use /inks instead.
Pantone on materials
Each fabric zone prints the Pantone of the material it wears, or No Pantone on file when there is none. Glossi does not look up Pantone colors, so a code always travels with its sRGB hex.
POST /materials/pantone creates a flat-color library material that renders as the Pantone:
{ "name": "Team Navy", "pantoneCode": "281 C", "hex": "#1F2A44" }All three fields are required. The response is 201:
{ "id": "material-id", "name": "Team Navy", "pantoneCode": "281 C", "hex": "#1F2A44" }PUT /materials/:materialId/pantone records a Pantone on any existing material, in the same response shape:
{ "pantoneCode": "281 C", "hex": "#1F2A44" }A code requires its hex. A null or empty pantoneCode clears both. This only records the Pantone; the material's look does not change.
REST and MCP operations
| REST | MCP tool |
|---|---|
POST /models/:modelId/production-files/export | export_production_file |
GET /production-file-exports/:exportId | get_production_file_export |
GET /models/:modelId/production-file-exports | none |
POST /models/:modelId/production-files | create_production_file |
GET /models/:modelId/production-files | list_production_files |
POST /models/:modelId/production-files/preview | none |
GET /models/:modelId/production-views | get_production_views_status |
POST /models/:modelId/production-views | request_production_views |
PUT /models/:modelId/variants/:variantId/decal-slots/:slotId/decoration-method | set_decoration_method |
PUT /decals/:decalId/inks | set_decal_inks |
POST /materials/pantone | create_pantone_material |
PUT /materials/:materialId/pantone | set_material_pantone |
With an MCP agent, you can ask:
Export one production file for these two variants of the Jersey, flat views with detail pages, and give me the link: https://app.glossi.io/library/models/MODEL_ID/variants/VARIANT_A and .../variants/VARIANT_B
The agent calls export_production_file, then polls get_production_file_export until the file is ready. The agent can look up variants and slots itself with list_model_variants and get_decal_slots; variant page links work too.
Variants and logos
List and create model variants, add them to a project, choose which variant each model wears, render only the ones you want, and set the logo in each decal slot, through the REST API or an MCP agent.
Model prep
Split a model into parts, label its parts and finishes, unwrap its UVs and assign materials, then keep or discard the result, through the REST API or an MCP agent.