macadress / macadress-php
Official PHP client for the macadress.com MAC address and OUI vendor lookup API. Laravel-ready.
Requires
- php: ^8.2
- ext-json: *
- guzzlehttp/guzzle: ^7.8
Requires (Dev)
- laravel/pint: ^1.16
- orchestra/testbench: ^9.0
- phpstan/phpstan: ^2.0
- phpunit/phpunit: ^11.0
Suggests
- illuminate/support: Enables the auto-discovered Laravel service provider, Macadress facade and publishable config.
README
Official PHP client for the macadress.com MAC address and OUI vendor lookup API.
- Vendor name, OUI, IEEE block, country, address type, EUI-64 / IPv6 link-local, randomization confidence, device guess
- Keyless vendor-name lookup, plus keyed single / batch / directory-search endpoints
- Typed results and a typed exception per failure mode
- Laravel service provider, facade and publishable config, auto-discovered
$mac = new \Macadress\Client('mk_live_xxx'); $mac->vendor('00:03:93:AB:12:34'); // "Apple, Inc." (no API key required) $mac->lookup('00:03:93:AB:12:34')->country(); // "US"
Requirements
- PHP 8.2+
guzzlehttp/guzzle7.8+ (pulled in automatically)
Install
composer require macadress/macadress-php
Getting a key
vendor() needs no key. Everything else does. A free key (1,000 lookups a day)
is instant at macadress.com/signup; see
pricing for more.
Usage
Create a client
use Macadress\Client; $mac = new Client('mk_live_xxx'); // keyless: only vendor() will work $mac = new Client(); // options $mac = new Client('mk_live_xxx', [ 'base_uri' => 'https://api.macadress.com', // change only for a self-hosted deployment 'timeout' => 10.0, 'connect_timeout' => 5.0, 'headers' => ['X-Trace' => 'my-app'], ]);
vendor() — name only, no key
Returns the vendor string, or null when the address is valid but has no
vendor to report (unregistered, private, or locally administered / randomized).
$mac->vendor('00:03:93:AB:12:34'); // "Apple, Inc." $mac->vendor('02:1a:2b:3c:4d:5e'); // null
lookup() — full analysis
$r = $mac->lookup('3C:22:FB:12:34:56'); $r->organization(); // ?string $r->isVendorLookupReliable(); // bool (false for a private block / LAA) $r->oui(); // "3C:22:FB" $r->matchedPrefix(); // full matched block at its real width $r->blockType(); // Macadress\Enums\BlockType::MaL | null $r->country(); // "US" | null $r->administrationType(); // AdministrationType::Universal | ::Local $r->isPotentiallyRandomized(); // bool $r->randomizationConfidence(); // RandomizationConfidence::None | ::Possible | ::Likely $r->eui64(); // "3E:22:FB:FF:FE:12:34:56" | null $r->ipv6LinkLocal(); // "fe80::3e22:fbff:fe12:3456" | null $r->device()->category(); // DeviceCategory::Unknown (usually) $r->explanation(); // plain-English summary $r->databaseVersion(); // "2026-08-30" (UTC sync date)
Any field not covered by a typed getter is still reachable:
$r->get('vendor_location.city'); // dot path, null if absent $r['organization']; // array access $r->toArray(); // the raw decoded payload
batch() — up to 100 at once
Results come back in input order; check each item for a per-entry error.
foreach ($mac->batch(['00:03:93:00:00:00', '3C:22:FB:00:00:00', 'bad']) as $item) { echo $item->failed() ? "{$item->input()} -> ERROR {$item->error()}\n" : "{$item->input()} -> {$item->organization()}\n"; }
Throws \InvalidArgumentException (no request made) if the array is empty or has more than 100 entries.
searchVendors() — the directory
$result = $mac->searchVendors('Cisco', ['country' => 'US', 'limit' => 20]); $result->total(); // total matches, ignoring the limit foreach ($result as $block) { echo "{$block->blockType()?->value} {$block->organization()} ({$block->country()})\n"; }
health()
$mac->health(); // bool, keyless, uncounted
Errors
Every failure is an exception extending Macadress\Exceptions\MacadressException.
| Exception | When |
|---|---|
InvalidMacException |
HTTP 400, the input did not parse |
AuthenticationException |
HTTP 401, missing or invalid API key |
RateLimitException |
HTTP 429, per-minute rate exceeded. ->retryAfter (seconds) when sent |
QuotaExceededException |
HTTP 429, billing-cycle quota spent. Subclass of RateLimitException |
ApiException |
any other 4xx/5xx, or an unreadable response |
TransportException |
never reached the API: DNS, connection, TLS, timeout |
ConfigurationException |
bad constructor options (thrown before any request) |
Each carries ->statusCode, ->requestId and ->responseBody where available.
use Macadress\Exceptions\RateLimitException; use Macadress\Exceptions\MacadressException; try { $r = $mac->lookup($input); } catch (RateLimitException $e) { sleep($e->retryAfter ?? 5); } catch (MacadressException $e) { report("macadress {$e->statusCode}: {$e->getMessage()} ({$e->requestId})"); }
Laravel
The provider and Macadress facade are auto-discovered. Add your key to .env:
MACADRESS_API_KEY=mk_live_xxx # optional; omit for keyless vendor() only # MACADRESS_BASE_URI=https://api.macadress.com # MACADRESS_TIMEOUT=10
Optionally publish the config:
php artisan vendor:publish --tag=macadress-config
Use the facade:
use Macadress\Laravel\Facades\Macadress; Macadress::vendor('00:03:93:AB:12:34'); Macadress::lookup('00:03:93:AB:12:34')->organization();
or inject the client (it is a singleton):
use Macadress\Client; public function show(string $mac, Client $macadress) { return $macadress->lookup($mac)->toArray(); }
See examples/06-laravel.php for more, including
releasing a queued job on RateLimitException.
Examples
Runnable scripts in examples/:
php examples/01-vendor-name.php 00:03:93:AB:12:34 MACADRESS_API_KEY=mk_live_xxx php examples/02-full-lookup.php 3C:22:FB:00:00:00 MACADRESS_API_KEY=mk_live_xxx php examples/03-batch.php MACADRESS_API_KEY=mk_live_xxx php examples/04-search-vendors.php Cisco US
Development
composer install composer test # phpunit composer analyse # phpstan (level 8) composer format # laravel/pint
Links
- API reference: https://macadress.com/docs
- OpenAPI spec: https://api.macadress.com (
/static/openapi.yamlon the site) - Issues: https://github.com/sapisos/macadress-php/issues
License
MIT, see LICENSE. A product of ApisOS FZE.