Zum Inhalt springen

Entwickler

API-Dokumentation

So rufen Ihre Systeme Kabel, Familien und Dateien ab und legen Anfragen an. Die Beispiele zeigen erfundene Daten einer Beispiel-Website; Ihre eigene Adresse und Ihre Daten sehen Sie erst mit einem API-Schlüssel.

Grundlagen

Basis-URL: https://testing.cablecreations.de/api/v1

  • Alle Antworten sind JSON. Zeitangaben sind ISO 8601 in UTC, IDs sind undurchsichtige Zeichenketten.
  • Die API liefert nur veröffentlichte Kabel und öffentliche Dateien – dasselbe, was Ihr öffentlicher Katalog zeigt.
  • Datei-URLs sind absolut und dürfen dauerhaft zwischengespeichert werden: Ändert sich eine Datei, ändert sich ihr contentHash.
  • Die Antworten sind ein stabiler Vertrag der Version v1. Neue Felder können hinzukommen; bestehende ändern ihre Bedeutung nicht.
  • Die technischen Daten eines Kabels (technical) sind eine geordnete Liste: Die Reihenfolge ist die des Datenblatts.

OpenAPI-Dokument (JSON)

Authentifizierung

Jeder Aufruf braucht einen API-Schlüssel Ihrer Organisation im Kopf Authorization:

Authorization: Bearer cbl_…
  • Ein Schlüssel gilt genau für Ihre Organisation. Mit ihm lässt sich nichts anderer Organisationen lesen oder ändern.
  • Die Berechtigung Lesen genügt für alle Abrufe; zum Anlegen von Anfragen braucht der Schlüssel zusätzlich Schreiben.
  • Über die API angelegte Anfragen werden der Person zugeordnet, die den Schlüssel angelegt hat. Verlässt sie Ihre Organisation, kann der Schlüssel weiter lesen, aber nicht mehr schreiben: Legen Sie dann einen neuen an.
  • Die API ist für die Kommunikation zwischen Servern gedacht. Sie sendet keine CORS-Freigaben: Verwenden Sie den Schlüssel nie im Browser oder in einer App, sondern nur auf Ihrem Server.
  • Behandeln Sie den Schlüssel wie ein Passwort. Widerrufen Sie ihn, sobald er nicht mehr gebraucht wird oder bekannt geworden sein könnte.

Aufrufe

Kabel auflisten

GET /api/v1/cablesBerechtigung: Lesen

Alle veröffentlichten Kabel Ihrer Organisation, sortiert nach dem URL-Namen (slug), mit technischen Daten und öffentlichen Dateien.

Aufruf

curl "https://testing.cablecreations.de/api/v1/cables?limit=1" \
  -H "Authorization: Bearer $API_KEY"

Antwort (200)

{
  "data": [
    {
      "id": "0f8b3c1e-5a0d-4a51-9d0e-3a8f4a8f5b11",
      "slug": "nym-j-3x1-5",
      "name": "NYM-J 3x1,5",
      "designation": "NYM-J 3x1,5 mm²",
      "description": "Mantelleitung für die feste Verlegung.",
      "family": {
        "id": "7c1d2a90-0d53-4f0e-8f47-5a0c1c0a2e01",
        "slug": "installationsleitungen",
        "name": "Installationsleitungen"
      },
      "technical": [
        {
          "kind": "field",
          "label": "Nennspannung",
          "value": {
            "kind": "text",
            "text": "300/500 V"
          }
        },
        {
          "kind": "field",
          "label": "Aderzahl",
          "value": {
            "kind": "text",
            "text": "3"
          }
        }
      ],
      "assets": [
        {
          "id": "b6f0a4d2-93c4-4a6b-a1b5-2f1f6f3f9c22",
          "kind": "image",
          "name": "nym-j-3x1-5-catalog-profile.png",
          "url": "https://kabel.example/files/b6f0a4d2-93c4-4a6b-a1b5-2f1f6f3f9c22/nym-j-3x1-5-catalog-profile.png",
          "mime": "image/png",
          "bytes": 184320,
          "width": 1600,
          "height": 256,
          "contentHash": "9f2c7d0b6a1e4c3f8b5d2a7e0c9f4b1d6e3a8c5f2b7d0e9a4c1f6b3d8e5a2c7f",
          "createdAt": "2026-03-09T12:00:00.000Z"
        }
      ],
      "mainPictureId": "b6f0a4d2-93c4-4a6b-a1b5-2f1f6f3f9c22",
      "variants": [
        {
          "id": "3d0c7e52-6c1a-4a0e-9a57-0b6a4a3b7d10",
          "name": "3x1,5",
          "articleNumber": "100-315",
          "outerDiameterMm": 8.4,
          "weightKgPerKm": 122,
          "copperKgPerKm": 43,
          "extra": [
            {
              "label": "Biegeradius",
              "value": "34 mm"
            }
          ],
          "hasModel": true,
          "crossSectionUrl": "https://kabel.example/files/derived/7c2f1d7e-0b4a-4f0e-9d53-6a1b2c3d4e5f/4be1c07a92d35f68/querschnitt-nym-j-3x1-5.svg",
          "crossSectionDatasheetUrl": "https://kabel.example/files/derived/a41d9c3b-58e2-4c17-b0f6-2d7e8f9a0b1c/90c3e6f1a2b4d578/querschnitt-sw-nym-j-3x1-5.svg",
          "webModelUrl": "https://kabel.example/files/derived/e8b05f26-1c3d-4a79-8e42-5f6a7b8c9d0e/1f6d2a8c4e0b7359/modell-nym-j-3x1-5.glb",
          "crossSectionLineArtUrl": "https://kabel.example/files/derived/3d7a2c51-9e4b-4f86-a1c0-6b8e2d4f7a19/5e8c1a3f7b2d9046/querschnitt-linien-nym-j-3x1-5.svg",
          "crossSectionShadedUrl": "https://kabel.example/files/derived/9f41c2d8-6a7e-4b35-8d10-2e5c7b9a4f63/7a2e5c9d1f4b8036/querschnitt-schattiert-nym-j-3x1-5.svg",
          "crossSectionEngravedUrl": "https://kabel.example/files/derived/c58e3b1a-2d9f-4e70-b6a4-8f1c0d7e5a92/e9b4d27c3a6f1085/querschnitt-kreuzschraffur-nym-j-3x1-5.svg",
          "profileUrl": "https://kabel.example/files/derived/b62e9f17-4a3c-4d58-9b0e-1c7f3a5d8e24/c3a91f6e2b8d4075/profil-nym-j-3x1-5.svg"
        },
        {
          "id": "5a9e1f04-2b7c-4d3e-8c61-7e2f9d0a1b33",
          "name": "5x2,5",
          "articleNumber": null,
          "outerDiameterMm": 11.2,
          "weightKgPerKm": null,
          "copperKgPerKm": null,
          "extra": [],
          "hasModel": false,
          "crossSectionUrl": null,
          "crossSectionDatasheetUrl": null,
          "webModelUrl": null,
          "crossSectionLineArtUrl": null,
          "crossSectionShadedUrl": null,
          "crossSectionEngravedUrl": null,
          "profileUrl": null
        }
      ],
      "publishedAt": "2026-03-10T08:30:00.000Z",
      "updatedAt": "2026-03-10T08:30:00.000Z",
      "datasheetUrl": "https://kabel.example/api/v1/cables/nym-j-3x1-5/datasheet"
    }
  ],
  "next": "WyJueW0tai0zeDEtNSJd"
}

Ein Kabel abrufen

GET /api/v1/cables/{slug}Berechtigung: Lesen

Ein veröffentlichtes Kabel anhand seines URL-Namens. Entwürfe und archivierte Kabel antworten mit 404.

Aufruf

curl "https://testing.cablecreations.de/api/v1/cables/nym-j-3x1-5" \
  -H "Authorization: Bearer $API_KEY"

Antwort (200)

