Документация интеграции

Партнёрский API v1

Проверяйте коды, отправляйте тестовые и разрешённые активации, затем следите за состоянием операций. API использует те же проверки и ограничения поставщиков, что и клиентский интерфейс.

Bearer API key JSON / UTF-8 HTTPS · new.rootactivation.ru

Возможности и текущие ограничения

Публичный Base URL: https://new.rootactivation.ru/api/partner/v1. Локальная mock-среда запускается отдельно по адресу http://127.0.0.1:8765/api/partner/v1; её синтетические коды не предназначены для production.

Партнёр может проверять код, предварительно проверить аккаунт, запустить разрешённую активацию и читать свои операции. Вызов запуска возвращает оболочку {"operation": ...}, а выполнение продолжается в фоне. Для обновления состояния вызывайте POST /status с тем же кодом.

Доступность зависит от кода и конфигурации. Live-потоки покрывают Dorin ChatGPT Plus; ByPrice ChatGPT Plus Direct, ChatGPT Pro 20× Direct, ChatGPT Plus/Go iOS, SuperGrok Pro/Plus и Grok 7 дней; vip666ai для поддержанного продукта за префиксом PRO5SPECIAL- с типом погашения, возвращённым probe; и тарифы Gpay, которые подтвердил поставщик. Неизвестный тариф не становится поддерживаемым по одному префиксу. Dorin, ByPrice и vip666ai требуют серверный live-флаг, настройки/ключ (если требуется) и включённый провайдер; Gpay отдельно требует включения администратором и ключа. Партнёр также должен иметь разрешение allowActivation.

Проверка не запускает активацию. canActivate учитывает точный результат проверки, известный продукт, доступность провайдера и разрешение партнёра. Поддерживаемый VIP probe может выбрать тип chatgpt_account_id или chatgpt_session_json; передавайте сессию и путь аккаунта, указанные в ответе.

Успех подтверждается только распознанным ответом конкретного поставщика: Dorin activation.completed или проверкой статуса исходного кода used; ByPrice — completed для GPT или done для Grok на ожидаемом заказе; VIP — подтверждённый статус успеха на ожидаемом idempotency key/заказе; Gpay — совпадающий заказ с status=completed и terminal=true. Неизвестный ответ, review и истёкшее локальное ожидание не подтверждают подписку. Claude пока не поддерживается: для него нужна отдельная настройка учётных данных.

Маршруты, авторизованные ключом партнёра, показывают только операции этого партнёра. Если такой маршрут отклоняет код из-за чужого закрепления, ответ — общий 404 code_not_found, не раскрывающий владельца или наличие операции. Ошибки неизвестного или некорректного кода зависят от проверки и не обязаны иметь тот же статус. Клиентский API остаётся доступен по коду: покупатель, уже знающий код, может проверить его результат по обычному клиентскому сценарию.

Доступ и управление ключами

Администратор создаёт партнёра в панели. Полный ключ API показывается только при создании или ротации. Сервер хранит SHA-256-дайджест и последние четыре символа для подсказки; повторно показать полный ключ нельзя. Храните секрет на сервере интеграции и не передавайте его в браузер, URL, журнал или репозиторий. Управление партнёром и его ключом выполняет администратор; отдельного партнёрского API для этого или настройки поставщиков нет.

Все шесть маршрутов требуют заголовок:

Authorization: Bearer <PARTNER_API_KEY>
Accept: application/json

Для POST-запроса добавьте Content-Type: application/json; charset=utf-8. Cookie администратора не заменяет Bearer-ключ. Ключ партнёра не открывает панель администратора и не даёт доступа к секретам поставщиков.

Администратор может отключить партнёра, ограничить лимит, запретить новые preview/activate, отозвать ключ или выпустить новый. Лимит requestsPerMinute по умолчанию равен 60; допустимое значение — от 1 до 600 запросов в минуту. Отключение партнёра, allowActivation=false, ротация или отзыв ключа не отменяют уже выполняющиеся фоновые операции. При allowActivation=false вызовы preview и activate возвращают 403 activation_disabled; проверка, конфигурация и чтение списка операций остаются доступны, а проверка может вернуть canActivate:false.

