Company numbers
Darvis\UblPeppol\CompanyRegistrationService checks whether a company registration number has the right format for its country. It makes no network call and does not know whether the company exists.
Check a number
use Darvis\UblPeppol\CompanyRegistrationService;
$service = new CompanyRegistrationService();
$result = $service->validate('0681.845.662', 'BE');
if ($result['valid']) {
$number = $result['formatted']; // "0681845662"
} else {
$message = $result['error']; // for example "Invalid checksum. KBO number failed mod97 validation."
}
The arguments are the number first, then the two-letter country code. Spaces, dots and dashes are removed from the number before the check, and the country code is made upper case.
What is checked per country
| Country | type | Format | Checksum | Example |
|---|---|---|---|---|
NL | KVK | 8 digits | No | 12345678 |
BE | KBO | 10 digits | Yes: the last two digits are 97 minus (the first eight digits modulo 97) | 0681845662 |
LU | RCS | 1 letter and 6 digits | No | B123456 |
FR | SIREN or SIRET | 9 digits (SIREN) or 14 digits (SIRET) | No | 732829320, 73282932000074 |
DE | HRA or HRB | HRA or HRB and 1 to 6 digits, space optional | No | HRB 12345 |
getSupportedCountries() returns this list as an array with the keys name, type, type_name, format and example per country code.
The result
validate() always returns an array and never throws.
| Key | Holds |
|---|---|
valid | true or false |
country | The country code, upper case |
country_name | The English name of the country |
number | The number after cleaning: 12 34 56 78 becomes 12345678, HRB 12345 becomes HRB12345 |
formatted | The number for display, or null when invalid. Germany gets a space (HRB 12345), Luxembourg is made upper case |
type | KVK, KBO, RCS, SIREN, SIRET, HRA or HRB. null when a French or German number has the wrong shape |
type_name | The full name of the register. Missing when type is null |
error | null when valid, otherwise a sentence |
Extra keys: a valid SIRET adds siren (the first 9 digits) and nic (the last 5). A valid German number adds registration_number (the digits).
A country the service does not know returns valid false, type null and the error Unsupported country code: US. That result has no country_name, formatted or type_name key, and number is the input as you passed it.
The error messages
| Country | error |
|---|---|
NL | Invalid format. Expected 8 digits. |
BE | Invalid format. Expected 10 digits. or Invalid checksum. KBO number failed mod97 validation. |
LU | Invalid format. Expected 1 letter + 6 digits (e.g., B123456). |
FR | Invalid format. Expected 9 digits (SIREN) or 14 digits (SIRET)., or Invalid SIREN format. Expected 9 digits. and Invalid SIRET format. Expected 14 digits. when the length is right but a character is not a digit |
DE | Invalid format. Expected HRA or HRB followed by 1-6 digits (e.g., HRB 12345). |
Use it in a Laravel form
// app/Http/Controllers/CustomerController.php
use Darvis\UblPeppol\CompanyRegistrationService;
$country = (string) $request->input('country');
$request->validate([
'registration_number' => [
'required',
function (string $attribute, mixed $value, \Closure $fail) use ($country) {
$result = app(CompanyRegistrationService::class)->validate((string) $value, $country);
if (! $result['valid']) {
$fail($result['error']);
}
},
],
]);
Store $result['number'], not the raw input, so the value goes into an invoice without dots and spaces.
Where the number goes in an invoice
- Netherlands: the KvK number is the
endpointIdwith scheme0106, and thecompanyIdof the customer. See Dutch invoices. - Belgium: the enterprise number is the
endpointIdwith scheme0208, and theregistrationNumberof the customer. See Belgian invoices.
To check whether a VAT number exists, use VAT numbers.