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

ActiveLibrary

hyvor/sdk
=========

Official PHP SDK for HYVOR products

0.0.2(1mo ago)09↑2566.7%MITPHPPHP &gt;=8.4

Since Jul 18Pushed 1mo agoCompare

[ Source](https://github.com/hyvor/sdk-php)[ Packagist](https://packagist.org/packages/hyvor/sdk)[ RSS](/packages/hyvor-sdk/feed)WikiDiscussions main Synced 1mo ago

READMEChangelog (4)Dependencies (12)Versions (3)Used By (0)

hyvor/sdk-php
=============

[](#hyvorsdk-php)

Official PHP SDK for HYVOR Products.

Install
-------

[](#install)

```
composer require hyvor/sdk
```

Requires PHP &gt;= 8.4. The SDK talks HTTP through [PSR-18](https://www.php-fig.org/psr/psr-18/) / [PSR-17](https://www.php-fig.org/psr/psr-17/) and does not ship its own HTTP client. If your project already has one installed (Guzzle, Symfony HttpClient, Nyholm, etc.), it's discovered automatically via [php-http/discovery](https://github.com/php-http/discovery) - no extra wiring needed.

Usage
-----

[](#usage)

```
use Hyvor\Sdk\HyvorClient;
use Hyvor\Sdk\Talk\Dto\Website\CreateWebsiteRequest;
use Hyvor\Sdk\Talk\Dto\Comment\ListCommentsRequest;

// org-level access, via a cloud API key
$client = new HyvorClient(
    cloudApiKey: 'your-cloud-api-key', // or tokenProvider: new SomeTokenProviderInterface()
);

// GET /api/console/v1/{id}/website — resource-level access to a specific website.
// The cloud API key/token provider must have access to this website.
$website = $client->talk->website($websiteId)->get();

// POST /api/console/v1/websites — org-level endpoint, not scoped to one website
$website = $client->talk->websites->create(
    new CreateWebsiteRequest(name: 'My Blog', domain: 'blog.example.com')
);

// every Console API resource hangs off the website client, e.g.:
$comments = $client->talk->website($websiteId)->comments->list(new ListCommentsRequest(limit: 10));
$pages = $client->talk->website($websiteId)->pages->list();
$moderators = $client->talk->website($websiteId)->moderators->list();
```

`$client->talk->website($websiteId)` exposes: `comments`, `reactions`, `ratings`, `pages`, `users`, `analytics`, `moderators`, `emailDomain`, `rules`, `emailLogs`, `ips`, `domains`, `badges`, `sso`, `jobs`, `webhooks`, `integrations` (`->slack`), and `media` — matching the [Console API](https://talk.hyvor.com/docs/api-console) one-to-one, plus `get()`/`update()` for the website itself.

### Hyvor Post

[](#hyvor-post)

```
$client = new HyvorClient(cloudApiKey: 'your-cloud-api-key');

// resource-level access to a specific newsletter (the cloud API key/token
// provider must have access to it)
$newsletter = $client->post->newsletter($newsletterId)->get();
$newsletter = $client->post->newsletter($newsletterId)->update(['name' => 'My Newsletter']);

$issues = $client->post->newsletter($newsletterId)->issues->list(['limit' => 10]);
$subscribers = $client->post->newsletter($newsletterId)->subscribers->list();
```

`$client->post->newsletter($newsletterId)` exposes: `issues`, `lists`, `subscribers`, `subscriberMetadataDefinitions`, `sendingProfiles`, `templates`, `users`, `invites`, `media`, and `exports` — matching the [Console API](https://post.hyvor.com/docs/api-console) one-to-one, plus `get()`/`update()` for the newsletter itself.

Unlike Talk, Post has no org-level endpoints (there's no API to create a newsletter), so `PostClient` only exposes `newsletter()`. Also unlike Talk, Post's Console API doesn't embed the newsletter's ID in the URL — every request instead carries an `X-Newsletter-Id` header, which is how an org-level cloud API key (otherwise valid for every newsletter the org can access) resolves to one specific newsletter.

### Resource-level API keys

[](#resource-level-api-keys)

Resource-level API keys are generated in the Console of each product and are scoped to a single resource (e.g. one website). They can be used without any client-level auth:

```
$client = new HyvorClient();

$website = $client->talk->website($websiteId, 'your-product-api-key')->get();

// org-level endpoints (like $client->talk->websites->create()) are not supported
// this way, since resource-level API keys are scoped to a single resource.
```

### Configuration

[](#configuration)

```
$client = new HyvorClient(
    cloudApiKey: '...',                          // or tokenProvider: ...
    cloudInstance: 'https://hyvor.com',          // default
    logger: $psrLogger,                          // PSR-3 logger, default NullLogger
    httpClient: $psr18Client,                    // Psr\Http\Client\ClientInterface, default: auto-discovered
    requestFactory: $psr17Factory,               // Psr\Http\Message\RequestFactoryInterface, default: auto-discovered
    streamFactory: $psr17Factory,                // Psr\Http\Message\StreamFactoryInterface, default: auto-discovered
    retryMaxAttempts: 3,
    retryBackoffFactor: 2.0,
);
```

### Authentication

[](#authentication)

`HyvorClient` accepts at most one of (both are optional — see resource-level API keys above):

- `cloudApiKey` — a Cloud API key created at `https://hyvor.com/account/org/api-keys`. The SDK exchanges it for a short-lived JWT internally (and refreshes it as needed).
- `tokenProvider` — a `Hyvor\Sdk\Auth\TokenProviderInterface` implementation for full control over how the bearer token is obtained. `Hyvor\Sdk\Auth\StaticTokenProvider` is included for the common case of using a single, pre-issued token (e.g. a JWT generated by an internal integration):

```
use Hyvor\Sdk\Auth\StaticTokenProvider;

$client = new HyvorClient(
    tokenProvider: new StaticTokenProvider('your-jwt'),
);
```

### Request options

[](#request-options)

Per-request overrides (retries, extra headers):

```
use Hyvor\Sdk\RequestOptions;

$client->talk->websites->create(
    new CreateWebsiteRequest(name: 'My Blog', domain: 'blog.example.com'),
    new RequestOptions(retryMaxAttempts: 1),
);
```

### Acting as a specific moderator

[](#acting-as-a-specific-moderator)

By default, the Console API is authenticated as the website owner. To act as a different moderator (see the Console API's "User Authentication" docs), set `X-AUTH-USER-EMAIL` or `X-AUTH-USER-SSO-ID` — either as a default for every call made through a `WebsiteClient` and its sub-resources:

```
$website = $client->talk->website($websiteId, headers: ['X-AUTH-USER-EMAIL' => 'mod@example.com']);
$website->comments->reply($commentId, new ReplyToCommentRequest(body: 'Thanks!'));
```

or per call, via `RequestOptions::$headers` (overrides the client-level default for that call):

```
$website->comments->reply(
    $commentId,
    new ReplyToCommentRequest(body: 'Thanks!'),
    new RequestOptions(headers: ['X-AUTH-USER-EMAIL' => 'mod@example.com']),
);
```

### Errors

[](#errors)

All API errors extend `Hyvor\Sdk\Exceptions\HyvorApiException`:

- `ValidationFailedException` (422) — has `$errors` (field =&gt; messages)
- `RateLimitException` (429) — has `$retryAfterSeconds`
- `AuthenticationException` (401/403)
- `NotFoundException` (404)
- `ServerErrorException` (5xx)
- `NetworkException` — request could not be sent (connection/timeout, from the underlying PSR-18 client)
- `ApiException` — fallback for other error statuses

Requests to `RateLimitException` and `ServerErrorException`-triggering statuses are retried automatically with exponential backoff before the exception is thrown.

Development
-----------

[](#development)

See [DEV.md](../DEV.md) at the repo root for running tests (with or without Docker).

Notes
-----

[](#notes)

- Talk requests are sent directly to the product's own instance, derived from `cloudInstance` by prefixing its host with the product name — e.g. `cloudInstance: 'https://hyvor.com'` (the default) resolves to `https://talk.hyvor.com`. Both org-level endpoints (like `$client->talk->websites->create()`) and resource-level ones (everything under `$client->talk->website($id)`) go through this same per-product instance.
- A `cloudApiKey` is exchanged for a short-lived JWT via `POST {cloudInstance}/api/cloud/token`, then sent as `Authorization: Bearer ` on Talk requests. A resource-level API key (passed to `$client->talk->website($id, $apiKey)`) is sent the same way, as a bearer token, without any token exchange — even though the public Console API docs only document `X-API-KEY` auth for resource-level keys.

DTO fields mirror the publicly documented [Talk Console API](https://talk.hyvor.com/docs/api-console) one-to-one, except: request DTOs treat a `null` property as "omit this field" (so partial updates and list filters don't need every property set) rather than sending a literal JSON `null` — the one documented exception is `VoteOnCommentRequest::$type`, where `null` is itself a meaningful instruction (remove the vote), so it's always sent verbatim.

- Post's Console API paths (unlike Talk's) don't embed any resource ID — `GET /issues`, not `GET /{newsletterId}/issues`. `$client->post->newsletter($id)` instead sends `X-Newsletter-Id: $id`as a default header on every request made through it and its sub-resources, which is what lets an org-level cloud API key (otherwise valid for every newsletter the org can access) resolve to one specific newsletter. DTO fields otherwise mirror the publicly documented [Post Console API](https://post.hyvor.com/docs/api-console) one-to-one, with the same null-means-omit convention as Talk.

###  Health Score

38

—

LowBetter than 82% of packages

Maintenance91

Actively maintained with recent releases

Popularity7

Limited adoption so far

Community6

Small or concentrated contributor base

Maturity42

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

Every ~0 days

Total

2

Last Release

46d ago

### Community

Maintainers

![](https://avatars.githubusercontent.com/u/53796347?v=4)[HYVOR](/maintainers/HYVOR)[@hyvor](https://github.com/hyvor)

---

Top Contributors

[![supun-io](https://avatars.githubusercontent.com/u/44988673?v=4)](https://github.com/supun-io "supun-io (1 commits)")

###  Code Quality

TestsPHPUnit

### Embed Badge

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

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

###  Alternatives

[typo3/cms

TYPO3 CMS is a free open source Content Management Framework initially created by Kasper Skaarhoj and licensed under GNU/GPL.

1.2k1.9M122](/packages/typo3-cms)[shopware/core

Shopware platform is the core for all Shopware ecommerce products.

605.9M718](/packages/shopware-core)[shopware/platform

The Shopware e-commerce core

3.4k1.5M3](/packages/shopware-platform)[flow-php/flow

PHP ETL - Extract Transform Load - Data processing framework

86538.6k](/packages/flow-php-flow)[sylius/sylius

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

8.5k6.1M799](/packages/sylius-sylius)[tempest/framework

The PHP framework that gets out of your way.

2.3k42.4k21](/packages/tempest-framework)

PHPackages © 2026

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