Weave Code
Weaver
Helps Laravel developers discover, compare, and choose open-source packages. See popularity, security, maintainers, and scores at a glance to make better decisions.
Feedback
Share your thoughts, report bugs, or suggest improvements.
Subject
Message

Iugu Bundle Laravel Package

hugomn/iugu-bundle

Symfony bundle for integrating the Brazilian Iugu payment gateway into PHP applications. It provides configuration and services for Iugu API operations including charges, invoices, subscriptions, credit card and boleto payments, and webhook handling, simplifying payment processing in Symfony project...

View on GitHub
Deep Wiki
Context7

Getting Started

This is a Symfony 2/3-era bundle that wires the iugu/iugu-php SDK into the container. Nothing more. Treat it as a thin configuration shim, not a full abstraction.

  1. Install — composer require hugomn/iugu-bundle. This pulls in the legacy iugu/iugu-php SDK, which is not PSR-4 namespaced (classes are Iugu_Charge, Iugu_Customer, Iugu_Invoice, …). Expect a classmap autoload entry alongside your normal PSR-4 config.

  2. Register the bundle in app/AppKernel.php:

    new hugomn\IuguBundle\IuguBundle(),
    

    There is no Flex recipe and no config/bundles.php support — this bundle predates Symfony 4.

  3. Configure your API key. The bundle's job is essentially to call Iugu::setApiKey() for you boot-time. Keep the key out of config.yml:

    # app/config/parameters.yml
    parameters:
        iugu_api_key: '%env(IUGU_API_KEY)%'   # or hardcode in parameters.yml, gitignored
    
    # app/config/config.yml
    hugomn_iugu:
        api_key: '%iugu_api_key%'
    
  4. Where to look first — vendor/hugomn/iugu-bundle/ for DependencyInjection/Configuration.php (that file tells you the exact config keys and whether an environment/sandbox switch exists) and the service definition in Resources/config/services.yml. Confirm what service ID is registered (hugomn_iugu.client or similar) and whether it's public — in Symfony 3.4+ private services may need an explicit alias to be usable via $container->get().

  5. First use case — a one-off charge, which is the 90% path. You do not send card data to your server:

    // 1. Browser: iugu.js tokenizes the card -> you POST the token id to your controller
    $charge = Iugu_Charge::create([
        'token' => $request->get('token'),
        'email' => $order->getEmail(),
        'items' => [[
            'description' => 'Pedido #'.$order->getId(),
            'quantity'    => 1,
            'price_cents' => $order->getTotalCents(),
        ]],
    ]);
    

    If $charge->status === 'paid', mark the order paid. Anything else, keep it pending and let the webhook settle it.

Implementation Patterns

Wrap the SDK — don't call statics from controllers. The SDK's static surface (Iugu_Charge::create, Iugu::setApiKey) is untestable and leaks global state. Put a PaymentGateway service around it, define it once in your own services.yml, and inject the bundle's configured client (or just re-call setApiKey() from parameters) inside that adapter. Then mock your interface in tests, not Iugu's.

Customer-first, then invoice. For anything recurring, create the Iugu_Customer once and store the id on your local user row. Subsequent charges reference customer_id plus a token, which keeps billing history coherent in the Iugu dashboard and lets support staff reconcile by customer.

Subscriptions. Create the Iugu_Plan once (via dashboard, honestly — plans rarely change and the dashboard is less error-prone than code), then Iugu_Subscription::create(['plan_identifier' => ..., 'customer_id' => ...]). Mirror the subscription id locally with its status and expires_at, refreshed by webhook — do not compute entitlement from your own clock alone.

Webhooks are the source of truth. Add a route like /webhooks/iugu, exclude it from CSRF and from your auth firewall (security.firewalls.main.anonymous: ~ with a pattern exclusion), respond 200 in under a second, and push the actual work to a queue or a deferred command. Iugu retries on non-2xx, so the handler must be idempotent — key on the invoice/subscription ID, not on the payload hash.

Don't trust the webhook body. Re-fetch the resource through the API (Iugu_Invoice::fetch($id)) before flipping order state. That both validates authenticity and protects you against replay/forgery, since the legacy SDK offers no signature verification helper.

