Produtos

Referência

Um produto é o cadastro do que você vende: nome, descrição e as regras de nota fiscal, e-mail e WhatsApp que se aplicam a ele. Este guia explica como produto e preço se relacionam, o que a API faz automaticamente ao criar um price e a diferença real entre arquivar e remover.

Criar um produto já gera link de pagamento. Cada item de prices[] enviado em Criar Produto recebe, por trás dos panos, um checkout (payment link) próprio: a resposta já vem com checkoutId e checkoutUrl por preço.

O que é um produto

O valor cobrado não fica no produto. Cada produto tem uma ou mais entidades price associadas, cada uma com seu próprio priceId, valor, moeda e periodicidade. Um mesmo produto pode ter vários preços simultâneos, como “Mensal” e “Anual” do mesmo plano, cada um com seu próprio link de pagamento.

O campo type do produto (RECURRING ou ONE_TIME, padrão RECURRING) classifica o produto como um todo. Já a periodicidade de cobrança de verdade é definida por price, no campo recurrenceType.

Produto e preços

Em POST /v1/products, você envia o produto e o array prices[] num único payload. A API cria o produto, depois cria cada price separadamente e, para cada um, cria automaticamente um checkout (link de pagamento, prefixo pl_) já configurado com as formas de pagamento e o parcelamento compatíveis com aquele price:

JSON
{
  "productId": "prod_xxx",
  "name": "Plano Premium",
  "prices": [
    {
      "priceId": "price_xxx",
      "amount": 99.90,
      "recurrenceType": "MONTHLY",
      "checkoutId": "pl_xxx",
      "checkoutUrl": "https://app.validapay.com.br/pagamento/pl_xxx"
    }
  ]
}

Quando o price tem trialDays maior que zero, o link gerado automaticamente habilita só creditcard em allowedPaymentMethods. Sem trial, a API libera creditcard, pix e boleto, filtrados pela periodicidade do price.

Tipos de recorrência

Valores aceitos em prices[].recurrenceType:

ValorPeriodicidade
ONE_TIMECobrança avulsa, sem repetição.
WEEKLYSemanal.
MONTHLYMensal.
QUARTERLYTrimestral.
SEMIANNUALSemestral.
YEARLYAnual.
  • recurrenceInterval multiplica o intervalo (ex.: 2 com MONTHLY vira bimestral). Mínimo 1, padrão 1.
  • trialDays define dias de teste antes da primeira cobrança.
  • compareAtPriceé o preço “de”, exibido riscado no checkout para reforçar o desconto do valor atual.

Atualizar produto e preços

PUT /v1/products/:id só altera os campos do produto que você enviar. O array prices[], quando enviado, é tratado como a lista completa de preços desejada:

1

Item com priceId existente: atualiza esse price no lugar.

2

Item sem priceId: cria um price novo, que ganha link de pagamento automaticamente e volta em newPrices na resposta.

3

Price já cadastrado que não aparece em nenhum item do array enviado: é excluído.

Para manter um preço existente sem alterá-lo, inclua o priceId dele no array. Se você enviar prices[] só com o preço novo, os antigos são apagados.

O campo messageRuler (régua de mensagens de WhatsApp) passa por validação própria a cada atualização. Um array vazio ([]) para limpar a régua é sempre aceito; qualquer valor não vazio exige que a conta tenha a automação de WhatsApp habilitada, senão a API responde 403 WHATSAPP_AUTOMATION_NOT_ENABLED.

Arquivar vs. remover

RotaO que acontece
POST /v1/products/:id/archiveMuda o status do produto para archived e desativa (status inactive) todo checkout que estava active e vinculado a um price deste produto. Produto, prices e histórico de cobranças continuam intactos. Não verifica assinaturas vinculadas.
DELETE /v1/products/:idApaga o produto definitivamente. Bloqueado com 400 PRODUCT_HAS_SUBSCRIPTIONS se qualquer price do produto tiver assinatura vinculada.

A resposta de arquivar traz quantos checkouts foram desativados:

