Integration der Alter Product Public API

Die Public API ist für Server-zu-Server-Integrationen mit Shops, E-Commerce-Backends, WordPress/WooCommerce-Plugins und externen Produktionsabläufen vorgesehen.

Authentifizierung und Basis-URL

https://alterproduct.com/public-api/v1

Erstelle API-Zugangsdaten in den E-Commerce-Einstellungen. Das Access Token wird nur einmal angezeigt. Speichere es daher sofort im sicheren Geheimnisspeicher deines Backends.

Bewahre Access Key und Access Token auf deinem Server auf. Authentifizierte Endpunkte lehnen vom Browser ausgehende Aufrufe mit Origin- oder Referer-Headern ab.

Zugangsdaten können auf Berechtigungsbereiche beschränkt werden. Prüfe mit GET /auth/check den aktiven Shop, die Tarifmöglichkeiten und die für die Zugangsdaten zurückgegebenen Berechtigungsbereiche.

x-alter-access-key: YOUR_API_KEY
x-alter-access-token: YOUR_API_TOKEN
ParameterErforderlichDetails
x-alter-access-keyjaÖffentliche Kennung der Zugangsdaten.
x-alter-access-tokenjaGeheimes Token, das zum Zugriffsschlüssel gehört.
x-alter-client-fingerprintneinOptionaler stabiler Fingerabdruck zur Begrenzung von Einbettungssitzungsanfragen.
Authorizationnur LaufzeitVon POST /embed/session zurückgegebenes Bearer-Token für /runtime/bootstrap.

Verbindungstest

Nutze den Authentifizierungsendpunkt, bevor du Synchronisierung oder Einbettungsfunktionen in einer Live-Integration aktivierst.

GET https://alterproduct.com/public-api/v1/auth/check

Beispielanfrage (fetch)

const response = await fetch('https://alterproduct.com/public-api/v1/auth/check', {
  method: 'GET',
  headers: {
    'x-alter-access-key': process.env.ALTER_ACCESS_KEY,
    'x-alter-access-token': process.env.ALTER_ACCESS_TOKEN
  }
});

const payload = await response.json();

if (!response.ok) {
  throw new Error(payload?.code || payload?.error || `Alter API ${response.status}`);
}

console.log(payload);

Beispielantwort

{
  "ok": true,
  "message": "success",
  "storefrontId": 12,
  "userOwnerId": 34,
  "credentialId": 56,
  "scopes": ["orders:read", "orders:write", "products:read"],
  "plan": {
    "requiredPlan": "Business",
    "currentPlanName": "Business",
    "eligible": true,
    "runtimeFlags": {
      "viewer": true,
      "configurator": true,
      "customizer": true
    },
    "limits": {
      "activeRuntimeBindingsLimit": 100,
      "monthlyReassignmentLimit": 1000,
      "monthlyEmbedTokenLimit": 50000
    }
  }
}

Die folgende Hilfsfunktion wird in den weiteren Beispielen verwendet. Sie nutzt einfaches fetch und läuft in Node.js 18+ oder jeder Serverlaufzeit, die fetch bereitstellt.

const ALTER_API_BASE = 'https://alterproduct.com/public-api/v1';

const authHeaders = {
  'x-alter-access-key': process.env.ALTER_ACCESS_KEY,
  'x-alter-access-token': process.env.ALTER_ACCESS_TOKEN
};

async function alterFetch(path, options = {}) {
  const response = await fetch(`${ALTER_API_BASE}${path}`, {
    ...options,
    headers: {
      ...authHeaders,
      ...(options.body ? { 'Content-Type': 'application/json' } : {}),
      ...options.headers
    }
  });

  const payload = await response.json().catch(() => null);

  if (!response.ok) {
    throw new Error(payload?.code || payload?.error || `Alter API ${response.status}`);
  }

  return payload;
}

Endpunktübersicht

Die folgende Tabelle entspricht den in backend-public-api/app.js eingebundenen öffentlichen Routen. Pfade enthalten das öffentliche Proxy-Präfix für externe Integrationen.

