Integração via API REST

Endereço da API: https://distsys.com — nos exemplos ele aparece como {{baseUrl}}, a mesma variável da collection do Postman.

Como funciona

A API permite que os sistemas da sua corporação (ERP, PDV, WMS, BI) conversem com a Distsys sem intervenção manual. Os dados são organizados assim:

  • Corporação — a empresa dona da conta. Cada credencial de API pertence a uma corporação e só enxerga os dados dela.
  • Lojas (stores) — as unidades (CNPJs) da corporação. Cada loja conecta as suas contas nos marketplaces.
  • Itens (items) — o cadastro de produtos da corporação, identificado pelo código do seu ERP e compartilhado por todas as lojas.
  • Preço e estoque — são de cada loja: o mesmo item pode ter preço e estoque diferentes em cada unidade.
  • Anúncios (offers) — os anúncios da loja em cada marketplace, importados automaticamente das contas conectadas ou cadastrados pela API, e vinculados aos itens.
  • Vendas (sales) — os pedidos da loja, importados dos marketplaces ou enviados pela API (vendas de outros canais, nota fiscal e andamento da entrega).

Início rápido

  1. Um administrador da corporação entra na Distsys, abre a página da corporação e cria uma credencial de API no card Credenciais de API, escolhendo os escopos (permissões) e, se quiser, as lojas permitidas.
  2. Copie o client_id e o client_secret. O segredo aparece uma única vez.
  3. O seu sistema troca a credencial por um token em POST /oauth2/token.
  4. Use o token no cabeçalho Authorization: Bearer <token> em todas as chamadas a /v1. Ele vale 15 minutos: peça um novo quando expirar.

Collection do Postman

Distsys API v1 — collection com todos os exemplos

Autenticação, lojas, itens, preços e estoques, anúncios e vendas.

Baixar collection
  1. No Postman, clique em Import e escolha o arquivo baixado.
  2. Na aba Variables da collection, preencha clientId e clientSecret (e ajuste baseUrl, se necessário).
  3. Execute 1. Autenticação › Obter token: o token é salvo em accessToken e usado automaticamente pelas demais requisições.
  4. As requisições de criação gravam os ids retornados (storeId, offerId, saleId) para as seguintes. Você também pode rodar a pasta inteira no Runner.

1. Autenticação (OAuth 2.0 Client Credentials)

Envie o client_id e o client_secret em HTTP Basic (recomendado) ou no corpo do formulário. O parâmetro opcional scope pede só parte dos escopos da credencial.

curl -X POST {{baseUrl}}/oauth2/token \
  -u "$CLIENT_ID:$CLIENT_SECRET" \
  -d grant_type=client_credentials
{
  "access_token": "eyJraWQiOi...",
  "token_type": "Bearer",
  "expires_in": 900,
  "scope": "stores:read items:read items:write stock:write"
}

O token é um JWT assinado (RS256). A chave pública está em GET /oauth2/jwks. Se a credencial for revogada, os tokens dela deixam de valer na hora.

Escopos

EscopoPermite
stores:readLer lojas
stores:writeCadastrar e alterar lojas
items:readLer itens, preços e estoques
items:writeCadastrar e alterar itens
offers:readLer anúncios
offers:writeCadastrar e alterar anúncios
prices:writeAtualizar preços por loja
stock:writeAtualizar estoques por loja
sales:readLer vendas
sales:writeCadastrar e alterar vendas

Convenções e erros

  • JSON em UTF-8. Envie Content-Type: application/json nos corpos.
  • Valores monetários com ponto e até 2 casas: 59.90.
  • Datas em ISO-8601 com fuso: 2026-10-22T10:15:30-03:00.
  • Listas paginadas: page (a partir de 0) e size (padrão 100, máximo 500). Resposta: {"data": [...], "page": 0, "size": 100, "total": 250}.
  • POST cria (resposta 201 com o cabeçalho Location); PATCH altera só os campos enviados; PUT em itens cria ou atualiza pelo código.
  • Operações em lote aceitam até 500 entradas e processam cada uma separadamente (succeeded, failed e o erro de cada código).

Erros seguem o formato application/problem+json (RFC 7807) com um code estável:

