SelectwinDOCS
Produtos

Visão geral

O recurso Produtos (Products) é o seu catálogo na Selectwin. Cada produto agrupa uma ou mais Variantes (Variants), e é a variante que carrega o preço e as regras de cobrança — é ela que você referenci

O recurso Produtos (Products) é o seu catálogo na Selectwin. Cada produto agrupa uma ou mais Variantes (Variants), e é a variante que carrega o preço e as regras de cobrança — é ela que você referencia ao criar transações e assinaturas. Use esta página como ponto de partida: ela explica o modelo do objeto, o ciclo de vida e todas as operações disponíveis.

O que é (e por que existe)

Pense em um produto como a "ficha" do que você vende (nome, descrição, imagens, garantia), e nas variantes como as ofertas concretas desse produto, cada uma com seu preço. Um produto "Plano Premium" pode ter as variantes "Mensal", "Anual" e "Vitalício" — mesmo produto, preços e cadências diferentes.

A separação importa porque o produto nunca tem preço; quem tem preço é a variante (no objeto pricing). Isso permite vender o mesmo produto de várias formas sem duplicar o cadastro.

  • Uma variante de cobrança única (pricing.type = oneTime) é o que você cobra em uma Transação avulsa.
  • Uma variante recorrente (pricing.type = recurring) é o que compõe os itens de uma Assinatura.

Nota

Todo produto pertence à conta autenticada pela SelectKey. As respostas de produto não incluem o objeto merchant. Para as regras gerais (autenticação, dinheiro em centavos, datas em UTC, IDs opacos), veja Convenções.

Modelo do objeto Produto

Identificadores: produto usa o prefixo prd_ e variante usa var_. Trate-os como strings opacas — não faça parsing. Valores monetários (unitPrice, oldPrice, costPerItem) são inteiros em centavos (9900 = R$ 99,00) e datas são ISO 8601 em UTC.

{
  "id": "prd_01hqzvabc",
  "enabled": true,
  "name": "Plano Premium",
  "description": "Full access plan",
  "type": "digital",                 // enum: physical | digital | other
  "language": "pt-BR",
  "category": "saas",
  "slug": "plano-premium",
  "images": ["https://cdn.selectwin.io/p/img1.png"],
  "warrantyDays": 30,                // dias de garantia (7..3650)
  "externalReference": "PROD-EXT-1", // sua referência no seu sistema
  "variants": [ /* ver modelo da variante abaixo */ ],
  "createdAt": "2026-04-12T17:56:33.000Z",
  "updatedAt": "2026-04-12T17:56:33.000Z"
}

Campos do produto

CampoTipoDescrição
idstringIdentificador público (prd_...), opaco
namestringNome do produto
slugstringIdentificador legível para URLs
typestringphysical | digital | other
languagestringCódigo de idioma (ex.: pt-BR)
categorystringCategoria de negócio
salesPagestring (url)Página de vendas
imagesarrayURLs de imagens
warrantyDaysintegerDias de garantia (faixa 7..3650)
salesQtyintegerQuantidade vendida (somente leitura; aparece em listagens)
enabledbooleanSe o produto está ativo/vendável
externalReferencestringSua referência externa de catálogo
variantsarrayVariantes do produto, cada uma com pricing
createdAt / updatedAtstring (date-time)Carimbos ISO 8601 UTC

Em listagens (GET /v1/products), os itens são projeções leves: trazem campos como id, name, slug, category, salesQty, enabled, images, type e os timestamps — mas não trazem variants. Para o produto completo com variantes, use Consultar produto.

Modelo do objeto Variante

A variante é onde mora o preço. Modelo completo (como retornado em Consultar variante):

{
  "id": "var_01hqzvabc",
  "productId": "prd_01hqzvabc",
  "name": "Mensal",
  "enabled": true,
  "description": "Monthly billing",
  "sku": "SKU-M",
  "pricing": {
    "unitPrice": 9900,            // centavos (500..200000000)
    "currency": "BRL",            // ISO 4217; hoje só BRL
    "schema": "unit",             // como o preço é calculado (só "unit")
    "type": "recurring",          // oneTime | recurring
    "oldPrice": 14900,            // preço "de" (riscado), centavos
    "costPerItem": 5000,          // custo (COGS), centavos — para margem
    "billingType": "prepaid",     // prepaid | postpaid | exactday
    "billingFrequency": "monthly",// daily | weekly | monthly | yearly
    "billingFrequencyCount": 1,   // multiplicador da frequência
    "billingExactDay": 10,        // dia do mês quando billingType=exactday
    "cycles": 12,                 // nº de ciclos (null = infinito)
    "trialInterval": "day",       // day | week | month | year
    "trialIntervalCount": 7,      // duração do trial
    "daysTrial": 7               // trial em dias (derivado, leitura)
  },
  "images": ["https://cdn.selectwin.io/v/var.png"],
  "metadata": { "tier": "pro" },
  "attributes": {},
  "externalReference": "VAR-EXT-1",
  "createdAt": "2026-04-12T17:56:33.000Z",
  "updatedAt": "2026-04-12T17:56:33.000Z"
}