MethodeEndpunktBeschreibungZugriff
GET/public-api/healthzStatusprüfung des Dienstes.öffentlich
GET/public-api/v1/auth/checkValidiert Zugangsdaten und gibt Shop, Berechtigungsbereiche und Tarifmöglichkeiten zurück.beliebige authentifizierte Zugangsdaten
GET/public-api/v1/customer-ordersGibt eine paginierte und filterbare Liste von Kundenbestellungen zurück.orders:read
GET/public-api/v1/customer-orders/:idGibt eine einzelne Kundenbestellung mit konfigurierten Produktpositionen zurück.orders:read
POST/public-api/v1/customer-orders/batchGibt bis zu 100 Bestellungen anhand ihrer IDs zurück.orders:read
PATCH/public-api/v1/customer-orders/:id/statusAktualisiert den Bestellstatus.orders:write
PATCH/public-api/v1/customer-orders/:orderId/quantityAktualisiert die Mengen ausgewählter Bestellpositionen.orders:write
PATCH/public-api/v1/customer-orders/:orderId/quantity/allLegt eine einheitliche Menge für jede Position einer Bestellung fest.orders:write
DELETE/public-api/v1/customer-orders/:idLöscht eine Kundenbestellung, die dem Shop-Inhaber gehört.orders:write
GET/public-api/v1/productsGibt Shop-Produkte/-Designs mit Einbettungsverfügbarkeit und Medien-URLs zurück.products:read
GET/public-api/v1/products/:idGibt ein Shop-Produkt/-Design zurück.products:read
POST/public-api/v1/embed/sessionStellt ein kurzlebiges JWT für eingebettete Werkzeuge einschließlich des Modellgenerators aus.embed:session:create
GET/public-api/v1/runtime/bootstrapErmittelt den Laufzeitkontext aus einem Einbettungs-JWT.Bearer-Einbettungstoken
GET/public-api/v1/assetsListet Asset-Katalogeinträge des angeforderten Typs auf.beliebige authentifizierte Zugangsdaten
GET/public-api/v1/assets/:type/:assetIdGibt ein Asset-Manifest mit herunterladbaren Dateirollen zurück.beliebige authentifizierte Zugangsdaten
GET/public-api/v1/assets/:type/:assetId/files/:roleLädt eine Asset-Datei anhand ihrer Rolle herunter.beliebige authentifizierte Zugangsdaten
GET/public-api/v1/design-importsListet importierbare, bei Alter gehostete Designs auf.authentifizierte Zugangsdaten, Business-Tarif erforderlich
GET/public-api/v1/design-imports/:idGibt Designimportdaten und Dateibeschreibungen zurück.authentifizierte Zugangsdaten, Business-Tarif erforderlich
GET/public-api/v1/design-imports/:id/files/:fileIdLädt eine Datei aus einer Designimportbeschreibung herunter.authentifizierte Zugangsdaten, Business-Tarif erforderlich
GET/public-api/v1/file/public/products/:productId/:sizeGibt eine öffentliche Produktvorschau zurück. Die Größe muss small.png, medium.png oder big.png sein.öffentlich
GET/public-api/v1/file/protected/:keyGibt eine geschützte Datei anhand ihres Speicherschlüssels zurück.signierte URL oder files:read
GET/public-api/v1/fontsGibt alle verfügbaren Schriftarten zurück.öffentlich
GET/public-api/v1/currenciesGibt alle Währungen zurück.öffentlich
POST/public-api/v1/runtime-bindings/sync-from-wordpressErstellt oder aktualisiert Laufzeitzuordnungen aus WordPress-Produktzuordnungen.beliebige authentifizierte Zugangsdaten
PATCH/public-api/v1/runtime-bindings/:idAktualisiert eine Laufzeitzuordnung teilweise.beliebige authentifizierte Zugangsdaten
POST/public-api/v1/runtime-bindings/:id/activateAktiviert eine Laufzeitzuordnung.beliebige authentifizierte Zugangsdaten
POST/public-api/v1/runtime-bindings/:id/deactivateDeaktiviert eine Laufzeitzuordnung.beliebige authentifizierte Zugangsdaten
POST/public-api/v1/wp-connect/exchangeTauscht einen WordPress-Auto-Connect-Übergabecode gegen API-Zugangsdaten aus.einmaliger Übergabecode
GET/public-api/v1/model-generator/catalogListet sichtbare Generatorprodukte, Konfigurationen und Vorlagenrevisionen auf.embed:session:create
GET/public-api/v1/model-generator/modelsListet Modelle mit auf bestimmte Generatorquellen festgelegten Deskriptoren für den Import auf.embed:session:create
GET/public-api/v1/model-generator/designer-catalogLiefert den von Designer verwendeten Katalog der Generatormodelle.embed:session:create
GET/public-api/v1/model-generator/projectsListet die Generatorprojekte des Eigentümers und global verfügbare Projekte auf.embed:session:create
GET/public-api/v1/model-generator/projects/:projectIdLiefert die neueste oder ausgewählte Projektrevision, die Vorlage und das Dateimanifest.embed:session:create
GET/public-api/v1/model-generator/projects/:projectId/revisions/:revisionLiefert die neueste oder ausgewählte Projektrevision, die Vorlage und das Dateimanifest.embed:session:create
GET/public-api/v1/model-generator/projects/:projectId/artifacts/:artifactIdLädt ein Artefakt nach Prüfung des Zugriffs auf sein Projekt herunter.embed:session:create
GET/public-api/v1/model-generator/configurations/:configurationId/revisions/:revision/templateLiefert ein zugängliches Vorlagendokument für die ausgewählte Konfigurationsrevision.embed:session:create
GET/public-api/v1/model-generator/configurations/:configurationId/revisions/:revision/importLiefert das Importpaket der Vorlage einschließlich der abhängigen Dateien.embed:session:create
GET/public-api/v1/model-generator/mannequinsLiefert beide Schaufensterpuppen und die Deskriptoren ihrer Ressourcen.embed:session:create
GET/public-api/v1/model-generator/image-libraries/:kind/assetsListet Assets der Textur- oder Hintergrundbibliothek mit importierbaren Dateien auf.embed:session:create
GET/public-api/v1/model-generator/image-libraries/:kind/assets/:assetIdLiefert ein einzelnes Textur- oder Hintergrund-Asset mit seinen importierbaren Dateien.embed:session:create
GET/public-api/v1/model-generator/public-files/:keyLädt eine erlaubte Abhängigkeitsdatei des Generators herunter.embed:session:create

