Integração da Public API do Alter Product

A Public API foi criada para integrações entre servidores com lojas, backends de e-commerce, plugins WordPress/WooCommerce e fluxos de produção externos.

Autenticação e URL base

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

Crie credenciais de API no painel de configurações de e-commerce. O Access Token é exibido uma única vez; por isso, guarde-o imediatamente no armazenamento de segredos do seu backend.

Mantenha a Access Key e o Access Token no seu servidor. Os endpoints autenticados rejeitam chamadas originadas no navegador que incluam os cabeçalhos Origin ou Referer.

As credenciais podem ter escopos limitados. Use GET /auth/check para verificar a loja ativa, os recursos do plano e os escopos retornados para a credencial.

x-alter-access-key: YOUR_API_KEY
x-alter-access-token: YOUR_API_TOKEN
ParâmetroObrigatórioDetalhes
x-alter-access-keysimIdentificador público da credencial.
x-alter-access-tokensimToken secreto associado à chave de acesso.
x-alter-client-fingerprintnãoIdentificador estável opcional para limitar solicitações de sessões de incorporação.
Authorizationsomente runtimeToken Bearer retornado por POST /embed/session, usado por /runtime/bootstrap.

Teste de conexão

Use o endpoint de verificação de autenticação antes de ativar a sincronização ou os recursos de incorporação numa integração em produção.

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

Exemplo de solicitação (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);

Exemplo de resposta

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

A função auxiliar abaixo é usada nos demais exemplos. Ela usa fetch simples e pode ser executada no Node.js 18+ ou em qualquer ambiente de servidor que ofereça 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;
}

Visão geral dos endpoints

A tabela abaixo reflete as rotas públicas montadas em backend-public-api/app.js. Os caminhos são exibidos com o prefixo de proxy público usado pelas integrações externas.

