concept7/nbo-php-sdk

An SDK written in PHP to work with the NieuwbouwOffice API

Maintainers

Package info

github.com/concept7/nbo-php-sdk

pkg:composer/concept7/nbo-php-sdk

Fund package maintenance!

concept7

Statistics

Installs: 654

Dependents: 1

Suggesters: 0

Stars: 0

Open Issues: 0

0.0.2 2026-05-20 13:46 UTC

README

Latest Version on Packagist Tests Total Downloads

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/ uses public readonly properties; instantiate them via Project::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 return null for everything not in the list payload. Look up the full property set in src/Data/Project.php, UnitType.php, Unit.php, and Media.php.
  • Shared media endpoint. All three resources reach /.../media/ through a single decorating GetMediaRequest (src/Requests/Media/GetMediaRequest.php) that wraps the parent detail request and appends media/. The same Media DTO is used regardless of which parent the media belongs to.
  • Casting. Numeric strings become int or float; date strings become Carbon\CarbonImmutable; the API's "-1" / "0" booleans become real bool (-1true, 0false).
  • Errors. The connector uses Saloon's AlwaysThrowOnErrors trait, so non-2xx responses raise a Saloon\Exceptions\Request\RequestException subclass 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.