Kundenbestellungen

Mit den Kundenbestellendpunkten kann ein externer Shop konfigurierte Positionen lesen, Mengen aktualisieren, Bestellungen durch Abwicklungsstatus führen und aufgegebene Bestellungen entfernen.

ParameterErforderlichDetails
nameneinDurchsucht Designnamen und numerische Bestell-IDs.
category_idneinFiltert nach Produktkategorie-ID.
order_statusneinEiner der zulässigen Bestellstatus.
offsetneinStandard 0. Muss >= 0 sein.
limitneinStandard 9 für diesen Controller, maximal 50.
order_byneinid, created_at oder design_name.
directionneinASC oder DESC.

Beispielanfrage (fetch)

const params = new URLSearchParams({
  limit: '20',
  offset: '0',
  order_status: 'shopping_cart',
  order_by: 'created_at',
  direction: 'DESC'
});

const orders = await alterFetch(`/customer-orders?${params.toString()}`);

const order = await alterFetch('/customer-orders/123');

const batch = await alterFetch('/customer-orders/batch', {
  method: 'POST',
  body: JSON.stringify({
    customerOrderIds: [123, 124, 125]
  })
});

Zulässige Werte

StatusBeschreibung
shopping_cartWarenkorbablauf; der Kunde kann die Konfiguration weiterhin bearbeiten.
editableDie Bestellung bleibt für den Kunden bearbeitbar.
paidDie Bestellung ist bezahlt und bereit zur Abwicklung.
processingDie Bestellung wird abgewickelt.
completedDie Bestellung wurde abgewickelt.
cancelledDie Bestellung wurde storniert.

Beispielanfrage (fetch)

await alterFetch('/customer-orders/123/status', {
  method: 'PATCH',
  body: JSON.stringify({
    status: 'processing'
  })
});

await alterFetch('/customer-orders/123/quantity', {
  method: 'PATCH',
  body: JSON.stringify({
    items: [
      { orderDetailId: 987, quantity: 3 }
    ]
  })
});

await alterFetch('/customer-orders/123/quantity/all', {
  method: 'PATCH',
  body: JSON.stringify({
    quantity: 2
  })
});

await alterFetch('/customer-orders/123', {
  method: 'DELETE'
});

Beispielantwort

{
  "order": {
    "id": 123,
    "customizerId": 381,
    "orderStatus": "shopping_cart",
    "createdAt": "2026-05-28T10:15:00.000Z",
    "customizerOrderURL": "https://alterproduct.com/app/customizer/381/123",
    "productItems": [
      {
        "id": 987,
        "model3d": { "id": 381 },
        "size": {
          "id": 395,
          "name": { "pl": "M", "en": "M" },
          "measureSize": null
        },
        "material": {
          "id": 2,
          "name": { "pl": "Bawełna", "en": "Cotton" }
        },
        "printType": {
          "id": 1,
          "name": { "pl": "DTG", "en": "DTG" }
        },
        "color": {
          "id": 418,
          "name": { "pl": "Domyślny", "en": "Default" },
          "hex": "#ffffff"
        },
        "variant": {
          "id": 531,
          "metadata": null,
          "stockQuantity": 25
        },
        "unitPrice": { "value": 12.5, "currency": "EUR" },
        "totalPrice": { "value": 37.5, "currency": "EUR" },
        "quantity": 3
      }
    ],
    "customizerName": "Men's T-Shirt",
    "productGroup": {
      "id": 4,
      "name": { "pl": "Koszulka", "en": "T-Shirt" }
    },
    "totalPrice": { "value": 37.5, "currency": "EUR" }
  }
}

Shop-Produkte

Produktendpunkte geben Shop-Designs zurück, die als Viewer, Configurator oder Customizer eingebettet werden können.

ParameterErforderlichDetails
nameneinDurchsucht Produkt-/Designnamen.
customizerneintrue oder false.
offsetneinStandard 0. Muss >= 0 sein.
limitneinStandard 9, maximal 50.
order_byneinid, name oder created_at.
directionneinASC oder DESC.

