woweb / laravel-openproduct
Laravel wrapper for Open Product
Requires
- php: ^8.2
- guzzlehttp/guzzle: ^7.2
- illuminate/http: ^10.0|^11.0|^12.0
- illuminate/support: ^10.0|^11.0|^12.0
- illuminate/validation: ^10.0|^11.0|^12.0
- orchestra/testbench: ^10.0
Requires (Dev)
- phpunit/phpunit: ^10.0|^11.0
This package is auto-updated.
Last update: 2026-04-24 13:18:12 UTC
README
Laravel wrapper for the Product API and Producttypes API based on Open Product.
Supported API versions
| API | Version |
|---|---|
| Producten API | v1.4.0 |
| Producttypen API | v1.4.0 |
Requirements
- PHP 8.2 or higher
- Laravel 10, 11, or 12
Installation
composer require woweb/laravel-openproduct
The service provider is registered automatically via Laravel's package auto-discovery.
Publish the configuration:
php artisan vendor:publish --provider="Woweb\Openproduct\OpenProductServiceProvider"
Configuration
Add the following variables to your .env:
OPENPRODUCT_URL=https://your-openproduct-instance.nl/open-product/ OPENPRODUCT_AUTH_TOKEN=your-api-token OPENPRODUCT_LANGUAGE=nl
OPENPRODUCT_LANGUAGE sets the Accept-Language header on every API request. Defaults to nl.
Upgrading from v1.x
Method names were changed in v2 to be consistent across all classes. Update your call sites:
| Old (v1) | New (v2) |
|---|---|
Producten::getAllProducten() |
Producten::list() |
Producten::getSingleProduct($uuid) |
Producten::get($uuid) |
Producten::createProduct($data) |
Producten::create($data) |
Producten::updateProduct($uuid, $data) |
Producten::patch($uuid, $data) |
ProductTypen::getAllProducttypes() |
ProductTypen::list() |
ProductTypen::getSingleProducttype($uuid) |
ProductTypen::get($uuid) |
ProductTypen::updateProducttype($uuid, $data) |
ProductTypen::patch($uuid, $data) |
Usage
All classes throw OpenProductValidationException for invalid input before the API call is made, and OpenProductException for HTTP errors returned by the API.
Error handling
use Woweb\Openproduct\Exceptions\OpenProductException; use Woweb\Openproduct\Exceptions\OpenProductValidationException; try { $product = Producten::create($data); } catch (OpenProductValidationException $e) { // Validation error in the provided data (before the API call) logger()->error($e->getMessage()); } catch (OpenProductException $e) { // HTTP error from the API (e.g. 404, 500) logger()->error('API error ' . $e->getCode() . ': ' . $e->getMessage()); }
Producten
Endpoint: producten/api/v1/producten
use Woweb\Openproduct\Api\Producten; // List products (optional filters) $producten = Producten::list(['status' => 'actief', 'page' => 1]); // Get a single product $product = Producten::get('550e8400-e29b-41d4-a716-446655440000'); // Create a product $product = Producten::create([ 'producttype_uuid' => '550e8400-e29b-41d4-a716-446655440001', 'eigenaren' => [['bsn' => '123456789']], 'naam' => 'Parking permit', 'start_datum' => '2026-01-01', 'status' => 'actief', 'frequentie' => 'eenmalig', ]); // Full update (PUT) $product = Producten::update('550e8400-...', [ 'producttype_uuid' => '550e8400-...', 'eigenaren' => [['bsn' => '123456789']], ]); // Partial update (PATCH) $product = Producten::patch('550e8400-...', ['status' => 'ingetrokken']); // Delete Producten::delete('550e8400-...');
Valid values for status: initieel, in_aanvraag, gereed, actief, ingetrokken, geweigerd, verlopen.
Valid values for frequentie: eenmalig, maandelijks, jaarlijks.
ProductTypen
Endpoint: producttypen/api/v1/producttypen
use Woweb\Openproduct\Api\ProductTypen; // List product types (optional filters) $typen = ProductTypen::list(['doelgroep' => 'burgers']); // Get a single product type $type = ProductTypen::get('550e8400-...'); // Create $type = ProductTypen::create([ 'doelgroep' => 'burgers', 'thema_uuids' => ['497f6eca-...'], 'naam' => 'Parkeervergunning', 'samenvatting' => 'Vergunning voor parkeren in de stad.', 'code' => 'PT-PARKEER', ]); // Full update (PUT) $type = ProductTypen::update('550e8400-...', [...]); // Partial update (PATCH) $type = ProductTypen::patch('550e8400-...', ['naam' => 'Updated name']); // Delete ProductTypen::delete('550e8400-...'); // Get the current/active price for a product type $prijs = ProductTypen::getActuelePrijs('550e8400-...'); // Get current prices for all product types $prijzen = ProductTypen::getAllActuelePrijzen(); // Get content blocks linked to a product type $content = ProductTypen::getContent('550e8400-...', ['taal' => 'nl']); // Create or replace a translation (PUT) $vertaling = ProductTypen::updateVertaling('550e8400-...', 'en', [ 'naam' => 'Parking permit', 'samenvatting' => 'Permit for parking in the city.', ]); // Partial translation update (PATCH) $vertaling = ProductTypen::patchVertaling('550e8400-...', 'en', ['naam' => 'Parking permit']); // Delete a translation ProductTypen::deleteVertaling('550e8400-...', 'en');
Valid values for doelgroep: burgers, bedrijven, burgers_en_bedrijven.
code must match the pattern ^[A-Z0-9-]+$.
Themas
Endpoint: producttypen/api/v1/themas
use Woweb\Openproduct\Api\Themas; $themas = Themas::list(); $thema = Themas::get('550e8400-...'); $thema = Themas::create(['naam' => 'Wonen & Leven', 'producttype_uuids' => []]); $thema = Themas::update('550e8400-...', ['naam' => 'Updated', 'producttype_uuids' => []]); $thema = Themas::patch('550e8400-...', ['naam' => 'Patched']); Themas::delete('550e8400-...');
Content
Endpoint: producttypen/api/v1/content
use Woweb\Openproduct\Api\Content; $content = Content::get('550e8400-...'); $content = Content::create(['content' => '<p>Beschrijving</p>', 'producttype_uuid' => '550e8400-...']); $content = Content::update('550e8400-...', ['content' => '<p>Updated</p>', 'producttype_uuid' => '550e8400-...']); $content = Content::patch('550e8400-...', ['content' => '<p>Patched</p>']); Content::delete('550e8400-...'); // Translations $vertaling = Content::updateVertaling('550e8400-...', 'en', ['content' => '<p>Description</p>']); Content::deleteVertaling('550e8400-...', 'en');
ContentLabels
Endpoint: producttypen/api/v1/contentlabels (read-only)
use Woweb\Openproduct\Api\ContentLabels; $labels = ContentLabels::list(['page' => 1]);
Prijzen
Endpoint: producttypen/api/v1/prijzen
use Woweb\Openproduct\Api\Prijzen; $prijzen = Prijzen::list(['producttype_uuid' => '550e8400-...']); $prijs = Prijzen::get('550e8400-...'); $prijs = Prijzen::create(['producttype_uuid' => '550e8400-...', 'actief_vanaf' => '2026-01-01']); $prijs = Prijzen::update('550e8400-...', ['producttype_uuid' => '550e8400-...', 'actief_vanaf' => '2026-01-01']); $prijs = Prijzen::patch('550e8400-...', ['actief_vanaf' => '2026-06-01']); Prijzen::delete('550e8400-...');
Schemas
Endpoint: producttypen/api/v1/schemas
Note: schemas use an integer $id, not a UUID.
use Woweb\Openproduct\Api\Schemas; $schemas = Schemas::list(); $schema = Schemas::get(42); $schema = Schemas::create(['naam' => 'Aanvraagschema', 'schema' => ['type' => 'object']]); $schema = Schemas::update(42, ['naam' => 'Updated', 'schema' => ['type' => 'object']]); $schema = Schemas::patch(42, ['naam' => 'Patched']); Schemas::delete(42);
Links
Endpoint: producttypen/api/v1/links
use Woweb\Openproduct\Api\Links; $links = Links::list(['producttype_uuid' => '550e8400-...']); $link = Links::get('550e8400-...'); $link = Links::create([ 'naam' => 'Meer informatie', 'url' => 'https://example.com/info', 'producttype_uuid' => '550e8400-...', ]); $link = Links::update('550e8400-...', ['naam' => 'Updated', 'url' => 'https://example.com', 'producttype_uuid' => '550e8400-...']); $link = Links::patch('550e8400-...', ['naam' => 'Patched']); Links::delete('550e8400-...');
Bestanden
Endpoint: producttypen/api/v1/bestanden
File uploads use multipart form data automatically.
use Woweb\Openproduct\Api\Bestanden; $bestanden = Bestanden::list(['producttype_uuid' => '550e8400-...']); $bestand = Bestanden::get('550e8400-...'); // Upload a file $bestand = Bestanden::create('/path/to/file.pdf', '550e8400-...'); // Replace a file (PUT) $bestand = Bestanden::update('550e8400-...', '/path/to/new-file.pdf', '550e8400-...'); // Partially update (PATCH, file and/or producttype_uuid optional) $bestand = Bestanden::patch('550e8400-...', '/path/to/file.pdf'); Bestanden::delete('550e8400-...');
Acties
Endpoint: producttypen/api/v1/acties
use Woweb\Openproduct\Api\Acties; $acties = Acties::list(['producttype_uuid' => '550e8400-...']); $actie = Acties::get('550e8400-...'); $actie = Acties::create([ 'naam' => 'Indienen aanvraag', 'tabel_endpoint' => 'https://beslistabellen.example.com/pt-001', 'dmn_tabel_id' => 'pt-001-aanvraag', 'producttype_uuid' => '550e8400-...', ]); $actie = Acties::update('550e8400-...', [...]); $actie = Acties::patch('550e8400-...', ['naam' => 'Patched']); Acties::delete('550e8400-...');
Locaties
Endpoint: producttypen/api/v1/locaties
use Woweb\Openproduct\Api\Locaties; $locaties = Locaties::list(['stad' => 'Nijmegen']); $locatie = Locaties::get('550e8400-...'); $locatie = Locaties::create([ 'naam' => 'Stadskantoor Nijmegen', 'straat' => 'Mariƫnburg', 'huisnummer' => '75', 'postcode' => '6511 PS', 'stad' => 'Nijmegen', ]); $locatie = Locaties::update('550e8400-...', [...]); $locatie = Locaties::patch('550e8400-...', ['stad' => 'Arnhem']); Locaties::delete('550e8400-...');
postcode must match the Dutch format ^[1-9][0-9]{3}\s?[A-Za-z]{2}$ (e.g. 6511 PS or 6511PS).
Organisaties
Endpoint: producttypen/api/v1/organisaties
use Woweb\Openproduct\Api\Organisaties; $organisaties = Organisaties::list(['naam' => 'Gemeente']); $organisatie = Organisaties::get('550e8400-...'); $organisatie = Organisaties::create(['naam' => 'Gemeente Nijmegen', 'code' => 'GEM-NIJMEGEN']); $organisatie = Organisaties::update('550e8400-...', ['naam' => 'Updated', 'code' => 'GEM-NMG']); $organisatie = Organisaties::patch('550e8400-...', ['naam' => 'Patched']); Organisaties::delete('550e8400-...');
Contacten
Endpoint: producttypen/api/v1/contacten
use Woweb\Openproduct\Api\Contacten; $contacten = Contacten::list(['naam' => 'Jan']); $contact = Contacten::get('550e8400-...'); $contact = Contacten::create([ 'naam' => 'Jan de Vries', 'email' => 'jan@example.com', // optional 'telefoonnummer' => '0612345678', // optional 'rol' => 'Contactpersoon', // optional 'organisatie_uuid' => '550e8400-...', // optional ]); $contact = Contacten::update('550e8400-...', ['naam' => 'Updated']); $contact = Contacten::patch('550e8400-...', ['email' => 'nieuw@example.com']); Contacten::delete('550e8400-...');
Testing
composer install vendor/bin/phpunit
License
EUPL-1.2. See LICENSE for details.