VipterCentral de Ajuda

Referência da API (v1)

Cada endpoint da API do Vipter com os parâmetros, um exemplo de chamada e de resposta, e a tabela de campos de cada objeto: conta, cliente, assinatura e suas ações, cobrança na assinatura, uso medido (medidores, eventos de uso, itens e períodos), pedido, oferta, produto, sessão de checkout, sessão do portal do cliente, eventos e endpoints de webhook.

Admin ou DonoTodos os planos

Todos os endpoints ficam em https://api.vipter.com/v1, pedem uma chave de API e seguem as convenções: dinheiro em inteiros na menor unidade, datas em segundos Unix, moeda em minúsculas, listas paginadas por cursor. Os endpoints GET pedem o escopo read; os POST e DELETE pedem o escopo write e aceitam uma Idempotency-Key, que a cobrança na assinatura exige.

A descrição legível por máquina, em OpenAPI 3.1, está em GET https://api.vipter.com/v1/openapi.json. Ela serve para gerar clientes. Uma coleção Postman gerada dela, com uma pasta por recurso e corpos de exemplo, está em GET https://api.vipter.com/v1/postman.json; importa no Postman, no Bruno e no Insomnia. Para agentes de IA, veja Integrar com agentes de IA.

Os exemplos usam IDs fictícios e valores em reais. O Authorization foi encurtado para vk_live_….

Conta

Consultar a conta

GET /v1/account

Devolve a loja e a chave que fizeram a chamada. É a primeira chamada de uma integração nova: se ela responde 200, a chave está certa e a API está liberada.

curl https://api.vipter.com/v1/account \
  -H "Authorization: Bearer vk_live_…"
{
  "id": "a3f1c2d4-5e6f-4a7b-8c9d-0e1f2a3b4c5d",
  "object": "account",
  "name": "Loja Demo",
  "slug": "loja-demo",
  "country": "BR",
  "currency": "brl",
  "timezone": "America/Sao_Paulo",
  "api_key": {
    "id": "ak_4f8e2c1a9b7d6e5f3a2b1c0d",
    "name": "ERP",
    "scopes": ["read"],
    "default_version": "2026-11-01"
  },
  "api_version": "2026-11-01",
  "livemode": true
}
CampoTipoConteúdo
idtextoID da loja no Vipter.
name, slugtextoNome e slug da loja. slug é null se a loja não tem um.
countrytextoPaís da loja, ISO 3166-1 alfa-2.
currencytextoMoeda padrão da loja.
timezonetextoFuso horário da loja, no formato IANA.
api_keyobjetoA chave usada: id, name, scopes (read, write) e default_version, a versão da API que a chave usa quando a chamada não envia Vipter-Version.
api_versiontextoA versão usada nesta chamada.
livemodebooleanotrue em produção.

Clientes

Um cliente é quem comprou ou assinou na loja. Ele é criado pelo checkout, pela equipe no painel ou por POST /v1/customers.

Listar clientes

GET /v1/customers
ParâmetroTipoConteúdo
emailtextoSó clientes com esse e-mail, sem diferenciar maiúsculas.
limit, starting_after, ending_beforePaginação.
curl "https://api.vipter.com/v1/customers?email=ana@example.com" \
  -H "Authorization: Bearer vk_live_…"
{
  "object": "list",
  "url": "https://api.vipter.com/v1/customers",
  "has_more": false,
  "data": [
    {
      "id": "cust_9d2e4f6a8b1c3d5e",
      "object": "customer",
      "email": "ana@example.com",
      "name": "Ana Souza",
      "phone": "+5511999990000",
      "document": { "type": "cpf", "number_masked": "*******1234" },
      "address": {
        "line1": "Rua das Flores, 100",
        "line2": "Apto 42",
        "city": "São Paulo",
        "state": "SP",
        "postal_code": "01310-100",
        "country": "BR"
      },
      "country": "BR",
      "locale": "pt-BR",
      "metadata": {},
      "livemode": true,
      "created": 1790186400
    }
  ]
}

Buscar um cliente

GET /v1/customers/{id}
curl https://api.vipter.com/v1/customers/cust_9d2e4f6a8b1c3d5e \
  -H "Authorization: Bearer vk_live_…"

Devolve o objeto customer. Um ID que não existe na loja recebe 404 resource_missing.

Criar um cliente

POST /v1/customers

Cria o cliente na loja antes da primeira compra, para abrir uma sessão de checkout com customer ou para gravar metadata. Pede o escopo write. O provedor de pagamento exige nome completo, telefone e documento, por isso eles são obrigatórios aqui.

ParâmetroTipoConteúdo
emailtextoObrigatório. Guardado em minúsculas.
nametextoObrigatório. Nome completo, de 3 a 120 caracteres.
phonetextoObrigatório. Em formato internacional (+5511999990000), ou um número nacional do país da loja. Um número que não é válido para o país recebe 400 parameter_invalid com param phone.
document[type], document[number]textoObrigatório. type é cpf, cnpj, passport ou tax_id; number pode vir com pontos e traços, que são removidos.
addressobjetoEndereço de cobrança: line1, city, state, postal_code e country (ISO 3166-1 alfa-2) obrigatórios dentro do objeto; line2, number e district opcionais.
metadataobjetoDados livres, com os mesmos limites do metadata das sessões de checkout.
curl -X POST https://api.vipter.com/v1/customers \
  -H "Authorization: Bearer vk_live_…" \
  -H "Idempotency-Key: 2a7c0e4b-9d1f-4b3a-8e6c-5f2d7a1b0c9e" \
  -H "Content-Type: application/json" \
  -d '{
    "email": "ana@example.com",
    "name": "Ana Souza",
    "phone": "+5511999990000",
    "document": { "type": "cpf", "number": "123.456.789-09" },
    "metadata": { "user_id": "user_8213" }
  }'

A resposta é o objeto customer, com 201 quando o cliente foi criado. Se já existe um cliente com esse e-mail na loja, a resposta é 200 com o cliente existente, sem alterar nenhum campo: para mudar os dados, use Alterar um cliente. Um cliente novo gera o evento customer.created.

codeHTTPSignificado
parameter_missing, parameter_invalid400Campo obrigatório ausente ou com formato errado. param diz qual.
customer_rejected400O provedor de pagamento recusou o cadastro. A message traz o motivo informado por ele, como um documento inválido.

Alterar um cliente

POST /v1/customers/{id}

Aceita os mesmos campos de Criar um cliente, todos opcionais. Só o que vier é alterado, com uma exceção: metadata substitui o mapa inteiro, como na Stripe. Para apagar uma chave, envie o mapa sem ela. Um ID que não existe recebe 404 resource_missing antes de qualquer alteração.

curl -X POST https://api.vipter.com/v1/customers/cust_9d2e4f6a8b1c3d5e \
  -H "Authorization: Bearer vk_live_…" \
  -H "Content-Type: application/json" \
  -d '{ "metadata": { "user_id": "user_8213", "plan": "pro" } }'

Devolve o objeto customer atualizado e gera o evento customer.updated. Os erros são os mesmos da criação.

O objeto customer

CampoTipoConteúdo
idtextocust_…
objecttexto"customer"
emailtextoE-mail do cliente. É o que identifica a pessoa no checkout e na área do cliente.
nametexto ou nullNome informado no checkout.
phonetexto ou nullTelefone em formato internacional, com + e o código do país.
documentobjeto ou nulltype (como cpf ou cnpj) e number_masked, só com os últimos quatro dígitos. A API nunca devolve o documento inteiro.
addressobjeto ou nullEndereço de cobrança: line1, line2, city, state, postal_code, country. Cada campo pode ser null.
countrytexto ou nullPaís do cliente, ISO 3166-1 alfa-2.
localetexto ou nullIdioma do cliente, como pt-BR, en ou es.
metadataobjetoOs dados gravados por POST /v1/customers ou POST /v1/customers/{id}. {} nos clientes criados pelo checkout ou pelo painel. O metadata de uma sessão de checkout vai para o pedido e para a assinatura, não para o cliente.
livemodebooleanotrue em produção.
createdinteiroQuando o cliente foi criado.

Assinaturas

Listar assinaturas

GET /v1/subscriptions
ParâmetroTipoConteúdo
customertextoSó assinaturas desse cliente (cust_…).
statustextoUm de trialing, active, past_due, paused, canceled, expired. Outro valor recebe 400 parameter_invalid.
limit, starting_after, ending_beforePaginação.
curl "https://api.vipter.com/v1/subscriptions?status=active&limit=1" \
  -H "Authorization: Bearer vk_live_…"
{
  "object": "list",
  "url": "https://api.vipter.com/v1/subscriptions",
  "has_more": true,
  "data": [
    {
      "id": "sub_3c7a9e1f5b2d8c4e",
      "object": "subscription",
      "status": "active",
      "customer": "cust_9d2e4f6a8b1c3d5e",
      "customer_email": "ana@example.com",
      "offer": { "id": "ofr_6e2b8d4f1a9c3e7b", "name": "Plano Pro mensal" },
      "product": { "id": "prd_1a5c9e3b7d2f6a8c", "name": "Plano Pro" },
      "billing_cycle": "monthly",
      "custom_billing_days": null,
      "currency": "brl",
      "amount": 9900,
      "current_period_start": 1790186400,
      "current_period_end": 1792778400,
      "next_billing_at": 1792778400,
      "trial_start": null,
      "trial_end": null,
      "cycles_completed": 1,
      "cycle_limit": null,
      "cancel_at_period_end": false,
      "canceled_at": null,
      "ended_at": null,
      "cancellation_details": null,
      "default_payment_method": { "id": "pm_8f3d1c7e2a5b9d4f", "type": "card" },
      "installments": null,
      "past_due_details": null,
      "checkout_session": "cs_4b7e2d9a1c3f5e8b0d2a6c4e1f3b",
      "client_reference_id": "user_8213",
      "metadata": { "plan": "pro" },
      "livemode": true,
      "created": 1790186400
    }
  ]
}

Buscar uma assinatura

GET /v1/subscriptions/{id}
curl https://api.vipter.com/v1/subscriptions/sub_3c7a9e1f5b2d8c4e \
  -H "Authorization: Bearer vk_live_…"

Devolve o objeto subscription.

O objeto subscription

