Skip to content
Registrieren

Getting Started

Dieser Guide zeigt, wie Sie einen Shop, ein ERP oder MIS mit radixSubmit integrieren: einen Auftrag programmatisch erstellen, Ihren Kunden einen Upload-Link übergeben, auf den Completion-Webhook reagieren und die fertigen Dateien herunterladen.

Die interaktive Endpoint-Referenz finden Sie in der API-Referenz. Die zugehörige maschinenlesbare Spezifikation ist shop-openapi.yaml — importieren Sie sie in Postman, Insomnia oder Ihr Codegen-Tool.

Voraussetzungen

Ein Mandanten-Admin stellt Ihnen ein clientId + clientSecret-Paar aus und konfiguriert (optional) den Order-Completion-Webhook, damit Sie auf Bestätigungen reagieren können. Alle Beispiele verwenden https://api.example.com — ersetzen Sie das durch die radixSubmit-API-Basis- URL, die Sie mit Ihren Zugangsdaten erhalten.

End-to-end-Ablauf

1. POST /auth/token            → { token: "app_…", expireAt }
2. POST /orders                → { order: { id, products[…] } }
3. POST /orders/{id}/share     → { sharedKey }
4. PORTAL_URL/s/{key} senden   → Kunde lädt hoch, ordnet zu, preflightet, bestätigt
5. Webhook: order.confirmed    → POST an Ihren Endpoint (signiert)
6. GET /products/{id}/resources → preflightete Dateien herunterladen (presigned URLs)

1. Authentifizieren

Tauschen Sie Ihre Client-Zugangsdaten gegen einen Bearer-Token. Der Token ist 24 Stunden gültig — cachen Sie ihn bis expireAt und authentifizieren Sie sich bei jedem 401 neu.

bash
curl -X POST https://api.example.com/auth/token \
  -H "Content-Type: application/json" \
  -d '{ "clientId": "YOUR_CLIENT_ID", "clientSecret": "YOUR_CLIENT_SECRET" }'
json
{ "token": "app_eyJhbGciOi...", "type": "Bearer", "expireAt": 1715200000 }

Senden Sie ihn bei jedem weiteren Aufruf mit:

Authorization: Bearer app_eyJhbGciOi...

Einfacher: statischer API-Key (ohne Token-Tausch)

Lieber in einem Schritt? Authentifizieren Sie sich per HTTP Basic mit Ihrer clientId als Benutzername und clientSecret als Passwort — kein /auth/token, kein Ablauf:

bash
curl -u "YOUR_CLIENT_ID:YOUR_CLIENT_SECRET" \
  -X POST https://api.example.com/orders/simple \
  -H "Content-Type: application/json" -d @order.json

Beide Wege liefern dieselbe Application-Identität. Immer über HTTPS senden.


2. Auftrag erstellen

Es gibt zwei Wege, einen Auftrag anzulegen:

  • POST /orders/simple — ein flacher, template-freier Payload für die häufigen Fälle (Flachprodukte, gefalzte Leaflets, rückendrahtgeheftete Broschüren). Für die meisten Shops empfohlen.
  • POST /orders — das vollständige verschachtelte XJDF-basierte Modell (Klebebindung, Hardcover, Multi-Variant). Weiter unten dokumentiert.

Quick order — POST /orders/simple

Beschreiben Sie jede Position flach; das Backend expandiert sie in die volle Hierarchie. Mit options.createShareLink erhalten Sie die Portal-URL direkt zurück.

bash
curl -X POST https://api.example.com/orders/simple \
  -H "Authorization: Bearer app_..." \
  -H "Content-Type: application/json" \
  -d @order.json
json
{
  "order": {
    "name": "Webshop-Bestellung #10249",
    "externalOrderId": "SHOP-10249",
    "customer": { "name": "Acme Retail AG", "email": "max@acme.example" },
    "items": [
      { "type": "flat", "name": "A5 Flyer", "quantity": 500, "format": "A5", "pages": 2, "colors": "4/4" },
      {
        "type": "booklet", "name": "Sommerkatalog", "quantity": 1000,
        "format": "A4", "bodyPages": 32, "coverPages": 4, "binding": "saddle",
        "cover": { "name": "Umschlag", "colors": "4/4" },
        "body":  { "name": "Inhalt",  "colors": "4/4" }
      }
    ]
  },
  "options": { "createShareLink": true }
}

Die Antwort enthält den neuen Auftrag und — bei Bedarf — eine fertige shareUrl:

json
{
  "id": "9b2f8c1a-…",
  "orderNumber": 10249,
  "status": "READY",
  "milestone": "10_CREATED",
  "shareUrl": "https://portal.example.com/portal/3f9a…",
  "products": [
    { "id": "2c1d…", "name": "A5 Flyer", "type": "FlatWork" },
    { "id": "7e4b…", "name": "Sommerkatalog", "type": "Booklet", "displayType": "Booklet" }
  ]
}