Beispielanfrage (fetch)

const params = new URLSearchParams({
  limit: '20',
  offset: '0',
  name: 't-shirt',
  customizer: 'true',
  order_by: 'created_at',
  direction: 'DESC'
});

const products = await alterFetch(`/products?${params.toString()}`);
const product = await alterFetch('/products/381');

Beispielantwort

{
  "products": {
    "items": [
      {
        "id": 381,
        "name": "Men's T-Shirt",
        "createdAt": "2026-01-03T23:55:05.000Z",
        "productId": 4,
        "media": {
          "img": {
            "big": "https://alterproduct.com/public-api/v1/file/public/products/4/big.png",
            "medium": "https://alterproduct.com/public-api/v1/file/public/products/4/medium.png",
            "small": "https://alterproduct.com/public-api/v1/file/public/products/4/small.png"
          },
          "mockups": []
        },
        "storefrontProduct": {
          "id": 89,
          "idUserDesign": 381,
          "shareAccess": "public",
          "isCustomizer": 1
        },
        "runtimeBindings": [
          {
            "id": 42,
            "runtimeType": "customizer",
            "status": "active",
            "externalProductId": "wc_123"
          }
        ],
        "embeddable": {
          "viewer": true,
          "configurator": true,
          "customizer": true
        }
      }
    ],
    "total": 1
  }
}

Einbettungssitzungen und Laufzeitinitialisierung

Erstelle auf deinem Server ein kurzlebiges Einbettungstoken und übergib es an das iframe bzw. die Laufzeit. Diese ruft anschließend die Initialisierung mit einem Bearer-Token auf.

ParameterErforderlichDetails
runtimeBindingIdempfohlenBevorzugte Kennung für aktive Laufzeitzuordnungen.
toolohne runtimeBindingId erforderlichdesigner | viewer | configurator | customizer | model-generator
toolIdtool: model-generatorPositive numerische ID des lokalen Generatorprojekts, nicht dessen UUID oder die WooCommerce-Produkt-ID.
originjaOrigin, auf dem die Einbettung dargestellt wird, z. B. https://yourstore.com.
designIdeine KennungAlter Product Design-ID. Nicht mit orderId kombinieren.
orderIdeine KennungCustomizer-Bestell-ID. Nur für customizer gültig.
cartKey + cartModeneinWarenkorbkontext nur für Customizer. cartMode ist view oder edit.

Beispielanfrage (fetch)

const session = await alterFetch('/embed/session', {
  method: 'POST',
  headers: {
    'x-alter-client-fingerprint': '9f1b7a5e4b3c2d1f9f1b7a5e4b3c2d1f'
  },
  body: JSON.stringify({
    runtimeBindingId: 42,
    origin: 'https://yourstore.com'
  })
});

const bootstrapResponse = await fetch('https://alterproduct.com/public-api/v1/runtime/bootstrap', {
  method: 'GET',
  headers: {
    Authorization: `Bearer ${session.token}`
  }
});

const bootstrap = await bootstrapResponse.json();
console.log({ session, bootstrap });

Hinweise

await alterFetch('/embed/session', {
  method: 'POST',
  body: JSON.stringify({
    tool: 'customizer',
    origin: 'https://yourstore.com',
    orderId: 123
  })
});

await alterFetch('/embed/session', {
  method: 'POST',
  body: JSON.stringify({
    tool: 'viewer',
    origin: 'https://yourstore.com',
    designId: 381
  })
});

Beispielantwort

{
  "token": "eyJhbGciOiJIUzI1NiIsImtpZCI6IjEifQ...",
  "expiresIn": 900,
  "kid": "1",
  "mode": "design",
  "runtimeBindingId": 42,
  "runtimeType": "customizer"
}

Runtime bootstrap

{
  "runtimeBindingId": 42,
  "designId": 381,
  "productId": "wc_123",
  "runtimeType": "customizer",
  "storageMode": "wordpress_local",
  "manifestUrl": "https://yourstore.com/wp-content/uploads/alter/381/manifest.json",
  "assetBaseUrl": "https://yourstore.com/wp-content/uploads/alter/381/",
  "manifestHash": "a3b1...",
  "planCapabilities": {
    "viewer": true,
    "configurator": true,
    "customizer": true
  },
  "cartKey": null,
  "cartMode": null,
  "orderId": null
}

3D-Modellgenerator

Die Importendpunkte des Generators erlauben nur lesende Anfragen zwischen Servern. Sie erfordern die üblichen API-Header, den Scope embed:session:create und einen aktiven Tarif. Die Importautorisierung erstellt keine Editorsitzung und verbraucht deren monatliches Kontingent nicht. Beim Öffnen des Editors gilt derselbe Zähler monthlyEmbedTokenLimit wie für die anderen eingebetteten Werkzeuge.

