A strongly typed, framework-independent PHP 8.3+ client for the official Surfsight API.
Jane generates endpoint and model code from the committed OpenAPI specification. A small maintained API provides regional configuration, authentication, stable resource groups, pagination, media downloads, PSR dependency discovery, and package exceptions.
- Official Surfsight API 2.0.0 models and all 129 specification paths
- PSR-18, PSR-17, and PSR-7 compatibility
- Automatic HTTP implementation discovery or explicit dependency injection
- Credential authentication, 24-hour token reuse, and one controlled re-authentication after HTTP 401
- Explicit Europe or North America selection
- Lazy offset pagination for device events
- Streaming media downloads without forwarding Surfsight credentials to media hosts
- No Symfony FrameworkBundle dependency
composer require virtuallast/surfsight-php-client symfony/http-client nyholm/psr7use VirtualLast\Surfsight\Configuration;
use VirtualLast\Surfsight\Region;
use VirtualLast\Surfsight\SurfsightClient;
$client = SurfsightClient::create(
new Configuration(
region: Region::Europe,
email: $_ENV['SURFSIGHT_EMAIL'],
password: $_ENV['SURFSIGHT_PASSWORD'],
),
);
$device = $client->devices()->getDeviceByImei($imei);
echo $device->getData()->getName();Region::Europe uses https://api.de.surfsight.net/v2; Region::NorthAmerica uses https://api-prod.surfsight.net/v2. A region is always required.
The client calls the documented POST /authenticate operation on first use, reuses the returned token for its documented 24-hour user-token lifetime, and adds Authorization: Bearer … to API calls. An HTTP 401 invalidates the token and permits exactly one re-authentication and retry.
Authentication failures throw AuthenticationException. Passwords and tokens are redacted from debug output and are never included in package exception messages.
$client = SurfsightClient::create(
$configuration,
$psr18Client,
$psr17RequestFactory,
$psr17StreamFactory,
);When omitted, php-http/discovery locates the implementations.
$page = $client->events()->getEvents($imei, [
'start' => '2026-07-01T00:00:00Z',
'end' => '2026-07-02T00:00:00Z',
'limit' => '100',
]);
foreach ($client->events()->iterateEvents($imei, [
'start' => '2026-07-01T00:00:00Z',
'end' => '2026-07-02T00:00:00Z',
'limit' => '100',
]) as $event) {
// $event is VirtualLast\Surfsight\Generated\Model\Event
}The iterator follows the API's limit/offset metadata lazily and rejects repeated offsets.
$link = $client->media()->getEventFileLink($imei, [
'fileId' => $fileId,
'fileType' => 'video',
]);
$stream = $client->media()->download($link);Media links are temporary. Downloads require a valid HTTPS URL and return a PSR-7 stream. The Surfsight bearer token is never attached to the returned external URL.
$ranges = $client->recordings()->getRecordingRanges($imei, [
'start' => '2026-07-01T00:00:00Z',
'end' => '2026-07-01T01:00:00Z',
]);Maintained high-level APIs currently cover authentication, device retrieval/update, device events/details, event file links/downloads, and recording ranges.
Every other generated operation remains deliberately available through $client->generated(), including alarms, audit logs, calibration, device operations, drivers, geofences, groups, health, OAuth, organizations, partners, streaming, telemetry, users, virtual events, webhooks, and organization albums. This low-level surface follows upstream naming and is less stable.
ConfigurationExceptionreports invalid local configuration.AuthenticationExceptionreports safe authentication failures.ApiExceptioncarries the operation, HTTP status, headers, safe decoded details, and previous generated exception.TransportExceptionwraps PSR transport failures.
No general-purpose retry policy is applied. Configure retries in the injected transport if desired.
The original official specification is committed at openapi/surfsight.yaml (JSON syntax, which is valid YAML). Generated files live only in generated/ and must never be edited.
composer update-spec
composer generate
composer test
composer analyse
composer run validateThe update command downloads the official portal's page-data representation, validates its identity, and atomically replaces the file. Generation applies one documented temporary preprocessing fix; the committed upstream file is unchanged.
Only the priority resource groups have polished wrappers in this initial release. Other API groups use generated() until maintained wrappers are added. No live integration tests run by default, and no claim is made here that requests have been verified with real Surfsight credentials.
MIT