Anmeldedaten von Kunde für Bexio & Developer Bexio Portal
Bexio API Token: https://developer.bexio.com/
Personal Access Token setzen
– Website Formular
– Company Eingeben und Token rauskopieren.
– Wichtig! Expires notieren!
Datei in wp-content speichern. Es geht nicht via Plugin, oder nur sehr mühsam.
/wp-content/bexio-webhook.php
PHP
<?php
// Verhindert direkten Zugriff ohne POST-Daten
if ($_SERVER['REQUEST_METHOD'] !== 'POST') {
http_response_code(405);
die('Method Not Allowed');
}
/**
* Bexio Contact Handler - Mit Smart Update
* Leere Felder überschreiben vorhandene Werte NICHT
*/
// === KONFIGURATION ===
define('BEXIO_TOKEN', 'BEXIO_API_TOKEN');
define('BEXIO_API_BASE', 'https://api.bexio.com/2.0');
define('BEXIO_USER_ID', 2);
define('BEXIO_OWNER_ID', 2);
define('BEXIO_COUNTRY_ID', 1);
// === BEXIO API REQUEST ===
function bexioRequest($url, $method = 'POST', $data = null) {
$ch = curl_init($url);
curl_setopt_array($ch, [
CURLOPT_RETURNTRANSFER => true,
CURLOPT_CUSTOMREQUEST => $method,
CURLOPT_HTTPHEADER => [
'Authorization: Bearer ' . BEXIO_TOKEN,
'Accept: application/json',
'Content-Type: application/json'
]
]);
if ($data !== null) {
curl_setopt($ch, CURLOPT_POSTFIELDS, json_encode($data));
}
$response = curl_exec($ch);
$httpCode = curl_getinfo($ch, CURLINFO_HTTP_CODE);
$error = curl_error($ch);
curl_close($ch);
if ($error) {
throw new Exception("cURL Error: $error");
}
return [
'code' => $httpCode,
'body' => json_decode($response, true)
];
}
// === HELPER FUNCTIONS ===
function cleanString($value) {
if ($value === null) {
return '';
}
return trim((string)$value);
}
function hasValue($value) {
$cleaned = cleanString($value);
return !empty($cleaned);
}
// === SMART MERGE ===
function smartMerge($newData, $existingData) {
$merged = $newData;
$smartFields = [
'phone_mobile',
'phone_fixed',
'street_name',
'house_number',
'address_addition',
'postcode',
'city',
'mail_second'
];
foreach ($smartFields as $field) {
if (!hasValue($merged[$field] ?? '') && hasValue($existingData[$field] ?? '')) {
$merged[$field] = $existingData[$field];
}
}
return $merged;
}
// === PRÜFE OB ZUSATZADRESSE SCHON EXISTIERT ===
function isAdditionalAddressDuplicate($existingAddresses, $name, $street, $houseNumber, $postcode, $city) {
if (empty($existingAddresses)) {
return false;
}
foreach ($existingAddresses as $addr) {
$nameMatch = strtolower(trim($addr['name'] ?? '')) === strtolower(trim($name));
$streetMatch = strtolower(trim($addr['street_name'] ?? '')) === strtolower(trim($street));
$houseMatch = trim($addr['house_number'] ?? '') === trim($houseNumber);
$postcodeMatch = trim($addr['postcode'] ?? '') === trim($postcode);
$cityMatch = strtolower(trim($addr['city'] ?? '')) === strtolower(trim($city));
if ($nameMatch && $streetMatch && $houseMatch && $postcodeMatch && $cityMatch) {
return true;
}
}
return false;
}
// === HAUPTLOGIK ===
try {
header('Content-Type: application/json');
$rawInput = file_get_contents('php://input');
if (empty($rawInput)) {
throw new Exception('Keine Daten empfangen');
}
$formData = json_decode($rawInput, true);
if (!$formData) {
throw new Exception('JSON-Decode Fehler: ' . json_last_error_msg());
}
// === VALIDIERUNG ===
if (!isset($formData['rechnung_typ'])) {
throw new Exception('Feld "rechnung_typ" fehlt');
}
if (!hasValue($formData['mail'] ?? '')) {
throw new Exception('E-Mail-Adresse ist erforderlich');
}
$rechnungsTyp = cleanString($formData['rechnung_typ']);
$email = cleanString($formData['mail']);
$emailSecond = cleanString($formData['mail_second'] ?? '');
// === KONTAKTDATEN VORBEREITEN (RECHNUNGSADRESSE) ===
if ($rechnungsTyp === 'Firma') {
$firmenname = cleanString($formData['firma_name'] ?? '');
$firmennameZusatz = cleanString($formData['firma_name_zusatz'] ?? '');
if (!hasValue($firmenname)) {
throw new Exception('Firmenname ist erforderlich bei Firmen');
}
$contactData = [
'contact_type_id' => 1,
'name_1' => $firmenname,
'name_2' => hasValue($firmennameZusatz) ? $firmennameZusatz : null,
'street_name' => cleanString($formData['street_name'] ?? ''),
'house_number' => cleanString($formData['house_number'] ?? ''),
'address_addition' => hasValue($formData['address_addition'] ?? '') ? cleanString($formData['address_addition']) : null,
'postcode' => cleanString($formData['postcode'] ?? ''),
'city' => cleanString($formData['city'] ?? ''),
'mail' => $email,
'mail_second' => hasValue($emailSecond) ? $emailSecond : '',
'phone_fixed' => cleanString($formData['phone_mobile'] ?? ''),
'phone_mobile' => '',
'country_id' => BEXIO_COUNTRY_ID,
'user_id' => BEXIO_USER_ID,
'owner_id' => BEXIO_OWNER_ID
];
} else {
$vorname = cleanString($formData['name_2'] ?? '');
$nachname = cleanString($formData['name_1'] ?? '');
if (!hasValue($vorname) || !hasValue($nachname)) {
throw new Exception('Vor- und Nachname sind erforderlich bei Privatpersonen');
}
$contactData = [
'contact_type_id' => 2,
'name_1' => $nachname,
'name_2' => $vorname,
'street_name' => cleanString($formData['street_name'] ?? ''),
'house_number' => cleanString($formData['house_number'] ?? ''),
'address_addition' => hasValue($formData['address_addition'] ?? '') ? cleanString($formData['address_addition']) : null,
'postcode' => cleanString($formData['postcode'] ?? ''),
'city' => cleanString($formData['city'] ?? ''),
'mail' => $email,
'mail_second' => hasValue($emailSecond) ? $emailSecond : '',
'phone_mobile' => cleanString($formData['phone_mobile'] ?? ''),
'phone_fixed' => '',
'country_id' => BEXIO_COUNTRY_ID,
'user_id' => BEXIO_USER_ID,
'owner_id' => BEXIO_OWNER_ID
];
}
// === DUPLIKAT-CHECK FÜR RECHNUNGSKONTAKT ===
$searchResult = bexioRequest(
BEXIO_API_BASE . '/contact/search',
'POST',
[[
'field' => 'mail',
'value' => $email,
'criteria' => '='
]]
);
$contactId = null;
// === KONTAKT ERSTELLEN ODER AKTUALISIEREN ===
if (!empty($searchResult['body']) && is_array($searchResult['body'])) {
$contactId = $searchResult['body'][0]['id'];
$existingContact = bexioRequest(
BEXIO_API_BASE . "/contact/$contactId",
'GET'
);
$contactData = smartMerge($contactData, $existingContact['body']);
$result = bexioRequest(
BEXIO_API_BASE . "/contact/$contactId",
'POST',
$contactData
);
} else {
$result = bexioRequest(
BEXIO_API_BASE . '/contact',
'POST',
$contactData
);
$contactId = $result['body']['id'] ?? null;
}
// === STANDORTADRESSE ALS ADDITIONAL ADDRESS HINZUFÜGEN ===
if ($contactId) {
$standortVorname = cleanString($formData['vorname_standort'] ?? '');
$standortNachname = cleanString($formData['nachname_standort'] ?? '');
$standortName = trim($standortVorname . ' ' . $standortNachname);
$standortStrasse = cleanString($formData['strasse_standort'] ?? '');
$standortHausnummer = cleanString($formData['hausnummer_standort'] ?? '');
$standortAdresszusatz = cleanString($formData['adresszusatz_standort'] ?? '');
$standortPLZ = cleanString($formData['plz_standort'] ?? '');
$standortOrt = cleanString($formData['ort_standort'] ?? '');
$standortTelefon = cleanString($formData['telefon_standort'] ?? '');
$standortEmail = cleanString($formData['mail_standort'] ?? '');
if (hasValue($standortName) && hasValue($standortStrasse) && hasValue($standortPLZ)) {
$existingAddresses = bexioRequest(
BEXIO_API_BASE . "/contact/$contactId/additional_address",
'GET'
);
$isDuplicate = isAdditionalAddressDuplicate(
$existingAddresses['body'] ?? [],
$standortName,
$standortStrasse,
$standortHausnummer,
$standortPLZ,
$standortOrt
);
$addressCount = count($existingAddresses['body'] ?? []);
if (!$isDuplicate && $addressCount < 17) {
// Nur E-Mail in Beschreibung (oder leer lassen wenn keine E-Mail)
$description = hasValue($standortEmail) ? $standortEmail : '';
$additionalAddressData = [
'name' => $standortName,
'name_addition' => hasValue($standortTelefon) ? $standortTelefon : null,
'street_name' => $standortStrasse,
'house_number' => $standortHausnummer,
'address_addition' => hasValue($standortAdresszusatz) ? $standortAdresszusatz : null,
'postcode' => $standortPLZ,
'city' => $standortOrt,
'country_id' => BEXIO_COUNTRY_ID,
'subject' => $standortName,
'description' => $description
];
bexioRequest(
BEXIO_API_BASE . "/contact/$contactId/additional_address",
'POST',
$additionalAddressData
);
}
}
}
// === ERFOLG ===
http_response_code($result['code']);
echo json_encode($result['body']);
} catch (Exception $e) {
http_response_code(500);
echo json_encode([
'error' => true,
'message' => $e->getMessage()
]);
}
?>