{
  "status": 403,
  "title": "Forbidden",
  "detail": "O token não tem o escopo items:write.",
  "code": "insufficient_scope"
}
HTTPcodeQuando
400invalid_requestCampo obrigatório ausente ou valor inválido.
401invalid_tokenToken ausente, expirado ou de credencial revogada.
403insufficient_scopeO token não tem o escopo exigido.
403store_restrictedCredencial restrita a lojas tentando cadastrar loja.
404not_foundRecurso inexistente ou de outra corporação/loja não permitida.
409conflictCNPJ, anúncio (externalId) ou pedido já cadastrado.

2. Lojas (stores)

MétodoCaminhoEscopoDescrição
GET/v1/storesstores:readLista as lojas permitidas à credencial.
GET/v1/stores/{storeId}stores:readDetalha uma loja.
POST/v1/storesstores:writeCadastra uma loja na corporação (credenciais sem restrição de lojas).
PATCH/v1/stores/{storeId}stores:writeAltera os campos enviados.
POST {{baseUrl}}/v1/stores
{
  "name": "Loja Centro",
  "taxNumber": "12.345.678/0001-90",
  "zipCode": "01001-000",
  "state": "SP",
  "city": "São Paulo",
  "address": "Praça da Sé, 100",
  "phone": "(11) 3333-4444",
  "stateTaxNumber": "123.456.789.000"
}
201 Created
{
  "id": "6ada1f7f8b57d20833b729ea",
  "name": "Loja Centro",
  "taxNumber": "12.345.678/0001-90",
  "city": "São Paulo",
  "state": "SP",
  "connectedMarketplaces": [],
  "zipCode": "01001-000",
  "address": "Praça da Sé, 100",
  "phone": "(11) 3333-4444",
  "site": null,
  "stateTaxNumber": "123.456.789.000",
  "cityTaxNumber": null
}
A conexão da loja com os marketplaces (Mercado Livre, Amazon, Magalu...) é feita pela tela da loja, pois exige a autorização do vendedor em cada marketplace.

3. Itens (items)

Os itens são da corporação e identificados pelo código do seu ERP ({code}, até 60 caracteres; codifique na URL caracteres especiais).

MétodoCaminhoEscopoDescrição
GET/v1/items?updatedSince=&page=&size=items:readLista os itens (filtro opcional por data de alteração).
GET/v1/items/{code}items:readDetalha um item.
PUT/v1/items/{code}items:writeCadastra ou atualiza o item (idempotente).
POST/v1/items/batchitems:writeCadastra ou atualiza até 500 itens.
PUT {{baseUrl}}/v1/items/CAM-001
{
  "description": "Camiseta básica algodão",
  "ean13": "7891234567895",
  "brand": "Marca X",
  "enabled": true
}
POST {{baseUrl}}/v1/items/batch
{
  "items": [
    { "code": "CAM-002", "description": "Camiseta gola V" },
    { "code": "CAM-003", "description": "Camiseta manga longa", "ean13": "7891234567802" }
  ]
}

200 OK
{ "succeeded": 2, "failed": 0, "results": [ { "code": "CAM-002", "success": true, "error": null }, ... ] }

Dados para criar anúncios (listing)

Para publicar um item nos marketplaces, o cadastro precisa de mais que descrição e EAN: título, descrição completa, imagens, peso e medidas da embalagem, dados fiscais, categoria e ficha técnica. Envie esses dados no objeto listing do PUT /v1/items/{code} (ou de cada item do lote).

  • listing ausente: os dados de anúncio do item são mantidos.
  • Dentro de listing, campo ausente é mantido e campo presente substitui o valor (listas e mapas inteiros; lista vazia limpa; "" limpa um texto; {} limpa um grupo como tax).
  • O GTIN é validado (8, 12, 13 ou 14 dígitos e dígito verificador). Ao enviar gtin, o campo ean13 acompanha quando for EAN-13.
  • Imagens: URLs públicas (https); a primeira sem role vira a principal (MAIN).