{
  "id": "0f8b3c1e-5a0d-4a51-9d0e-3a8f4a8f5b11",
  "slug": "nym-j-3x1-5",
  "name": "NYM-J 3x1,5",
  "designation": "NYM-J 3x1,5 mm²",
  "description": "Mantelleitung für die feste Verlegung.",
  "family": {
    "id": "7c1d2a90-0d53-4f0e-8f47-5a0c1c0a2e01",
    "slug": "installationsleitungen",
    "name": "Installationsleitungen"
  },
  "technical": [
    {
      "kind": "field",
      "label": "Nennspannung",
      "value": {
        "kind": "text",
        "text": "300/500 V"
      }
    },
    {
      "kind": "field",
      "label": "Aderzahl",
      "value": {
        "kind": "text",
        "text": "3"
      }
    }
  ],
  "assets": [
    {
      "id": "b6f0a4d2-93c4-4a6b-a1b5-2f1f6f3f9c22",
      "kind": "image",
      "name": "nym-j-3x1-5-catalog-profile.png",
      "url": "https://kabel.example/files/b6f0a4d2-93c4-4a6b-a1b5-2f1f6f3f9c22/nym-j-3x1-5-catalog-profile.png",
      "mime": "image/png",
      "bytes": 184320,
      "width": 1600,
      "height": 256,
      "contentHash": "9f2c7d0b6a1e4c3f8b5d2a7e0c9f4b1d6e3a8c5f2b7d0e9a4c1f6b3d8e5a2c7f",
      "createdAt": "2026-03-09T12:00:00.000Z"
    }
  ],
  "mainPictureId": "b6f0a4d2-93c4-4a6b-a1b5-2f1f6f3f9c22",
  "variants": [
    {
      "id": "3d0c7e52-6c1a-4a0e-9a57-0b6a4a3b7d10",
      "name": "3x1,5",
      "articleNumber": "100-315",
      "outerDiameterMm": 8.4,
      "weightKgPerKm": 122,
      "copperKgPerKm": 43,
      "extra": [
        {
          "label": "Biegeradius",
          "value": "34 mm"
        }
      ],
      "hasModel": true,
      "crossSectionUrl": "https://kabel.example/files/derived/7c2f1d7e-0b4a-4f0e-9d53-6a1b2c3d4e5f/4be1c07a92d35f68/querschnitt-nym-j-3x1-5.svg",
      "crossSectionDatasheetUrl": "https://kabel.example/files/derived/a41d9c3b-58e2-4c17-b0f6-2d7e8f9a0b1c/90c3e6f1a2b4d578/querschnitt-sw-nym-j-3x1-5.svg",
      "webModelUrl": "https://kabel.example/files/derived/e8b05f26-1c3d-4a79-8e42-5f6a7b8c9d0e/1f6d2a8c4e0b7359/modell-nym-j-3x1-5.glb",
      "crossSectionLineArtUrl": "https://kabel.example/files/derived/3d7a2c51-9e4b-4f86-a1c0-6b8e2d4f7a19/5e8c1a3f7b2d9046/querschnitt-linien-nym-j-3x1-5.svg",
      "crossSectionShadedUrl": "https://kabel.example/files/derived/9f41c2d8-6a7e-4b35-8d10-2e5c7b9a4f63/7a2e5c9d1f4b8036/querschnitt-schattiert-nym-j-3x1-5.svg",
      "crossSectionEngravedUrl": "https://kabel.example/files/derived/c58e3b1a-2d9f-4e70-b6a4-8f1c0d7e5a92/e9b4d27c3a6f1085/querschnitt-kreuzschraffur-nym-j-3x1-5.svg",
      "profileUrl": "https://kabel.example/files/derived/b62e9f17-4a3c-4d58-9b0e-1c7f3a5d8e24/c3a91f6e2b8d4075/profil-nym-j-3x1-5.svg"
    },
    {
      "id": "5a9e1f04-2b7c-4d3e-8c61-7e2f9d0a1b33",
      "name": "5x2,5",
      "articleNumber": null,
      "outerDiameterMm": 11.2,
      "weightKgPerKm": null,
      "copperKgPerKm": null,
      "extra": [],
      "hasModel": false,
      "crossSectionUrl": null,
      "crossSectionDatasheetUrl": null,
      "webModelUrl": null,
      "crossSectionLineArtUrl": null,
      "crossSectionShadedUrl": null,
      "crossSectionEngravedUrl": null,
      "profileUrl": null
    }
  ],
  "publishedAt": "2026-03-10T08:30:00.000Z",
  "updatedAt": "2026-03-10T08:30:00.000Z",
  "datasheetUrl": "https://kabel.example/api/v1/cables/nym-j-3x1-5/datasheet"
}

Dateien auflisten

GET /api/v1/assetsBerechtigung: Lesen

Die öffentlichen Dateien Ihrer veröffentlichten Kabel, die neueste zuerst. Mit cable=<slug> nur die Dateien eines Kabels.

Aufruf

curl "https://testing.cablecreations.de/api/v1/assets?cable=nym-j-3x1-5" \
  -H "Authorization: Bearer $API_KEY"

Antwort (200)

{
  "data": [
    {
      "id": "b6f0a4d2-93c4-4a6b-a1b5-2f1f6f3f9c22",
      "kind": "image",
      "name": "nym-j-3x1-5-catalog-profile.png",
      "url": "https://kabel.example/files/b6f0a4d2-93c4-4a6b-a1b5-2f1f6f3f9c22/nym-j-3x1-5-catalog-profile.png",
      "mime": "image/png",
      "bytes": 184320,
      "width": 1600,
      "height": 256,
      "contentHash": "9f2c7d0b6a1e4c3f8b5d2a7e0c9f4b1d6e3a8c5f2b7d0e9a4c1f6b3d8e5a2c7f",
      "createdAt": "2026-03-09T12:00:00.000Z",
      "cable": {
        "slug": "nym-j-3x1-5",
        "name": "NYM-J 3x1,5"
      }
    }
  ],
  "next": null
}

Familien auflisten

GET /api/v1/familiesBerechtigung: Lesen

Die Kabelfamilien, die mindestens ein veröffentlichtes Kabel enthalten, sortiert nach Position.

Aufruf

curl "https://testing.cablecreations.de/api/v1/families" \
  -H "Authorization: Bearer $API_KEY"

Antwort (200)

{
  "data": [
    {
      "id": "7c1d2a90-0d53-4f0e-8f47-5a0c1c0a2e01",
      "slug": "installationsleitungen",
      "name": "Installationsleitungen",
      "position": 1,
      "cableCount": 12
    }
  ],
  "next": null
}

Anfrage anlegen

POST /api/v1/requestsBerechtigung: Schreiben

Legt eine Anfrage für ein neues Kabel an. Pflicht ist nur der Titel; es gelten dieselben Regeln wie im Formular des Portals. Unbekannte Felder werden abgelehnt.

Aufruf

curl -X POST "https://testing.cablecreations.de/api/v1/requests" \
  -H "Authorization: Bearer $API_KEY" \
  -H "Content-Type: application/json" \
  -d '{"title":"Steuerleitung für Schleppketten","construction":"4x2x0,75","sheathColour":"grau RAL 7001","datasheetReference":"https://example.com/datenblatt.pdf"}'

Antwort (201)

{
  "id": "3d5e7a10-2b4c-4d6e-8f90-1a2b3c4d5e6f",
  "title": "Steuerleitung für Schleppketten",
  "status": "open",
  "details": {
    "designation": null,
    "construction": "4x2x0,75",
    "sheathColour": "grau RAL 7001",
    "printText": null,
    "datasheetReference": "https://example.com/datenblatt.pdf",
    "note": null
  },
  "source": "api",
  "rejectionReason": null,
  "cable": null,
  "createdAt": "2026-04-01T10:00:00.000Z",
  "updatedAt": "2026-04-01T10:00:00.000Z"
}

Anfragen auflisten

GET /api/v1/requestsBerechtigung: Lesen

Die Anfragen Ihrer Organisation, die neueste zuerst.

Aufruf

curl "https://testing.cablecreations.de/api/v1/requests" \
  -H "Authorization: Bearer $API_KEY"

Antwort (200)

{
  "data": [
    {
      "id": "3d5e7a10-2b4c-4d6e-8f90-1a2b3c4d5e6f",
      "title": "Steuerleitung für Schleppketten",
      "status": "open",
      "details": {
        "designation": null,
        "construction": "4x2x0,75",
        "sheathColour": "grau RAL 7001",
        "printText": null,
        "datasheetReference": "https://example.com/datenblatt.pdf",
        "note": null
      },
      "source": "api",
      "rejectionReason": null,
      "cable": null,
      "createdAt": "2026-04-01T10:00:00.000Z",
      "updatedAt": "2026-04-01T10:00:00.000Z"
    }
  ],
  "next": null
}

Eine Anfrage abrufen