Generatormodelle finden und importieren

Über /model-generator/models können Sie verfügbare Modelle mit Generator auflisten. Der Deskriptor generator legt projectId, revision, configurationId, templateRevision, productId und productModel3dId fest. Rufen Sie seinen importPath auf, um genau diese Quellrevision abzurufen. Die Manifeste der Produkt-Assets enthalten ebenfalls generators sowie den Deskriptor generator jedes Modells. Vorlagen können anhand ihrer Konfiguration und Revision separat importiert werden.

Katalogfilter

EndpunktDetails
/model-generator/modelsModellliste: name (oder q), categoryId, scope (all, own, global), limit (1–50) und offset.
/model-generator/catalogVorlagenkatalog: generatorType, productId, audience, q, templateKey, configurationId, limit und offset.
/model-generator/projectsProjektliste: configurationId, q, scope (all, own, global), limit und offset. Der öffentliche Proxy setzt scope standardmäßig auf all.
/model-generator/image-libraries/:kind/assetsTextur- und Hintergrundbibliotheken: kind ist texture oder background; q, category und mapType filtern die verfügbaren Assets.

Ein Projektimport enthält document, revision, template und ein Manifest files. Jede Datei liefert einen path unter /v1/model-generator/; stellen Sie beim Herunterladen von Alter Product /public-api voran. Kopieren Sie die benötigten Dateien in Ihren eigenen Speicher und ersetzen Sie die Quellverweise durch lokale Verweise. Importieren Sie Schaufensterpuppen und Texturbibliotheken über ihre Katalogendpunkte; public-files ist auf erlaubte Ressourcenpfade beschränkt, und Vorlagen müssen die Zugriffsprüfung für ihre Konfiguration und Revision bestehen.

Beispielanfrage (fetch)

// Server-side: uses the alterFetch helper and authHeaders defined above.
const catalog = await alterFetch('/model-generator/models?' + new URLSearchParams({
  scope: 'all', limit: '24', offset: '0'
}));

const selected = catalog.items[0];
if (!selected?.generator) throw new Error('Select an available generator model');

const importPath = selected.generator.importPath;
if (!importPath.startsWith('/v1/model-generator/projects/')) {
  throw new Error('Invalid generator import path');
}
const bundle = await alterFetch(importPath.slice('/v1'.length));

for (const file of bundle.files) {
  if (!file.path.startsWith('/v1/model-generator/')) {
    throw new Error('Invalid generator file path');
  }
  const response = await fetch('https://alterproduct.com/public-api' + file.path, {
    headers: authHeaders,
    redirect: 'error'
  });
  if (!response.ok) throw new Error(`File download failed: ${response.status}`);
  const bytes = new Uint8Array(await response.arrayBuffer());
  // Persist bytes in your local storage; record the mapping from
  // file.sourceHref / file.href to the resulting local file reference.
}
// Persist bundle.document, bundle.template and revision metadata locally.
// Import the related product asset and its textures/mockups as needed:
const product = await alterFetch('/assets/products/' + selected.generator.productId);
const mannequins = await alterFetch('/model-generator/mannequins');
console.log({ product, mannequins });

Editorsitzung und lokale Speicherung

Erstellen Sie die Editorsitzung mit tool: model-generator, einer positiven numerischen toolId zur Identifizierung des lokalen Generatorprojekts (nicht dessen UUID oder der WooCommerce-Produkt-ID) und dem erlaubten Ursprung des Shops. Übergeben Sie für dieses Werkzeug weder designId, orderId, runtimeBindingId noch Warenkorbfelder. Die UUID des Generatorprojekts ist ein separater Bezeichner. Übermitteln Sie das zurückgegebene Token über den Iframe-Handshake; der Runtime-Bootstrap liefert den Generatorkontext mit storageMode: wordpress_local.

// Server-side, after authorizing the merchant's access to this local project.
const localProjectId = 42; // Local generator project ID, not its UUID or WC product ID.
const session = await alterFetch('/embed/session', {
  method: 'POST',
  body: JSON.stringify({
    tool: 'model-generator',
    toolId: localProjectId,
    origin: 'https://yourstore.com'
  })
});

// The iframe receives session.token through ALTER_CUSTOMIZER_SESSION_READY.
// Do not put API credentials or the token in the iframe URL.
const bootstrapResponse = await fetch('https://alterproduct.com/public-api/v1/runtime/bootstrap', {
  headers: { Authorization: `Bearer ${session.token}` }
});
if (!bootstrapResponse.ok) throw new Error('Generator bootstrap failed');
const context = await bootstrapResponse.json();
console.log(context);

Beispielantwort