CampoTipoConteúdo
idtextosub_…
objecttexto"subscription"
statustextotrialing (em teste grátis), active, past_due (a última cobrança falhou e o Vipter está tentando de novo), paused, canceled, expired (chegou ao limite de ciclos ou ao fim sem renovar).
customertexto ou nullcust_… do assinante.
customer_emailtexto ou nullE-mail do assinante, para não precisar de outra chamada.
offerobjeto ou nullA oferta atual: id (ofr_…) e name.
productobjeto ou nullO produto: id (prd_…) e name.
billing_cycletexto ou nullO intervalo de cobrança: daily, biweekly, monthly, quarterly, half_yearly, yearly ou custom.
custom_billing_daysinteiro ou nullCom billing_cycle custom, o intervalo em dias.
currencytexto ou nullMoeda da assinatura.
amountinteiro ou nullValor de cada cobrança, na menor unidade.
current_period_start, current_period_endinteiro ou nullO período já pago.
next_billing_atinteiro ou nullQuando a próxima cobrança está prevista. null quando não há próxima.
trial_start, trial_endinteiro ou nullO período de teste grátis, se houve.
cycles_completedinteiroQuantas cobranças já foram feitas.
cycle_limitinteiro ou nullQuantas cobranças a assinatura faz no total, nas ofertas com número fixo de ciclos. null é sem limite.
cancel_at_period_endbooleanotrue quando o cancelamento foi agendado para o fim do período pago. O status continua active até lá.
canceled_atinteiro ou nullQuando o cancelamento foi pedido.
ended_atinteiro ou nullQuando a assinatura deixou de valer.
cancellation_detailsobjeto ou nullreason (código do motivo), comment (texto livre) e source: quem cancelou, como o painel, a área do cliente ou o provedor.
default_payment_methodobjeto ou nullO cartão salvo que paga as renovações: id e type (card). null quando a assinatura paga por PIX ou outro meio sem cartão salvo.
installmentsinteiro ou nullEm quantas parcelas cada cobrança é feita, quando a oferta permite.
past_due_detailsobjeto ou nullSó com status past_due: attempts (quantas tentativas já falharam), next_retry_at e since (quando a primeira falhou).
checkout_sessiontexto ou nullcs_… da sessão de checkout que criou a assinatura. null nas assinaturas vindas de um link comum ou do painel.
client_reference_idtexto ou nullO seu identificador, copiado do client_reference_id da sessão de checkout ou gravado por POST /v1/subscriptions/{id}.
metadataobjetoO subscription_data[metadata] da sessão de checkout ou, quando ele não veio, o metadata da sessão; ou o que você gravou por POST /v1/subscriptions/{id}. {} nas outras assinaturas.
livemodebooleanotrue em produção.
createdinteiroQuando a assinatura começou.

Ações na assinatura

As mesmas ações que a equipe faz na página da assinatura no painel, e que o assinante faz na área do cliente. Todas pedem o escopo write, aceitam uma Idempotency-Key e devolvem o objeto subscription já atualizado: leia status, cancel_at_period_end, offer e next_billing_at na resposta em vez de esperar o webhook. O evento correspondente sai do mesmo jeito que numa ação pelo painel; veja o catálogo de eventos.

Um ID que não existe na loja recebe 404 resource_missing. Uma ação que não cabe no estado atual da assinatura, como pausar uma assinatura já pausada ou retomar uma que não está pausada, recebe 400 provider_error, com o motivo na message.

Alterar uma assinatura

POST /v1/subscriptions/{id}

Grava a sua referência e o metadata na assinatura, ou agenda o cancelamento para o fim do período pago, como o cancel_at_period_end da Stripe.

ParâmetroTipoConteúdo
client_reference_idtexto ou nullO seu identificador, até 200 caracteres. null apaga.
metadataobjetoSubstitui o mapa inteiro, como na Stripe. Para apagar uma chave, envie o mapa sem ela. Mesmos limites do metadata das sessões de checkout.
cancel_at_period_endbooleanotrue agenda o cancelamento: o status continua active até current_period_end, e a assinatura não renova. false é recusado com 400 parameter_invalid: para desfazer um cancelamento agendado, chame POST …/reactivate.
cancellation_details[reason]textoCom cancel_at_period_end: true: o motivo, um de too_expensive, not_using, missing_features, switching, temporary, other. Outro valor é ignorado.
cancellation_details[comment]textoCom cancel_at_period_end: true: um comentário livre, até 500 caracteres.
curl -X POST https://api.vipter.com/v1/subscriptions/sub_3c7a9e1f5b2d8c4e \
  -H "Authorization: Bearer vk_live_…" \
  -H "Content-Type: application/json" \
  -d '{
    "cancel_at_period_end": true,
    "cancellation_details": { "reason": "switching", "comment": "Vai migrar para o plano anual em janeiro." }
  }'

Devolve o objeto subscription com cancel_at_period_end: true e cancellation_details com o motivo e o comentário. Alterar client_reference_id ou metadata não gera evento, e agendar o cancelamento também não: o objeto aparece com cancel_at_period_end: true no próximo evento da assinatura e, quando o período termina, sai customer.subscription.deleted. Quando a chamada traz a referência e o agendamento juntos, a referência é gravada primeiro; se o agendamento for recusado, ela já ficou salva.

Cancelar agora

DELETE /v1/subscriptions/{id}

Cancela na hora, sem esperar o fim do período pago, como o DELETE da Stripe. O motivo vai na query string, com os mesmos valores de Alterar uma assinatura.

curl -X DELETE "https://api.vipter.com/v1/subscriptions/sub_3c7a9e1f5b2d8c4e?cancellation_details[reason]=not_using" \
  -H "Authorization: Bearer vk_live_…"

Devolve o objeto subscription com status: "canceled" e gera customer.subscription.deleted (subscription.cancelled no catálogo original). Em cancellation_details, o source de um cancelamento pela API vem como dashboard, o mesmo valor de um cancelamento pela equipe. O assinante recebe os mesmos avisos de um cancelamento pelo painel.

Pausar e retomar

POST /v1/subscriptions/{id}/pause
POST /v1/subscriptions/{id}/resume

Pausar interrompe as renovações sem cancelar; retomar volta a cobrar. O corpo de pause aceita reason, um texto livre de até 200 caracteres que fica no histórico da assinatura; resume não tem corpo.

curl -X POST https://api.vipter.com/v1/subscriptions/sub_3c7a9e1f5b2d8c4e/pause \
  -H "Authorization: Bearer vk_live_…" \
  -H "Content-Type: application/json" \
  -d '{ "reason": "Cliente pediu uma pausa de dois meses." }'

Devolvem o objeto subscription com status: "paused" e, depois, "active", e geram customer.subscription.paused e customer.subscription.resumed. Uma assinatura pausada não aceita cobranças avulsas.

Reativar

POST /v1/subscriptions/{id}/reactivate

Desfaz um cancelamento agendado (cancel_at_period_end volta a false e a assinatura renova normalmente) ou reativa uma assinatura cancelada ou expirada, quando o provedor de assinaturas permite; uma reativação que ele recusa recebe 400 provider_error. Sem corpo.

curl -X POST https://api.vipter.com/v1/subscriptions/sub_3c7a9e1f5b2d8c4e/reactivate \
  -H "Authorization: Bearer vk_live_…"

Devolve o objeto subscription e gera customer.subscription.updated (subscription.reactivated no catálogo original).

Trocar de oferta

POST /v1/subscriptions/{id}/change_offer

Move a assinatura para outra oferta, como um upgrade do plano mensal para o anual.

ParâmetroTipoConteúdo
offertextoObrigatório. O ofr_… da oferta nova. Só o ID; o slug não é aceito. Uma oferta que não existe na loja recebe 404 resource_missing com param offer.

A oferta nova precisa pertencer ao mesmo produto, ou à mesma família de produtos, da oferta atual; fora disso, a troca é recusada com 400 provider_error.

curl -X POST https://api.vipter.com/v1/subscriptions/sub_3c7a9e1f5b2d8c4e/change_offer \
  -H "Authorization: Bearer vk_live_…" \
  -H "Content-Type: application/json" \
  -d '{ "offer": "ofr_9a4c2e8b6d1f3a7c" }'

Devolve o objeto subscription com offer, amount, billing_cycle e next_billing_at já da oferta nova, e gera customer.subscription.updated (subscription.upgraded ou subscription.downgraded no catálogo original, conforme o valor novo seja maior ou igual, ou menor, que o anterior).

Cobranças na assinatura

Uma cobrança na assinatura é um valor avulso cobrado agora no cartão salvo de uma assinatura, fora do ciclo: um excedente de uso, um adicional, um serviço extra. A data da próxima renovação e o valor recorrente não mudam. É a mesma cobrança que a equipe faz no painel pelo botão Cobrar valor extra… da assinatura (Cobrança avulsa); as duas aparecem na mesma lista, e o campo source diz de onde cada uma veio (API ou Painel na página da assinatura).

A cobrança não pede nada ao assinante: o Vipter cobra o cartão salvo sem o cliente presente, pelo mesmo provedor que fez a primeira cobrança da assinatura. Cada cobrança aprovada vira um pedido pago e conta como um pedido na cota do plano Vipter da loja. O roteiro para cobrar uso num SaaS está em Cobrança adicional por uso.

Cobrar o cartão salvo

POST /v1/subscriptions/{id}/charges

Pede o escopo write e exige uma Idempotency-Key: sem ela, a chamada recebe 400 idempotency_key_required antes de qualquer coisa. Use um valor que identifique a cobrança que você pretende fazer, como o ID do período de uso no seu sistema. A mesma chave nunca cobra duas vezes: ela devolve a mesma cobrança, com 200 e o cabeçalho Idempotent-Replayed: true. Diferente das outras chamadas, a chave de uma cobrança não vence em 24 horas: ela fica ligada à cobrança para sempre, e repeti-la meses depois ainda devolve a mesma cobrança.

ParâmetroTipoConteúdo
amountinteiroObrigatório. O total a cobrar, na menor unidade da moeda (4990 é R$ 49,90). O mínimo é uma unidade da moeda (100 em brl ou usd), senão 400 amount_too_small.
currencytextoOpcional. Precisa ser a moeda da assinatura, senão 400 currency_mismatch. Sem ela, a moeda da assinatura é usada.
descriptiontextoAté 140 caracteres. É a descrição da cobrança enviada ao provedor e, sem lines, o nome do único item do pedido. Sem description, vale a descrição da primeira linha.
lines[]listaDe 1 a 50 itens que explicam o valor; viram os itens do pedido. Cada item: description (obrigatório, até 140 caracteres), quantity (inteiro, padrão 1) e unit_amount (inteiro, na menor unidade). A soma de quantity × unit_amount precisa ser igual a amount, senão 400 lines_total_mismatch. Sem lines, o pedido tem um item só, com description e amount.
metadataobjetoDados livres, com os mesmos limites do metadata das sessões de checkout. Fica na cobrança e volta nos eventos subscription_charge.*.
curl -X POST https://api.vipter.com/v1/subscriptions/sub_3c7a9e1f5b2d8c4e/charges \
  -H "Authorization: Bearer vk_live_…" \
  -H "Idempotency-Key: usage:user_8213:2026-09" \
  -H "Content-Type: application/json" \
  -d '{
    "amount": 5750,
    "currency": "brl",
    "description": "Uso adicional de setembro",
    "lines": [
      { "description": "Chamadas além da franquia", "quantity": 2300, "unit_amount": 2 },
      { "description": "Armazenamento adicional (GB)", "quantity": 23, "unit_amount": 50 }
    ],
    "metadata": { "user_id": "user_8213", "period": "2026-09" }
  }'

A resposta é 201 com o objeto subscription_charge:

