Base de connaissances

Vendez l'hébergement Zinn® depuis HostBill, Blesta ou votre propre système

Vendez l'hébergement Zinn via HostBill, Blesta ou votre propre système : le module HostBill gratuit, le client PHP à fichier unique, les deux règles qui coûtent cher lorsqu'elles sont enfreintes, et les deux champs de requête qu'il est facile d'oublier.

Si vous utilisez WHMCS, utilisez le module WHMCS à la place — cette page traite de tout le reste. Il existe deux options, toutes deux gratuites et sous licence GPL-2.0-or-later.

HostBill

Un module d'hébergement doté des six mêmes actions que celui de WHMCS.

  1. Téléchargez-le et décompressez-le.
  2. Téléchargez le répertoire zinn dans includes/modules/Hosting/ afin que les fichiers se trouvent dans
  3. includes/modules/Hosting/zinn/class.zinn.php et includes/modules/Hosting/zinn/ZinnHostBillClient.php.

  4. Settings → Modules → Hosting, activez Zinn Digital®, et ajoutez une connexion :
  • API address : https://api.zinndigital.com
  • API key : votre clé d'API Zinn® (un champ password, afin que HostBill la stocke de manière chiffrée)
  1. Sur le produit, définissez la Product line (par ex. mainstream), le Stack (wordpress par
  2. défaut), et éventuellement l'Application et la PHP version.

  3. Appuyez sur Test connection.

Ne renommez pas le répertoire zinn. Le chargeur de HostBill déduit la classe qu'il recherche à partir du nom du répertoire, de sorte qu'un renommage produit un module que le panneau liste mais n'appelle jamais.

Tout le reste — le client PHP

Un fichier, aucune dépendance, aucune hypothèse sur le panneau. Placez ZinnProvisioning.php dans votre propre code source et appelez six méthodes.

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));

Vous n'écrivez pas en PHP ? Les mêmes appels se trouvent dans la référence de l'API et vous pouvez les effectuer depuis n'importe quoi.

La clé d'API

Sept autorisations, et pas une de plus : org.create, org.read, sites.create, sites.view, sites.delete, reseller.view, reseller.provision.

Pas reseller.manage. Une clé que vous collez dans un panneau de facturation doit être capable de suspendre un client pour non-paiement et de le connecter ; elle ne doit pas être capable de réécrire vos propres identifiants de passerelle de paiement.

Les deux règles qui coûtent de l'argent lorsqu'elles sont enfreintes

  1. Associez le compte à votre CLIENT, et le site à votre SERVICE. Le deuxième
  2. commande d'un client doit aboutir dans le compte qu'il possède déjà. Associez les deux au service et un client se retrouve avec trois comptes sans lien entre eux et trois panneaux de contrôle séparés.

  3. Envoyez une clé d'idempotence à chaque création, dérivée de votre propre identifiant pour l'élément. Chaque
  4. système de facturation réessaie — le retour d'une passerelle arrive deux fois, un administrateur relance une provision échouée, un client clique deux fois. Sans cela, la deuxième tentative crée un deuxième site et vous êtes facturé pour celui-ci. Les modules et le client PHP font cela pour vous ; si vous appelez l'API directement, envoyez Idempotency-Key.

Trois champs qu'il est facile d'omettre

Chacun d'eux rompt un verbe entier, et aucun n'apparaît autrement que comme une erreur de validation — à l'exception du premier, qui apparaît comme rien du tout :

  • ⛔⛔ Un client doit être rattaché à un forfait AVANT que son premier site ne soit provisionné, avec
  • POST /v1/reseller/clients/{orgId}/plan, et son subscription_id transmis à POST /v1/sites. C'est celui qui ne présente aucune erreur à lire. Un nouveau compte client ne contient aucun abonnement et POST /v1/sites n'a pas de champ de forfait, de sorte qu'un site provisionné sans forfait ne comporte aucun forfait du tout : votre relevé de gros est établi à partir des abonnements actifs de vos clients, aucune ligne n'est donc générée et Zinn® ne vous facture rien tant que l'hébergement fonctionne ; votre client ne bénéficie d'aucune allocation, aucun quota n'est donc appliqué à son site ; et il n'y a rien à modifier lors d'une mise à niveau. La commande renvoie 201, le site est provisionné, et il fonctionne parfaitement. Rien de part et d'autre ne signale quoi que ce soit de tout cela.

L'ordre a de l'importance : POST /v1/sites enregistre l'abonnement présent au moment où il s'exécute, de sorte qu'un forfait défini après coup ne s'applique pas de manière rétrospective.

  • POST /v1/sites requiert stack_type. Omettez-le et aucune commande ne pourra aboutir.
  • **DELETE /v1/sites/{siteId} requiert un corps `{"confirm_domain": "<the site's own
  • domain>"}** — une confirmation saisie, car il s'agit du verbe destructeur. Omettez-la et aucune annulation ne pourra aboutir, de sorte que le service continue de fonctionner et que vous continuez d'être facturé pour cela. Lisez le domaine à partir de GET /v1/reseller/services/{siteId}` plutôt que d'utiliser votre propre enregistrement : il est comparé au domaine principal du site lui-même et jamais à un alias.

Lire l'erreur en entier, pas seulement la phrase

Le message de refus de validation est délibérément générique — "The request was well-formed but failed validation." — parce que la moitié exploitable se trouve dans details, qui nomme le champ et explique pourquoi. Les modules et le client PHP l'ajoutent tous deux au message qu'ils affichent à votre administrateur. Si vous appelez l'API vous-même, lisez error.details ; certaines entrées comportent une valeur brute plutôt qu'une phrase, ce qui explique comment max_sites: 0 vous parvient lorsque votre forfait revendeur n'a plus de place.

Avant votre première commande

Les sites achetés par vos clients sont décomptés de l'allocation de sites de votre propre forfait revendeur, vous avez donc besoin d'un forfait disposant de l'espace nécessaire. Un test de connexion ne peut pas détecter cela — il lit votre programme et ne provisionne rien — il signale donc un compte sain mais qui ne peut pas encore vendre. Une commande passée sans allocation est refusée avec un message explicitement formulé en ce sens.

Vérifiez votre téléchargement

Les deux archives sont servies via TLS depuis notre propre nom d'hôte, jamais redirigées ailleurs, avec leurs sommes de contrôle SHA-256 affichées à côté des liens de téléchargement sur la page des téléchargements.

Toujours bloqué ?

Le support est inclus dans chaque forfait et les réponses sont rédigées dans votre propre langue.

Contacter le support Tous les articles
Vendez l'hébergement Zinn® depuis HostBill, Blesta ou votre propre système