Integración de la API pública de Alter Product

La API pública está diseñada para integraciones de servidor a servidor con tiendas, backends de comercio electrónico, plugins de WordPress/WooCommerce y procesos externos de producción.

Autenticación y URL base

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

Crea las credenciales API en el panel de ajustes de comercio electrónico. Access Token se muestra una sola vez, así que guárdalo inmediatamente en el almacén de secretos de tu backend.

Guarda Access Key y Access Token en tu servidor. Los endpoints autenticados rechazan llamadas desde el navegador que incluyan cabeceras Origin o Referer.

Las credenciales pueden tener ámbitos limitados. Usa GET /auth/check para verificar la tienda activa, las funciones del plan y los ámbitos devueltos para la credencial.

x-alter-access-key: YOUR_API_KEY
x-alter-access-token: YOUR_API_TOKEN
ParámetroObligatorioDetalles
x-alter-access-keyIdentificador público de la credencial.
x-alter-access-tokenToken secreto asociado a la clave de acceso.
x-alter-client-fingerprintnoIdentificador estable opcional para limitar las solicitudes de sesiones de integración.
Authorizationsolo en ejecuciónToken Bearer devuelto por POST /embed/session y utilizado por /runtime/bootstrap.

Prueba de conexión

Usa el endpoint de comprobación de autenticación antes de activar la sincronización o las funciones de integración en producción.

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

Ejemplo de solicitud (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);

Ejemplo de respuesta

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

Los demás ejemplos utilizan la función auxiliar siguiente. Usa fetch estándar y puede ejecutarse en Node.js 18+ o en cualquier entorno de servidor que proporcione 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;
}

Resumen de endpoints

La tabla siguiente refleja las rutas públicas montadas en backend-public-api/app.js. Las rutas se muestran con el prefijo del proxy público utilizado por las integraciones externas.

MétodoEndpointDescripciónAcceso
GET/public-api/healthzComprobación del estado del servicio.público
GET/public-api/v1/auth/checkValida las credenciales y devuelve la tienda, los ámbitos y las funciones del plan.cualquier credencial autenticada
GET/public-api/v1/customer-ordersDevuelve una lista paginada y filtrable de pedidos de clientes.orders:read
GET/public-api/v1/customer-orders/:idDevuelve un pedido de cliente con los artículos de producto configurados.orders:read
POST/public-api/v1/customer-orders/batchDevuelve hasta 100 pedidos por ID.orders:read
PATCH/public-api/v1/customer-orders/:id/statusActualiza el estado del pedido.orders:write
PATCH/public-api/v1/customer-orders/:orderId/quantityActualiza las cantidades de las líneas seleccionadas del pedido.orders:write
PATCH/public-api/v1/customer-orders/:orderId/quantity/allEstablece una cantidad para todos los artículos de un pedido.orders:write
DELETE/public-api/v1/customer-orders/:idElimina un pedido de cliente que pertenece al propietario de la tienda.orders:write
GET/public-api/v1/productsDevuelve productos/diseños de la tienda con disponibilidad de integración y URL multimedia.products:read
GET/public-api/v1/products/:idDevuelve un producto/diseño de la tienda.products:read
POST/public-api/v1/embed/sessionEmite un JWT de corta duración para las herramientas integradas, incluido el generador de modelos.embed:session:create
GET/public-api/v1/runtime/bootstrapResuelve el contexto de ejecución a partir de un JWT de integración.token de integración Bearer
GET/public-api/v1/assetsLista los elementos del catálogo de recursos del tipo solicitado.cualquier credencial autenticada
GET/public-api/v1/assets/:type/:assetIdDevuelve un manifiesto del recurso con las funciones de archivo descargables.cualquier credencial autenticada
GET/public-api/v1/assets/:type/:assetId/files/:roleDescarga un archivo de recurso según su función.cualquier credencial autenticada
GET/public-api/v1/design-importsLista los diseños importables alojados en Alter.credencial autenticada, se requiere plan Business
GET/public-api/v1/design-imports/:idDevuelve la carga útil de importación de un diseño y los descriptores de archivos.credencial autenticada, se requiere plan Business
GET/public-api/v1/design-imports/:id/files/:fileIdDescarga un archivo a partir del descriptor de importación de un diseño.credencial autenticada, se requiere plan Business
GET/public-api/v1/file/public/products/:productId/:sizeDevuelve una vista previa pública del producto. El tamaño debe ser small.png, medium.png o big.png.público
GET/public-api/v1/file/protected/:keyDevuelve un archivo protegido mediante su clave de almacenamiento.URL firmada o files:read
GET/public-api/v1/fontsDevuelve todas las fuentes disponibles.público
GET/public-api/v1/currenciesDevuelve todas las monedas.público
POST/public-api/v1/runtime-bindings/sync-from-wordpressCrea o actualiza vinculaciones de herramientas a partir de las correspondencias de productos de WordPress.cualquier credencial autenticada
PATCH/public-api/v1/runtime-bindings/:idModifica una vinculación de herramienta.cualquier credencial autenticada
POST/public-api/v1/runtime-bindings/:id/activateActiva una vinculación de herramienta.cualquier credencial autenticada
POST/public-api/v1/runtime-bindings/:id/deactivateDesactiva una vinculación de herramienta.cualquier credencial autenticada
POST/public-api/v1/wp-connect/exchangeIntercambia un código de transferencia de conexión automática de WordPress por credenciales API.código de transferencia de un solo uso
GET/public-api/v1/model-generator/catalogLista los productos del generador, las configuraciones y las revisiones de plantillas visibles.embed:session:create
GET/public-api/v1/model-generator/modelsLista modelos con descriptores de fuentes del generador fijados a revisiones concretas para su importación.embed:session:create
GET/public-api/v1/model-generator/designer-catalogDevuelve el catálogo de modelos del generador utilizado por Designer.embed:session:create
GET/public-api/v1/model-generator/projectsLista los proyectos del generador del propietario y los disponibles globalmente.embed:session:create
GET/public-api/v1/model-generator/projects/:projectIdDevuelve la revisión más reciente o seleccionada del proyecto, la plantilla y el manifiesto de archivos.embed:session:create
GET/public-api/v1/model-generator/projects/:projectId/revisions/:revisionDevuelve la revisión más reciente o seleccionada del proyecto, la plantilla y el manifiesto de archivos.embed:session:create
GET/public-api/v1/model-generator/projects/:projectId/artifacts/:artifactIdDescarga un artefacto tras comprobar el acceso a su proyecto.embed:session:create
GET/public-api/v1/model-generator/configurations/:configurationId/revisions/:revision/templateDevuelve un documento de plantilla accesible para la revisión de configuración seleccionada.embed:session:create
GET/public-api/v1/model-generator/configurations/:configurationId/revisions/:revision/importDevuelve el paquete de importación de la plantilla con los archivos de dependencias.embed:session:create
GET/public-api/v1/model-generator/mannequinsDevuelve ambos maniquíes y los descriptores de sus recursos.embed:session:create
GET/public-api/v1/model-generator/image-libraries/:kind/assetsLista los recursos de las bibliotecas de texturas o fondos con archivos importables.embed:session:create
GET/public-api/v1/model-generator/image-libraries/:kind/assets/:assetIdDevuelve un recurso de textura o fondo con sus archivos importables.embed:session:create
GET/public-api/v1/model-generator/public-files/:keyDescarga un archivo de dependencia permitido del generador.embed:session:create