{
  "id": "sch_7e2a9c4b1d3f5a6e8b0c2d4f",
  "object": "subscription_charge",
  "status": "succeeded",
  "subscription": "sub_3c7a9e1f5b2d8c4e",
  "customer": "cust_9d2e4f6a8b1c3d5e",
  "amount": 5750,
  "currency": "brl",
  "description": "Uso adicional de setembro",
  "lines": [
    { "description": "Chamadas além da franquia", "quantity": 2300, "unit_amount": 2, "amount": 4600 },
    { "description": "Armazenamento adicional (GB)", "quantity": 23, "unit_amount": 50, "amount": 1150 }
  ],
  "order": "ord_2f8c4e6a1b3d5f7e",
  "transaction": "tx_9b1d3f5a7c2e4a6c",
  "failure_code": null,
  "failure_message": null,
  "source": "api",
  "metadata": { "user_id": "user_8213", "period": "2026-09" },
  "livemode": true,
  "created": 1790790400,
  "settled_at": 1790790403
}

O que acontece com uma cobrança aprovada:

  • Ela vira um pedido com billing_reason: "manual", order_type: "api", recurrence: "unscheduled", subscription preenchido e as lines como itens (kind: "charge"). O sch_… da cobrança fica em external_order_id do pedido.
  • Saem os eventos invoice.paid (com o pedido) e subscription_charge.succeeded (com a cobrança) no catálogo 2026-11-01, e order.paid no original.
  • O assinante recebe o e-mail de confirmação de compra da loja, quando ele está ativo, e vê o pedido na área do cliente.

Uma cobrança que o provedor deixa em análise volta com 201 e status: "pending", sem settled_at. Ela é concluída depois, quando o provedor avisa, e aí passa a succeeded ou failed e gera os eventos. Consulte-a por GET /v1/subscription_charges/{id} ou espere subscription_charge.succeeded / subscription_charge.failed.

Cartão recusado. A resposta é 402 com type card_error, como na Stripe. O code é o código de recusa informado pelo provedor, ou declined quando ele não informa um; os códigos variam por provedor, então não dependa de uma lista fixa. A cobrança recusada vem inteira em error.subscription_charge, com status: "failed", failure_code e failure_message:

{
  "error": {
    "type": "card_error",
    "code": "insufficient_funds",
    "message": "Saldo insuficiente.",
    "doc_url": "https://docs.vipter.com/pt-br/developers/api-conventions#erros",
    "subscription_charge": {
      "id": "sch_7e2a9c4b1d3f5a6e8b0c2d4f",
      "object": "subscription_charge",
      "status": "failed",
      "subscription": "sub_3c7a9e1f5b2d8c4e",
      "customer": "cust_9d2e4f6a8b1c3d5e",
      "amount": 5750,
      "currency": "brl",
      "description": "Uso adicional de setembro",
      "lines": [
        { "description": "Chamadas além da franquia", "quantity": 2300, "unit_amount": 2, "amount": 4600 },
        { "description": "Armazenamento adicional (GB)", "quantity": 23, "unit_amount": 50, "amount": 1150 }
      ],
      "order": "ord_2f8c4e6a1b3d5f7e",
      "transaction": "tx_9b1d3f5a7c2e4a6c",
      "failure_code": "insufficient_funds",
      "failure_message": "Saldo insuficiente.",
      "source": "api",
      "metadata": { "user_id": "user_8213", "period": "2026-09" },
      "livemode": true,
      "created": 1790790400,
      "settled_at": 1790790402
    }
  }
}

Uma recusa gera subscription_charge.failed e, quando o provedor registrou um pedido para a tentativa, invoice.payment_failed com esse pedido (status: "failed"). O Vipter não tenta de novo sozinho: a cobrança fica failed, e repetir a mesma Idempotency-Key devolve o mesmo 402. Para cobrar outra vez, depois de o assinante trocar o cartão na área do cliente, por exemplo, faça uma chamada nova com outra chave.

Erros desta chamada, além dos erros gerais:

codeHTTPSignificado
idempotency_key_required400A chamada veio sem Idempotency-Key. O type é idempotency_error.
resource_missing404A assinatura não existe na loja.
subscription_not_chargeable400A assinatura está paused, canceled ou expired. Só active, trialing e past_due aceitam cobrança.
no_payment_method400A assinatura não tem cartão salvo: paga por PIX ou outro meio sem cartão.
payment_method_not_chargeable400O cartão está guardado num provedor que não aceita cobrança sem o cliente presente. Hoje, o Mercado Pago.
currency_mismatch400currency é diferente da moeda da assinatura. A message diz qual é.
amount_too_small400amount é menor que uma unidade da moeda.
lines_total_mismatch400A soma das linhas não bate com amount. A message traz os dois valores.
provider_error400O provedor recusou o pedido de cobrança antes de chegar ao cartão. A message traz o motivo. A cobrança fica registrada como failed com essa chave; use outra para tentar de novo.
project_inactive403A loja não pode cobrar porque a mensalidade do Vipter está em atraso. O type é permission_error.

Listar as cobranças de uma assinatura

GET /v1/subscriptions/{id}/charges
ParâmetroTipoConteúdo
statustextopending, succeeded ou failed.
limit, starting_after, ending_beforePaginação.
curl "https://api.vipter.com/v1/subscriptions/sub_3c7a9e1f5b2d8c4e/charges?status=succeeded" \
  -H "Authorization: Bearer vk_live_…"

Devolve um objeto list de subscription_charge, da mais nova para a mais antiga, com as cobranças feitas pela API e as feitas no painel.

Buscar uma cobrança

GET /v1/subscription_charges/{id}
curl https://api.vipter.com/v1/subscription_charges/sch_7e2a9c4b1d3f5a6e8b0c2d4f \
  -H "Authorization: Bearer vk_live_…"

Devolve o objeto subscription_charge. É a chamada para acompanhar uma cobrança que ficou pending.

O objeto da cobrança

CampoTipoConteúdo
idtextosch_…
objecttexto"subscription_charge"
statustextopending (em análise no provedor), succeeded (paga) ou failed (recusada, ou o pedido de cobrança foi recusado).
subscriptiontextosub_… da assinatura cobrada.
customertexto ou nullcust_… do assinante.
amountinteiroO total cobrado, na menor unidade.
currencytextoA moeda, em minúsculas: sempre a da assinatura.
descriptiontexto ou nullA descrição enviada, ou a da primeira linha.
lineslistaAs linhas enviadas: description, quantity, unit_amount e amount (unit_amount × quantity). [] quando a cobrança veio sem lines.
ordertexto ou nullord_… do pedido que a cobrança gerou. null quando o provedor não registrou um pedido.
transactiontexto ou nullO ID da transação no provedor de pagamento.
failure_codetexto ou nullCom status failed: o código de recusa do provedor, declined quando ele não informou um, ou o código do erro quando o pedido de cobrança foi recusado.
failure_messagetexto ou nullCom status failed: o motivo, no texto do provedor.
sourcetextoDe onde a cobrança veio: api (esta API), dashboard (o botão do painel) ou usage (cobrança por uso medido, feita pelo Vipter no fechamento de um período).
metadataobjetoO que você enviou. {} nas cobranças feitas no painel.
livemodebooleanotrue em produção.
createdinteiroQuando a cobrança foi pedida.
settled_atinteiro ou nullQuando ela passou a succeeded ou failed. null enquanto pending.

Uso medido

Cobrança por consumo com a conta do lado do Vipter, no formato dos Billing Meters da Stripe: um medidor por tipo de uso, eventos de uso por cliente, um item de uso que dá preço ao medidor na assinatura, e um período por ciclo da assinatura, que fecha e vira uma cobrança na assinatura com source: "usage". O roteiro, com exemplos de preço e o que acontece no fim do ciclo, está em Uso medido (Meters). Os GET pedem o escopo read; os POST e DELETE, o escopo write.

Criar um medidor

POST /v1/billing/meters
ParâmetroTipoConteúdo
display_nametextoObrigatório. Nome do medidor, de 1 a 250 caracteres. Aparece na linha do pedido do comprador.
event_nametextoObrigatório. O nome que os eventos usam: só a-z, 0-9, _, . e -, até 100 caracteres, único na loja. Não muda depois.
default_aggregation[formula]textosum (soma os valores, padrão), count (conta os eventos, ignora o valor) ou last (fica com o último valor do período).
customer_mapping[event_payload_key]textoA chave do payload que traz o cust_… do cliente. Padrão customer_id. customer_mapping[type] só aceita by_id.
value_settings[event_payload_key]textoA chave do payload que traz o valor. Padrão value.
curl -X POST https://api.vipter.com/v1/billing/meters \
  -H "Authorization: Bearer vk_live_…" \
  -H "Content-Type: application/json" \
  -d '{ "display_name": "Chamadas de API", "event_name": "api_calls", "default_aggregation": { "formula": "sum" } }'

A resposta é 201 com o objeto billing.meter. Um event_name que já existe na loja recebe 400 event_name_taken.

Listar medidores

GET /v1/billing/meters
ParâmetroTipoConteúdo
statustextoactive ou inactive.
limitinteiroTamanho da página.

Devolve um objeto list de billing.meter, do mais novo para o mais antigo.

Buscar e alterar um medidor

GET /v1/billing/meters/{id}
POST /v1/billing/meters/{id}

O POST aceita só display_name; os outros campos do medidor não mudam. Um ID que não existe na loja recebe 404 resource_missing.

Desativar um medidor

POST /v1/billing/meters/{id}/deactivate

Sem corpo. O medidor passa a inactive com status_transitions.deactivated_at preenchido, e novos eventos com o seu event_name recebem 400 meter_inactive. Os períodos abertos continuam mostrando a quantidade do medidor, com preço zero. Não há reativação pela API.

O objeto billing.meter

{
  "id": "mtr_4f8e2c1a9b7d6e5f3a2b1c0d",
  "object": "billing.meter",
  "display_name": "Chamadas de API",
  "event_name": "api_calls",
  "default_aggregation": { "formula": "sum" },
  "customer_mapping": { "type": "by_id", "event_payload_key": "customer_id" },
  "value_settings": { "event_payload_key": "value" },
  "status": "active",
  "status_transitions": { "deactivated_at": null },
  "livemode": true,
  "created": 1791100800,
  "updated": 1791100800
}
CampoTipoConteúdo
idtextomtr_…
objecttexto"billing.meter"
display_nametextoO nome do medidor.
event_nametextoO nome que os eventos usam.
default_aggregationobjetoformula: sum, count ou last.
customer_mappingobjetotype (by_id) e event_payload_key, a chave do payload com o cliente.
value_settingsobjetoevent_payload_key, a chave do payload com o valor.
statustextoactive ou inactive.
status_transitionsobjetodeactivated_at: quando o medidor foi desativado, ou null.
livemodebooleanotrue em produção.
created, updatedinteiroCriação e última alteração.

Registrar um evento de uso

