Skip to content

REST API

RouteMethodAuthHandlerBestand
/wp-json/acs/v1/jobs/createPOSTGeenacs_job_api_createapi-job.php
/wp-json/acs/v1/contactsGETGeenacs_contacts_listapi-contact.php
/wp-json/acs/v1/contacts/{id}GETGeenacs_contacts_getapi-contact.php
/wp-json/acs/v1/contacts/upsertPOSTGeenacs_contacts_upsertapi-contact.php
/wp-json/acs/v1/filesGETGeenacs_files_listapi-file.php
/wp-json/acs/v1/files/{id}GETGeenacs_files_getapi-file.php

Alle endpoints hebben permission_callback => return true. Er is GEEN authenticatie. Zie Security Audit.

api-job.php
register_rest_route('acs/v1', '/jobs/create', [
'methods' => 'POST',
'callback' => 'acs_job_api_create',
'permission_callback' => 'acs_job_api_permission', // return true
]);
// api-contact.php
register_rest_route('acs/v1', '/contacts', [
'methods' => 'GET',
'callback' => 'acs_contacts_list',
'permission_callback' => 'acs_permission_contacts', // return true
]);
register_rest_route('acs/v1', '/contacts/(?P<id>\d+)', [
'methods' => 'GET',
'callback' => 'acs_contacts_single',
'permission_callback' => 'acs_permission_contacts',
]);
register_rest_route('acs/v1', '/contacts/upsert', [
'methods' => 'POST',
'callback' => 'acs_contacts_upsert',
'permission_callback' => 'acs_permission_contacts',
]);

Alle contact endpoints gebruiken deze mapping:

function acs_acf_field_map(): array {
return [
'type' => 'contact-type',
'firstname' => 'contact-firstname',
'lastname' => 'contact-lastname',
'company' => 'contact-company',
'email' => 'contact-email',
'phone' => 'contact-phone',
'zipcode' => 'contact-zipcode',
'streetname' => 'contact-streetname',
'number' => 'contact-number',
'addition' => 'contact-addition',
'city' => 'contact-city',
'note' => 'contact-note',
'moneybird_id' => 'moneybird_id',
];
}
function acs_job_api_normalize_zipcode(string $zipcode): string {
$z = strtoupper(str_replace(' ', '', trim($zipcode)));
if (preg_match('/^(\d{4})([A-Z]{2})$/', $z, $m)) {
return $m[1] . ' ' . $m[2]; // "3029 AK" (met spatie)
}
return strtoupper($zipcode);
}
function acs_job_api_zip_compact(string $zipcode): string {
return strtoupper(str_replace(' ', '', trim($zipcode))); // "3029AK" (zonder)
}
ParameterTypeVerplichtBeschrijving
moneybird_idstringNeeMoneybird contact ID
zipcodestringNeePostcode
numberstringNeeHuisnummer
additionstringNeeToevoeging
emailstringNeeEmail
companystringNeeBedrijfsnaam
firstnamestringNeeVoornaam
lastnamestringNeeAchternaam
phonestringNeeTelefoon
typestringNeemaasdelta, particulier, zakelijk
statusstringNee0, 1, 2 (default: 0)
datestringNeePlanningsdatum (Ymd)
streetnamestringNeeStraatnaam
citystringNeeStad
descriptionstringNeeBeschrijving
notestringNeeNotitie
employerstring/arrayNeeMonteur user ID(s)
Prioriteit 4: moneybird_id match → found_by: "moneybird_id"
Prioriteit 3: postcode + huisnr + toevoeging + email → found_by: "address_email"
Prioriteit 2: postcode + huisnr + toevoeging → found_by: "address"
Prioriteit 1: email → found_by: "email"
Geen match ��� acs_job_api_create_contact() → found_by: "created"

acs_job_api_lookup_address() zoekt in wp_werkbon_addresses:

  • Gevonden → overschrijft streetname + city met database waarden
  • is_maasdelta → forceert contact-type naar ‘maasdelta’
{
"success": true,
"job_id": 1234,
"contact_id": 567,
"contact_created": false,
"found_by": "address_email",
"address_normalized": true,
"is_maasdelta": false
}
ParameterTypeDefaultBeschrijving
pageint1Pagina
per_pageint50Items per pagina
searchstring""Zoekterm (post title)
{
"items": [
{
"id": 567,
"title": "Jan de Vries",
"company": "Loodgieter BV",
"firstname": "Jan",
"lastname": "de Vries",
"email": "jan@example.nl",
"phone": "+31612345678",
"streetname": "Hoofdstraat",
"number": "42",
"addition": "a",
"zipcode": "1234AB",
"city": "Rotterdam",
"type": "zakelijk",
"moneybird_id": "123456789"
}
],
"totalPages": 5,
"total": 243
}

Enkel contact met alle velden. Zelfde structuur als items hierboven.

ParameterTypeVerplicht
moneybird_idstringJa (match key)
company, firstname, lastname, email, phonestringNee
zipcode, streetname, number, addition, citystringNee
  1. Zoek contact met moneybird_id
  2. Gevonden �� update ingevulde velden
  3. Niet gevonden → nieuw contact
  4. Trigger acf/save_post → webhook

Zelfde paginatie als contacts. Response bevat alle file ACF velden.

Enkel werkbon inclusief invoice details.

acs_file_build_details_attributes($file_id):

{
"details_attributes": [
{"description": "Riool ontstopt - Keuken, Badkamer (05-04-2026)", "amount": "1"},
{"description": "PVC Buis 110mm", "amount": "2"}
]
}

Moneybird-compatibel. Zie Integraties.

Terminal window
curl -s 'https://werkbon.nl/wp-json/acs/v1/contacts?per_page=10&search=jan' | jq
Terminal window
curl -X POST 'https://werkbon.nl/wp-json/acs/v1/jobs/create' \
-H 'Content-Type: application/json' \
-d '{
"moneybird_id": "123456789",
"zipcode": "3029AK",
"number": "42",
"firstname": "Jan",
"lastname": "de Vries",
"email": "jan@example.nl",
"description": "Lekkage in badkamer",
"status": "0"
}'
Terminal window
curl -X POST 'https://werkbon.nl/wp-json/acs/v1/contacts/upsert' \
-H 'Content-Type: application/json' \
-d '{
"moneybird_id": "123456789",
"company": "Loodgieter BV",
"email": "info@loodgieter.nl"
}'
StatusWanneerResponse
200Succes{"success": true, ...}
400Ongeldige parameters{"code": "rest_invalid_param", ...}
404Contact/file niet gevonden{"code": "rest_no_route", ...}
500Interne fout{"success": false, "error": "..."}

Let op: door de open permission_callback is er geen 401/403 response mogelijk.

In de nieuwe Beam stack worden deze endpoints vervangen door een Hono API op Cloudflare Workers met Supabase als database. Alle endpoints krijgen authenticatie via Bearer token. Zie Migratie naar Beam Stack.

BestandLocatieFunctie
api-job.phpfunctions/POST /jobs/create + contact lookup
api-contact.phpfunctions/GET/POST contacts + webhook
api-file.phpfunctions/GET files + webhook
db-addresses.phpfunctions/Address lookup voor normalisatie