Общие правила запросов

  • Успешный вызов возвращает HTTP 200 и JSON. Ошибка использует оболочку {"error":{"code":"...","message":"..."}}.
  • POST принимает JSON-объект только с полями маршрута; лишние поля отклоняются с 400 invalid_request. POST query-параметры не поддерживает. Передавайте код в теле, не в URL.
  • session — строка, внутри которой находится JSON-сессия, принятая существующим клиентским потоком для этого кода. Передавайте её как JSON-строку, а не вложенный объект. Общий предел — 32 768 символов; сценарий поставщика может ограничивать её сильнее.
  • Максимальный размер HTTP-тела — 64 КиБ. Формат сессии и её более строгие пределы зависят от поставщика. Синтетические сессии и mock-сценарии доступны только в локальной среде.
  • Лимит партнёра действует на все маршруты в общем скользящем 60-секундном окне. Он задаётся администратором в requestsPerMinute (по умолчанию 60, диапазон 1–600). При превышении API возвращает 429 rate_limited. Проверки также могут иметь отдельный лимит поставщика и вернуть 429 check_rate_limited.
  • Production-запросы должны идти по HTTPS на new.rootactivation.ru. Сервер-серверный клиент может опустить Origin; если он передан, используйте origin https://new.rootactivation.ru. Локальный mock-клиент обращается только к loopback адресу http://127.0.0.1:8765.
  • Cookie запрещены на маршрутах партнёра (400 bearer_only). Сырая сессия обрабатывается во время вызова; она не возвращается, не записывается в партнёрский журнал и не попадает в HTTP-логи. Для восстановления операции сервис может сохранять маскированный ID/email и данные, нужные рабочему процессу.

Маршруты

GET/api/partner/v1/config

Возвращает версию API, разрешение активации для этого партнёра и рекомендуемую частоту опроса статуса.

{
  "apiVersion": "v1",
  "activationEnabled": true,
  "pollIntervalMs": 1500
}

activationEnabled отражает только партнёрскую настройку allowActivation. Она не включает поставщика и не гарантирует, что конкретный код можно активировать. Проверяйте canActivate в ответе /check. Конфигурация не раскрывает локальные сценарии, sample session, секреты или внутренние параметры поставщиков.

POST/api/partner/v1/check

Проверяет код, не запуская активацию.

{"code":"<CODE>"}

Обычный тестовый ответ содержит product, codeStatus, canActivate, instruction, accountField, operation и checkedAt. Если операции ещё нет, operation равен null.

Синтетический пример ответа

{
  "product": "ChatGPT Plus",
  "codeStatus": "available",
  "canActivate": true,
  "instruction": "Для реальной активации введите код и проверьте нужный аккаунт.",
  "accountField": "user.id",
  "operation": null,
  "checkedAt": "2026-10-11T10:00:00Z"
}

Ответ нормализован сервисом и не раскрывает сырые ответы поставщика, его секреты или внутренние поля заказов. Неизвестные поля API-контракта игнорируйте.

POST/api/partner/v1/preview

Проверяет допустимость кода и аккаунта по текущим настройкам. Код и сессия обязательны:

{"code":"<CODE>","session":"<JSON_SESSION_STRING>"}

В ответе — тариф и публичное представление аккаунта; поля account всегда содержат только email, маскированный ID, тип ID и источник.

{
  "product": "ChatGPT Plus",
  "account": {
    "email": "demo@example.invalid",
    "maskedId": "dem••••123",
    "idType": "user.id",
    "source": "customer"
  }
}

preview не запускает активацию и не закрепляет код. Если партнёрский маршрут отклоняет код из-за операции другого владельца, он возвращает общий 404 code_not_found; другие ошибки проверки, отсутствующего или некорректного кода могут отличаться.

POST/api/partner/v1/activate

Запускает разрешённую операцию. Оба поля обязательны:

{"code":"<CODE>","session":"<JSON_SESSION_STRING>"}

Успешный вызов возвращает HTTP 200 с конвертом operation:

{
  "operation": {
    "id": "op_<32 lowercase hex characters>",
    "product": "ChatGPT Plus",
    "state": "queued",
    "codeStatus": "processing",
    "executionMode": "mock",
    "createdAt": "2026-10-11T10:00:00Z",
    "updatedAt": "2026-10-11T10:00:00Z",
    "lastCheckedAt": "2026-10-11T10:00:00Z",
    "account": {
      "email": "demo@example.invalid",
      "maskedId": "dem••••123",
      "idType": "user.id",
      "source": "customer"
    },
    "publicCode": null,
    "message": "Тестовый запрос принят и ожидает обработки.",
    "events": [
      {"at":"2026-10-11T10:00:00Z","state":"queued","label":"Тестовый запрос принят в очередь"}
    ]
  }
}