Campos de pricing

CampoAplica aTipo / enumDescrição
unitPriceambosinteger, 500..200000000Preço unitário em centavos (obrigatório)
currencyambosenum ["BRL"]ISO 4217 (obrigatório)
schemaambosenum ["unit"]Como o preço é calculado. Hoje só unit. Imutável
typeambosenum ["oneTime","recurring"]Natureza da cobrança. Default oneTime. Imutável
oldPriceambosinteger, 500..200000000Preço "de" (riscado/promocional), em centavos
costPerItemambosinteger, 0..200000000Custo do item (COGS) em centavos, base para margem no analytics. Pode ser 0
billingTyperecurringenum ["prepaid","postpaid","exactday"]Tipo de cobrança recorrente. Obrigatório quando type=recurring
billingFrequencyrecurringenum ["daily","weekly","monthly","yearly"]Unidade da cadência. Obrigatório quando type=recurring
billingFrequencyCountrecurringinteger, 1..999Multiplicador da frequência (ex.: monthly + 3 = trimestral). Obrigatório quando type=recurring
billingExactDayrecurringinteger, 1..31Dia fixo de cobrança, usado quando billingType=exactday
cyclesrecurringinteger, 1..999Total de ciclos. Omitir/null = infinito
trialIntervalrecurringenum ["day","week","month","year"]Unidade do período de teste
trialIntervalCountrecurringinteger, 1..365Duração do trial (ex.: 2 + week = 2 semanas)

O trial é bidimensional: combine trialInterval (unidade) com trialIntervalCount (quantidade). O campo daysTrial aparece apenas na leitura como a duração equivalente em dias — não o envie ao criar/atualizar.

Modelo de precificação (dois eixos)

A precificação é organizada em dois eixos independentes, ambos imutáveis depois de criados.

Eixo 1 — pricing.type (natureza da cobrança)

pricing.typeSignificadoOnde é usada
oneTimeCobrança única (default)Transações
recurringCobrança recorrenteAssinaturas
  • Uma variante recurring não pode ser cobrada em transação avulsa → variantRecurringNotAllowedInTransaction (422).
  • Uma variante oneTime não pode entrar em assinatura → oneTimeVariantNotAllowedInSubscription (422).
  • Tentar mudar o type após a criação → pricingTypeImmutable (422).

Eixo 2 — pricing.schema (como o preço é calculado)

pricing.schemaSignificado
unitPreço por unidade (unitPrice × quantity)

Hoje só existe unit. Tentar mudar o schema após a criação → pricingSchemaImmutable (422).

Ciclo de vida

Um produto e suas variantes são criados juntos, vivem sendo editados (com a ressalva dos campos imutáveis de preço) e podem ser desativados (enabled: false) ou removidos. Desativar é reversível e tira a oferta de circulação sem apagar histórico; excluir é uma ação destrutiva.

Atenção

enabled = false é o caminho reversível para tirar um produto ou variante de venda. DELETE remove o recurso do catálogo — confirme antes que nenhuma assinatura, link de pagamento ou cupom dependa daquela variante.

Operações disponíveis

Produtos

OperaçãoMétodo e caminhoPágina
Criar produto (com variantes inline)POST /v1/productsCriar
Listar produtos (paginado)GET /v1/productsListar
Listar todos (sem paginação leve)GET /v1/products/listallListar
Consultar produto + variantesGET /v1/products/{productId}Consultar
Substituir produto (completo)PUT /v1/products/{productId}Atualizar
Atualizar parcialmentePATCH /v1/products/{productId}Atualizar
Excluir produtoDELETE /v1/products/{productId}Atualizar

Variantes

