Интеграция публичного API Alter Product

Публичный API предназначен для серверных интеграций с магазинами, торговыми системами, плагинами WordPress/WooCommerce и внешними производственными процессами.

Аутентификация и базовый URL

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

Создайте учётные данные API в настройках интернет-магазина. Токен доступа показывается только один раз, поэтому сразу сохраните его в защищённом хранилище секретов на сервере.

Храните ключ и токен доступа на своём сервере. Конечные точки с аутентификацией отклоняют вызовы из браузера с заголовками Origin или Referer.

Учётным данным можно назначить ограниченные права. Используйте GET /auth/check для проверки активного магазина, возможностей тарифа и прав, возвращаемых для учётных данных.

x-alter-access-key: YOUR_API_KEY
x-alter-access-token: YOUR_API_TOKEN
ПараметрОбязательноПодробности
x-alter-access-keyдаПубличный идентификатор учётных данных.
x-alter-access-tokenдаСекретный токен, связанный с ключом доступа.
x-alter-client-fingerprintнетНеобязательный стабильный отпечаток для ограничения частоты запросов сеансов встраивания.
Authorizationтолько среда выполненияТокен Bearer, возвращаемый POST /embed/session и используемый /runtime/bootstrap.

Проверка подключения

Проверяйте аутентификацию через соответствующую конечную точку перед включением синхронизации или встраивания в рабочей интеграции.

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

Пример запроса (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);

Пример ответа

{
  "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
    }
  }
}

Вспомогательная функция ниже используется в остальных примерах. Она основана на обычном fetch и работает в Node.js 18+ или любой серверной среде, предоставляющей fetch.

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;
}

Обзор конечных точек

Таблица ниже соответствует публичным маршрутам, подключённым в backend-public-api/app.js. Пути показаны с префиксом публичного прокси, используемым внешними интеграциями.

МетодКонечная точкаОписаниеДоступ
GET/public-api/healthzПроверка работоспособности сервиса.публичный
GET/public-api/v1/auth/checkПроверяет учётные данные и возвращает магазин, права доступа и возможности тарифа.любые аутентифицированные учётные данные
GET/public-api/v1/customer-ordersВозвращает список заказов покупателей с разбивкой на страницы и фильтрами.orders:read
GET/public-api/v1/customer-orders/:idВозвращает отдельный заказ покупателя с настроенными товарными позициями.orders:read
POST/public-api/v1/customer-orders/batchВозвращает до 100 заказов по ID.orders:read
PATCH/public-api/v1/customer-orders/:id/statusОбновляет статус заказа.orders:write
PATCH/public-api/v1/customer-orders/:orderId/quantityОбновляет количество выбранных позиций заказа.orders:write
PATCH/public-api/v1/customer-orders/:orderId/quantity/allУстанавливает одинаковое количество для каждой позиции заказа.orders:write
DELETE/public-api/v1/customer-orders/:idУдаляет заказ покупателя, принадлежащий владельцу магазина.orders:write
GET/public-api/v1/productsВозвращает товары/дизайны магазина с доступностью встраивания и URL медиафайлов.products:read
GET/public-api/v1/products/:idВозвращает один товар/дизайн магазина.products:read
POST/public-api/v1/embed/sessionВыдаёт краткосрочный JWT для встроенных инструментов, включая генератор моделей.embed:session:create
GET/public-api/v1/runtime/bootstrapОпределяет контекст среды выполнения по JWT встраивания.токен встраивания Bearer
GET/public-api/v1/assetsВозвращает список ресурсов каталога запрошенного типа.любые аутентифицированные учётные данные
GET/public-api/v1/assets/:type/:assetIdВозвращает манифест ресурса с ролями скачиваемых файлов.любые аутентифицированные учётные данные
GET/public-api/v1/assets/:type/:assetId/files/:roleСкачивает файл ресурса по роли.любые аутентифицированные учётные данные
GET/public-api/v1/design-importsВозвращает список доступных для импорта дизайнов, хранящихся в Alter.аутентифицированные учётные данные, требуется тариф Business
GET/public-api/v1/design-imports/:idВозвращает данные импорта дизайна и описания файлов.аутентифицированные учётные данные, требуется тариф Business
GET/public-api/v1/design-imports/:id/files/:fileIdСкачивает файл по описанию импорта дизайна.аутентифицированные учётные данные, требуется тариф Business
GET/public-api/v1/file/public/products/:productId/:sizeВозвращает публичный предпросмотр товара. Размер должен быть small.png, medium.png или big.png.публичный
GET/public-api/v1/file/protected/:keyВозвращает защищённый файл по ключу хранилища.подписанный URL или files:read
GET/public-api/v1/fontsВозвращает все доступные шрифты.публичный
GET/public-api/v1/currenciesВозвращает все валюты.публичный
POST/public-api/v1/runtime-bindings/sync-from-wordpressСоздаёт или обновляет привязки среды выполнения по сопоставлениям товаров WordPress.любые аутентифицированные учётные данные
PATCH/public-api/v1/runtime-bindings/:idИзменяет привязку среды выполнения.любые аутентифицированные учётные данные
POST/public-api/v1/runtime-bindings/:id/activateАктивирует привязку среды выполнения.любые аутентифицированные учётные данные
POST/public-api/v1/runtime-bindings/:id/deactivateДеактивирует привязку среды выполнения.любые аутентифицированные учётные данные
POST/public-api/v1/wp-connect/exchangeОбменивает код передачи автоматического подключения WordPress на учётные данные API.одноразовый код передачи
GET/public-api/v1/model-generator/catalogВыводит доступные для просмотра товары генератора, конфигурации и ревизии шаблонов.embed:session:create
GET/public-api/v1/model-generator/modelsВыводит модели с дескрипторами, фиксирующими исходные ревизии генератора для импорта.embed:session:create
GET/public-api/v1/model-generator/designer-catalogВозвращает каталог моделей генератора, используемый Designer.embed:session:create
GET/public-api/v1/model-generator/projectsВыводит проекты генератора владельца и глобально доступные проекты.embed:session:create
GET/public-api/v1/model-generator/projects/:projectIdВозвращает последнюю или выбранную ревизию проекта, шаблон и манифест файлов.embed:session:create
GET/public-api/v1/model-generator/projects/:projectId/revisions/:revisionВозвращает последнюю или выбранную ревизию проекта, шаблон и манифест файлов.embed:session:create
GET/public-api/v1/model-generator/projects/:projectId/artifacts/:artifactIdЗагружает артефакт после проверки доступа к его проекту.embed:session:create
GET/public-api/v1/model-generator/configurations/:configurationId/revisions/:revision/templateВозвращает доступный документ шаблона для выбранной ревизии конфигурации.embed:session:create
GET/public-api/v1/model-generator/configurations/:configurationId/revisions/:revision/importВозвращает пакет импорта шаблона с файлами зависимостей.embed:session:create
GET/public-api/v1/model-generator/mannequinsВозвращает оба манекена и дескрипторы их ресурсов.embed:session:create
GET/public-api/v1/model-generator/image-libraries/:kind/assetsВыводит ресурсы библиотеки текстур или фонов с файлами для импорта.embed:session:create
GET/public-api/v1/model-generator/image-libraries/:kind/assets/:assetIdВозвращает один ресурс текстуры или фона с файлами для импорта.embed:session:create
GET/public-api/v1/model-generator/public-files/:keyЗагружает разрешённый файл зависимости генератора.embed:session:create