POST /v1/billing/meter_events
ParâmetroTipoConteúdo
event_nametextoObrigatório. O event_name do medidor.
payloadobjetoObrigatório. Até 20 chaves com valores texto, número ou booleano. Precisa trazer o cliente na chave do medidor (customer_id por padrão; stripe_customer_id é aceito como apelido) e, fora dos medidores count, o valor numérico na chave do valor (value por padrão). subscription_id escolhe a assinatura quando o cliente tem mais de uma com preço para o medidor.
identifiertextoAté 100 caracteres. Idempotência por medidor: o mesmo identifier devolve o evento já gravado, com 200. Sem ele, o Vipter gera um.
timestampinteiroQuando o uso aconteceu, em segundos Unix: até 35 dias atrás e até 5 minutos à frente. Padrão: agora.
curl -X POST https://api.vipter.com/v1/billing/meter_events \
  -H "Authorization: Bearer vk_live_…" \
  -H "Content-Type: application/json" \
  -d '{ "event_name": "api_calls", "identifier": "req_01J9X3K7M2", "payload": { "customer_id": "cust_9d2e4f6a8b1c3d5e", "value": 1 } }'

A resposta é 201 com o objeto billing.meter_event, ou 200 com o evento já gravado quando o identifier se repete. Na chegada, o evento é ligado à assinatura active, trialing ou past_due do cliente que tem um item de uso para o medidor (a mais recente, se houver mais de uma). Um evento sem assinatura é gravado com subscription: null, não é cobrado, e dispara billing.meter.error_report_triggered, no máximo uma vez por medidor e por hora. Veja Eventos sem assinatura.

codeHTTPSignificado
no_meter_found400Nenhum medidor tem esse event_name.
meter_inactive400O medidor foi desativado.
invalid_payload400Falta o cliente, ou o valor não é um número. param diz a chave (payload.customer_id, payload.value).
timestamp_out_of_range400timestamp fora da janela de 35 dias atrás a 5 minutos à frente.
resource_missing404O cliente do payload não existe na loja. param é a chave do cliente.

Registrar eventos em lote

POST /v1/billing/meter_events/batch
ParâmetroTipoConteúdo
events[]listaObrigatório. De 1 a 100 eventos, cada um com os campos de Registrar um evento de uso.
curl -X POST https://api.vipter.com/v1/billing/meter_events/batch \
  -H "Authorization: Bearer vk_live_…" \
  -H "Content-Type: application/json" \
  -d '{
    "events": [
      { "event_name": "api_calls", "identifier": "req_01J9X3K7M2", "payload": { "customer_id": "cust_9d2e4f6a8b1c3d5e", "value": 1 } },
      { "event_name": "api_calls", "identifier": "req_01J9X3K7M3", "payload": { "customer_id": "cust_0000000000000000", "value": 1 } }
    ]
  }'
{
  "object": "billing.meter_event_batch",
  "accepted": 1,
  "duplicates": 0,
  "errors": 1,
  "results": [
    { "status": "accepted", "event": { "id": "mev_1a5c9e3b7d2f6a8c0e4b2d6f", "object": "billing.meter_event", "event_name": "api_calls", "identifier": "req_01J9X3K7M2", "payload": { "customer_id": "cust_9d2e4f6a8b1c3d5e", "value": 1 }, "customer": "cust_9d2e4f6a8b1c3d5e", "subscription": "sub_3c7a9e1f5b2d8c4e", "value": 1, "timestamp": 1791101000, "livemode": true, "created": 1791101000 } },
    { "status": "error", "error": { "code": "customer_not_found", "message": "No such customer: 'cust_0000000000000000'", "param": "payload.customer_id" } }
  ]
}

Cada evento é aceito ou recusado por conta própria, na ordem enviada: results[i] responde events[i] com status accepted (gravado agora), duplicate (o identifier já existia; event é o gravado) ou error (error com code, message e param, os mesmos códigos da chamada unitária, com customer_not_found no lugar de resource_missing). A resposta é 200 sempre que ao menos um evento foi aceito ou repetido, e 400 só quando nenhum entrou. Um lote com um campo inválido no corpo (como events vazio) recebe 400 parameter_invalid sem gravar nada.

O objeto billing.meter_event

CampoTipoConteúdo
idtextomev_…
objecttexto"billing.meter_event"
event_nametextoO medidor.
identifiertextoO seu identifier, ou o gerado pelo Vipter.
payloadobjetoO payload enviado.
customertextocust_… do cliente.
subscriptiontexto ou nullA assinatura em que o evento será cobrado. null quando nenhuma assinatura ativa do cliente tem preço para o medidor.
valuenúmeroO valor do evento. 1 nos medidores count.
timestampinteiroQuando o uso aconteceu. Decide em qual período o evento cai.
livemodebooleanotrue em produção.
createdinteiroQuando o evento chegou.

Consultar o uso agregado de um cliente

GET /v1/billing/meters/{id}/event_summaries
ParâmetroTipoConteúdo
customertextoObrigatório. O cust_….
start_time, end_timeinteiroObrigatórios. O intervalo, em segundos Unix: start_time inclusive, end_time exclusive. end_time precisa ser maior, e o intervalo pode ter até um ano, senão 400 parameter_invalid.
value_grouping_windowtextohour ou day: um resumo por hora ou por dia (em UTC), só dos intervalos que têm eventos. Sem ele, um resumo só.
curl "https://api.vipter.com/v1/billing/meters/mtr_4f8e2c1a9b7d6e5f3a2b1c0d/event_summaries?customer=cust_9d2e4f6a8b1c3d5e&start_time=1790186400&end_time=1792778400&value_grouping_window=day" \
  -H "Authorization: Bearer vk_live_…"
{
  "object": "list",
  "url": "https://api.vipter.com/v1/billing/meters/mtr_4f8e2c1a9b7d6e5f3a2b1c0d/event_summaries",
  "has_more": false,
  "data": [
    { "object": "billing.meter_event_summary", "meter": "mtr_4f8e2c1a9b7d6e5f3a2b1c0d", "customer": "cust_9d2e4f6a8b1c3d5e", "start_time": 1790186400, "end_time": 1790208000, "aggregated_value": 412, "livemode": true },
    { "object": "billing.meter_event_summary", "meter": "mtr_4f8e2c1a9b7d6e5f3a2b1c0d", "customer": "cust_9d2e4f6a8b1c3d5e", "start_time": 1790208000, "end_time": 1790294400, "aggregated_value": 1180, "livemode": true }
  ]
}

aggregated_value aplica a fórmula do medidor (sum, count ou last) aos eventos do cliente no intervalo, ligados ou não a uma assinatura. A lista não é paginada.

Itens de uso de uma assinatura

GET /v1/subscriptions/{id}/usage_items
POST /v1/subscriptions/{id}/usage_items
DELETE /v1/subscriptions/{id}/usage_items/{itemId}

Um item de uso dá preço a um medidor numa assinatura: um item por medidor. Ele nasce da oferta (configurado no painel, na página da oferta) na primeira rodada do uso medido depois de a assinatura ser criada, em até 10 minutos, com source: "offer", ou é definido aqui, com source: "api". Um item definido pela API nunca é sobrescrito pela herança da oferta. O POST do mesmo meter substitui o item.

ParâmetroTipoConteúdo
metertextoObrigatório. O mtr_…. Um medidor que não existe recebe 404 resource_missing.
currencytextoOpcional. Precisa ser a moeda da assinatura, senão 400 currency_mismatch.
unit_amountnúmeroObrigatório. Preço de uma unidade, na menor unidade da moeda, com frações: 0.4 é R$ 0,004. 0 ou mais. Com tiers, não entra no cálculo.
included_unitsnúmeroFranquia: unidades do período que não são cobradas. Padrão 0.
tiers[]listaDe 1 a 20 faixas graduadas sobre as unidades além da franquia, cada uma com up_to (limite superior, inclusive; null na última), unit_amount (por unidade na faixa) e flat_amount (opcional, cobrado uma vez quando a faixa é usada). up_to precisa ser crescente e o último null, senão 400 parameter_invalid com param tiers.
roundingtextoup (para cima, padrão) ou nearest (mais próximo), aplicado ao total da linha, em centavos inteiros.
billing_thresholdinteiroEm centavos. O período fecha e cobra antes do fim do ciclo quando o total acumulado o atinge.
labeltextoAté 120 caracteres, para o seu controle.
curl -X POST https://api.vipter.com/v1/subscriptions/sub_3c7a9e1f5b2d8c4e/usage_items \
  -H "Authorization: Bearer vk_live_…" \
  -H "Content-Type: application/json" \
  -d '{ "meter": "mtr_4f8e2c1a9b7d6e5f3a2b1c0d", "unit_amount": 0.4, "included_units": 10000, "billing_threshold": 20000 }'

O POST responde 201 com o objeto usage_item; o GET devolve um objeto list de usage_item, sem paginação; o DELETE devolve { "id": "usi_…", "object": "usage_item", "deleted": true }, ou 404 resource_missing se o item não é dessa assinatura.

O objeto usage_item

{
  "id": "usi_9d2e4f6a8b1c3d5e7f0a2b4c",
  "object": "usage_item",
  "meter": "mtr_4f8e2c1a9b7d6e5f3a2b1c0d",
  "subscription": "sub_3c7a9e1f5b2d8c4e",
  "offer": null,
  "currency": "brl",
  "unit_amount": 0.4,
  "included_units": 10000,
  "tiers": null,
  "rounding": "up",
  "billing_threshold": 20000,
  "label": null,
  "source": "api",
  "livemode": true,
  "created": 1791100900
}
CampoTipoConteúdo
idtextousi_…
objecttexto"usage_item"
metertextomtr_… do medidor.
subscriptiontextosub_… da assinatura.
offernullReservado. Nos itens de uma assinatura vem sempre null.
currencytextoA moeda, em minúsculas: a da assinatura.
unit_amount, included_units, tiers, rounding, billing_threshold, labelComo enviados. tiers e billing_threshold vêm null quando não há.
sourcetextooffer (herdado da oferta), api ou dashboard.
livemodebooleanotrue em produção.
createdinteiroQuando o item foi criado.

Consultar os períodos de uso

GET /v1/subscriptions/{id}/usage
curl https://api.vipter.com/v1/subscriptions/sub_3c7a9e1f5b2d8c4e/usage \
  -H "Authorization: Bearer vk_live_…"

Devolve um objeto list com os 12 períodos mais recentes da assinatura, do mais novo para o mais antigo, sem paginação. O período open é calculado na hora, a partir dos eventos; os closed vêm como ficaram no fechamento. Uma assinatura sem itens de uso devolve uma lista vazia.

O objeto usage_period

