Referência da API
Atualizar oferta
Atualiza campos da Offer. Campos snapshot (amount, billingCycle, billingCycleCount, maxCycles, trialDays) são bloqueados se a Offer tem assinaturas ou PaymentLinks ativos — a API recusa com 400 listando quantos dependentes ativos existem. Verifique stats.canEditSnapshotFields em GET /v2/offers/:id antes de tentar editar.
Campos sempre editáveis: name, description, active, externalId, metadata e os de vitrine (successUrl, failureUrl, checkoutLogoUrl, checkoutBrandColor, checkoutLocale, metaPixelId, googleAdsId, googleAdsLabel, tiktokPixelId) — ver Personalizar o checkout. Mandar null num campo de vitrine limpa ele.
PDF de entrega: este endpoint não aceita deliveryPdfUrl no corpo. Use POST /v2/offers/:id/delivery-pdf pra trocar ou DELETE /v2/offers/:id/delivery-pdf pra remover.
/v2/offers/:idamount Tentar editar amount/billingCycle/etc com assinaturas ativas retorna 400. Use stats.canEditSnapshotFields pra saber se pode editar, ou simplesmente crie uma Offer nova com o valor corrigido e desative a antiga via active: false.Autenticação
HTTP Basic Auth. Envie sua secret key no header:
Authorization: Basic {base64(secret:SUA_SECRET_KEY)}Parâmetros
idstring (path, UUID)obrigatórioUUID da Offer.
Exemplo: off_xyz789
Body da requisição
Content-Type: application/json
// Edição segura (sem campos de preço/ciclo):
{
"name": "Plano Mensal Premium",
"description": "Atualizado com novo material",
"active": false
}
// Tentativa de editar preço/ciclo (vai dar 400 se houver dependentes):
{
"amount": 5900,
"trialDays": 14
}Respostas
Offer atualizada.
{
"id": "off_xyz789",
"name": "Plano Mensal Premium",
"active": false,
"updatedAt": "2026-05-26T16:00:00.000Z"
}Causas: tentou editar campos de preço/ciclo com dependentes ativos, validação falhou, externalId já existe, ou Offer arquivada.
{
"status": 400,
"error": "Esta oferta tem 47 assinatura(s) ativa(s) e 2 link(s) de pagamento ativo(s). Os campos amount, trialDays nao podem ser alterados — crie uma nova oferta com o valor atualizado e desative esta."
}Offer não encontrada.
{ "status": 404, "error": "Oferta nao encontrada" }Exemplos
# Edição segura — desativa a oferta sem mudar valores
curl -X PATCH "https://api.ihubplay.com/v2/offers/off_xyz789" \
-H "Authorization: Basic $(echo -n 'secret:SUA_SECRET_KEY' | base64)" \
-H "Content-Type: application/json" \
-d '{ "active": false }'// Padrão: cria oferta nova e desativa a antiga (mudança de preço segura)
const token = Buffer.from("secret:" + process.env.IHUBGAMES_SECRET_KEY).toString("base64");
const headers = { Authorization: `Basic ${token}`, "Content-Type": "application/json" };
// 1. Cria oferta nova com preço novo
const novaOferta = await fetch("https://api.ihubplay.com/v2/offers", {
method: "POST", headers,
body: JSON.stringify({
productId: oldOffer.productId,
name: oldOffer.name + " — preço 2026",
amount: 5900, // novo preço em centavos
billingCycle: oldOffer.billingCycle,
billingCycleCount: oldOffer.billingCycleCount,
maxCycles: oldOffer.maxCycles,
trialDays: oldOffer.trialDays,
}),
}).then(r => r.json());
// 2. Desativa a antiga (mas mantém ela ativa pra subs existentes)
await fetch(`https://api.ihubplay.com/v2/offers/${oldOffer.id}`, {
method: "PATCH", headers,
body: JSON.stringify({ active: false }),
});
// 3. Atualiza seus PaymentLinks pra apontar pra nova oferta
// (PaymentLink usa offerId — veja docs de PaymentLinks)