Tratar cobrança na sua integração
Uma função quoteAndRun pronta para cotar e executar operações pagas, com limite de custo, cotação vencida e resultado incerto tratados.
Toda operação paga passa por cotação. Em vez de repetir isso em cada chamada, centralize numa função que:
- cota com o
requestexato; - recusa se o custo máximo passar do seu teto ou se faltar saldo (
dueCents > 0); - executa com o
quoteId; - se a cotação venceu entre os passos (
BILLING_QUOTE_EXPIRED), cota de novo uma vez; - não repete em resultado incerto (
OUTCOME_UNCERTAIN,RPC_DEADLINE_EXCEEDED): devolve o erro para você conferir o estado.
Valores em micro-reais: 1000000 = R$ 1,00.
const API = process.env.ZYNZAP_API_BASE_URL ?? "https://api.zynzap.com.br/v1";
class ZynzapError extends Error {
constructor(status, error) {
super(`${error.code} ${error.reason ?? ""}: ${error.message}`);
Object.assign(this, { status, ...error });
}
}
async function post(path, body) {
const response = await fetch(`${API}${path}`, {
method: "POST",
headers: { Authorization: `Bearer ${process.env.ZYNZAP_API_KEY}`, "Content-Type": "application/json" },
body: JSON.stringify(body),
});
const data = await response.json();
if (!response.ok) throw new ZynzapError(response.status, data.error);
return data;
}
/** Cota e executa uma operação paga. `maxMicrobrl`: teto aceito (ex.: 200000 = R$ 0,20). */
export async function quoteAndRun(method, request, { maxMicrobrl = 1_000_000 } = {}) {
for (let attempt = 0; attempt < 2; attempt++) {
const quote = await post("/billing/quotes", { method, request });
if (BigInt(quote.maxMicrobrl) > BigInt(maxMicrobrl)) throw new Error(`Custo acima do teto: ${quote.maxMicrobrl}`);
if (quote.dueCents > 0) throw new Error(`Saldo insuficiente: faltam ${quote.dueCents} centavos`);
try {
return await post(`/rpc/${method}`, { request, billing: { quoteId: quote.quoteId } });
} catch (error) {
if (error.reason === "BILLING_QUOTE_EXPIRED" && attempt === 0) continue; // cota de novo uma vez
throw error; // inclui OUTCOME_UNCERTAIN: confira o estado antes de repetir
}
}
}
// Uso:
// await quoteAndRun("SendMessage", { session_id: "...", to_jid: "5511987654321", text: "Olá!" }, { maxMicrobrl: 200_000 });Saldo e excedente
dueCents > 0na cotação significa que falta saldo. Compre créditos ou habilite o excedente mensal no cartão no painel (Plano e consumo); a cotação mostra quanto entraria no excedente emmonthlyOverageMicrobrl.- Campanhas grandes reservam o custo máximo inteiro na execução. O que não for usado volta para o saldo ao terminar ou cancelar.
Custos gratuitos
- Leituras, configurações, contatos, CRM e eventos não custam nada.
- Respostas pelo atendimento dentro de 24 horas da última mensagem do cliente saem com
coverage: "inbox_window"e custo zero (ainda com cotação). - Isenções concedidas pelo Zynzap aparecem como
coverage: "waived".