{
  "runtimeBindingId": null,
  "designId": null,
  "productId": 42,
  "toolId": 42,
  "runtimeType": "model-generator",
  "storageMode": "wordpress_local",
  "parentOrigin": "https://yourstore.com"
}
// Host page: WordPress returns a numeric toolId and a UUID in id.
const url = new URL('https://alterproduct.com/app/model-generator');
url.search = new URLSearchParams({
  embedded: '1',
  lng: 'en',
  parentOrigin: window.location.origin,
  toolId: String(localProject.toolId),
  serverProjectId: localProject.id
}).toString();
// Optional: serverProjectRevision pins an existing saved revision.
iframe.src = url.toString();
// Install the authenticated handshake and storage bridge described below.
// Setting iframe.src alone does not authorize the editor or provide storage.

Iframe-Nachrichten der WordPress-Brücke

Das WordPress-Plugin stellt die Speicherbrücke bereit und prüft Administrator- oder WooCommerce-Manager-Berechtigungen. Es validiert Iframe-Ursprung, Quellfenster, nonce, Anfrage-ID und erlaubte Projektpfade. Die Brücke leitet lokale Lese- und Schreibvorgänge an /wp-json/alter-wc/v1/model-generator weiter. API-Zugangsdaten bleiben auf dem Server. Eine eigene Integration muss eine gleichwertige authentifizierte Speicherverarbeitung bereitstellen; die öffentliche Generator-API speichert keine Projekte bei Alter Product.

TypBeschreibung
ALTER_CHILD_HELLO / ALTER_PARENT_ACKDas Iframe startet den Handshake mit einer nonce; die übergeordnete Seite bestätigt dieselbe nonce.
ALTER_CUSTOMIZER_INIT_SESSION / ALTER_CUSTOMIZER_SESSION_READYDas Iframe fordert eine Bearbeitungssitzung für model-generator an; die übergeordnete Seite liefert das autorisierte Token.
ALTER_MODEL_GENERATOR_REQUESTDas Iframe sendet requestId, nonce und request mit method, path, data und responseType.
ALTER_MODEL_GENERATOR_RESPONSEDie übergeordnete Seite antwortet mit derselben requestId und nonce sowie status, data, headers und gegebenenfalls error.
// Messages after ALTER_CHILD_HELLO / ALTER_PARENT_ACK agree on the nonce.
// Iframe -> parent:
const sessionRequest = {
  type: 'ALTER_CUSTOMIZER_INIT_SESSION',
  nonce: handshakeNonce,
  payload: {
    tool: 'model-generator', alterProductId: localProject.toolId, mode: 'edit'
  }
};

// Parent -> iframe, after the server authorizes the merchant and issues a token:
const sessionReady = {
  type: 'ALTER_CUSTOMIZER_SESSION_READY',
  nonce: handshakeNonce,
  token: session.token,
  tool: 'model-generator',
  cartKey: `model-generator:${localProject.id}`,
  mode: 'edit',
  localSession: false,
  adminSession: true
};
// Send only to the validated iframe's exact origin and source window.
// An authorized token and successful bootstrap are still required.

Beim Speichern werden expectedRevision, templateRevision, document und Artefaktverweise übermittelt. Dadurch entsteht eine unveränderliche Revision; ein veralteter Wert für expectedRevision führt zu HTTP 409. WordPress speichert Metadaten in seiner Datenbank und Dateien im Uploads-Verzeichnis. JSON wird minifiziert und mit gzip komprimiert, wenn dies die Dateigröße verringert.

// Example message from the iframe; savedSnapshot and artifact IDs come
// from the generator. The host checks origin/source/nonce/project permissions.
const message = {
  type: 'ALTER_MODEL_GENERATOR_REQUEST',
  requestId: crypto.randomUUID(),
  nonce: handshakeNonce,
  request: {
    method: 'POST',
    path: `/pattern-generator/projects/${projectUuid}/revisions`,
    data: {
      expectedRevision: loadedRevision,
      name: projectName,
      templateRevision,
      document: savedSnapshot,
      references: { artifactIds: savedArtifactIds }
    },
    responseType: 'json'
  }
};

Gespeichertes Modell im Design verwenden veröffentlicht eine vollständige gespeicherte Revision in einem verknüpften Produktdesign. Kunden sehen sie anschließend im bestehenden Customizer, Configurator oder Viewer mit den üblichen Produktzuordnungen und Abonnementprüfungen. Der Generatoreditor bleibt ein Werkzeug für Händler. Bestellverknüpfungen behalten das gespeicherte Projekt und dessen Revision bei, sodass spätere Änderungen frühere Bestellungen nicht unbemerkt verändern.

Asset-Katalog

Der Asset-Katalog stellt Produktquellassets, Hintergründe, Umgebungen, Grafiken, Designvorlagen und Mockup-Assets bereit. Listenendpunkte liefern schlanke Beschreibungen; Detailendpunkte enthalten Dateimanifeste.

