concept7 / nbo-php-sdk
An SDK written in PHP to work with the NieuwbouwOffice API
Fund package maintenance!
Requires
- php: ^8.3
- nesbot/carbon: ^3.0
- saloonphp/saloon: ^4.0
Requires (Dev)
- laravel/pint: ^1.0
- pestphp/pest: ^4.0
This package is auto-updated.
Last update: 2026-05-20 13:49:03 UTC
README
A PHP SDK for the NieuwbouwOffice REST API. Built on Saloon, it ships typed DTOs and enums for projects, unit types, units, and their media so you can work with the API without touching its Dutch JSON keys.
Installation
You can install the package via composer:
composer require concept7/nbo-php-sdk
Usage
Instantiate the connector with your API token, then access resources off of it:
use NieuwbouwOffice\PhpSdk\NieuwbouwOffice; $nbo = new NieuwbouwOffice('your-api-token'); // All projects (returns Project[]) $projects = $nbo->projects()->list(); // A single project (returns Project) $project = $nbo->projects()->get('e00afb7a1791a22eb8bca3707687c549');
Each DTO exposes typed, readonly properties. Dates are parsed into Carbon\CarbonImmutable and categorical fields like Project::$status are backed by enums (see NieuwbouwOffice\PhpSdk\Enums\ProjectStatus and NieuwbouwOffice\PhpSdk\Enums\UnitStatus).
Unit types and units
Both are scoped to a project. unitTypes() returns the per-project housing types (e.g. "Tussenwoning"), and units() returns the individual homes within those types:
$unitTypes = $nbo->unitTypes($project->uuid)->list(); $unitType = $nbo->unitTypes($project->uuid)->get($unitTypes[0]->uuid); $units = $nbo->units($project->uuid)->list(); $unit = $nbo->units($project->uuid)->get($units[0]->uuid);
Media
Every project, unit type, and unit has an attached media collection (photos, plans, etc.). Each resource exposes a media() method that returns Media[]:
$projectMedia = $nbo->projects()->media($project->uuid); $unitTypeMedia = $nbo->unitTypes($project->uuid)->media($unitType->uuid); $unitMedia = $nbo->units($project->uuid)->media($unit->uuid);
Overriding the base URL
The connector defaults to the production base URL. Pass a second argument to point at a staging or local environment:
$nbo = new NieuwbouwOffice('your-api-token', 'https://staging.nbo.nl/rest');
Documentation
Resources
All resources hang off the NieuwbouwOffice connector and return typed DTOs from NieuwbouwOffice\PhpSdk\Data.
| Call | HTTP request | Returns |
|---|---|---|
$nbo->projects()->list() |
GET /projects/ |
Project[] |
$nbo->projects()->get($uuid) |
GET /projects/{uuid}/ |
Project |
$nbo->unitTypes($projectUuid)->list() |
GET /projects/{projectUuid}/projectwoningen/ |
UnitType[] |
$nbo->unitTypes($projectUuid)->get($uuid) |
GET /projects/{projectUuid}/projectwoningen/{uuid}/ |
UnitType |
$nbo->units($projectUuid)->list() |
GET /projects/{projectUuid}/woningen/ |
Unit[] |
$nbo->units($projectUuid)->get($uuid) |
GET /projects/{projectUuid}/woningen/{uuid}/ |
Unit |
$nbo->projects()->media($uuid) |
GET /projects/{uuid}/media/ |
Media[] |
$nbo->unitTypes($projectUuid)->media($uuid) |
GET /projects/{projectUuid}/projectwoningen/{uuid}/media/ |
Media[] |
$nbo->units($projectUuid)->media($uuid) |
GET /projects/{projectUuid}/woningen/{uuid}/media/ |
Media[] |
Authentication is handled by the connector via an apikey-prefixed Authorization header — pass your token to the constructor and Saloon takes care of the rest.
DTO conventions
- Readonly value objects. Every DTO in
src/Data/usespublic readonlyproperties; instantiate them viaProject::fromResponse($array)(which the request classes do for you), then read. - One DTO per resource, list and detail. Detail-only fields are nullable, so
list()results returnnullfor everything not in the list payload. Look up the full property set insrc/Data/Project.php,UnitType.php,Unit.php, andMedia.php. - Shared media endpoint. All three resources reach
/.../media/through a single decoratingGetMediaRequest(src/Requests/Media/GetMediaRequest.php) that wraps the parent detail request and appendsmedia/. The sameMediaDTO is used regardless of which parent the media belongs to. - Casting. Numeric strings become
intorfloat; date strings becomeCarbon\CarbonImmutable; the API's"-1"/"0"booleans become realbool(-1→true,0→false). - Errors. The connector uses Saloon's
AlwaysThrowOnErrorstrait, so non-2xx responses raise aSaloon\Exceptions\Request\RequestExceptionsubclass instead of silently returning.
Enums
Categorical fields are typed where the value set is known. tryFrom() is used internally, so unknown values come through as null instead of throwing.
| Enum | Backing | Cases | Used by |
|---|---|---|---|
NieuwbouwOffice\PhpSdk\Enums\ProjectStatus |
string (Dutch label) |
9 | Project::$status |
NieuwbouwOffice\PhpSdk\Enums\UnitStatus |
string (Dutch label) |
14 | Unit::$status |
Testing
composer test
Changelog
Please see CHANGELOG for more information on what has changed recently.
Contributing
Please see CONTRIBUTING for details.
Security Vulnerabilities
Please review our security policy on how to report security vulnerabilities.
Credits
License
The MIT License (MIT). Please see License File for more information.