ruudk/moneybird-bundle
Symfony bundle for integrating the Moneybird accounting platform into your app. Provides configuration and service wiring for the Moneybird API, making it easier to work with invoices, contacts, and financial data.
Read this first: the package is archived and effectively unusable for new work. Last release 2015-08-04, Symfony 2.x-era, and it targets the retired Moneybird v1 API (the current API is v2, which changed auth scopes, URL structure — every resource is now nested under /administrations/{id}/... — and payload shapes). The only realistic reason to read this bundle is to maintain an existing Symfony 2.8/3.x app that already talks to a legacy Moneybird account, or to crib the OAuth wiring pattern.
For a new integration, depend on an actively maintained PHP client (picqer/moneybird-php-client is the de-facto one) and write ~50 lines of Symfony service wiring yourself. You will spend less time than resurrecting this bundle.
If you genuinely must install it:
composer require ruudk/moneybird-bundle (expect resolver conflicts on anything above Symfony 3.x / PHP 7.x).app/AppKernel.php (new Ruudk\MoneybirdBundle\MoneybirdBundle()).app/console config:dump-reference moneybird. The parameters are OAuth client credentials plus a redirect route — check DependencyInjection/Configuration.php for the exact tree rather than trusting README examples, which predate several Symfony config-schema changes.Resources/config/services.xml first. The bundle is thin: it registers a Moneybird client service plus whatever OAuth plumbing it needs. That file tells you every service ID you can inject and every place you can override.The first real use case is almost always: pull the administrations list, then pull contacts or sales invoices for one administration and reconcile them locally.
Token bootstrap as a one-shot console command. The bundle doesn't give you a durable token store. The pattern that works: a moneybird:authorize command that prints the authorize URL, a controller action at the registered redirect route that receives ?code=, exchanges it via the client, and writes the token to a Doctrine entity or a file. Everything else in your app then reads that stored token. Do not try to re-run the flow per request.
Inject the client, not the bundle. Keep your domain code dependent on the bundle's client service only at the composition root. Wrap it in your own MoneybirdGateway interface with methods like administrations(), contacts($administrationId), salesInvoices($administrationId, $filters). When you eventually migrate to API v2, you rewrite one class instead of grepping the codebase.
Pull-based sync over scheduled commands. There were no useful webhooks in the v1 era. Run a moneybird:sync command from cron, keep a last_synced_at column, and use it as a filter. Make the command idempotent by upserting on Moneybird's numeric ID, not on name or email.
Map money to integer cents immediately. API payloads carry amounts as strings/decimals. Convert at the boundary into an integer-cents value object and never let a float touch an invoice total. Same for tax rates — store the rate and the base separately, never a pre-computed total, or your reconciliation will drift by a cent on rounding.
Isolate pagination in the gateway. Moneybird pages results; v1 used page/per_page query params. Put the loop inside your gateway so callers get a generator or a full collection, and add a hard page cap so a misbehaving API can't spin forever.
Test by faking the gateway, not the HTTP layer. Because the bundle's client is a concrete service, the cheapest test strategy is to bind your MoneybirdGateway interface to a fixture-backed fake in config/services_test.yml. Asserting against recorded HTTP fixtures of a dead API has poor value.
Decorator for logging. Register a decorator on the bundle's client service that logs method, URL, status, and body at debug level. This is the single highest-value addition for debugging, and it survives the eventual client swap.
services.yaml defaults, and PHP 7.2+ return-type strictness. Expect to patch services.xml for public/private service visibility and to add public: true on anything you fetch from the container in a legacy app. On PHP 8 it will likely fatal on deprecations-turned-errors or old each()-style code in transitive deps.parameters.yml. Old Symfony convention encourages committing credentials. Move client_id/client_secret to environment variables from day one; you'll be rotating them during the migration anyway.How can I help you explore Laravel packages today?