CR80 PARTNER INTEGRATION

Integrate CR80 into your website

Connect the CR80 editor to your website with an iframe. Find configuration, JavaScript examples and APIs for receiving and using CR80 designs in your system.

HTTP workflow for AI agents (English) · JSON Schema v1 · Example design

  1. After approval, open the partner workspace and sign in with the verified email address from your application. Claim your invitation there.
  2. Open partner settings. Configure your brand, exact HTTPS origins and physical card catalogue. Each material and technology is a separate SKU.
  3. Replace YOUR_PARTNER_ID in the examples with the partner ID from settings. This is a public identifier. Licence keys and API secrets are used only on the server.
  4. In test mode, previews carry the PROVPERIOD watermark and the editor emits cr80-test-design. Production APIs become available when the partner has active production access.

Embed the editor

Add your website origin, including the scheme and any non-default port, in partner settings. The page embedding the editor must match an approved origin. Use HTTPS in production.

<iframe id="cr80-editor"
  src="https://cr80.se/editor?partner=YOUR_PARTNER_ID&embed=1"
  title="Card editor"
  style="width:100%;height:760px;border:0"
></iframe>

The partner selects branding, catalogue and capabilities. Browser embedding does not grant account access. CR80 accounts and partner customer accounts remain separate.

Receive a design safely

The editor sends the design to the host page using postMessage. The example filters by CR80 origin, iframe window, partner ID and message type. The message contains name and design. Test mode uses cr80-test-design with test: true; active production access uses cr80-design with test: false.

const frame = document.getElementById("cr80-editor");
const partnerId = "YOUR_PARTNER_ID";
window.addEventListener("message", (event) => {
  if (event.origin !== "https://cr80.se") return;
  if (event.source !== frame.contentWindow) return;
  const message = event.data;
  if (!message || message.partner !== partnerId) return;
  if (message.type === "cr80-test-design" && message.test === true) {
    // Test-mode completion uses a separate message type.
    document.getElementById("result").textContent = "Test design received";
    return;
  }
  if (message.type !== "cr80-design" || message.test !== false) return;
  // message.design contains the versioned CR80 design document.
  // Pass it to your backend to continue your integration.
  document.getElementById("result").textContent = message.name;
});

The JavaScript example applies only to communication between the iframe and host page in the browser. The server APIs below use standard HTTP requests and JSON and are independent of programming language.

Create a result element on your page: <p id="result" role="status"></p>. The example displays the design name in this element. The message transfers a design and does not create an order. Validation and any order processing take place in your server integration.

APIs and the design contract

Public read-only partner endpoints
EndpointPurpose
GET /api/partner/config?id=IDBrand, approved origins, capabilities and access mode.
GET /api/partner/catalog?id=IDPhysical card SKUs and public availability.

The design format is versioned JSON. Saving and reopening a design uses the complete document, including its version and any extension fields. Measurements use millimetres and monetary amounts use integer öre. The selected SKU links the design to the partner’s material, technology and finishing options.

CR80 rendering uses the same design format for previews and production files. Production rendering is part of the server integration.

Signed launches, managed customer identities, production rendering and SPI use scoped server credentials. They are separate from the iframe integration and are enabled per partner. The partner ID provides identification, not authentication.

Render a design file using the API

An exported .cr80.json file is the design object sent in the design field. These APIs accept JSON, not multipart uploads. Neither an open editor nor a local printer is needed for PNG previews or PDF exports.

Server authentication

The APIs use HTTPS and JSON and can be called from any server-side language. Examples show the method, path, headers and JSON directly, without an SDK or a specific runtime. CR80 enables machine access for an active partner organization with a version 1 production contract. This is separate from the public iframe configuration.

Choose X-CR80-Contract per API using the table. The machine credential stays on the server. Approved iframe origins do not grant browser access to these server APIs.