Marketplace/split payments. If you're a split-payment scenario, the flow is Iugu_Marketplace + per-seller account config, and the split array on charges/invoices. This is where the bundle adds nothing — you're essentially using the raw SDK with a configured key, so budget time to read Iugu's own docs rather than the bundle's.

Use one adapter per payment method. Card, boleto and PIX (if the pinned SDK version even supports PIX — see gotchas) have different required fields. A ->chargeCard(), ->chargeBoleto() pair on your gateway class keeps the branching out of controllers.

Gotchas and Tips

Vintage, and it shows. Last release 2016-09-27, zero stars, zero dependents. There is no Symfony 4/5/6+ support: no autowiring alias, no AbstractBundle, no attribute-based config. On Symfony 4+ you'll be copying the service definition into your own services.yaml and manually calling Iugu::setApiKey() from a compiler pass or a boot listener. At that point the bundle is earning nothing — consider depending on iugu/iugu-php directly, or better, writing a small Guzzle client against the REST API so you control retries, timeouts and error shapes.

Static API key = single-tenant only. Iugu::setApiKey() sets process-global state. Multi-account, multi-currency or "charge on behalf of a sub-merchant with a different key" scenarios will fight you, especially under long-running workers (RoadRunner/Swoole) or anything that runs two tenants in one PHP process. If you need that, skip the bundle.

Classmap autoload collisions. The legacy Iugu_* class prefixes sit in the global namespace. If you also pull in another Iugu integration (or a newer SDK), you get fatal redeclares with no obvious cause. composer why iugu/iugu-php is your first debugging command.

Money is in cents, always. price_cents, total_cents. Brazilian gateway, BRL only. The most common bug in this integration is a R$ 149,90 order being charged R$ 1,49 or R$ 14.990,00. Assert in one place and test it.

Document validation. CPF/CNPJ is required for boleto and for most customer records. Validate locally before the API call — Iugu's error responses for malformed documents are terse and easy to misroute to the user as a generic "payment failed".

Card data must never touch your server. Tokenize with iugu.js in the browser, POST only the token. This isn't optional advice — it's the PCI scope boundary, and it's also why the bundle has no card form helpers.

Testing/static state bleed. In PHPUnit, setUp() must reset the API key and any SDK-level config, otherwise a test that sets a sandbox key poisons the rest of the suite. Better: run integrations against a sandbox key with a @group integration annotation and keep the unit suite entirely behind your own gateway interface.

Errors are opaque. The SDK throws its own exception types with the raw HTTP body stuffed in. Wrap every call in a try/catch that logs the request payload (minus card data) and the response body, then rethrow a domain exception. Without that, "Iugu returned 400" is all you'll see in production logs.

Idempotency is yours to build. If a request times out, you don't know whether the charge happened. Keep a local payment_attempts row keyed by your own UUID before calling, and reconcile by querying Iugu for the created resource before retrying. Retrying blindly double-charges customers.

Version pinning. Pin iugu/iugu-php to an exact version in composer.json. The SDK's API surface changed across versions and the bundle does nothing to guard you. Also check whether your pinned version predates Iugu's PIX support and any deprecated endpoints — a 2016-era SDK calling a 2024 API is a slow-motion outage.

Weaver

How can I help you explore Laravel packages today?

Conversation history is not saved when not logged in.
Prompt
Add packages to context
No packages found.
shitoudev/permissionmanager
johannesclimacus/laravel-tui
hocvt/seotools
vitalybaev/sypexgeo
amphibee/themosis-ignition
gito-me/fast-excel
frankyso/laravel-ipaymu
geolize-studio/laravel-chile
boomerangui/chat
jinas/dhivatar
store-doc/laravel-storage-driver
plus-it/laravel-translation-manager
diephp/perhaps
diephp/telegraph
osmaviation/spreadsheet
microsoft/fluentui-system-icons
mmccook/php-json-canonicalization-scheme
middlewares/firewall
qubiqx/montapacking
nyoncode/laravel-package-console