PHPackages                             astermd/vrio-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. [Payment Processing](/categories/payments)
4. /
5. astermd/vrio-client

ActiveLibrary[Payment Processing](/categories/payments)

astermd/vrio-client
===================

Unofficial PHP client for the VRIO commerce API: campaigns, customers, offers, carts, discounts, orders and routes, with opt-in redacted request logging.

v0.0.1(yesterday)00MITPHPPHP &gt;=8.4CI passing

Since Aug 16Pushed yesterdayCompare

[ Source](https://github.com/astermd/vrio-client)[ Packagist](https://packagist.org/packages/astermd/vrio-client)[ RSS](/packages/astermd-vrio-client/feed)WikiDiscussions main Synced today

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

astermd/vrio-client
===================

[](#astermdvrio-client)

A small, dependency-free PHP client for the VRIO commerce API — campaigns, customers, offers, discounts, carts, orders and routes — with opt-in request logging that is redacted by default.

> **Unofficial.** This is an independent client library. It is not the official VRIO PHP SDK and is not affiliated with, endorsed by or supported by VRIO. "VRIO" and related marks belong to their owner, . The name is used here only to identify the API this library talks to. See [LICENSE](LICENSE) for the full notice.

API reference: ****

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

[](#requirements)

- PHP **8.4 minimum**, **8.5 recommended**
- `ext-curl`, `ext-json`

No runtime dependencies. CI runs the full gate on 8.4 and 8.5.

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

[](#installation)

```
composer require astermd/vrio-client
```

Quick start
-----------

[](#quick-start)

```
use AsterMD\VrioClient\API;

$api = new API($apiKey);                       // host defaults to api.vrio.app

$orders = $api->searchOrder(['with' => 'items'])->getInArray();

if ($orders['response']['success']) {
    foreach ($orders['response']['data'] as $order) {
        // ...
    }
}
```

The API key is a **required argument**. This package ships no default credentials and reads none from the environment.

Configuration
-------------

[](#configuration)

```
$api = new API($apiKey, [
    'host'               => 'api.vrio.app',
    'basePath'           => '',
    'timeout'            => 30,
    'connectTimeout'     => 10,
    'debug'              => false,
    'debugRedact'        => true,
    'debugFile'          => null,
    'debugRetentionDays' => 7,
    'debugTimezone'      => 'UTC',
    'debugSink'          => null,
]);
```

OptionTypeDefaultPurpose`host`string`api.vrio.app`**Bare hostname only.** A scheme, path, query or space is rejected.`basePath`string`''`Optional path prefix below the host, e.g. `v1`.`timeout`int`30`Transfer timeout in seconds.`connectTimeout`int`10`Connection timeout in seconds.`debug`bool`false`Master switch for request/response logging.`debugRedact`bool`true`Mask credentials and sensitive fields in log entries.`debugFile`string—Base path for the built-in dated file sink. Required when `debug` is on and no `debugSink` is given.`debugRetentionDays`int`7`Days of log history to keep. `0` keeps everything.`debugTimezone`string`UTC`IANA timezone for log timestamps and dated filenames.`debugSink`callable—Replaces the file sink entirely.### Choosing an environment

[](#choosing-an-environment)

Pass whichever host VRIO issued you. Production defaults to `api.vrio.app`; if your account has a separate sandbox or test host, supply it the same way:

```
$sandbox = new API($sandboxKey, ['host' => 'sandbox-host-from-your-vrio-account']);
```

Full URLs are rejected on purpose — the scheme is always HTTPS and path assembly stays inside the client:

```
new API($apiKey, ['host' => 'https://api.vrio.app']);   // throws VrioException
new API($apiKey, ['host' => 'api.vrio.app/v1']);        // throws VrioException
new API($apiKey, ['host' => 'api.vrio.app', 'basePath' => 'v1']);  // correct
```

Reading a response
------------------

[](#reading-a-response)

Every resource call is chainable and returns the client. Three accessors read the result:

```
$api->searchOrder()->get();          // envelope as a JSON string
$api->searchOrder()->getInArray();   // envelope decoded to an array
$api->searchOrder()->getInObject();  // envelope decoded to an object
```

Pass `true` to also receive the request URL and payload:

```
$api->searchOrder(['with' => 'items'])->getInArray(true);
```

```
[
    'response' => [
        'success' => true,
        'message' => '',
        'data'    => [ /* the provider's body, verbatim */ ],
    ],
    'payload' => [
        'endPoint' => 'https://api.vrio.app/orders?with=items',
        'with'     => 'items',
    ],
]
```

`payload` never contains your API key — it is safe to surface in your own diagnostics.

When the provider returns an error the envelope carries it:

```
[
    'success'         => false,
    'message'         => 'Order not found',
    'validation_code' => 'not_found',
    'data'            => [ /* the provider's error body */ ],
]
```

If the request never reached the provider, the array accessor returns `['curlError' => '...']` instead.

Available methods
-----------------

[](#available-methods)

Consult the [VRIO API reference](https://docs.vrio.com/reference/vrio-api-overview)for the fields each endpoint accepts. `$params` is sent as query parameters on `GET` calls and as the JSON body on the rest.

### Campaigns

[](#campaigns)

MethodRequest`getCampaignItems(string $campaignId, array $params = [])``GET /campaigns/{campaignId}/items`### Customers

[](#customers)

MethodRequest`getCustomer(string $customerId, array $params = [])``GET /customers/{customerId}`### Offers

[](#offers)

MethodRequest`searchOffer(array $params = [])``GET /offers`### Routes

[](#routes)

MethodRequest`getRoute(string $routeId, array $params = [])``GET /routes/{routeId}`### Discounts

[](#discounts)

MethodRequest`validateDiscount(array $params = [])``POST /discounts/validate``calculateDiscount(array $params = [])``POST /discounts/calculate` — the array is sent as the body's `offers` member### Orders

[](#orders)

MethodRequest`searchOrder(array $params = [])``GET /orders``getOrder(string $orderId, array $params = [])``GET /orders/{orderId}``addOrder(array $params = [])``POST /orders``editOrder(array $params = [])``PATCH /orders/{order_id}` — requires `order_id` in `$params``processOrder(string $orderId, array $params = [])``POST /orders/{orderId}/process``completeOrder(string $orderId, array $params = [])``POST /orders/{orderId}/complete``authorizeOrder(string $orderId, array $params = [])``POST /orders/{orderId}/authorize``captureOrder(string $orderId, array $params = [])``POST /orders/{orderId}/capture``addOrderNote(string $orderId, array $params = [])``POST /orders/{orderId}/notes`### Carts

[](#carts)

MethodRequest`createCart(array $params = [])``POST /carts``createPaypalToken(array $params = [])``POST /carts/{cart_token}/payment_tokens` — requires `cart_token``getPaypalData(array $params = [])``GET /carts/{cart_token}/payment_tokens/{payment_token_id}`Examples:

```
$api->getCampaignItems('camp_1', ['with' => 'offers'])->getInArray();

$api->addOrder([
    'connection_id' => 'con_1',
    'campaign_id'   => 'camp_1',
    'email'         => 'buyer@example.test',
])->getInObject();

$api->captureOrder('ord_1', ['amount' => 1000])->getInArray();
```

Errors
------

[](#errors)

Everything the package raises is an `AsterMD\VrioClient\Exception\VrioException`, which extends `\Exception`:

```
use AsterMD\VrioClient\Exception\VrioException;

try {
    $result = $api->getOrder($orderId)->getInArray();
} catch (VrioException $e) {
    // empty API key, non-bare host, missing required argument,
    // unknown method, or an undecodable response
}
```

Provider-side errors and transport failures are **not** exceptions — they come back in the envelope, as shown above.

Debug logging
-------------

[](#debug-logging)

Logging is off unless you turn it on. When on, entries are redacted by default and written as copy-pasteable cURL commands with the response beneath.

```
$api = new API($apiKey, [
    'debug'              => true,
    'debugFile'          => '/var/log/vrio/client.log',
    'debugRetentionDays' => 7,
    'debugTimezone'      => 'UTC',
]);
```

Which produces `/var/log/vrio/client-2026-08-16.log` containing:

```
[2026-08-16 09:14:02.481930 UTC]
curl --location --request POST 'https://api.vrio.app/orders' \
  --header 'Content-Type: application/json' \
  --header 'hostname: api.vrio.app' \
  --header 'X-Api-Key: [REDACTED]' \
  --data '{"email":"buyer@example.test","card":{"number":"[REDACTED]","cvv":"[REDACTED]"}}'

# Response: HTTP 201
{"id":"ord_1","access_token":"[REDACTED]"}

```

### What is redacted

[](#what-is-redacted)

Headers and bodies. In headers: `X-Api-Key`, `Authorization` (the scheme is kept, so `Bearer [REDACTED]`), `Proxy-Authorization`, `Cookie`. In bodies, by field name: API keys and secrets, passwords, every `*_token` including `access_token` and `refresh_token`, card numbers, CVV/CVC, expiry fields, bank account and routing numbers, IBAN, and government identifiers such as SSN, tax ID and date of birth. Card numbers are additionally caught by shape — any 13–19 digit string that passes a Luhn check is masked wherever it appears.

A body that is not decodable JSON cannot be field-masked, so it is replaced whole rather than logged on the chance it is harmless.

**Redaction never changes what is sent or what you receive.** The logger reads from immutable request and response objects and produces a string; the wire request and the value returned to your code are untouched. The test suite asserts this directly.

### The URL is logged verbatim

[](#the-url-is-logged-verbatim)

By design — you need the real URL for a log entry to be reproducible. That means anything the API takes in a path segment or query string is written to the log even with redaction on. In this client that is:

CallWhat lands in the log`getPaypalData()`the cart token and the payment token, both in the path`createPaypalToken()`the cart token, in the path`getCustomer()`the customer ID, in the path`getOrder()`, `processOrder()`, `completeOrder()`, `authorizeOrder()`, `captureOrder()`, `addOrderNote()`, `editOrder()`the order ID, in the path`getCampaignItems()`, `getRoute()`the campaign or route ID, in the pathany `GET` with `$params`every query parameter you passed, encoded but unmaskedDo not pass sensitive values as query parameters to `GET` calls if your log retention cannot accommodate them.

### Turning redaction off

[](#turning-redaction-off)

```
$api = new API($apiKey, [
    'debug'       => true,
    'debugRedact' => false,     // logs the real API key and full bodies
    'debugFile'   => '/tmp/vrio-debug.log',
]);
```

This writes live credentials and complete payloads to disk. It exists for local debugging. **Never enable it in production.**

### File rotation and retention

[](#file-rotation-and-retention)

The built-in sink writes one file per calendar day, deriving the name from your base path: `/var/log/vrio/client.log` becomes `client-2026-08-16.log`, `client-2026-08-17.log`, and so on.

Pruning removes files older than `debugRetentionDays` (default 7; `0` keeps everything). It only ever matches this package's own dated filename pattern for your base path — other files in the directory are never touched — and it reads the age from the filename rather than the modification time, so an appended-to or restored file keeps its true age. It runs once per process, not once per request.

### Sending logs somewhere else

[](#sending-logs-somewhere-else)

Supply a closure and the file sink is replaced entirely. The package then writes no files, and retention becomes your responsibility:

```
$api = new API($apiKey, [
    'debug'     => true,
    'debugSink' => static function (string $entry): void {
        $myLogger->debug($entry);
    },
]);
```

The closure receives the finished entry, already redacted unless you opted out. This is the extension point for any external destination — a PSR-3 logger, a queue, a log shipper, an object store.

A failure inside your sink is caught and discarded: logging must never break an API call.

### Logs stay sensitive after redaction

[](#logs-stay-sensitive-after-redaction)

A redacted entry still records which account touched which order, cart, customer and route, and when. Store logs on encrypted volumes, restrict read access, ship them only to systems cleared for that data, and apply a retention period at least as strict as the rest of your order data.

Proxy support
-------------

[](#proxy-support)

```
$api->withProxy('proxy.example.test:8080', 'user:password')
    ->searchOrder()
    ->getInArray();
```

The setting applies to the next call only.

Custom transport
----------------

[](#custom-transport)

Pass anything implementing `HttpClientInterface` as the third constructor argument to route requests through your own stack, or to test without a network:

```
use AsterMD\VrioClient\Http\HttpClientInterface;
use AsterMD\VrioClient\Http\Request;
use AsterMD\VrioClient\Http\Response;

final class MyTransport implements HttpClientInterface
{
    public function send(Request $request): Response
    {
        // ... hand $request to Guzzle, a PSR-18 client, a fixture ...
        return new Response(200, $body, ['http_code' => 200]);
    }
}

$api = new API($apiKey, [], new MyTransport());
```

TLS peer and host verification are always on in the bundled cURL transport, and there is no option to disable them.

Further documentation
---------------------

[](#further-documentation)

- [Integration guide](docs/INTEGRATION_GUIDE.md) — setup, environments, production logging, error handling, troubleshooting.
- [Architecture](docs/ARCHITECTURE.md) — how a call flows through the package and where to extend it.
- [Security policy](SECURITY.md) — private disclosure and credential handling.
- [Changelog](CHANGELOG.md)

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

[](#development)

```
composer install
composer gate     # phpcs → phpstan (max) → phpunit
```

See [CLAUDE.md](CLAUDE.md) for the conventions the gate enforces. No test in this suite makes a network call.

Support
-------

[](#support)

Email ****, or open an issue at .

Report security issues privately — see [SECURITY.md](SECURITY.md). Do not open a public issue for a vulnerability.

Compliance
----------

[](#compliance)

Using this package does not by itself make your application PCI DSS, HIPAA or GDPR compliant. It is one component in your system. Scoping, encryption at rest, access control, audit logging, breach procedures and your agreements with VRIO and your payment processors remain your responsibility.

License
-------

[](#license)

MIT — see [LICENSE](LICENSE), including the trademark and affiliation notice.

###  Health Score

38

—

LowBetter than 83% of packages

Maintenance100

Actively maintained with recent releases

Popularity0

Limited adoption so far

Community6

Small or concentrated contributor base

Maturity40

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

1d ago

### Community

Maintainers

![](https://avatars.githubusercontent.com/u/294126516?v=4)[astermd-dev](/maintainers/astermd-dev)[@astermd-dev](https://github.com/astermd-dev)

---

Top Contributors

[![raunak-cispl1](https://avatars.githubusercontent.com/u/72799540?v=4)](https://github.com/raunak-cispl1 "raunak-cispl1 (2 commits)")

---

Tags

api-clientecommercephprest-clientvriopaymentsecommerceapi clientorderscheckoutrest-clientvriovrio-api

###  Code Quality

TestsPHPUnit

Static AnalysisPHPStan

Code StylePHP\_CodeSniffer

Type Coverage Yes

### Embed Badge

![Health badge](/badges/astermd-vrio-client/health.svg)

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

###  Alternatives

[cybersource/rest-client-php

Client SDK for CyberSource REST APIs

40975.8k6](/packages/cybersource-rest-client-php)[amsgames/laravel-shop

Package set to provide shop or e-commerce functionality (such as CART, ORDERS, TRANSACTIONS and ITEMS) to Laravel for customizable builds.

4825.9k](/packages/amsgames-laravel-shop)[sylius/payment-bundle

Flexible payments system for Symfony e-commerce applications.

22297.7k10](/packages/sylius-payment-bundle)[sebdesign/laravel-viva-payments

A Laravel package for integrating the Viva Payments gateway

4952.7k](/packages/sebdesign-laravel-viva-payments)[sylius/payment

Flexible payments system for PHP e-commerce applications.

17359.0k11](/packages/sylius-payment)[litle/payments-sdk

The Vantiv eCommerce PHP SDK is a PHP implementation of the \[Vantiv eCommerce\](https://developer.vantiv.com/community/ecommerce). XML API. This SDK was created to make it as easy as possible to connect process your payments with Vantiv eCommerce

19140.8k1](/packages/litle-payments-sdk)

PHPackages © 2026

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