Rendering and export endpoints
EndpointX-CR80-ContractResponse
POST /api/production/previewprint-station-v1PNG image
GET /api/production/export-profilesprint-export-v1JSON containing profiles
POST /api/production/exportsprint-export-v1JSON containing a download URL
GET /api/production/exports/{id}print-export-v1ZIP containing PDF and production data

Authentication headers

The base URL is https://cr80.se. Replace YOUR_PARTNER_ID and YOUR_MACHINE_CREDENTIAL with your server credentials. Send the complete design file JSON object in design. The examples use a small name card; also replace white-pvc with your card SKU. Your HTTP client serializes the JSON and handles transport headers such as Content-Length. Allow up to 180 seconds for rendering.

X-CR80-Contract: print-station-v1
X-CR80-Partner: YOUR_PARTNER_ID
X-License-Key: YOUR_MACHINE_CREDENTIAL

PNG preview

POST /api/production/preview returns image/png with HTTP 200. The preview is rendered at 100 dpi using CR80’s shared renderer. The response is not cached and the request does not save a design. Test mode adds the PROVPERIOD watermark.

Preview request fields
FieldDescription
schemaVersionRequired. The API contract version, always 1. The design’s own version is in design.version.
designRequired. The complete JSON object from the design file.
renderedAtRequired. An ISO 8601 UTC timestamp, such as 2026-09-21T12:00:00.000Z. Fixes time-dependent fields during rendering.
sideOptional: front or back. Defaults to front.
rowOptional object containing column names and string values for the displayed card. Use the column names bound in the design.
rowIndex / rowCountOptional: zero-based row index and total row count. Defaults are 0 and 1. Pass the actual row separately in row.
POST /api/production/preview HTTP/1.1
Host: cr80.se
X-CR80-Contract: print-station-v1
X-CR80-Partner: YOUR_PARTNER_ID
X-License-Key: YOUR_MACHINE_CREDENTIAL
Content-Type: application/json

{
  "schemaVersion": 1,
  "design": {
    "version": 1,
    "name": "Example card",
    "orientation": "portrait",
    "baseCardSku": "white-pvc",
    "front": {
      "background": "#ffffff",
      "layers": [
        {
          "id": "name",
          "type": "text",
          "x": 6,
          "y": 15,
          "widthMm": 42,
          "fontSizeMm": 4,
          "text": "{name}"
        }
      ]
    }
  },
  "side": "front",
  "row": {
    "name": "Sample Person"
  },
  "rowIndex": 0,
  "rowCount": 2,
  "renderedAt": "2026-09-21T12:00:00.000Z"
}

Response

HTTP/1.1 200 OK
Content-Type: image/png
Cache-Control: private, no-store

[binary PNG body]

Save the binary response body as a PNG file. Set side to back for the reverse side. For multiple cards, send one request per side and row; set row, rowIndex and rowCount to match your data table.

PDF export

1. Retrieve an export profile

The partner’s export profile defines PDF/X-4 or PDF/X-1a:2001, the CMYK/ICC profile, bleed, crop marks and page order. Configure it under Partner workspace → Print files. GET /api/production/export-profiles returns only the authenticated partner’s active profiles.

GET /api/production/export-profiles HTTP/1.1
Host: cr80.se
X-CR80-Contract: print-export-v1
X-CR80-Partner: YOUR_PARTNER_ID
X-License-Key: YOUR_MACHINE_CREDENTIAL

The response is an object containing profiles. Each entry includes id, revision, profile, iccSha256 and card. The profile object includes sku, standard and pageOrder. Without profileId, export selects the active profile for design.baseCardSku. With profileId, selection is pinned to a profile revision; a stale revision returns 409.

2. Prepare the export JSON

The rows field contains exactly the cards to include, one object per card. Values are strings and keys match the design’s bound fields. For two identical cards without data fields, use [{}, {}]. The API does not automatically select rows from the design file’s embedded data table.

