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

Samsara Laravel Package

erikgall/samsara

Laravel package for integrating Samsara's fleet telematics API into your application, providing a clean, expressive interface for managing vehicles, drivers, and real-time tracking data.

View on GitHub
Deep Wiki
Context7

Getting Started

Requirements: PHP 8.2+ and Laravel 12.x (12.0+) or 13.x. Laravel 10, 11, and PHP 8.1 are no longer supported as of v1.1.0 — Composer will refuse to install on those stacks.

Install and configure:

composer require erikgall/samsara
php artisan vendor:publish --tag="samsara-config"

Add your API token to .env (the config file's key name is authoritative — check config/samsara.php after publishing):

SAMSARA_API_TOKEN=your-token-here

Where to look first:

  1. config/samsara.php — token, base URL, timeouts, retry settings.
  2. The Samsara facade class — its accessor methods tell you which resources exist (vehicles(), drivers(), trips(), tags(), etc.).
  3. src/Entity.php — this is the value object every response is hydrated into. Understanding it is the key to everything downstream.

First use case — read a resource and iterate it:

use ErikGall\Samsara\Facades\Samsara;

foreach (Samsara::vehicles()->all() as $vehicle) {
    dump($vehicle->id, $vehicle->name);
}

Confirm the exact accessor and method names against the facade before building on them; most resources follow a consistent all() / get($id) shape.

Implementation Patterns

Wrap the SDK in your own service layer. Don't let Samsara:: calls leak into controllers or Blade. Create a thin adapter (App\Services\Samsara\FleetService) that calls the SDK and returns your own DTOs or Eloquent models. Samsara's API surface is large and changes; the adapter is where you absorb that.

Map Entity to something you own. Entities are fluent-style read objects, not Eloquent models. Map them at the boundary:

$vehicle = Samsara::vehicles()->get($id);

VehicleRecord::updateOrCreate(
    ['samsara_id' => $vehicle->id],
    ['name' => $vehicle->name, 'updated_at' => now()]
);

Sync via queued jobs, not request cycles. Anything beyond a single lookup belongs in a job. Samsara list endpoints are paginated and can be slow:

class SyncVehicles implements ShouldQueue
{
    use InteractsWithQueue, Queueable;

    public int $tries = 5;

    public function backoff(): array
    {
        return [10, 30, 60, 120];
    }

    public function handle(FleetService $fleet): void
    {
        foreach ($fleet->allVehiclesLazy() as $vehicle) {
            // upsert
        }
    }
}

Use a generator/lazy-style loop rather than collecting every page into memory; fleets get large.

Respect rate limits with job middleware. Samsara enforces per-endpoint limits and returns 429 with retry hints. Use Laravel's RateLimited middleware and treat 429/5xx as retryable, 4xx as permanent:

public function middleware(): array
{
    return [(new RateLimited('samsara'))->releaseAfter(30)];
}

Define the samsara limiter in a service provider with a conservative perMinute value derived from your account tier.

Inject rather than facade-call inside tests. If the manager resolves from the container, prefer constructor-injecting it (or your own adapter) so you can swap in fakes. Otherwise stub at the HTTP layer:

Http::fake([
    'api.samsara.com/*' => Http::response(['data' => [/* ... */]], 200),
]);

Faking HTTP is the most reliable approach because it also exercises pagination and hydration.

Cache slow-moving reference data. Vehicles, tags, and driver rosters change infrequently. A 5–15 minute Cache::remember around list calls cuts API traffic substantially and keeps you clear of rate limits.

Handle Samsara webhooks in a dedicated endpoint. Verify the signature/secret from the Samsara dashboard, respond 200 immediately, and dispatch a job to fetch the canonical record from the API rather than trusting the payload shape.

Gotchas and Tips

v1.1.0 is a breaking release for older stacks. Dropping Laravel 10/11 and PHP 8.1 means composer update will fail on those projects — it isn't a soft deprecation. If you share the package across multiple apps, bump each one's laravel/framework and php constraints first, then update. Check your CI matrix too, not just local.

Entity::make() is now local, not Fluent::make(). This is the subtle one. The SDK previously constructed entities via Illuminate\Support\Fluent::make(), which only landed in Laravel 12.9 — so on 12.0–12.8 entities were effectively broken. The new local factory fixes that. The consequence: Entity may no longer be a Fluent instance, or may inherit from it without relying on its static factory. If you wrote Entity::make([...]) in your own code or extended Entity, re-test. If you used Fluent-specific methods on entity objects (->get(), ->set(), ->first(), ->forget()), verify each still exists — prefer plain property access and toArray() / all() for portability.

Laravel 12.0–12.8 is now genuinely supported. If you pinned laravel/framework: ^12.9 solely to work around the Fluent::make() bug, you can relax that constraint. The new --prefer-lowest CI cell exists to keep those lower bounds honest.

Entities are read-oriented. Treat values as immutable once hydrated. Don't persist entity objects into cache or the session — serialize toArray() instead; class shape changes between minor versions are not a breaking-change concern for the maintainer.

Timestamps arrive as strings. Samsara returns RFC3339 UTC. Wrap with Carbon::parse() at your boundary and store as UTC; don't rely on the entity to cast for you.

config:cache will bite you. After changing the token or base URL, run php artisan config:cache (or config:clear in dev). Also note that if you're swapping tokens per-tenant at runtime with config()->set(), an already-cached config still resolves correctly for config() reads — but anything reading env() directly inside the SDK will not.

Debugging outbound calls. The SDK hides the underlying HTTP client, so Http::dd() isn't directly available. Use Laravel's global HTTP middleware to log everything transparently (Laravel 11+):

Http::globalRequestMiddleware(fn ($request) =>
    logger()->debug('samsara', ['url' => (string) $request->url()]));

Alternatively, drop a Log::debug inside your adapter around each call — often simpler and scoped to just Samsara traffic.

Pagination limits are per-endpoint. Samsara caps limit differently across resources. Don't hardcode a single page size; read it from config or pass it through your adapter and let the API reject bad values early.

Extension points. If the manager is container-bound, you can bind()/extend() a custom client or adapter — useful for adding correlation IDs, metrics, or a mock transport in tests. Check whether the facade is macroable before reaching for Samsara::macro(); if it isn't, the service-container binding is the supported seam.

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.
jinas/dhivatar
store-doc/laravel-storage-driver
plus-it/laravel-translation-manager
diephp/perhaps
diephp/telegraph
osmaviation/spreadsheet
microsoft/fluentui-system-icons
mmccook/php-json-canonicalization-scheme
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
cgv/localized-resource