OperaçãoMétodo e caminhoPágina
Listar variantes de um produtoGET /v1/products/{productId}/variantsVariantes
Adicionar variante a um produtoPOST /v1/products/{productId}/variantsVariantes
Atualizar variante (por id no corpo)PATCH /v1/products/{productId}/variantsVariantes
Listar todas as variantes do produtoGET /v1/products/variants/listallVariantes
Listar todas as variantes (conta)GET /v1/variantsVariantes
Consultar variante por IDGET /v1/variants/{variantId}Variantes
Excluir varianteDELETE /v1/variants/{variantId}Variantes

Há dois "endereços" para variantes: aninhado no produto (/v1/products/{productId}/variants) e no nível da conta (/v1/variants e /v1/variants/{variantId}). A leitura individual e a exclusão usam o caminho de conta com o variantId; a criação e a atualização em lote usam o caminho aninhado no produto.

Exemplo rápido

Criar um produto digital já com uma variante mensal recorrente. Todas as requisições usam o header SelectKey (em produção começa com sl_live_; em sandbox, sl_test_) — nunca Authorization: Bearer/Basic.

curl -X POST https://api.selectwin.io/v1/products \
  -H "SelectKey: sl_live_aBcDeFgHiJkLmNoPqRsTuVwXyZ" \
  -H "Content-Type: application/json" \
  -H "X-Idempotency-Key: prod-create-2026-06-10-001" \
  -d '{
    "name": "Plano Premium",
    "type": "digital",
    "category": "saas",
    "warrantyDays": 30,
    "variants": [
      {
        "name": "Mensal",
        "sku": "SKU-M",
        "pricing": {
          "unitPrice": 9900,
          "currency": "BRL",
          "type": "recurring",
          "billingType": "prepaid",
          "billingFrequency": "monthly",
          "billingFrequencyCount": 1
        }
      }
    ]
  }'

Campos obrigatórios no produto: name, type, category, warrantyDays e ao menos uma variant. Em cada variante, name e pricing são obrigatórios; dentro de pricing, unitPrice e currency sempre, e os campos de billing* quando type=recurring. Detalhes e variações em Criar produto.

Erros específicos do recurso

Trate sempre pelo error.code (estável), não pela message. Os códigos abaixo são os específicos de Produtos & Variantes; os transversais (401 unauthorized, 403 forbidden, 422 unprocessableEntity, 429 tooManyRequests, 500 serverError) também se aplicam.

error.codeHTTPQuando ocorre
productIdNotFound404Produto não encontrado
productIdIsInvalid400ID de produto inválido ou inexistente
variantIdNotFound404Variante não encontrada
variantIdIsInvalid / productVariantIdIsInvalid400ID de variante inválido ou inexistente
productVariantIdIsRequired400ID da variante é obrigatório (ex.: PATCH de variante sem id)
pricingTypeImmutable422Tentou alterar pricing.type após a criação
pricingSchemaImmutable422Tentou alterar pricing.schema após a criação
variantRecurringNotAllowedInTransaction422Variante recurring usada em transação avulsa
productCreationFailed / productDeleteFailed422Falha ao criar / excluir o produto
productCreateLimitReached403Limite de criação de produtos atingido

Catálogo completo e estrutura do envelope: Códigos de Erro e Tratamento de Erros.

Boas práticas

  • Decida o pricing.type e o schema antes de criar — eles são imutáveis. Para "trocar de preço", crie uma nova variante e desative a antiga, em vez de tentar editar o tipo.
  • Use externalReference no produto e na variante para casar com o id do seu próprio catálogo; assim você relaciona seus registros sem depender de parsing de IDs.
  • Modele o trial nos dois campos (trialInterval + trialIntervalCount). Não tente enviar daysTrial — ele é apenas leitura.
  • Desative em vez de excluir quando quiser pausar vendas mantendo histórico e vínculos (enabled: false). Reserve DELETE para limpeza definitiva.
  • Preencha costPerItem se quiser relatórios de margem/lucro corretos no analytics; pode ser 0, mas omiti-lo zera a análise de COGS daquela variante.
  • Envie X-Idempotency-Key em criações e atualizações para que uma repetição (timeout, retry) não gere produtos ou variantes duplicados — veja Idempotência.
  • Para o objeto completo, consulte o recurso individual. As listagens são projeções leves e não trazem variants (no produto) nem todos os campos de pricing.

Veja também

How is this guide?

On this page