GET /api/v1/requests/{id}Berechtigung: Lesen

Status einer Anfrage. Bei abgelehnten Anfragen steht der Grund in rejectionReason, bei gelieferten das Kabel in cable, sobald es veröffentlicht ist.

Aufruf

curl "https://testing.cablecreations.de/api/v1/requests/3d5e7a10-2b4c-4d6e-8f90-1a2b3c4d5e6f" \
  -H "Authorization: Bearer $API_KEY"

Antwort (200)

{
  "id": "3d5e7a10-2b4c-4d6e-8f90-1a2b3c4d5e6f",
  "title": "Steuerleitung für Schleppketten",
  "status": "open",
  "details": {
    "designation": null,
    "construction": "4x2x0,75",
    "sheathColour": "grau RAL 7001",
    "printText": null,
    "datasheetReference": "https://example.com/datenblatt.pdf",
    "note": null
  },
  "source": "api",
  "rejectionReason": null,
  "cable": null,
  "createdAt": "2026-04-01T10:00:00.000Z",
  "updatedAt": "2026-04-01T10:00:00.000Z"
}

Motive und Preise abrufen

GET /api/v1/render-motifsBerechtigung: Bestellen

Alle bestellbaren Motive mit Größen in Pixeln und dem Preis je Größe – ohne und mit Untergrund. Den Preis in Euro nennt der Preis einer Bestellung (amount). options nennt die Dateiformate und die Untergründe.

Aufruf

curl "https://testing.cablecreations.de/api/v1/render-motifs" \
  -H "Authorization: Bearer $API_KEY"

Antwort (200)

{
  "data": [
    {
      "key": "catalog-profile",
      "label": "Katalogbild (Seitenansicht)",
      "look": "catalog",
      "shot": "profile",
      "surface": "none",
      "sizes": [
        {
          "key": "web",
          "width": 1600,
          "height": 256,
          "price": 1,
          "priceOnSurface": null
        },
        {
          "key": "print",
          "width": 3200,
          "height": 512,
          "price": 2,
          "priceOnSurface": null
        },
        {
          "key": "max",
          "width": 6400,
          "height": 1024,
          "price": 4,
          "priceOnSurface": null
        }
      ],
      "video": {
        "motions": [
          {
            "name": "turn",
            "seconds": 8,
            "loops": true,
            "surface": false,
            "lettered": false,
            "requires": []
          }
        ],
        "resolutions": [
          {
            "key": "hd",
            "width": 1280,
            "height": 204,
            "pricePerSecond": 1
          },
          {
            "key": "fullhd",
            "width": 1920,
            "height": 308,
            "pricePerSecond": 2
          }
        ]
      }
    }
  ],
  "options": {
    "formats": [
      "png",
      "jpg",
      "webp"
    ],
    "surfaces": [
      {
        "name": "concrete",
        "label": "Beton"
      }
    ],
    "poses": [
      "straight",
      "arc",
      "s-curve",
      "loop",
      "end-lift",
      "bend-90",
      "u-turn",
      "wave",
      "coil"
    ],
    "cuts": [
      "cores-out",
      "cores-stripped",
      "flush",
      "pie",
      "pie-stepped",
      "stepped",
      "straight"
    ],
    "videoFormats": [
      "mp4",
      "webm",
      "mov",
      "zip"
    ],
    "videoLengths": [
      "short",
      "standard",
      "long"
    ],
    "frameRates": [
      25,
      30,
      60
    ],
    "videoSurfacePricePercent": 150,
    "views": [
      {
        "key": "profile",
        "label": "Seitenansicht",
        "group": "whole",
        "environments": [
          "cutout",
          "white",
          "grey",
          "custom"
        ],
        "videoEnvironments": [
          "cutout",
          "white",
          "grey",
          "custom"
        ]
      }
    ],
    "environments": [
      {
        "key": "cutout",
        "label": "Freigestellt",
        "group": "plain",
        "looks": [
          "catalog"
        ],
        "colour": null,
        "surface": null,
        "pricePercent": 100
      },
      {
        "key": "white",
        "label": "Weiß",
        "group": "plain",
        "looks": [
          "catalog"
        ],
        "colour": "#ffffff",
        "surface": null,
        "pricePercent": 100
      }
    ],
    "compositions": [
      {
        "key": "stairs",
        "label": "Treppe",
        "fewest": 2,
        "most": 6,
        "film": false,
        "views": [
          {
            "key": "above",
            "label": "Von oben",
            "format": "4:5",
            "sizes": [
              {
                "key": "web",
                "width": 600,
                "height": 750
              },
              {
                "key": "print",
                "width": 1200,
                "height": 1500
              },
              {
                "key": "max",
                "width": 2400,
                "height": 3000
              }
            ]
          }
        ],
        "environments": [
          "cutout",
          "white",
          "grey",
          "custom",
          "studio-light",
          "studio-dark"
        ],
        "priceFactors": [
          {
            "count": 2,
            "percent": 150
          },
          {
            "count": 3,
            "percent": 200
          },
          {
            "count": 4,
            "percent": 250
          },
          {
            "count": 5,
            "percent": 300
          },
          {
            "count": 6,
            "percent": 350
          }
        ]
      }
    ]
  }
}

Preis einer Bestellung abfragen

POST /api/v1/orders/priceBerechtigung: Bestellen

Nennt den Preis einer Auswahl in Euro (amount, netto) und ob die Bestellung jetzt etwas kosten würde: nichts, wenn es das Bild schon gibt oder es gerade entsteht. Es wird nichts bestellt.

Aufruf

curl -X POST "https://testing.cablecreations.de/api/v1/orders/price" \
  -H "Authorization: Bearer $API_KEY" \
  -H "Content-Type: application/json" \
  -d '{"cable":"nym-j-3x1-5","view":"profile","environment":"white","format":"png","extraFormats":["jpg"],"size":"web"}'

Antwort (200)

{
  "state": "new",
  "amount": {
    "currency": "EUR",
    "netCents": 200
  }
}

Bild bestellen

POST /api/v1/ordersBerechtigung: Bestellen

Bestellt ein Bild eines Kabels – auch eines noch nicht veröffentlichten. Der Kopf Idempotency-Key ist Pflicht: Wiederholen Sie einen Aufruf mit demselben Schlüssel, wird nichts doppelt bestellt. 201 heißt: neu bestellt; berechnet wird, sobald das Bild geliefert ist. 200 heißt: Das Bild gibt es schon oder es entsteht gerade – ohne Kosten.

Aufruf

curl -X POST "https://testing.cablecreations.de/api/v1/orders" \
  -H "Authorization: Bearer $API_KEY" \
  -H "Idempotency-Key: 8f14e45f-ceea-467f-a9f1-0b6d2c3e4f50" \
  -H "Content-Type: application/json" \
  -d '{"cable":"nym-j-3x1-5","view":"profile","environment":"white","format":"png","extraFormats":["jpg"],"size":"web","expectedNetCents":200}'

Antwort (201)

{
  "id": "6b1f0c9e-7a2d-4e53-9c10-4d5e6f708192",
  "status": "queued",
  "source": "api",
  "cable": {
    "slug": "nym-j-3x1-5",
    "name": "NYM-J 3x1,5"
  },
  "variant": {
    "id": "3d0c7e52-6c1a-4a0e-9a57-0b6a4a3b7d10",
    "name": "3x1,5"
  },
  "motif": "catalog-profile",
  "kind": "image",
  "format": "png",
  "size": "web",
  "video": null,
  "scene": {
    "kind": "colour",
    "colour": "#ffffff"
  },
  "view": "profile",
  "environment": "white",
  "extraFormats": [
    "jpg"
  ],
  "pose": null,
  "cut": null,
  "cables": null,
  "composition": null,
  "compositionView": null,
  "amount": {
    "currency": "EUR",
    "netCents": 200,
    "state": "authorised"
  },
  "files": [],
  "createdAt": "2026-04-01T10:00:00.000Z",
  "finishedAt": null
}

Bestellungen auflisten

GET /api/v1/ordersBerechtigung: Bestellen

Die Bildbestellungen Ihrer Organisation, die neueste zuerst – auch die im Portal aufgegebenen (source).

Aufruf

curl "https://testing.cablecreations.de/api/v1/orders" \
  -H "Authorization: Bearer $API_KEY"

Antwort (200)