Konventionen

  • Format: benannt (A6/A5/A4/A3/DL) oder explizit width/height in mm.
  • colors: Farben vorne/hinten — 4/4 (CMYK beidseitig), 4/0 (nur vorne), 1/0 (Schwarz vorne).
  • material: { weight, type }weight in g/m².
  • Broschüren: nur Rückendrahtheftung (Phase 1), bodyPages ein Vielfaches von 4; Farben pro cover/body; cover: null für eine selbstdeckende Broschüre.

Für Klebebindung, Hardcover oder Multi-Variant nutzen Sie die vollständige Form unten.

Vollständiger Auftrag — POST /orders

Aufträge nutzen ein XJDF-basiertes Auftragsmodell — eine verschachtelte Hierarchie:

order
└── products[]      (1..n)   was produziert wird
    └── parts[]     (1..n)   Bestandteile (Umschlag, Inhalt, Einleger)
        └── pageRanges[] (1..n)  Seitengruppen innerhalb eines Teils
            └── variants[]  (0..n)  Versionen pro Auflage (A/B, Sprache)

Eine minimale mehrteilige Broschüre (Rückendrahtheftung, Umschlag + Inhalt):

bash
curl -X POST https://api.example.com/orders \
  -H "Authorization: Bearer app_..." \
  -H "Content-Type: application/json" \
  -d @order.json
json
{
  "order": {
    "name": "Summer catalogue — A4 8 pages 4/4",
    "externalOrderId": "SHOP-12345",
    "jobCustomer": { "name": "Acme Retail AG" },
    "jobContacts": [
      { "contactType": "Buyer", "name": "Max Mustermann", "email": "max@acme.example" }
    ],
    "products": [
      {
        "name": "Summer catalogue",
        "type": "Booklet",
        "amount": 500,
        "parts": [
          {
            "name": "Body",
            "type": "Body",
            "intent": {
              "layoutIntent": {
                "pages": 4,
                "sides": "TwoSidedHeadToHead",
                "dimensions": { "width": 595.276, "height": 793.701 },
                "numberUp": { "width": 1, "height": 1 }
              }
            },
            "pageRanges": [
              { "value": "1-4", "variants": [{ "name": "1", "amount": 500 }] }
            ]
          },
          {
            "name": "Cover",
            "type": "Cover",
            "intent": {
              "layoutIntent": {
                "pages": 4,
                "sides": "TwoSidedHeadToHead",
                "dimensions": { "width": 595.276, "height": 793.701 },
                "numberUp": { "width": 1, "height": 1 }
              }
            },
            "pageRanges": [
              { "value": "1-4", "variants": [{ "name": "1", "amount": 500 }] }
            ]
          }
        ]
      }
    ]
  }
}

Die Antwort enthält den erstellten Auftrag mit IDs, die Sie später brauchen (order.id, jede product.id, jede variant.id), sowie einen standardOrder-XJDF-Export:

json
{
  "order": {
    "id": "a7e12b7a-4c3d-4b1a-9e8f-1d2c3b4a5f6e",
    "orderNumber": 1042,
    "status": "new",
    "milestone": "created",
    "products": [{ "id": "c3f3…", "parts": [ /* … */ ] }],
    "standardOrder": { "...": "XJDF-compliant export" }
  }
}

Feldanforderungen

layoutIntent.pages, sides, dimensions und numberUp sind erforderlich, damit das Portal Seitenplätze rendern kann. colorIntent und mediaIntent verbessern das Preflight-Routing (sonst werden FOGRA-Defaults verwendet). Maße sind in Punkt (A4 = 595.276 × 841.890). Die API-Referenz enthält das vollständige Schema und ausführlichere Beispiele.

Häufige Fehler

HTTPcodeUrsache
400invalid_argumentPflichtfeld fehlt, unbekanntes Enum oder inkonsistente variants[].amount-Summe vs. product.amount
401unauthenticatedFehlender / abgelaufener / ungültiger Bearer-Token
403permission_deniedToken gehört zu einem anderen Mandanten

Sobald der Auftrag existiert, erstellen Sie einen Share-Link — die URL, über die Ihre Kunden hochladen. Optional hängen Sie Metadaten an, um die Kunden zu identifizieren.

bash
curl -X POST https://api.example.com/orders/{ORDER_ID}/share \
  -H "Authorization: Bearer app_..." \
  -H "Content-Type: application/json" \
  -d '{ "metadata": { "externalUserId": "shop-user-998", "externalUserEmail": "buyer@example.com" } }'
json
{ "sharedKey": "sk_…" }

Bauen Sie die URL, die Sie per E-Mail senden oder auf die Sie weiterleiten:

${PORTAL_URL}/s/${sharedKey}

