База знаний

Продавайте хостинг Zinn® через HostBill, Blesta или собственную систему

Продавайте хостинг Zinn® через HostBill, Blesta или собственную систему: бесплатный модуль HostBill, однофайловый клиент PHP, два правила, нарушение которых стоит денег, и два поля запроса, которые легко упустить из виду.

Если вы используете WHMCS, используйте вместо этого модуль WHMCS — эта страница предназначена для всего остального. Доступны два варианта, оба бесплатные и под лицензией GPL-2.0-or-later.

HostBill

Модуль хостинга с теми же шестью действиями, что и модуль для WHMCS.

  1. Скачайте его и распакуйте архив.
  2. Загрузите каталог zinn в includes/modules/Hosting/, чтобы файлы оказались по путям includes/modules/Hosting/zinn/class.zinn.php и includes/modules/Hosting/zinn/ZinnHostBillClient.php.
  3. Settings → Modules → Hosting, активируйте Zinn Digital® и добавьте подключение:
  • API address: https://api.zinndigital.com
  • API key: ваш API-ключ Zinn® (поле типа password, поэтому HostBill сохраняет его в зашифрованном виде)
  1. В настройках продукта укажите Product line (например, mainstream), Stack (по умолчанию wordpress) и, при необходимости, Application и PHP version.
  2. Нажмите Test connection.

⛔ Не переименовывайте каталог zinn. Загрузчик HostBill определяет искомый класс на основе имени каталога, поэтому переименование приведет к тому, что модуль будет отображаться в панели, но никогда не будет вызываться.

Все остальное — клиент PHP

Один файл, никаких зависимостей, никаких привязок к панели. Поместите ZinnProvisioning.php в свою кодовую базу и вызывайте шесть методов.

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

Не пишете на PHP? Те же самые вызовы описаны в справочнике по API, и вы можете выполнять их на любом языке.

API-ключ

Семь разрешений и ничего лишнего: org.create, org.read, sites.create, sites.view, sites.delete, reseller.view, reseller.provision.

⛔ Не reseller.manage. Ключ, который вы вставляете в биллинговую панель, должен позволять блокировать клиента за неуплату и выполнять вход от его имени; он не должен иметь возможности изменять ваши собственные учетные данные платежного шлюза.

Два правила, нарушение которых стоит денег

  1. Привязывайте аккаунт к вашему КЛИЕНТУ, а сайт — к вашей УСЛУГЕ. Второй заказ клиента должен попадать в аккаунт, который у него уже есть. Если привязать и то, и другое к услуге, один клиент получит три несвязанных аккаунта и три отдельные панели управления.
  2. Передавайте ключ идемпотентности при каждом создании, сформированный на основе вашего собственного идентификатора объекта. Любая биллинговая система выполняет повторные попытки: обратный вызов шлюза приходит дважды, администратор повторно запускает неудавшуюся подготовку, клиент делает двойной клик. Без этого вторая попытка создаст второй сайт, и вам будет выставлен за него счет. Оба модуля и клиент PHP делают это автоматически; если вы вызываете API напрямую, передавайте заголовок Idempotency-Key.

Три поля, которые легко пропустить

Каждое из них нарушает работу целой операции, и ни одно из них не проявляется иначе, чем ошибка валидации — кроме первого, которое не отображается вовсе:

  • ⛔⛔ Клиент должен быть переведен на тарифный план ДО подготовки его первого сайта с помощью POST /v1/reseller/clients/{orgId}/plan, а его subscription_id должен быть передан в POST /v1/sites. В этом случае ошибка не возвращается. Новая учетная запись клиента не содержит подписки, а в POST /v1/sites нет поля для тарифного плана, поэтому сайт, подготовленный без него, вообще не имеет тарифного плана: ваша оптовая ведомость формируется на основе действующих подписок ваших клиентов, поэтому строка не создается и Zinn® не выставляет вам счета все время, пока работает хостинг; ваш клиент не получает никаких лимитов, поэтому к его сайту не применяется квота; и для изменения при обновлении ничего нет. Заказ возвращает 201, сайт подготавливается и работает безупречно. Ни одна из сторон ничего об этом не сообщает.

Порядок действий имеет значение: POST /v1/sites фиксирует ту подписку, которая существует на момент его выполнения, поэтому тарифный план, заданный позже, не применяется задним числом.

  • Для POST /v1/sites требуется stack_type. Опустите его, и ни один заказ не будет выполнен успешно.
  • Для DELETE /v1/sites/{siteId} требуется тело {"confirm_domain": "<the site's own domain>"} — подтверждение, введенное вручную, поскольку это деструктивный метод. Опустите его, и ни одна отмена не завершится успешно, служба продолжит работу, а вам продолжат выставлять за нее счета. Считывайте домен из GET /v1/reseller/services/{siteId}, а не из собственной записи: он сравнивается с собственным основным доменом сайта и никогда — с псевдонимом.

Читайте всю ошибку, а не только предложение

Сообщение об отказе при проверке намеренно сделано общим — «The request was well-formed but failed validation.», — поскольку значимая часть находится в details, где указано имя поля и причина. Оба модуля и клиент PHP добавляют его к сообщению, которое они показывают вашему администратору. Если вы вызываете API самостоятельно, читайте error.details; некоторые записи содержат только значение, а не предложение — именно так вы получаете max_sites: 0, когда в вашем реселлерском плане нет места.

Перед вашим первым заказом

Сайты, которые покупают ваши клиенты, учитываются в лимите сайтов вашего реселлерского плана, поэтому вам нужен план со свободным местом. Проверка подключения не может это обнаружить — она считывает вашу программу и ничего не подготавливает, поэтому сообщает об исправной учетной записи, которая пока не может осуществлять продажи. Заказ, размещенный при отсутствии лимита, отклоняется с сообщением, в котором говорится именно об этом.

Проверьте скачанный файл

Оба архива отдаются по протоколу TLS с нашего собственного имени хоста, без перенаправления на сторонние ресурсы, а их контрольные суммы SHA-256 указаны рядом со ссылками на скачивание на странице загрузок.

Новое в блоге

О чем мы писали: хостинг, SEO и масштабирование сайтов.

SEO и наращивание ссылочной массы на уровне хостинга: Взгляд оператора в 2026 году

Как хостинг влияет на индексацию и ссылочный вес в 2026 году: поддержание страниц в индексе, проверка старых доменов перед запуском проектов, построение ссылок без цифрового следа (футпринта) и честный взгляд на то, что инфраструктура может и чего не может сделать для SEO.

Читать запись →

Как сделать WordPress быстрым и безопасным: чек-лист по производительности и плагинам

Практический контрольный список для быстрого и безопасного WordPress: кэширование на уровне сервера, объектный кэш для каждого сайта, несколько действительно полезных плагинов, поддержание стека в актуальном состоянии и страницы WooCommerce, которые ни в коем случае нельзя кэшировать.

Читать запись →

Как выбрать управляемый веб-хостинг в 2026 году: руководство для покупателя

Что на самом деле отличает хороший управляемый хостинг от дешевого сервера с панелью управления — миграции, резервное копирование, изоляция, реальное кэширование и честное масштабирование — и как оценить его до принятия обязательств.

Читать запись →

Читать блог →

Всё ещё нужна помощь?

Поддержка включена в каждый тарифный план, служба работает 24 часов в сутки, и вы можете писать нам на любом из наших 58 языков — мы ответим вам на вашем.

Связаться со службой поддержки → Все статьи →