AbacatePay
Pix and boleto, no card. HMAC-SHA256 webhooks and a BRL-only, decimal-reais API.
- Methods: pix, boleto, undefined — no credit card (routing
credit_cardhere throws at the manager, not at the gateway). - Setup:
payments.abacate({ apiKey, webhookSecret })—ABACATE_API_KEY/ABACATE_PUBLIC_KEY. - Webhooks: HMAC-SHA256 (base64) over the raw body in
x-webhook-signature, verified timing-safe againstwebhookSecret(the dashboard's "public key"). Eventscheckout.completed,checkout.refunded,checkout.disputed, the matchingtransparent.*trio, andsubscription.completed/renewed/cancelled. - Idempotency: AbacatePay has none —
refund,createCustomer,createSubscriptionandupdateSubscriptionthrow on anidempotencyKeyrather than dropping it. - Subscriptions: recurring — no transparent checkout for the recurring charge yet.
- Transparent checkout:
chargeusesPOST /v2/transparents/create— PIX and Boleto inline, no redirect. The response carries the QR (brCodeBase64→pixQrCodeImage,brCode→pixCode) or the barcode (url→hostedUrl). Needs the payer'sname+taxId— pass them via the charge'scustomerblock or create the gateway customer with them.
Webhook verification is required at boot
This driver reports webhookVerification: 'unconfigured' — and the app refuses to boot — when
neither webhookSecret nor publicKey is configured (env fallback ABACATE_PUBLIC_KEY).
Set it before you deploy, or — only when verification genuinely happens upstream — name this
provider in allowUnverifiedWebhooks. An empty credential slot is not "skip verification": with nothing to check against,
POST /payments/webhook/abacate would accept any body anyone posted to it — including one
that marks a payment paid. The app refuses to start instead. See Configuration.
Chargebacks
checkout.disputed and transparent.disputed — "Disputa/chargeback aberta em um
checkout" and "…em um pagamento transparente", one per charge flow — normalize to
payment.disputed, not payment.failed. A failed payment says the money never moved; a
chargeback says it moved and came back. Only the second one means an account's access has to
be reconsidered, and a row that says failed never raises that question.
Those two events are AbacatePay's entire dispute vocabulary. The published event list —
checkout.*, transparent.*, subscription.*, transfer.*, payout.* — has nothing
before a dispute and nothing after it, so this driver emits neither
payment.dispute_warning nor payment.dispute_closed here, and a test keeps a later edit
from inventing one.
Opened is the only dispute signal AbacatePay sends
There is no fraud alert, no retrieval request and no "a chargeback is incoming"
notification, so nothing warns you while a refund would still stop the chargeback being
filed. And there is no *.dispute_won / *.dispute_lost event and no dispute value in the
billing status enum, so the outcome never reaches you as a webhook either. Both ends are
reconciliation work.
Two things AbacatePay's reference does not answer
It does not say whether the funds are withdrawn when *.disputed fires — the event
list gives one line per event and there is no payload example for these two — and it
publishes no response deadline anywhere, so the normalized event carries no
actionableUntil. The mapping stays at payment.disputed rather than being demoted to a
warning on a guess: a filed dispute is what that event names. If you need to know where the
money is, read event.raw.data and the billing's own status.
Idempotency: AbacatePay has none
No endpoint documents an idempotency header or field — the only request header on any of
them is Authorization, and AbacatePay's own guidance mentions idempotency solely for
consuming webhooks (dedupe on the event id). So refund, createCustomer,
createSubscription and updateSubscription throw when handed an idempotencyKey:
silently dropping it would turn a caller's retry guarantee into a second refund.
charge() still accepts one, as it always has, but not as deduplication — it is a legacy
fallback for externalReference, sent as the transparent checkout's externalId.
await payments.driver('pix').charge({
customerId: 'cus_123',
amount: 1990,
customer: { name: 'Jane Doe', taxId: '123.456.789-00' },
invoice: true,
})