gonetto/finance-consult-api-client
A PHP client for the Gonetto Finance Consult API, wrapping remote endpoints in a clean, Laravel-friendly interface so you can query consulting data and handle responses without hand-rolling HTTP calls.
This is a Symfony bundle, not a Laravel package. There is no ServiceProvider, no config/*.php publish tag, and no facade. A Laravel developer's first job is to figure out whether the bundle is just a thin DI wrapper around a usable client (good) or whether the client logic is entangled with Symfony's container (painful).
Minimal path:
Install it and immediately inspect what it pulled in:
composer require gonetto/finance-consult-api-client
Open vendor/gonetto/finance-consult-api-client/composer.json first. You care about:
require — does it hard-depend on symfony/http-kernel, symfony/dependency-injection, symfony/config, symfony/http-client, symfony/serializer? Those are the friction points against a Laravel app.autoload — where the actual API client class lives (usually src/), separate from the bundle glue (DependencyInjection/, Resources/config/, *Bundle.php).Find the real client class. In src/, look for something like *Client.php or *ApiClient.php, plus a DependencyInjection/Configuration.php (this tells you every config key the bundle expects: base URL, API key, timeout, etc.) and Resources/config/services.yaml (this tells you how the client is constructed — constructor args, injected HTTP client, serializer).
First use case — bypass the bundle entirely. Write a throwaway Artisan command (php artisan make:command ProbeFinanceConsult) that news up the client manually with credentials from .env, calls one read-only endpoint, and dump()s the raw response:
// app/Console/Commands/ProbeFinanceConsult.php
$client = new \Gonetto\FCApiClient\Client(
baseUrl: config('services.finance_consult.base_url'),
apiKey: config('services.finance_consult.api_key'),
);
$response = $client->someReadMethod(/* ... */);
dump($response);
Getting one raw response out is the fastest way to learn the DTO shapes, auth header format, and error envelope before you commit to any integration architecture.
Treat the package as a library and hide it behind an interface you control. This is the only sane approach for a 0-star dependency.
namespace App\Services\FinanceConsult;
interface FinanceConsultClient
{
public function getConsultation(string $id): ConsultationData;
public function listContracts(array $filters = []): array;
}
namespace App\Services\FinanceConsult;
use Gonetto\FCApiClient\Client as GonettoClient;
final class GonettoFinanceConsultClient implements FinanceConsultClient
{
public function __construct(private GonettoClient $client) {}
public function getConsultation(string $id): ConsultationData
{
$raw = $this->client->getConsultation($id); // Symfony DTO or array
return ConsultationData::fromArray((array) $raw);
}
}
Read Resources/config/services.yaml and translate constructor arguments into a Laravel singleton. Map Symfony parameters (%gonetto_fc.api_key%) to config() calls.
namespace App\Providers;
use Illuminate\Support\ServiceProvider;
use Gonetto\FCApiClient\Client;
class FinanceConsultServiceProvider extends ServiceProvider
{
public function register(): void
{
$this->mergeConfigFrom(config_path('finance-consult.php'), 'finance-consult');
$this->app->singleton(Client::class, fn ($app) => new Client(
baseUrl: $app['config']->get('finance-consult.base_url'),
apiKey: $app['config']->get('finance-consult.api_key'),
httpClient: $app->make(\GuzzleHttp\Client::class), // if the client accepts an HTTP client
));
$this->app->bind(FinanceConsultClient::class, GonettoFinanceConsultClient::class);
}
}
Configuration.php tree into config/finance-consult.php. Keep the keys 1:1 with the Symfony tree so that if the package is ever fixed for Laravel you can reconcile easily.src/. If it exists, wire it as a singleton and refresh inside a queued job, not per-request. Store tokens in cache, not in the DB.$tries, backoff(), and a failed() handler. Financial APIs are usually slow and rate-limited.Http::fake() won't intercept it. Either swap the injected Guzzle client in a test binding, or mock your FinanceConsultClient interface at the boundary. The interface approach makes tests trivial.// tests
$this->mock(FinanceConsultClient::class)
->shouldReceive('getConsultation')
->once()
->andReturn(new ConsultationData(id: 'abc', /* ... */));
Bundle::boot() relies on the kernel and container internals that Laravel doesn't have. Just skip the bundle and use the classes underneath."gonetto/finance-consult-api-client": "1.0.*" or even a commit hash. Zero dependents means zero incentive to maintain BC.composer.json requires symfony/http-kernel, composer will install the whole Symfony HTTP stack alongside Laravel. That's usually fine (they coexist), but if the package requires an incompatible Symfony major version you'll hit a dependency resolution wall. Run composer why-not laravel/framework if install refuses.%env()% placeholders won't resolve. Symfony's config tree resolves %env(GONETTO_API_KEY)% at container compile time. In Laravel, config('finance-consult.api_key') will return the literal "%env(...)%" string. Always map env vars manually in the config file.services.yaml, you must reimplement them as Laravel bindings / listeners / cache repositories. Grep services.yaml for tags: before assuming it's trivial.symfony/serializer for DTO hydration, you're now carrying that component. It works standalone, but be aware that its normalizer configuration differs from Laravel's conventions — don't try to share your JsonResource layer with it.Symfony\Contracts\HttpClient\HttpClientInterface, you'll need to install symfony/http-client and cannot just hand it a Guzzle client. If it type-hints Guzzle, you can share Laravel's Guzzle instance — check before designing.FinanceConsultException hierarchy so your app's Handler config stays coherent.src/ end-to-end. If the package is critical, consider vendoring the client class into app/Services/FinanceConsult/Vendor/ so a future removal of the repo doesn't break you.services.yaml; (2) confirm the auth header actually reached the wire with Http::fake-style middleware or a Guzzle on_stats callback; (3) inspect the raw JSON body, not the hydrated DTO — DTO hydration is where silent failures hide; (4) check for API version prefixes in the base URL.Configuration.php keys. There's no middleware pipeline out of the box — if you need retries, rate limiting, or circuit breaking, wrap the client and implement them yourself rather than hoping the package does.FinanceConsultClient, replacing this package with a hand-rolled Http:: client is a one-file change. Given the package's health signals, plan for that day.How can I help you explore Laravel packages today?