MétodoEndpointDescriçãoAcesso
GET/public-api/healthzVerificação de disponibilidade do serviço.público
GET/public-api/v1/auth/checkValida as credenciais e retorna a loja, os escopos e os recursos do plano.qualquer credencial autenticada
GET/public-api/v1/customer-ordersRetorna uma lista paginada e filtrável de pedidos de clientes.orders:read
GET/public-api/v1/customer-orders/:idRetorna um pedido de cliente individual com os itens de produto configurados.orders:read
POST/public-api/v1/customer-orders/batchRetorna até 100 pedidos por ID.orders:read
PATCH/public-api/v1/customer-orders/:id/statusAtualiza o estado do pedido.orders:write
PATCH/public-api/v1/customer-orders/:orderId/quantityAtualiza as quantidades dos itens selecionados do pedido.orders:write
PATCH/public-api/v1/customer-orders/:orderId/quantity/allDefine uma única quantidade para todos os itens de um pedido.orders:write
DELETE/public-api/v1/customer-orders/:idElimina um pedido de cliente pertencente ao proprietário da loja.orders:write
GET/public-api/v1/productsRetorna produtos/designs da loja com disponibilidade de incorporação e URLs de multimédia.products:read
GET/public-api/v1/products/:idRetorna um produto/design da loja.products:read
POST/public-api/v1/embed/sessionEmite um JWT de curta duração para ferramentas incorporadas, incluindo o gerador de modelos.embed:session:create
GET/public-api/v1/runtime/bootstrapResolve o contexto do runtime a partir de um JWT de incorporação.token de incorporação Bearer
GET/public-api/v1/assetsLista os itens do catálogo de recursos do tipo solicitado.qualquer credencial autenticada
GET/public-api/v1/assets/:type/:assetIdRetorna um manifesto de recurso com as funções dos ficheiros disponíveis para download.qualquer credencial autenticada
GET/public-api/v1/assets/:type/:assetId/files/:roleDescarrega um ficheiro de recurso pela função.qualquer credencial autenticada
GET/public-api/v1/design-importsLista os designs alojados no Alter disponíveis para importação.credencial autenticada, plano Business obrigatório
GET/public-api/v1/design-imports/:idRetorna um payload de importação de design e descritores de ficheiros.credencial autenticada, plano Business obrigatório
GET/public-api/v1/design-imports/:id/files/:fileIdDescarrega um ficheiro a partir de um descritor de importação de design.credencial autenticada, plano Business obrigatório
GET/public-api/v1/file/public/products/:productId/:sizeRetorna uma pré-visualização pública de produto. O tamanho deve ser small.png, medium.png ou big.png.público
GET/public-api/v1/file/protected/:keyRetorna um ficheiro protegido pela chave de armazenamento.URL assinada ou files:read
GET/public-api/v1/fontsRetorna todas as fontes disponíveis.público
GET/public-api/v1/currenciesRetorna todas as moedas.público
POST/public-api/v1/runtime-bindings/sync-from-wordpressCria ou atualiza associações de runtime a partir das associações de produtos do WordPress.qualquer credencial autenticada
PATCH/public-api/v1/runtime-bindings/:idAltera parcialmente uma associação de runtime.qualquer credencial autenticada
POST/public-api/v1/runtime-bindings/:id/activateAtiva uma associação de runtime.qualquer credencial autenticada
POST/public-api/v1/runtime-bindings/:id/deactivateDesativa uma associação de runtime.qualquer credencial autenticada
POST/public-api/v1/wp-connect/exchangeTroca um código de transferência da conexão automática do WordPress por credenciais de API.código de transferência de uso único
GET/public-api/v1/model-generator/catalogLista os produtos do gerador, as configurações e as revisões de templates visíveis.embed:session:create
GET/public-api/v1/model-generator/modelsLista modelos com descritores de fontes do gerador fixados em revisões específicas para importação.embed:session:create
GET/public-api/v1/model-generator/designer-catalogDevolve o catálogo de modelos do gerador utilizado pelo Designer.embed:session:create
GET/public-api/v1/model-generator/projectsLista os projetos do gerador do proprietário e os disponíveis globalmente.embed:session:create
GET/public-api/v1/model-generator/projects/:projectIdDevolve a revisão mais recente ou selecionada do projeto, o template e o manifesto de ficheiros.embed:session:create
GET/public-api/v1/model-generator/projects/:projectId/revisions/:revisionDevolve a revisão mais recente ou selecionada do projeto, o template e o manifesto de ficheiros.embed:session:create
GET/public-api/v1/model-generator/projects/:projectId/artifacts/:artifactIdDescarrega um artefacto após verificar o acesso ao respetivo projeto.embed:session:create
GET/public-api/v1/model-generator/configurations/:configurationId/revisions/:revision/templateDevolve um documento de template acessível para a revisão de configuração selecionada.embed:session:create
GET/public-api/v1/model-generator/configurations/:configurationId/revisions/:revision/importDevolve o pacote de importação do template com os ficheiros de dependências.embed:session:create
GET/public-api/v1/model-generator/mannequinsDevolve ambos os manequins e os descritores dos respetivos recursos.embed:session:create
GET/public-api/v1/model-generator/image-libraries/:kind/assetsLista os recursos das bibliotecas de texturas ou fundos com ficheiros importáveis.embed:session:create
GET/public-api/v1/model-generator/image-libraries/:kind/assets/:assetIdDevolve um recurso de textura ou fundo com os respetivos ficheiros importáveis.embed:session:create
GET/public-api/v1/model-generator/public-files/:keyDescarrega um ficheiro de dependência permitido do gerador.embed:session:create

Pedidos de clientes

Os endpoints de pedidos de clientes permitem que uma loja externa leia os itens configurados, atualize quantidades, mova um pedido entre estados de processamento e remova pedidos abandonados.

ParâmetroObrigatórioDetalhes
namenãoPesquisa pelo nome do design e pelo ID numérico do pedido.
category_idnãoFiltra pelo ID da categoria do produto.
order_statusnãoUm dos estados de pedido permitidos.
offsetnãoValor predefinido: 0. Deve ser >= 0.
limitnãoValor predefinido: 9 neste controlador, máximo 50.
order_bynãoid, created_at ou design_name.
directionnãoASC ou DESC.

Exemplo de solicitação (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

EstadoDescrição
shopping_cartFluxo do carrinho; o cliente ainda pode editar a configuração.
editableO pedido continua editável pelo cliente.
paidO pedido está pago e pronto para processamento.
processingO pedido está em processamento.
completedO pedido foi concluído.
cancelledO pedido foi cancelado.

Exemplo de solicitação (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'
});

Exemplo de resposta

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

Produtos da loja

Os endpoints de produtos retornam designs da loja que podem ser incorporados como experiências de Viewer, Configurator ou Customizer.

ParâmetroObrigatórioDetalhes
namenãoPesquisa pelo nome do produto/design.
customizernãotrue ou false.
offsetnãoValor predefinido: 0. Deve ser >= 0.
limitnãoValor predefinido: 9, máximo 50.
order_bynãoid, name ou created_at.
directionnãoASC ou DESC.

