Wenn Sie WHMCS nutzen, verwenden Sie stattdessen das WHMCS-Modul – diese Seite ist für alles andere vorgesehen. Es gibt zwei Optionen, beide kostenlos und beide unter GPL-2.0-or-later.
HostBill
Ein Hosting-Modul mit denselben sechs Aktionen wie das für WHMCS.
- Laden Sie es herunter und entpacken Sie es.
- Laden Sie das Verzeichnis
zinn nach includes/modules/Hosting/ hoch, sodass die Dateien unter includes/modules/Hosting/zinn/class.zinn.php und includes/modules/Hosting/zinn/ZinnHostBillClient.php liegen.
- Einstellungen → Module → Hosting, aktivieren Sie Zinn Digital® und fügen Sie eine Verbindung hinzu:
- API-Adresse:
https://api.zinndigital.com
- API-Schlüssel: Ihr Zinn®-API-Schlüssel (ein
password-Feld, HostBill speichert ihn also verschlüsselt)
- Legen Sie beim Produkt Produktlinie (z. B.
mainstream), Stack (standardmäßig wordpress) und optional Anwendung sowie PHP-Version fest.
- Klicken Sie auf Verbindung testen.
⛔ Benennen Sie das Verzeichnis zinn nicht um. Der Loader von HostBill leitet die gesuchte Klasse vom Verzeichnisnamen ab; eine Umbenennung führt daher zu einem Modul, das im Panel aufgelistet, aber nie aufgerufen wird.
Alles andere – der PHP-Client
Eine Datei, keine Abhängigkeiten, keine Annahmen über das Panel. Fügen Sie ZinnProvisioning.php in Ihre eigene Codebasis ein und rufen Sie sechs Methoden auf.
require_once 'ZinnProvisioning.php';
$zinn = new ZinnProvisioning(getenv('ZINN_API_KEY'));
// When an order is paid — once per CUSTOMER, then once per SERVICE:
$orgId = $zinn->account('customer-4211', 'Acme Ltd');
$siteId = $zinn->provision('service-9915', $orgId, 'acme.com', 'mainstream', 'wordpress');
// Store $orgId against your customer and $siteId against your service.
$zinn->suspend($siteId, 'INV-2026-114 unpaid'); // an invoice goes unpaid
$zinn->unsuspend($siteId); // they pay
$zinn->terminate($siteId); // they cancel — schedules a deletion
// When they click "log in to my hosting" — mint it on the CLICK, never on page render:
header('Location: ' . $zinn->signInLink($siteId));
Sie schreiben kein PHP? Dieselben Aufrufe finden Sie in der API-Referenz und Sie können sie von überall aus durchführen.
Der API-Schlüssel
Sieben Berechtigungen, und nicht mehr: org.create, org.read, sites.create, sites.view, sites.delete, reseller.view, reseller.provision.
⛔ Nicht reseller.manage. Ein Schlüssel, den Sie in ein Abrechnungspanel einfügen, sollte in der Lage sein, einen Kunden wegen Nichtzahlung zu sperren und ihn anzumelden; er sollte nicht in der Lage sein, die Anmeldedaten Ihres eigenen Zahlungsgateways zu überschreiben.
Die zwei Regeln, deren Missachtung Geld kostet
- Binden Sie das Konto an Ihren KUNDEN und die Website an Ihren SERVICE. Die zweite Bestellung eines Kunden muss in dem Konto landen, das er bereits hat. Binden Sie beides an den Service, hat ein Kunde am Ende drei nicht miteinander verbundene Konten und drei separate Control-Panels.
- Senden Sie bei jeder Erstellung einen Idempotenz-Schlüssel, der von Ihrer eigenen ID für das Objekt abgeleitet ist. Jedes Abrechnungssystem führt Wiederholungsversuche durch – ein Gateway-Callback trifft zweimal ein, ein Administrator führt eine fehlgeschlagene Bereitstellung erneut aus, ein Kunde klickt doppelt. Ohne diesen Schlüssel erstellt der zweite Versuch eine zweite Website und diese wird Ihnen in Rechnung gestellt. Beide Module und der PHP-Client erledigen dies für Sie; wenn Sie die API direkt aufrufen, senden Sie
Idempotency-Key.
Drei Felder, die man leicht vergisst
Jedes davon setzt ein ganzes Verb außer Kraft, und keines wird anders als durch einen Validierungsfehler angezeigt – mit Ausnahme des ersten, das sich als überhaupt nichts bemerkbar macht:
- ⛔⛔ Ein Client muss einem Tarif zugewiesen werden, BEVOR seine erste Website bereitgestellt wird, und zwar mit
POST /v1/reseller/clients/{orgId}/plan, wobei dessen subscription_id an POST /v1/sites übergeben wird. Dies ist der Fall, bei dem kein Fehler zu lesen ist. Ein neues Client-Konto enthält kein Abonnement und POST /v1/sites verfügt über kein Tarif-Feld, sodass eine ohne Tarif bereitgestellte Website überhaupt keinen Tarif hat: Ihre Großhandelsabrechnung wird aus den aktiven Abonnements Ihrer Clients erstellt, sodass kein Posten aufgeführt wird und Zinn® Ihnen nichts in Rechnung stellt, solange das Hosting läuft; Ihr Client erbt keine Kontingente, sodass für seine Website keine Quote gilt; und es gibt nichts, was ein Upgrade ändern könnte. Die Bestellung gibt 201 zurück, die Website wird bereitgestellt und funktioniert einwandfrei. Keine der beiden Seiten meldet irgendetwas davon.
Die Reihenfolge ist wichtig: POST /v1/sites erfasst das Abonnement, das im Moment der Ausführung vorhanden ist, sodass ein nachträglich festgelegter Tarif nicht rückwirkend zugewiesen wird.
POST /v1/sites erfordert stack_type. Wenn Sie dies weglassen, kann keine Bestellung erfolgreich sein.
DELETE /v1/sites/{siteId} erfordert einen Body {"confirm_domain": "<the site's own domain>"} — eine getippte Bestätigung, da dies das destruktive Verb ist. Wenn Sie dies weglassen, kann keine Kündigung erfolgreich sein, sodass der Dienst weiterläuft und Ihnen weiterhin in Rechnung gestellt wird. Lesen Sie die Domain aus GET /v1/reseller/services/{siteId} aus, anstatt Ihren eigenen Datensatz zu verwenden: Sie wird mit der primären Domain der Website selbst abgeglichen und niemals mit einem Alias.
Lesen Sie die gesamte Fehlermeldung, nicht nur den Satz
Die Meldung einer Validierungsablehnung ist bewusst allgemein gehalten — „The request was well-formed but failed validation.“ —, da der handlungsrelevante Teil in details enthalten ist, wo das Feld und der Grund genannt werden. Sowohl Module als auch der PHP-Client hängen dies an die Meldung an, die sie Ihrem Administrator anzeigen. Wenn Sie die API selbst aufrufen, lesen Sie error.details; einige Einträge enthalten einen reinen Wert anstelle eines Satzes, wodurch Sie max_sites: 0 erhalten, wenn Ihr Reseller-Tarif keinen Platz mehr bietet.
Vor Ihrer ersten Bestellung
Websites, die Ihre Clients kaufen, werden auf das Website-Kontingent Ihres Reseller-Tarifs angerechnet, daher benötigen Sie einen Tarif mit freiem Platz. Ein Verbindungstest kann dies nicht erkennen — er liest Ihr Programm und stellt nichts bereit —, sodass er ein fehlerfreies Konto meldet, das jedoch noch nicht verkaufen kann. Eine Bestellung, die ohne verfügbares Kontingent aufgegeben wird, wird mit einer Meldung abgelehnt, die genau dies besagt.
Überprüfen Sie Ihren Download
Beide Archive werden über TLS von unserem eigenen Hostnamen bereitgestellt, niemals an andere Stellen umgeleitet, und ihre SHA-256-Prüfsummen sind neben den Download-Links auf der downloads page abgedruckt.