Gerenciar promoções
Listar promoções
GET /api/promotionsPermissão: Cadastro de promoções — visualização
Retorna as promoções da loja (exceto as excluídas), com filtros e paginação.
Query params
| Parâmetro | Tipo | Descrição |
|---|---|---|
page | int | Página, começando em 1. Padrão: 1. |
limit | int | Itens por página, de 1 a 100. Padrão: 10. |
search | string | Trecho do nome, ID exato ou código de cupom. %, _ e [ são buscados como texto. |
status | string | Ativa, Inativa, Expirada ou Programada, sem diferenciar maiúsculas (veja Status). Omita para trazer todas. |
active | bool | Filtra pelo indicador de ativação. |
initialDate | datetime | Início do período a filtrar. Só tem efeito junto com finalDate: retorna as promoções cuja vigência se sobrepõe ao período. |
finalDate | datetime | Fim do período a filtrar. Só tem efeito junto com initialDate. |
promotionsDate | enum | Período pré-definido; quando informado, substitui initialDate/finalDate. Valores em Períodos (nome ou número). |
hasCoupons | bool | Somente promoções com (true) ou sem (false) cupom. |
hasMultipleCoupons | bool | Somente promoções com múltiplos cupons. |
canAccumulate | bool | Filtra pelo indicador de acúmulo. |
conditions | long[] | Promoções que usam estes tipos de condição. IDs de GET /api/promotions/conditions (promotionConditionId). |
actions | long[] | Promoções que usam estes tipos de ação. IDs de GET /api/promotions/actions (promotionActionId). |
orderField | string | name, initialDate, finalDate ou order (prioridade), exatamente com essa grafia. Padrão: order. |
orderBy | string | asc ou desc. Padrão: desc. |
Valores fora das faixas e listas acima retornam 400 (VALIDATION_FAILED), com o parâmetro em details[].field.
Exemplo
curl "https://{loja}.commerce-wake.tech/api/promotions?status=Ativa&hasCoupons=true&page=1&limit=20&orderField=initialDate&orderBy=desc" \
-H "Authorization: Bearer {access_token}" \
-H "x-api-version: 2.0"Resposta 200
200{
"data": [
{
"promotionId": 1234,
"name": "Black Friday — 10% em Camisetas",
"description": null,
"initialDate": "2026-11-27T00:00:00-03:00",
"finalDate": "2026-11-30T23:59:59-03:00",
"active": true,
"status": "Programada",
"order": 1,
"coupons": ["BLACK10"],
"hasCoupon": true,
"hasMultipleCoupons": false,
"totalCouponsLimit": 1000,
"totalCouponsPerCustomer": 1,
"totalCouponsUsed": 0,
"canAccumulate": true,
"accumulationScope": 0,
"accumulationLinkCount": 0
}
],
"total": 1,
"page": 1,
"limit": 20
}| Campo | Descrição |
|---|---|
total | Total de promoções que atendem aos filtros (para paginação). |
page / limit | Página e tamanho de página usados. |
order | Prioridade. Pode ser null. |
description | Sempre null na listagem. Use Obter promoção. |
totalCouponsLimit / totalCouponsPerCustomer | Limites de uso total e por cliente (0 = ilimitado). |
totalCouponsUsed | Usos já realizados (pedidos cancelados não contam). |
accumulationLinkCount | Quantidade de promoções na lista de acúmulo. |
Períodos (promotionsDate)
promotionsDate)| Valor | Nome | Período | Valor | Nome | Período |
|---|---|---|---|---|---|
| 1 | Today | Hoje | 8 | Next30Days | Próximos 30 dias |
| 2 | Yesterday | Ontem | 9 | Next6Months | Próximos 6 meses |
| 3 | Last7Days | Últimos 7 dias | 10 | CurrentWeek | Semana atual |
| 4 | Last30Days | Últimos 30 dias | 11 | CurrentMonth | Mês atual |
| 5 | Last6Months | Últimos 6 meses | 12 | CurrentSemester | Semestre atual |
| 6 | Tomorrow | Amanhã | 13 | Last12Months | Últimos 12 meses |
| 7 | Next7Days | Próximos 7 dias |
Obter promoção
GET /api/promotions/{promotionId}Permissão: Cadastro de promoções — visualização
Retorna todos os dados de uma promoção. Retorna 404 se a promoção não existir ou tiver sido excluída.
| Path param | Tipo | Descrição |
|---|---|---|
promotionId (obrigatório) | int | ID da promoção (de Listar promoções ou da resposta de criação). |
Resposta 200
200{
"data": {
"generalInformation": {
"name": "Black Friday — 10% em Camisetas",
"description": "Campanha de Black Friday",
"isActive": true,
"startDate": "2026-11-27T00:00:00-03:00",
"endDate": "2026-11-30T23:59:59-03:00",
"canAccumulate": true,
"accumulationScope": 0,
"order": 1,
"totalUsageLimit": 1000,
"usageLimitPerCustomer": 1
},
"couponInformation": {
"couponCodes": ["BLACK10"],
"multipleCouponConfig": { "hasMultipleCoupons": false, "allowCustomerToReuseSameCoupon": false },
"couponTotalUsageLimit": 1000,
"couponUsageLimitPerCustomer": 1
},
"conditionGroups": [
{
"id": 881,
"name": "Grupo 1",
"conditions": [
{
"conditionGroup": 5,
"conditionSubGroup": 16,
"conditionPromotionId": 5521,
"logicOperator": { "id": 3, "arguments": [ { "id": 4, "name": "Valor", "values": ["199.90"], "optional": null } ] }
}
]
}
],
"discounts": [
{
"discountGroup": 1,
"discountSubGroup": 2,
"discountPromotionId": 7310,
"arguments": [
{ "id": 1, "name": "ValorDesconto", "values": ["10"], "optional": false },
{ "id": 3, "name": "CategoriasId", "values": ["15", "22"], "optional": false },
{ "id": 13, "name": "IgnorarProdutosRemarcados", "values": ["false"], "optional": false }
]
}
],
"entityRules": [ { "entityId": 3, "validationId": 4, "restrictionId": 2, "arguments": ["12"] } ],
"stamps": [ { "stampId": 31, "name": "Black Friday", "active": true, "order": 1, "urlImage": "https://..." } ],
"disclosure": [ { "type": "1", "title": "Black Friday", "content": "<strong>10% OFF</strong> em camisetas" } ],
"partners": [],
"accumulationLinks": [],
"accumulationLinkDetails": [],
"accumulationInboundLinks": []
}
}Campos que só existem na resposta
| Campo | Descrição |
|---|---|
conditionGroups[].id | ID do grupo de condições. Pode ser reenviado no PUT, mas é ignorado. |
conditionPromotionId | ID da condição nesta promoção. Usado em Clientes de uma condição e Categorias de uma condição. |
discountPromotionId | ID do desconto nesta promoção. Usado em Categorias de um desconto. |
arguments[].name / optional | Nome do argumento e se ele é complementar. |
stamps[].name / active / urlImage | Dados do selo. |
accumulationLinkDetails | Detalhes (promotionId, name, isActive, startDate, endDate) das promoções em accumulationLinks. |
accumulationInboundLinks | Promoções que citam esta no acúmulo delas (promotionId, name, accumulationScope, isActive). Enquanto houver itens, esta promoção não pode passar a “não acumular”. |
Os nomes de campos da resposta são os mesmos do corpo de Criar promoção. disclosure[].type volta como string ("1") e pode ser reenviado assim.
Os IDs internos mudam a cada atualização
conditionGroups[].id,conditionPromotionIdediscountPromotionIdsão gerados de novo em todoPUT. Leia a promoção novamente antes de usá-los.
Exceção: condição de clientes específicosA condição de clientes específicos retorna em
values[0]a quantidade de clientes vinculados, não os IDs. Se a promoção tiver mais de uma condição desse tipo, só a primeira vem como quantidade; as demais vêm com a lista de IDs, que também não pode ser reenviada como está. Para reenviar uma promoção lida, siga Editar uma promoção existente.
Criar promoção
POST /api/promotionsPermissão: Cadastro de promoções — visualização e edição
Cria uma promoção. O mesmo corpo é usado em Atualizar promoção.
Corpo da requisição
| Campo | Tipo | Descrição |
|---|---|---|
generalInformation (obrigatório) | object | Informações gerais (tabela abaixo). |
couponInformation (obrigatório) | object | Cupons. Envie mesmo em promoções sem cupom, com couponCodes: []. |
conditionGroups | array | Grupos de condições (veja Condições e grupos e Receitas). Omitido ou [] = sem condições. |
discounts | array | Descontos (veja Receitas de descontos). |
entityRules | array | Regras adicionais (veja Regras adicionais). |
stamps | array | [{ "stampId": int, "order": int }]. IDs em Onde obter os IDs. |
disclosure | array | [{ "type": 1|2, "title": string, "content": string }]. 1 = spot, 2 = página de produto. title até 50 caracteres. |
partners | int[] | IDs de parceiros. [] = sem restrição. |
accumulationLinks | long[] | IDs de promoções da lista de acúmulo (veja Acúmulo). |
Omita listas vazias ou envie[], nuncanullListas omitidas valem como
[]. Na criação,discounts,entityRules,stamps,disclosureoupartnersenviados comonullresultam em erro500. Em criação e atualização,values: nulleconditions: nulldentro de um grupo também resultam em500. Uma condição ou desconto semarguments(ou comnull) é descartado sem erro. A exceção éaccumulationLinks(veja Acúmulo).
generalInformation
generalInformation| Campo | Tipo | Descrição |
|---|---|---|
name (obrigatório) | string | Nome da promoção. Até 250 caracteres. |
description | string | Descrição interna. Até 1000 caracteres. |
startDate (obrigatório) | datetime | Início da vigência. |
endDate (obrigatório) | datetime | Fim da vigência. Maior que startDate e que o momento atual. |
isActive | bool | Se a promoção nasce ativa. Padrão: false. |
order | int | Prioridade (menor = avaliada antes). null, zero ou positivo. Padrão: null. |
canAccumulate | bool | Se acumula com outras promoções. Padrão: false. |
accumulationScope | int | 0 todas, 1 todas exceto as selecionadas, 2 somente as selecionadas. Padrão: 0. |
totalUsageLimit | int | Limite total de usos. 0, null ou omitido = ilimitado. |
usageLimitPerCustomer | int | Limite de usos por cliente. 0, null ou omitido = ilimitado. |
Textos acima do limite retornam 400 com o campo em details[].field.
couponInformation
couponInformation| Campo | Tipo | Descrição |
|---|---|---|
couponCodes (obrigatório) | string[] | Códigos de cupom. [] para promoções sem cupom. A quantidade define o tipo da promoção (veja Cupons). |
multipleCouponConfig.allowCustomerToReuseSameCoupon | bool | Permite que o mesmo cliente reutilize um código. Só com mais de um cupom. |
multipleCouponConfig.hasMultipleCoupons | bool | Somente leitura. É deduzido da quantidade de códigos e ignorado na escrita. |
couponTotalUsageLimit | int | Alternativa a totalUsageLimit (usada quando este é null). |
couponUsageLimitPerCustomer | int | Alternativa a usageLimitPerCustomer. |
Condição, desconto e regra adicional
| Objeto | Formato |
|---|---|
| Grupo de condições | { "name": string, "conditions": [condição] } |
| Condição | { "conditionGroup": int, "conditionSubGroup": int, "logicOperator": { "id": int, "arguments": [{ "id": int, "values": [string] }] } } |
| Desconto | { "discountGroup": int, "discountSubGroup": int, "arguments": [{ "id": int, "values": [string] }] } |
| Regra adicional | { "entityId": int, "validationId": int, "restrictionId": int, "arguments": [string] } |
arguments e values nunca devem ser null; use []. Argumentos com values vazio são descartados. Campos extras (como name dos argumentos, presentes na resposta do GET) são ignorados.
Exemplo
Cupom BLACK10: com subtotal a partir de R$ 199,90 e entrega em SP ou RJ, dá 10% nas categorias 15 e 22 e frete grátis, sem descontar produtos da marca 12.
curl -X POST "https://{loja}.commerce-wake.tech/api/promotions" \
-H "Authorization: Bearer {access_token}" \
-H "x-api-version: 2.0" \
-H "Content-Type: application/json" \
-d '{
"generalInformation": {
"name": "Black Friday — 10% em Camisetas",
"description": "Campanha de Black Friday",
"startDate": "2026-11-27T00:00:00-03:00",
"endDate": "2026-11-30T23:59:59-03:00",
"isActive": true,
"order": 1,
"canAccumulate": true,
"accumulationScope": 0,
"totalUsageLimit": 1000,
"usageLimitPerCustomer": 1
},
"couponInformation": {
"couponCodes": ["BLACK10"],
"multipleCouponConfig": { "allowCustomerToReuseSameCoupon": false }
},
"conditionGroups": [
{
"name": "Grupo 1",
"conditions": [
{ "conditionGroup": 5, "conditionSubGroup": 16,
"logicOperator": { "id": 3, "arguments": [ { "id": 4, "values": ["199.90"] } ] } },
{ "conditionGroup": 2, "conditionSubGroup": 7,
"logicOperator": { "id": 7, "arguments": [ { "id": 9, "values": ["25", "19"] } ] } }
]
}
],
"discounts": [
{ "discountGroup": 1, "discountSubGroup": 2,
"arguments": [
{ "id": 1, "values": ["10"] },
{ "id": 3, "values": ["15", "22"] },
{ "id": 13, "values": ["false"] }
] },
{ "discountGroup": 2, "discountSubGroup": 2,
"arguments": [ { "id": 1, "values": ["100"] } ] }
],
"entityRules": [
{ "entityId": 3, "validationId": 4, "restrictionId": 2, "arguments": ["12"] }
],
"stamps": [ { "stampId": 31, "order": 1 } ],
"disclosure": [ { "type": 1, "title": "Black Friday", "content": "<strong>10% OFF</strong> em camisetas" } ],
"partners": []
}'No exemplo: 5/16 com operador 3 e argumento 4 = subtotal ≥ R$ 199,90; 2/7 com operador 7 e argumento 9 = estado de entrega em São Paulo (25) ou Rio de Janeiro (19); o desconto 1/2 com argumentos 1 e 3 = 10% nas categorias; 2/2 com 100 = 100% de desconto no frete; a regra adicional 3/4/2 = não aplicar o desconto em produtos da marca 12.
Resposta 201
201Header Location: /api/promotions/1234.
{ "data": { "promotionId": 1234 } }Resposta 400
400{
"code": "VALIDATION_FAILED",
"displayMessage": "A promoção não pôde ser salva",
"details": [
{ "code": "END_DATE_IS_REQUIRED", "issue": "A data de término é um campo obrigatório" },
{ "code": "DISCOUNT_PERCENTAGE_OUT_OF_RANGE", "issue": "O percentual de desconto da ação (Id 5) deve ser maior que 0 e no máximo 100; valor informado: 150" }
],
"traceId": "0HN7…:00000001"
}Os códigos estão em Códigos de erro. A validação acontece em duas etapas: primeiro as regras acima; só se todas passarem, as regras da gravação (datas, cupons já usados, IDs inexistentes, operadores e argumentos incompatíveis) são conferidas e voltam como um item PRIVATE_API_VALIDATION, com uma ou mais mensagens separadas por quebra de linha em issue. Corrija tudo e reenvie, porque uma nova etapa pode trazer outros erros.
Atualizar promoção
PUT /api/promotions/{promotionId}Permissão: Cadastro de promoções — visualização e edição
Substitui todos os dados da promoção pelo conteúdo enviado. O corpo é idêntico ao de Criar promoção.
Substituição completaCondições, descontos, regras adicionais, selos, textos de divulgação e parceiros que não estiverem no corpo são removidos — uma lista omitida vale como
[]. Para alterar um único campo, leia a promoção, altere o campo e reenvie tudo — veja Editar uma promoção existente.A única exceção é
accumulationLinkscom escopo1ou2: se for omitido (ounull), os vínculos atuais são mantidos (veja Acúmulo).
| Path param | Tipo | Descrição |
|---|---|---|
promotionId (obrigatório) | int | ID da promoção. |
Grupos de condições, condições e descontos são recriados a cada atualização, então conditionGroups[].id, conditionPromotionId e discountPromotionId mudam. Leia a promoção de novo antes de usar esses IDs.
Resposta 200
200{ "data": { "promotionId": 1234 } }Erros
| Status | Quando |
|---|---|
400 | Corpo inválido ou regra de negócio recusada, no mesmo formato de Criar promoção. Os erros de formato e da primeira etapa de regras podem aparecer antes do 404. |
404 | Promoção inexistente ou excluída. code NOT_FOUND; o texto “Promoção não encontrada.” vem em details[0].issue. |
500 | Erro inesperado ao gravar. Leia a promoção para conferir o estado e tente de novo. |
Promoções gravadas com percentual fora da faixaPromoções antigas com desconto percentual igual a 0 ou acima de 100 recebem
400(DISCOUNT_PERCENTAGE_OUT_OF_RANGE) em qualquer atualização até o valor ser corrigido para a faixa (0, 100].
Ativar / inativar promoção
PUT /api/promotions/{promotionId}/statusPermissão: Ativação de promoções — visualização e edição
Liga ou desliga a promoção sem alterar o restante do cadastro.
| Campo | Tipo | Descrição |
|---|---|---|
active (obrigatório) | bool | true ativa, false inativa. |
startDate | datetime | Nova data de início. Use só ao ativar, junto com endDate. |
endDate | datetime | Nova data de término, maior que o início e que o momento atual. |
Vigência ao ativarSem datas, a promoção é ativada com a vigência atual. Se essa vigência já terminou, a resposta é
400, comdisplayMessagecontendo “A promoção está expirada; informe uma nova data de término para ativá-la.” (a mensagem pode trazer vários motivos, um por linha): enviestartDateeendDate, que então substituem a vigência. Enviar só uma das datas é recusado. Ao inativar, omita as datas: elas não são gravadas.
curl -X PUT "https://{loja}.commerce-wake.tech/api/promotions/1234/status" \
-H "Authorization: Bearer {access_token}" -H "x-api-version: 2.0" -H "Content-Type: application/json" \
-d '{ "active": true }'Resposta 200
200{ "data": { "success": true, "message": "..." } }Erros
| Status | Quando |
|---|---|
400 | active ausente, datas incompletas ou inválidas, promoção expirada sem nova data. O motivo vem em displayMessage. |
404 | Promoção inexistente ou excluída. |
500 | Erro inesperado. |
Duplicar promoção
POST /api/promotions/duplicatePermissão: Cadastro de promoções — visualização e edição
Cria uma cópia de uma promoção existente com um novo nome.
| Campo | Tipo | Descrição |
|---|---|---|
promotionId (obrigatório) | long | ID da promoção de origem. |
name (obrigatório) | string | Nome da nova promoção. Não pode repetir o nome de outra promoção. |
{ "promotionId": 1234, "name": "Black Friday — 10% em Camisetas (cópia)" }Resposta 201
201Header Location: /api/promotions/1250.
{ "data": { "promotionId": 1250 }, "message": "... Nova promoção com Id: 1250" }Erros
| Status | Quando |
|---|---|
400 | name ausente. |
404 | A promoção de origem não existe ou promotionId não foi informado (verificado antes do nome). |
409 | O nome já é usado por outra promoção (“Já existe uma promoção com o nome preenchido”). |
500 | Erro inesperado. |
Revise a cópia com Obter promoção antes de ativá-la: se a vigência da origem já passou, ajuste as datas com Atualizar promoção.
Excluir promoções
POST /api/promotions/batch-deletePermissão: Cadastro de promoções — visualização e edição
Exclui de 1 a 100 promoções por requisição. Promoções excluídas deixam de ser aplicadas e de aparecer nas consultas. IDs repetidos são processados uma vez.
| Campo | Tipo | Descrição |
|---|---|---|
promotionIds (obrigatório) | long[] | De 1 a 100 IDs, todos maiores que zero. Fora disso a resposta é 400 (VALIDATION_FAILED). |
curl -X POST "https://{loja}.commerce-wake.tech/api/promotions/batch-delete" \
-H "Authorization: Bearer {access_token}" -H "x-api-version: 2.0" -H "Content-Type: application/json" \
-d '{ "promotionIds": [1234, 1250] }'Resposta 200
200{
"data": {
"results": [
{ "promotionId": 1234, "deleted": true, "message": "Promoção deletada com sucesso." },
{ "promotionId": 1250, "deleted": false, "message": "Promoção não encontrada." }
]
}
}O resultado é individual: verifique deleted de cada item. A resposta é 200 sempre que houver resultado por item, mesmo quando nenhuma promoção é excluída. Uma falha da requisição inteira (sem resultado por item) retorna um status de erro, normalmente 500.
Histórico de alterações
GET /api/promotions/{promotionId}/logsPermissão: Cadastro de promoções — visualização e edição
Retorna as alterações mais recentes registradas para a promoção nos últimos 120 dias, da mais nova para a mais antiga. Cada registro traz quem alterou, quando, e uma fotografia da promoção naquele momento. O único parâmetro de consulta suportado é limit; não envie outros.
| Parâmetro | Tipo | Descrição |
|---|---|---|
promotionId (obrigatório) | int (path) | ID da promoção. |
limit | int (query) | Quantidade de registros, de 1 a 100. Padrão: 10. |
{
"data": [
{ "changeDate": "2026-10-14T16:32:10-03:00", "user": "integracao-erp", "payload": "{\"dataAlteracao\":\"...\",\"autor\":\"integracao-erp\", ...}" }
],
"total": 1, "totalGeneral": 1, "page": 1, "limit": 10
}| Campo | Descrição |
|---|---|
changeDate | Data e hora da alteração. |
user | Autor da alteração, obtido do token (o client_id, para aplicações). |
payload | String com o JSON completo do registro de histórico. |
total | Quantidade de registros retornados nesta resposta (não o total existente). |
Updated about 2 hours ago