Pedidos de clientes

Los endpoints de pedidos de clientes permiten a una tienda externa leer las líneas configuradas, actualizar cantidades, cambiar los estados de tramitación y eliminar pedidos abandonados.

ParámetroObligatorioDetalles
namenoBusca por nombre del diseño e ID numérico del pedido.
category_idnoFiltra por ID de categoría del producto.
order_statusnoUno de los estados de pedido permitidos.
offsetnoPredeterminado: 0. Debe ser >= 0.
limitnoPredeterminado: 9 para este controlador; máximo: 50.
order_bynoid, created_at o design_name.
directionnoASC o DESC.

Ejemplo de solicitud (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]
  })
});

Valores permitidos

EstadoDescripción
shopping_cartFlujo del carrito; el cliente todavía puede editar la configuración.
editableEl cliente puede seguir editando el pedido.
paidEl pedido está pagado y listo para su tramitación.
processingEl pedido está en tramitación.
completedEl pedido se ha completado.
cancelledEl pedido se ha cancelado.

Ejemplo de solicitud (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'
});

Ejemplo de respuesta

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

Productos de la tienda

Los endpoints de productos devuelven diseños de la tienda que pueden integrarse como Viewer, Configurator o Customizer.

ParámetroObligatorioDetalles
namenoBusca por nombre del producto/diseño.
customizernotrue o false.
offsetnoPredeterminado: 0. Debe ser >= 0.
limitnoPredeterminado: 9; máximo: 50.
order_bynoid, name o created_at.
directionnoASC o DESC.

