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?