Ответ означает, что операция принята или уже существует, а не то, что она завершена. При первом запуске код атомарно закрепляется за партнёром. Партнёрские маршруты не раскрывают операции других владельцев; это ограничение авторизации партнёрского API не меняет поведение существующего клиентского API для покупателя, который уже передал тот же код.

Реальный код может запустить реальную активацию. Для mock-тестов используйте только синтетические TEST-… коды в локальной среде. Live-запуск возможен только для известного поддерживаемого продукта при включённом провайдере и разрешении партнёра. Не запускайте production-код ради проверки интеграции.

POST/api/partner/v1/status

Принимает исходный код:

{"code":"<CODE>"}

Возвращает тот же клиентский ответ, что и /check, включая вложенный operation, если он существует. Вложенный объект очищен от внутренних ID заказов и сырых статусов поставщика. Маршрут принимает код, а не operation.id; сохраните исходный код для последующего опроса.

GET/api/partner/v1/operations?page=1

Возвращает до 20 собственных операций, отсортированных от новых к старым. Если операций нет, ответ содержит пустую первую страницу.

{
  "items": [
    {
      "id": "op_<32 lowercase hex characters>",
      "product": "ChatGPT Plus",
      "state": "running",
      "codeStatus": "processing",
      "executionMode": "mock",
      "createdAt": "2026-10-11T10:00:00Z",
      "updatedAt": "2026-10-11T10:00:02Z",
      "lastCheckedAt": "2026-10-11T10:00:02Z",
      "account": {"email":"demo@example.invalid","maskedId":"dem••••123","idType":"user.id","source":"customer"},
      "publicCode": null,
      "message": "Выполняется локальная тестовая операция.",
      "events": [
        {"at":"2026-10-11T10:00:00Z","state":"queued","label":"Тестовый запрос принят в очередь"},
        {"at":"2026-10-11T10:00:02Z","state":"running","label":"Локальная тестовая операция началась"}
      ]
    }
  ],
  "total": 1,
  "page": 1,
  "pages": 1
}

Элементы используют ту же очищенную схему operation, что и ответ activate; список не содержит исходный код. Номер страницы должен быть положительным целым числом в существующем диапазоне.

Поля ответов

Ответ проверки похож на клиентский API. В партнёрском ответе могут присутствовать дополнительные поля проверки поставщика; этот список описывает основные стабильные поля и не является закрытым перечнем.

ПолеФорма и смысл
productНазвание тарифа или продукта.
codeStatusСтатус кода/заказа, а не состояние операции. Часто встречаются available, processing, used, unavailable и unknown. Не используйте это поле вместо operation.state и допускайте новые значения.
canActivateБулево разрешение для проверенного кода, известного продукта и текущих настроек провайдера/партнёра. При allowActivation=false проверка может успешно вернуть canActivate:false.
accountFieldОжидаемый путь ID в JSON-строке session: user.id — $.user.id; account.id — $.account.id; userId для Grok — текущий путь $.session.userId (устаревший вариант $.userId тоже распознаётся). null означает, что проверка только для чтения не требует аккаунт.
operationnull до создания операции или объект текущей операции. В ответах партнёра нет сырых ответов, статусов, идентификаторов заказа или других внутренних полей поставщика.
operation.statequeued, running, reconciling, review, succeeded или failed. Это состояние приложения; оно отдельно от codeStatus.
operation.executionModemock для локального сценария или real для реальной операции поставщика.
operation.accountПубличные поля email, maskedId, idType, source. Email и ID маскируются и могут отсутствовать.
operation.publicCodeПубличный код ситуации или null; не содержит сырой ответ поставщика.
operation.eventsИстория приложения: элементы с at, state, label. Время передаётся в ISO 8601 UTC с суффиксом Z.

Для preview и activate поле session — строка с сериализованным JSON. Например, тело запроса для синтетического ChatGPT-кода (вложенные кавычки экранированы, секретов здесь нет):

{"code":"TEST-success-012345ABCDEF","session":"{\"status\":\"authenticated\",\"user\":{\"id\":\"synthetic-chatgpt-user-123456\",\"email\":\"chatgpt@example.invalid\"}}"}

Для Grok текущий формат использует вложенное session.userId; в этом примере код должен соответствовать локальному Grok-сценарию:

{"code":"TEST-grok-012345ABCDEF","session":"{\"status\":\"authenticated\",\"session\":{\"userId\":\"synthetic-grok-user-123456\",\"email\":\"grok@example.invalid\"}}"}

