SelectwinSelectwin

Criar Produto

POST /v1/products

Cria um produto e suas variantes na mesma requisição (variants[] é obrigatório, com pelo menos uma variante). A precificação de cada variante vai em pricing (veja o modelo de precificação).

Escopo requerido: products:create. Suporta chave de idempotência (X-Idempotency-Key).

Requisição

Shell
curl -X POST "https://api.selectwin.io/v1/products" \
  -H "SelectKey: sk_live_aBcDeFgHiJkLmNoPqRsTuVwXyZ" \
  -H "Content-Type: application/json" \
  -d '{
    "name": "Premium Course",
    "salesPage": "https://loja.com/premium",
    "description": "Curso completo",
    "enabled": true,
    "type": "digital",
    "language": "pt-BR",
    "category": "courses",
    "warrantyDays": 30,
    "externalReference": "SKU-EXT-1",
    "images": ["https://example.com/img1.png"],
    "variants": [
      {
        "name": "Plano Anual",
        "sku": "SKU-001",
        "description": "Acesso por 12 meses",
        "enabled": true,
        "externalReference": "VAR-EXT-1",
        "pricing": {
          "unitPrice": 49900,
          "currency": "BRL",
          "schema": "unit",
          "type": "oneTime",
          "oldPrice": 69900,
          "costPerItem": 12000
        }
      }
    ]
  }'

Campos do produto

CampoTipoObrigatórioDescrição
namestringSimNome do produto (máx. 40 caracteres)
categorystringSimCategoria de negócio (1–100 caracteres)
warrantyDaysintegerSimDias de garantia (7–3650)
typestringSimphysical, digital ou other
variants[]arraySimVariantes do produto (1 a 100), cada uma com pricing
languagestringNãoIdioma, até 10 caracteres (default pt-BR)
enabledbooleanNãoAtivo (default true)
salesPagestring (url)NãoPágina de vendas (até 255 caracteres)
descriptionstringNãoDescrição (até 400 caracteres)
externalReferencestringNãoSua referência externa (até 255 caracteres)
images[]arrayNãoURLs de imagens (até 10) — ver Imagens abaixo
fiscalobject | nullNãoO perfil fiscal — o que vai na nota fiscal da venda quando a loja emite nota (ver Perfil fiscal abaixo); null limpa

Campos da variante (variants[])

CampoTipoObrigatórioDescrição
namestringSimNome da variante (1–255 caracteres)
pricingobjectSimVeja campos de pricing. type e schema são imutáveis depois de criados
descriptionstringNãoDescrição (até 255 caracteres)
skustringNãoSKU (até 50 caracteres)
images[]arrayNãoURL de imagem (no máximo 1) — ver Imagens abaixo
metadataobjectNãoPares chave/valor livres
attributesobjectNãoAtributos livres da variante
externalReferencestringNãoSua referência externa (até 255 caracteres)
enabledbooleanNãoAtivo (default true)
fiscalobject | nullNãoO que a variante muda no perfil fiscal do produto (tipicamente o gtin); mesmo formato

Perfil fiscal (fiscal)

Quando a loja emite nota fiscal ao comprador (o app Notas Fiscais, com o Notazz ou o eNotas), cada venda vira uma NFS-e (serviço) ou uma NF-e (mercadoria) com estes dados. Tudo é opcional: o que faltar sai dos padrões do app ou do cadastro no painel do emissor. A variante completa o produto.

CampoTipoDescrição
kindstringservice (NFS-e) ou goods (NF-e). Sem ele: produto physical é mercadoria, os outros são serviço
ncmstringNCM, 8 dígitos (mercadoria)
ceststringCEST, 7 dígitos
gtinstringGTIN/EAN — 8, 12, 13 ou 14 dígitos
originintegerOrigem da mercadoria, 0 a 8 (0 = nacional)
unitstringUnidade comercial (UN, KG, CX…), até 6 caracteres
cClassTribstringClassificação tributária do IBS/CBS, 6 dígitos
serviceCodestringItem da lista de serviços da LC 116 (01.07 ou 0107)
cityServiceCodestringCódigo do serviço na prefeitura, até 20 caracteres
nbsstringNBS, 9 dígitos (serviço)

