jlecter / checkvin-php-api-client
Package for working with CheckVin API
Package info
github.com/Jlecter/checkvin-php-api-client
pkg:composer/jlecter/checkvin-php-api-client
Requires
- php: >=8.1
- ext-curl: *
- ext-json: *
- checkvin/vincode: ^1.0
Requires (Dev)
- nyholm/psr7: ^1.8
- phpunit/phpunit: ^10.5
- psr/http-client: ^1.0
- psr/http-factory: ^1.1
Suggests
- psr/http-client: Required to use Psr18Client — plug in Guzzle, Symfony HttpClient, or any PSR-18 implementation
- psr/http-factory: Required to use Psr18Client — provides the RequestFactoryInterface for building PSR-7 requests
Provides
None
Conflicts
None
Replaces
None
This package is auto-updated.
Last update: 2026-10-05 16:37:49 UTC
README
CONTENTS OF THIS FILE
- Updates
- Description
- Key packages / extensions
- Installation
- Usage
- Upgrading from 0.x
UPDATES
-
17.03.2023 - published version (v0.1.0) - added an ability to work with AutoCheck, Balance, Carfax.
-
16.08.2023 - published version (v0.2.0) - fixed curl close bug.
-
21.01.2024 - published version (v0.3.0) - added VehicleProvider.
-
2026-10-05 - published version (v1.0.1) - PHP 8.1+, configurable timeouts, client injection, malformed-body safety, dedicated exception, full test suite,
CheckVinfacade entry-point. See Upgrading from 0.x for breaking changes. v1.0.0 was withdrawn (it was published from the wrong commit) — use^1.0.1.DESCRIPTION
CheckVin API client is a package for a convenient working with CheckVin API.
KEY PACKAGES / EXTENSIONS
- php >= 8.1
- ext-curl
- ext-json
- checkvin/vincode ^1.0
INSTALLATION
Run: composer require jlecter/checkvin-php-api-client:^1.0.1
USAGE
- Choose provider what do you need. Available now:
- AutocheckDataProvider
- BalanceDataProvider
- CarfaxDataProvider
- VehicleDataProvider
-
Use it by passing inside your API key and calling available methods.
-
Get a response object with such available methods:
- "isSuccess" (returns true/false depends on response)
- "getData" (returns empty array while error response)
- "getError" (returns object while error response, null while success)
Error object methods (CheckVin\Api\Http\Data\Error):
getMessage(): string— human-readable message (may include flattenederrorsfields)getHttpCode(): int— the real HTTP status code from the responsegetErrors(): array— rawerrorspayload if the API returned an array, otherwise[]isMalformedBody(): bool—truewhen the response body was not a JSON object (e.g. HTML error page, JSON list, empty body)getData(): array— full decoded response body for the error;[]when the body was malformed. Useful for 404 responses with a meaningful body, e.g.checkReportExistsreturns{"message":"Report not found","preset_link":"","checked":true}— access$error->getData()['preset_link']to read that field.
VIN validation (client-side, before any HTTP request):
All VIN-based endpoints validate the supplied VIN before making any HTTP call. The VIN is trimmed, stripped of dashes and spaces, uppercased and then checked for:
- 17-character length (
LengthNotValidException) - Allowed characters — I, O and Q are forbidden (
NotValidLetterException) - North-American check digit at position 9 (
CheckSumNotValidException)
An invalid VIN throws CheckVin\Api\Exception\InvalidVinCode (extends \InvalidArgumentException, implements CheckVinApiException). The original package exception is available via getPrevious().
use CheckVin\Api\Exception\InvalidVinCode; try { $response = $provider->getAutoCheckForVinCode('not-a-vin'); } catch (InvalidVinCode $e) { echo $e->getMessage(); // reason from checkvin/vincode // $e->getPrevious() is the LengthNotValidException / NotValidLetterException / CheckSumNotValidException }
Note: report endpoints (getAutoCheckForVinCode, checkReportExists, getCarfaxForVinCode) only accept North-American VINs (WMI starting with 1–5). A non-North-American VIN that happens to pass the check-digit may be accepted client-side but will be rejected by the API with HTTP 422 "Vincode Invalid. Auto not from North America.". The vehicle/info endpoint (getInfo) is less strict server-side — non-NA VINs were accepted in testing — but client-side validation still requires a valid checksum.
Basic usage — CheckVin facade (recommended):
The CheckVin class is the recommended entry-point. It accepts your API key once,
resolves the HTTP client once, and lazily creates each provider on demand while
sharing the same client across all of them.
use CheckVin\Api\CheckVin; $checkVin = new CheckVin('your-api-key'); $response = $checkVin->autocheck()->checkReportExists('1FM5K7D85HGB31870'); if ($response->isSuccess()) { var_dump($response->getData()); } else { $error = $response->getError(); if ($error->isMalformedBody()) { // Transport / gateway problem — no API error payload echo 'Unexpected response, HTTP ' . $error->getHttpCode(); } elseif ($error->getHttpCode() === 422 && $error->getMessage() === 'Пользователь не найден') { // Invalid API key — the server returns HTTP 422, not 401/403. // It cannot be distinguished from a validation error by status code alone; // check getMessage() for the exact string when you need to tell them apart. echo 'Invalid API key'; } elseif ($error->getHttpCode() === 404) { echo 'Report not found'; } elseif ($error->getHttpCode() === 429) { echo 'Rate limit exceeded'; } else { // 422 validation error, 5xx, etc. echo $error->getMessage(); // Field-level details if available: foreach ($error->getErrors() as $field => $messages) { echo $field . ': ' . (is_array($messages) ? implode(', ', $messages) : $messages); } } }
All four providers are available through the facade:
$checkVin->autocheck()->getAutoCheckForVinCode('1FM5K7D85HGB31870'); $checkVin->carfax()->getCarfaxForVinCode('1FM5K7D85HGB31870'); $checkVin->vehicle()->getInfo('1FM5K7D85HGB31870'); $checkVin->balance()->getBalance();
Alternative: instantiate providers directly
You can still create each provider individually when you only need one, or when you need different configuration per provider:
use CheckVin\Api\Provider\Autocheck\AutocheckDataProvider; $provider = new AutocheckDataProvider('your-api-key'); $response = $provider->checkReportExists('1FM5K7D85HGB31870');
Custom host and timeouts:
use CheckVin\Api\Config\Config; use CheckVin\Api\Http\Client\Client; use CheckVin\Api\Provider\Autocheck\AutocheckDataProvider; $config = new Config( host: 'https://apicheckvin.xyz', connectTimeoutMs: 1000, // 1 s connect timeout timeoutMs: 5000, // 5 s total timeout ); $client = new Client($config); $provider = new AutocheckDataProvider('your-api-key', $client);
Catching transport failures:
use CheckVin\Api\Exception\RequestFailed; try { $response = $provider->checkReportExists('1FM5K7D85HGB31870'); } catch (RequestFailed $e) { // curl transport error or timeout echo $e->getMessage(); // "Request failed (errno N): ..." }
API BEHAVIOUR NOTES
Balance: getData()['message'] is a number (float), not a string. For example: 12.6.
Invalid API key: the server responds with HTTP 422 (not 401/403) and {"message":"Пользователь не найден"}. This status is identical to a validation error; distinguish by the message text when necessary.
Validation errors (422): follow Laravel format. getErrors() returns an object where each key is a field name and the value is an array of messages:
// ["vincode" => ["The vincode must be at least 17 characters."]] $error->getErrors();
checkReportExists (carfax and autocheck):
- HTTP 200 → report found;
getData()['preset_link']contains the view URL. - HTTP 404 → report not found;
isSuccess()isfalse. UsegetError()->getData()to read the full body, includingpreset_link(empty string). - For carfax, the body contains
"checked": truein both cases. This means the lookup ran — it does not indicate that a report exists. Always useisSuccess()(orgetError()->getHttpCode()) to determine whether a report was found.
Rate limit: 60 requests per minute. The server sends X-Ratelimit-Limit and X-Ratelimit-Remaining headers, but these are not exposed by the client; handle HTTP 429 via getError()->getHttpCode().
Full report response shapes:
Autocheck (getAutoCheckForVinCode): vin (decoded as [] — server quirk, returns {} instead of a VIN string), has_autocheck (bool), updated_at (ISO 8601 datetime string), autocheck_data (HTML string), link (string).
Carfax (getCarfaxForVinCode): vin (string), hash (string), has_carfax (bool), updated_at ("HH:MM:SS DD-MM-YYYY" format — different from autocheck's ISO 8601), carfax_data (HTML string), link (string, may contain a double slash in the path — server quirk).
Vehicle info (getInfo): data → {brand, model, vin, year (int), engine_fuel, engine_hp (int)}.
USING YOUR OWN HTTP CLIENT (PSR-18)
By default the SDK uses its built-in curl client. If you need connection pooling, retries, a proxy, or any other transport feature, pass any PSR-18-compatible HTTP client to the provider instead.
Install the adapter and a PSR-7 factory (only needed by callers that use
Psr18Client; the SDK itself has no runtime dependency on these packages):
composer require guzzlehttp/guzzle nyholm/psr7
Wire it up:
use CheckVin\Api\Http\Client\Psr18Client; use CheckVin\Api\Provider\Balance\BalanceDataProvider; use GuzzleHttp\Client as GuzzleClient; use Nyholm\Psr7\Factory\Psr17Factory; // Guzzle 7 implements PSR-18 natively. // GuzzleHttp\Psr7\HttpFactory also works as the request factory // (verify the class name against your installed guzzlehttp/psr7 version). $guzzle = new GuzzleClient([ 'connect_timeout' => 1, // seconds 'timeout' => 10, ]); $factory = new Psr17Factory(); // nyholm/psr7 — implements RequestFactoryInterface $client = new Psr18Client($guzzle, $factory); $provider = new BalanceDataProvider('your-api-key', $client); $response = $provider->getBalance();
Note: timeouts, retries, and proxy settings must be configured on the
PSR-18 client directly. Psr18Client does not apply any timeouts of its own.
Transport errors thrown by the PSR-18 client (Psr\Http\Client\ClientExceptionInterface)
are mapped to CheckVin\Api\Exception\RequestFailed, with the original exception
available via getPrevious().
UPGRADING FROM 0.x
1.0 introduces the following breaking changes:
-
PHP >= 8.1 required. PHP 7.4 and 8.0 are no longer supported.
-
Configconstructor now accepts parameters. Old:new Config()— no parameters, uses hard-coded internal defaults. New:new Config(string $host, int $connectTimeoutMs, int $timeoutMs)— all optional.Configis nowfinal. Default timeouts changed: connect timeout is now 10 000 ms (10 s), total timeout is now 60 000 ms (60 s). Previously there was no total timeout and the curl default connect timeout applied. A trailing slash on$hostis silently trimmed, sohttps://host/andhttps://hostbehave identically.connectTimeoutMs <= 0ortimeoutMs <= 0throwsCheckVin\Api\Exception\InvalidConfig(extends\InvalidArgumentException).timeoutMs < connectTimeoutMsalso throwsInvalidConfig— a total timeout shorter than the connect timeout would make the connect timeout unreachable. -
All four providers accept an optional
ClientInterfaceas second constructor argument. Old:new AutocheckDataProvider('key'). New:new AutocheckDataProvider('key', ?ClientInterface $client = null). Existing call sites continue to work unchanged. -
VehicleDataProvider::getInfo()now requires a$vinCodeargument. Old (broken — caused a fatalArgumentCountErrorat runtime):$provider->getInfo(). New:$provider->getInfo(string $vinCode): ApiResponse. The matching interfaceVehicleDataProviderInterfaceis updated accordingly. -
Malformed / non-JSON response bodies no longer cause a
TypeError. Old: a curl response that is not a JSON object (HTML error page, empty body, truncated response) caused aTypeError(null passed to array parameter) even on HTTP 200. New: those cases return an errorApiResponse(isSuccess() === false). The error message now includes the HTTP status, e.g."Malformed response body (HTTP 200)". A 200 response with a non-JSON body is also treated as an error. 1.0 also treats a JSON list (e.g.[1,2,3],[]) as a malformed body — the API contract requires a JSON object. An empty object{}remains valid. -
\LogicExceptionreplaced byCheckVin\Api\Exception\RequestFailed. Old: curl transport errors threw\LogicException. New: they throwCheckVin\Api\Exception\RequestFailed(extends\RuntimeException, implementsCheckVin\Api\Exception\CheckVinApiException). Update anycatch (\LogicException $e)blocks. -
Most concrete classes are now
final. The following classes cannot be extended:Config,Client,ClientResponse,Error,ApiResponse,ApiUriGlossary,AutocheckDataProvider,BalanceDataProvider,CarfaxDataProvider,VehicleDataProvider. If you were extending any of these, compose instead. -
ClientInterface::makeResponse()has been removed. Old:ClientInterfacehad bothrequest()andmakeResponse(). New:ClientInterfaceonly hasrequest(). Response mapping is handled byApiResponse::fromClientResponse(ClientResponse): ApiResponse. Update customClientInterfaceimplementations and any direct calls to$client->makeResponse(). -
AutoCheckDataProviderInterfacerenamed toAutocheckDataProviderInterface. Old:CheckVin\Api\Provider\Autocheck\AutoCheckDataProviderInterface. New:CheckVin\Api\Provider\Autocheck\AutocheckDataProviderInterface. Update any type hints,implementsclauses, andusestatements referencing the old name. -
Client-side VIN validation is now enforced before any HTTP request. Calling any VIN-based endpoint (
getAutoCheckForVinCode,checkReportExists,getCarfaxForVinCode,getInfo) with an invalid VIN now throwsCheckVin\Api\Exception\InvalidVinCode(extends\InvalidArgumentException) before any network call is made. Previously, the raw string was forwarded to the API and validation errors came back as HTTP 4xx responses. The underlying package exception (LengthNotValidException,NotValidLetterException, orCheckSumNotValidExceptionfromcheckvin/vincode) is available via$e->getPrevious(). Only North-American VINs (valid check digit at position 9) are accepted. A new Composer dependencycheckvin/vincode ^1.0is required. -
Response class hierarchy collapsed into a single
ApiResponse. Old:Abstraction\ApiResponse→Abstraction\ErrorResponse/Abstraction\SuccessResponse→Error\ApplicationErrorResponse/Success\ApplicationSuccessResponse. New: onefinal class ApiResponseatCheckVin\Api\Http\Response\ApiResponsewith a named constructorApiResponse::fromClientResponse(ClientResponse): ApiResponse.
- Replace any
use CheckVin\Api\Http\Response\Abstraction\ApiResponsewithuse CheckVin\Api\Http\Response\ApiResponse. - Replace
instanceof ErrorResponse/instanceof ApplicationErrorResponsechecks with!$response->isSuccess(). - Replace
instanceof SuccessResponse/instanceof ApplicationSuccessResponsechecks with$response->isSuccess(). SuccessResponse::SUCCESS_CODE(= 200) has no public replacement; remove references to it.