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

Laravel Firefly Laravel Package

andreaselia/laravel-firefly

A Laravel wrapper for the Firefly III API. Connect your app to a Firefly III instance to manage accounts, transactions, budgets, categories, and reports through a simple, fluent PHP interface. Configure your API token and start building finance integrations quickly.

View on GitHub
Deep Wiki
Context7

Getting Started

This package is a thin, config-driven wrapper around the Firefly III REST API. You still need a running Firefly III instance and a personal access token; the package only handles the base URL, auth header, and Laravel wiring.

Minimal setup

composer require andreaselia/laravel-firefly
php artisan vendor:publish --provider="AndreasElia\Firefly\FireflyServiceProvider"

Set the connection values in .env (names may vary slightly—check the published config/firefly.php):

FIREFLY_URL=https://firefly.example.com
FIREFLY_TOKEN=your-personal-access-token

Generate the token in Firefly III under Options → Profile → OAuth → Personal Access Tokens. The token grants full API access, so treat it like a password.

Where to look first

  1. config/firefly.php — confirms the exact env keys and whether the base URL includes /api/v1.
  2. src/FireflyServiceProvider.php and the facade class — confirms the container binding and facade alias.
  3. The resource classes under src/ — these map to Firefly endpoints (accounts, transactions, budgets, etc.) and define the available methods.

First use case

Pull accounts into a dashboard or select list:

use AndreasElia\Firefly\Facades\Firefly;

$accounts = Firefly::accounts()->all();

foreach ($accounts['data'] as $account) {
    // $account['id'], $account['attributes']['name'], ...
}

Push a transaction from a form or webhook:

Firefly::transactions()->create([
    'type' => 'withdrawal',
    'date' => now()->toIso8601String(),
    'amount' => '12.50',
    'description' => 'Coffee',
    'source_id' => $assetAccountId,
    'destination_id' => $expenseAccountId,
]);

The payloads mirror the Firefly III API, so the official API docs are the real reference once the wrapper is configured.

Implementation Patterns

Wrap the facade in a domain service. Avoid calling Firefly:: directly from controllers. A small service makes the integration testable and gives you one place to normalize Firefly’s JSON:API responses.

class FireflyAccountService
{
    public function all(): Collection
    {
        return collect(Firefly::accounts()->all()['data'])
            ->map(fn (array $account) => [
                'id' => $account['id'],
                'name' => $account['attributes']['name'],
                'type' => $account['attributes']['type'],
            ]);
    }
}

Separate read and write workflows. Most apps do one of two things:

Read/sync pattern: a scheduled command pulls accounts, transactions, or budgets and upserts them locally. Paginate explicitly and store the Firefly ID as a unique key.

$page = 1;
do {
    $response = Firefly::transactions()->all(['page' => $page]);
    foreach ($response['data'] as $transaction) {
        LocalTransaction::updateOrCreate(
            ['firefly_id' => $transaction['id']],
            ['payload' => $transaction],
        );
    }
    $page++;
} while ($page <= ($response['meta']['pagination']['total_pages'] ?? 1));

Write-through pattern: after a local event (order paid, invoice created, expense submitted), dispatch a queued job that creates the Firefly transaction. Store the returned Firefly ID on your model so retries are idempotent.

dispatch(new CreateFireflyTransaction($order));

Queue and throttle writes. Firefly III is usually self-hosted and not built for high write volume. Use queued jobs with ->onQueue('firefly') and a rate limiter or Bus::batch() for backfills.

Keep an account map. Firefly transactions reference source_id and destination_id, not account names. Cache a name => id map locally rather than hitting /accounts on every write.

Handle Firefly webhooks if you need near-real-time data. Firefly can POST transaction events to your app. Put a route behind signature verification, then refresh the affected local record. This is often cheaper than polling.

Test with Http::fake(). The wrapper ultimately uses Laravel’s HTTP client or Guzzle, so faking the Firefly endpoints keeps tests fast and deterministic:

Http::fake([
    'firefly.example.com/api/v1/accounts*' => Http::response([
        'data' => [/* ... */],
    ]),
]);

$this->artisan('firefly:sync-accounts')->assertSuccessful();

Gotchas and Tips

  • The package is lightly maintained. The last release was February 2023, and the repo has a small audience. Pin the version in composer.json and smoke-test against your Firefly III version. Newer Firefly fields or endpoints may require raw HTTP calls or a fork.
  • The wrapper is thin, not typed. Responses are arrays, not DTOs. Validate keys defensively ($account['attributes']['name'] ?? null) and centralize parsing in a service.
  • Amounts are strings. Firefly uses decimal strings to avoid floating-point errors. Keep them as strings through your stack; cast only at the display boundary.
  • Date formats matter. Firefly expects ISO-8601 or Y-m-d depending on the endpoint. Use now()->toIso8601String() for timestamps and now()->toDateString() for date-only fields.
  • Transactions are split-based. A Firefly transaction payload contains a transactions array of splits, each with its own amount, source, and destination. If the wrapper exposes create() for a single split, confirm the shape it sends before relying on it for transfers or multi-split transactions.
  • Base URL quirks. Set FIREFLY_URL to the instance root (https://firefly.example.com). If the wrapper appends /api/v1, adding it yourself produces /api/v1/api/v1. Check the published config and test with php artisan tinker.
  • Token scope is all-or-nothing. Firefly personal access tokens don’t have fine-grained scopes. Keep the token server-side, never expose it to the frontend, and rotate it if leaked.
  • Self-signed certificates. If your Firefly instance uses a private CA, Guzzle will reject it. Look for a config option for HTTP client options; if none exists, bind a configured client or fork the package to pass verify => false (development only) or a CA bundle path.
  • Config caching. After changing FIREFLY_URL or FIREFLY_TOKEN, run php artisan config:clear locally or php artisan config:cache in deployment. Stale config is a common “why is it hitting the old host?” cause.
  • Pagination is opt-in. all() likely returns one page, not everything. Always inspect meta.pagination and loop or pass per_page explicitly.
  • Errors are HTTP exceptions. Firefly returns 422 with a JSON message and errors object for validation failures. Catch RequestException, log the response body, and surface a useful message rather than a generic 500.
  • Extension point: the container binding. If you need multiple Firefly instances (multi-tenant), the singleton config is a limitation. Create a small factory that instantiates the underlying client per tenant, or bind a scoped instance in a service provider.
  • Upgrade path. Because releases are infrequent, keep an integration test that hits a fake Firefly response and one manual smoke test against a real instance. That gives you confidence when Firefly III itself upgrades.
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.
middlewares/firewall
qubiqx/montapacking
nyoncode/laravel-package-console
pnscripts/filament-broadquill-lite
pnscripts/laravel-sentfold-lite
vleap/mx-sdk-laravel-internal
twidpay/utils
htetmyathlaing/scout-elasticsearch-driver
artisan-toolbox/front-awesome
ls/client-assistant
users-au/laravel-client
robertmarney/lara-hierarchial-collections
simonschaufi/rule-doc-generator
emissaoja/emissaoja
blackbricksoftware/gravityforms-civicrm-form-processor
al-rahabi/fancy-crud
jinas/dhivatar-component
mltstephane/laravel-quality
bernskiold/laravel-talentlms
bernskioldmedia/laravel-form-architect