aade / afm-lookup
PHP client for querying Greek VAT/AFM numbers via AADE's official SOAP service
v0.1.1
2026-01-17 06:24 UTC
Requires
- php: ^8.1
- ext-dom: *
- ext-soap: *
Requires (Dev)
- friendsofphp/php-cs-fixer: ^3.0
- phpstan/phpstan: ^1.10
- phpunit/phpunit: ^10.0
README
PHP library for querying Greek VAT (AFM) numbers via AADE's official SOAP service.
Quick Start
composer require aade/afm-lookup
use Aade\AfmLookup\AadeClient; $client = new AadeClient('your_username', 'your_password'); $response = $client->getVatInfo('094014201'); if ($response->success) { echo $response->basic->name; // Business name echo $response->basic->afm; // VAT number echo $response->basic->isActive; // true/false }
Note: You need AADE credentials. Register here.
Table of Contents
Requirements
| Requirement | Version |
|---|---|
| PHP | >= 8.1 |
| ext-soap | * |
| ext-dom | * |
Installation
composer require aade/afm-lookup
Usage Guide
Creating a Client
Basic:
use Aade\AfmLookup\AadeClient; $client = new AadeClient('your_username', 'your_password');
With options:
$client = new AadeClient( username: 'your_username', password: 'your_password', callerAfm: '123456789', // Your AFM (for AADE logging) timeout: 60, // Seconds (default: 30) verifySsl: true, // Default: true );
Looking Up an AFM
$response = $client->getVatInfo('094014201'); if ($response->success) { $info = $response->basic; // Business identity echo $info->afm; // "094014201" echo $info->name; // "ΔΗΜΟΣΙΑ ΕΠΙΧΕΙΡΗΣΗ ΗΛΕΚΤΡΙΣΜΟΥ Α.Ε." echo $info->commercialTitle; // "ΔΕΗ Α.Ε." // Tax office echo $info->doyCode; // "1159" echo $info->doyDescription; // "Φ.Α.Ε. ΑΘΗΝΩΝ" // Address echo $info->postalAddress; // "ΧΑΛΚΟΚΟΝΔΥΛΗ" echo $info->postalAddressNumber; // "30" echo $info->postalZipCode; // "10432" echo $info->postalCity; // "ΑΘΗΝΑ" // Status echo $info->isActive; // true echo $info->isNormalVat; // true echo $info->legalStatusDescription; // "ΑΕ" // Dates (DateTimeImmutable or null) echo $info->registrationDate?->format('d/m/Y'); // "01/01/1950" echo $info->stopDate; // null (if active) }
Validating AFM Format
Validate locally before making an API call:
use Aade\AfmLookup\AadeClient; // Static method - no API call if (AadeClient::validateAfm('094014201')) { // Valid format (9 digits, correct check digit) } // Invalid examples: AadeClient::validateAfm('12345678'); // false - only 8 digits AadeClient::validateAfm('000000000'); // false - all zeros AadeClient::validateAfm('094014202'); // false - wrong check digit
Historical Lookups
Query business information as it was on a specific date:
use DateTimeImmutable; // Get info as of January 15, 2023 $date = new DateTimeImmutable('2023-01-15'); $response = $client->getVatInfo('094014201', $date);
Date format: The library accepts any
DateTimeInterfaceimplementation. Internally, dates are sent to AADE inY-m-dformat (e.g.,2023-01-15).
Business Activities
Each business can have multiple registered activities (KAD codes):
$response = $client->getVatInfo('094014201'); // Get main activity $main = $response->getMainActivity(); if ($main !== null) { echo $main->code; // "35.11" echo $main->description; // "Παραγωγή ηλεκτρικής ενέργειας" } // Iterate all activities foreach ($response->firmActivities as $activity) { echo $activity->code; // KAD code echo $activity->description; // Activity description echo $activity->kind; // 1 = main, 2+ = secondary echo $activity->kindDescription; // "ΚΥΡΙΑ" or "ΔΕΥΤΕΡΕΥΟΥΣΑ" echo $activity->isMainActivity(); // true/false }
Error Handling
use Aade\AfmLookup\AadeClient; use Aade\AfmLookup\Exception\InvalidAfmException; use Aade\AfmLookup\Exception\AuthenticationException; use Aade\AfmLookup\Exception\RateLimitException; use Aade\AfmLookup\Exception\SoapException; use Aade\AfmLookup\Exception\AadeException; try { $response = $client->getVatInfo('094014201'); } catch (InvalidAfmException $e) { // AFM format is invalid (checked locally before API call) } catch (AuthenticationException $e) { // Wrong username/password or account not authorized } catch (RateLimitException $e) { // Daily call limit exceeded } catch (SoapException $e) { // Network error or SOAP fault } catch (AadeException $e) { // Other AADE service errors $errorCode = $e->getErrorCode(); // ErrorCode enum or null }
Checking error types via ErrorCode:
if ($e->getErrorCode()?->isAuthenticationError()) { /* ... */ } if ($e->getErrorCode()?->isRateLimitError()) { /* ... */ } if ($e->getErrorCode()?->isNotFoundError()) { /* ... */ } if ($e->getErrorCode()?->isBlockedError()) { /* ... */ }
API Reference
AadeClient
public function __construct( string $username, string $password, ?string $callerAfm = null, int $timeout = 30, bool $verifySsl = true, )
| Method | Returns | Description |
|---|---|---|
getVatInfo(string $afm, ?DateTimeInterface $asOnDate = null) |
AfmInfoResponse |
Query AFM information |
getVersion() |
string |
Get AADE service version |
validateAfm(string $afm) |
bool |
Validate AFM format (static) |
Response Objects
AfmInfoResponse
| Property | Type | Description |
|---|---|---|
success |
bool |
true if lookup succeeded |
callSequenceId |
?string |
AADE call tracking ID |
basic |
?BasicInfo |
Business information |
firmActivities |
FirmActivity[] |
List of activities |
error |
?ErrorInfo |
Error details (if failed) |
| Method | Returns | Description |
|---|---|---|
getMainActivity() |
?FirmActivity |
Get primary business activity |
BasicInfo
| Property | Type | Description |
|---|---|---|
afm |
?string |
VAT number |
name |
?string |
Legal business name |
commercialTitle |
?string |
Commercial/trade name |
doyCode |
?string |
Tax office code |
doyDescription |
?string |
Tax office name |
legalStatusCode |
?string |
Legal form code |
legalStatusDescription |
?string |
Legal form (ΑΕ, ΕΠΕ, etc.) |
postalAddress |
?string |
Street name |
postalAddressNumber |
?string |
Street number |
postalZipCode |
?string |
Postal code |
postalCity |
?string |
City |
registrationDate |
?DateTimeImmutable |
Registration date |
stopDate |
?DateTimeImmutable |
Deactivation date |
isNormalVat |
bool |
Normal VAT regime |
isActive |
bool |
Currently active |
FirmActivity
| Property | Type | Description |
|---|---|---|
code |
?string |
KAD activity code |
description |
?string |
Activity description |
kind |
?int |
1 = main, 2+ = secondary |
kindDescription |
?string |
Kind label |
| Method | Returns | Description |
|---|---|---|
isMainActivity() |
bool |
Check if primary activity |
ErrorInfo
| Property | Type | Description |
|---|---|---|
code |
?ErrorCode |
Error code enum |
description |
?string |
Error message from AADE |
AADE Error Codes
| Code | Description | Exception Type |
|---|---|---|
RG_WS_PUBLIC_TOKEN_USERNAME_NOT_AUTHENTICATED |
Invalid credentials | AuthenticationException |
RG_WS_PUBLIC_TOKEN_USERNAME_NOT_DEFINED |
Username missing | AuthenticationException |
RG_WS_PUBLIC_TOKEN_USERNAME_NOT_ACTIVE |
Account inactive | AuthenticationException |
RG_WS_PUBLIC_TOKEN_AFM_NOT_AUTHORIZED |
AFM not authorized | AuthenticationException |
RG_WS_PUBLIC_MAX_DAILY_CALLS_EXCEEDED |
Daily limit reached | RateLimitException |
RG_WS_PUBLIC_MAX_DAILY_USERNAME_CALLS_EXCEEDED |
User daily limit | RateLimitException |
RG_WS_PUBLIC_EPIT_NF |
AFM not found | AadeException |
RG_WS_PUBLIC_WRONG_AFM |
Invalid AFM | InvalidAfmException |
RG_WS_PUBLIC_AFM_CALLED_BY_BLOCKED |
Caller AFM blocked | AadeException |
RG_WS_PUBLIC_SERVICE_NOT_ACTIVE |
Service unavailable | AadeException |
See ErrorCode.php for the complete list.
License
MIT License. See LICENSE for details.