{
  "data": [
    {
      "id": "6b1f0c9e-7a2d-4e53-9c10-4d5e6f708192",
      "status": "delivered",
      "source": "api",
      "cable": {
        "slug": "nym-j-3x1-5",
        "name": "NYM-J 3x1,5"
      },
      "variant": {
        "id": "3d0c7e52-6c1a-4a0e-9a57-0b6a4a3b7d10",
        "name": "3x1,5"
      },
      "motif": "catalog-profile",
      "kind": "image",
      "format": "png",
      "size": "web",
      "video": null,
      "scene": {
        "kind": "colour",
        "colour": "#ffffff"
      },
      "view": "profile",
      "environment": "white",
      "extraFormats": [
        "jpg"
      ],
      "pose": null,
      "cut": null,
      "cables": null,
      "composition": null,
      "compositionView": null,
      "amount": {
        "currency": "EUR",
        "netCents": 200,
        "state": "captured"
      },
      "files": [
        {
          "id": "b6f0a4d2-93c4-4a6b-a1b5-2f1f6f3f9c22",
          "name": "nym-j-3x1-5-catalog-profile.png",
          "url": "https://kabel.example/api/v1/orders/6b1f0c9e-7a2d-4e53-9c10-4d5e6f708192/files/b6f0a4d2-93c4-4a6b-a1b5-2f1f6f3f9c22",
          "mime": "image/png",
          "bytes": 184320,
          "width": 1600,
          "height": 256,
          "contentHash": "9f2c7d0b6a1e4c3f8b5d2a7e0c9f4b1d6e3a8c5f2b7d0e9a4c1f6b3d8e5a2c7f"
        },
        {
          "id": "c7a1b5e3-04d5-4b7c-b2c6-3a2a7a4a0d33",
          "name": "nym-j-3x1-5-catalog-profile.jpg",
          "url": "https://kabel.example/api/v1/orders/6b1f0c9e-7a2d-4e53-9c10-4d5e6f708192/files/c7a1b5e3-04d5-4b7c-b2c6-3a2a7a4a0d33",
          "mime": "image/jpeg",
          "bytes": 61440,
          "width": 1600,
          "height": 256,
          "contentHash": "4e1b8d3a6c0f2e5b9a7d1c4f8e2b6a0d3c9f5e1b7a4d0c6e2f8b5a1d9c3e7f0b"
        }
      ],
      "createdAt": "2026-04-01T10:00:00.000Z",
      "finishedAt": "2026-04-01T10:04:12.000Z"
    }
  ],
  "next": null
}

Eine Bestellung abrufen

GET /api/v1/orders/{id}Berechtigung: Bestellen

Status einer Bestellung: queued, rendering, delivered, failed oder cancelled. Nach der Lieferung stehen die Dateien in files.

Aufruf

curl "https://testing.cablecreations.de/api/v1/orders/6b1f0c9e-7a2d-4e53-9c10-4d5e6f708192" \
  -H "Authorization: Bearer $API_KEY"

Antwort (200)

{
  "id": "6b1f0c9e-7a2d-4e53-9c10-4d5e6f708192",
  "status": "delivered",
  "source": "api",
  "cable": {
    "slug": "nym-j-3x1-5",
    "name": "NYM-J 3x1,5"
  },
  "variant": {
    "id": "3d0c7e52-6c1a-4a0e-9a57-0b6a4a3b7d10",
    "name": "3x1,5"
  },
  "motif": "catalog-profile",
  "kind": "image",
  "format": "png",
  "size": "web",
  "video": null,
  "scene": {
    "kind": "colour",
    "colour": "#ffffff"
  },
  "view": "profile",
  "environment": "white",
  "extraFormats": [
    "jpg"
  ],
  "pose": null,
  "cut": null,
  "cables": null,
  "composition": null,
  "compositionView": null,
  "amount": {
    "currency": "EUR",
    "netCents": 200,
    "state": "captured"
  },
  "files": [
    {
      "id": "b6f0a4d2-93c4-4a6b-a1b5-2f1f6f3f9c22",
      "name": "nym-j-3x1-5-catalog-profile.png",
      "url": "https://kabel.example/api/v1/orders/6b1f0c9e-7a2d-4e53-9c10-4d5e6f708192/files/b6f0a4d2-93c4-4a6b-a1b5-2f1f6f3f9c22",
      "mime": "image/png",
      "bytes": 184320,
      "width": 1600,
      "height": 256,
      "contentHash": "9f2c7d0b6a1e4c3f8b5d2a7e0c9f4b1d6e3a8c5f2b7d0e9a4c1f6b3d8e5a2c7f"
    },
    {
      "id": "c7a1b5e3-04d5-4b7c-b2c6-3a2a7a4a0d33",
      "name": "nym-j-3x1-5-catalog-profile.jpg",
      "url": "https://kabel.example/api/v1/orders/6b1f0c9e-7a2d-4e53-9c10-4d5e6f708192/files/c7a1b5e3-04d5-4b7c-b2c6-3a2a7a4a0d33",
      "mime": "image/jpeg",
      "bytes": 61440,
      "width": 1600,
      "height": 256,
      "contentHash": "4e1b8d3a6c0f2e5b9a7d1c4f8e2b6a0d3c9f5e1b7a4d0c6e2f8b5a1d9c3e7f0b"
    }
  ],
  "createdAt": "2026-04-01T10:00:00.000Z",
  "finishedAt": "2026-04-01T10:04:12.000Z"
}

Bestellung stornieren

POST /api/v1/orders/{id}/cancelBerechtigung: Bestellen

Storniert eine Bestellung, die noch in der Warteschlange steht; sie wird nicht berechnet. Sobald ein Bild in Arbeit ist, antwortet der Aufruf mit 409.

Aufruf

curl -X POST "https://testing.cablecreations.de/api/v1/orders/6b1f0c9e-7a2d-4e53-9c10-4d5e6f708192/cancel" \
  -H "Authorization: Bearer $API_KEY"

Antwort (200)

{
  "id": "6b1f0c9e-7a2d-4e53-9c10-4d5e6f708192",
  "status": "cancelled",
  "source": "api",
  "cable": {
    "slug": "nym-j-3x1-5",
    "name": "NYM-J 3x1,5"
  },
  "variant": {
    "id": "3d0c7e52-6c1a-4a0e-9a57-0b6a4a3b7d10",
    "name": "3x1,5"
  },
  "motif": "catalog-profile",
  "kind": "image",
  "format": "png",
  "size": "web",
  "video": null,
  "scene": {
    "kind": "colour",
    "colour": "#ffffff"
  },
  "view": "profile",
  "environment": "white",
  "extraFormats": [
    "jpg"
  ],
  "pose": null,
  "cut": null,
  "cables": null,
  "composition": null,
  "compositionView": null,
  "amount": {
    "currency": "EUR",
    "netCents": 200,
    "state": "authorised"
  },
  "files": [],
  "createdAt": "2026-04-01T10:00:00.000Z",
  "finishedAt": "2026-04-01T10:01:00.000Z"
}

Preis einer Umwandlung

POST /api/v1/conversions/priceBerechtigung: Umwandeln

Nennt den Preis in Euro (netto) für eine Umwandlung mit den gewählten Ausgaben. Braucht keine Datei und startet nichts.

Aufruf

curl -X POST "https://testing.cablecreations.de/api/v1/conversions/price" \
  -H "Authorization: Bearer $API_KEY" \
  -H "Content-Type: application/json" \
  -d '{"outputs":["dxf"]}'

Antwort (200)

{
  "currency": "EUR",
  "lines": [
    {
      "kind": "conversion",
      "name": "conversion",
      "cents": 3900
    },
    {
      "kind": "extra",
      "name": "dxf",
      "cents": 500
    }
  ],
  "netCents": 4400,
  "tier": {
    "fromJobs": 0,
    "percentOff": 0,
    "requestsPerWindow": 100
  }
}

Spec umwandeln

POST /api/v1/conversionsBerechtigung: Umwandeln

Prüft die Spec eines Kabels (JSON) mit dem Generator, reserviert den Preis in Ihrem Monatslimit und baut die Dateien ohne weiteren Schritt, in der Regel in wenigen Minuten. Eine Spec, die der Generator ablehnt, beantwortet der Aufruf sofort mit 400 und je einem Fehler an seiner Stelle (field ist der JSON-Pfad); es wird nichts reserviert. Sonst antwortet er mit 202. Der Header Idempotency-Key ist Pflicht. Ohne Rechnungsadresse oder bei erreichtem Monatslimit antwortet der Aufruf mit 402, bei zu vielen laufenden Umwandlungen mit 429.