Exemplo de solicitação (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');

Exemplo de resposta

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

Sessões de incorporação e inicialização do runtime

Crie um token de incorporação de curta duração no seu servidor, passe-o ao iframe/runtime e deixe o runtime chamar bootstrap com um token Bearer.

ParâmetroObrigatórioDetalhes
runtimeBindingIdrecomendadoIdentificador preferencial para associações de runtime ativas.
toolobrigatório sem runtimeBindingIddesigner | viewer | configurator | customizer | model-generator
toolIdtool: model-generatorID numérico positivo do projeto local do gerador, não o seu UUID nem o ID do produto WooCommerce.
originsimOrigem em que a incorporação é renderizada, por exemplo, https://yourstore.com.
designIdum identificadorID de design do Alter Product. Não combine com orderId.
orderIdum identificadorID de pedido do Customizer. Válido somente para customizer.
cartKey + cartModenãoContexto do carrinho exclusivo do Customizer. cartMode é view ou edit.

Exemplo de solicitação (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
  })
});

Exemplo de resposta

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

Gerador de modelos 3D

Os endpoints de importação do gerador aceitam apenas pedidos de leitura entre servidores. Exigem os cabeçalhos API habituais, o âmbito embed:session:create e um plano ativo. A autorização de importação não cria uma sessão do editor nem consome a respetiva quota mensal. A abertura do editor utiliza o mesmo contador monthlyEmbedTokenLimit das restantes ferramentas incorporadas.

Encontrar e importar modelos com gerador

Utilize /model-generator/models para listar os modelos disponíveis com geradores. O descritor generator fixa projectId, revision, configurationId, templateRevision, productId e productModel3dId. Siga o respetivo importPath para obter exatamente essa revisão de origem. Os manifestos de recursos de produto também disponibilizam generators e o descritor generator de cada modelo. Os templates podem ser importados separadamente por configuração e revisão.

Filtros dos catálogos

EndpointDetalhes
/model-generator/modelsLista de modelos: name (ou q), categoryId, scope (all, own, global), limit (1–50) e offset.
/model-generator/catalogCatálogo de templates: generatorType, productId, audience, q, templateKey, configurationId, limit e offset.
/model-generator/projectsLista de projetos: configurationId, q, scope (all, own, global), limit e offset. O proxy público define scope como all por predefinição.
/model-generator/image-libraries/:kind/assetsBibliotecas de texturas e fundos: kind é texture ou background; q, category e mapType filtram os recursos disponíveis.

A importação de um projeto contém document, revision, template e um manifesto files. Cada ficheiro fornece um path em /v1/model-generator/; acrescente /public-api antes desse caminho ao descarregá-lo do Alter Product. Copie os ficheiros necessários para o seu próprio armazenamento e substitua as referências de origem por referências locais. Importe manequins e bibliotecas de texturas através dos respetivos endpoints de catálogo; public-files está limitado aos caminhos de recursos permitidos, e os templates têm de passar pelas verificações de acesso da respetiva configuração e revisão.

Exemplo de solicitação (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 });

Sessão do editor e armazenamento local

Crie a sessão do editor com tool: model-generator, um toolId numérico positivo que identifique o projeto local do gerador (não o seu UUID nem o ID do produto WooCommerce) e a origem permitida da loja. Não envie designId, orderId, runtimeBindingId nem campos do carrinho para esta ferramenta. O UUID do projeto do gerador é um identificador separado. Transmita o token recebido através do handshake do iframe; o bootstrap do runtime devolve o contexto do gerador com 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);

Exemplo de resposta

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

Mensagens iframe utilizadas pela ponte WordPress

O plugin WordPress aloja a ponte de armazenamento e verifica as permissões de administrador ou gestor WooCommerce. Valida a origem do iframe, a janela de origem, o nonce, o ID do pedido e os caminhos de projeto permitidos. A ponte envia as leituras e escritas locais para /wp-json/alter-wc/v1/model-generator. As credenciais API permanecem no servidor. Uma integração personalizada tem de implementar um tratamento autenticado do armazenamento equivalente; a API pública do gerador não guarda projetos no Alter Product.

TipoDescrição
ALTER_CHILD_HELLO / ALTER_PARENT_ACKO iframe inicia o handshake com um nonce; a página principal confirma esse mesmo nonce.
ALTER_CUSTOMIZER_INIT_SESSION / ALTER_CUSTOMIZER_SESSION_READYO iframe pede uma sessão de edição model-generator; a página principal devolve o token autorizado.
ALTER_MODEL_GENERATOR_REQUESTO iframe envia requestId, nonce e request com method, path, data e responseType.
ALTER_MODEL_GENERATOR_RESPONSEA página principal responde com os mesmos requestId e nonce, além de status, data, headers e, se existir, 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.

