mihaighita / heartland-retail
A PHP client library for the Heartland Retail (retail.heartland.us) REST API
v1.0.7
2026-03-03 19:21 UTC
Requires
- php: ^8.2
- ext-curl: *
- ext-json: *
Requires (Dev)
- friendsofphp/php-cs-fixer: ^3.0
- phpstan/phpstan: ^2.0
- phpunit/phpunit: ^11.0
README
A complete, PHP 8.2+ client library for the Heartland Retail REST API.
Features
- Full API coverage — Items, Customers, Inventory, Sales, Purchasing, Promotions, Gift Cards, Webhooks, Users & Roles, Tax, Locations, Reports, Custom Fields
- OAuth 2.0 authorization-code flow built-in
- Typed exceptions —
AuthenticationException,AuthorizationException,NotFoundException,ValidationException,RateLimitException,TransportException - Automatic rate-limit retry with
Retry-Aftersupport and exponential back-off on 5xx - Proactive throttling — optional
requestsPerSecondcap - Auto-pagination —
->all()helpers transparently walk every page andyieldrecords - PSR-4 autoloading, strict types throughout
- TLS enforced —
CURLOPT_SSL_VERIFYPEERis alwaystrue; no option to disable it - Sensitive parameter redaction — access tokens are marked with
#[\SensitiveParameter]
Installation
composer require mihaighita/heartland-retail
Requires PHP 8.2+, ext-curl, and ext-json.
Quick Start
use HeartlandRetail\Client; $client = Client::withToken( accessToken: 'your_token_here', subdomain: 'yourstore', // → https://yourstore.retail.heartland.us/api requestsPerSecond: 5.0 // optional: proactive throttle ); // Get a single item $item = $client->items()->get(1234); echo $item->get('description'); // Search customers foreach ($client->customers()->search(['email' => 'jane@example.com']) as $c) { echo $c['first_name'] . ' ' . $c['last_name']; } // Walk ALL items without managing pagination yourself foreach ($client->items()->all(['active' => true]) as $item) { // $item is an associative array }
OAuth 2.0 Setup
use HeartlandRetail\Auth\OAuthClient; use HeartlandRetail\Client; $oauth = new OAuthClient(clientId: 'xxx', clientSecret: 'yyy'); // 1. Redirect the user $state = bin2hex(random_bytes(16)); $_SESSION['oauth_state'] = $state; header('Location: ' . $oauth->getAuthorizationUrl($redirectUri, $scopes, $state)); // 2. In your callback if ($_GET['state'] !== $_SESSION['oauth_state']) { die('CSRF'); } $token = $oauth->exchangeCodeForToken($_GET['code'], $redirectUri); $host = $oauth->lookupAccountHost($token->accessToken); $client = new Client($token->baseUrlFor($host), $token->accessToken);
Filters
$client->items()->search([ 'active' => true, // q[active]=1 'price' => ['>=', 10.00], // q[price][>=]=10 'description' => ['~', 'shirt'], // q[description][~]=shirt ]);
Supported operators: =, !=, <, >, <=, >=, ~ (contains), !~ (not contains)
Error Handling
use HeartlandRetail\Exception\{ AuthenticationException, AuthorizationException, NotFoundException, ValidationException, RateLimitException, TransportException }; try { $client->items()->get(99999); } catch (AuthenticationException $e) { /* expired/invalid token */ } catch (NotFoundException $e) { /* 404 */ } catch (ValidationException $e) { print_r($e->getErrors()); } catch (RateLimitException $e) { /* exhausted all retries */ } catch (TransportException $e) { /* network / cURL error */ }