Aufruf

curl -X POST "https://testing.cablecreations.de/api/v1/conversions" \
  -H "Authorization: Bearer $API_KEY" \
  -H "Idempotency-Key: 2c6f8a1e-9d3b-4e75-a0c4-7b1d5f3e8a92" \
  -H "Content-Type: application/json" \
  -d '{"spec":{"name":"RG 58 C/U","cut":{"preset":"stepped","at":68},"build":[{"conductor":{"diameter":0.9,"strand_pitch":0.19,"material":"copper-tinned","color":"#c9cdd1"}},{"insulation":{"thickness":1.02,"material":"rubber","color":"#d3dde3"}},{"braid":{"carriers":12,"wires_per_carrier":8,"wire_diameter":0.12,"lay_length":20,"material":"copper-tinned","color":"#c9cdd1"}},{"sheath":{"thickness":0.76,"material":"pvc","color":"#1e1e20"}}]},"outputs":["dxf"]}'

Antwort (202)

{
  "id": "cv_4f7a1c9e2b8d4a6f9c3e5d7b1a2c4e6f",
  "status": "queued",
  "source": "spec_json",
  "size": "RG 58 C/U",
  "outputs": [
    "glb_web",
    "section_svg",
    "check_json",
    "dxf"
  ],
  "amount": {
    "currency": "EUR",
    "netCents": 4400,
    "state": "authorised"
  },
  "refusal": null,
  "files": [],
  "cable": null,
  "filesKeptUntil": null,
  "createdAt": "2026-04-01T10:02:00.000Z",
  "finishedAt": null
}

Umwandlungen auflisten

GET /api/v1/conversionsBerechtigung: Umwandeln

Alle Umwandlungen Ihrer Organisation, die neueste zuerst, mit Status und Dateien.

Aufruf

curl "https://testing.cablecreations.de/api/v1/conversions" \
  -H "Authorization: Bearer $API_KEY"

Antwort (200)

{
  "data": [
    {
      "id": "cv_4f7a1c9e2b8d4a6f9c3e5d7b1a2c4e6f",
      "status": "completed",
      "source": "spec_json",
      "size": "RG 58 C/U",
      "outputs": [
        "glb_web",
        "section_svg",
        "check_json",
        "dxf"
      ],
      "amount": {
        "currency": "EUR",
        "netCents": 4400,
        "state": "captured"
      },
      "refusal": null,
      "files": [
        {
          "id": "e1c7b0a4-5d2f-4a39-8c6e-9b3d1f7a2c58",
          "name": "rg-58-c-u-3d-web.glb",
          "kind": "glb_web",
          "mime": "model/gltf-binary",
          "bytes": 412860,
          "url": "https://kabel.example/api/v1/conversions/cv_4f7a1c9e2b8d4a6f9c3e5d7b1a2c4e6f/files/e1c7b0a4-5d2f-4a39-8c6e-9b3d1f7a2c58",
          "contentHash": "3b5d9e1f7a2c4806b1d3f5a7c9e0b2d4f6a8c1e3b5d7f9a0c2e4b6d8f1a3c5e7"
        }
      ],
      "cable": {
        "slug": "rg-58-c-u",
        "name": "RG 58 C/U"
      },
      "filesKeptUntil": "2027-03-31T22:00:00.000Z",
      "createdAt": "2026-04-01T10:02:00.000Z",
      "finishedAt": "2026-04-01T10:04:00.000Z"
    }
  ],
  "next": null
}

Eine Umwandlung abrufen

GET /api/v1/conversions/{id}Berechtigung: Umwandeln

Status der Umwandlung: queued, reading, in_review, building, completed, refused (mit Code und Satz) oder cancelled. Geliefert wird ein 3D-Modell für das Web (GLB), die Schnittzeichnung (SVG) und der Prüfbericht (JSON), auf Wunsch weitere Formate.

Aufruf

curl "https://testing.cablecreations.de/api/v1/conversions/cv_4f7a1c9e2b8d4a6f9c3e5d7b1a2c4e6f" \
  -H "Authorization: Bearer $API_KEY"

Antwort (200)

{
  "id": "cv_4f7a1c9e2b8d4a6f9c3e5d7b1a2c4e6f",
  "status": "completed",
  "source": "spec_json",
  "size": "RG 58 C/U",
  "outputs": [
    "glb_web",
    "section_svg",
    "check_json",
    "dxf"
  ],
  "amount": {
    "currency": "EUR",
    "netCents": 4400,
    "state": "captured"
  },
  "refusal": null,
  "files": [
    {
      "id": "e1c7b0a4-5d2f-4a39-8c6e-9b3d1f7a2c58",
      "name": "rg-58-c-u-3d-web.glb",
      "kind": "glb_web",
      "mime": "model/gltf-binary",
      "bytes": 412860,
      "url": "https://kabel.example/api/v1/conversions/cv_4f7a1c9e2b8d4a6f9c3e5d7b1a2c4e6f/files/e1c7b0a4-5d2f-4a39-8c6e-9b3d1f7a2c58",
      "contentHash": "3b5d9e1f7a2c4806b1d3f5a7c9e0b2d4f6a8c1e3b5d7f9a0c2e4b6d8f1a3c5e7"
    }
  ],
  "cable": {
    "slug": "rg-58-c-u",
    "name": "RG 58 C/U"
  },
  "filesKeptUntil": "2027-03-31T22:00:00.000Z",
  "createdAt": "2026-04-01T10:02:00.000Z",
  "finishedAt": "2026-04-01T10:04:00.000Z"
}

Umwandlung stornieren

POST /api/v1/conversions/{id}/cancelBerechtigung: Umwandeln

Storniert eine Umwandlung, bevor sie gebaut wird; die Reservierung auf der Karte wird freigegeben. Danach antwortet der Aufruf mit 409.

Aufruf

curl -X POST "https://testing.cablecreations.de/api/v1/conversions/cv_4f7a1c9e2b8d4a6f9c3e5d7b1a2c4e6f/cancel" \
  -H "Authorization: Bearer $API_KEY"

Antwort (200)

{
  "id": "cv_4f7a1c9e2b8d4a6f9c3e5d7b1a2c4e6f",
  "status": "cancelled",
  "source": "spec_json",
  "size": "RG 58 C/U",
  "outputs": [
    "glb_web",
    "section_svg",
    "check_json",
    "dxf"
  ],
  "amount": {
    "currency": "EUR",
    "netCents": 4400,
    "state": "released"
  },
  "refusal": null,
  "files": [],
  "cable": null,
  "filesKeptUntil": null,
  "createdAt": "2026-04-01T10:02:00.000Z",
  "finishedAt": "2026-04-01T10:05:00.000Z"
}

Datenblatt eines Kabels abrufen

GET /api/v1/cables/{slug}/datasheetBerechtigung: Lesen

Das Datenblatt eines veröffentlichten Kabels als PDF in Ihrem Erscheinungsbild: Typdaten, öffentliche Bilder und die Tabelle der Querschnitte. Die Adresse steht bei jedem Kabel im Feld datasheetUrl.

Antwort (200) · application/pdf

Gelieferte Datei herunterladen

GET /api/v1/orders/{id}/files/{fileId}Berechtigung: Bestellen

Die Datei selbst. Der Aufruf braucht den API-Schlüssel wie jeder andere; die Adresse steht bei jeder Datei im Feld url.

Antwort (200) · application/octet-stream

Datei einer Umwandlung

GET /api/v1/conversions/{id}/files/{fileId}Berechtigung: Umwandeln

Die Datei selbst. Der Aufruf braucht den API-Schlüssel wie jeder andere; die Adresse steht bei jeder Datei im Feld url.

Antwort (200) · application/octet-stream

Bilder bestellen

