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.
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:
{
"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:
| Valor | Periodicidade |
|---|---|
ONE_TIME | Cobrança avulsa, sem repetição. |
WEEKLY | Semanal. |
MONTHLY | Mensal. |
QUARTERLY | Trimestral. |
SEMIANNUAL | Semestral. |
YEARLY | Anual. |
- •
recurrenceIntervalmultiplica o intervalo (ex.: 2 com MONTHLY vira bimestral). Mínimo 1, padrão 1. - •
trialDaysdefine 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:
Item com priceId existente: atualiza esse price no lugar.
Item sem priceId: cria um price novo, que ganha link de pagamento automaticamente e volta em newPrices na resposta.
Price já cadastrado que não aparece em nenhum item do array enviado: é excluído.
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
| Rota | O que acontece |
|---|---|
POST /v1/products/:id/archive | Muda 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/:id | Apaga 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:
{
"productId": "prod_xxx",
"archivedAt": "2026-07-14T21:39:36.322Z",
"checkoutsDeactivated": 3
}O que a API de produtos permite
| Operação | Descrição |
|---|---|
| Criar Produto | Cadastra produto e preços (prices[]) juntos; cada price ganha um link de pagamento automaticamente. |
| Listar Produtos | Lista paginada, com filtro por status e busca textual. |
| Buscar Produto | Detalhes do produto com todos os prices vinculados. |
| Atualizar Produto | Altera campos do produto e sincroniza prices[] (cria, atualiza e remove). |
| Remover Produto | Exclusão definitiva, bloqueada quando há assinatura vinculada a algum price. |
| Arquivar Produto | Soft-archive: desativa checkouts ativos do produto, mantém histórico. |
Erros comuns
| code | Status | Quando acontece |
|---|---|---|
INVALID_PRODUCT_DATA | 400 | Corpo 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_DATA | 400 | Um item de prices[] é inválido ao criar o produto (POST /v1/products). Repare no casing exato: é este, não INVALID_PRICE_DATA. |
INVALID_PRICE_DATA | 400 | Um 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_RULER | 400 | messageRuler 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_ENABLED | 403 | Você 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_FOUND | 404 | productId não existe (Buscar, Atualizar, Remover ou Arquivar Produto). |
FORBIDDEN | 401 | O produto existe, mas pertence a outra conta. |
PRODUCT_HAS_SUBSCRIPTIONS | 400 | DELETE bloqueado: algum price deste produto tem assinatura vinculada. Arquive em vez de remover. |