Отправляйте сессию только по защищённому каналу в теле запроса. Не подставляйте в документацию, тесты или журналы реальные пользовательские сессии.

Состояния и опрос

СостояниеЗначение
queuedЗапрос принят и ожидает обработки.
runningЛокальная операция или задача поставщика выполняется.
reconcilingСервис уточняет результат уже запущенной операции.
reviewОперация ожидает ручной проверки.
succeededУспех подтверждён.
failedОперация завершена для приложения. При коде тайм-аута исход у поставщика может оставаться неизвестным.

Типичный путь: queued → running → succeeded или queued → running → failed. Сценарии поставщика могут включать reconciling или review. succeeded и failed — терминальные состояния этой операции; новые версии могут добавлять промежуточные состояния, поэтому неизвестное состояние не должно ломать клиент.

После запуска опрашивайте POST /status с тем же кодом с рекомендуемым интервалом из /config — сейчас 1500 мс. Состояние сохраняется сервером и может оставаться прежним между запросами. Опрос API не управляет частотой внутренних запросов к поставщику.

Если клиент потерял ответ /activate или получил сетевой тайм-аут, не запускайте активацию повторно автоматически: запуск мог уже начаться. Проверьте тот же код через /status или найдите операцию через /operations. Dorin, ByPrice и vip666ai прекращают локальное ожидание после более чем 180 секунд без подтверждённого изменения статуса. Это не отменяет запрос у поставщика и не доказывает отсутствие подписки. У Gpay собственное восстановление по заказу. При неопределённом результате передайте продавцу publicCode, если он есть, и уточните исход.

Операция не возвращает исходный код. Партнёру следует хранить код у себя с соответствующими мерами защиты. Ответы партнёра исключают внутренние идентификаторы заказов и статусы поставщиков.

Ошибки и восстановление

Все ошибки используют оболочку:

{"error":{"code":"invalid_partner_key","message":"Проверьте ключ партнёра."}}
HTTPКодыДействие
400invalid_request, invalid_json, invalid_code, invalid_session, missing_account_id, invalid_page, invalid_host, bearer_onlyИсправить тело, формат входных данных, страницу или Host; на этих маршрутах не передавать Cookie.
401invalid_partner_keyПроверить Bearer-заголовок и статус ключа; после ротации использовать новый ключ.
403partner_disabled, activation_disabled, same_origin_requiredДоступ или запуск запрещён настройкой, либо переданный Origin не совпал с origin запроса.
404code_not_foundПри отказе по владению ответ не раскрывает, кому принадлежит код или существует ли операция. Для некорректного/неизвестного кода и ошибки проверки возможны другие статусы и коды.
409activation_in_progress, code_not_activatable, provider_disabled, Gpay preflight-кодыСначала выяснить текущий статус; не повторять activate вслепую. Случаи Gpay описаны ниже.
429rate_limited, check_rate_limitedСнизить частоту. Сообщение объясняет общий лимит партнёра или ограничение проверки поставщика.
502–503Ошибка поставщика или provider_disabledПроверка или поставщик временно недоступны; ошибка не подтверждает допустимость активации.
500internal_errorДля запроса активации сначала выяснить текущее состояние через status/operations.

Клиенту следует ветвиться по HTTP-коду и error.code. Текст message можно показать пользователю, но не использовать как машинный идентификатор.

Предварительная проверка Gpay

Для реального Gpay код и аккаунт должны пройти предварительную проверку до запуска; после preview используйте тот же аккаунт и ту же сессию в activate. Предварительная проверка действует пять минут.

HTTP / кодВосстановление
409 preflight_requiredВыполнить POST /preview с кодом и сессией предполагаемого аккаунта, затем вызвать /activate с той же сессией.
409 preflight_expiredПовторить /preview с тем же аккаунтом и сессией, затем оперативно повторить запуск. Это безопасно лишь если предшествующая попытка запуска точно не началась; при сетевом тайм-ауте сначала опросить /status.
409 preflight_account_mismatchСессия не соответствует предварительно проверенному аккаунту. Не переключать аккаунт между /preview и /activate; повторно выполнить проверку с нужной сессией, если запуск ещё не начинался.
409 account_unusableПоставщик не разрешил запуск для этого аккаунта. Не повторять с тем же аккаунтом; уточнить у продавца, какой аккаунт допустим.

Повторяйте запуск только при однозначном ответе, что он не был принят. Если соединение оборвалось после отправки /activate, опрашивайте тот же код и не отправляйте новый запуск автоматически.