Ao guardar, são enviados expectedRevision, templateRevision, document e as referências aos artefactos. É criada uma revisão imutável; um valor expectedRevision desatualizado devolve HTTP 409. O WordPress armazena os metadados na sua base de dados e os ficheiros no diretório uploads. O JSON é minificado e comprimido com gzip quando a compressão reduz o seu tamanho.

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

Utilizar modelo guardado no design publica uma revisão guardada completa num design de produto associado. Os clientes passam a vê-la através do Customizer, Configurator ou Viewer existente, com as associações de produto e as verificações de subscrição habituais. O editor do gerador continua a ser uma ferramenta do comerciante. As ligações das encomendas preservam o projeto e a revisão guardados para que as edições posteriores não alterem silenciosamente as encomendas anteriores.

Catálogo de recursos

O catálogo de recursos disponibiliza os recursos originais dos produtos, fundos, ambientes, itens da biblioteca de imagens, modelos de design e recursos de mockup. Os endpoints de listagem retornam descritores leves; os endpoints de detalhes incluem manifestos de ficheiros.

TipoDescrição
productsRecursos base do produto, pré-visualizações, modelos 3D e descritores de materiais e texturas.
backgroundsFundos estáticos do Viewer.
environmentsMapas de ambiente e imagens de pré-visualização.
image_libraryRecursos da biblioteca de imagens, incluindo imagens restritas à loja.
design_templatesPré-visualizações de modelos de design e referências a ficheiros de camadas. Aceita o filtro product_id.
mockupsRecursos do gerador de mockups, fundos e mapas de sobreposição. Aceita o filtro product_id.

Exemplo de solicitação (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();

Exemplo de resposta

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

Importações de designs

As importações de designs disponibilizam designs alojados no Alter e seus ficheiros para fluxos externos de produção ou migração. A API verifica a elegibilidade do plano Business.

ParâmetroObrigatórioDetalhes
searchnãoPesquisa pelo título ou ID do design.
offsetnãoValor predefinido: 0.
limitnãoValor predefinido: 20, máximo 100.

Exemplo de solicitação (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();

Exemplo de resposta

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

Ficheiros, fontes e moedas

Os ficheiros públicos de pré-visualização são compatíveis com navegadores. Os ficheiros protegidos exigem um URL assinado ou uma credencial de API com files:read. Fontes e moedas são endpoints públicos de leitura.

EndpointAcessoDetalhes
/file/public/products/:productId/small.pngpúblicoPré-visualização pequena do produto.
/file/public/products/:productId/medium.pngpúblicoPré-visualização média do produto.
/file/public/products/:productId/big.pngpúblicoPré-visualização grande do produto.
/file/protected/:keyURL assinada ou files:readFicheiro protegido no armazenamento de objetos.
/fontspúblicoArray de registos de fontes.
/currenciespúblicoArray de registos de moedas.

Exemplo de solicitação (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());

Exemplo de resposta

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

Associações de runtime

As associações de runtime conectam produtos de e-commerce externos a designs e tipos de runtime do Alter Product. São usadas principalmente por integrações WordPress/WooCommerce e backends avançados de lojas.

ParâmetroObrigatórioDetalhes
designIdnãoID do design do Alter Product pertencente à loja.
externalProductIdsim para sincronizaçãoID do produto externo, por exemplo, um ID de produto do WooCommerce.
runtimeTypesim para sincronizaçãoviewer, configurator ou customizer.
statusnãodraft, active, inactive, archived ou legacy_active.
legacyStorefrontProductIdnãoID opcional da associação legada.
legacyBindingMetanãoMetadados JSON opcionais, por exemplo, manifestHash.

Exemplo de solicitação (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'
          }
        }
      }
    ]
  })
});

Exemplo de resposta

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

Troca de código de conexão do WordPress

O endpoint de troca de conexão do WordPress consome um código de transferência de uso único e retorna credenciais de API ao plugin. Ele não é um endpoint genérico de criação de credenciais.

Exemplo de solicitação (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();

Exemplo de resposta

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

Erros e limites de solicitações

A maioria dos erros dos controladores é normalizada para uma resposta code. O middleware de autenticação e os limitadores de solicitações podem retornar uma resposta error.

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

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

{
  "error": "Too Many Requests"
}
TipoLimiteJanela
Global600 solicitações60 segundos
GET /auth/check60 solicitações60 segundos
Leitura de pedidos/produtos300 solicitações60 segundos
Gravação de pedidos/sessões de incorporação/associações de runtime120 solicitações60 segundos
Leitura de recursos/importações de designs180 solicitações60 segundos
Fontes300 solicitações60 segundos
Troca de conexão do WP30 solicitações60 segundos
GET /model-generator/*600 solicitações60 segundos