garu 0.7.0
garu: ^0.7.0 copied to clipboard
Dart/Flutter SDK for the Garu payment gateway — PIX, credit card, boleto, recurring charges, webhooks.
0.7.0 #
Added #
-
garu.installmentPlans— boleto parcelado (carnê). One product sold as N monthly bank slips. This is seller-financed consumer credit, not a card instalment: nobody guarantees a boleto, so a buyer who stops at parcela 4 leaves the seller with four parcelas and no advance from anyone. Only the first slip exists at creation; the rest are emitted month by month and the sale activates when parcela 1 compensates.create,list,get,reissueInstallment,postponeInstallment,markInstallmentPaid,cancel,requestRefund.createalways sendsX-Idempotency-Key. It matters more here than anywhere else in the API: the call registers a real boleto, so a blind retry hands one buyer two payable barcodes.CreateInstallmentPlanParams.affiliateIdis fixed at sale time — every later parcela inherits it, so omitting it pays that affiliate nothing for the whole carnê.Installment.isPayableis false until a slip is actually registered, so a future parcela is never rendered to a buyer as an empty barcode.InstallmentPlan.remainingScheduledclamps at zero: multa and mora can pushtotalCollectedabovetotalScheduled, and naive subtraction would report a negative debt.
-
garu.refundRequests— refunds Garu cannot make for you. A boleto cannot be reversed and Celcoin exposes no Pix devolução, so the funds already settled to the seller and the return is a bank transfer only they can make.list,get,confirm,reject. Confirming records that the seller asserts the money went back; Garu never observes the transfer. -
V1List<T>for the/api/v1list envelope, which is flat (data/count/totalCount/totalPages) rather than nesting undermeta.
0.6.0 #
Makes the products resource read-write. Tracks @garuhq/node@0.15.0. Additive — existing read-only callers (list / get / portalConfig) are unchanged.
Added:
products.create(CreateProductParams)—POST /api/products(gateway returns 201), parses back a typedProduct.nameis required;value(centavos),description,image,tags,pix,boleto,creditCard,pixAutomatic,installments,isSubscription,subscriptionType,unitLabel,returnUrl,returnUrlButtonText,statementDescriptorare optional. Null fields are omitted from the wire body. Auto-attachesX-Idempotency-Key(UUIDv4) unlessCreateProductParams.idempotencyKeyis supplied — sent as a header, never in the body — so the runner's transient-failure retries can't double-create a product (matchesscheduledCharges.create).products.update(Object id, UpdateProductParams)—PATCH /api/products/{id}.idaccepts the numeric id (int) or the product UUID (String) — mirroring@garuhq/node'sstring | numbersignature — interpolated throughUri.encodeComponentfor the same path-injection hardening the rest of the SDK uses. AllUpdateProductParamsfields are optional and only the ones you set are sent, so updates stay partial.CreateProductParams/UpdateProductParamsexported frompackage:garu/garu.dart. Field names are camelCase on the wire, verified against@garuhq/node@0.15.0'sCreateProductParams/UpdateProductParams.
Validated:
dart analyzeclean.- 56 unit tests passing (8 new) in a new
products_test.dart— covers thecreatePOST + 201 parse, the auto-generated and caller-suppliedX-Idempotency-Key(key omitted from the body), null-field omission,updatePATCH with numeric and UUID ids, partial-body merge semantics, and id URL-encoding against aMockClient.
0.5.0 #
Surfaces Pix Automático — Brazil's BACEN auto-debit recurring Pix — across the SDK. Tracks Garu backend v0.13.0 + v0.14.0. Every change is additive: existing Card/Pix/Boleto callers need no changes.
Pix Automático lets a customer authorize a recurring debit once (a consent link / QR in their bank app); subsequent cycles debit silently with no card on file.
Added:
PaymentMethodenum (pix/boleto/card/pixAutomatic, plus a forward-compatibleunknownsentinel). Each value exposes its APIwireValue(PaymentMethod.pixAutomatic.wireValue == 'pix_automatic') and afromWireparser that resolves unrecognized future values tounknowninstead of throwing. Exported frompackage:garu/garu.dart.Charge.method— a typed, forward-compatiblePaymentMethodview over the rawCharge.paymentMethodstring. Branch on this ontransaction.*webhooks to tell a Pix Automático debit apart from a card charge (no new event names — Pix Automático fires the samesubscription.*/transaction.payment.*events as card).Product.pixAutomatic(non-nullablebool, defaultsfalse) — whether the public checkout exposes Pix Automático for the product. Read fromProduct.fromJson.scheduledCharges.createnow accepts'pix_automatic'inmethods. A debug-modeassertincreate()enforces the gateway's constraint —'pix_automatic'requirestype: 'recurring'and aproductId— and is compiled out of release/AOT builds; the gateway is authoritative and rejects violations with400/404/409.
Docs:
- README gains a "Pix Automático" recipe (create a recurring auto-debit series, branch webhooks on
Charge.method, failure/cancellation model) and refreshed version/status to0.5.0.
Build:
- Dependency constraints use caret ranges (
http ^1.2.2,crypto ^3.0.5,uuid ^4.5.1,test ^1.25.8,lints ^4.0.0) — the pub.dev convention for libraries, so downstream consumers can resolve alongside other packages. Exact resolved versions are captured inpubspec.lock.
Validated:
dart analyzeclean.- 49 unit tests passing (11 new) — covers
PaymentMethod.fromWire(known values,pix_automaticwire value,unknownfallback),Charge.methodresolution,Product.pixAutomaticparse + default, the recurringpix_automaticcreate round-trip, and thetype/productIdassertions increate().
0.4.0 #
Adds immediate dispatch for scheduled charges and per-series recovery windows. Both changes are additive — no breaking changes.
Added:
scheduledCharges.chargeNow(String id)— dispatch a cycle's charge + customer notification immediately instead of waiting for the due date (the same path the daily billing cron runs). Idempotent: an already-dispatched cycle reportsalreadySentand is never re-charged, so the call is safe to retry. Returns a typedChargeNowResult{outcome,cycleNumber,reason,message}.ChargeNowOutcomeenum —dispatched/alreadySent/notSent/failed, plus a forward-compatibleunknownsentinel.notSent/failedcarry areason(no_email,lock_lost,no_saved_payment_method;card_expired,payment_method_missing,customer_missing, or a raw gateway code).CreateScheduledChargeParams.maxRecoveryDays(int?, 1–365) — how long the gateway keeps recovering a missed cycle before giving up. Omit for the system default (14). The 1–365 range is checked by a debug-modeassert(compiled out of release/AOT builds); the gateway is the authoritative boundary and rejects out-of-range values with a 400.ScheduledChargeRecord.maxRecoveryDays(int?) on the returned object, withfromJson/toJsonsupport.
Security:
- Every
scheduledChargesper-id endpoint now interpolates the id throughUri.encodeComponent(id), extending the v0.3.0 path-injection hardening (previously applied only toproducts.portalConfig) to the whole resource. An id containing/,?, or#can no longer spawn extra path segments or leak a query/fragment into the constructed URL.
Validated:
dart analyzeclean.- 38 unit tests passing (16 new) across
models_test.dartand a newscheduled_charges_test.dart— coverschargeNowHTTP wiring (POST,/charge-nowpath, empty body) against aMockClient, id URL-encoding, all four outcomes + theunknownfallback, themaxRecoveryDaysrange assertion, andScheduledChargeRecordround-tripping.
0.3.0 #
Tracks Garu backend v0.10.0. Per-product portal-config endpoints now accept the product UUID in addition to the legacy numeric id.
Breaking:
products.portalConfig.{get,set,patch,clear}signature changed fromint productIdtoString productId. Pass the product UUID (preferred — same identifier returned byproducts.list()and webhook payloads) or convert legacy integer ids with'$id'.ProductPortalConfig.productIdfield type changed frominttoStringfor symmetry with the request signature — round-tripping a returnedproductIdno longer requires manual conversion.
Security:
- URL path interpolation now goes through
Uri.encodeComponent(productId)to prevent query/fragment-segment injection (?,#,/in productId would otherwise corrupt the constructed URL).
Why: integer ids are sequential and enumerable. UUIDs are the public-facing identifier across the rest of the API; this brings portal-config in line.
0.2.0 #
Full feature parity with @garuhq/node@0.8.0. Public API still pre-1.0 — breaking changes possible until v1.0.0, but the surface is now complete enough for production integrations.
Added:
customersresource (CRUD +setBillingEmailOverride)productsresource (list,get) +products.portalConfig.{get,set,patch,clear}(B2B2C primitive)scheduledChargesresource — full lifecycle:create,list,get,markPaid,postpone,pause,resume,cancelRecurrence,cancelAtPeriodEnd,changePaymentMethod,clearPaymentMethod,listAttempts(per-attempt billing audit, SPEC §4.2)metaresource (discover supported payment methods + webhook events)- Strongly-typed models:
Charge,Customer,Product,ProductPortalConfig,SetProductPortalConfigParams,ScheduledChargeRecord,ScheduledChargeAttempt,PaginatedList<T>,PaginationMeta GaruFailureCodeenum — 10 canonical values +isPermanenthelper for routing recurring billing failuresScheduledChargeAttemptSourceandScheduledChargeAttemptStatusenums with forward-compatiblefromWireparsers (unrecognized values resolve to.unknowninstead of throwing)
Validated:
dart analyzeclean (Dart 3.11.5)- 22 unit tests passing across
webhooks_test.dart,models_test.dart,errors_test.dart— covers signature verification (5 cases including tamper detection + replay window), error mapping by HTTP status, and JSON parsing for the v0.8.0 surfaces
Still TODO before v1.0.0:
- Strongly-typed event-timeline models for
scheduledCharges.getdetail bundle - Card tokenization helpers (today: pass raw card to
charges.create) - Multi-status filter for
scheduledCharges.list(currently passes first only) - Example Flutter app
0.1.0 (alpha) #
Initial scaffold with Garu client, error hierarchy, charges resource, and webhook signature verification. NOT at parity with @garuhq/node.