PUT {{baseUrl}}/v1/items/PF-N1234
{
  "description": "PAST FREIO DIANT N1234",
  "brand": "Cobreq",
  "listing": {
    "title": "Pastilha de Freio Dianteira Cobreq N-1234 Gol Voyage Fox",
    "longDescription": "Pastilha de freio dianteira em composto cerâmico...",
    "bulletPoints": ["Composto cerâmico", "Baixo ruído"],
    "gtin": "7891234567895",
    "model": "N-1234",
    "manufacturer": "Cobreq",
    "condition": "NEW",
    "originCountry": "BR",
    "categoryId": "6ae4a1c2...",
    "attributes": { "posicao": "Dianteira", "material": "Cerâmica" },
    "images": [
      { "url": "https://cdn.exemplo.com.br/pf-n1234-1.jpg", "role": "MAIN" },
      { "url": "https://cdn.exemplo.com.br/pf-n1234-2.jpg" }
    ],
    "packageDimensions": { "weightKg": 0.8, "heightCm": 6, "widthCm": 12, "lengthCm": 15 },
    "handlingTimeDays": 1,
    "tax": { "ncm": "68132090", "origin": "0", "unit": "UN" },
    "warranty": { "type": "MANUFACTURER", "months": 3 }
  }
}
Campo de listingTipoObservação
title, longDescriptiontextoTítulo (até 255; cortado conforme o marketplace) e descrição completa. Sem título, vale description.
bulletPoints, keywordslista de textosDestaques (até 6) e palavras-chave.
gtin, gtinType, gtinExemptionReasontextoTipo EAN8, EAN13, EAN14 ou UPC (deduzido se ausente); motivo quando não há GTIN.
model, mpn, manufacturertextoModelo, código do fabricante e fabricante.
conditionNEW, USED, REFURBISHEDPadrão NEW.
originCountrytexto (2 letras)ISO 3166-1, ex.: BR.
categoryIdtextoId de GET /v1/categories.
attributesmapa texto → textoFicha técnica com nomes internos (cor, tamanho, voltagem...).
groupCode, variationValuestexto, mapaGrade: código do grupo e os valores desta variação ({"cor": "Azul", "tamanho": "M"}).
images[]{url, role, variationValue}role: MAIN, DETAIL, SWATCH ou SIZE_CHART. Até 20.
videoUrltextoURL do vídeo.
packageDimensions, productDimensions{weightKg, heightCm, widthCm, lengthCm}Embalagem (frete) e produto.
handlingTimeDaysinteiroPrazo de despacho (0 a 90 dias).
tax{ncm, cest, origin, unit, cfopSameState, cfopOtherState}NCM 8 dígitos, origem 0 a 8, CEST 7 dígitos, CFOP 4 dígitos.
warranty{type, months}NONE, SELLER ou MANUFACTURER; meses de 1 a 120.
certifications[]{type, number, fileUrl}INMETRO, ANATEL, ANVISA...
O mapeamento de cada campo para os campos do anúncio em Mercado Livre, Amazon, Magalu, Shopee, Shein, Casas Bahia, TikTok Shop e Temu está na planilha mapeamento-item-marketplaces.xlsx.

Categorias, grupos e o que falta para anunciar

MétodoCaminhoEscopoDescrição
GET/v1/categoriesitems:readCategorias da corporação (cadastradas na tela Categorias e mapeamentos) e a categoria de cada marketplace.
GET/v1/item-groups/{code}items:readGrupo (grade) e os códigos dos itens dele.
PUT/v1/item-groups/{code}items:writeCria ou altera o grupo: title, longDescription, brand, categoryId, variationAxes, images. Campos vazios dos itens herdam do grupo.
GET/v1/stores/{storeId}/items/{code}/listing-readinessitems:readPara cada marketplace: se o item já pode ser anunciado na loja e o que falta.
GET {{baseUrl}}/v1/stores/{storeId}/items/PF-N1234/listing-readiness

200 OK
{
  "data": [
    {
      "marketplace": "mercadolivre",
      "ready": false,
      "missing": [
        { "field": "CATEGORY", "label": "Categoria do marketplace", "detail": "categoria sem equivalente neste marketplace",
          "source": "Item.categoryId → Category.marketplaces" },
        { "field": "LISTING_TYPE", "label": "Tipo de anúncio", "detail": "configuração da loja", "source": "ListingSettings.listingTypeId" }
      ],
      "recommended": [],
      "warnings": ["Título com 66 caracteres: o limite é 60. ..."]
    },
    ...
  ]
}
A publicação dos anúncios nos marketplaces a partir dos itens ainda não está disponível pela API: por enquanto os dados ficam prontos e a verificação mostra o que falta.