Mit der Berechtigung Bestellen geben Ihre Systeme dieselben Bildbestellungen auf wie Ihre Mitarbeiter im Portal – zu denselben Preisen und Regeln.

  • Ablauf: Motive und Preise abrufen, optional den Preis einer Auswahl abfragen, bestellen, den Status abrufen (oder sich per Webhook benachrichtigen lassen), die Dateien herunterladen.
  • Ein Bild benennen Sie mit Ansicht und Umgebung: view (von wo die Kamera schaut) und environment (wo das Kabel liegt – Hintergrund und Boden passen immer zusammen), bei custom dazu environmentColour. options.views und options.environments der Motivliste nennen, welche Paare bestellbar sind. Die ältere Form mit motif und scene gilt weiter; beides in einer Bestellung wird abgelehnt.
  • Eine Bestellung ist eine Bildgröße (web, print oder max) oder eine Filmauflösung; mehrere bestellen Sie mit mehreren Aufrufen. Weitere Dateiformate desselben Bildes oder Films stehen in extraFormats (zum Beispiel png und dazu jpg); sie kosten nichts. Ein freigestelltes JPG oder MP4 liegt auf Weiß.
  • Filme gibt es in HD, Full HD und 4K (resolution uhd, 3.840 Pixel an der langen Seite). 4K gibt es in jeder Länge und Bildrate. Eine Datei, die größer als 1 GiB würde (etwa ProRes oder PNG-Einzelbilder eines langen 4K-Films), wird mit too_large abgelehnt; MP4 und WebM passen immer.
  • Jede Bestellung braucht den Kopf Idempotency-Key mit einem Wert Ihrer Wahl (z. B. eine UUID). Derselbe Wert mit demselben Inhalt bestellt nie doppelt; die Antwort trägt dann Idempotent-Replay: true. Derselbe Wert mit anderem Inhalt wird mit 409 abgelehnt.
  • Gibt es das Bild schon oder entsteht es gerade, kostet die Bestellung nichts (200 statt 201).
  • Mit expectedNetCents sichern Sie sich ab – dem Nettopreis in Cent, den die Preisabfrage genannt hat (amount.netCents): Kostet ein neues Bild etwas anderes, wird nichts bestellt (409 price_changed).
  • Überschreitet die Bestellung das Ausgabenlimit, ist das Budget des Schlüssels erschöpft oder sind Bestellungen angehalten, antwortet die API mit 402 und einem eigenen code. Es wird nichts bestellt; derselbe Idempotency-Key gilt danach weiter.
  • Preise: amount nennt den Preis netto in Cent (netCents) mit der Währung. Hersteller bezahlen mit der Monatsrechnung, Entwickler mit ihrer monatlichen Sammelrechnung innerhalb ihres Monatslimits; ein fehlgeschlagenes oder storniertes Bild wird nicht berechnet.
  • Bestellungen werden der Person zugeordnet, die den Schlüssel angelegt hat, und erscheinen im Portal unter Bestellungen.
  • Gelieferte Dateien laden Sie mit dem Schlüssel über die Adresse in files[].url herunter. Die Adressen funktionieren nicht ohne Schlüssel.
  • Pro Schlüssel sind 60 Bestellungen in 10 Minuten möglich; darüber antwortet die API mit 429.

Mehrere Kabel in einem Bild

  • Statt cable nennen Sie cables: zwei bis sechs Kabel in der Reihenfolge des Bildes (von links nach rechts, von vorn nach hinten), jedes mit cable und auf Wunsch variant. Dasselbe Kabel darf mehrfach vorkommen.
  • Dazu composition (wie die Kabel zueinander liegen) und compositionView (der Blickwinkel; ohne ihn der erste angebotene) sowie environment – freigestellt, auf einer Farbe oder im Studio, nicht auf einem Boden. options.compositions der Motivliste nennt, welche Anordnungen mit welchen Blickwinkeln, Größen und Umgebungen bestellbar sind.
  • Eine Abmantelung (cut) gilt für alle Kabel und geht nur, wenn jedes Kabel sie erlaubt. pose, view, motif und scene gibt es bei mehreren Kabeln nicht; einen Film nur verdrillt, von der Seite (compositionView side; „Mit Kabelenden“ gibt es nur als Bild).
  • Jedes weitere Kabel kostet die Hälfte des Einzelpreises dazu (priceFactors). Die Preisabfrage nennt den Preis der Auswahl; expectedNetCents, Idempotency-Key und die Antworten 200, 402 und 409 gelten wie bei einem Kabel.
  • Abgelehnt wird Feld für Feld: cables[i] mit unknown_cable oder not_ready, composition mit not_offered, count_needs oder einem Grund des Bündels (helix_sizes_apart, helix_too_stiff, helix_too_short), environment mit not_with_several, video mit only_helix, compositionView mit unavailable (ein Film der Kabelenden).
  • Die Bestellung nennt cables (mit position), composition und compositionView; cable und variant nennen das erste Kabel. Webhooks tragen dieselbe Bestellung.

Aufruf

curl -X POST "https://testing.cablecreations.de/api/v1/orders" \
  -H "Authorization: Bearer $API_KEY" \
  -H "Idempotency-Key: 4b7e2d90-6c1f-4a83-b5d2-9e0f1a3c5e77" \
  -H "Content-Type: application/json" \
  -d '{"cables":[{"cable":"nym-j-3x1-5"},{"cable":"nym-j-3x2-5"},{"cable":"nym-j-5x1-5"}],"composition":"stairs","compositionView":"above","environment":"cutout","format":"png","size":"web","expectedNetCents":1200}'

Antwort (201)

{
  "id": "8c2d4e6f-1a3b-4c5d-9e7f-2b4d6f8a0c13",
  "status": "queued",
  "source": "api",
  "cable": {
    "slug": "nym-j-3x1-5",
    "name": "NYM-J 3x1,5"
  },
  "variant": {
    "id": "3d0c7e52-6c1a-4a0e-9a57-0b6a4a3b7d10",
    "name": "3x1,5"
  },
  "motif": "photo-stairs",
  "kind": "image",
  "format": "png",
  "size": "web",
  "video": null,
  "scene": {
    "kind": "transparent"
  },
  "view": null,
  "environment": "cutout",
  "extraFormats": [],
  "pose": null,
  "cut": null,
  "cables": [
    {
      "position": 0,
      "cable": {
        "slug": "nym-j-3x1-5",
        "name": "NYM-J 3x1,5"
      },
      "variant": {
        "id": "3d0c7e52-6c1a-4a0e-9a57-0b6a4a3b7d10",
        "name": "3x1,5"
      }
    },
    {
      "position": 1,
      "cable": {
        "slug": "nym-j-3x2-5",
        "name": "NYM-J 3x2,5"
      },
      "variant": {
        "id": "5a7c9e1b-3d5f-4a7c-8e0b-2d4f6a8c0e21",
        "name": "3x2,5"
      }
    },
    {
      "position": 2,
      "cable": {
        "slug": "nym-j-5x1-5",
        "name": "NYM-J 5x1,5"
      },
      "variant": {
        "id": "7e9a1c3d-5f7b-4c9e-a1d3-5f7b9d1e3a42",
        "name": "5x1,5"
      }
    }
  ],
  "composition": "stairs",
  "compositionView": "above",
  "amount": {
    "currency": "EUR",
    "netCents": 1200,
    "state": "authorised"
  },
  "files": [],
  "createdAt": "2026-04-01T10:00:00.000Z",
  "finishedAt": null
}

Specs umwandeln

Mit dem Zugang für Entwickler und der Berechtigung Umwandeln machen Ihre Systeme aus der Spec eines Kabels ein 3D-Kabel: ein 3D-Modell fürs Web (GLB), die Schnittzeichnung (SVG) und einen Prüfbericht (JSON), auf Wunsch weitere Formate. Sie bezahlen nur, was geliefert wird.