O CFOP não vai no produto: depende da venda (mesmo estado ou outro) e fica nos padrões do app. Campo desconhecido é recusado.

Imagens

images[] aceita somente URL — no produto e na variante. Mandar o arquivo embutido ({"name": "foto.jpg", "base64": "..."}) responde 422, com a mensagem apontando o caminho certo.

Para anexar um arquivo, use o fluxo de upload presigned e mande a URL do asset confirmado:

Texto
1. POST /v1/assets/uploads              → { uploadUrl, asset: { id } }
2. PUT  <uploadUrl>  com o header Content-Type igual ao contentType pedido (o arquivo, direto no storage — não passa por esta API)
3. POST /v1/assets/uploads/{assetId}/confirm  → { url }
4. POST /v1/products  com  "images": ["<url do passo 3>"]

Detalhes, tetos de tamanho e o campo byteSize: Assets.

Uma URL externa (fora do nosso CDN) também é aceita: ela é baixada e re-hospedada no nosso storage de forma assíncrona, e a URL gravada passa a ser a nossa.

A imagem não se herda

images é de cada recurso. Mandar a imagem no produto não põe imagem em nenhuma variante: a variante que não declara images é gravada com null, e é isso que GET /v1/products/{id}, GET /v1/variants e os webhooks product.created e variant.created devolvem. Se você quer a variante com foto, mande images também dentro dela (no máximo 1).

Resposta 201 Created

Retorna o produto completo com suas variantes (mesmo formato de Consultar):

JSON
{
  "id": "prd_01hqzvabc",
  "name": "Premium Course",
  "slug": "premium-course",
  "salesPage": "https://loja.com/premium",
  "description": "Curso completo",
  "language": "pt-BR",
  "enabled": true,
  "salesQty": null,
  "type": "digital",
  "category": "courses",
  "externalReference": "SKU-EXT-1",
  "warrantyDays": 30,
  "images": ["https://example.com/img1.png"],
  "imageAssetIds": null,
  "createdAt": "2026-04-12T17:56:33.000Z",
  "updatedAt": "2026-04-12T17:56:33.000Z",
  "variants": [
    {
      "id": "var_01hqzvabc",
      "productId": "prd_01hqzvabc",
      "name": "Plano Anual",
      "slug": "plano-anual",
      "description": "Acesso por 12 meses",
      "sku": "SKU-001",
      "primary": true,
      "enabled": true,
      "pricing": {
        "unitPrice": 49900,
        "oldPrice": 69900,
        "costPerItem": 12000,
        "currency": "BRL",
        "schema": "unit",
        "type": "oneTime"
      },
      "images": null,
      "metadata": null,
      "attributes": null,
      "externalReference": "VAR-EXT-1",
      "checkoutUrl": null,
      "createdAt": "2026-04-12T17:56:33.000Z",
      "updatedAt": "2026-04-12T17:56:33.000Z"
    }
  ]
}

Erros

error.codeHTTPQuando
invalidParameters400Corpo inválido (campo obrigatório ausente, fora de faixa etc.)
invalidPricing422Configuração de pricing inconsistente com o schema/recorrência

Catálogo completo: Códigos de Erro.

Atualizado em 21 de outubro de 2026

Preferências de cookies

Hoje o site usa só cookies essenciais: nenhuma ferramenta de medição ou de anúncios está ligada, e nada é compartilhado com terceiros. Se isso mudar, você decide aqui antes de qualquer coisa ser carregada.

  • Mantêm o site funcionando: segurança, a sua escolha sobre cookies e preferências como a versão da documentação. Não dependem de consentimento.

    Sempre ativos