TypBeschreibung
productsBasis-Produktassets, Vorschauen, 3D-Modelle sowie Material- und Texturbeschreibungen.
backgroundsStatische Viewer-Hintergründe.
environmentsUmgebungskarten und Vorschaubilder.
image_libraryAssets der Grafikbibliothek, einschließlich shopspezifischer Grafiken.
design_templatesVorschauen von Designvorlagen und Verweise auf Ebenendateien. Unterstützt den Filter product_id.
mockupsAssets, Hintergründe und Überlagerungskarten des Mockup-Generators. Unterstützt den Filter product_id.

Beispielanfrage (fetch)

const assets = await alterFetch('/assets?' + new URLSearchParams({
  type: 'products',
  limit: '20',
  offset: '0',
  search: 'mug'
}));

const details = await alterFetch('/assets/products/4');

const fileResponse = await fetch(
  'https://alterproduct.com/public-api/v1/assets/products/4/files/preview_medium',
  {
    headers: authHeaders
  }
);

const fileBlob = await fileResponse.blob();

Beispielantwort

{
  "type": "products",
  "items": [
    {
      "assetType": "products",
      "assetId": "4",
      "title": "Mug 450ml",
      "slug": "product-4",
      "description": "Base product 4",
      "primaryRole": "preview_big",
      "fileCount": 8,
      "remoteVersion": "1.0",
      "thumbnail": {
        "role": "preview_small",
        "fileName": "product-4-preview-small.png",
        "mime": "image/png",
        "downloadPath": "/v1/assets/products/4/files/preview_small"
      },
      "metadata": {
        "productCategoryId": 2,
        "productModelCount": 1,
        "isDedicated": false
      }
    }
  ],
  "total": 1,
  "limit": 20,
  "offset": 0
}

Designimporte

Designimporte stellen bei Alter gehostete Designs und ihre Dateien für externe Produktions- oder Migrationsabläufe bereit. Die API prüft die Berechtigung des Business-Tarifs.

ParameterErforderlichDetails
searchneinDurchsucht Designtitel oder ID.
offsetneinStandard 0.
limitneinStandard 20, maximal 100.

Beispielanfrage (fetch)

const imports = await alterFetch('/design-imports?' + new URLSearchParams({
  limit: '20',
  offset: '0',
  search: 'mug'
}));

const details = await alterFetch('/design-imports/381');

const fileId = details.files[0].id;
const fileResponse = await fetch(
  `https://alterproduct.com/public-api/v1/design-imports/381/files/${fileId}`,
  {
    headers: authHeaders
  }
);

const fileBlob = await fileResponse.blob();

Beispielantwort

{
  "eligible": true,
  "requiredPlan": "Business",
  "currentPlanName": "Business",
  "designs": [
    {
      "id": 381,
      "title": "Men's T-Shirt",
      "createdAt": "2026-01-03T23:55:05.000Z",
      "sourceStorefrontId": 12,
      "productId": 4,
      "productName": {
        "pl": "Koszulka",
        "en": "T-Shirt"
      },
      "storageMode": "alter",
      "runtimeStatus": {
        "designer": true,
        "viewer": true,
        "configurator": true,
        "customizer": true
      },
      "thumbnail": {
        "kind": "design-mockup",
        "fileId": "7df7...",
        "downloadPath": "/v1/design-imports/381/files/7df7..."
      }
    }
  ],
  "total": 1
}

Dateien, Schriftarten und Währungen

Öffentliche Vorschaudateien sind für Browser geeignet. Geschützte Dateien erfordern eine signierte URL oder API-Zugangsdaten mit files:read. Schriftarten und Währungen sind öffentlich lesbare Endpunkte.

EndpunktZugriffDetails
/file/public/products/:productId/small.pngöffentlichKleine Produktvorschau.
/file/public/products/:productId/medium.pngöffentlichMittlere Produktvorschau.
/file/public/products/:productId/big.pngöffentlichGroße Produktvorschau.
/file/protected/:keysignierte URL oder files:readGeschützte Datei im Objektspeicher.
/fontsöffentlichArray von Schriftarteinträgen.
/currenciesöffentlichArray von Währungseinträgen.

Beispielanfrage (fetch)

const publicPreview = await fetch(
  'https://alterproduct.com/public-api/v1/file/public/products/4/medium.png'
);

const protectedFile = await fetch(
  'https://alterproduct.com/public-api/v1/file/protected/user_34/381/design/mockup-large.webp',
  {
    headers: authHeaders
  }
);

const fonts = await fetch('https://alterproduct.com/public-api/v1/fonts').then((res) => res.json());
const currencies = await fetch('https://alterproduct.com/public-api/v1/currencies').then((res) => res.json());

Beispielantwort

