Skip to content
Finowl

Framework · Laravel

Use Finowl in Laravel with the Http facade

Laravel gives each Finowl product a natural home. Breached password checks become a validation rule you add to a FormRequest next to min and confirmed, email breach checks run in a queued listener on the Registered event, and gender enrichment fits a queued job that processes customers in chunks. The Http facade handles JSON, bearer tokens and timeouts, and Http::fake makes the whole integration simple to test without network access.

Instead of a separate SDK class, the setup below registers an Http::finowl() macro in AppServiceProvider. It reads the key through config('services.finowl.key'), which config/services.php maps to the FINOWL_API_KEY environment variable, so config caching keeps working. A FinowlException::fromResponse helper turns failed responses into the status, error code and Retry-After seconds that rules, listeners and jobs use to decide whether to release, fail or carry on.

STEP 1

A reusable Laravel client

Keep your key in the FINOWL_API_KEY environment variable and route every call through one helper, so authentication, timeouts and error handling live in one place.

Install
php artisan make:rule NotBreachedPassword
php artisan make:listener CheckEmailBreaches --event="Illuminate\Auth\Events\Registered"
php artisan make:job EnrichCustomerGender
Laravel client
<?php
// config/services.php
// 'finowl' => ['key' => env('FINOWL_API_KEY')],

// app/Providers/AppServiceProvider.php
namespace App\Providers;

use Illuminate\Http\Client\PendingRequest;
use Illuminate\Support\Facades\Http;
use Illuminate\Support\ServiceProvider;

class AppServiceProvider extends ServiceProvider
{
    public function boot(): void
    {
        Http::macro('finowl', fn (): PendingRequest => Http::baseUrl('https://api.finowl.co')
            ->withToken(config('services.finowl.key'))
            ->acceptJson()
            ->asJson()
            ->connectTimeout(5)
            ->timeout(15));
    }
}

// app/Exceptions/FinowlException.php
namespace App\Exceptions;

use Illuminate\Http\Client\Response;
use RuntimeException;

class FinowlException extends RuntimeException
{
    public function __construct(
        public readonly int $status,
        public readonly string $errorCode,
        public readonly ?int $retryAfter = null,
    ) {
        parent::__construct("Finowl API error {$status}: {$errorCode}", $status);
    }

    public static function fromResponse(Response $response): self
    {
        $retryAfter = $response->header('Retry-After');

        return new self(
            $response->status(),
            $response->json('error.code') ?? 'unknown_error',
            $retryAfter !== '' ? (int) $retryAfter : null,
        );
    }
}

STEP 2

Call the API you need

  • Check email breaches in Laravel with a queued listener

    Laravel fires Illuminate\Auth\Events\Registered when a user signs up, both in the starter kits and in controllers that call event(new Registered($user)). The CheckEmailBreaches listener implements ShouldQueue, so the Finowl lookup runs on a queue worker instead of slowing the registration request. It filters breaches to those whose DataClasses include Passwords and notifies the user with each breach Title and BreachDate.

  • Validate breached passwords with a Laravel rule

    NotBreachedPassword implements Laravel's ValidationRule interface, so you use it like any other rule object in a FormRequest or Validator::make call. The validate method sends the value to /v1/breaches/password through the Http::finowl() macro with a five second timeout, and calls $fail when the response says breached is true. The message uses the :attribute placeholder, so it reads naturally whatever the field is called.

  • Queue gender enrichment jobs in Laravel

    EnrichCustomerGender is a queued job that takes up to 50 customer ids, loads the models, and sends them to /v1/gender/batch as name items with an optional country_code hint. array_filter removes the country key when a customer has none, keeping each item valid. Results come back in order with each item's id, so the job updates the matching Customer through the keyed collection without another query.

A FEW GOOD QUESTIONS

Laravel questions

Other languages and frameworks

Ship with Laravel today

100 free credits every month. Try every request in the sandbox first.