Ofertas do Merchant
Crie, liste, atualize, arquive, restaure e exclua (soft delete) ofertas — os planos de preços vinculados a um produto — a partir da superfície de Merchant do Tokeflow Dashboard.
Uma oferta é um plano comprável vinculado a um produto: ela define o ciclo de cobrança, o comportamento de trial e de setup, os limites de ciclo e um ou mais preços específicos por moeda. Um produto pode ter várias ofertas — um plano mensal, um plano anual, uma variante promocional — e cada oferta carrega seus próprios preços em unidades menores por moeda ISO 4217. As ofertas são o que os clientes de fato assinam ou compram no checkout.
Esses endpoints alimentam as telas de gerenciamento de ofertas do Tokeflow Dashboard para um único Merchant. As ofertas referenciam um produto e, por sua vez, são referenciadas por assinaturas, razão pela qual a exclusão é protegida: uma oferta com qualquer histórico de assinatura é preservada para os registros de cobrança.
Esses endpoints alimentam a interface do Tokeflow Dashboard. Eles são autenticados com uma sessão do dashboard (JWT bearer) obtida ao fazer login — não com chaves de API sk_/pk_. Toda solicitação também deve enviar o header x-merchant-id identificando o contexto do Merchant (mrc_…). Veja Autenticação do Dashboard.
Ciclo de vida da oferta
Arquivar oculta uma oferta de novos checkouts mantendo-a totalmente legível; é reversível com unarchive. A exclusão por soft delete remove a oferta (e propaga em cascata para seus preços), mas é recusada com 409 enquanto qualquer assinatura — em qualquer status — ainda a referenciar, e pode ser revertida com restore.
O objeto oferta
Derivado de OfferResponseDto, retornado por todos os endpoints desta página que retornam um corpo.
| Campo | Tipo | Descrição |
|---|---|---|
id | string | ID da oferta, prefixado com ofr_. |
product_id | string | Produto pai, prefixado com prd_. |
name | string | Nome de exibição da oferta. |
slug | string | Identificador em minúsculas, único por produto. |
description | string | null | Descrição em texto livre. |
billing_cycle | string | Um de daily, biweekly, monthly, quarterly, half_yearly, yearly, custom, none. |
custom_billing_days | number | null | Período em dias. Obrigatório quando billing_cycle = custom. |
cycle_limit | number | null | Número fixo de cobranças. null = cobrar até o cancelamento. |
free_trial | boolean | Se a oferta começa com um trial gratuito. |
trial_days | number | null | Duração do trial em dias. Obrigatório quando free_trial = true. |
setup_charge | boolean | Se o primeiro ciclo é cobrado com um valor de primeira cobrança distinto. |
renew_after_cycle_limit | boolean | Se a assinatura renova após atingir cycle_limit. |
renewal_offer_id | string | null | Oferta usada para renovação após cycle_limit. null = renovar com a mesma oferta. |
is_default | boolean | Se esta é a oferta padrão do seu produto. |
status | string | active ou archived. |
created_at | string | Timestamp de criação (ISO 8601 UTC). |
updated_at | string | Timestamp da última atualização (ISO 8601 UTC). |
prices | array | Preços da oferta. Preenchido quando os preços são carregados de forma eager (create, get por ID). |
billing_cycle: "none" descreve uma oferta avulsa, sem recorrência. Para ciclos recorrentes que não se encaixam nos presets, use custom junto com custom_billing_days.
Endpoints
GET/api/v1/merchant/offers
Auth: Dashboard session (JWT bearer). É necessário ser membro do Merchant.
Retorna uma lista paginada das ofertas do Merchant, filtrável por produto, status, ciclo de cobrança e nome.
Parâmetros de consulta
| Campo | Tipo | Obrigatório | Descrição |
|---|---|---|---|
page | number | Não | Número da página, indexado a partir de 1 (padrão 1, mín. 1). |
limit | number | Não | Itens por página (padrão 20, mín. 1, máx. 100). |
product_id | string | Não | Filtra as ofertas para um único produto. |
status | string | Não | Filtra por status: active ou archived. |
billing_cycle | string | Não | Filtra por ciclo de cobrança: daily, biweekly, monthly, quarterly, half_yearly, yearly, custom ou none. |
is_default | boolean | Não | Filtra apenas as ofertas padrão. |
name | string | Não | Filtro de correspondência parcial pelo nome da oferta. |
Exemplo de requisição
curl -G https://api.tokeflow.com/api/v1/merchant/offers \
-H "Authorization: Bearer <session-jwt>" \
-H "x-merchant-id: mrc_9f8e7d6c5b" \
--data-urlencode "product_id=prd_a1b2c3d4e5" \
--data-urlencode "status=active" \
--data-urlencode "page=1" \
--data-urlencode "limit=20"Exemplo de resposta — 200 OK
{
"data": [
{
"id": "ofr_a1b2c3d4e5",
"product_id": "prd_a1b2c3d4e5",
"name": "Mensal",
"slug": "mensal",
"description": "Plano mensal padrão",
"billing_cycle": "monthly",
"custom_billing_days": null,
"cycle_limit": 12,
"free_trial": false,
"trial_days": null,
"setup_charge": false,
"renew_after_cycle_limit": false,
"renewal_offer_id": null,
"is_default": true,
"status": "active",
"created_at": "2026-05-19T12:00:00Z",
"updated_at": "2026-05-19T12:00:00Z"
}
],
"meta": {
"page": 1,
"limit": 20,
"total": 42,
"total_pages": 3,
"has_next": true,
"has_prev": false
}
}POST/api/v1/merchant/offers
Auth: Dashboard session (JWT bearer). É necessário ser membro do Merchant.
Cria uma oferta com seus preços iniciais. Pelo menos um preço é obrigatório; cada preço é um valor em unidades menores para uma moeda ISO 4217.
Campos da requisição
| Campo | Tipo | Obrigatório | Descrição |
|---|---|---|---|
product_id | string | Sim | Produto pai, prefixado com prd_. |
name | string | Sim | Nome de exibição (máx. 255 caracteres). |
slug | string | Sim | Identificador em minúsculas, único por produto (máx. 100 caracteres). |
description | string | Não | Descrição em texto livre (máx. 2000 caracteres). |
billing_cycle | string | Sim | Um de daily, biweekly, monthly, quarterly, half_yearly, yearly, custom, none. |
custom_billing_days | number | Condicional | Período em dias (mín. 1). Obrigatório quando billing_cycle = custom. |
cycle_limit | number | Não | Número fixo de cobranças (mín. 1). Omita ou null = cobrar até o cancelamento. |
free_trial | boolean | Não | Se a oferta começa com um trial gratuito. Padrão false. |
trial_days | number | Condicional | Duração do trial em dias (mín. 1). Obrigatório quando free_trial = true. |
setup_charge | boolean | Não | Cobra o primeiro ciclo pelo first_charge_amount de cada preço. Padrão false. |
renew_after_cycle_limit | boolean | Não | Renova a assinatura após cycle_limit cobranças. Padrão false. |
renewal_offer_id | string | Não | Oferta para renovação após cycle_limit. Omita = renovar com a mesma oferta. |
is_default | boolean | Não | Torna esta a oferta padrão do seu produto. Padrão false. |
status | string | Sim | active ou archived. |
prices | array | Sim | Pelo menos um preço (veja abaixo). |
Campos de preço (prices[])
| Campo | Tipo | Obrigatório | Descrição |
|---|---|---|---|
currency | string | Sim | Código de moeda ISO 4217. |
amount | number | Sim | Valor em unidades menores (mín. 0). Ex.: R$99,00 = 9900. |
first_charge_amount | number | Não | Valor do primeiro ciclo em unidades menores. Usado quando setup_charge = true. 0 = apenas validação de cartão. |
is_default | boolean | Não | Marca esta moeda como a padrão da oferta. |
Exemplo de requisição
curl -X POST https://api.tokeflow.com/api/v1/merchant/offers \
-H "Authorization: Bearer <session-jwt>" \
-H "x-merchant-id: mrc_9f8e7d6c5b" \
-H "Content-Type: application/json" \
-d '{
"product_id": "prd_a1b2c3d4e5",
"name": "Mensal",
"slug": "mensal",
"description": "Plano mensal padrão",
"billing_cycle": "monthly",
"cycle_limit": 12,
"free_trial": false,
"setup_charge": false,
"is_default": true,
"status": "active",
"prices": [
{ "currency": "BRL", "amount": 9900, "is_default": true },
{ "currency": "USD", "amount": 1900 }
]
}'Exemplo de resposta — 201 Created
{
"id": "ofr_a1b2c3d4e5",
"product_id": "prd_a1b2c3d4e5",
"name": "Mensal",
"slug": "mensal",
"description": "Plano mensal padrão",
"billing_cycle": "monthly",
"custom_billing_days": null,
"cycle_limit": 12,
"free_trial": false,
"trial_days": null,
"setup_charge": false,
"renew_after_cycle_limit": false,
"renewal_offer_id": null,
"is_default": true,
"status": "active",
"created_at": "2026-05-19T12:00:00Z",
"updated_at": "2026-05-19T12:00:00Z",
"prices": [
{
"currency": "BRL",
"amount": 9900,
"is_default": true
},
{
"currency": "USD",
"amount": 1900,
"is_default": false
}
]
}Um trial gratuito não precisa de uma cobrança de setup: free_trial: true com trial_days já cobra 0 no início, e o cartão continua sendo cadastrado por uma validação de cartão. Para cobrar uma taxa de adesão junto com o trial, adicione setup_charge: true com um first_charge_amount acima de 0 no preço; first_charge_amount: 0 é a forma explícita de dizer "validar o cartão, não cobrar nada".
GET/api/v1/merchant/offers/:id
Auth: Dashboard session (JWT bearer). É necessário ser membro do Merchant.
Recupera uma única oferta pelo ID, incluindo seus preços. Retorna o objeto oferta.
Exemplo de requisição
curl https://api.tokeflow.com/api/v1/merchant/offers/ofr_a1b2c3d4e5 \
-H "Authorization: Bearer <session-jwt>" \
-H "x-merchant-id: mrc_9f8e7d6c5b"Exemplo de resposta — 200 OK
{
"id": "ofr_a1b2c3d4e5",
"product_id": "prd_a1b2c3d4e5",
"name": "Mensal",
"slug": "mensal",
"description": "Plano mensal padrão",
"billing_cycle": "monthly",
"custom_billing_days": null,
"cycle_limit": 12,
"free_trial": false,
"trial_days": null,
"setup_charge": false,
"renew_after_cycle_limit": false,
"renewal_offer_id": null,
"is_default": true,
"status": "active",
"created_at": "2026-05-19T12:00:00Z",
"updated_at": "2026-05-19T12:00:00Z",
"prices": [
{
"currency": "BRL",
"amount": 9900,
"is_default": true
}
]
}PATCH/api/v1/merchant/offers/:id
Auth: Dashboard session (JWT bearer). É necessário ser membro do Merchant.
Atualiza uma oferta. Envie apenas os campos que deseja alterar; o objeto oferta atualizado é retornado.
Exemplo de requisição
curl -X PATCH https://api.tokeflow.com/api/v1/merchant/offers/ofr_a1b2c3d4e5 \
-H "Authorization: Bearer <session-jwt>" \
-H "x-merchant-id: mrc_9f8e7d6c5b" \
-H "Content-Type: application/json" \
-d '{ "name": "Mensal Plus", "description": "Plano mensal com upgrade" }'Exemplo de resposta — 200 OK
{
"id": "ofr_a1b2c3d4e5",
"product_id": "prd_a1b2c3d4e5",
"name": "Mensal Plus",
"slug": "mensal",
"description": "Plano mensal com upgrade",
"billing_cycle": "monthly",
"custom_billing_days": null,
"cycle_limit": 12,
"free_trial": false,
"trial_days": null,
"setup_charge": false,
"renew_after_cycle_limit": false,
"renewal_offer_id": null,
"is_default": true,
"status": "active",
"created_at": "2026-05-19T12:00:00Z",
"updated_at": "2026-05-19T14:30:00Z"
}DELETE/api/v1/merchant/offers/:id
Auth: Dashboard session (JWT bearer). É necessário ser membro do Merchant.
Exclui uma oferta por soft delete, propagando em cascata para seus preços. A solicitação é recusada com 409 enquanto qualquer assinatura — em qualquer status — referenciar a oferta; ofertas referenciadas por assinaturas são mantidas para o histórico de cobrança. Uma oferta excluída por soft delete pode ser recuperada com restore.
Códigos de resposta
| Código | Quando |
|---|---|
204 No Content | Oferta excluída por soft delete. |
404 Not Found | Oferta não encontrada. |
409 Conflict | A oferta tem assinaturas e não pode ser excluída. |
Exemplo de requisição
curl -X DELETE https://api.tokeflow.com/api/v1/merchant/offers/ofr_a1b2c3d4e5 \
-H "Authorization: Bearer <session-jwt>" \
-H "x-merchant-id: mrc_9f8e7d6c5b"Exemplo de resposta — 204 No Content (corpo vazio)
Quando uma oferta não pode ser excluída porque assinaturas a referenciam, arquive-a em vez disso — ofertas arquivadas ficam fora de novos checkouts enquanto seu histórico de cobrança permanece intacto.
POST/api/v1/merchant/offers/:id/archive
Auth: Dashboard session (JWT bearer). É necessário ser membro do Merchant.
Arquiva uma oferta, definindo status como archived. Retorna o objeto oferta atualizado.
Exemplo de requisição
curl -X POST https://api.tokeflow.com/api/v1/merchant/offers/ofr_a1b2c3d4e5/archive \
-H "Authorization: Bearer <session-jwt>" \
-H "x-merchant-id: mrc_9f8e7d6c5b"Exemplo de resposta — 201 Created
{
"id": "ofr_a1b2c3d4e5",
"product_id": "prd_a1b2c3d4e5",
"name": "Mensal",
"slug": "mensal",
"description": "Plano mensal padrão",
"billing_cycle": "monthly",
"custom_billing_days": null,
"cycle_limit": 12,
"free_trial": false,
"trial_days": null,
"setup_charge": false,
"renew_after_cycle_limit": false,
"renewal_offer_id": null,
"is_default": false,
"status": "archived",
"created_at": "2026-05-19T12:00:00Z",
"updated_at": "2026-05-19T15:00:00Z"
}POST/api/v1/merchant/offers/:id/unarchive
Auth: Dashboard session (JWT bearer). É necessário ser membro do Merchant.
Desarquiva uma oferta, definindo status de volta como active. Retorna o objeto oferta atualizado.
Exemplo de requisição
curl -X POST https://api.tokeflow.com/api/v1/merchant/offers/ofr_a1b2c3d4e5/unarchive \
-H "Authorization: Bearer <session-jwt>" \
-H "x-merchant-id: mrc_9f8e7d6c5b"Exemplo de resposta — 201 Created
{
"id": "ofr_a1b2c3d4e5",
"product_id": "prd_a1b2c3d4e5",
"name": "Mensal",
"slug": "mensal",
"description": "Plano mensal padrão",
"billing_cycle": "monthly",
"custom_billing_days": null,
"cycle_limit": 12,
"free_trial": false,
"trial_days": null,
"setup_charge": false,
"renew_after_cycle_limit": false,
"renewal_offer_id": null,
"is_default": false,
"status": "active",
"created_at": "2026-05-19T12:00:00Z",
"updated_at": "2026-05-19T15:10:00Z"
}POST/api/v1/merchant/offers/:id/restore
Auth: Dashboard session (JWT bearer). É necessário ser membro do Merchant.
Restaura uma oferta excluída por soft delete e seus preços. Retorna o objeto oferta restaurado.
Exemplo de requisição
curl -X POST https://api.tokeflow.com/api/v1/merchant/offers/ofr_a1b2c3d4e5/restore \
-H "Authorization: Bearer <session-jwt>" \
-H "x-merchant-id: mrc_9f8e7d6c5b"Exemplo de resposta — 201 Created
{
"id": "ofr_a1b2c3d4e5",
"product_id": "prd_a1b2c3d4e5",
"name": "Mensal",
"slug": "mensal",
"description": "Plano mensal padrão",
"billing_cycle": "monthly",
"custom_billing_days": null,
"cycle_limit": 12,
"free_trial": false,
"trial_days": null,
"setup_charge": false,
"renew_after_cycle_limit": false,
"renewal_offer_id": null,
"is_default": false,
"status": "active",
"created_at": "2026-05-19T12:00:00Z",
"updated_at": "2026-05-19T16:00:00Z"
}GET/api/v1/merchant/offers/:id/default-price
Auth: Dashboard session (JWT bearer). É necessário ser membro do Merchant.
Retorna o preço padrão de uma oferta para uma dada moeda, ou null se a oferta não tiver preço padrão nessa moeda.
Parâmetros de consulta
| Campo | Tipo | Obrigatório | Descrição |
|---|---|---|---|
currency | string | Sim | Código de moeda ISO 4217 para resolver o preço padrão. |
Exemplo de requisição
curl -G https://api.tokeflow.com/api/v1/merchant/offers/ofr_a1b2c3d4e5/default-price \
-H "Authorization: Bearer <session-jwt>" \
-H "x-merchant-id: mrc_9f8e7d6c5b" \
--data-urlencode "currency=BRL"Exemplo de resposta — 200 OK
{
"currency": "BRL",
"amount": 9900,
"is_default": true
}GET/api/v1/merchant/offers/:fromId/transitions/:toId/effective-behavior
Auth: Dashboard session (JWT bearer). É necessário ser membro do Merchant.
Resolve o change_charge_behavior efetivo para um par de transição de oferta — como uma assinatura movendo-se da oferta :fromId para a oferta :toId será cobrada. Use-o para pré-visualizar o comportamento de cobrança que o Dashboard aplicará antes de confirmar uma mudança de plano.
Exemplo de requisição
curl https://api.tokeflow.com/api/v1/merchant/offers/ofr_a1b2c3d4e5/transitions/ofr_f6g7h8i9j0/effective-behavior \
-H "Authorization: Bearer <session-jwt>" \
-H "x-merchant-id: mrc_9f8e7d6c5b"Exemplo de resposta — 200 OK
Erros
Respostas de erro comuns para este recurso:
| HTTP | Causa típica |
|---|---|
400 | Corpo inválido — ex.: prices ausente, billing_cycle: "custom" sem custom_billing_days, ou free_trial: true sem trial_days. |
401 | Sessão do dashboard ausente ou expirada. |
403 | O usuário da sessão não é membro do Merchant em x-merchant-id. |
404 | Oferta não encontrada ou não pertencente ao Merchant. |
409 | Exclusão recusada — a oferta é referenciada por pelo menos uma assinatura. |
Relacionados
- Produtos — as entradas de catálogo às quais as ofertas pertencem.
- Assinaturas — cobrança recorrente criada a partir de ofertas.
- Sessões de checkout — onde os clientes escolhem uma oferta e pagam.
- Autenticação do Dashboard — como as sessões do dashboard são emitidas.