spatie/laravel-float-sdk
Laravel-friendly SDK for interacting with the Float.com API (v3). Configure your API token and user agent via .env/config and use the provided FloatClient to access Float endpoints. Not a full API implementation; contributions welcome.
composer require spatie/laravel-float-sdk
.env:
FLOAT_API_TOKEN=your_float_api_token_here
FLOAT_USER_AGENT="YourAppName (your-email@example.com)"
php artisan vendor:publish --tag="float-sdk-config"
Inject the FloatClient into a controller or service and retrieve a user by ID:
use Spatie\FloatSdk\FloatClient;
class UserController extends Controller
{
public function __construct(protected FloatClient $float) {}
public function show($id)
{
$user = $this->float->users()->get($id);
return response()->json($user);
}
}
users(), projects(), allocations(), etc.) in the README.GetUsersParams, GetProjectsParams, etc., for filtering, pagination, and field selection.FloatClient is auto-bound, so dependency injection works out of the box.public function __construct(protected FloatClient $float) {}
$this->float->projects()->all(new GetProjectsParams(clientId: 10));
get(1)) return a Value Object (VO).all()) return a Collection of VOs.$allocations = $this->float->allocations()->all(
new GetAllocationsParams(
status: 'pending',
startDate: now()->subDays(7)->format('Y-m-d'),
endDate: now()->format('Y-m-d')
)
);
$this->float->allocations()->update($id, ['status' => 'approved']);
$project = $this->float->projects()->get(10, new GetProjectsParams(
expand: ['client']
));
$allocations = $this->float->allocations()->all(
new GetAllocationsParams(projectId: $project->id)
);
$totalSpent = $allocations->sum(fn ($a) => $a->amount);
$timeOffs = $this->float->timeOff()->all(
now()->startOfYear()->format('Y-m-d'),
now()->endOfYear()->format('Y-m-d')
);
foreach ($timeOffs as $to) {
// Map to your HR model
YourHrModel::updateOrCreate(
['employee_id' => $to->userId],
['time_off_type' => $to->type, 'dates' => $to->dates]
);
}
$client = $this->float->clients()->get(5, new GetClientsParams(
expand: ['projects']
));
$projects = $client->projects;
$projectStats = $projects->map(fn ($p) => [
'name' => $p->name,
'budget' => $p->budget,
'spent' => $this->calculateSpentForProject($p->id),
]);
float.allocation.created).SyncFloatData::dispatch($floatClient)->onQueue('float-sync');
$users = Cache::remember('float.users.all', now()->addHours(1), fn () =>
$this->float->users()->all()
);
try {
$data = $this->float->projects()->get($id);
} catch (FloatApiException $e) {
Log::error("Float API error: {$e->getMessage()}");
return response()->json(['error' => 'Service unavailable'], 503);
}
Single Object Response Handling:
get() method may return a single object or an array depending on the API response. As seen in PR #28, this can cause parsing errors.get() responses as Value Objects (VOs) and avoid assuming array structure:
$allocation = $this->float->allocations()->get(1);
// Use $allocation->property instead of $allocation['property']
Pagination Limits:
perPage is 50. For large datasets, implement manual pagination:
$page = 1;
do {
$users = $this->float->users()->all(
new GetUsersParams(page: $page, perPage: 100)
);
// Process $users
$page++;
} while ($users->count() > 0);
Field Selection:
fields parameter. Refer to the Float API docs for supported fields.expand to include related data (e.g., expand: ['client'] for projects).Rate Limiting:
use Spatie\FloatSdk\Exceptions\FloatApiException;
try {
$data = $this->float->users()->all();
} catch (FloatApiException $e) {
if ($e->getCode() === 429) {
sleep(2); // Retry after 2 seconds
retry();
}
}
Time Zone Handling:
$allocations = $this->float->allocations()->all(
new GetAllocationsParams(
startDate: now('America/New_York')->startOfMonth()->format('Y-m-d'),
endDate: now('America/New_York')->endOfMonth()->format('Y-m-d')
)
);
debug config option to true to log API requests:
'debug' => env('FLOAT_DEBUG', false),
$response = $this->float->users()->get(1)->getResponse();
Log::debug($response->body());
FLOAT_API_TOKEN is correct. Test with a simple call:
$this->float->users()->all()->isEmpty(); // Should return false if token is valid
Custom Query Parameters:
Params classes or create new ones for unsupported filters:
namespace App\Float;
use Spatie\FloatSdk\QueryParameters\QueryParams;
class GetUsersByRoleParams extends QueryParams
{
public function __construct(
public ?string $role = null,
public ?int $page = 1,
public ?int $perPage = 50
) {}
}
FloatClient service provider.Add Missing Endpoints:
FloatClient:
namespace App\Extensions\Float;
use Spatie\FloatSdk\FloatClient as BaseFloatClient;
class ExtendedFloatClient extends BaseFloatClient
{
public function customEndpoint()
{
return $this->saloon->send(new CustomEndpointRequest());
}
}
config/app.php:
'bindings
How can I help you explore Laravel packages today?