Локальная mock-проверка (опционально)

Этот пример обращается только к локальному серверу 127.0.0.1:8765, а не к production API. Тестовые коды и sample session недоступны на публичном сервере.

  1. Запустите приложение и создайте партнёра в панели администратора. Сохраните ключ на сервере интеграции, включите партнёра и разрешите ему запуск теста (allowActivation).
  2. В клиентском интерфейсе откройте Тестовые сценарии и создайте код для сценария «Успешная активация». Он имеет вид TEST-success-<12 заглавных hex-символов>. Это локальная имитация; она не отправляет заказ поставщику и не оформляет подписку.
  3. Установите переменные окружения PARTNER_API_KEY и TEST_CODE. Пример ниже прекращает работу до первого сетевого запроса, если код не соответствует точному формату этого тестового сценария.

Пример Python 3 с urllib выполняет полный mock-путь: /config → /check → /preview → один вызов /activate → опрос /status. Для ChatGPT тестовая сессия использует только синтетические значения:

import json
import os
import re
import time
import urllib.error
import urllib.request

BASE = "http://127.0.0.1:8765/api/partner/v1"
API_KEY = os.environ["PARTNER_API_KEY"]
TEST_CODE = os.environ["TEST_CODE"]
# Fail closed before sending any request; never substitute a real code.
if not re.fullmatch(r"TEST-success-[A-F0-9]{12}", TEST_CODE):
    raise SystemExit("TEST_CODE must be a locally generated TEST-success code")

HEADERS = {"Authorization": f"Bearer {API_KEY}", "Accept": "application/json"}
SESSION = json.dumps({
    "status": "authenticated",
    "user": {"id": "synthetic-chatgpt-user-123456", "email": "chatgpt@example.invalid"},
})

def call(method, path, payload=None):
    data = None if payload is None else json.dumps(payload).encode("utf-8")
    headers = dict(HEADERS)
    if data is not None:
        headers["Content-Type"] = "application/json; charset=utf-8"
    request = urllib.request.Request(BASE + path, data=data, headers=headers, method=method)
    try:
        with urllib.request.urlopen(request, timeout=15) as response:
            return response.status, json.load(response)
    except urllib.error.HTTPError as error:
        return error.code, json.load(error)

def require_ok(result):
    status, body = result
    if status != 200:
        raise RuntimeError(f"HTTP {status}: {body}")
    return body

config = require_ok(call("GET", "/config"))
if not config["activationEnabled"]:
    raise SystemExit("Enable this partner's test activation in local admin first")
checked = require_ok(call("POST", "/check", {"code": TEST_CODE}))
if checked.get("codeStatus") != "available" or not checked.get("canActivate"):
    raise SystemExit("The generated mock code is not available for this partner")
require_ok(call("POST", "/preview", {"code": TEST_CODE, "session": SESSION}))

# Send activate once only. If the connection times out, recover by polling status;
# do not send a second activate request.
try:
    launch = require_ok(call("POST", "/activate", {"code": TEST_CODE, "session": SESSION}))
    print("Accepted:", launch["operation"].get("state"))
except (TimeoutError, urllib.error.URLError) as error:
    print("Launch response was ambiguous; polling the same test code:", error)

terminal = {"succeeded", "failed"}
deadline = time.monotonic() + 30
while time.monotonic() < deadline:
    status = require_ok(call("POST", "/status", {"code": TEST_CODE}))
    operation = status.get("operation")
    if operation:
        print("Current state:", operation.get("state"))
        if operation.get("state") in terminal:
            break
    time.sleep(config["pollIntervalMs"] / 1000)
else:
    print("Still unresolved; inspect GET /operations?page=1. Do not launch again.")

Активация в этом примере строго ограничена синтетическим TEST-success-… кодом и выполняется ровно один раз. Для Grok используйте отдельный синтетический TEST-grok-… код и строку сессии с session.userId, показанную выше. Не передавайте реальные коды, пользовательские сессии или GPAY-…. Партнёрский API не создаёт тест-коды и не выдаёт список сценариев; тесты не должны обращаться к внешним API.

Совместимость и эксплуатация

apiVersion обозначает контракт v1. Клиент должен игнорировать неизвестные поля, учитывать operation: null и не полагаться на наличие email или publicCode. Даты — ISO 8601 UTC с суффиксом Z. Элементы /operations используют ту же очищенную схему операции, что и ответ запуска. Партнёрские ответы содержат только нормализованные поля этого документа и не раскрывают сырые ответы поставщиков или секреты.