JSON
{
  "productId": "prod_xxx",
  "archivedAt": "2026-07-14T21:39:36.322Z",
  "checkoutsDeactivated": 3
}

O que a API de produtos permite

OperaçãoDescrição
Criar ProdutoCadastra produto e preços (prices[]) juntos; cada price ganha um link de pagamento automaticamente.
Listar ProdutosLista paginada, com filtro por status e busca textual.
Buscar ProdutoDetalhes do produto com todos os prices vinculados.
Atualizar ProdutoAltera campos do produto e sincroniza prices[] (cria, atualiza e remove).
Remover ProdutoExclusão definitiva, bloqueada quando há assinatura vinculada a algum price.
Arquivar ProdutoSoft-archive: desativa checkouts ativos do produto, mantém histórico.

Erros comuns

codeStatusQuando acontece
INVALID_PRODUCT_DATA400Corpo do produto não passou na validação (Zod) em Criar Produto ou Atualizar Produto: nome ausente, URL inválida em productUrlPurchased, etc.
INVALID_Price_DATA400Um item de prices[] é inválido ao criar o produto (POST /v1/products). Repare no casing exato: é este, não INVALID_PRICE_DATA.
INVALID_PRICE_DATA400Um item de prices[] é inválido ao atualizar o produto (PUT /v1/products/:id). Mesmo problema do anterior, código com casing diferente por vir de outra rota.
INVALID_MESSAGE_RULER400messageRuler não passou na validação: templateName fora do catálogo, offsetDays maior que 10 dias antes do vencimento, ou dois lembretes no mesmo momento.
WHATSAPP_AUTOMATION_NOT_ENABLED403Você tentou gravar um messageRuler não vazio, mas a conta não tem a automação de WhatsApp habilitada. Enviar [] para limpar a régua continua permitido mesmo sem a permissão.
PRODUCT_NOT_FOUND404productId não existe (Buscar, Atualizar, Remover ou Arquivar Produto).
FORBIDDEN401O produto existe, mas pertence a outra conta.
PRODUCT_HAS_SUBSCRIPTIONS400DELETE bloqueado: algum price deste produto tem assinatura vinculada. Arquive em vez de remover.

Perguntas frequentes

Por que criar um produto já retorna um link de pagamento pronto?
Porque cada item de prices[] enviado em Criar Produto passa, internamente, por uma criação automática de checkout (payment link): a API gera o pl_, grava checkoutId e checkoutUrl no price e devolve os dois já na resposta. Você não precisa chamar POST /v1/checkouts à parte para ter uma URL de pagamento por preço.
Se eu enviar prices[] parcial em Atualizar Produto, o que acontece com os preços que eu não enviei?
Eles são excluídos. PUT /v1/products/:id trata prices[] como a lista completa desejada: item com priceId é atualizado, item sem priceId vira preço novo (e ganha link de pagamento automaticamente), e qualquer price já cadastrado que não apareça no array é deletado. Para manter um preço, inclua o priceId dele no array mesmo sem alterar nada.
Qual a diferença entre arquivar e remover um produto?
Remover (DELETE) apaga o produto e é bloqueado com PRODUCT_HAS_SUBSCRIPTIONS se qualquer price dele tiver assinatura vinculada. Arquivar (POST /archive) não faz essa checagem: muda o status do produto para archived e desativa (status inactive) os checkouts que estavam active e vinculados a um price do produto, mas preserva produto, prices e todo o histórico de cobranças.
Por que o link de pagamento gerado para um preço com trial só aceita cartão?
Quando o price tem trialDays maior que zero, o link de pagamento criado automaticamente para ele habilita só creditcard em allowedPaymentMethods. Para os demais preços (sem trial), a API libera creditcard, pix e boleto, filtrados pela periodicidade do price.
O campo type do produto (RECURRING/ONE_TIME) é a mesma coisa que o recurrenceType do price?
Não. type é uma classificação do produto como um todo (usada, por exemplo, para marcar o tipo de cobrança gerada no checkout transparente) e vem por padrão como RECURRING. recurrenceType vive em cada price e é o que de fato determina a periodicidade de cobrança daquele preço específico.
Essa página foi útil?