Ejemplo de solicitud (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');

Ejemplo de respuesta

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

Sesiones de integración e inicialización del entorno de ejecución

Crea un token de integración de corta duración desde tu servidor, pásalo al iframe o entorno de ejecución y permite que este llame a bootstrap con un token Bearer.

ParámetroObligatorioDetalles
runtimeBindingIdrecomendadoIdentificador preferido para vinculaciones activas de herramientas.
toolobligatorio sin runtimeBindingIddesigner | viewer | configurator | customizer | model-generator
toolIdtool: model-generatorID numérico positivo del proyecto local del generador, no su UUID ni el ID del producto WooCommerce.
originOrigen donde se muestra la integración, por ejemplo, https://yourstore.com.
designIdun identificadorID de diseño de Alter Product. No combinar con orderId.
orderIdun identificadorID de pedido de Customizer. Solo válido para customizer.
cartKey + cartModenoContexto de carrito exclusivo de Customizer. cartMode es view o edit.

Ejemplo de solicitud (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 });

Notas

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

Ejemplo de respuesta

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

Generador de modelos 3D

Los endpoints de importación del generador solo admiten solicitudes de lectura entre servidores. Requieren las cabeceras API habituales, el permiso embed:session:create y un plan activo. La autorización de importación no crea una sesión del editor ni consume su cuota mensual. La apertura del editor utiliza el mismo contador monthlyEmbedTokenLimit que las demás herramientas integradas.

Buscar e importar modelos con generador

Utiliza /model-generator/models para listar los modelos disponibles con generador. El descriptor generator fija projectId, revision, configurationId, templateRevision, productId y productModel3dId. Sigue su importPath para obtener exactamente esa revisión de origen. Los manifiestos de recursos de producto también exponen generators y el descriptor generator de cada modelo. Las plantillas se pueden importar por separado según su configuración y revisión.

Filtros de los catálogos

EndpointDetalles
/model-generator/modelsLista de modelos: name (o q), categoryId, scope (all, own, global), limit (1–50) y offset.
/model-generator/catalogCatálogo de plantillas: generatorType, productId, audience, q, templateKey, configurationId, limit y offset.
/model-generator/projectsLista de proyectos: configurationId, q, scope (all, own, global), limit y offset. El proxy público establece scope en all de forma predeterminada.
/model-generator/image-libraries/:kind/assetsBibliotecas de texturas y fondos: kind es texture o background; q, category y mapType filtran los recursos disponibles.

La importación de un proyecto contiene document, revision, template y un manifiesto files. Cada archivo proporciona un path bajo /v1/model-generator/; antepón /public-api al descargarlo desde Alter Product. Copia los archivos necesarios a tu propio almacenamiento y sustituye las referencias de origen por referencias locales. Importa maniquíes y bibliotecas de texturas mediante sus endpoints de catálogo; public-files se limita a las rutas de recursos permitidas, y las plantillas deben superar las comprobaciones de acceso de su configuración y revisión.

Ejemplo de solicitud (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 });

Sesión del editor y almacenamiento local

Crea la sesión del editor con tool: model-generator, un toolId numérico positivo que identifique el proyecto local del generador (no su UUID ni el ID del producto WooCommerce) y el origen permitido de la tienda. No envíes designId, orderId, runtimeBindingId ni campos del carrito para esta herramienta. El UUID del proyecto del generador es un identificador independiente. Transmite el token recibido mediante el intercambio inicial del iframe; la inicialización del runtime devuelve el contexto del generador con 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);

Ejemplo de respuesta

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

Mensajes del iframe utilizados por el puente de WordPress

El plugin de WordPress aloja el puente de almacenamiento y comprueba los permisos de administrador o gestor de WooCommerce. Valida el origen del iframe, la ventana de origen, el nonce, el identificador de solicitud y las rutas de proyecto permitidas. El puente envía las lecturas y escrituras locales a /wp-json/alter-wc/v1/model-generator. Las credenciales API permanecen en el servidor. Una integración personalizada debe implementar una gestión autenticada del almacenamiento equivalente; la API pública del generador no guarda proyectos en Alter Product.

TipoDescripción
ALTER_CHILD_HELLO / ALTER_PARENT_ACKEl iframe inicia el intercambio con un nonce; la página principal confirma ese mismo nonce.
ALTER_CUSTOMIZER_INIT_SESSION / ALTER_CUSTOMIZER_SESSION_READYEl iframe solicita una sesión de edición de model-generator; la página principal devuelve el token autorizado.
ALTER_MODEL_GENERATOR_REQUESTEl iframe envía requestId, nonce y request con method, path, data y responseType.
ALTER_MODEL_GENERATOR_RESPONSELa página principal responde con los mismos requestId y nonce, además de status, data, headers y, si procede, 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.

Al guardar se envían expectedRevision, templateRevision, document y las referencias a los artefactos. Se crea una revisión inmutable; un valor expectedRevision desactualizado devuelve HTTP 409. WordPress almacena los metadatos en su base de datos y los archivos en su directorio uploads. El JSON se minifica y se comprime con gzip cuando la compresión reduce su tamaño.

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

