POSTCriar promoção
Cria uma promoção automática ou por cupom, de carrinho ou de catálogo.
Crie uma promoção quando a loja quer dar desconto sem editar preço por preço: 10% no carrinho acima de R$ 200, frete grátis, compre 3 leve 4. A promoção nasce ativa (a menos que você mande outro status) e começa a valer na hora, se valid_from for omitido. Cada criação grava uma linha no registro de atividades do administrador.
A plataforma recusa de antemão as promoções que nasceriam "mortas": tipo desconhecido, desconto negativo, condição que não existe na zona escolhida, id de produto ou categoria que não existe, compre X leve Y sem a mecânica do brinde. Leia a mensagem do 400: ela diz o que corrigir.
Criar uma promoção
/api/v1/admin/promotionsAdminCria uma promoção
Cabeçalhos
X-Margin-OverridestringToken de exceção do Protetor de Margem, quando a oferta foi aprovada fora do piso.
Parâmetros de consulta
confirm_store_widebooleanpadrão: falseEnvie
true para confirmar que uma promoção de catálogo sem produto nem categoria deve valer para a loja toda.Corpo da requisição
namestringobrigatórioNome interno da promoção.
typestringobrigatóriopercentagefixedfree_shippingbuy_x_get_yto_percentageto_fixedorder_discountproduct_discountcategory_discountfree_productsgive_usergroupgive_couponfree_productassign_usergroupTipo da promoção. Veja a tabela de tipos na home da seção.
discountintegerPontos-base em
percentage (1000 = 10%, máximo 10000), centavos em fixed. Nunca negativo. Pode ser 0 em free_shipping e buy_x_get_y.descriptionstringDescrição livre.
codestringCódigo do cupom. Vira maiúsculo. Omita para promoção automática.
max_discountintegerTeto do desconto em centavos.
priorityintegerpadrão: 0Ordem de avaliação; menor primeiro.
stop_other_rulesbooleanpadrão: falseInterrompe a avaliação das promoções seguintes.
stackablebooleanpadrão: falsePode se combinar com outras acumuláveis.
conditionsobjectCondições simples. Veja a home da seção.
condition_groupsobjectCondições aninhadas E/OU.
bonusesarrayLista de bônus:
[{"bonus_type":"order_discount","config":{"discount_type":"by_percentage","discount_value":1000}}].bonus_typestringBônus único (formato antigo).
bonus_configobjectConfiguração do bônus único (formato antigo).
free_shipping_method_iduuidForma de envio que recebe frete grátis (tipo
free_shipping).usage_limitintegerpadrão: 0Máximo de usos no total.
0 = sem limite.per_user_limitintegerMáximo de usos por cliente.
valid_fromstring (RFC 3339)Início da vigência. Se omitido, vale a partir de agora.
valid_untilstring (RFC 3339)Fim da vigência. Se omitido, não expira.
statusstringactiveinactivedisabledexpireddraftADEactive, inactive/disabled, expired, draft (vira inativa) ou a letra. Vazio vira ativa.zonestringcartcatalogcart ou catalog. Veja como o padrão é escolhido na home da seção.vendor_iduuidAtribui a promoção a um seller. Omita para promoção da loja.
descriptionsobjectTextos por idioma: mapa de código de idioma (
pt-BR, en) para um objeto com o nome e a descrição traduzidos. Idiomas ausentes herdam name e description.Exemplo de requisição: criar
bash
curl -X POST "$BASE_URL/api/v1/admin/promotions" \
-H "Authorization: Bearer $TOKEN" \
-H "Content-Type: application/json" \
-d '{
"name": "Black Friday 10% nas camisas",
"type": "percentage",
"discount": 1000,
"code": "BLACK10",
"zone": "cart",
"conditions": {
"min_cart_total": 20000
},
"usage_limit": 500,
"per_user_limit": 1,
"valid_from": "2026-11-27T00:00:00-03:00",
"valid_until": "2026-11-29T23:59:59-03:00"
}'Resposta: criar
201Promoção criada
json
{
"id": "7c1f0a52-3b8e-4d11-9a47-5e2b6d8c1f30",
"name": "Black Friday 10% nas camisas",
"description": "",
"type": "percentage",
"code": "BLACK10",
"discount": 1000,
"conditions": { "min_cart_total": 20000 },
"usage_limit": 500,
"usage_count": 0,
"valid_from": "2026-11-27T03:00:00Z",
"valid_until": "2026-11-30T02:59:59Z",
"status": "A",
"priority": 0,
"stop_other_rules": false,
"stackable": false,
"zone": "cart",
"condition_groups": null,
"bonus_type": null,
"bonus_config": null,
"bonuses": [],
"free_shipping_method_id": null,
"per_user_limit": 1,
"created_at": "2026-10-11T14:02:10.482113Z",
"updated_at": "2026-10-11T14:02:10.482113Z",
"promotion_id": "7c1f0a52-3b8e-4d11-9a47-5e2b6d8c1f30",
"coupon_id": "7c1f0a52-3b8e-4d11-9a47-5e2b6d8c1f30",
"bonus_value": 1000,
"from_date": 1795748400,
"expiry_date": 1796007599,
"users": 0,
"timestamp": 1791727330,
"updated_timestamp": 1791727330
}201Criada, mas com campos ignorados
json
{
"id": "7c1f0a52-3b8e-4d11-9a47-5e2b6d8c1f30",
"name": "Black Friday 10% nas camisas",
"valid_until": null,
"...": "demais campos como acima",
"ignored_fields": ["end_at", "title"],
"warning": "a promoção foi criada, mas estes campos do corpo não entraram nela: end_at, title. Campos aceitos: vendor_id, name, ..."
}Campos da resposta
iduuidIdentificador da promoção (UUID).
vendor_iduuid | omittedSeller dono da promoção. Ausente quando a promoção vale para a loja toda.
namestringNome interno, mostrado no painel.
descriptionstringDescrição livre. Pode ser vazia.
typestringTipo da promoção (veja a tabela de tipos na home da seção).
codestring | nullCódigo do cupom, sempre em maiúsculas.
null quando a promoção é automática.discountintegerValor do desconto. Em
percentage são pontos-base (1000 = 10%). Em fixed são centavos (2500 = R$ 25,00).max_discountinteger | omittedTeto do desconto em centavos. Ausente quando não há teto.
conditionsobjectCondições simples (veja a home da seção).
{} quando não há.condition_groupsobject | nullCondições aninhadas E/OU.
null quando não há.usage_limitintegerMáximo de usos no total.
0 = sem limite.per_user_limitinteger | omittedMáximo de usos por cliente.
usage_countintegerQuantas vezes já foi usada em pedidos.
valid_fromstring (RFC 3339)Início da vigência, em UTC.
valid_untilstring (RFC 3339) | nullFim da vigência, em UTC.
null = sem fim.statusstringLetra do status:
A ativa, D inativa, E expirada.priorityintegerOrdem de avaliação. Menor número é avaliado primeiro.
stop_other_rulesbooleanQuando
true, as promoções seguintes deixam de ser avaliadas.stackablebooleanQuando
true, pode se combinar com outras promoções acumuláveis.zonestringcart (carrinho) ou catalog (preço na vitrine).bonus_typestring | nullTipo de bônus único (formato antigo). Prefira
bonuses.bonus_configobject | nullConfiguração do bônus único (formato antigo).
bonusesarrayLista de bônus. Cada item tem
bonus_type e config.free_shipping_method_iduuid | nullForma de envio que ganha frete grátis, quando o tipo é
free_shipping.labelsobjectSó no detalhe de uma promoção: mapa de id para nome (produto, categoria, seller, grupo) de tudo que as condições citam.
catalog_scopeobject | omittedSó em promoções de catálogo: alcance real, com
store_wide (loja toda), products e categories (quantidades).created_atstring (RFC 3339)Criação.
updated_atstring (RFC 3339)Última alteração.
ignored_fieldsarray of string | omittedSó aparece quando o corpo trouxe chaves desconhecidas. Elas foram descartadas.
warningstring | omittedTexto (em português) que lista as chaves descartadas e as aceitas.
promotion_id, coupon_id, bonus_value, from_date, expiry_date, users, timestamp, updated_timestampmixedApelidos que repetem
id, discount, valid_from, valid_until (estes dois em segundos Unix), usage_count e as datas de criação e alteração. coupon_id só vem quando há código. Em integrações novas ignore-os.Erros: criar
| Status | Quando | Corpo de exemplo |
|---|---|---|
| 401 | Token ausente ou inválido. | {"error":"authentication required"} |
| 403 | O módulo promotions está desligado na loja. | {"error":"module_disabled","module":"promotions"} |
| 403 | O usuário não tem o privilégio exigido (view_promotions para ler, manage_promotions para gravar). | {"error":"insufficient privileges","required":"manage_promotions"} |
| 400 | name ou type ausente. | {"error":"name is required","detail":"campos aceitos: vendor_id, name, ..."} |
| 400 | Corpo não é JSON válido, ou um valor com formato errado (por exemplo data sem hora). A mensagem diz o campo e o formato. | {"error":"invalid request body","detail":"..."} |
| 400 | Validação de regra: tipo, desconto, status, condição, zona ou escopo inválidos. A mensagem é em português e traz as opções aceitas. | {"error":"invalid promotion type: percent; tipos aceitos: percentage, fixed, ...","detail":""} |
| 400 | Promoção de catálogo para a loja toda sem confirm_store_wide=true. | {"error":"store_wide_unconfirmed","detail":"esta promoção de catálogo não tem produto nem categoria e vale para a LOJA TODA. ..."} |
| 409 | O código já pertence a outra promoção não excluída. | {"error":"coupon_code_in_use","detail":"este código de cupom já está em outra promoção ..."} |
| 422 | A oferta fica abaixo do piso de margem (Protetor de Margem). O corpo é o detalhamento da conta. | {"ok":false,"floor_bps":1500,"reason":"below_floor","worst":{...},"violations":[...]} |
| 500 | Falha inesperada ao gravar. | {"error":"failed to create promotion","detail":"..."} |