Генератор 3D-моделей
Эндпоинты импорта генератора поддерживают только чтение при взаимодействии между серверами. Для них требуются стандартные заголовки API, разрешение embed:session:create и активный тариф. Авторизация импорта не создаёт сеанс редактора и не расходует его месячный лимит. Открытие редактора использует тот же счётчик monthlyEmbedTokenLimit, что и остальные встроенные инструменты.
Поиск и импорт моделей с генератором
Используйте /model-generator/models для получения списка доступных моделей с генераторами. Дескриптор generator фиксирует projectId, revision, configurationId, templateRevision, productId и productModel3dId. Перейдите по его importPath, чтобы получить именно эту исходную ревизию. Манифесты ресурсов товара также предоставляют generators и дескриптор generator для каждой модели. Шаблоны можно импортировать отдельно по конфигурации и ревизии.
Фильтры каталогов
| Конечная точка | Подробности |
|---|---|
/model-generator/models | Список моделей: name (или q), categoryId, scope (all, own, global), limit (1-50) и offset. |
/model-generator/catalog | Каталог шаблонов: generatorType, productId, audience, q, templateKey, configurationId, limit и offset. |
/model-generator/projects | Список проектов: configurationId, q, scope (all, own, global), limit и offset. Публичный прокси по умолчанию использует scope all. |
/model-generator/image-libraries/:kind/assets | Библиотеки текстур и фонов: kind принимает значение texture или background; q, category и mapType фильтруют доступные ресурсы. |
Импорт проекта содержит document, revision, template и манифест files. Каждый файл предоставляет path в пространстве /v1/model-generator/; при загрузке из Alter Product добавьте перед ним /public-api. Скопируйте необходимые файлы в собственное хранилище и замените исходные ссылки локальными. Импортируйте манекены и библиотеки текстур через их эндпоинты каталогов; public-files допускает только разрешённые пути ресурсов, а шаблоны проходят проверку доступа к конфигурации и ревизии.
Пример запроса (fetch)
// Server-side: uses alterFetch and authHeaders from the API connection guide.
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 });Сеанс редактора и локальное хранение
Создайте сеанс редактора с tool: model-generator, положительным числовым toolId локального проекта генератора (не его UUID и не ID товара WooCommerce) и разрешённым origin магазина. Не передавайте designId, orderId, runtimeBindingId или поля корзины для этого инструмента. UUID проекта генератора - отдельный идентификатор. Передайте полученный токен через handshake iframe; runtime bootstrap вернёт контекст генератора со 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);Пример ответа
{
"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, используемые для связи с WordPress
Плагин WordPress обеспечивает связь с локальным хранилищем и проверяет права администратора или менеджера WooCommerce. Он проверяет origin iframe, исходное окно, nonce, идентификатор запроса и разрешённые пути проекта. Локальные операции чтения и записи направляются на /wp-json/alter-wc/v1/model-generator. Учётные данные API остаются на сервере. Собственная интеграция должна реализовать равноценную обработку хранения с аутентификацией; публичный API генератора не сохраняет проекты в Alter Product.
| Тип | Описание |
|---|---|
ALTER_CHILD_HELLO / ALTER_PARENT_ACK | Дочерний iframe начинает handshake с nonce; родительская страница подтверждает тот же nonce. |
ALTER_CUSTOMIZER_INIT_SESSION / ALTER_CUSTOMIZER_SESSION_READY | Дочерний iframe запрашивает сеанс редактирования model-generator; родительская страница возвращает авторизованный токен. |
ALTER_MODEL_GENERATOR_REQUEST | Дочерний iframe отправляет requestId, nonce и request, содержащий method, path, data и responseType. |
ALTER_MODEL_GENERATOR_RESPONSE | Родительская страница отвечает с теми же requestId и nonce, а также полями status, data, headers и 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.При сохранении передаются expectedRevision, templateRevision, document и ссылки на артефакты. Создаётся неизменяемая ревизия; устаревший expectedRevision возвращает HTTP 409. WordPress хранит метаданные в своей базе данных, а файлы - в каталоге uploads. JSON минифицируется и сжимается с помощью gzip, если сжатие уменьшает его размер.
// 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'
}
};Действие «Использовать сохранённую модель в дизайне» публикует полную сохранённую ревизию в связанном дизайне. Покупатели затем видят её в существующем Customizer, Configurator или Viewer с обычными привязками товара и проверками подписки. Редактор генератора остаётся инструментом продавца. Ссылки в заказах сохраняют проект и ревизию, поэтому последующие правки не изменяют прошлые заказы автоматически.