Прямой Диалог документация
На сайт Войти в панель

Эталонная реализация (PHP)

Отправная точка, а не обязательный код: архитектура сайта ваша. Здесь показан минимум — проверка подписи, поиск по своим данным, ответ и отправка уведомления.

dd-config.php — вне git, своё значение на каждом окружении #

<?php
const DD_SERVER_SECRET = '…серверный секрет из панели…';
const DD_NOTIFY_URL    = 'https://app.direct-dialog.ru/api/sites/shop.ru/marks/changed';

Эндпоинт проверки посетителя (канал 2) #

<?php
declare(strict_types=1);
require __DIR__ . '/dd-config.php';

header('Content-Type: application/json; charset=utf-8');

function fail(int $code, string $error): never
{
    http_response_code($code);
    echo json_encode(['error' => $error]);
    exit;
}

if ($_SERVER['REQUEST_METHOD'] !== 'POST') { fail(405, 'method'); }

// 1. Свежесть и подпись — до любой работы с телом
$body = file_get_contents('php://input');
$ts   = $_SERVER['HTTP_X_DD_TIMESTAMP'] ?? '';
$sig  = $_SERVER['HTTP_X_DD_SIGNATURE'] ?? '';

if (!ctype_digit($ts) || abs(time() - (int)$ts) > 300) { fail(401, 'stale'); }
if (!hash_equals('sha256=' . hash_hmac('sha256', $ts . '.' . $body, DD_SERVER_SECRET), $sig)) {
    fail(401, 'bad_signature');
}

$req = json_decode($body, true);
if (!is_array($req) || ($req['event'] ?? '') !== 'visitor.marks') { fail(400, 'bad_request'); }

// 2. Свои идентификаторы из ключей
$userIds = [];
foreach ($req['keys'] ?? [] as $item) {
    $key = (string)($item['key'] ?? '');
    if (str_starts_with($key, 'user:')) { $userIds[] = substr($key, 5); }
}
if (!$userIds) {
    echo json_encode(['ttl' => 900, 'marks' => []]);
    exit;
}

// 3. Решение принимает сайт. Не смогли узнать — 503, а не пустой список
try {
    $until = planPaidUntil($userIds);   // unix-время окончания тарифа или 0
} catch (Throwable $e) {
    fail(503, 'backend_unavailable');
}

if ($until <= time()) {
    echo json_encode(['ttl' => 900, 'marks' => []]);
    exit;
}

// 4. Метка
echo json_encode([
    'ttl'   => 3600,
    'marks' => [[
        'key'              => 'vip',
        'priority'         => 10,
        'expires_at'       => gmdate('Y-m-d\TH:i:s\Z', $until),
        'tooltip'          => 'Тариф «Бизнес» до ' . date('d.m.Y', $until),
        'live_row_bg'      => '#aaddcc6b',
        'live_row_bg_dark' => '#2e7d6440',
        'chat_rail_bottom' => '#2e9e7a',
        'badge'            => ['text' => 'Бизнес', 'color' => '#2e9e7a'],
        'counter_icon'     => '⭐️',
        'max_prefix'       => '⭐ Приоритетный',
    ]],
], JSON_UNESCAPED_UNICODE);

Уведомление об изменении (канал 3) — вызывать после оплаты, возврата, смены тарифа #

/**
 * Сообщает «Прямому Диалогу», что у пользователей изменился статус.
 * Не бросает исключений и не задерживает основной сценарий дольше 3 секунд.
 */
function ddNotifyChanged(array $userIds): void
{
    $keys = [];
    foreach ($userIds as $id) {
        $id = trim((string)$id);
        if ($id !== '') { $keys['user:' . $id] = true; }
    }
    if (!$keys) { return; }

    $body = json_encode(['keys' => array_keys($keys)]);
    $ts   = (string)time();

    $ch = curl_init(DD_NOTIFY_URL);
    curl_setopt_array($ch, [
        CURLOPT_POST           => true,
        CURLOPT_POSTFIELDS     => $body,
        CURLOPT_RETURNTRANSFER => true,
        CURLOPT_CONNECTTIMEOUT => 2,
        CURLOPT_TIMEOUT        => 3,
        CURLOPT_HTTPHEADER     => [
            'Content-Type: application/json',
            'X-DD-Timestamp: ' . $ts,
            'X-DD-Signature: sha256=' . hash_hmac('sha256', $ts . '.' . $body, DD_SERVER_SECRET),
        ],
    ]);
    curl_exec($ch);
    $code = (int)curl_getinfo($ch, CURLINFO_HTTP_CODE);
    curl_close($ch);

    if ($code !== 202) { error_log('Direct Dialog notify failed: HTTP ' . $code); }
}

Проверить уведомление вручную #

SECRET='…серверный секрет…'
TS=$(date +%s)
BODY='{"keys":["user:98765"]}'
SIG=$(printf '%s.%s' "$TS" "$BODY" | openssl dgst -sha256 -hmac "$SECRET" | sed 's/^.* //')

curl -i -X POST \
  -H 'Content-Type: application/json' \
  -H "X-DD-Timestamp: $TS" \
  -H "X-DD-Signature: sha256=$SIG" \
  --data "$BODY" \
  https://app.direct-dialog.ru/api/sites/shop.ru/marks/changed
# ожидается HTTP 202