{
  "id": "usp_7b3e9f1c2a8d4e6f0b2d4f6a",
  "object": "usage_period",
  "subscription": "sub_3c7a9e1f5b2d8c4e",
  "status": "closed",
  "close_reason": "period_end",
  "period_start": 1790186400,
  "period_end": 1792778400,
  "currency": "brl",
  "lines": [
    { "meter": "mtr_4f8e2c1a9b7d6e5f3a2b1c0d", "event_name": "api_calls", "quantity": 12300, "included": 10000, "billable": 2300, "unit_amount": 0.4, "amount": 920 }
  ],
  "amount_total": 920,
  "charge": "sch_7e2a9c4b1d3f5a6e8b0c2d4f",
  "computed_at": 1792778700,
  "closed_at": 1792778700,
  "livemode": true,
  "created": 1790187000
}
CampoTipoConteúdo
idtextousp_…
objecttexto"usage_period"
subscriptiontextosub_… da assinatura.
statustextoopen (acumulando), closing (sendo cobrado) ou closed.
close_reasontexto ou nullperiod_end (o ciclo terminou), threshold (atingiu o billing_threshold) ou subscription_ended (a assinatura deixou de ser cobrável). null enquanto aberto.
period_start, period_endinteiroO intervalo do período: o ciclo da assinatura, ou o trecho dele depois de um fechamento por limiar.
currencytextoA moeda, em minúsculas.
lineslistaUma por medidor com item: meter, event_name, quantity (o agregado), included (a franquia), billable (quantity menos included), unit_amount e amount (em centavos).
amount_totalinteiroA soma das linhas, em centavos.
chargetexto ou nullsch_… da cobrança do período, aprovada ou recusada. null enquanto aberto, quando o total foi zero, ou quando a cobrança foi recusada antes de chegar ao cartão.
computed_atinteiro ou nullQuando as linhas foram calculadas. No período aberto, a hora da chamada.
closed_atinteiro ou nullQuando o período fechou.
livemodebooleanotrue em produção.
createdinteiroQuando o período abriu.

Erros do uso medido

Além dos erros gerais:

codeHTTPOndeSignificado
event_name_taken400Criar um medidorJá existe um medidor com esse event_name.
no_meter_found400EventosNenhum medidor tem esse event_name.
meter_inactive400EventosO medidor foi desativado.
invalid_payload400EventosFalta o cliente no payload, ou o valor não é um número.
timestamp_out_of_range400Eventostimestamp fora da janela de 35 dias atrás a 5 minutos à frente.
customer_not_foundLoteSó dentro de results[]: o cliente não existe. Na chamada unitária é 404 resource_missing.
currency_mismatch400Itens de usocurrency é diferente da moeda da assinatura.
parameter_invalid400Itens de uso, resumostiers fora de ordem ou sem a última faixa null; end_time antes de start_time ou intervalo maior que um ano.
resource_missing404TodosMedidor, assinatura, item ou cliente que não existe na loja.

Pedidos

Um pedido é uma cobrança: uma compra avulsa, a primeira cobrança de uma assinatura, uma renovação, uma cobrança avulsa na assinatura feita no painel ou pela API. É o que a Stripe chama de fatura (invoice); o nome segue o que o lojista vê no painel.

Listar pedidos

GET /v1/orders
ParâmetroTipoConteúdo
customertextoSó pedidos desse cliente (cust_…).
subscriptiontextoSó pedidos dessa assinatura (sub_…).
statustextoUm de pending, pre_authorized, authorized, failed, canceled, refund_pending, partially_refunded, refunded, charged_back.
limit, starting_after, ending_beforePaginação.
curl "https://api.vipter.com/v1/orders?subscription=sub_3c7a9e1f5b2d8c4e&limit=1" \
  -H "Authorization: Bearer vk_live_…"
{
  "object": "list",
  "url": "https://api.vipter.com/v1/orders",
  "has_more": true,
  "data": [
    {
      "id": "ord_7b3e9f1c2a8d4e6f",
      "object": "order",
      "status": "authorized",
      "paid": true,
      "status_source": "provider",
      "billing_reason": "subscription_cycle",
      "customer": "cust_9d2e4f6a8b1c3d5e",
      "customer_email": "ana@example.com",
      "subscription": "sub_3c7a9e1f5b2d8c4e",
      "offer": "ofr_6e2b8d4f1a9c3e7b",
      "order_type": "renewal",
      "recurrence": "subsequent",
      "currency": "brl",
      "amount_total": 9900,
      "amount_refunded": 0,
      "amount_discount": 0,
      "amount_shipping": 0,
      "amount_interest": 0,
      "installments": 1,
      "payment_method": "credit_card",
      "provider": "pagarme",
      "coupon_codes": [],
      "lines": [
        {
          "description": "Plano Pro mensal",
          "quantity": 1,
          "unit_amount": 9900,
          "amount": 9900,
          "offer": "ofr_6e2b8d4f1a9c3e7b",
          "product": "prd_1a5c9e3b7d2f6a8c",
          "kind": "main"
        }
      ],
      "shipping": null,
      "external_order_id": null,
      "checkout_session": null,
      "client_reference_id": null,
      "metadata": {},
      "paid_at": 1790790412,
      "livemode": true,
      "created": 1790790400
    }
  ]
}

Buscar um pedido

GET /v1/orders/{id}
curl https://api.vipter.com/v1/orders/ord_7b3e9f1c2a8d4e6f \
  -H "Authorization: Bearer vk_live_…"

Devolve o objeto order.

O objeto order

CampoTipoConteúdo
idtextoord_…
objecttexto"order"
statustextoVeja Status do pedido.
paidbooleanotrue quando o dinheiro entrou, mesmo que depois tenha sido estornado no todo ou em parte. Use status para o detalhe.
status_sourcetextoprovider quando o status veio do provedor de pagamento; manual quando alguém definiu o status no painel.
billing_reasontextoPor que o pedido existe: purchase (compra avulsa), subscription_create (primeira cobrança de uma assinatura), subscription_cycle (renovação), manual (cobrança avulsa numa assinatura, pelo painel ou pela API), usage (cobrança por uso medido, no fechamento de um período).
customer, customer_emailtexto ou nullO comprador.
subscriptiontexto ou nullsub_… quando o pedido pertence a uma assinatura.
offertexto ou nullofr_… da oferta principal do pedido.
order_typetexto ou nullComo o pedido nasceu: checkout, renewal (renovação), api (cobrança iniciada pelo lojista), trial_setup ou card_setup (cadastro de cartão sem cobrança). Pode ganhar valores novos.
recurrencetexto ou nullinitial, subsequent ou unscheduled nos pedidos de assinatura; null nas compras avulsas.
currencytextoMoeda do pedido.
amount_totalinteiroO total cobrado, na menor unidade, com desconto, frete e juros já aplicados.
amount_refundedinteiroQuanto já foi estornado.
amount_discountinteiroO desconto de cupons.
amount_shippinginteiroO frete, em produtos físicos.
amount_interestinteiroOs juros do parcelamento repassados ao comprador.
installmentsinteiro ou nullEm quantas parcelas foi pago.
payment_methodtexto ou nullcredit_card, debit_card, pix, boleto ou wallet.
providertexto ou nullO provedor que processou, como pagarme, stripe, mercadopago ou asaas.
coupon_codeslista de textoOs cupons aplicados.
lineslistaOs itens do pedido. Veja Linhas do pedido.
shippingobjeto ou nullSó em pedidos com entrega: status da entrega, carrier, tracking_code, tracking_url e address, no mesmo formato do endereço do cliente.
external_order_idtexto ou nullUm identificador seu, quando o pedido veio com um. Nos pedidos de uma cobrança na assinatura, o sch_… da cobrança.
checkout_sessiontexto ou nullcs_… da sessão de checkout que gerou o pedido. Só no pedido pago pela sessão: as renovações da assinatura vêm com null, e você as liga ao seu sistema por subscription.
client_reference_idtexto ou nullO seu identificador, copiado do client_reference_id da sessão de checkout.
metadataobjetoO metadata da sessão de checkout. {} nos outros pedidos.
paid_atinteiro ou nullQuando o pagamento foi confirmado.
livemodebooleanofalse quando o pagamento passou por uma conexão de teste do provedor.
createdinteiroQuando o pedido foi criado.

Status do pedido

statuspaidSignificado
pendingfalseAguardando pagamento: PIX gerado e não pago, boleto emitido, cartão em análise.
pre_authorizedfalseValor reservado no cartão, ainda não capturado.
authorizedtruePago.
failedfalseO pagamento foi recusado ou expirou.
canceledfalseCancelado antes de ser pago.
refund_pendingtrueEstorno pedido e ainda não confirmado pelo provedor.
partially_refundedtrueParte do valor foi devolvida. amount_refunded diz quanto.
refundedtrueTodo o valor foi devolvido.
charged_backtrueO comprador contestou a cobrança no banco.

Linhas do pedido

Cada item de lines:

CampoTipoConteúdo
descriptiontexto ou nullO nome do item como apareceu no checkout.
quantityinteiroQuantidade.
unit_amountinteiro ou nullPreço unitário, na menor unidade.
amountinteiro ou nullunit_amount vezes quantity.
offer, producttexto ou nullofr_… e prd_… do item.
kindtextoO papel do item no pedido: main (o item principal), bump (oferta adicional marcada no checkout), composition (linha composta pela equipe num link rápido) ou charge (linha de uma cobrança na assinatura).

Ofertas

Uma oferta é o que o comprador pode pagar: um produto com preço, ciclo de cobrança e condições. É o equivalente ao price da Stripe. Cada oferta tem um link de checkout pronto.

Listar ofertas

GET /v1/offers
ParâmetroTipoConteúdo
producttextoSó ofertas desse produto (prd_…).
activetrue ou falseSó ofertas ativas, ou só as que não estão ativas.
typetextoone_time ou recurring.
limit, starting_after, ending_beforePaginação. Ofertas vêm em ordem alfabética de nome.
curl "https://api.vipter.com/v1/offers?active=true&type=recurring" \
  -H "Authorization: Bearer vk_live_…"
{
  "object": "list",
  "url": "https://api.vipter.com/v1/offers",
  "has_more": false,
  "data": [
    {
      "id": "ofr_6e2b8d4f1a9c3e7b",
      "object": "offer",
      "name": "Plano Pro mensal",
      "slug": "pro-mensal",
      "product": { "id": "prd_1a5c9e3b7d2f6a8c", "name": "Plano Pro" },
      "type": "recurring",
      "billing_cycle": "monthly",
      "custom_billing_days": null,
      "cycle_limit": null,
      "trial_days": 7,
      "setup_charge": false,
      "status": "active",
      "active": true,
      "prices": [
        { "id": "prc_2d8f4a6c1e9b3d7f", "currency": "brl", "unit_amount": 9900, "first_charge_amount": null, "default": true },
        { "id": "prc_7a1c3e5b9d2f4a6c", "currency": "usd", "unit_amount": 1900, "first_charge_amount": null, "default": false }
      ],
      "checkout_url": "https://pay.vipter.com/pro-mensal",
      "livemode": true,
      "created": 1788300000
    }
  ]
}

Buscar uma oferta

GET /v1/offers/{id}
curl https://api.vipter.com/v1/offers/ofr_6e2b8d4f1a9c3e7b \
  -H "Authorization: Bearer vk_live_…"

Devolve o objeto offer.

O objeto offer