[
  {
    "name": "Sample Person"
  },
  {
    "name": "Another Person"
  }
]
PDF export request fields
FieldDescription
schemaVersionRequired. The API contract version, always 1. The design’s own version is in design.version.
designRequired. The complete JSON object from the design file.
requestKeyRequired UUID identifying the export. Reuse the same key and JSON when retrying.
rowsRequired: 1–100 objects containing string values. Each object produces one card; the export profile determines which sides are included.
profileIdOptional UUID from the profile’s id. Omit it to select automatically using design.baseCardSku.
renderedAtRequired. An ISO 8601 UTC timestamp, such as 2026-09-21T12:00:00.000Z. Fixes time-dependent fields during rendering.

Generate a new UUID in requestKey for each new export and set the rendering timestamp in renderedAt. Replace the example values below for a new export. Store the request in your system so the complete JSON, including its key and timestamp, can be reused for retries.

3. Create and download the print file

POST /api/production/exports returns HTTP 200 with id, downloadUrl, ticket and expiresAt when the export is ready. Exporting does not start a print job or create an order.

POST /api/production/exports HTTP/1.1
Host: cr80.se
X-CR80-Contract: print-export-v1
X-CR80-Partner: YOUR_PARTNER_ID
X-License-Key: YOUR_MACHINE_CREDENTIAL
Content-Type: application/json

{
  "schemaVersion": 1,
  "requestKey": "5dc49711-acb9-4a92-8ed6-b6f9d0617625",
  "design": {
    "version": 1,
    "name": "Example card",
    "orientation": "portrait",
    "baseCardSku": "white-pvc",
    "front": {
      "background": "#ffffff",
      "layers": [
        {
          "id": "name",
          "type": "text",
          "x": 6,
          "y": 15,
          "widthMm": 42,
          "fontSizeMm": 4,
          "text": "{name}"
        }
      ]
    }
  },
  "rows": [
    {
      "name": "Sample Person"
    },
    {
      "name": "Another Person"
    }
  ],
  "renderedAt": "2026-09-21T12:00:00.000Z"
}

Example response (selected fields; ticket omitted)

HTTP/1.1 200 OK
Content-Type: application/json
Cache-Control: private, no-store

{
  "id": "export-aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa",
  "downloadUrl": "/api/production/exports/export-aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa",
  "expiresAt": "2026-09-22T12:00:00.000Z"
}

Download the ZIP file

Use the path in the response’s downloadUrl for the next GET request to https://cr80.se, with the same print-export-v1 authentication. Save the binary response body as a ZIP file and read print.pdf from it.

GET /api/production/exports/export-aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa HTTP/1.1
Host: cr80.se
X-CR80-Contract: print-export-v1
X-CR80-Partner: YOUR_PARTNER_ID
X-License-Key: YOUR_MACHINE_CREDENTIAL
HTTP/1.1 200 OK
Content-Type: application/zip
Cache-Control: private, no-store

[binary ZIP body]

The ZIP contains print.pdf, production.json and LAS-MIG.txt. Ticket and production.json describe the frozen profile revision, page-to-row mapping, geometry and file hashes. The download URL is private, requires authentication and is valid for 24 hours as specified by expiresAt.

Retries and limits

On timeout or a transient failure, resend the same POST request with unchanged JSON. An identical retry returns the original export even if the profile has since changed. Changed JSON under the same requestKey returns 409. An expired export returns 410 and requires a new request with a new key.

The maximum request size is 32 MB. PDF exports allow up to 100 cards and a 100 MB PDF. Preview allows 60 requests/minute; PDF export allows 10 writes and 120 reads/minute per organization and server process. One PDF preparation runs at a time per server process. On 429, wait before resending the same request.

The PDF contract does not support UV/holographic panels, magnetic or chip encoding, spot colors, PDF/VT or press-sheet imposition. Such input is rejected or falls outside this API.

Responses and errors

Error responses are JSON containing error. Some also include code, issues or agreementUrl. Clients should use the HTTP status and any code rather than parse the localized error message.

