Als u WHMCS gebruikt, gebruik dan in plaats daarvan de WHMCS-module — deze pagina is voor al het andere. Er zijn twee opties, beide gratis en beide GPL-2.0-or-later.
HostBill
Een hostingmodule met dezelfde zes acties als die voor WHMCS.
- Download deze en pak het bestand uit.
- Upload de map
zinn naar includes/modules/Hosting/ zodat de bestanden terechtkomen op includes/modules/Hosting/zinn/class.zinn.php en includes/modules/Hosting/zinn/ZinnHostBillClient.php.
- Instellingen → Modules → Hosting, activeer Zinn Digital® en voeg een verbinding toe:
- API-adres:
https://api.zinndigital.com
- API-sleutel: uw Zinn® API-sleutel (een
password-veld, dus HostBill slaat deze versleuteld op)
- Stel op het product Productlijn in (bijv.
mainstream), Stack (standaard wordpress), en optioneel Applicatie en PHP-versie.
- Druk op Verbinding testen.
⛔ Hernoem de map zinn niet. De loader van HostBill leidt de klasse die hij zoekt af van de mapnaam; hernoemen levert dus een module op die het paneel wel vermeldt, maar nooit aanroept.
Al het andere — de PHP-client
Eén bestand, geen afhankelijkheden, geen aannames over het paneel. Plaats ZinnProvisioning.php in uw eigen codebase en roep zes methoden aan.
require_once 'ZinnProvisioning.php';
$zinn = new ZinnProvisioning(getenv('ZINN_API_KEY'));
// Wanneer een bestelling is betaald — eenmaal per KLANT, daarna eenmaal per DIENST:
$orgId = $zinn->account('customer-4211', 'Acme Ltd');
$siteId = $zinn->provision('service-9915', $orgId, 'acme.com', 'mainstream', 'wordpress');
// Sla $orgId op bij uw klant en $siteId bij uw dienst.
$zinn->suspend($siteId, 'INV-2026-114 unpaid'); // een factuur blijft onbetaald
$zinn->unsuspend($siteId); // ze betalen
$zinn->terminate($siteId); // ze annuleren — plant een verwijdering in
// Wanneer ze klikken op "inloggen op mijn hosting" — genereer deze bij de KLIK, nooit bij het renderen van de pagina:
header('Location: ' . $zinn->signInLink($siteId));
Schrijft u geen PHP? Dezelfde aanroepen staan in de API-referentie en u kunt ze vanuit elke taal uitvoeren.
De API-sleutel
Zeven permissies, en niet meer: org.create, org.read, sites.create, sites.view, sites.delete, reseller.view, reseller.provision.
⛔ Niet reseller.manage. Een sleutel die u in een facturatiepaneel plakt, moet een klant kunnen blokkeren wegens wanbetaling en hen kunnen inloggen; deze mag niet uw eigen inloggegevens voor de betalingsgateway kunnen overschrijven.
De twee regels die geld kosten wanneer ze worden overtreden
- Koppel het account aan uw KLANT en de site aan uw DIENST. Een tweede bestelling van een klant moet terechtkomen in het account dat deze al heeft. Koppel ze allebei aan de dienst en één klant eindigt met drie niet-gerelateerde accounts en drie afzonderlijke controlepanelen.
- Stuur bij elke aanmaakopdracht een idempotentiesleutel mee, afgeleid van uw eigen id voor het item. Elk facturatiesysteem probeert het opnieuw — een callback van de gateway komt twee keer binnen, een beheerder voert een mislukte provisioning opnieuw uit, een klant dubbelklikt. Zonder deze sleutel maakt de tweede poging een tweede site aan en wordt deze aan u gefactureerd. Zowel de modules als de PHP-client regelen dit voor u; als u de API rechtstreeks aanroept, verstuur dan
Idempotency-Key.
Drie velden die gemakkelijk worden weggelaten
Elk veld breekt een heel werkwoord, en geen ervan verschijnt als iets anders dan een validatiefout — behalve de eerste, die als helemaal niets verschijnt:
- ⛔⛔ Een klant moet op een plan worden gezet VOORDAT de eerste site wordt geprovisioneerd, met
POST /v1/reseller/clients/{orgId}/plan, en de subscription_id daarvan moet worden doorgegeven aan POST /v1/sites. Dit is het geval waarbij er geen foutmelding te lezen is. Een nieuw klantaccount bevat geen abonnement en POST /v1/sites heeft geen planveld, dus een site die zonder plan wordt geprovisioneerd heeft helemaal geen plan: uw groothandelsafrekening wordt opgebouwd uit de actieve abonnementen van uw klanten, dus er wordt geen regel opgenomen en Zinn® factureert u niets zolang de hosting draait; uw klant erft geen toewijzingen, dus er wordt geen quotum toegepast op de site; en er is niets dat een upgrade kan wijzigen. De order retourneert 201, de site wordt geprovisioneerd en deze functioneert perfect. Niets aan beide kanten rapporteert hiervan iets.
De volgorde is van belang: POST /v1/sites registreert het abonnement dat op het moment van uitvoering bestaat, dus een later ingesteld plan wordt niet met terugwerkende kracht gekoppeld.
POST /v1/sites vereist stack_type. Laat u het weg, dan kan geen order slagen.
- **
DELETE /v1/sites/{siteId} vereist een body `{"confirm_domain": "<the site's own
domain>"}** — een getypte bevestiging, omdat dit het destructieve werkwoord is. Laat u het weg, dan kan geen annulering slagen, dus de dienst blijft draaien en u blijft ervoor gefactureerd. Lees het domein terug uit GET /v1/reseller/services/{siteId}` in plaats van uw eigen record te gebruiken: het wordt vergeleken met het eigen primaire domein van de site en nooit met een alias.
Lees de hele foutmelding, niet alleen de zin
Het bericht van een validatieweigering is bewust algemeen — "The request was well-formed but failed validation." — omdat het bruikbare deel in details staat, dat het veld en de reden noemt. Zowel de modules als de PHP-client voegen het toe aan het bericht dat ze aan uw beheerder tonen. Als u de API zelf aanroept, lees dan error.details; sommige vermeldingen bevatten een kale waarde in plaats van een zin, zo bereikt max_sites: 0 u wanneer uw resellerplan geen ruimte heeft.
Voor uw eerste order
Sites die uw klanten kopen, tellen mee voor de sitelimiet van uw resellerplan, dus u hebt een plan nodig met ruimte. Een verbindingstest kan dit niet detecteren — deze leest uw programma en provisioneert niets — dus deze meldt een gezond account dat nog niet kan verkopen. Een order die zonder toewijzing wordt geplaatst, wordt geweigerd met een bericht dat precies dat zegt.
Controleer uw download
Beide archieven worden via TLS vanaf onze eigen hostnaam aangeboden, nooit elders naartoe omgeleid, met hun SHA-256-controlesommen vermeld naast de downloadlinks op de downloadpagina.