# Webhook API v2 — Catálogo Mobile

Use esta API para criar/atualizar produtos, estoques, preços e fotos a partir do seu ERP. Os endpoints individuais continuam disponíveis; produtos, estoques e preços também aceitam lote.

> **Antes de homologar:** `idEcommerce` é o número que identifica a origem das requisições da sua integração. Ele não é código de produto, empresa, catálogo, pedido nem `integrationCode`. Ao concluir o desenvolvimento, solicite o seu `idEcommerce` ao suporte do Catálogo Mobile e use exatamente esse valor em todas as requisições. Nos exemplos, substitua apenas `{{idEcommerce_fornecido_pelo_suporte}}` pelo número informado: não invente esse valor nem o envie entre aspas no JSON.

## Base, identificação e limites

- Base: `https://sistema.catalogomobile.com.br/api/v2/integracao/webhook`
- Substitua `{integrationCode}` pelo código exibido na tela da integração Webhook.
- Envie `Content-Type: application/json`.
- Todo envio precisa de `cnpj`, `idEcommerce` e `tipo`.
- Lotes: no máximo **100 itens** por requisição para produto, estoque ou preço.
- Produtos e variações: no máximo **1000 entidades** no total do lote. Um produto pai e cada variação contam individualmente.
- **Throttling obrigatório:** envie no máximo **1 requisição de lote por segundo para cada integração**, somando produto, estoque e preço. Uma nova tentativa dentro desse intervalo retorna `HTTP 429` e `Retry-After: 1`. As chamadas individuais existentes não mudam.
- A atualização de fotos (`inserirFotos`) é sempre individual e não aceita lote.

## Como enviar um lote

Mantenha o mesmo envelope da integração unitária. A única diferença é que `dados` passa de um objeto para uma lista de objetos. Cada item é validado, registrado e enfileirado de forma independente: se um item falhar, os demais continuam.

```text
POST /api/v2/integracao/webhook/{endpoint}/{integrationCode}/
```

Os aliases em inglês (`addProduct`, `notifyStock`, `sendPrice` e `insertPhotos`) continuam aceitos e também aceitam os nomes de campos em inglês quando já usados na integração atual.

Exemplo em cURL, usando um arquivo de lote já preenchido com o número de `idEcommerce` fornecido pelo suporte:

```bash
curl --request POST \
  'https://sistema.catalogomobile.com.br/api/v2/integracao/webhook/adicionarProduto/{integrationCode}/' \
  --header 'Content-Type: application/json' \
  --data @lote-produtos.json
```

## Produtos — individual ou lote

`POST /api/v2/integracao/webhook/adicionarProduto/{integrationCode}/`

Alias: `POST /api/v2/integracao/webhook/addProduct/{integrationCode}/`

Em produto, cada item exige `idMapeamento`, `nome`, `preco` e `estoqueAtual`. Variações ficam dentro de `variacoes`; cada uma precisa de `idMapeamento`, `preco` e `estoqueAtual`.

Para anexar imagens em lote, envie URLs em `anexos`. Não envie arquivos `multipart/form-data` em lote.

```json
{
  "cnpj": "12345678000190",
  "idEcommerce": {{idEcommerce_fornecido_pelo_suporte}},
  "tipo": "produto",
  "dados": [
    {
      "idMapeamento": "1001001",
      "skuMapeamento": "SKU-1001",
      "nome": "Camiseta básica",
      "codigo": "CAM-001",
      "preco": 59.9,
      "precoPromocional": 49.9,
      "estoqueAtual": 12,
      "anexos": [
        { "url": "https://cdn.exemplo.com/produtos/cam-001-frente.jpg" }
      ],
      "variacoes": [
        {
          "idMapeamento": "1001002",
          "skuMapeamento": "SKU-1001-AZ-M",
          "preco": 59.9,
          "estoqueAtual": 4,
          "grade": [{ "chave": "Cor", "valor": "Azul" }, { "chave": "Tamanho", "valor": "M" }]
        }
      ]
    },
    {
      "idMapeamento": "1002001",
      "nome": "Boné",
      "preco": 39.9,
      "estoqueAtual": 8
    }
  ]
}
```

## Estoque — individual ou lote

`POST /api/v2/integracao/webhook/notificaEstoque/{integrationCode}/`