Niemand von uns arbeitet daran: Der Generator prüft die Spec beim Aufruf und baut sie gleich danach. Das dauert normalerweise wenige Minuten.

  • Ablauf: Preis abfragen, die Umwandlung mit der Spec und den Ausgaben starten, den Status abrufen (oder per Webhook conversion.completed und conversion.refused benachrichtigt werden), die Dateien herunterladen.
  • Eine Umwandlung ist genau ein Kabel in einem Querschnitt. size benennt den Querschnitt (zum Beispiel 3G1,5); ohne size gilt der name der Spec.
  • Jede Umwandlung braucht den Kopf Idempotency-Key. Derselbe Wert mit demselben Inhalt startet nie doppelt (die Antwort trägt dann Idempotent-Replay: true); mit anderem Inhalt wird er mit 409 abgelehnt.
  • Beim Start wird der Preis in Ihrem Monatslimit reserviert; berechnet wird er mit der Lieferung, auf Ihrer Monatsrechnung. Wird abgelehnt oder storniert, geben wir die Reservierung frei. Ohne Rechnungsadresse oder bei erreichtem Monatslimit antwortet der Aufruf mit 402 und reason, bei zu vielen laufenden Umwandlungen mit 429.
  • Stornieren geht, solange die Umwandlung wartet (queued); danach antwortet der Aufruf mit 409.
  • Die Daten in der Spec müssen Ihnen gehören oder Sie müssen sie verwenden dürfen. Die gelieferten Dateien dürfen Sie in Ihrem eigenen Produkt nutzen.
  • Aufbewahrung: die gelieferten Dateien 12 Monate nach der Lieferung (filesKeptUntil nennt den Tag). Das Kabel mit seiner Spec bleibt in Ihrem Zugang.
  • Bilder Ihres Kabels: Eine gelieferte Umwandlung nennt ihr Kabel (cable.slug). Mit der Berechtigung Bestellen bestellen Sie dafür Bilder über POST /orders. Jedes neue Bild wird in Ihrem Monatslimit reserviert (402 und 429 wie oben) und mit der Lieferung berechnet; amount in der Antwort nennt den Preis in Euro. Ein Bild, das es schon gibt oder das gerade entsteht, kostet nicht noch einmal.

Die Spec als JSON

  • spec ist das Spec-Format des Generators als JSON: eine Tabelle ist ein Objekt, ein Array von Tabellen ein Array, ein Bauschritt ein Objekt mit einem Schlüssel ({"conductor": {…}}). Längen in Millimetern.
  • Erlaubt sind Zeichenketten, endliche Zahlen, true und false, Arrays und Objekte; Schlüssel aus Buchstaben, Ziffern, _ und -. null, unendliche Zahlen und Arrays von Arrays werden vor dem Generator abgelehnt (not_an_object, invalid_key, invalid_value, too_large ab 256 KB).
  • Der Generator prüft die Spec wie cable check: Jeder Fehler kommt als eigenes Detail mit dem JSON-Pfad (spec.build[2].conductor.diameter), seinem Code und seinem Satz. Weicht der gebaute Außendurchmesser vom Ziel unter [datasheet] ab, ist das ebenfalls ein Fehler.
  • Mit einem Testschlüssel wird die Spec genauso geprüft; nur die Lieferung ist ein Beispiel.

Preise (netto, in Euro)

  • Umwandlung eines Querschnitts mit 3D-Modell fürs Web, Schnittzeichnung und Prüfbericht: 39,00 €
  • Zusätzlich Detailmodell mit allen Drähten (GLB, outputs: glb_full): 5,00 €
  • Zusätzlich OBJ mit Materialien (ZIP, outputs: obj): 5,00 €
  • Zusätzlich STL (outputs: stl): 5,00 €
  • Zusätzlich FBX für Blender, Unity und Unreal (outputs: fbx): 9,00 €
  • Zusätzlich USDZ für Apple (outputs: usdz): 9,00 €
  • Zusätzlich Schnittzeichnung (DXF, outputs: dxf): 5,00 €

Stände einer Umwandlung

  • queued Die Spec ist geprüft; die Umwandlung wartet auf den Bau.
  • reading Nur bei Umwandlungen des früheren Datenblatt-Wegs: Das Datenblatt wurde gelesen.
  • in_review Nur bei Umwandlungen des früheren Datenblatt-Wegs: Der Aufbau wurde geprüft.
  • building Die Dateien werden gebaut.
  • completed Geliefert und berechnet; files enthält die Dateien.
  • refused Nicht geliefert; refusal nennt Code und Satz, es wird nichts berechnet.
  • cancelled Von Ihnen storniert; die Reservierung ist freigegeben.

Gründe einer Ablehnung (refusal.code)

  • unreadable_datasheet Das Datenblatt lässt sich nicht lesen (Scan, beschädigt, ohne brauchbaren Text).
  • not_a_cable Das Dokument beschreibt kein Kabel, das wir bauen können.
  • size_not_found Das Datenblatt hat keinen Querschnitt mit dieser Bezeichnung.
  • not_buildable Die Spec ließ sich nicht bauen.
  • diameter_off_target Der gebaute Aufbau weicht im Außendurchmesser vom Datenblatt ab.
  • not_delivered_in_time Die Umwandlung wurde nicht rechtzeitig fertig; die Reservierung wurde freigegeben.
  • other Ein anderer Grund; refusal.message nennt ihn.

Webhooks

Statt Bestellungen und Kabel regelmäßig abzufragen, lassen Sie sich benachrichtigen. Inhaber richten die Endpunkte unter Einstellungen → Webhooks ein.

  • Jedes Ereignis kommt als JSON per POST mit demselben Umschlag: id, type, version, createdAt und data. Die id eines Ereignisses bleibt bei jeder Wiederholung gleich – verwenden Sie sie, um doppelte Zustellungen zu erkennen.
  • data enthält nur IDs und das, was die API Ihrem Schlüssel ohnehin zeigt. Bei render.finished ist es die Bestellung mit ihren Dateien; bei enquiry.received nur die ID der Anfrage und das Kabel – keine Angaben zur anfragenden Person. Die einzige Ausnahme sind die Ereignisse lead.*, siehe unten.
  • Antworten Sie innerhalb von zehn Sekunden mit einem Status 2xx. Alles andere – auch eine Weiterleitung – gilt als fehlgeschlagen und wird wiederholt: nach 1, 4, 16 und 64 Minuten und nach gut 4 Stunden, insgesamt sechs Versuche.
  • Schlägt die Zustellung drei Tage lang fehl, deaktivieren wir den Endpunkt und benachrichtigen die Inhaber per E-Mail.
  • Die Adresse muss mit https:// beginnen und im öffentlichen Internet erreichbar sein.

Ereignisse

  • render.finished Ein bestelltes Bild wurde geliefert.
  • render.failed Ein bestelltes Bild ist endgültig fehlgeschlagen.
  • cable.published Ein Kabel wurde veröffentlicht.
  • cable.updated Die Daten eines veröffentlichten Kabels wurden geändert.
  • cable.unpublished Ein Kabel wurde aus dem Katalog genommen.
  • request.status_changed Ein Kabelauftrag hat einen neuen Stand: jeder Schritt von eingegangen bis abgenommen.
  • service_order.status_changed Ein Auftrag für eine Leistung (Gestaltung) hat einen neuen Stand: jeder Schritt von eingegangen bis abgenommen.
  • enquiry.received Über den Katalog ist eine Anfrage eingegangen.
  • lead.catalogue_enquiry Eine Anfrage aus dem Katalog – mit Name, E-Mail, Firma und Nachricht der anfragenden Person.
  • lead.expose_reply Eine Antwort auf ein Exposé – mit Name, E-Mail und Nachricht der antwortenden Person und den angekreuzten Kabeln.
  • conversion.completed Eine Umwandlung wurde geliefert; ihre Dateien stehen bereit.
  • conversion.refused Eine Umwandlung wurde abgelehnt; es wurde nichts abgebucht.

Beispiel einer Zustellung

{
  "id": "evt_3f1d6c0a-9b2e-4c57-8d10-7a6b5c4d3e2f",
  "type": "render.finished",
  "version": 1,
  "createdAt": "2026-04-01T10:04:13.000Z",
  "data": {
    "order": {
      "id": "6b1f0c9e-7a2d-4e53-9c10-4d5e6f708192",
      "status": "delivered",
      "source": "api",
      "cable": {
        "slug": "nym-j-3x1-5",
        "name": "NYM-J 3x1,5"
      },
      "variant": {
        "id": "3d0c7e52-6c1a-4a0e-9a57-0b6a4a3b7d10",
        "name": "3x1,5"
      },
      "motif": "catalog-profile",
      "kind": "image",
      "format": "png",
      "size": "web",
      "video": null,
      "scene": {
        "kind": "colour",
        "colour": "#ffffff"
      },
      "view": "profile",
      "environment": "white",
      "extraFormats": [],
      "pose": null,
      "cut": null,
      "cables": null,
      "composition": null,
      "compositionView": null,
      "amount": {
        "currency": "EUR",
        "netCents": 200,
        "state": "captured"
      },
      "files": [
        {
          "id": "b6f0a4d2-93c4-4a6b-a1b5-2f1f6f3f9c22",
          "name": "nym-j-3x1-5-catalog-profile.png",
          "url": "https://kabel.example/api/v1/orders/6b1f0c9e-7a2d-4e53-9c10-4d5e6f708192/files/b6f0a4d2-93c4-4a6b-a1b5-2f1f6f3f9c22",
          "mime": "image/png",
          "bytes": 184320,
          "width": 1600,
          "height": 256,
          "contentHash": "9f2c7d0b6a1e4c3f8b5d2a7e0c9f4b1d6e3a8c5f2b7d0e9a4c1f6b3d8e5a2c7f"
        }
      ],
      "createdAt": "2026-04-01T10:00:00.000Z",
      "finishedAt": "2026-04-01T10:04:12.000Z"
    }
  }
}