CampoTipoConteúdo
idtextoofr_…
objecttexto"offer"
nametextoNome da oferta.
slugtexto ou nullO slug do link de checkout, quando a oferta tem um.
productobjetoid (prd_…) e name do produto.
typetextoone_time (compra avulsa) ou recurring (assinatura).
billing_cycletexto ou nullO intervalo de cobrança nas ofertas recorrentes: daily, biweekly, monthly, quarterly, half_yearly, yearly ou custom. null nas avulsas.
custom_billing_daysinteiro ou nullCom billing_cycle custom, o intervalo em dias.
cycle_limitinteiro ou nullQuantas cobranças a assinatura faz no total. null é sem limite.
trial_daysinteiro ou nullDias de teste grátis. null quando a oferta não tem teste.
setup_chargebooleanotrue quando a primeira cobrança tem um valor diferente das demais (first_charge_amount em prices).
statustextoO status no catálogo, como active ou inactive.
activebooleanotrue quando status é active. Só ofertas ativas aceitam compras.
priceslistaUm preço por moeda: id, currency, unit_amount, first_charge_amount (o valor da primeira cobrança quando é diferente, senão null) e default (a moeda que o checkout usa quando o comprador não escolhe).
checkout_urltexto ou nullO link de checkout da oferta, no domínio próprio da loja quando há um. null quando o link está desligado nas configurações da oferta. Aceita os parâmetros de URL.
livemodebooleanotrue em produção.
createdinteiro ou nullQuando a oferta foi criada.

Produtos

Um produto agrupa ofertas: "Plano Pro" é o produto, "Plano Pro mensal" e "Plano Pro anual" são ofertas dele.

Listar produtos

GET /v1/products
ParâmetroTipoConteúdo
activetrue ou falseSó produtos ativos, ou só os que não estão ativos.
limit, starting_after, ending_beforePaginação.
curl "https://api.vipter.com/v1/products?active=true" \
  -H "Authorization: Bearer vk_live_…"
{
  "object": "list",
  "url": "https://api.vipter.com/v1/products",
  "has_more": false,
  "data": [
    {
      "id": "prd_1a5c9e3b7d2f6a8c",
      "object": "product",
      "name": "Plano Pro",
      "description": "Acesso completo à plataforma.",
      "type": "digital",
      "status": "active",
      "active": true,
      "product_family": null,
      "metadata": {},
      "livemode": true,
      "created": 1788200000
    }
  ]
}

Buscar um produto

GET /v1/products/{id}
curl https://api.vipter.com/v1/products/prd_1a5c9e3b7d2f6a8c \
  -H "Authorization: Bearer vk_live_…"

Devolve o objeto product.

O objeto product

CampoTipoConteúdo
idtextoprd_…
objecttexto"product"
nametextoNome do produto.
descriptiontexto ou nullDescrição.
typetexto ou nullO tipo do produto, como digital ou physical. Pode ganhar valores novos.
statustextoO status no catálogo, como active ou inactive.
activebooleanotrue quando o produto está ativo e não foi excluído.
product_familytexto ou nullO ID da família de produtos, quando o produto pertence a uma.
metadataobjetoDados livres gravados no produto.
livemodebooleanotrue em produção.
createdinteiro ou nullQuando o produto foi criado.

Sessões de checkout

Uma sessão de checkout é um checkout aberto pelo seu sistema para uma oferta, com o comprador, a sua referência e o destino depois do pagamento já definidos. A resposta traz a url para onde você manda o comprador. Quando ele paga, a sessão passa a apontar para customer, order e subscription, e o evento checkout.session.completed sai no catálogo 2026-11-01. É o equivalente da Checkout Session da Stripe. O passo a passo com código está em SaaS: do cadastro ao dashboard.

A sessão fixa a oferta, o pacote, a moeda e o cupom: o comprador não troca nenhum deles na página. Com customer ou customer_email, o campo de e-mail vem preenchido e travado. Criar a sessão não cria nada no provedor de pagamento; isso acontece quando o comprador preenche o formulário, como num link de checkout comum.

Criar uma sessão

POST /v1/checkout/sessions

Pede o escopo write. Envie uma Idempotency-Key para repetir a chamada depois de um erro de rede sem criar duas sessões.

ParâmetroTipoConteúdo
offertextoObrigatório, a menos que line_items venha. A oferta: ofr_… ou o slug do link de checkout. Uma oferta que não existe ou é de outra loja recebe 404 resource_missing com param offer.
line_items[0][price], line_items[0][quantity]texto, inteiroApelido no formato da Stripe: price é a oferta e quantity é o pacote. Só um item. Quando offer ou pack também vêm, eles valem.
packinteiroO pacote, em unidades (1 a 999). A oferta precisa ter um pacote com essa quantidade, senão 400 pack_unavailable.
currencytextoMoeda da sessão, ISO 4217 (brl, usd). Precisa existir em prices da oferta, senão 400 currency_unsupported, com as moedas disponíveis na message. Sem ela, o checkout abre na moeda padrão da oferta e o comprador pode trocar, como num link comum.
customertextocust_… de um cliente da loja. O e-mail dele vem preenchido e travado; nome, telefone e documento vêm preenchidos. Um ID que não existe recebe 404 resource_missing com param customer.
customer_emailtextoE-mail do comprador, quando ele ainda não é cliente. O campo vem preenchido e travado: o checkout só aceita pagar com esse e-mail. Guardado em minúsculas.
customer_nametextoNome para preencher o formulário, de 2 a 120 caracteres. O comprador pode alterar.
client_reference_idtextoO seu identificador, até 200 caracteres: o ID do usuário no seu sistema. É copiado para o pedido e para a assinatura, e filtra a lista de sessões.
metadataobjetoAté 50 chaves; chave com até 40 caracteres, valor com até 500. Números e booleanos são guardados como texto; null remove a chave. Fica na sessão e é copiado para o pedido.
subscription_data[metadata]objetoO metadata da assinatura que a sessão criar, nas ofertas recorrentes. Sem ele, a assinatura recebe o metadata da sessão. Mesmos limites.
discounts[0][coupon]textoO código de um cupom ativo da loja, sem diferenciar maiúsculas. Vem aplicado no checkout. Cupom inexistente ou inativo recebe 400 coupon_invalid. Só um cupom.
success_urltextoPara onde o comprador vai depois de pagar. https://, até 2000 caracteres (http://localhost é aceito em desenvolvimento). O texto {CHECKOUT_SESSION_ID} é trocado pelo id da sessão. Veja Depois do pagamento.
cancel_urltextoVira o link de voltar no topo do checkout. Também é para onde o comprador vai se abrir a sessão depois de ela expirar. Mesmas regras de formato.
redirect_delayinteiroSegundos que a página de obrigado do Vipter fica na tela antes de ir para success_url: de 0 a 30, padrão 5.
expires_atinteiroQuando a sessão expira, em segundos Unix: entre 30 minutos e 24 horas a partir de agora, senão 400 parameter_invalid. Padrão: 24 horas.
localetextoIdioma do comprador, gravado na sessão e devolvido no objeto: en, pt, es, fr, de, it, ja, ko, ru ou zh.
modetextopayment ou subscription. Opcional: o Vipter deduz pelo tipo da oferta e devolve no objeto. Um valor diferente do tipo da oferta recebe 400 mode_mismatch.
allow_promotion_codesbooleanoAceito por compatibilidade com a Stripe e ignorado por enquanto.
curl -X POST https://api.vipter.com/v1/checkout/sessions \
  -H "Authorization: Bearer vk_live_…" \
  -H "Idempotency-Key: 9c1f0a52-7e4b-4d3a-9b8e-2f6c1d0a7e45" \
  -H "Content-Type: application/json" \
  -d '{
    "offer": "ofr_6e2b8d4f1a9c3e7b",
    "customer_email": "ana@example.com",
    "client_reference_id": "user_8213",
    "metadata": { "plan": "pro" },
    "success_url": "https://app.example.com/billing/success?session_id={CHECKOUT_SESSION_ID}",
    "cancel_url": "https://app.example.com/billing"
  }'

A resposta é 201 com o objeto checkout.session:

{
  "id": "cs_4b7e2d9a1c3f5e8b0d2a6c4e1f3b",
  "object": "checkout.session",
  "status": "open",
  "payment_status": "unpaid",
  "url": "https://pay.vipter.com/c/cs_4b7e2d9a1c3f5e8b0d2a6c4e1f3b",
  "mode": "subscription",
  "offer": { "id": "ofr_6e2b8d4f1a9c3e7b", "name": "Plano Pro mensal" },
  "pack": null,
  "currency": null,
  "amount_total": 9900,
  "customer": null,
  "customer_email": "ana@example.com",
  "customer_name": null,
  "client_reference_id": "user_8213",
  "metadata": { "plan": "pro" },
  "subscription_data": { "metadata": {} },
  "discounts": [],
  "success_url": "https://app.example.com/billing/success?session_id={CHECKOUT_SESSION_ID}",
  "cancel_url": "https://app.example.com/billing",
  "redirect_delay": 5,
  "locale": null,
  "order": null,
  "subscription": null,
  "expires_at": 1790272800,
  "completed_at": null,
  "livemode": true,
  "created": 1790186400
}

Mande o comprador para url. O endereço fica em https://pay.vipter.com/c/{id} ou, quando a loja tem um domínio próprio ativo, nesse domínio.

Erros desta chamada, além dos erros gerais:

codeHTTPSignificado
resource_missing404A oferta (param offer) ou o cliente (param customer) não existe na loja.
offer_unavailable400A oferta existe mas não pode ser vendida agora: link de checkout desligado, oferta arquivada, sem preço, ou a loja não está em condição de vender. A message diz o motivo.
pack_unavailable400A oferta não tem um pacote com a quantidade pedida em pack.
currency_unsupported400A oferta não tem preço na moeda pedida.
mode_mismatch400mode não bate com o tipo da oferta.
coupon_invalid400O cupom não existe ou está inativo. param é discounts[0].coupon.
selling_blocked403A loja está impedida de vender porque a mensalidade do Vipter está em atraso. O type é permission_error.

Buscar uma sessão

GET /v1/checkout/sessions/{id}
curl https://api.vipter.com/v1/checkout/sessions/cs_4b7e2d9a1c3f5e8b0d2a6c4e1f3b \
  -H "Authorization: Bearer vk_live_…"

Devolve o objeto checkout.session. É a chamada que a sua página de sucesso faz com o id que chegou na success_url: confira status e payment_status em vez de confiar só no redirecionamento. Depois do pagamento, customer, order e, nas ofertas recorrentes, subscription vêm preenchidos. subscription pode chegar alguns segundos depois de order, quando o aviso do provedor é processado; se ele ainda vier null, consulte de novo ou espere o webhook.

Listar sessões

GET /v1/checkout/sessions
ParâmetroTipoConteúdo
customertextoSó sessões desse cliente (cust_…), incluindo as que ganharam o cliente ao serem pagas.
client_reference_idtextoSó sessões criadas com esse client_reference_id, igualdade exata.
statustextoopen, complete ou expired.
payment_statustextounpaid, paid ou pending.
limit, starting_after, ending_beforePaginação.
curl "https://api.vipter.com/v1/checkout/sessions?client_reference_id=user_8213&status=complete" \
  -H "Authorization: Bearer vk_live_…"

Devolve um objeto list de checkout.session, da mais nova para a mais antiga.

Expirar uma sessão

POST /v1/checkout/sessions/{id}/expire

