Skip to content

REST API ​

The TronDesigner REST API lets your server read and upload logos, read print jobs, download preview images, proofreading PDFs and print data, generate new proofreadings and print data, render logo visualizations, and create signed editor links. It's a server-to-server API: call it from your backend, ERP or integration middleware, never from the browser.

TIP

Reference: every endpoint, parameter and response model is in the Swagger UI (OpenAPI JSON: https://api-v1.trondesigner.com/swagger/v1/swagger.json).

Choose the right integration ​

Integration script (window.tronDesigner)REST API
Runs inYour customer's browserYour server
KeyWebsite integration API key (public, restricted by allowed domains)REST API key (secret, optionally restricted by IP address)
Typical useOpen the editor, react to events, show images on your pagesFetch print jobs after checkout, download proofreading and print data, automate ERP flows, generate editor links for e-mails

Most integrations use both: the script captures the printJobGuid in the browser (see Events and callbacks), and your server later uses the REST API to fetch the files it needs. For browser-side downloads, see Retrieving print jobs and files.

Before you start ​

  • License. Your TronDesigner license must include API Access (all read and download endpoints) and, for the endpoints that generate something, API Automation; rendering logo visualizations needs API Visualizations. If a feature is missing, the Admin Portal says so on the REST API Keys tab and the API answers 401 Unauthorized.
  • Base URL: https://api-v1.trondesigner.com/api. Paths below are relative to https://api-v1.trondesigner.com.
  • Format. Requests and responses are JSON with camelCase property names. Enums are strings (for example "state": "ProofApproved"), dates are ISO 8601.
  • Language. Send Accept-Language (en-US, cs-CZ, fr-FR, de-DE, es-ES or it-IT) to choose the language of localized texts and the default language of generated documents. Only the first value is used; the default is English.

Create a REST API key ​

  1. In the Admin Portal open Settings → API Keys and switch to the REST API Keys tab.

  2. Create a key, give it a name and pick its roles:

    RoleWhat it allows
    Read Access (TronDesigner) — TronDesigner.RestApiKey.ReadAccessRead and download logos, print jobs and print visualizations. For apps that only consume existing data.
    Update Access (TronDesigner) — TronDesigner.RestApiKey.UpdateAccessCreate, update and delete logos, print jobs and print visualizations. For apps that generate proofreadings or print data.
  3. Optionally add Allowed IP addresses. When the list isn't empty, only requests from exactly these addresses are accepted (no ranges).

  4. Copy the key from the confirmation dialog. It is shown only once. If you lose it, edit the key and choose Generate new key — the old value stops working immediately.

Use View Usage on a key to see its request log (time, method, URL, IP address), and switch Active off to disable a key without deleting it.

Authenticate requests ​

Send the key as a bearer token in the Authorization header of every request. POST requests with a JSON body also need Content-Type: application/json (otherwise the API returns 415). The logo upload is the one exception: it takes multipart/form-data.

bash
curl https://api-v1.trondesigner.com/api/logos?pageSize=1 \
  -H "Authorization: Bearer $TD_REST_API_KEY"

A 200 OK with a JSON page of logos means the key, roles and license are set up correctly. The REST API ignores the TronDesigner-ApiKey header used by the integration script.

Endpoints ​

GroupMethod and pathReturnsLicense feature
Print jobsGET /api/print-jobsPaged listAPI Access
GET /api/print-jobs/{printJobGuid}Print job detailAPI Access
ImagesGET /api/print-jobs/{printJobGuid}/{printingGuid}/motive-imageMotive image (the designed graphics)API Access
GET /api/print-jobs/{printJobGuid}/{printingGuid}/{variantGuid}/preview-imageProduct variant preview; printAreaImageType = MOCKUP, MOCKUP_CLEAR (default), VISUALIZATION or AI_MOOD_SCENEAPI Access
ProofreadingPOST /api/print-jobs/{printJobGuid}/proofreading{ "proofreadingGuid" }API Automation
GET /api/print-jobs/{printJobGuid}/proofreading/listAll proofreadings (with dataUrl)API Access
GET /api/print-jobs/{printJobGuid}/proofreading/last · …/proofreading/{proofreadingGuid}PDF fileAPI Access
Print data (print job)POST /api/print-jobs/{printJobGuid}/print-data{ "printDataGuid" }API Automation
GET /api/print-jobs/{printJobGuid}/print-data/listAll print data (with dataUrl)API Access
GET /api/print-jobs/{printJobGuid}/print-data/last · …/print-data/{printDataGuid}PDF fileAPI Access
Print data (one printing)POST /api/print-jobs/{printJobGuid}/printing/{printingGuid}/print-dataPDF file (in the response)API Automation
GET …/printing/{printingGuid}/print-data/list · …/last · …/{printDataGuid}List or PDF fileAPI Access
LogosGET /api/logos · GET /api/logos/{logoGuid}Paged list · logo detailAPI Access
GET /api/logos/{logoGuid}/fileLogo file; fileType = ORIGINAL, CONVERTED (default) or PREVIEWAPI Access
POST /api/logos (multipart/form-data) · GET /api/logos/{logoGuid}/upload-statusUpload a logo (asynchronous, see Upload a logo) · its processing statusAPI Automation · API Access
POST /api/logos/{logoGuid}/recolorA new, recolored logo, see Recolor a logoAPI Automation
VisualizationsGET /api/visualizations/renderJPEG image of a logo on a product, see Render a logo visualizationAPI Visualizations
Editor linksPOST /api/integration-site-links/generate-open-editor-link{ "linkToken", "link" }API Automation

List endpoints accept page (default 1), pageSize (default 10), requireTotalCount, requireGroupCounts, search, createdFrom and createdTo; print jobs also filter by states, logos by type and customerGuid.

Get a print job ​

Use the printJobGuid you stored from the printJob created event or a webhook.

bash
curl https://api-v1.trondesigner.com/api/print-jobs/76b2be59-6403-4f89-9c9a-3a64588c05d3 \
  -H "Authorization: Bearer $TD_REST_API_KEY" \
  -H "Accept-Language: en-US"
json
{
  "printJobGuid": "76b2be59-6403-4f89-9c9a-3a64588c05d3",
  "code": "PJ00000069",
  "state": "ProofApproved",
  "customer": { "customerGuid": "a70b77d6-…", "orderCode": "ORDER-1001", "orderItemCode": "1" },
  "product": { "title": "Oregon 400 ml", "variants": [ … ] },
  "printings": [
    {
      "printingGuid": "5f60a5a1-4575-481a-90ad-7b0b11203aa8",
      "printData": { "positionCodeDisplay": "front", "technologyCodeDisplay": "PAD03", … },
      "printMotive": {
        "motiveImage": { "printJobFileUrl": "https://api-v1.trondesigner.com/api/print-jobs/76b2…/5f60…/motive-image", … },
        "printAreaImages": [ … ]
      }
    }
  ],
  "customProperties": { "cartLineId": "CL-4711" }
}

(Shortened.) The printJobFileUrl values point back to the REST API image endpoints, so request them with the same Authorization header.

Processing a logo (parsing, color detection, conversion for print) takes from under a second to a minute, so the upload is asynchronous: the API accepts the file, answers right away, and you find out the result separately.

bash
curl -X POST https://api-v1.trondesigner.com/api/logos \
  -H "Authorization: Bearer $TD_REST_API_KEY" \
  -H "Idempotency-Key: order-1001-logo-1" \
  -F "File=@company-logo.eps" \
  -F "Name=Company logo" \
  -F "CustomerGuid=a70b77d6-1f0e-4a8b-9c1d-2e3f4a5b6c7d" \
  -F "CustomerCompany=ACME Ltd." \
  -F "WaitSeconds=10"
Form fieldRequiredMeaning
FileyesThe logo file, at most 20 MB (20 971 520 bytes). Only the formats allowed for your account are accepted — the 400 response lists them.
NamenoDisplay name. Replaces the base of the file name and keeps the extension: logo.eps with name Company logo becomes Company logo.eps.
CustomerGuidnoYour identifier of the end customer the logo belongs to. Omit it for a logo shared by your whole account.
CustomerPerson, CustomerCompany, CustomerEmail, CustomerIdentitynoContact data of that customer. Ignored without CustomerGuid.
WaitSecondsno0–30, default 0. Hold the response up to this many seconds until processing finishes.

Read the result ​

ResponseMeaning
202 AcceptedProcessing has started. The body has "status": "Queued" or "Processing", the Location header and statusUrl point to the status resource, and Retry-After says how many seconds to wait before asking.
200 OKProcessing has already finished — within WaitSeconds, or because the file was uploaded before. It doesn't mean it succeeded: check status, which is Completed or Failed.
400, 413The file was rejected before processing: no or empty file, a format your account doesn't allow, an invalid field — or 413 for a file over 20 MB. Nothing was created.
json
{
  "logoGuid": "6993afa3-f416-4af3-9a14-2ce7e3c774f8",
  "status": "Queued",
  "progress": 0,
  "deduplicated": false,
  "statusUrl": "https://api-v1.trondesigner.com/api/logos/6993afa3-f416-4af3-9a14-2ce7e3c774f8/upload-status",
  "logo": null
}

Keep the logoGuid — it identifies the logo from the first response on. While status is Queued or Processing, poll GET /api/logos/{logoGuid}/upload-status, waiting Retry-After seconds between requests. Completed and Failed never change again:

text
response = POST /api/logos (with WaitSeconds=10)
while response.status in (Queued, Processing):
    sleep(response.headers["Retry-After"] or 2 seconds)
    response = GET response.statusUrl
if response.status == Completed: use response.logo
else: report response.message / response.messageCode

upload-status returns the same logoGuid, status and progress, plus:

  • message — what is happening or why it failed, in the language of Accept-Language;
  • messageCode — the same as a fixed code, for example LogoUpload.UploadEvents.ProcessingFailed. React to this one in code, message can change;
  • created, updated — when the upload was submitted and when its state last changed;
  • logo — the finished logo (the same as GET /api/logos/{logoGuid}) once status is Completed, otherwise null.

WaitSeconds saves you the polling for most files, but always handle a 202: a large or complex file can take longer, and then you get the usual 202 and processing continues.

Failed uploads ​

A file that can't be processed (for example a damaged or empty graphic) ends with "status": "Failed". No logo is created: GET /api/logos/{logoGuid} answers 404, and the failure is visible only in the upload and status responses. The status of an upload is kept for 24 hours; after that a failed upload answers 404 as well, while a completed one keeps answering Completed.

Retries and duplicates ​

  • Idempotency-Key (header, optional but recommended). Any string up to 255 characters, remembered for 24 hours. Repeating the key returns the state of the original upload instead of uploading again — even when the repeated request carries a different file. Use one key per logo you mean to upload, for example derived from your order line.
  • The same file is stored only once per customer. Uploading a file that already exists returns 200 with "deduplicated": true and the logoGuid of the existing logo, whatever name you send.
  • Webhooks. A successfully stored logo sends the logo.created webhook; a deduplicated or failed upload doesn't. The webhook also fires for logos created by edits (a recolor, edits in the editor), so match its LogoGuid with the logoGuid you got here. Never rely on the webhook alone — always read the upload response.
bash
curl https://api-v1.trondesigner.com/api/logos/6993afa3-f416-4af3-9a14-2ce7e3c774f8 \
  -H "Authorization: Bearer $TD_REST_API_KEY"
json
{
  "version": "1.0",
  "logoGuid": "6993afa3-f416-4af3-9a14-2ce7e3c774f8",
  "originalLogoGuid": null,
  "previousLogoGuid": null,
  "customer": {
    "customerGUID": "00000000-0000-0000-0000-000000000000",
    "customerPerson": null, "customerCompany": null, "customerEmail": null, "customerIdentity": null
  },
  "created": "2026-10-15T05:24:09.3307471+00:00",
  "updated": null,
  "filename": "Company logo.svg",
  "name": "Company logo.svg",
  "type": "VECTOR",
  "state": "Active",
  "colors": {
    "isFullColor": false,
    "colorList": [
      { "mapHex": "#FF0000FF", "pmsName": "PANTONE 185 C", "cmykHex": "#00FFD114", "rgbHex": "#EB002AFF", "source": "RGB" },
      { "mapHex": "#0000FFFF", "pmsName": "PANTONE 2736 C", "cmykHex": "#E0C50053", "rgbHex": "#1527ACFF", "source": "RGB" }
    ],
    "shouldUseDarkBackground": false
  },
  "logoUrls": {
    "original": "https://api-v1.trondesigner.com/api/logos/6993afa3-…/file?fileType=ORIGINAL",
    "converted": "https://api-v1.trondesigner.com/api/logos/6993afa3-…/file?fileType=CONVERTED",
    "preview": "https://api-v1.trondesigner.com/api/logos/6993afa3-…/file?fileType=PREVIEW"
  },
  "dimensions": { "size": { "unit": "PIXELS", "width": 200, "height": 100 } },
  "properties": [ { "classPath": "HasTransparency", "value": "True" } ]
}
  • customer — a customerGUID of all zeros means the logo belongs to your whole account, not to a specific end customer.
  • type — VECTOR (SVG, PDF, EPS, AI, …) or RASTER (PNG, JPG, TIFF, …).
  • state — Active for regular logos, which GET /api/logos lists. Hidden for results of edits such as a recolor: readable by their GUID, but not listed.
  • originalLogoGuid, previousLogoGuid — for a logo derived from another one (recolor), the first logo of the chain and the direct predecessor; null for an uploaded logo.
  • colors — isFullColor is true for photos and gradients, which have too many colors to separate; colorList is then empty. Otherwise each color comes in every color system: mapHex as it is in the file, the matched Pantone pmsName, cmykHex (8 hex digits, C, M, Y, K) and rgbHex (the screen color of the matched print color, so it can differ from mapHex). shouldUseDarkBackground is true for mostly light logos (e.g. a white logo) that are invisible on white — show their preview on a dark background. null for logos uploaded before this was added.
  • logoUrls — download links; send the same Authorization header. ORIGINAL is the file as uploaded, CONVERTED the file prepared for print, PREVIEW an image for display.
  • properties — detected characteristics (HasTransparency, HasGradient, HasRasterImage, …), usually with the value "True" or "False". Ignore names you don't know, more may be added.

An unknown logo, a logo of another account and a failed upload all answer 404.

Replace colors of a logo, for example to print it in the customer's brand Pantone. Recoloring always creates a new logo — the source logo stays untouched.

bash
curl -X POST https://api-v1.trondesigner.com/api/logos/6993afa3-f416-4af3-9a14-2ce7e3c774f8/recolor \
  -H "Authorization: Bearer $TD_REST_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{
    "type": "PMS",
    "colors": [
      { "valueFrom": "PANTONE 185 C", "valueTo": "PANTONE Yellow C" },
      { "valueFrom": "PANTONE 2736 C", "valueTo": null }
    ]
  }'
  • type — the color system of all values in the request: PMS (Pantone names such as "PANTONE Yellow C"), CMYK ("#" and 8 hex digits, two per channel C, M, Y, K, e.g. "#0021FF00") or RGB ("#" and 6 hex digits, or 8 with alpha, e.g. "#FFDE00"). For print, prefer PMS or CMYK.
  • valueFrom — a color the logo really has, read from colors.colorList of the logo: pmsName for PMS, cmykHex for CMYK, rgbHex for RGB. Matching ignores case and, for RGB, an opaque FF alpha.
  • valueTo — the new color, or null to remove the color from the logo. Colors you don't list stay as they are.