Kabelaufträge: request.status_changed

Das Ereignis kommt bei jedem Schritt eines Kabelauftrags. status und previousStatus sind der Status der Anfrage mit seinen vier Werten, wie ihn GET /requests zeigt. orderState und previousOrderState sagen genauer, wo der Auftrag steht, und actsNext, auf wen er wartet: customer, operator oder nobody. Bewegt sich nur der Auftrag – bei einer Rückfrage, einer Änderungsrunde oder der Abnahme –, sind status und previousStatus gleich. Ein Angebot und eine einfache Nachricht ändern keinen Stand und melden nichts.

Werte von orderState

  • submitted Der Auftrag ist eingegangen.
  • in_progress Wir arbeiten an dem Kabel.
  • question_to_customer Wir haben eine Rückfrage. Der Auftrag wartet auf Ihre Antwort.
  • delivered Eine Fassung ist geliefert und wartet auf Ihre Abnahme.
  • change_requested Sie haben Änderungen gewünscht. Wir arbeiten an der nächsten Fassung.
  • accepted Die Fassung ist abgenommen, durch Sie oder nach Ablauf der Abnahmefrist. Erst jetzt kann das Kabel veröffentlicht werden.
  • rejected Wir haben den Auftrag abgelehnt.
  • withdrawn Sie haben den Auftrag zurückgezogen.

Beispiel: Eine Fassung wurde abgenommen

{
  "id": "evt_8c2a41d7-5e0b-4f36-a9c1-2b3d4e5f6a70",
  "type": "request.status_changed",
  "version": 1,
  "createdAt": "2026-04-08T09:15:02.000Z",
  "data": {
    "request": {
      "id": "0c9d2f5a-1b3e-4c7d-8e9f-a1b2c3d4e5f6",
      "status": "delivered",
      "previousStatus": "delivered",
      "orderState": "accepted",
      "previousOrderState": "delivered",
      "actsNext": "nobody"
    }
  }
}

Signatur prüfen

Jede Zustellung trägt den Kopf Cable-Signature: t=<Zeitstempel>,v1=<Signatur>. Die Signatur ist der HMAC-SHA256 über „<Zeitstempel>.<unveränderter Body>“ mit Ihrem Signaturgeheimnis. Prüfen Sie sie über den rohen Body, vergleichen Sie in konstanter Zeit und lehnen Sie Zeitstempel ab, die älter als fünf Minuten sind.

import { createHmac, timingSafeEqual } from "node:crypto";

// header: the value of the Cable-Signature header
// rawBody: the request body exactly as it arrived (text, not parsed JSON)
export function isFromCablePlatform(rawBody, header, secret) {
  const match = /^t=(\d+),v1=([0-9a-f]{64})$/.exec(header ?? "");
  if (match === null) return false;
  const [, timestamp, signature] = match;
  const ageSeconds = Math.abs(Date.now() / 1000 - Number(timestamp));
  if (ageSeconds > 300) return false;
  const expected = createHmac("sha256", secret)
    .update(`${timestamp}.${rawBody}`)
    .digest("hex");
  return timingSafeEqual(Buffer.from(signature, "hex"), Buffer.from(expected, "hex"));
}

Seitenweise abrufen

  • Listen liefern data und next. Ist next nicht null, holen Sie die nächste Seite mit ?cursor=<next>.
  • Mit limit bestimmen Sie die Seitengröße: 1 bis 100, ohne Angabe 50.
  • Der Cursor ist undurchsichtig: Bauen oder verändern Sie ihn nicht.
  • Kommen während des Abrufs neue Einträge hinzu, wird kein Eintrag doppelt geliefert und keiner übersprungen.

Fehler

Fehler haben immer dieselbe Form. Werten Sie code aus, nicht den Text in message.

StatusCodeBedeutung
401unauthorizedDer Schlüssel fehlt, ist unbekannt oder wurde widerrufen.
403forbiddenDem Schlüssel fehlt die Berechtigung für diesen Aufruf.
404not_foundUnter diesem Namen gibt es nichts, was der Schlüssel sehen darf – auch nicht veröffentlichte Kabel antworten so.
400validation_failedEin Parameter oder ein Feld wurde abgelehnt. details nennt jedes betroffene Feld mit einem Code.
429rate_limitedZu viele Anfragen. Retry-After nennt die Wartezeit in Sekunden.
500internalFehler auf unserer Seite. Bitte später erneut versuchen.
402spending_limit_reachedDie Bestellung überschreitet das monatliche Ausgabenlimit Ihrer Organisation.
402budget_exceededDie Bestellung übersteigt das Budget des Schlüssels, des Gastes, dem er gehört, oder Ihr eigenes Monatslimit.
402billing_blockedBestellungen sind für Ihre Organisation derzeit angehalten. Den Grund sehen Inhaber unter Abrechnung.
409price_changedDie Bestellung kostet etwas anderes als in expectedNetCents angegeben. Fragen Sie den Preis erneut ab.
409idempotency_conflictDieser Idempotency-Key wurde schon für eine andere Bestellung verwendet.
409not_cancellableDie Bestellung steht nicht mehr in der Warteschlange.
403plan_requiredDer API-Zugang gehört nicht zum Tarif Ihrer Organisation. Der Schlüssel bleibt erhalten und funktioniert wieder, sobald der Tarif ihn enthält. Mit dem Grund storage_full (beim Bestellen): Der Speicher Ihrer Organisation ist voll; lesende Aufrufe funktionieren weiter.
402payment_requiredEs wurde nichts gestartet und nichts berechnet. reason ist invoice_address_required (für die Monatsrechnung fehlt noch die Rechnungsadresse) oder monthly_limit_reached (der Auftrag würde das monatliche Limit des Inhabers überschreiten).
429too_many_jobsFür die Organisation sind zu viele Umwandlungen in Arbeit.
503service_unavailableDer Zahlungsanbieter ist nicht erreichbar; es wurde nichts gestartet.

Beispiele

Antwort (400)

{
  "error": {
    "code": "validation_failed",
    "message": "The request is not valid. See `details`.",
    "details": [
      {
        "field": "title",
        "code": "required",
        "message": "title is required."
      },
      {
        "field": "construction",
        "code": "no_number",
        "message": "construction must contain a number."
      }
    ]
  }
}

Antwort (401)

{
  "error": {
    "code": "unauthorized",
    "message": "Missing or invalid API key. Send it as `Authorization: Bearer <key>`."
  }
}

Antwort (403)

{
  "error": {
    "code": "forbidden",
    "message": "This API key does not have the scope this call needs."
  }
}

Antwort (404)

{
  "error": {
    "code": "not_found",
    "message": "Not found."
  }
}

Antwort (429)

{
  "error": {
    "code": "rate_limited",
    "message": "Too many requests. Wait for the time given in `Retry-After`."
  }
}

Antwort (402)

{
  "error": {
    "code": "spending_limit_reached",
    "message": "This order exceeds the organization's monthly spending limit."
  }
}

Antwort (409)

{
  "error": {
    "code": "idempotency_conflict",
    "message": "This `Idempotency-Key` was already used for another order. Use a new key for a new order."
  }
}

Antwort (402)

{
  "error": {
    "code": "payment_required",
    "message": "This job would exceed the monthly limit, so nothing was started. Its owner can raise the limit under Usage & invoices.",
    "reason": "monthly_limit_reached"
  }
}

Limits

  • Pro Schlüssel sind 100 Anfragen in Folge erlaubt. Nach 10 Sekunden ohne Anfrage steht das volle Kontingent wieder bereit.
  • Ist das Kontingent erschöpft, antwortet die API mit 429 und nennt in Retry-After die Wartezeit in Sekunden.
  • Rufen Sie Daten nicht bei jedem Seitenaufruf Ihrer Website ab, sondern speichern Sie sie zwischen.