PHPackages                             byte8/module-client - 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. [HTTP &amp; Networking](/categories/http)
4. /
5. byte8/module-client

ActiveMagento2-module[HTTP &amp; Networking](/categories/http)

byte8/module-client
===================

Byte8 thin HTTPS client shared by Byte8 SaaS connectors (Sage Accounting, Xero, future providers). Owns the JWT-signed publish/fetch surface and the local event outbox.

1.0.1(1mo ago)002proprietaryPHPPHP ~8.1.0||~8.2.0||~8.3.0||~8.4.0

Since Apr 29Pushed 1mo agoCompare

[ Source](https://github.com/byte8io/magento-client)[ Packagist](https://packagist.org/packages/byte8/module-client)[ RSS](/packages/byte8-module-client/feed)WikiDiscussions main Synced 1w ago

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

Byte8 Client
============

[](#byte8-client)

Shared chassis for every Byte8 SaaS connector module on Magento 2. **Not directly merchant-facing** — installed transitively as a dependency of the per-provider modules (`byte8/module-sage-accounting`, future `byte8/module-xero`, …).

If you're a merchant, install one of the connector metapackages (e.g. `byte8/magento-sage-accounting`) — this module gets pulled in automatically.

If you're a Byte8 platform engineer building a new connector, this is the module you build on top of.

Role in the stack
-----------------

[](#role-in-the-stack)

```
┌────────────────────────────────┐    ┌──────────────────────────┐
│  Magento 2                     │    │  ledger.byte8.io (SaaS)  │
│                                │    │                          │
│  ┌──────────────────────────┐  │    │  ┌────────────────────┐  │
│  │ byte8/module-sage-       │  │    │  │ Tenant + binding   │  │
│  │ accounting (or -xero …)  │  │    │  │ OAuth tokens       │  │
│  │                          │  │    │  │ Sage / Xero API    │  │
│  │   - observers            │  │    │  │ Retry + audit      │  │
│  │   - admin UI surfaces    │  │    │  │ Per-tenant rate    │  │
│  │   - per-provider config  │  │    │  │   limits           │  │
│  └────────────┬─────────────┘  │    │  └─────────┬──────────┘  │
│               │                │    │            │             │
│               ▼                │    │            ▼             │
│  ┌──────────────────────────┐  │    │  ┌────────────────────┐  │
│  │  byte8/module-client     │◄─┼────┼──┤  HTTP + JWT        │  │
│  │  (THIS MODULE)           │  │    │  │  Inbound + outbound│  │
│  │                          │  │    │  │                    │  │
│  │   - ByteClient publish   │  │    │  └────────────────────┘  │
│  │   - byte8_event_outbox   │  │    │                          │
│  │   - JWT verify + mint    │  │    │                          │
│  │   - canonical REST       │  │    │                          │
│  │   - sync-state mirror    │  │    │                          │
│  └──────────────────────────┘  │    │                          │
└────────────────────────────────┘    └──────────────────────────┘

```

This module owns the **wire**: outbox, JWT auth (both directions), canonical entity REST endpoints, and the Magento-side mirror of ledger sync state. Per-provider modules own the **events** that publish into this wire and the **admin UI surfaces** that the merchant sees.

By design, no PHP-side OAuth — that lives in the Byte8 Ledger SaaS, which talks to the actual provider APIs (`api.accounting.sage.com`, `api.xero.com`, …). Magento never touches a provider API directly.

What this module provides
-------------------------

[](#what-this-module-provides)

### `ByteClient` — outbound publish API

[](#byteclient--outbound-publish-api)

`Byte8\Client\Api\ByteClientInterface`. The single entry point per-provider observers use:

- **`enqueueEvent($eventName, $payload, $idempotencyKey?, $providerForMirror?)`** — outbox-only (no HTTP in the save transaction). The `OutboxDrain` cron picks it up within 60s. **Use this from observers.**
- **`publishEvent($eventName, $payload, $idempotencyKey?)`** — sync POST with outbox fallback on transient failure. Returns the ledger `sync_run_id` on success. Use only when the caller needs the id back immediately.
- **`fetchHealth()`** — cached tile health for the admin dashboard (30s TTL, swallows transient errors so a ledger outage doesn't break the dashboard).
- **`fetchStatus($entityType, $entityId)`** — per-entity sync-status lookup.
- **`disconnect()`** — best-effort tenant disconnect on revoke.

### Outbox

[](#outbox)

`byte8_event_outbox` table with three terminal states: `pending` / `succeeded` / `dead_lettered`. The classifier:

- **5xx / network / timeout** → `pending` with exponential backoff (10 attempts, ~7 days).
- **4xx (deterministic failure)** → `dead_lettered` on first attempt. No infinite-retry void.
- **Success** → `succeeded`. GC'd after 30 days by `OutboxGc` cron.

Operator triage:

```
bin/magento byte8:sage:outbox:inspect            # list dead-lettered rows
bin/magento byte8:sage:outbox:requeue        # flip back to pending
bin/magento byte8:sage:outbox:cleanup --days=30  # purge succeeded
```

Dead-letter count surfaces as a banner on the admin config page (via the `ConnectionStatus` block in per-provider modules).

### Inbound REST surface

[](#inbound-rest-surface)

Under the `Byte8_Client::byte8_webapi` ACL, JWT-authed via `JwtUserContext`:

MethodPathPurpose`GET``/V1/byte8/ping`Liveness probe (ledger's proactive health loop)`GET``/V1/byte8/payment-methods`Installed payment methods (for ledger's `payment_method_map` UI)`GET``/V1/byte8/invoice/:id`Canonical invoice (snake\_case shape per `ledger-core/src/canonical/invoice.rs`)`GET``/V1/byte8/customer/:id`Canonical customer / contact`GET``/V1/byte8/creditmemo/:id`Canonical credit memo (handles offline-payment refunds with no parent invoice)`GET``/V1/byte8/payment/:id`Canonical payment`GET``/V1/byte8/product/:id`Canonical product (with stock data)`POST``/V1/byte8/sync-state`Inbound from ledger worker — UPSERT `byte8_entity_sync_state`### JWT auth

[](#jwt-auth)

- **HKDF-SHA256 subkeys** derived from the shared `api_key` per direction (`PURPOSE_INBOUND` / `PURPOSE_OUTBOUND`).
- **HS256 JWT** sign + verify with `iss` / `aud` / `iat` / `nbf` / `exp` validation, 5-min TTL ceiling.
- **JTI replay cache** (5-min Magento cache scope) to defend against captured-token replay.
- `JwtUserContext` runs ahead of Magento's `TokenUserContext` and grants the synthetic integration user when the bearer JWT verifies. `SyntheticAclPlugin` short-circuits ACL checks against `Byte8_Client::byte8_webapi`.

### Sync-state mirror (PR7)

[](#sync-state-mirror-pr7)

`byte8_entity_sync_state` table, UNIQUE on `(entity_type, magento_id, provider)`. Read model only — never the source of truth. Two writers:

- **Magento-side write-through** at `enqueueEvent` time (when `$providerForMirror` is set) — UPSERTs `pending` row immediately so admin grids render the chip without waiting for the cron drain or ledger callback.
- **Ledger-side terminal callback** via `POST /V1/byte8/sync-state` — UPSERTs the terminal status (`synced` / `skipped` / `failed`) when the ledger sync\_run terminates.

Per-provider modules render this via grid columns + admin info blocks — see `byte8/module-sage-accounting/Block/Adminhtml/SyncStatus/EntityInfo.php` for the canonical example.

Adding a new connector module
-----------------------------

[](#adding-a-new-connector-module)

A new `byte8/module-` module needs:

1. `composer.json` requiring `byte8/module-core` + `byte8/module-client`.
2. `etc/module.xml` with `` listing `Byte8_Core` + `Byte8_Client`.
3. Per-provider config interface (mirror `Byte8\SageAccounting\Api\SageConfigInterface`) with a stable `PROVIDER_KEY` constant (`'sage_accounting'`, `'xero'`, …) — used as the `$providerForMirror` arg to `enqueueEvent`.
4. Observers on the entity events you want to sync — call `$this->byteClient->enqueueEvent($eventName, $payload, $idempotencyKey, ProviderConfig::PROVIDER_KEY)`. Stable idempotency keys (`invoice.created:{id}`).
5. Per-provider admin UI surfaces (Connect-flow blocks, settings page, sync-status grid columns) — copy the layout from `byte8/module-sage-accounting`.

You **don't** need to implement: outbox, drain cron, JWT auth, canonical entity getters, sync-state mirror table, dead-letter banner, retry logic, OAuth handshake. All in this module already.

Database
--------

[](#database)

`byte8_event_outbox` and `byte8_entity_sync_state`. Both managed via `etc/db_schema.xml` — `bin/magento setup:upgrade` applies them.

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

[](#requirements)

- PHP 8.1+ (8.4 supported)
- Magento Open Source / Adobe Commerce 2.4.4+
- MySQL 8.0+ / MariaDB 10.6+
- A configured Byte8 Ledger tenant (paired via the per-provider module's Connect flow)
- Outbound HTTPS to `ledger.byte8.io` (port 443)

Console commands
----------------

[](#console-commands)

```
bin/magento byte8:sage:outbox:inspect            # list dead-lettered events
bin/magento byte8:sage:outbox:requeue        # requeue a dead-lettered event
bin/magento byte8:sage:outbox:cleanup [--days=N] # purge succeeded events older than N days
```

(The `byte8:sage:` prefix is historical — these commands are provider-agnostic and work for any connector.)

Security
--------

[](#security)

See [`SECURITY.md`](SECURITY.md) for the full operator runbook covering JWT key rotation, dead-letter triage, and incident-response playbooks.

License
-------

[](#license)

[MIT](LICENSE.txt)

Support
-------

[](#support)

Byte8 Ltd —

###  Health Score

40

—

FairBetter than 86% of packages

Maintenance92

Actively maintained with recent releases

Popularity0

Limited adoption so far

Community10

Small or concentrated contributor base

Maturity52

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 ~2 days

Total

2

Last Release

38d ago

### Community

Maintainers

![](https://www.gravatar.com/avatar/612c19aab21c48e9c7d11d11eab8863b9473743c6ab7335aeb5a1424129b46cc?d=identicon)[softcom](/maintainers/softcom)

---

Top Contributors

[![softcommerceltd](https://avatars.githubusercontent.com/u/6104757?v=4)](https://github.com/softcommerceltd "softcommerceltd (3 commits)")

### Embed Badge

![Health badge](/badges/byte8-module-client/health.svg)

```
[![Health](https://phpackages.com/badges/byte8-module-client/health.svg)](https://phpackages.com/packages/byte8-module-client)
```

###  Alternatives

[php-http/cache-plugin

PSR-6 Cache plugin for HTTPlug

25025.5M79](/packages/php-http-cache-plugin)[illuminate/http

The Illuminate Http package.

13137.2M6.4k](/packages/illuminate-http)[rdkafka/rdkafka

A PHP extension for Kafka

2.2k20.0k1](/packages/rdkafka-rdkafka)[httpsoft/http-message

Strict and fast implementation of PSR-7 and PSR-17

87930.4k112](/packages/httpsoft-http-message)[mezzio/mezzio-router

Router subcomponent for Mezzio

265.3M82](/packages/mezzio-mezzio-router)[serpapi/google-search-results-php

Get Google, Bing, Baidu, Ebay, Yahoo, Yandex, Home depot, Naver, Apple, Duckduckgo, Youtube search results via SerpApi.com

69122.6k](/packages/serpapi-google-search-results-php)

PHPackages © 2026

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