Заказы покупателей

Конечные точки заказов позволяют внешнему магазину читать настроенные позиции, менять количество, переводить заказ между статусами выполнения и удалять брошенные заказы.

ПараметрОбязательноПодробности
nameнетПоиск по имени дизайна и числовому ID заказа.
category_idнетФильтрация по ID категории товара.
order_statusнетОдин из допустимых статусов заказа.
offsetнетПо умолчанию 0. Должно быть >= 0.
limitнетПо умолчанию для этого контроллера 9, максимум 50.
order_byнетid, created_at или design_name.
directionнетASC или DESC.

Пример запроса (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]
  })
});

Допустимые значения

СтатусОписание
shopping_cartПроцесс корзины; покупатель ещё может изменить конфигурацию.
editableПокупатель по-прежнему может редактировать заказ.
paidЗаказ оплачен и готов к выполнению.
processingЗаказ выполняется.
completedЗаказ выполнен.
cancelledЗаказ отменён.

Пример запроса (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'
});

Пример ответа

{
  "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" }
  }
}

Товары магазина

Конечные точки товаров возвращают дизайны магазина, доступные для встраивания в Viewer, Configurator или Customizer.

ПараметрОбязательноПодробности
nameнетПоиск по имени товара/дизайна.
customizerнетtrue или false.
offsetнетПо умолчанию 0. Должно быть >= 0.
limitнетПо умолчанию 9, максимум 50.
order_byнетid, name или created_at.
directionнетASC или DESC.

Пример запроса (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');

Пример ответа

{
  "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
  }
}

Сеансы встраивания и инициализация среды выполнения

Создайте краткосрочный токен встраивания на сервере, передайте его в iframe или среду выполнения, затем позвольте среде вызвать инициализацию с токеном Bearer.