Alias: `POST /api/v2/integracao/webhook/notifyStock/{integrationCode}/`

Use um identificador que sua integração já reconhece (`skuMapeamento`, `idMapeamento` ou `codigo`) e o saldo em `saldo`.

```json
{
  "cnpj": "12345678000190",
  "idEcommerce": {{idEcommerce_fornecido_pelo_suporte}},
  "tipo": "estoque",
  "dados": [
    { "skuMapeamento": "SKU-1001", "saldo": 10 },
    { "skuMapeamento": "SKU-1002", "saldo": 0 }
  ]
}
```

## Preço — individual ou lote

`POST /api/v2/integracao/webhook/enviaPreco/{integrationCode}/`

Alias: `POST /api/v2/integracao/webhook/sendPrice/{integrationCode}/`

```json
{
  "cnpj": "12345678000190",
  "idEcommerce": {{idEcommerce_fornecido_pelo_suporte}},
  "tipo": "precos",
  "dados": [
    { "skuMapeamento": "SKU-1001", "preco": 59.9, "precoPromocional": 49.9 },
    { "skuMapeamento": "SKU-1002", "preco": 39.9 }
  ]
}
```

## Fotos — somente individual

`POST /api/v2/integracao/webhook/inserirFotos/{integrationCode}/`

Alias: `POST /api/v2/integracao/webhook/insertPhotos/{integrationCode}/`

Envie uma requisição por produto, com `tipo: "foto"`, um identificador do produto e arquivos `foto1` a `foto4` em `multipart/form-data`. Para produto em lote, prefira `dados[].anexos[].url`.

## Detalhar produto

`GET /api/v2/integracao/webhook/detalharProduto/{integrationCode}/{campo}/{valor}/`

Alias: `GET /api/v2/integracao/webhook/detailProduct/{integrationCode}/{campo}/{valor}/`

Envie `Authorization: Bearer {token_da_integracao}`. O campo pode ser `skuMapeamento`, `idMapeamento` ou `code`. A forma legada com apenas um valor após o `integrationCode` continua consultando por `skuMapeamento`.

```text
GET /api/v2/integracao/webhook/detalharProduto/{integrationCode}/code/CAM-001/
Authorization: Bearer {token_da_integracao}
```

## Listar pedidos

`GET /api/v2/integracao/webhook/listarPedidos/{integrationCode}/?data=YYYY-MM-DD`

Alias: `GET /api/v2/integracao/webhook/listOrders/{integrationCode}/?date=YYYY-MM-DD`

Envie `Authorization: Bearer {token_da_integracao}`. A data é opcional: quando informada, deve estar entre hoje e os últimos sete dias. A resposta agrupa os itens por pedido/carrinho.

```text
GET /api/v2/integracao/webhook/listarPedidos/{integrationCode}/?data=2026-07-27
Authorization: Bearer {token_da_integracao}
```

## Resposta de lote e reprocessamento

Quando ao menos um item for aceito, a API retorna `202`. A resposta traz o resultado por posição em `items`; guarde o `request_id` dos itens aceitos ou rejeitados para consultar o processamento.

```json
{
  "status": "partially_accepted",
  "total_items": 2,
  "accepted_items": 1,
  "duplicate_items": 0,
  "rejected_items": 1,
  "failed_items": 0,
  "items": [
    { "item_index": 0, "status": "accepted", "http_status": 202, "request_id": "uuid" },
    { "item_index": 1, "status": "rejected_validation", "http_status": 422, "request_id": "uuid", "error": "..." }
  ]
}
```

- `202 accepted` ou `202 partially_accepted`: há itens enfileirados.
- `422`: nenhum item foi aceito por erro de validação, ou o lote excede os limites.
- `429`: respeite `Retry-After` e reenvie o lote depois do intervalo.
- `503`: o controle de limite está indisponível; tente novamente em instantes. Nenhum item foi enfileirado.
- Reenvie somente os itens que não foram aceitos. Não reenvie todos os itens de uma resposta parcial.

Consulte o status individual em:

```text
GET /api/v2/integracao/webhook/status/{request_id}/
```

## Compatibilidade

Requisições unitárias continuam usando `dados` como objeto e preservam o comportamento atual. Não use `sync=true` em lote: lote é sempre assíncrono.