Usar el modelo guardado en el diseño publica una revisión guardada completa en un diseño de producto vinculado. Los clientes la ven después mediante el Customizer, Configurator o Viewer existente, con las vinculaciones de producto y las comprobaciones de suscripción habituales. El editor del generador sigue siendo una herramienta para el comerciante. Los enlaces de los pedidos conservan el proyecto y la revisión guardados para que los cambios posteriores no alteren los pedidos anteriores sin aviso.

Catálogo de recursos

El catálogo de recursos ofrece recursos originales de productos, fondos, entornos, elementos de la biblioteca gráfica, plantillas de diseño y recursos de mockups. Los endpoints de listas devuelven descriptores ligeros; los de detalles incluyen manifiestos de archivos.

TipoDescripción
productsRecursos de productos base, vistas previas, modelos 3D y descriptores de materiales y texturas.
backgroundsFondos estáticos de Viewer.
environmentsMapas de entorno e imágenes de vista previa.
image_libraryRecursos de la biblioteca gráfica, incluidos gráficos específicos de la tienda.
design_templatesVistas previas de plantillas de diseño y referencias a archivos de capas. Admite el filtro product_id.
mockupsRecursos del generador de mockups, fondos y mapas de superposición. Admite el filtro product_id.

Ejemplo de solicitud (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();

Ejemplo de respuesta

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

Importaciones de diseños

Las importaciones de diseños proporcionan diseños alojados en Alter y sus archivos para procesos externos de producción o migración. La API comprueba la elegibilidad del plan Business.

ParámetroObligatorioDetalles
searchnoBusca por título o ID del diseño.
offsetnoPredeterminado: 0.
limitnoPredeterminado: 20; máximo: 100.

Ejemplo de solicitud (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();

Ejemplo de respuesta

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

Archivos, fuentes y monedas

Los archivos públicos de vista previa pueden usarse en el navegador. Los archivos protegidos requieren una URL firmada o una credencial API con files:read. Fuentes y monedas son endpoints públicos de lectura.

EndpointAccesoDetalles
/file/public/products/:productId/small.pngpúblicoVista previa pequeña del producto.
/file/public/products/:productId/medium.pngpúblicoVista previa mediana del producto.
/file/public/products/:productId/big.pngpúblicoVista previa grande del producto.
/file/protected/:keyURL firmada o files:readArchivo protegido del almacenamiento de objetos.
/fontspúblicoArray de registros de fuentes.
/currenciespúblicoArray de registros de monedas.

Ejemplo de solicitud (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());

Ejemplo de respuesta

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

Vinculaciones de herramientas

Las vinculaciones de herramientas conectan productos de comercio electrónico externos con diseños de Alter Product y tipos de herramientas. Se usan principalmente en integraciones de WordPress/WooCommerce y backends avanzados de tiendas.

ParámetroObligatorioDetalles
designIdnoID de diseño de Alter Product que pertenece a la tienda.
externalProductIdsí para sincronizaciónID de producto externo, por ejemplo, un ID de producto de WooCommerce.
runtimeTypesí para sincronizaciónviewer, configurator o customizer.
statusnodraft, active, inactive, archived o legacy_active.
legacyStorefrontProductIdnoID opcional de correspondencia heredada.
legacyBindingMetanoMetadatos JSON opcionales, por ejemplo, manifestHash.

Ejemplo de solicitud (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'
          }
        }
      }
    ]
  })
});

Ejemplo de respuesta

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

Intercambio de conexión de WordPress

El endpoint de intercambio de conexión de WordPress consume un código de transferencia de un solo uso y devuelve credenciales API al plugin. No es un endpoint de creación de credenciales de uso general.

Ejemplo de solicitud (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();

Ejemplo de respuesta

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

Errores y límites de solicitudes

La mayoría de los errores de controladores se normalizan como una respuesta code. El middleware de autenticación y los limitadores de solicitudes pueden devolver una respuesta error en su lugar.

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

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

{
  "error": "Too Many Requests"
}
TipoLímiteIntervalo
Global600 solicitudes60 segundos
GET /auth/check60 solicitudes60 segundos
Lectura de pedidos/productos300 solicitudes60 segundos
Escritura de pedidos/sesiones de integración/vinculaciones de herramientas120 solicitudes60 segundos
Lectura de recursos/importaciones de diseños180 solicitudes60 segundos
Fuentes300 solicitudes60 segundos
Intercambio de conexión de WP30 solicitudes60 segundos
GET /model-generator/*600 solicitudes60 segundos