PHPackages                             scanlyser/php-sdk - PHPackages - PHPackages  [Skip to content](#main-content)[PHPackages](/)[Directory](/)[Categories](/categories)[Trending](/trending)[Leaderboard](/leaderboard)[Changelog](/changelog)[Analyze](/analyze)[Collections](/collections)[Log in](/login)[Sign up](/register)

1. [Directory](/)
2. /
3. [API Development](/categories/api)
4. /
5. scanlyser/php-sdk

ActiveLibrary[API Development](/categories/api)

scanlyser/php-sdk
=================

PHP SDK for the ScanLyser API — accessibility, SEO, performance, UX, and security scanning.

v1.0.0(4mo ago)00MITPHPPHP ^8.2

Since Apr 8Pushed 4w agoCompare

[ Source](https://github.com/scanlyser/php-sdk)[ Packagist](https://packagist.org/packages/scanlyser/php-sdk)[ Docs](https://scanlyser.app)[ RSS](/packages/scanlyser-php-sdk/feed)WikiDiscussions main Synced 3w ago

READMEChangelog (1)Dependencies (3)Versions (2)Used By (0)

ScanLyser PHP SDK
=================

[](#scanlyser-php-sdk)

Official PHP SDK for the [ScanLyser](https://scanlyser.app) API. Run accessibility, SEO, performance, UX, and security scans programmatically.

Requirements
------------

[](#requirements)

- PHP 8.2+
- Guzzle 7.0+

Installation
------------

[](#installation)

```
composer require scanlyser/php-sdk
```

Quick Start
-----------

[](#quick-start)

```
use ScanLyser\Client;
use ScanLyser\Enums\ScanCategory;

$client = new Client(apiKey: 'your-api-token');

// List your sites
$sites = $client->sites($teamId)->list();

foreach ($sites->data as $site) {
    echo "{$site->name}: {$site->url}\n";
}

// Trigger a scoped scan. Omit categories to assess all five public categories.
$scan = $client->scans($teamId)->trigger(
    $siteId,
    wcagLevel: 'AA',
    categories: [ScanCategory::Accessibility, ScanCategory::SEO],
);

// Wait for completion
$scan = $client->scans($teamId)->awaitCompletion($scan->id);

// Get issues
$issues = $client->issues($teamId)->list($scan->id, severity: 'critical');

// Inspect scanner diagnostics independently from findings
$diagnostics = $client->diagnostics($teamId)->list($scan->id);
```

API Reference
-------------

[](#api-reference)

### Client

[](#client)

```
$client = new Client(
    apiKey: 'your-api-token',
    maxRetries: 3, // optional, retries on 429
);
```

### Teams

[](#teams)

```
$teams = $client->teams()->list();
$team = $client->teams()->get($teamId);
```

### Sites

[](#sites)

```
$sites = $client->sites($teamId)->list(perPage: 15);
$site = $client->sites($teamId)->create(name: 'My Site', url: 'https://example.com');
$site = $client->sites($teamId)->get($siteId);
$client->sites($teamId)->delete($siteId);
```

### Scans

[](#scans)

```
use ScanLyser\Enums\ScanCategory;

$scans = $client->scans($teamId)->list($siteId);
$scan = $client->scans($teamId)->trigger(
    $siteId,
    wcagLevel: 'AA',
    webhookUrl: 'https://example.com/webhooks/scanlyser',
    categories: [ScanCategory::SEO, ScanCategory::Performance],
);
$scan = $client->scans($teamId)->get($scanId);

// Poll until complete (default: 600s timeout, 10s interval)
$scan = $client->scans($teamId)->awaitCompletion(
    $scanId,
    timeoutSeconds: 600,
    pollIntervalSeconds: 10,
);

if ($scan->hasUsableScore()) {
    echo "Score: {$scan->scores->overall}\n";
} else {
    echo "Outcome: {$scan->assessmentOutcome?->value}\n";
}

if ($scan->hasUsableCategoryScore(ScanCategory::SEO)) {
    echo "SEO: {$scan->scores->seo}\n";
} else {
    $seoOutcome = $scan->categoryCoverage?->for(ScanCategory::SEO)->outcome->value ?? 'unavailable';
    echo "SEO: {$seoOutcome}\n";
}
```

Polling stops for completed, failed, and cancelled scans. A completed lifecycle does not by itself guarantee a score: inspect `assessmentOutcome`, `coverage`, or use `hasUsableScore()` before presenting score data. When a scan fails, `failure` contains only the stable `code`, customer-safe `message`, and support `correlationId`.

The optional `categories` argument is last in the trigger signature, preserving existing positional calls. Omitting it requests all public categories. Category score members (`wcag`, `seo`, `performance`, `ux`, `sitewide`, and `other`) are nullable: `null` means that bucket was not scored, never zero. Use `requestedCategories`, `categoryCoverage`, `scoredCategoryScope`, and `hasUsableCategoryScore()` to distinguish assessed, partial, inconclusive, and not-scanned categories. `IssueCategory` remains the separate six-value finding/report vocabulary and must not be used to select a scan scope.

### Pages

[](#pages)

```
$pages = $client->pages($teamId)->list($scanId);
$page = $client->pages($teamId)->get($scanId, $pageId);
```

Detailed pages keep `issues` and `diagnostics` as separate collections. `failure` uses the same safe lifecycle-failure object as scans; it never exposes raw exception text or a query-bearing page URL.

### Issues

[](#issues)

```
$issues = $client->issues($teamId)->list($scanId);
$issues = $client->issues($teamId)->list($scanId, category: 'wcag', severity: 'critical');
```

Every issue response is a readonly `Finding` (which extends the backwards-compatible `Issue` class) and carries a required `FindingResultEnvelope` in `$issue->result`. Issue hydration rejects diagnostic envelopes instead of presenting them as findings. Its nested data objects retain versioned check identity, explicitly nullable qualification, safe reasoning and limitations, structured evidence, reproduction context, remediation parameters, and references.

```
use ScanLyser\Enums\ResultOutcome;

$result = $issues->data[0]->result;

if ($result->outcome === ResultOutcome::ManualReview) {
    echo $result->explanation->reasoning;
}
```

Hydration rejects unsupported schema versions and invalid kind/outcome combinations. A null qualification property means the scanner explicitly declined to claim it; do not infer a value from the issue source.

### Diagnostics

[](#diagnostics)

```
$diagnostics = $client->diagnostics($teamId)->list($scanId, perPage: 50, page: 2);

foreach ($diagnostics->data as $diagnostic) {
    echo "{$diagnostic->code}: {$diagnostic->detail->message} ({$diagnostic->correlationId})\n";
}
```

`Diagnostic` is a separate readonly resource with `kind === ResultKind::Diagnostic`, an inconclusive or error outcome, string `index`, check and scope identity, non-null scope link, safe detail, optional recovery action, and support correlation ID. The `page` argument selects the API page. Diagnostics never contribute to issue counts.

### Reports

[](#reports)

```
$report = $client->reports($teamId)->json($scanId);
$client->reports($teamId)->pdf($scanId, saveTo: '/path/to/report.pdf');
```

Webhook Verification
--------------------

[](#webhook-verification)

Verify webhook signatures from scan completion callbacks:

```
use ScanLyser\Webhooks\WebhookSignature;

$isValid = WebhookSignature::verify(
    payload: $request->getContent(),
    signature: $request->header('X-Signature'),
    secret: $tokenHash,
);
```

Error Handling
--------------

[](#error-handling)

The SDK throws typed exceptions for API errors:

```
use ScanLyser\Exceptions\AuthenticationException;
use ScanLyser\Exceptions\ForbiddenException;
use ScanLyser\Exceptions\NotFoundException;
use ScanLyser\Exceptions\RateLimitException;
use ScanLyser\Exceptions\ValidationException;

try {
    $site = $client->sites($teamId)->get('nonexistent');
} catch (NotFoundException $exception) {
    // 404
} catch (ValidationException $exception) {
    // 422 - $exception->errors contains field-level errors
} catch (RateLimitException $exception) {
    // 429 - automatic retries exhausted
}
```

Rate-limited requests (429) are automatically retried up to 3 times with the `Retry-After` delay.

Laravel Integration
-------------------

[](#laravel-integration)

The SDK includes an optional service provider with auto-discovery.

### Publish the config:

[](#publish-the-config)

```
php artisan vendor:publish --tag=scanlyser-config
```

### Configure `.env`:

[](#configure-env)

```
SCANLYSER_TOKEN=your-api-token
SCANLYSER_TEAM=your-team-id
```

### Usage:

[](#usage)

```
use ScanLyser\Client;

class ScanController extends Controller
{
    public function trigger(Client $client): void
    {
        $scan = $client->scans(config('scanlyser.team_id'))
            ->trigger($siteId, wcagLevel: 'AA');
    }
}
```

License
-------

[](#license)

MIT

###  Health Score

36

—

LowBetter than 79% of packages

Maintenance87

Actively maintained with recent releases

Popularity0

Limited adoption so far

Community6

Small or concentrated contributor base

Maturity46

Maturing project, gaining track record

 Bus Factor1

Top contributor holds 100% of commits — single point of failure

How is this calculated?**Maintenance (25%)** — Last commit recency, latest release date, and issue-to-star ratio. Uses a 2-year decay window.

**Popularity (30%)** — Total and monthly downloads, GitHub stars, and forks. Logarithmic scaling prevents top-heavy scores.

**Community (15%)** — Contributors, dependents, forks, watchers, and maintainers. Measures real ecosystem engagement.

**Maturity (30%)** — Project age, version count, PHP version support, and release stability.

###  Release Activity

Cadence

Unknown

Total

1

Last Release

125d ago

### Community

Maintainers

![](https://avatars.githubusercontent.com/u/2211203?v=4)[Sebastian Sulinski](/maintainers/sebastiansulinski)[@sebastiansulinski](https://github.com/sebastiansulinski)

---

Top Contributors

[![sebastiansulinski](https://avatars.githubusercontent.com/u/2211203?v=4)](https://github.com/sebastiansulinski "sebastiansulinski (9 commits)")

---

Tags

apisdkaccessibilityseowcagscanlyser

###  Code Quality

TestsPest

Code StyleLaravel Pint

### Embed Badge

![Health badge](/badges/scanlyser-php-sdk/health.svg)

```
[![Health](https://phpackages.com/badges/scanlyser-php-sdk/health.svg)](https://phpackages.com/packages/scanlyser-php-sdk)
```

###  Alternatives

[aws/aws-sdk-php

AWS SDK for PHP - Use Amazon Web Services in your PHP project

6.2k555.0M2.8k](/packages/aws-aws-sdk-php)[eslazarev/wildberries-sdk

Wildberries OpenAPI clients (generated).

353.6k](/packages/eslazarev-wildberries-sdk)[tencentcloud/tencentcloud-sdk-php

TencentCloudApi php sdk

3661.3M49](/packages/tencentcloud-tencentcloud-sdk-php)[resend/resend-php

Resend PHP library.

608.3M51](/packages/resend-resend-php)[checkout/checkout-sdk-php

Checkout.com SDK for PHP

563.6M16](/packages/checkout-checkout-sdk-php)[files.com/files-php-sdk

Files.com PHP SDK

2482.9k](/packages/filescom-files-php-sdk)

PHPackages © 2026

[Directory](/)[Categories](/categories)[Trending](/trending)[Changelog](/changelog)[Analyze](/analyze)