Fecha uma sessão aberta antes do prazo: o comprador que abrir a url depois disso vai para cancel_url, ou vê uma página de link indisponível. Útil quando o usuário desistiu no seu sistema ou escolheu outro plano. Pede o escopo write.

curl -X POST https://api.vipter.com/v1/checkout/sessions/cs_4b7e2d9a1c3f5e8b0d2a6c4e1f3b/expire \
  -H "Authorization: Bearer vk_live_…"

Devolve o objeto com status: "expired" e gera o evento checkout.session.expired. Uma sessão que já está complete ou expired recebe 400 checkout_session_not_open, com o status atual na message.

O objeto checkout.session

CampoTipoConteúdo
idtextocs_…
objecttexto"checkout.session"
statustextoopen, complete ou expired. Veja Status da sessão.
payment_statustextounpaid, paid ou pending.
urltexto ou nullO endereço do checkout. Só enquanto status é open; depois vem null.
modetexto ou nullpayment numa oferta avulsa, subscription numa recorrente.
offerobjetoid (ofr_…) e name da oferta.
packinteiro ou nullO pacote fixado, em unidades.
currencytexto ou nullA moeda fixada na criação. null quando a sessão deixou o comprador escolher.
amount_totalinteiro ou nullO preço da oferta na moeda da sessão (ou na moeda padrão), na menor unidade: o valor da primeira cobrança, quando ela é diferente. Vem antes de cupom, frete e adicionais, e null nas sessões com pacote. O valor cobrado de fato está em amount_total do pedido.
customertexto ou nullcust_…: o que você passou, ou o cliente criado quando o comprador pagou.
customer_email, customer_nametexto ou nullO que você passou; com customer, o e-mail e o nome do cliente.
client_reference_idtexto ou nullO seu identificador.
metadataobjetoO que você enviou.
subscription_dataobjetometadata: o que você enviou em subscription_data[metadata], ou {}.
discountslista[{ "coupon": "CODIGO" }] quando a sessão tem cupom; senão [].
success_url, cancel_urltexto ou nullComo você enviou, com o {CHECKOUT_SESSION_ID} ainda por trocar.
redirect_delayinteiroSegundos antes do redirecionamento, de 0 a 30.
localetexto ou nullO idioma enviado.
ordertexto ou nullord_… do pedido que a sessão gerou. Preenchido quando o comprador paga ou gera um PIX.
subscriptiontexto ou nullsub_… da assinatura criada, nas ofertas recorrentes.
expires_atinteiroQuando a sessão expira.
completed_atinteiro ou nullQuando a sessão passou a complete.
livemodebooleanotrue em produção.
createdinteiroQuando a sessão foi criada.

Status da sessão

statuspayment_statusSignificado
openunpaidO comprador ainda não pagou. Um cartão recusado deixa a sessão aberta: ele pode tentar de novo na mesma página.
completepaidPago: cartão aprovado, ou PIX pago. order está preenchido.
completependingO comprador gerou um PIX, ou o cartão ficou em análise, e o dinheiro ainda não entrou. order está preenchido com status: "pending". A sessão fica assim até o pagamento confirmar (paid) ou falhar (unpaid).
completeunpaidO pagamento pendente não aconteceu: o PIX expirou ou a cobrança foi recusada depois da análise. A sessão não reabre; crie outra.
expiredunpaidO prazo passou sem pagamento, ou alguém chamou POST …/expire.

Cada mudança gera um evento do catálogo 2026-11-01: checkout.session.completed quando a sessão passa a complete (com paid ou pending), checkout.session.async_payment_succeeded quando um pagamento pendente confirma, checkout.session.async_payment_failed quando ele falha, e checkout.session.expired. Uma sessão só completa uma vez.

Depois do pagamento

  1. O comprador paga na página do Vipter e vê a página de obrigado da loja.
  2. Com o pagamento confirmado, a página conta redirect_delay segundos e vai para success_url, com {CHECKOUT_SESSION_ID} trocado pelo id da sessão. Enquanto um PIX não é pago, a página fica aguardando e não redireciona.
  3. A success_url da sessão tem prioridade sobre a URL de sucesso do link rápido, a da oferta e a padrão da loja. Sem success_url, vale a próxima da lista.

Quando o produto tem arquivos para download, a página não redireciona sozinha: mostra os arquivos e um botão para seguir para a success_url.

Um comprador que abre a url de uma sessão já paga é levado para a página de obrigado do pedido. Uma sessão expirada leva para cancel_url ou, sem ela, para uma página de link indisponível. As sessões vencidas são marcadas como expired por uma rotina periódica, e também na hora, se alguém abrir o link.

Portal do cliente

Criar uma sessão do portal

POST /v1/billing_portal/sessions

Gera um link de entrada direta na área do cliente da loja para um cliente, sem o passo do código por e-mail. Serve para o botão "gerenciar assinatura" do seu sistema: o cliente troca o cartão, cancela ou vê as cobranças no portal do Vipter. Pede o escopo write.

ParâmetroTipoConteúdo
customertextoObrigatório. cust_… do cliente.
return_urltextoAceito por compatibilidade com a Stripe e devolvido no objeto. O portal ainda não tem um botão de voltar para ele.
curl -X POST https://api.vipter.com/v1/billing_portal/sessions \
  -H "Authorization: Bearer vk_live_…" \
  -H "Content-Type: application/json" \
  -d '{ "customer": "cust_9d2e4f6a8b1c3d5e" }'
{
  "id": "bps_3e9a1c7f5b2d4e6a8c0b",
  "object": "billing_portal.session",
  "url": "https://portal.vipter.com/loja-demo/verify?token=EXEMPLO-TOKEN",
  "customer": "cust_9d2e4f6a8b1c3d5e",
  "return_url": null,
  "expires_at": 1790187300,
  "livemode": true,
  "created": 1790186400
}
CampoTipoConteúdo
idtextobps_…. A sessão não pode ser consultada depois.
objecttexto"billing_portal.session"
urltextoO link de entrada. Vale por 15 minutos e serve para uma entrada: ao ser aberto, cria a sessão do portal no navegador do cliente e deixa de funcionar. Gere um link novo a cada clique, na hora do clique, e redirecione o cliente para ele; não guarde nem envie por e-mail.
customertextoO cliente.
return_urltexto ou nullO que você enviou.
expires_atinteiroQuando o link deixa de valer.
livemodebooleanotrue em produção.
createdinteiroQuando a sessão foi criada.

O link abre no endereço do portal da loja: o domínio próprio, quando há um ativo, ou portal.vipter.com/{slug}.

codeHTTPSignificado
resource_missing404O cliente não existe na loja.
portal_disabled400A área do cliente está desligada nas configurações da loja. Veja Área do cliente.
portal_unavailable400A loja ainda não tem um endereço de portal: falta um slug ou um domínio próprio ativo.

Eventos

Todo evento que o Vipter gera fica guardado e pode ser consultado pela API, nos dois catálogos: serve para conferir o que o seu endpoint recebeu, recuperar o que ele não recebeu enquanto esteve desativado e pedir um reenvio por código. O corpo de cada evento é o mesmo envelope que chega ao endpoint, e api_version diz de qual catálogo ele é. Os eventos de teste não aparecem na lista.

Listar eventos

GET /v1/events
ParâmetroTipoConteúdo
typetextoUm tipo exato, como invoice.paid, ou um padrão com *, como invoice.* ou customer.subscription.*.
created[gte], created[gt], created[lte], created[lt]inteiroSó eventos criados a partir de, depois de, até ou antes desse momento, em segundos Unix.
limit, starting_after, ending_beforePaginação. O cursor é o id de um evento.
curl "https://api.vipter.com/v1/events?type=invoice.*&created[gte]=1790726400" \
  -H "Authorization: Bearer vk_live_…"
{
  "object": "list",
  "url": "https://api.vipter.com/v1/events",
  "has_more": false,
  "data": [
    {
      "id": "evt_5a7c9e1b3d5f7a9c1e3b5d7f",
      "object": "event",
      "type": "invoice.paid",
      "api_version": "2026-11-01",
      "created": 1790790413,
      "livemode": true,
      "pending_webhooks": 0,
      "request": { "id": null, "idempotency_key": null },
      "data": {
        "object": { "id": "ord_7b3e9f1c2a8d4e6f", "object": "order", "status": "authorized", "paid": true, "…": "…" }
      }
    }
  ]
}

A lista vem do mais novo para o mais antigo e junta os dois catálogos: o mesmo fato aparece duas vezes quando a loja tem endpoints nas duas versões, uma com cada nome. Um evento da versão 2026-09-01 vem sem pending_webhooks e request, como no envelope dessa versão.

Buscar um evento

GET /v1/events/{id}
curl https://api.vipter.com/v1/events/evt_5a7c9e1b3d5f7a9c1e3b5d7f \
  -H "Authorization: Bearer vk_live_…"

Devolve o objeto event, o mesmo JSON que o endpoint recebeu no POST. Na versão 2026-11-01, pending_webhooks é calculado na hora da consulta: quantas entregas do evento ainda não deram certo. Um evento de teste pode ser buscado pelo id que a chamada de teste devolve. Um id que não existe na loja recebe 404 resource_missing.

Reenviar um evento

POST /v1/events/{id}/resend

Coloca o evento de novo na fila de entrega, com o mesmo id e o mesmo created, e envia na hora. Pede o escopo write.

ParâmetroTipoConteúdo
webhook_endpointtextoO id de um endpoint. Com ele, só esse endpoint recebe o evento: a entrega dele volta a pending com as tentativas zeradas, ou é criada se o endpoint nunca teve uma, como um endpoint criado depois do evento ou que estava desativado quando ele saiu. Sem ele, toda entrega que o evento já tem é reenviada, inclusive as que já tinham dado certo.
curl -X POST https://api.vipter.com/v1/events/evt_5a7c9e1b3d5f7a9c1e3b5d7f/resend \
  -H "Authorization: Bearer vk_live_…" \
  -H "Content-Type: application/json" \
  -d '{ "webhook_endpoint": "0b7e2c4a-9d1f-4e3b-8a6c-5f2d1e0c9b8a" }'
{
  "object": "event_resend",
  "event": "evt_5a7c9e1b3d5f7a9c1e3b5d7f",
  "webhook_endpoint": "0b7e2c4a-9d1f-4e3b-8a6c-5f2d1e0c9b8a",
  "deliveries": 1
}

deliveries é quantas entregas foram colocadas na fila. Sem webhook_endpoint, é o número de endpoints que já tinham uma entrega do evento; 0 quando nenhum tinha. O endpoint precisa receber o catálogo do evento: um evento invoice.paid (2026-11-01) não pode ser enviado a um endpoint 2026-09-01. Reenviar para um endpoint desativado encerra a entrega com endpoint disabled; ative-o antes. Se a entrega falhar, ela segue o calendário de tentativas desde o início. O seu controle de idempotência trata o reenvio como repetição.

codeHTTPSignificado
resource_missing404O evento, ou o endpoint em webhook_endpoint, não existe na loja.
invalid_event_type400O endpoint recebe outro catálogo. A message diz qual é o do evento e qual é o do endpoint.

Endpoints de webhook