ПараметрОбязательноПодробности
runtimeBindingIdрекомендуетсяПредпочтительный идентификатор активных привязок среды выполнения.
toolобязательно без runtimeBindingIddesigner | viewer | configurator | customizer | model-generator
toolIdtool: model-generatorПоложительный числовой ID локального проекта генератора, а не его UUID или ID товара WooCommerce.
originдаOrigin страницы со встроенным инструментом, например https://yourstore.com.
designIdодин идентификаторID дизайна Alter Product. Не сочетайте с orderId.
orderIdодин идентификаторID заказа Customizer. Допустим только для customizer.
cartKey + cartModeнетКонтекст корзины только для Customizer. cartMode имеет значение view или edit.

Пример запроса (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 });

Примечания

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
  })
});

Пример ответа

{
  "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-моделей

Эндпоинты импорта генератора поддерживают только чтение при взаимодействии между серверами. Для них требуются стандартные заголовки 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 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 });

Сеанс редактора и локальное хранение

Создайте сеанс редактора с 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 с обычными привязками товара и проверками подписки. Редактор генератора остаётся инструментом продавца. Ссылки в заказах сохраняют проект и ревизию, поэтому последующие правки не изменяют прошлые заказы автоматически.

Каталог ресурсов

Каталог ресурсов предоставляет исходные ресурсы товаров, фоны, окружения, элементы библиотеки изображений, шаблоны дизайна и ресурсы мокапов. Конечные точки списков возвращают компактные описания, а точки подробных данных — манифесты файлов.

ТипОписание
productsИсходные ресурсы товаров, предпросмотры, 3D-модели, описания материалов и текстур.
backgroundsСтатические фоны Viewer.
environmentsКарты окружения и изображения предпросмотра.
image_libraryРесурсы библиотеки изображений, включая графику конкретного магазина.
design_templatesПредпросмотры шаблонов дизайна и ссылки на файлы слоёв. Поддерживает фильтр product_id.
mockupsРесурсы генератора мокапов, фоны и карты наложения. Поддерживает фильтр product_id.

Пример запроса (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();

Пример ответа

{
  "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
}

Импорт дизайнов

Импорт дизайнов предоставляет дизайны, хранящиеся в Alter, и их файлы для внешнего производства или миграции. API проверяет право использования тарифа Business.

ПараметрОбязательноПодробности
searchнетПоиск по названию или ID дизайна.
offsetнетПо умолчанию 0.
limitнетПо умолчанию 20, максимум 100.

Пример запроса (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();

Пример ответа

{
  "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
}

Файлы, шрифты и валюты

Публичные файлы предпросмотра доступны напрямую в браузере. Защищённые файлы требуют подписанного URL или учётных данных API с правом files:read. Шрифты и валюты доступны через публичные конечные точки чтения.

Конечная точкаДоступПодробности
/file/public/products/:productId/small.pngпубличныйМалый предпросмотр товара.
/file/public/products/:productId/medium.pngпубличныйСредний предпросмотр товара.
/file/public/products/:productId/big.pngпубличныйБольшой предпросмотр товара.
/file/protected/:keyподписанный URL или files:readЗащищённый файл объектного хранилища.
/fontsпубличныйМассив записей шрифтов.
/currenciesпубличныйМассив записей валют.

Пример запроса (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());

Пример ответа

[
  {
    "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
  }
]

Привязки среды выполнения

Привязки среды выполнения связывают товары внешних магазинов с дизайнами Alter Product и типами инструментов. Они преимущественно используются в интеграциях WordPress/WooCommerce и расширенных серверных системах магазинов.

ПараметрОбязательноПодробности
designIdнетID дизайна Alter Product, принадлежащего магазину.
externalProductIdда, для синхронизацииID внешнего товара, например ID товара WooCommerce.
runtimeTypeда, для синхронизацииviewer, configurator или customizer.
statusнетdraft, active, inactive, archived или legacy_active.
legacyStorefrontProductIdнетНеобязательный ID прежнего сопоставления.
legacyBindingMetaнетНеобязательные метаданные JSON, например manifestHash.

Пример запроса (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'
          }
        }
      }
    ]
  })
});

Пример ответа

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

Обмен данными подключения WordPress

Конечная точка обмена подключения WordPress принимает одноразовый код передачи и возвращает учётные данные API плагину. Она не предназначена для общего создания учётных данных.

Пример запроса (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();

Пример ответа

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

Ошибки и ограничения частоты запросов

Большинство ошибок контроллеров нормализуется в ответ code. Промежуточные обработчики аутентификации и ограничители частоты могут вместо этого возвращать ответ error.

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

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

{
  "error": "Too Many Requests"
}
ТипЛимитПериод
Глобальный600 запросов60 секунд
GET /auth/check60 запросов60 секунд
Чтение заказов/товаров300 запросов60 секунд
Запись заказов/сеансы встраивания/привязки среды выполнения120 запросов60 секунд
Чтение ресурсов/импортов дизайнов180 запросов60 секунд
Шрифты300 запросов60 секунд
Обмен данными подключения WP30 запросов60 секунд
GET /model-generator/*600 запросов60 секунд