{
  "info": {
    "_postman_id": "770d2f95-1ef2-4c2a-a6e2-43349c760ab1",
    "name": "API Sellume para Integradores (v1)",
    "description": "Coleção gerada do contrato OpenAPI da API v1. Documentação: https://docs.sellume.com.br\n\n1. Importe esta coleção e o ambiente \"Sellume — teste\".\n2. No ambiente, cole a sua chave sk_test_ em \"chave\" (ela aparece uma vez no portal, em Chaves de API).\n3. Siga a ordem: Créditos › Saldo, Contas › Criar, Produtos › Enviar a ficha e Conferir, Gerações › Galeria e Andamento.\n\nOs ids (contaId, produtoId, geracaoId…) são gravados nas variáveis pelos scripts de teste. POST que gasta crédito leva Idempotency-Key: {{$guid}} automático.\nEndereço oficial da API: https://api.sellume.com.br/v1 (OAuth em https://api.sellume.com.br/oauth/...).",
    "schema": "https://schema.getpostman.com/json/collection/v2.1.0/collection.json"
  },
  "auth": {
    "type": "bearer",
    "bearer": [
      {
        "key": "token",
        "value": "{{chave}}",
        "type": "string"
      }
    ]
  },
  "event": [
    {
      "listen": "test",
      "script": {
        "type": "text/javascript",
        "exec": [
          "const requestId = pm.response.headers.get('X-Request-Id');",
          "if (requestId && !pm.request.url.toString().includes('/integracao/chamadas')) {",
          "  if (pm.environment.name) pm.environment.set('requestId', requestId); else pm.collectionVariables.set('requestId', requestId);",
          "}"
        ]
      }
    }
  ],
  "variable": [
    {
      "key": "baseUrl",
      "value": "https://api.sellume.com.br/v1",
      "type": "string"
    },
    {
      "key": "tokenUrl",
      "value": "https://api.sellume.com.br/oauth/token",
      "type": "string"
    },
    {
      "key": "revogarUrl",
      "value": "https://api.sellume.com.br/oauth/revogar",
      "type": "string"
    }
  ],
  "item": [
    {
      "name": "Contas",
      "description": "Subcontas dos clientes finais do integrador e contas vinculadas por OAuth.",
      "item": [
        {
          "name": "Listar contas do integrador",
          "request": {
            "method": "GET",
            "header": [],
            "url": {
              "raw": "{{baseUrl}}/contas",
              "host": [
                "{{baseUrl}}"
              ],
              "path": [
                "contas"
              ],
              "query": [
                {
                  "key": "pagina",
                  "value": "",
                  "disabled": true,
                  "description": "Número da página, começando em 1."
                },
                {
                  "key": "limite",
                  "value": "",
                  "disabled": true,
                  "description": "Itens por página (padrão 100, máximo 100)."
                },
                {
                  "key": "situacao",
                  "value": "",
                  "disabled": true
                },
                {
                  "key": "codigoExterno",
                  "value": "",
                  "disabled": true
                },
                {
                  "key": "origem",
                  "value": "",
                  "disabled": true
                }
              ]
            },
            "description": "Referência: https://docs.sellume.com.br/referencia#listarContas"
          },
          "event": [
            {
              "listen": "test",
              "script": {
                "type": "text/javascript",
                "exec": [
                  "const definir = (k, v) => { if (v === undefined || v === null || v === '') return; if (pm.environment.name) pm.environment.set(k, v); else pm.collectionVariables.set(k, v); };",
                  "if (pm.response.code >= 200 && pm.response.code < 300) {",
                  "  const r = pm.response.json();",
                  "  if (!pm.variables.get('contaId') && Array.isArray(r.data) && r.data[0]) definir('contaId', r.data[0].id);",
                  "}"
                ]
              }
            }
          ]
        },
        {
          "name": "Criar a subconta de um cliente final",
          "request": {
            "method": "POST",
            "header": [
              {
                "key": "Content-Type",
                "value": "application/json"
              }
            ],
            "url": {
              "raw": "{{baseUrl}}/contas",
              "host": [
                "{{baseUrl}}"
              ],
              "path": [
                "contas"
              ]
            },
            "description": "Cria a subconta de um cliente do integrador (cada vendedor do ERP ou cada seguidor do\ninfluencer). A subconta não tem login nem recebe e-mails do Sellume. `codigoExterno` é o\nidentificador do cliente no sistema do integrador e é único por integrador: repetir o\nmesmo `codigoExterno` devolve `409` com o `id` existente em `error.fields`.\n\nReferência: https://docs.sellume.com.br/referencia#criarConta",
            "body": {
              "mode": "raw",
              "raw": "{\n  \"codigoExterno\": \"vendedor-98213\",\n  \"nome\": \"Loja Casa Bonita\",\n  \"metadados\": {\n    \"planoNoErp\": \"ouro\"\n  }\n}",
              "options": {
                "raw": {
                  "language": "json"
                }
              }
            }
          },
          "event": [
            {
              "listen": "test",
              "script": {
                "type": "text/javascript",
                "exec": [
                  "const definir = (k, v) => { if (v === undefined || v === null || v === '') return; if (pm.environment.name) pm.environment.set(k, v); else pm.collectionVariables.set(k, v); };",
                  "if (pm.response.code >= 200 && pm.response.code < 300) {",
                  "  const r = pm.response.json();",
                  "  if (r.data) definir('contaId', r.data.id);",
                  "}"
                ]
              }
            }
          ]
        },
        {
          "name": "Detalhar uma conta",
          "request": {
            "method": "GET",
            "header": [],
            "url": {
              "raw": "{{baseUrl}}/contas/{{contaId}}",
              "host": [
                "{{baseUrl}}"
              ],
              "path": [
                "contas",
                "{{contaId}}"
              ]
            },
            "description": "Referência: https://docs.sellume.com.br/referencia#obterConta"
          }
        },
        {
          "name": "Atualizar nome, metadados ou situação da subconta",
          "request": {
            "method": "PATCH",
            "header": [
              {
                "key": "Content-Type",
                "value": "application/json"
              }
            ],
            "url": {
              "raw": "{{baseUrl}}/contas/{{contaId}}",
              "host": [
                "{{baseUrl}}"
              ],
              "path": [
                "contas",
                "{{contaId}}"
              ]
            },
            "description": "`situacao: pausada` impede novas gerações da subconta (as em andamento terminam).\nContas vinculadas por OAuth não podem ser pausadas por aqui: revogue a autorização.\n\nReferência: https://docs.sellume.com.br/referencia#atualizarConta",
            "body": {
              "mode": "raw",
              "raw": "{\n  \"situacao\": \"pausada\"\n}",
              "options": {
                "raw": {
                  "language": "json"
                }
              }
            }
          }
        },
        {
          "name": "Encerrar a subconta",
          "request": {
            "method": "DELETE",
            "header": [],
            "url": {
              "raw": "{{baseUrl}}/contas/{{contaId}}",
              "host": [
                "{{baseUrl}}"
              ],
              "path": [
                "contas",
                "{{contaId}}"
              ]
            },
            "description": "Encerra a subconta: novas gerações são recusadas e os dados pessoais e mídias entram na\nrotina de exclusão (LGPD) depois do prazo de retenção do contrato. O extrato do integrador\ncontinua guardando o consumo dessa subconta (sem dados pessoais).\n\nReferência: https://docs.sellume.com.br/referencia#encerrarConta"
          }
        }
      ]
    },
    {
      "name": "Produtos",
      "description": "Ficha do produto (única fonte de dados e fotos) e conferência dos requisitos mínimos.",
      "item": [
        {
          "name": "Listar produtos da conta",
          "request": {
            "method": "GET",
            "header": [],
            "url": {
              "raw": "{{baseUrl}}/contas/{{contaId}}/produtos",
              "host": [
                "{{baseUrl}}"
              ],
              "path": [
                "contas",
                "{{contaId}}",
                "produtos"
              ],
              "query": [
                {
                  "key": "pagina",
                  "value": "",
                  "disabled": true,
                  "description": "Número da página, começando em 1."
                },
                {
                  "key": "limite",
                  "value": "",
                  "disabled": true,
                  "description": "Itens por página (padrão 100, máximo 100)."
                },
                {
                  "key": "situacao",
                  "value": "",
                  "disabled": true
                }
              ]
            },
            "description": "Referência: https://docs.sellume.com.br/referencia#listarProdutos"
          }
        },
        {
          "name": "Detalhar o produto",
          "request": {
            "method": "GET",
            "header": [],
            "url": {
              "raw": "{{baseUrl}}/contas/{{contaId}}/produtos/{{codigoProduto}}",
              "host": [
                "{{baseUrl}}"
              ],
              "path": [
                "contas",
                "{{contaId}}",
                "produtos",
                "{{codigoProduto}}"
              ]
            },
            "description": "Referência: https://docs.sellume.com.br/referencia#obterProduto"
          }
        },
        {
          "name": "Enviar ou atualizar a ficha do produto (única fonte)",
          "request": {
            "method": "PUT",
            "header": [
              {
                "key": "Content-Type",
                "value": "application/json"
              }
            ],
            "url": {
              "raw": "{{baseUrl}}/contas/{{contaId}}/produtos/{{codigoProduto}}",
              "host": [
                "{{baseUrl}}"
              ],
              "path": [
                "contas",
                "{{contaId}}",
                "produtos",
                "{{codigoProduto}}"
              ]
            },
            "description": "Envia a ficha completa com fotos — a **única fonte** de dados e fotos do produto. O Sellume não\nbusca nada no marketplace; `anuncio` é só rastreio. Campos compatíveis com Bling, Tiny, Magis5 e\nShopping de Preços (veja `FichaProduto`, que lista os requisitos mínimos).\n\nAs fotos são baixadas pelo servidor do Sellume (proteção contra endereços internos, tipo pelos\nbytes, tamanho e resolução conferidos, cópia no armazenamento) e passam pela triagem. Fotos e\ndados valem como oficiais (responsabilidade do integrador, por contrato).\n\nCada envio com conteúdo diferente cria uma nova versão e **inicia a conferência** dessa versão\nautomaticamente (o resultado chega no aviso `produto.conferido`). Gerações já pedidas usam a\nversão da hora do pedido. Envio idêntico ao anterior não cria versão nem nova conferência.\n\nReferência: https://docs.sellume.com.br/referencia#enviarFichaProduto",
            "body": {
              "mode": "raw",
              "raw": "{\n  \"nome\": \"Arandela LED de parede 12W luz quente\",\n  \"descricao\": \"Arandela de alumínio com difusor de vidro jateado, ideal para corredores e varandas.\",\n  \"descricaoComplementar\": \"Acompanha kit de fixação. Bivolt.\",\n  \"marca\": \"Lumina Casa\",\n  \"modelo\": \"AR-12Q\",\n  \"gtin\": \"7891234567895\",\n  \"categoria\": {\n    \"codigo\": \"ilum-arandelas\",\n    \"nome\": \"Arandelas\",\n    \"caminho\": \"Casa > Iluminação > Arandelas\"\n  },\n  \"atributos\": [\n    {\n      \"nome\": \"Cor\",\n      \"valor\": \"Preto fosco\"\n    },\n    {\n      \"nome\": \"Potência\",\n      \"valor\": \"12 W\"\n    },\n    {\n      \"nome\": \"Material\",\n      \"valor\": \"Alumínio\"\n    }\n  ],\n  \"imagens\": [\n    {\n      \"url\": \"https://cdn.erp.exemplo.com.br/p/arandela-1.jpg\",\n      \"ordem\": 1,\n      \"principal\": true\n    },\n    {\n      \"url\": \"https://cdn.erp.exemplo.com.br/p/arandela-2.jpg\",\n      \"ordem\": 2,\n      \"principal\": false\n    }\n  ],\n  \"dimensoes\": {\n    \"largura\": 12,\n    \"altura\": 25,\n    \"profundidade\": 8,\n    \"unidade\": \"cm\",\n    \"pesoLiquido\": 0.6,\n    \"pesoBruto\": 0.8,\n    \"unidadePeso\": \"kg\"\n  },\n  \"composicaoOferta\": [\n    {\n      \"item\": \"Arandela\",\n      \"quantidade\": 1\n    }\n  ],\n  \"garantia\": \"12 meses contra defeitos de fabricação\",\n  \"avaliacoes\": [\n    {\n      \"nota\": 5,\n      \"texto\": \"Iluminou bem o corredor e a instalação foi simples.\"\n    }\n  ],\n  \"perguntas\": [\n    {\n      \"pergunta\": \"Serve para área externa coberta?\",\n      \"resposta\": \"Sim, para área coberta.\"\n    }\n  ],\n  \"anuncio\": {\n    \"marketplace\": \"mercado_livre\",\n    \"id\": \"MLB4123456789\"\n  }\n}",
              "options": {
                "raw": {
                  "language": "json"
                }
              }
            }
          },
          "event": [
            {
              "listen": "test",
              "script": {
                "type": "text/javascript",
                "exec": [
                  "const definir = (k, v) => { if (v === undefined || v === null || v === '') return; if (pm.environment.name) pm.environment.set(k, v); else pm.collectionVariables.set(k, v); };",
                  "if (pm.response.code >= 200 && pm.response.code < 300) {",
                  "  const r = pm.response.json();",
                  "  if (r.data) definir('produtoId', r.data.id);",
                  "}"
                ]
              }
            }
          ]
        },
        {
          "name": "Remover o produto",
          "request": {
            "method": "DELETE",
            "header": [],
            "url": {
              "raw": "{{baseUrl}}/contas/{{contaId}}/produtos/{{codigoProduto}}",
              "host": [
                "{{baseUrl}}"
              ],
              "path": [
                "contas",
                "{{contaId}}",
                "produtos",
                "{{codigoProduto}}"
              ]
            },
            "description": "Remove o produto da conta. Gerações já entregues continuam no extrato e em `GET /geracoes`.\n\nReferência: https://docs.sellume.com.br/referencia#removerProduto"
          }
        },
        {
          "name": "Último resultado da conferência da versão atual",
          "request": {
            "method": "GET",
            "header": [],
            "url": {
              "raw": "{{baseUrl}}/produtos/{{produtoId}}/conferencia",
              "host": [
                "{{baseUrl}}"
              ],
              "path": [
                "produtos",
                "{{produtoId}}",
                "conferencia"
              ]
            },
            "description": "Referência: https://docs.sellume.com.br/referencia#obterConferencia"
          }
        },
        {
          "name": "Conferir os requisitos mínimos (obrigatório antes de gerar, grátis)",
          "request": {
            "method": "POST",
            "header": [],
            "url": {
              "raw": "{{baseUrl}}/produtos/{{produtoId}}/conferencia",
              "host": [
                "{{baseUrl}}"
              ],
              "path": [
                "produtos",
                "{{produtoId}}",
                "conferencia"
              ]
            },
            "description": "Confere a **versão atual** do produto contra os requisitos mínimos de qualidade do Sellume e\nresponde **aprovado ou reprovado por tipo de geração** (galeria, Apresentação, CinePremium),\ncom a lista exata do que falta (`bloqueio`) ou está fraco (`fraco`), em códigos estáveis e\nmensagens em português. Não cobra nada.\n\n**É obrigatória:** `POST /galerias` e `POST /videos` só aceitam produto cuja versão atual tenha\nconferência concluída e aprovada para o tipo pedido (e, na galeria, para a quantidade pedida).\nCaso contrário a geração é recusada antes de qualquer custo com `PRODUCT_NOT_VERIFIED` (sem\nconferência da versão atual) ou `PRODUCT_REQUIREMENTS_NOT_MET` (reprovado).\n\nA conferência já começa sozinha a cada nova versão da ficha. Este endpoint devolve o resultado\npronto (`200`) ou inicia/aguarda a conferência (`202`, resultado no aviso `produto.conferido`).\nUma conferência vale para a versão do produto e para a versão das regras (`politica`); se as\nregras mudarem, o produto precisa ser conferido de novo. Limite: 10 conferências por produto\npor dia.\n\nReferência: https://docs.sellume.com.br/referencia#conferirProduto"
          }
        }
      ]
    },
    {
      "name": "Gerações",
      "description": "Galerias de imagens, vídeos (Apresentação e CinePremium) e edições de imagem.",
      "item": [
        {
          "name": "Criar galeria de imagens (3, 6 ou 10)",
          "request": {
            "method": "POST",
            "header": [
              {
                "key": "Content-Type",
                "value": "application/json"
              },
              {
                "key": "Idempotency-Key",
                "value": "{{$guid}}",
                "description": "Um valor novo por pedido. Para testar a repetição segura, troque {{$guid}} por um valor fixo e envie duas vezes."
              }
            ],
            "url": {
              "raw": "{{baseUrl}}/galerias",
              "host": [
                "{{baseUrl}}"
              ],
              "path": [
                "galerias"
              ]
            },
            "description": "Exige a versão atual do produto **aprovada na conferência** para `galeria` e\n`quantidadeImagens` entre as `quantidadesAprovadas`; senão responde `422`\n(`PRODUCT_NOT_VERIFIED` ou `PRODUCT_REQUIREMENTS_NOT_MET`) sem reservar nada.\nAprovado: reserva os créditos na carteira do integrador e enfileira a galeria. A cobrança só\né liquidada na entrega; falha do Sellume devolve os créditos. Entrega parcial cobra só as\nimagens entregues.\n\nReferência: https://docs.sellume.com.br/referencia#criarGaleria",
            "body": {
              "mode": "raw",
              "raw": "{\n  \"produtoId\": \"{{produtoId}}\",\n  \"quantidadeImagens\": 6,\n  \"objetivo\": \"conversao\",\n  \"referenciaExterna\": \"pedido-erp-55120\"\n}",
              "options": {
                "raw": {
                  "language": "json"
                }
              }
            }
          },
          "event": [
            {
              "listen": "test",
              "script": {
                "type": "text/javascript",
                "exec": [
                  "const definir = (k, v) => { if (v === undefined || v === null || v === '') return; if (pm.environment.name) pm.environment.set(k, v); else pm.collectionVariables.set(k, v); };",
                  "if (pm.response.code >= 200 && pm.response.code < 300) {",
                  "  const r = pm.response.json();",
                  "  if (r.data) definir('geracaoId', r.data.id);",
                  "}"
                ]
              }
            }
          ]
        },
        {
          "name": "Criar vídeo Apresentação ou CinePremium (fala automática)",
          "request": {
            "method": "POST",
            "header": [
              {
                "key": "Content-Type",
                "value": "application/json"
              },
              {
                "key": "Idempotency-Key",
                "value": "{{$guid}}",
                "description": "Um valor novo por pedido. Para testar a repetição segura, troque {{$guid}} por um valor fixo e envie duas vezes."
              }
            ],
            "url": {
              "raw": "{{baseUrl}}/videos",
              "host": [
                "{{baseUrl}}"
              ],
              "path": [
                "videos"
              ]
            },
            "description": "Cria um vídeo vertical do produto. Exige a versão atual **aprovada na conferência** para o tipo\n(`video_apresentacao` ou `video_cinepremium`); senão responde `422` sem reservar nada.\n\n**A fala é automática**: o sistema gera as opções de fala e escolhe a melhor pelos mesmos\ncritérios e travas do fluxo atual (fato sem prova na ficha, CTA, duração). Não há etapa de\nescolha nem endpoint para escolher a fala. A fala usada volta no resultado\n(`resultados.video.fala` e `fala` na geração). Se nenhuma opção passar nas travas, a geração\nfalha antes de qualquer render pago, os créditos voltam e o erro vem como\n`VIDEO_SPEECH_NOT_APPROVED`. Depois que a geração começa, o vídeo não pode ser cancelado.\n\n**Como a fala é escolhida:** só contam as opções que passaram nas travas determinísticas; entre\nelas, a de maior nota do crítico quando a revisão existe; empate → a recomendada pelo motor e,\ndepois, a `safe` (no CinePremium, empate → `safe`).\n\n**Fila justa (13/10/2026):** ninguém é recusado por capacidade. O pedido entra na fila (`na_fila`, com\n`fila.posicao` e `fila.esperaEstimadaSegundos`) e o crédito fica reservado; o teto de vídeos do plano\n(Base 1, Growth 2, Business 3, Enterprise 4; Apresentação e CinePremium contam igual) limita só quantos\nrodam ao mesmo tempo. Ao ganhar a vaga passa a `gerando` (aviso `geracao.iniciada`). Um vídeo por produto\npor vez (`409`).\nCom chave `sk_test_` volta um vídeo de exemplo (sem motor e sem crédito), com a escolha da fala\nsimulada, concluído em cerca de 15 s.\n\nReferência: https://docs.sellume.com.br/referencia#criarVideo",
            "body": {
              "mode": "raw",
              "raw": "{\n  \"produtoId\": \"{{produtoId}}\",\n  \"tipo\": \"apresentacao\",\n  \"avatar\": \"automatico\",\n  \"referenciaExterna\": \"pedido-erp-55121\"\n}",
              "options": {
                "raw": {
                  "language": "json"
                }
              }
            }
          },
          "event": [
            {
              "listen": "test",
              "script": {
                "type": "text/javascript",
                "exec": [
                  "const definir = (k, v) => { if (v === undefined || v === null || v === '') return; if (pm.environment.name) pm.environment.set(k, v); else pm.collectionVariables.set(k, v); };",
                  "if (pm.response.code >= 200 && pm.response.code < 300) {",
                  "  const r = pm.response.json();",
                  "  if (r.data) definir('geracaoId', r.data.id);",
                  "}"
                ]
              }
            }
          ]
        },
        {
          "name": "Avatares oficiais para a Apresentação",
          "request": {
            "method": "GET",
            "header": [],
            "url": {
              "raw": "{{baseUrl}}/avatares",
              "host": [
                "{{baseUrl}}"
              ],
              "path": [
                "avatares"
              ]
            },
            "description": "Lista os avatares **ativos** que podem apresentar o produto num vídeo `apresentacao`, para o seu sistema montar a\nescolha e oferecer ao cliente. Envie o `codigo` no campo `avatar` de `POST /videos` (ou `automatico` para o sistema\nescolher). Grátis, não gasta crédito; pode ser guardada por 5 minutos (`Cache-Control: private, max-age=300`).\nBaixe e guarde a `foto` e a `previaAnimada` no seu sistema e atualize a lista de vez em quando: avatar pode sair\nde linha e outros podem entrar. Código inexistente ou inativo no pedido de vídeo: `400 VALIDATION_ERROR` com o\ncampo `avatar` e o código `AVATAR_INDISPONIVEL`. O CinePremium não usa avatar (use `voz`).\n\nReferência: https://docs.sellume.com.br/referencia#listarAvatares"
          }
        },
        {
          "name": "Editar uma imagem, mudando só o que foi pedido",
          "request": {
            "method": "POST",
            "header": [
              {
                "key": "Content-Type",
                "value": "application/json"
              },
              {
                "key": "Idempotency-Key",
                "value": "{{$guid}}",
                "description": "Um valor novo por pedido. Para testar a repetição segura, troque {{$guid}} por um valor fixo e envie duas vezes."
              }
            ],
            "url": {
              "raw": "{{baseUrl}}/imagens/{{imagemId}}/edicoes",
              "host": [
                "{{baseUrl}}"
              ],
              "path": [
                "imagens",
                "{{imagemId}}",
                "edicoes"
              ]
            },
            "description": "Edita uma imagem já entregue. **Só o que foi pedido muda**: produto, enquadramento, textos e\nfundo que não fazem parte do pedido são preservados. `troca_de_cor` troca a cor do produto\n(ou da parte indicada) pela cor pedida. A edição gera uma nova imagem (a original continua\ndisponível) e cobra o preço de edição da tabela do integrador.\n\nReferência: https://docs.sellume.com.br/referencia#editarImagem",
            "body": {
              "mode": "raw",
              "raw": "{\n  \"tipo\": \"troca_de_cor\",\n  \"cor\": {\n    \"nome\": \"Branco\",\n    \"hex\": \"#FFFFFF\"\n  },\n  \"parte\": \"corpo da arandela\"\n}",
              "options": {
                "raw": {
                  "language": "json"
                }
              }
            }
          },
          "event": [
            {
              "listen": "test",
              "script": {
                "type": "text/javascript",
                "exec": [
                  "const definir = (k, v) => { if (v === undefined || v === null || v === '') return; if (pm.environment.name) pm.environment.set(k, v); else pm.collectionVariables.set(k, v); };",
                  "if (pm.response.code >= 200 && pm.response.code < 300) {",
                  "  const r = pm.response.json();",
                  "  if (r.data) definir('geracaoId', r.data.id);",
                  "}"
                ]
              }
            }
          ]
        },
        {
          "name": "Listar gerações",
          "request": {
            "method": "GET",
            "header": [],
            "url": {
              "raw": "{{baseUrl}}/geracoes",
              "host": [
                "{{baseUrl}}"
              ],
              "path": [
                "geracoes"
              ],
              "query": [
                {
                  "key": "pagina",
                  "value": "",
                  "disabled": true,
                  "description": "Número da página, começando em 1."
                },
                {
                  "key": "limite",
                  "value": "",
                  "disabled": true,
                  "description": "Itens por página (padrão 100, máximo 100)."
                },
                {
                  "key": "contaId",
                  "value": "",
                  "disabled": true
                },
                {
                  "key": "produtoId",
                  "value": "",
                  "disabled": true
                },
                {
                  "key": "tipo",
                  "value": "",
                  "disabled": true
                },
                {
                  "key": "situacao",
                  "value": "",
                  "disabled": true
                },
                {
                  "key": "criadoDe",
                  "value": "",
                  "disabled": true
                },
                {
                  "key": "criadoAte",
                  "value": "",
                  "disabled": true
                }
              ]
            },
            "description": "Referência: https://docs.sellume.com.br/referencia#listarGeracoes"
          }
        },
        {
          "name": "Andamento e resultado, com links para baixar",
          "request": {
            "method": "GET",
            "header": [],
            "url": {
              "raw": "{{baseUrl}}/geracoes/{{geracaoId}}",
              "host": [
                "{{baseUrl}}"
              ],
              "path": [
                "geracoes",
                "{{geracaoId}}"
              ]
            },
            "description": "Referência: https://docs.sellume.com.br/referencia#obterGeracao"
          },
          "event": [
            {
              "listen": "test",
              "script": {
                "type": "text/javascript",
                "exec": [
                  "const definir = (k, v) => { if (v === undefined || v === null || v === '') return; if (pm.environment.name) pm.environment.set(k, v); else pm.collectionVariables.set(k, v); };",
                  "if (pm.response.code >= 200 && pm.response.code < 300) {",
                  "  const r = pm.response.json();",
                  "  const imgs = r.data && r.data.resultados && r.data.resultados.imagens;",
                  "  if (Array.isArray(imgs) && imgs[0]) definir('imagemId', imgs[0].id);",
                  "}"
                ]
              }
            }
          ]
        },
        {
          "name": "Cancela uma geração que ainda está na fila",
          "request": {
            "method": "POST",
            "header": [],
            "url": {
              "raw": "{{baseUrl}}/geracoes/{{geracaoId}}/cancelar",
              "host": [
                "{{baseUrl}}"
              ],
              "path": [
                "geracoes",
                "{{geracaoId}}",
                "cancelar"
              ]
            },
            "description": "Só enquanto a geração está `na_fila`. A passagem para `gerando` e o cancelamento são decididos numa\núnica transação no Sellume: ou a geração começa, ou é cancelada — nunca as duas. Os créditos reservados\nvoltam só se nenhum fornecedor de geração foi chamado para o pedido; se já houve chamada, o pedido não é\ncancelado e segue até o fim (cobrado só se entregue). Depois que começou (`gerando`), não cancela.\nToda tentativa fica no histórico do Sellume (quem pediu, quando, estado e decisão).\n\nReferência: https://docs.sellume.com.br/referencia#cancelarGeracao"
          }
        }
      ]
    },
    {
      "name": "Créditos",
      "description": "Saldo, extrato, plano, cota do mês (créditos do plano, que também são o teto) e pacotes avulsos da carteira do integrador.",
      "item": [
        {
          "name": "Saldo da carteira do integrador",
          "request": {
            "method": "GET",
            "header": [],
            "url": {
              "raw": "{{baseUrl}}/saldo",
              "host": [
                "{{baseUrl}}"
              ],
              "path": [
                "saldo"
              ]
            },
            "description": "Referência: https://docs.sellume.com.br/referencia#obterSaldo"
          }
        },
        {
          "name": "Extrato detalhado (por conta, produto e geração)",
          "request": {
            "method": "GET",
            "header": [],
            "url": {
              "raw": "{{baseUrl}}/extrato",
              "host": [
                "{{baseUrl}}"
              ],
              "path": [
                "extrato"
              ],
              "query": [
                {
                  "key": "pagina",
                  "value": "",
                  "disabled": true,
                  "description": "Número da página, começando em 1."
                },
                {
                  "key": "limite",
                  "value": "",
                  "disabled": true,
                  "description": "Itens por página (padrão 100, máximo 100)."
                },
                {
                  "key": "contaId",
                  "value": "",
                  "disabled": true
                },
                {
                  "key": "tipo",
                  "value": "",
                  "disabled": true
                },
                {
                  "key": "de",
                  "value": "",
                  "disabled": true
                },
                {
                  "key": "ate",
                  "value": "",
                  "disabled": true
                }
              ]
            },
            "description": "Referência: https://docs.sellume.com.br/referencia#listarExtrato"
          }
        },
        {
          "name": "Cota do mês (créditos do ciclo do plano, que também são o teto)",
          "request": {
            "method": "GET",
            "header": [],
            "url": {
              "raw": "{{baseUrl}}/cota-do-mes",
              "host": [
                "{{baseUrl}}"
              ],
              "path": [
                "cota-do-mes"
              ],
              "query": [
                {
                  "key": "competencia",
                  "value": "",
                  "disabled": true,
                  "description": "Mês do ciclo no formato AAAA-MM."
                }
              ]
            },
            "description": "Para integradores no modelo `plano_mensal`. O plano é pago **antes**: a fatura paga abre o ciclo com os\ncréditos do plano (a cota). A cota é também o **teto** do mês: não há excedente nem limite separado. Quando\nela acaba, o uso sai do crédito avulso guardado (pacote avulso, que não vence); sem ele, os pedidos que gastam\ncrédito respondem `402 INSUFFICIENT_CREDITS` **sem cobrar**, até um pacote avulso ou o próximo ciclo.\nSem `competencia`, devolve o ciclo aberto (ou o último). Integradores no modelo `pre_pago` recebem `404`.\n\nReferência: https://docs.sellume.com.br/referencia#obterCotaDoMes"
          }
        },
        {
          "name": "Plano atual, cota do mês, troca pendente, sugestão de subida e pacotes avulsos",
          "request": {
            "method": "GET",
            "header": [],
            "url": {
              "raw": "{{baseUrl}}/plano",
              "host": [
                "{{baseUrl}}"
              ],
              "path": [
                "plano"
              ]
            },
            "description": "Planos: **Sellume API Base** (máquinas compartilhadas com cota de simultâneos), **Growth** (máquina própria),\n**Business** (máquina própria maior e prioridade) e **Enterprise** (sob medida: cota e preço por contrato).\nValores definitivos na Fase 7 (`valoresDeExemplo` = true enquanto forem de exemplo).\n**Subir de plano** vale **na hora**: é pedida no portal e aplicada pelo time do Sellume; o plano novo é cobrado\n**inteiro** no mesmo dia (sem valor proporcional), o ciclo **recomeça** nesse dia, os créditos do plano novo entram\ninteiros e o saldo que sobrou continua até a data em que já venceria. **Descer de plano** vale **só no próximo\nciclo**; nada é cobrado na hora. **Pacote avulso** (`recarga.pacotes`): pago na hora pela página segura de pagamentos; o\ncrédito não vence e é gasto depois da cota do plano do mês; o crédito avulso custa mais que o crédito do plano\ne que o do plano de cima. Comprou pacote avulso em 2 ciclos seguidos → `sugestaoSubida`. No pré-pago, `atual`\né nulo e a recarga tem quantidade livre.\n\nReferência: https://docs.sellume.com.br/referencia#obterPlano"
          }
        },
        {
          "name": "Planos disponíveis para este integrador (com o movimento possível a partir do atual)",
          "request": {
            "method": "GET",
            "header": [],
            "url": {
              "raw": "{{baseUrl}}/planos",
              "host": [
                "{{baseUrl}}"
              ],
              "path": [
                "planos"
              ]
            },
            "description": "Referência: https://docs.sellume.com.br/referencia#listarPlanos"
          }
        },
        {
          "name": "Compra um pacote avulso (devolve o link da página segura de pagamentos)",
          "request": {
            "method": "POST",
            "header": [
              {
                "key": "Content-Type",
                "value": "application/json"
              }
            ],
            "url": {
              "raw": "{{baseUrl}}/recargas",
              "host": [
                "{{baseUrl}}"
              ],
              "path": [
                "recargas"
              ]
            },
            "description": "Plano: envie `pacote` (um dos de `GET /plano` → `recarga.pacotes`; de exemplo: avulso_1000, avulso_3000,\navulso_6000). Pré-pago (componente embutido): envie `creditos` (100 a 1.000.000). **Nada é cobrado nem\nconcedido nesta chamada:** os créditos entram quando o pagamento é confirmado na página segura de pagamentos\n(extrato `recarga`). O crédito avulso **não vence**. Com chave `sk_test_` de um integrador de produção a\ncompra é recusada (`409`): no teste não há cobrança.\n\nReferência: https://docs.sellume.com.br/referencia#comprarPacoteAvulso",
            "body": {
              "mode": "raw",
              "raw": "{\n  \"pacote\": \"avulso_1000\"\n}",
              "options": {
                "raw": {
                  "language": "json"
                }
              }
            }
          }
        }
      ]
    },
    {
      "name": "Avisos",
      "description": "Cadastro de endereços de webhook, entregas, reenvios e teste de assinatura.",
      "item": [
        {
          "name": "Listar endereços de aviso cadastrados",
          "request": {
            "method": "GET",
            "header": [],
            "url": {
              "raw": "{{baseUrl}}/avisos",
              "host": [
                "{{baseUrl}}"
              ],
              "path": [
                "avisos"
              ]
            },
            "description": "Referência: https://docs.sellume.com.br/referencia#listarAvisos"
          },
          "event": [
            {
              "listen": "test",
              "script": {
                "type": "text/javascript",
                "exec": [
                  "const definir = (k, v) => { if (v === undefined || v === null || v === '') return; if (pm.environment.name) pm.environment.set(k, v); else pm.collectionVariables.set(k, v); };",
                  "if (pm.response.code >= 200 && pm.response.code < 300) {",
                  "  const r = pm.response.json();",
                  "  if (!pm.variables.get('avisoId') && Array.isArray(r.data) && r.data[0]) definir('avisoId', r.data[0].id);",
                  "}"
                ]
              }
            }
          ]
        },
        {
          "name": "Cadastrar um endereço que recebe avisos",
          "request": {
            "method": "POST",
            "header": [
              {
                "key": "Content-Type",
                "value": "application/json"
              }
            ],
            "url": {
              "raw": "{{baseUrl}}/avisos",
              "host": [
                "{{baseUrl}}"
              ],
              "path": [
                "avisos"
              ]
            },
            "description": "O segredo de assinatura (`segredo`, prefixo `whsec_`) aparece **só nesta resposta** e na\nrotação. Guarde-o: ele confere a assinatura `X-Sellume-Signature` de cada aviso.\nO endereço precisa ser HTTPS público.\n\nReferência: https://docs.sellume.com.br/referencia#cadastrarAviso",
            "body": {
              "mode": "raw",
              "raw": "{\n  \"url\": \"https://erp.exemplo.com.br/webhooks/sellume\",\n  \"eventos\": [\n    \"geracao.concluida\",\n    \"geracao.falhou\",\n    \"creditos.baixos\"\n  ],\n  \"descricao\": \"Produção\"\n}",
              "options": {
                "raw": {
                  "language": "json"
                }
              }
            }
          },
          "event": [
            {
              "listen": "test",
              "script": {
                "type": "text/javascript",
                "exec": [
                  "const definir = (k, v) => { if (v === undefined || v === null || v === '') return; if (pm.environment.name) pm.environment.set(k, v); else pm.collectionVariables.set(k, v); };",
                  "if (pm.response.code >= 200 && pm.response.code < 300) {",
                  "  const r = pm.response.json();",
                  "  if (r.data) definir('avisoId', r.data.id);",
                  "}"
                ]
              }
            }
          ]
        },
        {
          "name": "Cadastrar ou atualizar um endereço pelo `url` (idempotente)",
          "request": {
            "method": "PUT",
            "header": [
              {
                "key": "Content-Type",
                "value": "application/json"
              }
            ],
            "url": {
              "raw": "{{baseUrl}}/avisos",
              "host": [
                "{{baseUrl}}"
              ],
              "path": [
                "avisos"
              ]
            },
            "description": "Mesmo corpo de `POST /avisos`. Se o endereço ainda não existe neste ambiente, cadastra e responde\n`201` com o `segredo` (mostrado uma única vez). Se já existe, atualiza `eventos` e `descricao` e\nresponde `200` **sem** o segredo. Útil para o ERP reaplicar a configuração sem duplicar endereços.\n\nReferência: https://docs.sellume.com.br/referencia#definirAviso",
            "body": {
              "mode": "raw",
              "raw": "{\n  \"url\": \"https://seu-servidor.com.br/webhooks/sellume\",\n  \"eventos\": [\n    \"produto.conferido\"\n  ],\n  \"descricao\": \"texto\"\n}",
              "options": {
                "raw": {
                  "language": "json"
                }
              }
            }
          },
          "event": [
            {
              "listen": "test",
              "script": {
                "type": "text/javascript",
                "exec": [
                  "const definir = (k, v) => { if (v === undefined || v === null || v === '') return; if (pm.environment.name) pm.environment.set(k, v); else pm.collectionVariables.set(k, v); };",
                  "if (pm.response.code >= 200 && pm.response.code < 300) {",
                  "  const r = pm.response.json();",
                  "  if (r.data) definir('avisoId', r.data.id);",
                  "}"
                ]
              }
            }
          ]
        },
        {
          "name": "Resultado de um teste de avisos (as três entregas)",
          "request": {
            "method": "GET",
            "header": [],
            "url": {
              "raw": "{{baseUrl}}/testes-de-avisos/{{testeId}}",
              "host": [
                "{{baseUrl}}"
              ],
              "path": [
                "testes-de-avisos",
                "{{testeId}}"
              ]
            },
            "description": "Referência: https://docs.sellume.com.br/referencia#obterTesteAvisos"
          }
        },
        {
          "name": "Disparar o teste de avisos (evento aviso.teste) e conferir a assinatura",
          "request": {
            "method": "POST",
            "header": [],
            "url": {
              "raw": "{{baseUrl}}/avisos/teste",
              "host": [
                "{{baseUrl}}"
              ],
              "path": [
                "avisos",
                "teste"
              ]
            },
            "description": "Envia o evento `aviso.teste` ao endereço indicado (ou a todos os ativos do ambiente) em **três\nentregas** e confere as respostas automaticamente:\n\n1. assinatura correta e carimbo atual → espera **2XX**;\n2. assinatura errada (cabeçalho `X-Sellume-Teste: assinatura_invalida`) → espera **400, 401 ou 403**;\n3. carimbo de horário de 10 minutos atrás, assinatura correta (`X-Sellume-Teste: carimbo_antigo`)\n   → espera **400, 401 ou 403**.\n\nAs três certas marcam a etapa `AVISOS_ASSINATURA` do status da integração. Assim o Sellume sabe\nque o integrador **confere** a assinatura, e não só responde 2XX. O resultado chega em\n`GET /integracao/status` e em `GET /testes-de-avisos/{testeId}` em segundos (a entrega sai na hora; tempo-limite de 5 s por entrega).\n\nReferência: https://docs.sellume.com.br/referencia#testarAvisos"
          },
          "event": [
            {
              "listen": "test",
              "script": {
                "type": "text/javascript",
                "exec": [
                  "const definir = (k, v) => { if (v === undefined || v === null || v === '') return; if (pm.environment.name) pm.environment.set(k, v); else pm.collectionVariables.set(k, v); };",
                  "if (pm.response.code >= 200 && pm.response.code < 300) {",
                  "  const r = pm.response.json();",
                  "  if (Array.isArray(r.data) && r.data[0]) definir('testeId', r.data[0].id);",
                  "}"
                ]
              }
            }
          ]
        },
        {
          "name": "Detalhar um endereço de aviso",
          "request": {
            "method": "GET",
            "header": [],
            "url": {
              "raw": "{{baseUrl}}/avisos/{{avisoId}}",
              "host": [
                "{{baseUrl}}"
              ],
              "path": [
                "avisos",
                "{{avisoId}}"
              ]
            },
            "description": "Referência: https://docs.sellume.com.br/referencia#obterAviso"
          }
        },
        {
          "name": "Alterar eventos, descrição ou reativar um endereço desligado",
          "request": {
            "method": "PATCH",
            "header": [
              {
                "key": "Content-Type",
                "value": "application/json"
              }
            ],
            "url": {
              "raw": "{{baseUrl}}/avisos/{{avisoId}}",
              "host": [
                "{{baseUrl}}"
              ],
              "path": [
                "avisos",
                "{{avisoId}}"
              ]
            },
            "description": "Referência: https://docs.sellume.com.br/referencia#atualizarAviso",
            "body": {
              "mode": "raw",
              "raw": "{\n  \"eventos\": [\n    \"produto.conferido\"\n  ],\n  \"descricao\": \"texto\",\n  \"situacao\": \"ativo\"\n}",
              "options": {
                "raw": {
                  "language": "json"
                }
              }
            }
          }
        },
        {
          "name": "Remover um endereço de aviso",
          "request": {
            "method": "DELETE",
            "header": [],
            "url": {
              "raw": "{{baseUrl}}/avisos/{{avisoId}}",
              "host": [
                "{{baseUrl}}"
              ],
              "path": [
                "avisos",
                "{{avisoId}}"
              ]
            },
            "description": "Referência: https://docs.sellume.com.br/referencia#removerAviso"
          }
        },
        {
          "name": "Trocar o segredo de assinatura",
          "request": {
            "method": "POST",
            "header": [],
            "url": {
              "raw": "{{baseUrl}}/avisos/{{avisoId}}/segredo",
              "host": [
                "{{baseUrl}}"
              ],
              "path": [
                "avisos",
                "{{avisoId}}",
                "segredo"
              ]
            },
            "description": "O segredo anterior continua aceito por 24 horas para a troca sem interrupção.\n\nReferência: https://docs.sellume.com.br/referencia#rotacionarSegredoAviso"
          }
        },
        {
          "name": "Listar entregas (inclui as que falharam)",
          "request": {
            "method": "GET",
            "header": [],
            "url": {
              "raw": "{{baseUrl}}/avisos/{{avisoId}}/entregas",
              "host": [
                "{{baseUrl}}"
              ],
              "path": [
                "avisos",
                "{{avisoId}}",
                "entregas"
              ],
              "query": [
                {
                  "key": "pagina",
                  "value": "",
                  "disabled": true,
                  "description": "Número da página, começando em 1."
                },
                {
                  "key": "limite",
                  "value": "",
                  "disabled": true,
                  "description": "Itens por página (padrão 100, máximo 100)."
                },
                {
                  "key": "situacao",
                  "value": "",
                  "disabled": true
                },
                {
                  "key": "evento",
                  "value": "",
                  "disabled": true
                }
              ]
            },
            "description": "Referência: https://docs.sellume.com.br/referencia#listarEntregasAviso"
          },
          "event": [
            {
              "listen": "test",
              "script": {
                "type": "text/javascript",
                "exec": [
                  "const definir = (k, v) => { if (v === undefined || v === null || v === '') return; if (pm.environment.name) pm.environment.set(k, v); else pm.collectionVariables.set(k, v); };",
                  "if (pm.response.code >= 200 && pm.response.code < 300) {",
                  "  const r = pm.response.json();",
                  "  if (Array.isArray(r.data) && r.data[0]) definir('entregaId', r.data[0].id);",
                  "}"
                ]
              }
            }
          ]
        },
        {
          "name": "Reenviar uma entrega agora",
          "request": {
            "method": "POST",
            "header": [],
            "url": {
              "raw": "{{baseUrl}}/avisos/{{avisoId}}/entregas/{{entregaId}}/reenvio",
              "host": [
                "{{baseUrl}}"
              ],
              "path": [
                "avisos",
                "{{avisoId}}",
                "entregas",
                "{{entregaId}}",
                "reenvio"
              ]
            },
            "description": "Reenvia o mesmo evento (mesmo `eventId`), com nova assinatura e novo carimbo de horário.\n\nReferência: https://docs.sellume.com.br/referencia#reenviarEntregaAviso"
          }
        }
      ]
    },
    {
      "name": "Integração",
      "description": "Status da integração (etapas verificadas automaticamente), registro de chamadas e catálogo de erros.",
      "item": [
        {
          "name": "Status da integração (etapas verificadas automaticamente)",
          "request": {
            "method": "GET",
            "header": [],
            "url": {
              "raw": "{{baseUrl}}/integracao/status",
              "host": [
                "{{baseUrl}}"
              ],
              "path": [
                "integracao",
                "status"
              ],
              "query": [
                {
                  "key": "ambiente",
                  "value": "",
                  "disabled": true,
                  "description": "Padrão, o ambiente da credencial usada."
                }
              ]
            },
            "description": "Etapas verificadas **automaticamente** pelo Sellume a partir das chamadas reais (o integrador não\nmarca nada). Quando todas as obrigatórias estão `ok` no ambiente de teste, o acesso de produção\nfica disponível: a chave `sk_live_` só pode ser criada com as etapas aprovadas **ou** com liberação\nmanual do Sellume (e com contrato vigente aprovado). O mesmo quadro aparece no portal do integrador\ne no painel do Sellume.\n\nPara a etapa `LIMITE_429`, uma chamada de teste com o cabeçalho `X-Sellume-Teste: forcar-429`\n(só com `sk_test_`) recebe um `429` com `Retry-After`; a etapa fica `ok` quando a chamada seguinte\nda mesma chave chega depois do tempo pedido.\n\nReferência: https://docs.sellume.com.br/referencia#obterStatusIntegracao"
          }
        },
        {
          "name": "Pedir acesso de produção",
          "request": {
            "method": "POST",
            "header": [],
            "url": {
              "raw": "{{baseUrl}}/integracao/pedido-producao",
              "host": [
                "{{baseUrl}}"
              ],
              "path": [
                "integracao",
                "pedido-producao"
              ]
            },
            "description": "Com todas as etapas obrigatórias do ambiente de teste `ok`, o acesso é liberado na hora\n(`liberacao: automatica`) e o portal permite criar a chave `sk_live_` (sempre com contrato vigente).\nCom etapas pendentes, responde `409` `INTEGRATION_STEPS_PENDING` e `fields` traz uma linha por etapa\nque falta (`campo: etapas`, `codigo` = código da etapa, `mensagem` = como concluir); o Sellume pode liberar\nà mão, com motivo. Repetir depois de liberado devolve o mesmo acesso (idempotente). Acesso suspenso pelo\nSellume responde `403` `FORBIDDEN`. Chave restrita a contas não pede produção (`403`).\nDisponível desde a Fase 3 (11/10/2026); o mesmo pedido existe no portal do integrador.\n\nReferência: https://docs.sellume.com.br/referencia#pedirAcessoProducao"
          }
        },
        {
          "name": "Registro de chamadas (request log) com o \"como corrigir\"",
          "request": {
            "method": "GET",
            "header": [],
            "url": {
              "raw": "{{baseUrl}}/integracao/chamadas",
              "host": [
                "{{baseUrl}}"
              ],
              "path": [
                "integracao",
                "chamadas"
              ],
              "query": [
                {
                  "key": "pagina",
                  "value": "",
                  "disabled": true,
                  "description": "Número da página, começando em 1."
                },
                {
                  "key": "limite",
                  "value": "",
                  "disabled": true,
                  "description": "Itens por página (padrão 100, máximo 100)."
                },
                {
                  "key": "de",
                  "value": "",
                  "disabled": true
                },
                {
                  "key": "ate",
                  "value": "",
                  "disabled": true
                },
                {
                  "key": "status",
                  "value": "",
                  "disabled": true,
                  "description": "Código HTTP exato (ex. 422) ou faixa: 2xx, 4xx, 5xx."
                },
                {
                  "key": "metodo",
                  "value": "",
                  "disabled": true
                },
                {
                  "key": "endpoint",
                  "value": "",
                  "disabled": true,
                  "description": "Modelo do endereço, ex. /galerias ou /contas/{contaId}/produtos/{codigo}."
                },
                {
                  "key": "codigoErro",
                  "value": "",
                  "disabled": true,
                  "description": "Valor de error.type ou de uma pendência (ex. PRODUCT_REQUIREMENTS_NOT_MET)."
                },
                {
                  "key": "contaId",
                  "value": "",
                  "disabled": true
                },
                {
                  "key": "chave",
                  "value": "",
                  "disabled": true,
                  "description": "Identificador público da chave (sk_test_xxxxxxxxxxxx)."
                },
                {
                  "key": "ambiente",
                  "value": "",
                  "disabled": true
                }
              ]
            },
            "description": "Cada chamada à API com data, endpoint, status, código do erro, mensagem, causa, **como corrigir**\ne link da documentação. Retenção: 30 dias. A lista não traz os corpos; use o detalhe.\n\nReferência: https://docs.sellume.com.br/referencia#listarChamadas"
          }
        },
        {
          "name": "Detalhe de uma chamada, com corpo enviado e recebido (mascarados)",
          "request": {
            "method": "GET",
            "header": [],
            "url": {
              "raw": "{{baseUrl}}/integracao/chamadas/{{requestId}}",
              "host": [
                "{{baseUrl}}"
              ],
              "path": [
                "integracao",
                "chamadas",
                "{{requestId}}"
              ]
            },
            "description": "Referência: https://docs.sellume.com.br/referencia#obterChamada"
          }
        },
        {
          "name": "Catálogo de erros e pendências, com \"como corrigir\"",
          "request": {
            "method": "GET",
            "header": [],
            "url": {
              "raw": "{{baseUrl}}/integracao/erros",
              "host": [
                "{{baseUrl}}"
              ],
              "path": [
                "integracao",
                "erros"
              ]
            },
            "description": "Todos os `error.type` da API e todos os códigos de pendência da conferência. Também publicado em docs.sellume.com.br.\n\nReferência: https://docs.sellume.com.br/referencia#listarCatalogoErros"
          }
        },
        {
          "name": "Forçar um 429 (etapa LIMITE_429)",
          "request": {
            "method": "GET",
            "header": [
              {
                "key": "X-Sellume-Teste",
                "value": "forcar-429",
                "description": "Só com chave sk_test_."
              }
            ],
            "url": {
              "raw": "{{baseUrl}}/saldo",
              "host": [
                "{{baseUrl}}"
              ],
              "path": [
                "saldo"
              ]
            },
            "description": "Responde 429 com Retry-After de 5 segundos. Espere esse tempo e faça qualquer outra chamada com a mesma chave: a etapa LIMITE_429 fica verde. https://docs.sellume.com.br/idempotencia-e-limites#teste-429"
          }
        }
      ]
    },
    {
      "name": "OAuth (contas vinculadas)",
      "description": "OAuth2 com PKCE (S256) para o ERP agir na conta Sellume de um vendedor que já é cliente do Sellume. Guia: https://docs.sellume.com.br/autenticacao#oauth2\n\n**Jeito mais fácil: o assistente do próprio Postman.** Na aba Authorization de uma requisição (ou desta pasta), escolha OAuth 2.0 e preencha:\n- Grant type: Authorization Code (With PKCE)\n- Callback URL: {{redirectUri}} (cadastre exatamente este endereço nas redirect_uris do app no portal; o padrão é https://oauth.pstmn.io/v1/callback)\n- Auth URL: https://app.sellume.com.br/oauth/autorizar\n- Access Token URL: {{tokenUrl}}\n- Client ID: {{clientId}} · Client Secret: {{clientSecret}} (app público: deixe vazio)\n- Code Challenge Method: SHA-256 · Code Verifier: deixe o Postman gerar\n- Scope: contas:ler produtos:escrever geracoes:criar\n- State: um valor aleatório\n- Client Authentication: Send as Basic Auth header\n\nClique em Get New Access Token, entre com a conta Sellume do vendedor de teste e autorize.\n\n**Passo a passo manual:** gere code_verifier e code_challenge (exemplos em Node, PHP e Python no guia), abra o link de autorização no navegador, copie o code da volta para a variável {{code}} e o code_verifier para {{codeVerifier}}, e use as requisições abaixo. O código vale 60 segundos e uma vez só.",
      "auth": {
        "type": "noauth"
      },
      "item": [
        {
          "name": "Trocar o código por tokens",
          "event": [
            {
              "listen": "test",
              "script": {
                "type": "text/javascript",
                "exec": [
                  "const definir = (k, v) => { if (v === undefined || v === null || v === '') return; if (pm.environment.name) pm.environment.set(k, v); else pm.collectionVariables.set(k, v); };",
                  "if (pm.response.code >= 200 && pm.response.code < 300) {",
                  "  const r = pm.response.json();",
                  "  definir('accessToken', r.access_token);",
                  "  definir('refreshToken', r.refresh_token);",
                  "}"
                ]
              }
            }
          ],
          "request": {
            "auth": {
              "type": "noauth"
            },
            "method": "POST",
            "header": [
              {
                "key": "Content-Type",
                "value": "application/x-www-form-urlencoded"
              }
            ],
            "body": {
              "mode": "urlencoded",
              "urlencoded": [
                {
                  "key": "grant_type",
                  "value": "authorization_code",
                  "type": "text"
                },
                {
                  "key": "code",
                  "value": "{{code}}",
                  "type": "text",
                  "description": "Recebido em redirect_uri?code=oac_…&state=…"
                },
                {
                  "key": "redirect_uri",
                  "value": "{{redirectUri}}",
                  "type": "text",
                  "description": "Exatamente a mesma da autorização."
                },
                {
                  "key": "code_verifier",
                  "value": "{{codeVerifier}}",
                  "type": "text"
                },
                {
                  "key": "client_id",
                  "value": "{{clientId}}",
                  "type": "text"
                },
                {
                  "key": "client_secret",
                  "value": "{{clientSecret}}",
                  "type": "text",
                  "description": "Só app confidencial (ou use HTTP Basic). App público: remova."
                }
              ]
            },
            "url": {
              "raw": "{{tokenUrl}}",
              "host": [
                "{{tokenUrl}}"
              ]
            },
            "description": "Troca o código (60 segundos, uso único) por access token (1 hora) e refresh token (30 dias, rotativo). Erros: https://docs.sellume.com.br/erros#oauth"
          }
        },
        {
          "name": "Renovar com o refresh token",
          "event": [
            {
              "listen": "test",
              "script": {
                "type": "text/javascript",
                "exec": [
                  "const definir = (k, v) => { if (v === undefined || v === null || v === '') return; if (pm.environment.name) pm.environment.set(k, v); else pm.collectionVariables.set(k, v); };",
                  "if (pm.response.code >= 200 && pm.response.code < 300) {",
                  "  const r = pm.response.json();",
                  "  definir('accessToken', r.access_token);",
                  "  definir('refreshToken', r.refresh_token);",
                  "}"
                ]
              }
            }
          ],
          "request": {
            "auth": {
              "type": "noauth"
            },
            "method": "POST",
            "header": [
              {
                "key": "Content-Type",
                "value": "application/x-www-form-urlencoded"
              }
            ],
            "body": {
              "mode": "urlencoded",
              "urlencoded": [
                {
                  "key": "grant_type",
                  "value": "refresh_token",
                  "type": "text"
                },
                {
                  "key": "refresh_token",
                  "value": "{{refreshToken}}",
                  "type": "text",
                  "description": "Cada uso devolve um novo par e invalida o anterior."
                },
                {
                  "key": "client_id",
                  "value": "{{clientId}}",
                  "type": "text"
                },
                {
                  "key": "client_secret",
                  "value": "{{clientSecret}}",
                  "type": "text",
                  "description": "Só app confidencial (ou use HTTP Basic). App público: remova."
                }
              ]
            },
            "url": {
              "raw": "{{tokenUrl}}",
              "host": [
                "{{tokenUrl}}"
              ]
            },
            "description": "Reusar um refresh já trocado revoga todos os tokens daquela autorização (o vendedor precisa autorizar de novo)."
          }
        },
        {
          "name": "Revogar a autorização",
          "request": {
            "auth": {
              "type": "noauth"
            },
            "method": "POST",
            "header": [
              {
                "key": "Content-Type",
                "value": "application/x-www-form-urlencoded"
              }
            ],
            "body": {
              "mode": "urlencoded",
              "urlencoded": [
                {
                  "key": "token",
                  "value": "{{refreshToken}}",
                  "type": "text",
                  "description": "Access token ou refresh token."
                },
                {
                  "key": "client_id",
                  "value": "{{clientId}}",
                  "type": "text"
                },
                {
                  "key": "client_secret",
                  "value": "{{clientSecret}}",
                  "type": "text",
                  "description": "Só app confidencial (ou use HTTP Basic). App público: remova."
                }
              ]
            },
            "url": {
              "raw": "{{revogarUrl}}",
              "host": [
                "{{revogarUrl}}"
              ]
            },
            "description": "Encerra a autorização inteira. Responde 200 sempre (RFC 7009)."
          }
        },
        {
          "name": "Listar a conta vinculada com o token",
          "request": {
            "auth": {
              "type": "bearer",
              "bearer": [
                {
                  "key": "token",
                  "value": "{{accessToken}}",
                  "type": "string"
                }
              ]
            },
            "method": "GET",
            "header": [],
            "url": {
              "raw": "{{baseUrl}}/contas",
              "host": [
                "{{baseUrl}}"
              ],
              "path": [
                "contas"
              ]
            },
            "description": "Com token OAuth, GET /contas devolve só a conta vinculada (conta_id do token)."
          }
        }
      ]
    }
  ]
}