Os mesmos endpoints da página GeralIntegraçõesAutomaçõesWebhooks do painel, criados e geridos por código. Um endpoint criado pela API aparece no painel como qualquer outro, e as regras são as de Receber eventos no seu sistema: URL https://, um catálogo por endpoint, novas tentativas e desativação automática. O id de um endpoint é um UUID; trate-o como texto opaco.

Listar endpoints

GET /v1/webhook_endpoints
curl https://api.vipter.com/v1/webhook_endpoints \
  -H "Authorization: Bearer vk_live_…"

Devolve um objeto list com todos os endpoints da loja, do mais antigo para o mais novo, sem filtros. O secret não vem na lista.

Criar um endpoint

POST /v1/webhook_endpoints

Pede o escopo write. A resposta é 201 e traz o secret (whsec_…) uma única vez: guarde-o no seu servidor para verificar a assinatura. Depois, só trocar o segredo gera outro.

ParâmetroTipoConteúdo
urltextoObrigatório. Endereço https:// do seu servidor, até 2000 caracteres, num host público. Um host da rede interna (localhost, 10.x, 192.168.x, nomes .internal ou .local) recebe 400 private_host; um endereço sem https:// recebe 400 invalid_url.
descriptiontextoUm lembrete para a equipe, até 200 caracteres.
enabled_eventslistaOs tipos que o endpoint recebe, até 100: nomes do catálogo da versão, como invoice.paid, ou padrões com *, como customer.subscription.*. Omitida, vazia ou ["*"], o endpoint recebe todos os eventos do catálogo, inclusive os criados no futuro. Um nome que não existe na versão recebe 400 invalid_event_type.
api_versiontextoO catálogo que o endpoint recebe: 2026-11-01 (padrão) ou 2026-09-01. Não muda depois de criado.
curl -X POST https://api.vipter.com/v1/webhook_endpoints \
  -H "Authorization: Bearer vk_live_…" \
  -H "Content-Type: application/json" \
  -d '{
    "url": "https://app.example.com/webhooks/vipter",
    "description": "Faturamento do SaaS",
    "enabled_events": ["checkout.session.*", "customer.subscription.*", "invoice.paid"]
  }'
{
  "id": "0b7e2c4a-9d1f-4e3b-8a6c-5f2d1e0c9b8a",
  "object": "webhook_endpoint",
  "url": "https://app.example.com/webhooks/vipter",
  "description": "Faturamento do SaaS",
  "enabled_events": ["checkout.session.*", "customer.subscription.*", "invoice.paid"],
  "api_version": "2026-11-01",
  "status": "enabled",
  "disabled_reason": null,
  "consecutive_failures": 0,
  "created_via": "api",
  "secret": "whsec_EXEMPLO0000000000000000000000000000",
  "livemode": true,
  "created": 1790186400
}

O endpoint nasce ativo e passa a receber os eventos criados a partir daí; eventos anteriores não chegam a ele, a não ser por um reenvio com webhook_endpoint.

Buscar um endpoint

GET /v1/webhook_endpoints/{id}
curl https://api.vipter.com/v1/webhook_endpoints/0b7e2c4a-9d1f-4e3b-8a6c-5f2d1e0c9b8a \
  -H "Authorization: Bearer vk_live_…"

Devolve o objeto webhook_endpoint, sem secret. Um id que não existe na loja recebe 404 resource_missing.

Alterar um endpoint

POST /v1/webhook_endpoints/{id}

Pede o escopo write. Só os campos enviados mudam.

ParâmetroTipoConteúdo
urltextoO endereço novo, com as mesmas regras da criação. As entregas seguintes já vão para ele.
descriptiontexto ou nullnull apaga a descrição.
enabled_eventslistaSubstitui a lista inteira. ["*"] volta a receber todos os eventos do catálogo. Pelo painel essa lista não pode ser alterada; pela API, pode.
statustextoenabled ou disabled. É a chave Ativo do painel: enabled zera consecutive_failures e apaga disabled_reason, o que religa um endpoint desativado sozinho. Enquanto está disabled, os eventos novos não são guardados para ele.

Um api_version no corpo é ignorado: a versão não muda. Para passar ao outro catálogo, crie um endpoint novo e remova o antigo.

curl -X POST https://api.vipter.com/v1/webhook_endpoints/0b7e2c4a-9d1f-4e3b-8a6c-5f2d1e0c9b8a \
  -H "Authorization: Bearer vk_live_…" \
  -H "Content-Type: application/json" \
  -d '{ "enabled_events": ["*"], "status": "enabled" }'

Devolve o objeto webhook_endpoint atualizado.

Remover um endpoint

DELETE /v1/webhook_endpoints/{id}

Apaga o endpoint, o segredo e o histórico de entregas dele; as entregas pendentes param. Pede o escopo write.

{ "id": "0b7e2c4a-9d1f-4e3b-8a6c-5f2d1e0c9b8a", "object": "webhook_endpoint", "deleted": true }

Trocar o segredo

POST /v1/webhook_endpoints/{id}/rotate_secret

Gera um segredo novo e devolve o objeto webhook_endpoint com ele em secret, uma única vez. O segredo anterior continua assinando por 24 horas: nesse período, cada entrega traz dois v1= no cabeçalho Vipter-Signature, e o seu servidor pode trocar a variável de ambiente sem perder eventos. Veja Trocar o segredo. Pede o escopo write.

curl -X POST https://api.vipter.com/v1/webhook_endpoints/0b7e2c4a-9d1f-4e3b-8a6c-5f2d1e0c9b8a/rotate_secret \
  -H "Authorization: Bearer vk_live_…"

Enviar um evento de teste

POST /v1/webhook_endpoints/{id}/test

Cria um evento customer.created de teste e entrega só a este endpoint, no catálogo dele: um objeto customer no formato da versão do endpoint, com "test": true a mais e livemode: false. É o mesmo que o botão Enviar evento de teste do card do endpoint no painel. O evento não passa por automações, e-mails, notas fiscais, áreas de membros nem pixels, não chega aos outros endpoints e não aparece em GET /v1/events. O formato está no catálogo. Pede o escopo write.

curl -X POST https://api.vipter.com/v1/webhook_endpoints/0b7e2c4a-9d1f-4e3b-8a6c-5f2d1e0c9b8a/test \
  -H "Authorization: Bearer vk_live_…"
{
  "object": "webhook_test",
  "webhook_endpoint": "0b7e2c4a-9d1f-4e3b-8a6c-5f2d1e0c9b8a",
  "event": "evt_1c3e5a7b9d0f2e4c6a8b0d2f"
}

A entrega sai na hora. Acompanhe-a em GET /v1/webhook_endpoints/{id}/deliveries ou em Entregas recentes no painel. Se o seu servidor falhar, ela segue o calendário de tentativas de um evento real e conta para a desativação automática. Com o endpoint desativado, a entrega termina na hora com endpoint disabled.

Listar as entregas de um endpoint

GET /v1/webhook_endpoints/{id}/deliveries
ParâmetroTipoConteúdo
statustextopending, delivering, succeeded, failed ou exhausted.
limit, starting_after, ending_beforePaginação. O cursor é o id de uma entrega.
curl "https://api.vipter.com/v1/webhook_endpoints/0b7e2c4a-9d1f-4e3b-8a6c-5f2d1e0c9b8a/deliveries?status=failed" \
  -H "Authorization: Bearer vk_live_…"
{
  "object": "list",
  "url": "https://api.vipter.com/v1/webhook_endpoints/0b7e2c4a-9d1f-4e3b-8a6c-5f2d1e0c9b8a/deliveries",
  "has_more": false,
  "data": [
    {
      "id": "6f1d2c3b-4a5e-4f6a-9b8c-7d6e5f4a3b2c",
      "object": "webhook_delivery",
      "event": "evt_5a7c9e1b3d5f7a9c1e3b5d7f",
      "webhook_endpoint": "0b7e2c4a-9d1f-4e3b-8a6c-5f2d1e0c9b8a",
      "status": "failed",
      "attempts": 2,
      "next_attempt_at": 1790790780,
      "last_attempt_at": 1790790480,
      "delivered_at": null,
      "last_response_status": 500,
      "last_error": "HTTP 500",
      "last_duration_ms": 184,
      "created": 1790790413
    }
  ]
}

Devolve um objeto list de webhook_delivery, da mais nova para a mais antiga: uma entrega por evento que o endpoint recebeu. O que cada status significa está em Tentativas, desativação e reenvio.

O objeto do endpoint

CampoTipoConteúdo
idtextoUUID do endpoint.
objecttexto"webhook_endpoint"
urltextoO endereço que recebe os eventos.
descriptiontexto ou nullA descrição.
enabled_eventslistaOs tipos e padrões que o endpoint recebe. ["*"] quando recebe todos os eventos do catálogo.
api_versiontexto2026-11-01 ou 2026-09-01: o catálogo que o endpoint recebe.
statustextoenabled ou disabled.
disabled_reasontexto ou nullO motivo, quando o Vipter desativou o endpoint sozinho: auto-disabled after 20 exhausted deliveries. null nos outros casos, inclusive quando a equipe desligou a chave.
consecutive_failuresinteiroEntregas seguidas que esgotaram as tentativas. Em 20, o endpoint é desativado; uma entrega succeeded zera.
created_viatextodashboard ou api: onde o endpoint foi criado.
secrettextoO segredo de assinatura, whsec_…. Só na resposta de criar e de trocar o segredo.
livemodebooleanotrue em produção.
createdinteiroQuando o endpoint foi criado.

O objeto da entrega

CampoTipoConteúdo
idtextoUUID da entrega.
objecttexto"webhook_delivery"
eventtextoevt_… do evento entregue. Busque-o em GET /v1/events/{id}.
webhook_endpointtextoO endpoint.
statustextopending (na fila), delivering (sendo enviada), succeeded (o seu servidor respondeu 2xx), failed (a última tentativa falhou e há outra agendada) ou exhausted (as tentativas acabaram, ou o endpoint estava desativado).
attemptsinteiroQuantas tentativas já foram feitas, de até 8. Volta a 0 num reenvio.
next_attempt_atinteiro ou nullQuando a próxima tentativa está agendada. Só com status pending ou failed.
last_attempt_atinteiro ou nullQuando foi a última tentativa.
delivered_atinteiro ou nullQuando o seu servidor respondeu 2xx.
last_response_statusinteiro ou nullO código HTTP da última resposta. null quando não houve resposta.
last_errortexto ou nullO erro da última tentativa: HTTP 500, timeout, endpoint disabled ou a mensagem de rede. null quando deu certo.
last_duration_msinteiro ou nullQuanto tempo a última tentativa levou, em milissegundos.
createdinteiroQuando a entrega foi criada.

Em breve

O que ainda não existe na API: um filtro por client_reference_id em GET /v1/subscriptions e em GET /v1/customers. Para achar a assinatura de um usuário seu, use o campo subscription da sessão de checkout que a criou, ou guarde o sub_… que chega no webhook. O uso medido, antes listado aqui, está no ar: veja Uso medido.

O que fazer a seguir

Esta página ajudou?

Nesta página

Idioma