[
  {
    "id": 1,
    "family": "Inter",
    "source": "google",
    "category": "sans-serif",
    "variants": ["regular", "600", "700"],
    "subsets": ["latin"],
    "version": "v19",
    "menu": "Inter",
    "files": {
      "regular": "https://..."
    }
  }
]
[
  {
    "id": 1,
    "code": "EUR",
    "name": "Euro",
    "symbol": "€",
    "decimalPlaces": 2
  }
]

Laufzeitzuordnungen

Laufzeitzuordnungen verbinden externe Shop-Produkte mit Alter Product Designs und Laufzeittypen. Sie werden hauptsächlich von WordPress/WooCommerce-Integrationen und erweiterten Shop-Backends verwendet.

ParameterErforderlichDetails
designIdneinID eines Alter Product Designs, das dem Shop gehört.
externalProductIdja für die SynchronisierungExterne Produkt-ID, z. B. eine WooCommerce-Produkt-ID.
runtimeTypeja für die Synchronisierungviewer, configurator oder customizer.
statusneindraft, active, inactive, archived oder legacy_active.
legacyStorefrontProductIdneinOptionale ID einer bisherigen Zuordnung.
legacyBindingMetaneinOptionale JSON-Metadaten, z. B. manifestHash.

Beispielanfrage (fetch)

await alterFetch('/runtime-bindings/sync-from-wordpress', {
  method: 'POST',
  body: JSON.stringify({
    bindings: [
      {
        externalProductId: 'wc_123',
        runtimeType: 'customizer',
        status: 'active',
        designId: 381,
        legacyBindingMeta: {
          manifestHash: 'a3b1...'
        }
      }
    ]
  })
});

await alterFetch('/runtime-bindings/42', {
  method: 'PATCH',
  body: JSON.stringify({
    status: 'inactive'
  })
});

await alterFetch('/runtime-bindings/42/activate', { method: 'POST' });
await alterFetch('/runtime-bindings/42/deactivate', { method: 'POST' });

wordpress_local

await alterFetch('/runtime-bindings/sync-from-wordpress', {
  method: 'POST',
  body: JSON.stringify({
    bindings: [
      {
        externalProductId: 'wc_123',
        runtimeType: 'viewer',
        status: 'active',
        externalDesign: {
          externalDesignKey: 'wp-design-381',
          productId: 4,
          title: 'WooCommerce local design',
          manifestUrl: 'https://yourstore.com/wp-content/uploads/alter/381/manifest.json',
          assetBaseUrl: 'https://yourstore.com/wp-content/uploads/alter/381/',
          manifestHash: 'a3b1...',
          sourceMeta: {
            pluginVersion: '1.2.0'
          }
        }
      }
    ]
  })
});

Beispielantwort

{
  "message": "runtimeBinding.syncCompleted",
  "runtimeBindings": [
    {
      "id": 42,
      "designId": 381,
      "externalProductId": "wc_123",
      "runtimeType": "customizer",
      "status": "active"
    }
  ]
}

WordPress-Verbindungsaustausch

Der WordPress-Verbindungsendpunkt löst einen einmaligen Übergabecode ein und gibt API-Zugangsdaten an das Plugin zurück. Er ist kein allgemeiner Endpunkt zum Erstellen von Zugangsdaten.

Beispielanfrage (fetch)

const response = await fetch('https://alterproduct.com/public-api/v1/wp-connect/exchange', {
  method: 'POST',
  headers: {
    'Content-Type': 'application/json'
  },
  body: JSON.stringify({
    code: 'ONE_TIME_HANDOFF_CODE',
    storeUrl: 'https://yourstore.com/',
    siteOrigin: 'https://yourstore.com',
    codeVerifier: 'PKCE_CODE_VERIFIER_32_TO_128_CHARS'
  })
});

const credentials = await response.json();

Beispielantwort

{
  "message": "wpConnect.exchange.ok",
  "accessKey": "generated-access-key",
  "accessToken": "generated-access-token",
  "storefrontId": 12
}

Fehler und Anfragelimits

Die meisten Controller-Fehler werden als Antwort mit code vereinheitlicht. Authentifizierungs-Middleware und Anfragelimiter können stattdessen eine Antwort mit error zurückgeben.

// Controller error
{
  "code": "assetCatalog.invalidType"
}

// Auth middleware or rate limit
{
  "error": "Unauthorized"
}

{
  "error": "Too Many Requests"
}
TypLimitZeitfenster
Global600 Anfragen60 Sekunden
GET /auth/check60 Anfragen60 Sekunden
Bestellungen lesen/Produkte lesen300 Anfragen60 Sekunden
Bestellungen schreiben/Einbettungssitzungen/Laufzeitzuordnungen120 Anfragen60 Sekunden
Assets/Designimporte lesen180 Anfragen60 Sekunden
Schriftarten300 Anfragen60 Sekunden
WP-Verbindungsaustausch30 Anfragen60 Sekunden
GET /model-generator/*600 Anfragen60 Sekunden