PHPackages                             rerout/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. rerout/sdk

ActiveLibrary[API Development](/categories/api)

rerout/sdk
==========

Official PHP SDK for the Rerout branded-link API.

v0.3.0(1mo ago)001MITPHP ^8.2

Since May 22Compare

[ Source](https://github.com/ModestNerds-Co/rerout-php)[ Packagist](https://packagist.org/packages/rerout/sdk)[ Docs](https://rerout.co)[ RSS](/packages/rerout-sdk/feed)WikiDiscussions Synced 3w ago

READMEChangelogDependencies (10)Versions (3)Used By (1)

rerout/sdk
==========

[](#reroutsdk)

Official PHP SDK for the [Rerout](https://rerout.co) API.

Branded link infrastructure on Cloudflare — create short links, render QR codes, read analytics, and verify webhook signatures.

Install
-------

[](#install)

```
composer require rerout/sdk
```

Requires PHP 8.2+ and the `json` and `hash` extensions. HTTP transport is [Guzzle 7](https://docs.guzzlephp.org/).

Usage
-----

[](#usage)

```
use Rerout\Rerout;
use Rerout\Models\CreateLinkInput;

$rerout = new Rerout(getenv('REROUT_API_KEY'));

$link = $rerout->links()->create(new CreateLinkInput(
    targetUrl: 'https://example.com/q4-sale',
    domainHostname: 'go.brand.com',
    code: 'q4',
));

echo $link->shortUrl; // https://go.brand.com/q4

$stats = $rerout->project()->stats(7);
echo "Last 7 days: {$stats->totalClicks} clicks, {$stats->qrScans} QR scans";
```

API
---

[](#api)

### Construction

[](#construction)

```
$rerout = new Rerout('rrk_…', [
    'base_url' => 'https://api.rerout.co', // optional, default shown
    'timeout' => 30,                       // optional, seconds
    'client' => $guzzleClient,             // optional — inject your own ClientInterface
    'default_headers' => [                 // optional — added to every request
        'User-Agent' => 'my-app/1.0',
    ],
]);
```

A blank or missing API key throws a `ReroutException` with code `missing_api_key`. The `base_url` has trailing slashes trimmed.

### Links

[](#links)

```
use Rerout\Models\CreateLinkInput;
use Rerout\Models\UpdateLinkInput;

$rerout->links()->create(new CreateLinkInput(
    targetUrl: 'https://example.com',
    domainHostname: 'go.brand.com', // optional
    code: 'promo',                  // optional
    expiresAt: 1893456000,          // optional, unix seconds
    seoTitle: 'Big Sale',           // optional SEO overrides
));

$result = $rerout->links()->list(cursor: null, limit: 50);
foreach ($result->links as $link) {
    echo $link->shortUrl, PHP_EOL;
}
// $result->nextCursor — pass back as `cursor` for the next page

$link = $rerout->links()->get('promo');

// Read-only tags attached to the link. Empty array when none are bound.
foreach ($link->tags as $tag) {
    echo $tag->id, ' ', $tag->name, ' ', $tag->color, PHP_EOL;
}

$link = $rerout->links()->update('promo', new UpdateLinkInput(
    isActive: false,
));

$deleted = $rerout->links()->delete('promo'); // bool

$stats = $rerout->links()->stats('promo', days: 30);
```

`UpdateLinkInput` distinguishes three states per field:

- **Leave alone** — omit the argument (the default). The field is not sent.
- **Set a value** — pass a concrete value.
- **Clear server-side** — pass `UpdateLinkInput::CLEAR`, which serialises as explicit `null`.

```
new UpdateLinkInput(
    targetUrl: 'https://example.com/v2',     // set
    expiresAt: UpdateLinkInput::CLEAR,        // null it on the server
    // seoTitle omitted — left untouched
);
```

Constructing an empty `UpdateLinkInput` and calling `update()` throws a `ReroutException` (code `bad_request`) client-side — the request never leaves your process.

### Project

[](#project)

```
$stats = $rerout->project()->stats(days: 30);
echo $stats->totalClicks, ' ', $stats->qrScans;

$me = $rerout->project()->me(); // array{id: string, name: string, slug: string}
```

### QR codes

[](#qr-codes)

```
use Rerout\Models\QrOptions;

// Pure URL builder — no network call.
$url = $rerout->qr()->url('promo', new QrOptions(
    size: 12,
    margin: 2,
    ecc: 'H',
    domain: 'go.brand.com',
    refresh: true, // true → `refresh=1`; any string is forwarded verbatim
));

// Fetch the rendered SVG (sends the bearer token).
$svg = $rerout->qr()->svg('promo', new QrOptions(size: 8));
```

### Webhook endpoint management

[](#webhook-endpoint-management)

Manage the project's webhook endpoints with an API key. The project is resolved from the key — there is no project id in the path. The `signingSecret` is returned **once** on create; store it to verify deliveries.

```
use Rerout\Models\CreateWebhookInput;

// Create an endpoint.
$created = $rerout->webhooks()->create(new CreateWebhookInput(
    name: 'Order events',
    url: 'https://example.com/hooks/rerout',
    events: ['link.created', 'link.clicked'],
    isActive: true,        // optional, default true
    payloadFormat: 'json', // optional, 'json' | 'slack'
));
echo $created->endpoint->id;       // wh_…
echo $created->signingSecret;      // whsec_… — shown once, store it now

// List endpoints + every event type the server can deliver.
$result = $rerout->webhooks()->list();
foreach ($result->endpoints as $endpoint) {
    echo $endpoint->url, PHP_EOL;
}
$allEventTypes = $result->eventTypes; // list

// Delete an endpoint (idempotent).
$deleted = $rerout->webhooks()->delete('wh_abc123'); // bool
```

### Webhook signature verification

[](#webhook-signature-verification)

Rerout signs every webhook delivery with an `X-Rerout-Signature` header in the form `t=,v1=`. Verify it before trusting the payload:

```
use Rerout\Webhooks\SignatureVerifier;

$ok = SignatureVerifier::verify(
    rawBody: file_get_contents('php://input'),
    signatureHeader: $_SERVER['HTTP_X_REROUT_SIGNATURE'] ?? '',
    secret: getenv('REROUT_WEBHOOK_SECRET'),
);

if (!$ok) {
    http_response_code(401);
    exit;
}
```

The HMAC is SHA-256 over `"."` and is compared in constant time. The default timestamp tolerance is 300 seconds — pass `toleranceSeconds: 0` to disable the staleness check, or a custom value to widen it. A `$clock` callable can be injected for testing.

### Error handling

[](#error-handling)

Every API call throws `Rerout\Exceptions\ReroutException` on failure:

```
use Rerout\Exceptions\ReroutException;

try {
    $rerout->links()->create(new CreateLinkInput(targetUrl: 'http://insecure'));
} catch (ReroutException $e) {
    echo $e->code();        // 'bad_target_url'
    echo $e->status();      // 400
    echo $e->getMessage();  // 'target_url must use https.'
    echo $e->path ?? '';    // the API path that failed
    if ($e->isRateLimited()) { /* back off */ }
    if ($e->isServerError()) { /* retry later */ }
}
```

When the server returns a JSON error body, `code` and `message` are taken verbatim. When it does not, a synthetic code is used:

ConditionCodeHTTP 401`unauthorized`HTTP 403`forbidden`HTTP 404`not_found`HTTP 429`rate_limited`HTTP 5xx`server_error`other 4xx`client_error`connection failure`network_error`timeout`timeout`2xx non-JSON body`unexpected_response`Local development
-----------------

[](#local-development)

```
composer install
composer test      # PHPUnit
composer analyse   # PHPStan, level 9
composer format    # php-cs-fixer
```

License
-------

[](#license)

MIT — see [LICENSE](../LICENSE).

Links
-----

[](#links-1)

- [Rerout](https://rerout.co)
- [Workspace repository](https://github.com/ModestNerds-Co/rerout-sdks)

###  Health Score

34

—

LowBetter than 75% of packages

Maintenance90

Actively maintained with recent releases

Popularity0

Limited adoption so far

Community5

Small or concentrated contributor base

Maturity37

Early-stage or recently created project

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

Every ~13 days

Total

2

Last Release

50d ago

### Community

Maintainers

![](https://www.gravatar.com/avatar/595d37695ae82443fe49534433413413198dd386e28d3d3c95fe59048257f09f?d=identicon)[modestnerd](/maintainers/modestnerd)

---

Tags

sdkurl shortenerqr codesshort-linksreroutbranded-links

###  Code Quality

TestsPHPUnit

Static AnalysisPHPStan

Code StylePHP CS Fixer

Type Coverage Yes

### Embed Badge

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

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

###  Alternatives

[aws/aws-sdk-php

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

6.2k543.5M2.7k](/packages/aws-aws-sdk-php)[neuron-core/neuron-ai

The PHP Agentic Framework.

2.0k656.1k46](/packages/neuron-core-neuron-ai)[sylius/sylius

E-Commerce platform for PHP, based on Symfony framework.

8.5k5.9M754](/packages/sylius-sylius)[tempest/framework

The PHP framework that gets out of your way.

2.2k34.4k16](/packages/tempest-framework)[eslazarev/wildberries-sdk

Wildberries OpenAPI clients (generated).

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

TencentCloudApi php sdk

3661.3M47](/packages/tencentcloud-tencentcloud-sdk-php)

PHPackages © 2026

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