Several colors of the file can match the same Pantone, so colorList can contain the same pmsName (and cmykHex) more than once. A PMS or CMYK recolor of that value replaces all of them.

The response is the new logo, the same model as GET /api/logos/{logoGuid}, with "state": "Hidden", originalLogoGuid and previousLogoGuid set. Keep its logoGuid: a hidden logo doesn't appear in GET /api/logos, so the GUID is the only way back to it. Use it like any other logo, for example in visualizations or editor links.

ResponseWhen
200 OKThe new logo.
400 Bad RequestThe request can't be applied: an unknown type; no colors; an empty or repeated valueFrom, or one the logo doesn't have (the message lists the logo's colors); a valueTo that isn't valid in the color system, such as an unknown Pantone name; nothing would change; every color would be removed; the logo is full color (isFullColor: true) and has no separate colors to replace.
404 Not FoundThe logo doesn't exist or belongs to another account.
504 Gateway TimeoutRecoloring didn't finish in time. Retrying is safe, but may leave an extra hidden logo behind.
  • Recoloring runs while the request waits — usually a fraction of a second, but tens of seconds for a complex vector. The API gives up after 100 seconds with 504, so set your HTTP client timeout above that.
  • Each call creates another logo, even when it is identical to an earlier one. The new logo sends the logo.createdwebhook.

Generate and download a proofreading ​

Generation runs synchronously: the POST returns once the PDF exists.

bash
# 1. Generate (body is optional; the language defaults to Accept-Language)
curl -X POST https://api-v1.trondesigner.com/api/print-jobs/$PRINT_JOB_GUID/proofreading \
  -H "Authorization: Bearer $TD_REST_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{ "proofreadingLanguageIso2Code": "en" }'
# → { "proofreadingGuid": "435b29be-3841-44e3-80c6-6d5adc74456e" }

# 2. Download it (or use /proofreading/last)
curl https://api-v1.trondesigner.com/api/print-jobs/$PRINT_JOB_GUID/proofreading/435b29be-3841-44e3-80c6-6d5adc74456e \
  -H "Authorization: Bearer $TD_REST_API_KEY" -o proofreading.pdf

templateTag selects a proofreading template by its tag. Print data works the same way: POST …/print-data with { "languageIso2Code": "en", "templateTag": null, "timeZone": "Europe/Prague" } returns { "printDataGuid" }, then GET …/print-data/last downloads the PDF. timeZone is an IANA name used for dates in the document (default UTC).

Generate a signed link that opens the editor on the TronDesigner Integration Site without exposing any key in the URL — for example in an e-mail or from your ERP. options takes the editor arguments (EditorArguments), see Token links. The full schema is GenerateIntegrationSiteLinkRequestDto in Swagger.

bash
curl -X POST https://api-v1.trondesigner.com/api/integration-site-links/generate-open-editor-link \
  -H "Authorization: Bearer $TD_REST_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{
    "options": {
      "openMode": "Create",
      "dataMode": "Exact",
      "printJob": {
        "addProducts": { "supplierCode": "PFC", "variants": [{ "productCode": "10086021" }] },
        "addPrintings": [{ "printPositionCode": "front", "printTechnologyCode": "PAD03" }]
      }
    },
    "expiresAt": "2026-12-31T23:59:59Z"
  }'