HTTP statuses for rendering and export APIs
StatusDescription
400Invalid JSON, design or request size.
401Missing or invalid authentication, including an incorrect contract header.
403Insufficient access, an untrusted origin or production not activated (PARTNER_PRODUCTION_NOT_ACTIVE).
404The export does not exist in the authenticated organization.
409The request key was reused with different content, or the export profile is stale or missing.
410The export has expired or been erased.
415POST requires Content-Type: application/json.
422The design could not be rendered or does not match the export profile. PDF validation errors may include issues.
428The organization’s current data-processing agreement is missing (PROCESSOR_AGREEMENT_REQUIRED). The response provides agreementUrl.
429The request limit has been reached or the PDF renderer is busy.
503The agreement service is temporarily unavailable (PROCESSOR_AGREEMENT_UNAVAILABLE).

Example 422 response

{
  "error": "Designen uppfyller inte tryckeriets krav.",
  "issues": [
    "Kort 1 saknar data i kolumnerna: name."
  ]
}

Organization export and switching

A verified owner or administrator can download a free export under Account → Organization export. Export remains available after commercial expiry and archival. You do not need a new subscription or a new agreement to retrieve existing data.

Designs and handovers
Versioned CR80 JSON, embedded images/fonts, variants and data rows. Only designs explicitly bound to the organization; handover snapshots belong to the sending organization, claimed copies to the receiving account.
Partner configuration
Branding, allowed origins, card catalogue, channel/provider revisions and PDF export profiles. ICC bytes are base64 with their SHA-256.
Production history
Submitted order designs and rows, deliveries, station configuration, immutable job payloads, per-card acknowledgements and recovery instructions. Provider-only orders exclude another seller’s retail pricing and invoices.
Billing and agreements
The organization’s billing account, subscriptions, invoice lines, invoice PDF bytes (base64), partner invoices/settlements, DPA source documents and acceptance evidence, and the accepted partner offer.

Format and boundaries

Numbered ZIP parts contain UTF-8 JSON pages and a SHA-256 manifest. Dimensions are millimetres and monetary amounts integer öre. Keep all parts. Each page is read consistently, but the full export is not a database snapshot: pause edits for a final transfer. Rows created after the export cutoff are omitted; edits and deletions can affect unread pages. Hardware reports reflect the time of each page.

Excluded: passwords, API/station/OAuth credentials, other organizations’ data, personal designs, customer-owned claimed copies, CR80 software and standard templates, transient browser sessions, expired shares and temporary production files. External URLs remain references; files stored only in a browser, partner system or external URL must be transferred from their owner. Existing print-PDF downloads retain their own 24-hour lifetime. Exporting source data does not create new production files or release print jobs.

HTTP interface

These account endpoints require the owner’s or administrator’s CR80 browser session. Partner machine credentials cannot export an entire organization. GET /api/account/organization-export lists authorized organizations (including archived ones), categories and the cutoff timestamp. POST the following JSON to /api/account/organizations/{organizationId}/export with Content-Type: application/json, the exact CR80 Origin and X-CR80-Data-Action: export-organization.

{
  "action": "page",
  "category": "designs",
  "after": "",
  "cutoff": "2026-09-21T12:00:00.000Z",
  "runId": "8c987cf9-6a43-433b-9e88-c9ed0bc984f0"
}

Use a new UUID and the returned cutoff. Follow nextCursor as after until null, for every category. The response has records, receiptId and X-Export-SHA256 for the exact response bytes. Pages hold up to 50 records/8 MiB, allowing one larger record up to 64 MiB; oversized records need assisted export. The limit is 120 requests/minute per account and server process. Retry the same cursor on 429/503; compare checksums because an intervening edit can change the result.

