Если вы используете WHMCS, используйте вместо этого модуль WHMCS — эта страница предназначена для всего остального. Доступны два варианта, оба бесплатные и под лицензией GPL-2.0-or-later.
HostBill
Модуль хостинга с теми же шестью действиями, что и модуль для WHMCS.
- Скачайте его и распакуйте архив.
- Загрузите каталог
zinn в includes/modules/Hosting/, чтобы файлы оказались по путям includes/modules/Hosting/zinn/class.zinn.php и includes/modules/Hosting/zinn/ZinnHostBillClient.php.
- Settings → Modules → Hosting, активируйте Zinn Digital® и добавьте подключение:
- API address:
https://api.zinndigital.com
- API key: ваш API-ключ Zinn® (поле типа
password, поэтому HostBill сохраняет его в зашифрованном виде)
- В настройках продукта укажите Product line (например,
mainstream), Stack (по умолчанию wordpress) и, при необходимости, Application и PHP version.
- Нажмите 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. Ключ, который вы вставляете в биллинговую панель, должен позволять блокировать клиента за неуплату и выполнять вход от его имени; он не должен иметь возможности изменять ваши собственные учетные данные платежного шлюза.
Два правила, нарушение которых стоит денег
- Привязывайте аккаунт к вашему КЛИЕНТУ, а сайт — к вашей УСЛУГЕ. Второй заказ клиента должен попадать в аккаунт, который у него уже есть. Если привязать и то, и другое к услуге, один клиент получит три несвязанных аккаунта и три отдельные панели управления.
- Передавайте ключ идемпотентности при каждом создании, сформированный на основе вашего собственного идентификатора объекта. Любая биллинговая система выполняет повторные попытки: обратный вызов шлюза приходит дважды, администратор повторно запускает неудавшуюся подготовку, клиент делает двойной клик. Без этого вторая попытка создаст второй сайт, и вам будет выставлен за него счет. Оба модуля и клиент 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 указаны рядом со ссылками на скачивание на странице загрузок.