# → { "linkToken": "eyJhbGciOi…", "link": "<Integration Site URL>?token=eyJhbGciOi…" }
  • apiKey (optional) — the website integration key the editor session uses. If you omit it, the key tagged Integration Site in Settings → API Keys is used.
  • expiresAt (optional) — the link stops working after this time. Without it the link doesn't expire.
  • returnUrl (optional) — absolute http(s) URL that the Integration Site opens when the editor closes.

To edit an existing design, send "openMode": "Edit" and "printJob": { "printJobGuid": "…" }.

Put customer and order data into printJob.customer. A customer object next to printJob (the old schema) is still accepted and moved there.

Render a logo visualization ​

Render one of your logos onto a product variant — for example for product feeds, e-mails or offers — the server-side counterpart of the integration script's logo visualizations. The response is the JPEG image itself.

bash
curl "https://api-v1.trondesigner.com/api/visualizations/render?logoGuid=$LOGO_GUID&supplierCode=TD&variantCode=10601353_TD&printPositionCode=FRONT&printTechnologyCode=DPRINT03&width=600&height=600" \
  -H "Authorization: Bearer $TD_REST_API_KEY" -o visualization.jpg
ParameterRequiredMeaning
logoGuidyesA logo of your instance (from GET /api/logos or an upload).
supplierCode or supplierGuidone of themsupplierCode must be one of the codes in Settings → Suppliers of the Admin Portal.
variantCodeyesThe supplier's product variant code.
printPositionCode, printTechnologyCodenoThe print option to visualize. Without them TronDesigner picks a print option of the variant.
width, heightnoSize the image fits into, 1–4096 px. Default 300 × 300.
visualization2DModenoVisualization source: RealisticFallbackGenerated (default — a realistic visualization set up for the print option, otherwise one generated from the product's print mockup), RealisticOnly or GeneratedOnly.
  • The key needs the TronDesigner.Products.Print.Visual.Read permission.
  • When there is nothing to render — no source the mode allows, an unknown variant or supplier, or a missing logo file — the API answers 404 Not Found with a short text such as Visual not found. Without supplierCode and supplierGuid it answers 400 Bad Request. 500 Internal Server Error means that rendering failed, and a retry may succeed. Error responses aren't cached.
  • The Settings → Logo Visualizations of the Admin Portal (source, watermark) apply to the integration script only; this endpoint takes the source from visualization2DMode and renders without a watermark.
  • Each successful render counts as one visualization towards the 2D Visualizations quota of your license, the same as the integration script's renders. Failed requests don't. A rendered image may be cached for one hour (Cache-Control: private, max-age=3600) — cache the images on your side instead of rendering the same image repeatedly.

Errors ​

StatusMeaning
400 Bad RequestInvalid request body or parameters (for example an unknown apiKey when creating an editor link).
401 Unauthorized (no body)Missing or malformed Authorization header, unknown or disabled key, or the caller's IP address isn't in the key's allowed list.
401 Unauthorized (JSON body)The key is valid but lacks the required role, or the license lacks API Access / API Automation.
404 Not FoundThe print job or logo doesn't exist (or belongs to another instance), the upload status is unknown or expired, the requested file (image, proofreading, print data) doesn't exist, or there is no logo visualization to render.
413 Payload Too LargeThe uploaded logo file is larger than 20 MB.
415 Unsupported Media TypeA JSON request body was sent without Content-Type: application/json, or the logo upload wasn't sent as multipart/form-data.
500 Internal Server ErrorUnexpected error — retry later or contact PromoTron support with the request time.
504 Gateway TimeoutA logo recolor didn't finish within 100 seconds.

Errors raised by TronDesigner have a JSON body with exceptionType (Validation, Authorization, ApplicationError or UnhandledError), title.message (a message or a message key such as BackEnd.Common.ErrorMessages.UnauthorizedMissingPermission) and a messages array with details:

json
{ "exceptionType": "Validation", "title": { "message": "The waitSeconds form field must be between 0 and 30.", "messageParameters": {} }, "messages": [], "url": null }

When the request itself can't be read — malformed JSON, a value of the wrong type such as WaitSeconds=abc, an unknown enum value or a missing required field — messages lists each problem, and messageParameters.field names the form or query field (waitSeconds) or the JSON path ($.colors[0].valueFrom; $ for the body as a whole):

json
{
  "exceptionType": "Validation",
  "title": { "message": "The request is not valid. Every problem is listed in messages.", "messageParameters": {} },
  "messages": [
    { "message": "The value 'abc' is not valid for WaitSeconds.", "messageParameters": { "field": "waitSeconds" } }
  ],
  "url": null
}

GET /api/logos/{logoGuid}/file returns 204 No Content when the requested file type doesn't exist for that logo.

Keep your REST API key safe ​

A REST API key gives access to every print job, logo, proofreading and print file of your TronDesigner instance.

  • Server only. Never put a REST API key into HTML, browser JavaScript, mobile apps or client-side logs. If it shows up in the browser's Network tab, treat it as leaked.
  • Don't mix key types. The website integration key in data-td-api-key is public by design and protected by its allowed domains. The REST API key is a secret; keep it in a secret store or server environment variable, not in your repository.
  • Least privilege. Give read-only consumers Read Access only, and one key per system so you can revoke them independently.
  • Restrict by IP when your servers have fixed outbound addresses.
  • If a key leaks: disable or regenerate it in the Admin Portal, deploy the new value, check View Usage for calls you don't recognize, and contact PromoTron support if you see data you didn't create.

See also ​

Czech Republic – The Country for the FutureFunded by the European Union – NextGenerationEUThe project was implemented within the The Country for the Future programme of the Ministry of Industry and Trade and co-financed by the European Union under NextGenerationEU.Support · Examples

Czech Republic – The Country for the FutureFunded by the European Union – NextGenerationEUThe project was implemented within the The Country for the Future programme of the Ministry of Industry and Trade and co-financed by the European Union under NextGenerationEU.Support · Examples