Preços e estoques por loja

O item precisa estar cadastrado antes. Preço e estoque são gravados na loja informada.

MétodoCaminhoEscopoDescrição
GET/v1/stores/{storeId}/itemsitems:readItens com o preço e o estoque da loja.
GET/v1/stores/{storeId}/items/{code}items:readPreço e estoque de um item na loja.
PUT/v1/stores/{storeId}/items/{code}/priceprices:write{"price": 59.90}; opcionais listPrice (preço "de") e marketplacePrices ({"amazon": 64.90}). Ausentes são mantidos.
PUT/v1/stores/{storeId}/items/{code}/stockstock:write{"quantity": 12}
POST/v1/stores/{storeId}/prices/batchprices:write{"items": [{"code": "CAM-001", "price": 59.90}]}
POST/v1/stores/{storeId}/stock/batchstock:write{"items": [{"code": "CAM-001", "quantity": 12}]}

4. Anúncios (offers)

Os anúncios das contas conectadas são importados automaticamente. Pela API você também pode cadastrar e alterar anúncios da loja e vinculá-los aos itens (itemCode; envie "" para desvincular).

MétodoCaminhoEscopoDescrição
GET/v1/stores/{storeId}/offers?marketplace=&itemCode=offers:readLista os anúncios da loja.
GET/v1/stores/{storeId}/offers/{offerId}offers:readDetalha um anúncio.
POST/v1/stores/{storeId}/offersoffers:writeCadastra um anúncio.
PATCH/v1/stores/{storeId}/offers/{offerId}offers:writeAltera os campos enviados.
POST {{baseUrl}}/v1/stores/{storeId}/offers
{
  "marketplace": "mercadolivre",
  "externalId": "MLB1234567890",
  "sku": "CAM-001",
  "title": "Camiseta básica algodão",
  "price": 59.90,
  "stock": 10,
  "status": "ACTIVE",
  "url": "https://produto.mercadolivre.com.br/MLB-1234567890",
  "itemCode": "CAM-001"
}

Marketplaces: mercadolivre, amazon, magalu, shopee, shein, casasbahia, tiktokshop, temu. Status: ACTIVE, PAUSED, INACTIVE, CLOSED.

O cadastro pela API registra o anúncio na Distsys; a publicação automática de novos anúncios nos marketplaces será disponibilizada em uma próxima versão. Anúncios de contas conectadas são atualizados pela sincronização com o marketplace.

5. Vendas (sales)

As vendas dos marketplaces conectados são importadas automaticamente. Pela API você também pode lançar vendas de outros canais e atualizar status, nota fiscal e datas de pagamento e envio.

MétodoCaminhoEscopoDescrição
GET/v1/stores/{storeId}/sales?status=&marketplace=&createdFrom=&createdTo=sales:readLista as vendas (mais recentes primeiro).
GET/v1/stores/{storeId}/sales/{saleId}sales:readDetalha uma venda.
POST/v1/stores/{storeId}/salessales:writeCadastra uma venda (única por marketplace + número do pedido).
PATCH/v1/stores/{storeId}/sales/{saleId}sales:writeAltera status, nota fiscal, datas, comprador ou valor.
POST {{baseUrl}}/v1/stores/{storeId}/sales
{
  "marketplace": "mercadolivre",
  "externalOrderId": "2000001234567890",
  "buyerName": "Maria Silva",
  "totalAmount": 119.80,
  "status": "PAID",
  "createdAt": "2026-10-22T09:30:00-03:00",
  "paidAt": "2026-10-22T09:31:00-03:00"
}
PATCH {{baseUrl}}/v1/stores/{storeId}/sales/{saleId}
{
  "status": "SHIPPED",
  "invoiceKey": "35261012345678000190550010000012341000012345",
  "invoiceNumber": "1234",
  "shippedAt": "2026-10-23T14:00:00-03:00"
}

Status aceitos: NEW, PAID, INVOICED, SHIPPED, DELIVERED, CANCELLED, REFUNDED. A chave da nota fiscal (invoiceKey) tem 44 dígitos.