Category identifiers and exact fields
organization
id, name, archived_at, created_at, updated_at
members
id, user_id, role, created_at
designs
id, user_id, name, design, project_id, revision, project_metadata, created_at, updated_at
shares
id, design_id, name, design, expires_at, revoked_at, created_at
quotes
id, retail, terms_version, target_working_days, expires_at, created_at
usage
id, event, origin, created_at
handovers
id, source_design_id, source_revision, recipient_email, customer_label, name, snapshot, expires_at, revoked_at, claimed_at, created_at
partners
id, name, config_version, logo_url, theme, allowed_origins, portal_url, pricing_url, catalog_url, pricing_visibility, capabilities, production_contract, fulfillment, fulfillment_label, destination_type, order_email, pricing, terms_url, design_guide_url, active, created_at
catalogue
id, partner_id, slug, name, technology, subtype, color, color_name, surcharge_ore, stock_quantity, oversell, active, sort_order, created_at
channels
id, legacy_partner_id, enabled, current_revision, created_at, updated_at
channel_revisions
id, branded_channel_id, revision, snapshot, created_at
providers
id, visibility, current_revision, created_at, updated_at
provider_revisions
id, fulfilment_provider_id, revision, snapshot, created_at
export_profiles
id, partner_id, sku, revision, profile, icc_sha256, icc_base64, created_at
orders
id, partner_id, commercial_channel, design_name, design, data_csv, quantity, status, price_ore, partner_order_ref, partner_status, tracking_url, customer_email, customer_name, shipping_address, terms_accepted_at, terms_version, created_at
fulfilment_orders
id, design_name, design, data_csv, quantity, partner_order_ref, partner_status, tracking_url, shipping_address, created_at
stations
id, name, partner_id, service_version, last_seen_at, revoked_at, created_at, updated_at
printers
id, station_id, instance_id, display_name, configuration, report, health, last_seen_at
encoders
id, station_id, instance_id, display_name, kind, connection, health, last_seen_at
jobs
id, station_id, printer_instance_id, payload, state, created_at, updated_at
acknowledgements
id, job_id, card_id, payload, created_at
recoveries
id, job_id, card_id, payload, state, created_at, applied_at
billing_accounts
id, legal_name, organization_number, vat_number, invoice_email, invoice_reference, billing_address, currency, billing_enabled, terms_accepted_at, terms_version, created_at, updated_at
subscriptions
id, catalog_item_id, status, cadence, current_period_start, current_period_end, trial_ends_at, cancel_at_period_end, ended_at, unit_ore_snapshot, vat_basis_points_snapshot, entitlement_snapshot, created_at, updated_at
subscription_history
id, subscription_id, event_type, occurred_at, previous_status, next_status, previous_period_start, previous_period_end, next_period_start, next_period_end, cancel_at_period_end, ended_at, created_at
invoices
id, original_invoice_id, document_number, kind, state, payment_state, currency, total_ore, vat_ore, issue_date, due_date, pdf_base64, pdf_sha256, created_at
invoice_lines
id, invoice_id, position, description, quantity, unit_list_ore, list_ore, discount_ore, vat_base_ore, vat_basis_points, vat_ore, total_ore, created_at
partner_invoices
id, partner_id, month, status, editor_loads, designs_sent, order_count, order_value_ore, license_ore, commission_ore, created_at, updated_at
settlements
id, order_id, amount_ore, currency, status, provider_reference, created_at, updated_at
agreements
id, snapshot_id, legal_entity_name, organization_number, country_code, accepted_by_name, accepted_by_email, accepted_by_role, authority_confirmed, accepted_at
agreement_documents
id, document_id, version, sha256, title, markdown, source_url, captured_at
partner_acceptance
partner_id, accepted_at, pilot_ends_at, acceptance, approved_at

After saving and checking a part, POST {action: "confirm", receipts: [{id: receiptId, sha256: responseHash}]} (at most 100 receipts). CR80 retains metadata-only preparation and recipient-confirmation evidence, not an extra copy of the customer’s content. Confirmation can be retried safely.

Switching and termination

For an assisted transfer, a large record, a final consistent snapshot or erasure, contact contact@premex.se with your organization ID and desired outcome. CR80 verifies your authority and the recipient, records the scope, timing and receipt, and provides secure transfer assistance. Do not email cardholder data or credentials. Billing termination, data retrieval and erasure are separate steps; archived source data is not automatically erased. The partner agreement and DPA govern timing, return, erasure and any required legal retention.