${PORTAL_URL} ist die Portal-Domain Ihres Mandanten (z. B. https://portal.ihre-firma.de). Der Link ist 7 Tage gültig. Ein neuer Share widerruft den vorherigen; Sie können auch explizit mit DELETE /orders/{ORDER_ID}/share widerrufen.


4. „Redirect-URL" — auf den Abschluss reagieren

Wie der Abschluss heute zugestellt wird

Das Portal nimmt keine browserseitige Redirect-URL pro Auftrag entgegen. Stattdessen liefert das Backend bei Bestätigung durch die Kunden einen signierten order.confirmed-Webhook an die in Ihren Mandanteneinstellungen konfigurierte URL. Behandeln Sie diesen Webhook als Ihr „Redirect"-/Rückkehrsignal. (Falls Sie eine echte Browser-Weiterleitung nach der Bestätigung brauchen, ist das eine mögliche künftige Erweiterung — sprechen Sie uns an.)

Webhook konfigurieren

Bitten Sie Ihren Mandanten-Admin, unter Mandanteneinstellungen → Integrationen → Webhook zu setzen:

  • orderCompletionUrl — Ihr HTTPS-Endpoint.
  • secret — ein gemeinsames Secret (32+ zufällige Bytes empfohlen).

Ist kein Webhook konfiguriert, wird nichts gesendet — pollen Sie als Fallback GET /orders/{id}.

Payload

json
{
  "event": "order.confirmed",
  "timestamp": "2026-04-18T14:32:09.117Z",
  "order": {
    "id": "a7e12b7a-...",
    "name": "Summer catalogue 2026",
    "reference": "SHOP-12345",
    "confirmedAt": "2026-04-18T14:31:55.000Z",
    "products": [
      {
        "id": "c3f…",
        "name": "32-page booklet A4",
        "resources": [
          {
            "id": "r01…",
            "name": "booklet-preflighted.pdf",
            "mimeType": "application/pdf",
            "downloadUrl": "https://s3.../preflighted.pdf?X-Amz-Signature=…"
          }
        ]
      }
    ]
  }
}

Zustellsemantik

  • Retries: bis zu 4 Versuche mit Backoff 0s, 1s, 3s, 9s.
  • Erfolg: beliebiger HTTP-2xx.
  • Kein Dedup-Header — machen Sie Ihren Handler idempotent auf order.id.

Signatur verifizieren

Jede Anfrage trägt X-Webhook-Signature: <hex>, wobei <hex> = HMAC-SHA256(rawBody, secret). Verifizieren Sie gegen den Raw-Body vor dem JSON-Parsen — erneutes Serialisieren ändert den Digest.

js
import crypto from 'node:crypto'
import express from 'express'

const app = express()
app.post(
  '/webhooks/radix-submit',
  express.raw({ type: 'application/json' }),
  (req, res) => {
    const expected = crypto
      .createHmac('sha256', process.env.RADIX_SUBMIT_WEBHOOK_SECRET)
      .update(req.body) // raw Buffer
      .digest('hex')

    const got = req.header('X-Webhook-Signature')
    if (!got || !crypto.timingSafeEqual(Buffer.from(expected), Buffer.from(got))) {
      return res.status(401).send('bad signature')
    }

    const payload = JSON.parse(req.body.toString('utf8'))
    // …payload.order verarbeiten (idempotent auf payload.order.id)…
    res.status(200).end()
  },
)

5. Preflightete Dateien herunterladen

Die downloadUrls im Webhook sind 7 Tage gültige presigned S3-URLs — laden Sie möglichst sofort herunter. Um die Ressourcen eines Produkts später abzurufen (oder nach Ablauf eines Links), listen Sie sie per Produkt-ID (order.products[].id). Download-URLs sind standardmäßig enthalten:

bash
curl "https://api.example.com/products/{PRODUCT_ID}/resources" \
  -H "Authorization: Bearer app_..."
json
{
  "resources": [
    {
      "id": "r01…",
      "name": "booklet-preflighted.pdf",
      "mimeType": "application/pdf",
      "pageCount": 32,
      "type": "Preflighted",
      "downloadUrl": "https://s3.../preflighted.pdf?X-Amz-Signature=…"
    }
  ]
}

Das liefert die Ressourcen auf Produktebene — das zusammengeführte, preflightete Ergebnis, das Sie an die Produktion weitergeben. Mit ?type=Preflighted filtern oder mit ?withDownloadUrls=false die presigned URLs weglassen. (Die kundenseitigen Eingaben pro Variante liegen unter order.products[].parts[].pageRanges[].variants[].resources[] in der Auftragsantwort.)


Endpoint-Referenz

MethodePfadZweck
POST/auth/tokenZugangsdaten tauschen → 24h-Bearer-Token
POST/ordersAuftrag erstellen (XJDF-basierter Auftrag)
GET/orders/{id}Auftrag + Hierarchie + Status abrufen
POST/orders/{id}/share7-Tage-Share-Link erstellen
DELETE/orders/{id}/shareAktive Shares widerrufen
GET/products/{id}/resourcesRessourcen eines Produkts + presigned Downloads auflisten
OutboundPOST {orderCompletionUrl}order.confirmed-Webhook bei Bestätigung

Vollständige Request-/Response-Schemata und „Try it out" finden Sie in der API-Referenz.