Widget · DocsWidget · документация
← Demo stand← к демо-стенду
GeneralОбщий

OverviewОбзор

Version 1.0. Audience: partner engineering teams embedding the GoMining Plug-and-Play (PnP) purchase widget. The widget ships as a Web Component (one <script> + one HTML element) and renders inside Shadow DOM — isolated from your site's styles. Версия 1.0. Аудитория: инженерные команды партнёров, встраивающие виджет покупки GoMining Plug-and-Play (PnP). Виджет поставляется как веб-компонент (один тег <script> + один HTML-элемент) и рендерится в Shadow DOM — изолирован от стилей вашего сайта.

The PnP widget lets users buy a GoMining NFT miner with a bank card directly inside the partner's site or app. A GoMining account is created automatically — the user verifies their email via a one-time code (OTP), with no password and no separate sign-up. If a known user's email is passed in the signToken (Backend → signToken), email verification is skipped.

Виджет PnP позволяет пользователям купить NFT-майнер GoMining банковской картой прямо внутри сайта или приложения партнёра. Аккаунт GoMining создаётся автоматически — пользователь подтверждает email одноразовым кодом (OTP), без пароля и без отдельной регистрации. Если email известного пользователя передан в signToken (Бекенд → signToken), подтверждение email пропускается.

GoMining handles the UI, email verification, miner catalog, payment and provisioning. GoMining never sees card data — payment runs on a PCI-compliant hosted page.

GoMining берёт на себя интерфейс, подтверждение email, каталог майнеров, оплату и провижининг. GoMining никогда не видит данные карты — оплата проходит на размещённой PCI-совместимой странице.

Partner responsibilitiesЗона ответственности партнёра

  1. generate a signToken per session (Backend → signToken);
  2. receive a conversion webhook on success/failure (Backend → webhooks);
  3. embed the widget (Frontend → embedding).
  1. генерировать signToken на каждую сессию (Бекенд → signToken);
  2. принимать вебхук о конверсии при успехе/ошибке (Бекенд → вебхуки);
  3. встроить виджет (Фронтенд → встраивание).

Everything else needs no partner work.

Всё остальное не требует работы со стороны партнёра.

GeneralОбщий

Integration at a glanceИнтеграция в двух словах

Four phases, in order.

Четыре этапа по порядку.

PhasesЭтапы

  1. Onboarding — one-time setup: generate an RSA key pair, send GoMining your public key + webhook URL + the miners to offer, receive your partnerId + environments + webhook signing secret.
  2. BackendsignToken generation + a conversion-webhook receiver.
  3. Frontend — embed the widget.
  4. Test & go live — security + go-live checklist.
  1. Онбординг — разовая настройка: сгенерировать пару RSA-ключей, отправить в GoMining публичный ключ + URL вебхука + список майнеров для продажи, получить свой partnerId + окружения + секрет подписи вебхуков.
  2. Бэкенд — генерация signToken + приёмник вебхука о конверсии.
  3. Фронтенд — встроить виджет.
  4. Тест и запуск — безопасность + чек-лист запуска.
GeneralОбщий

Onboarding (one-time)Онбординг (разово)

Generate an RSA key pair (2048-bit or more)Сгенерируйте пару RSA-ключей (2048 бит и больше)

The private key signs your signTokens; the public key lets GoMining verify them.

Приватный ключ подписывает ваши signToken; публичный ключ позволяет GoMining их проверять.

Generate the key pairГенерация пары ключей
# private key (PKCS#8, "BEGIN PRIVATE KEY")
openssl genpkey -algorithm RSA -pkeyopt rsa_keygen_bits:2048 -out gomining-pnp-private.pem

# public key (SPKI, "BEGIN PUBLIC KEY")
openssl rsa -in gomining-pnp-private.pem -pubout -out gomining-pnp-public.pem
  • Private key (BEGIN PRIVATE KEY) — keep it on your backend, it signs every signToken. Never send or expose it.
  • Public key (BEGIN PUBLIC KEY) — send it to GoMining.
  • Rotation: generate a new pair, send the new public key, coordinate the cut-over timing with GoMining.
  • Приватный ключ (BEGIN PRIVATE KEY) — храните на своём бэкенде, он подписывает каждый signToken. Никогда не отправляйте и не раскрывайте его.
  • Публичный ключ (BEGIN PUBLIC KEY) — отправьте его в GoMining.
  • Ротация: сгенерируйте новую пару, отправьте новый публичный ключ, согласуйте момент переключения с GoMining.

What you send to GoMiningЧто вы отправляете в GoMining

ItemЭлемент DetailsДетали
RS256 public key (PEM) required Публичный ключ RS256 (PEM) required The SPKI public key from "Generate an RSA key pair". Never the private key. Публичный ключ SPKI из «Сгенерируйте пару RSA-ключей». Никогда не приватный.
Webhook endpoint URL required URL эндпоинта вебхука required HTTPS endpoint that receives the webhooks. HTTPS-эндпоинт, принимающий вебхуки.
Miners to offer required Майнеры для продажи required Which miners appear and which are featured — chosen together with GoMining by hashrate (TH/s) and energy efficiency. Какие майнеры показывать и какие выделить — выбирается совместно с GoMining по хешрейту (TH/s) и энергоэффективности.

What GoMining sends youЧто GoMining отправляет вам

ItemЭлемент DetailsДетали
partnerId UUID — goes into every signToken and into the widget init. UUID — попадает в каждый signToken и в инициализацию виджета.
EnvironmentsОкружения Staging and production. Staging и production.
Webhook signing secretСекрет подписи вебхуков Used to verify webhook signatures. Для проверки подписей вебхуков.

GoMining enables the widget once onboarding is done.

GoMining включает виджет после завершения онбординга.

GeneralОбщий

Security requirementsТребования безопасности

  • The private key stays on the backend; generate signTokens server-side only; never ship the private key or the signing logic to the browser.
  • One token per session; a fresh jti; never reuse or cache.
  • Respect the 5-minute cap (exp − iat ≤ 300s); generate the token at widget-open time.
  • Verify webhook signatures before acting on a payload.
  • Приватный ключ остаётся на бэкенде; генерируйте signToken только на сервере; никогда не отправляйте приватный ключ или логику подписи в браузер.
  • Один токен на сессию; свежий jti; никогда не переиспользуйте и не кэшируйте.
  • Соблюдайте лимит в 5 минут (exp − iat ≤ 300с); генерируйте токен в момент открытия виджета.
  • Проверяйте подписи вебхуков перед действиями над payload.
GeneralОбщий

Go-live checklistЧек-лист запуска

OnboardingОнбординг

  • RSA key pair generated; public key sent; private key stored securely.
  • Webhook URL + miners (and featured ones) sent.
  • partnerId + environments + webhook signing secret received.
  • GoMining confirms the widget is enabled.
  • Пара RSA-ключей сгенерирована; публичный ключ отправлен; приватный ключ хранится безопасно.
  • URL вебхука + майнеры (и выделенные) отправлены.
  • partnerId + окружения + секрет подписи вебхуков получены.
  • GoMining подтвердил, что виджет включён.

BackendБэкенд

  • signToken generation validated server-side on staging.
  • An authenticated endpoint returns a fresh signToken per session.
  • Webhook receiver with signature verification in place.
  • Генерация signToken проверена на сервере в staging.
  • Аутентифицированный эндпоинт возвращает свежий signToken на каждую сессию.
  • Приёмник вебхуков с проверкой подписи готов.

Go-liveЗапуск

  • Full purchase flow tested end-to-end on staging.
  • Production config provisioned and happy-path smoke-tested.
  • Полный флоу покупки протестирован end-to-end в staging.
  • Прод-конфигурация подготовлена и проверена smoke-тестом по happy-path.
BackendБекенд

Generating the signTokenГенерация signToken

Per session, your backend issues a short-lived JWT signed with RS256 using your private key.

На каждую сессию ваш бэкенд выпускает короткоживущий JWT, подписанный RS256 вашим приватным ключом.

PayloadPayload

FieldПоле PurposeНазначение
partnerId required String UUID — your partner identifier. Строка UUID — идентификатор партнёра.
jti required String, unique per token (UUID). Single-use — reuse is rejected. Строка, уникальная на токен (UUID). Одноразовый — повторное использование отклоняется.
email optional If known and the user exists, email verification is skipped. Omit it to let the widget collect and verify the email. Если известен и пользователь существует, подтверждение email пропускается. Опустите, чтобы виджет сам собрал и подтвердил email.
iat / exp Standard issued-at / expiry. You usually don't set these by hand — most JWT libs add both when you specify a lifetime (expiresIn / ttl). Lifetime MUST be ≤ 300s (5 min). Стандартные issued-at / expiry. Обычно вы не задаёте их вручную — большинство JWT-библиотек добавляют оба при указании времени жизни (expiresIn / ttl). Время жизни ДОЛЖНО быть ≤ 300с (5 мин).
Full payloadПолный payload
{
  "partnerId": "<uuid>",
  "email": "<user-email-if-known>",
  "jti": "<uuid>"
}

Rules:

Правила:

  • RS256 only, signed with the private key.
  • Generate server-side at widget-open time — never in advance, never in the browser.
  • One token per session, with a unique jti.
  • Set the lifetime via the library's expiry option. (Manually setting iat may be stripped by some libs → the token is rejected.)
  • GoMining rejects tokens that live longer than 300s and tokens missing iat / exp.
  • Только RS256, подпись приватным ключом.
  • Генерировать на сервере в момент открытия виджета — никогда заранее и никогда в браузере.
  • Один токен на сессию, с уникальным jti.
  • Задавайте время жизни через опцию expiry библиотеки. (Ручная установка iat может быть выброшена некоторыми библиотеками → токен отклоняется.)
  • GoMining отклоняет токены со временем жизни больше 300с и токены без iat / exp.

Node.js exampleПример на Node.js

Install the dependency:

Установите зависимость:

npm
npm install jsonwebtoken
generateSignToken.js
const jwt = require('jsonwebtoken');
const { randomUUID } = require('crypto');

// full PEM with line breaks; if env strips newlines store base64 & decode
const PRIVATE_KEY = process.env.GOMINING_PNP_PRIVATE_KEY;
const PARTNER_ID = process.env.GOMINING_PARTNER_ID;

function generateSignToken(email) {
  const payload = { partnerId: PARTNER_ID, jti: randomUUID() };
  if (email) payload.email = email;
  return jwt.sign(payload, PRIVATE_KEY, { algorithm: 'RS256', expiresIn: 300 });
}

// expose via an authenticated endpoint the widget can call, or inject at render time.

Other languagesДругие языки

Same contract — RS256 with the private key:

Тот же контракт — RS256 с приватным ключом:

  • Python (PyJWT) — jwt.encode(payload, private_key, algorithm="RS256")
  • Go (golang-jwt) — jwt.NewWithClaims(jwt.SigningMethodRS256, claims)
  • PHP (firebase/php-jwt) — JWT::encode($payload, $privateKey, 'RS256')
  • Java (jjwt) — Jwts.builder().signWith(privateKey, SignatureAlgorithm.RS256)
BackendБекенд

Receiving conversion webhooksПриём вебхуков о конверсии

When a payment is processed, GoMining sends an HTTP webhook to your registered endpoint (Onboarding) so you can fulfil and reconcile independently of the widget UI. Verify the signature with your webhook signing secret before trusting any payload.

Когда платёж обработан, GoMining отправляет HTTP-вебхук на ваш зарегистрированный эндпоинт (Онбординг), чтобы вы могли выполнить fulfillment и сверку независимо от UI виджета. Проверяйте подпись секретом подписи вебхуков перед тем, как доверять любому payload.

TODO
(depends on backendзависит от бэкенда) detailed webhook documentation (payload schema, headers, signature algorithm, retries) is still being finalized by the backend team («добавить доку по вебхукам»). This section will be expanded once the contract is locked. подробная документация по вебхукам (схема payload, заголовки, алгоритм подписи, ретраи) ещё финализируется командой бэкенда («добавить доку по вебхукам»). Раздел будет расширен, как только контракт зафиксируют.
FrontendФронтенд

Embedding the widgetВстраивание виджета

Load the script once on the page, then place the <gomining-widget> element anywhere in your markup. The widget renders in Shadow DOM — your CSS does not leak into it, and its styles do not leak out.

Подключите скрипт один раз на странице, затем вставьте элемент <gomining-widget> в любое место разметки. Виджет рендерится в Shadow DOM — ваш CSS в него не протекает, а его стили не протекают наружу.

Minimal embedМинимальный embed

Minimal embedМинимальный embed
<!-- 1. load the script once -->
<script src="https://cdn.gomining.com/widget.js" async></script>

<!-- 2. drop the widget where you need it -->
<gomining-widget
  partner-id="your-partner-id"
  sign-token="<token from your backend>"
  locale="en"
  theme="dark"></gomining-widget>
TODO
(depends on CDNзависит от CDN) the URL https://cdn.gomining.com/widget.js is a placeholder. The final production CDN URL will be confirmed separately (open backend question about bundle hosting). URL https://cdn.gomining.com/widget.js — плейсхолдер. Финальный прод-URL CDN будет подтверждён отдельно (есть открытый бэкенд-вопрос по хостингу бандла).
FrontendФронтенд

AttributesАтрибуты

Attributes are set in kebab-case on the element. They can be changed at runtime via setAttribute() — the widget reacts reactively (theme, locale). Source: the root component's inputs (input()).

Атрибуты задаются в kebab-case на элементе. Их можно менять в рантайме через setAttribute() — виджет реагирует реактивно (тема, язык). Источник: входы (input()) корневого компонента.

AttributeАтрибут ValuesЗначения DefaultПо умолчанию PurposeНазначение
partner-id required string (your partner UUID) строка (ваш partner UUID) Partner identifier. Empty/missing → the widget shows a config error screen and emits widgetError with code invalid_partner_id. Идентификатор партнёра. Пустой/отсутствует → виджет показывает экран ошибки конфигурации и эмитит widgetError с кодом invalid_partner_id.
sign-token required string (JWT / signed token) строка (JWT / подпись) Signed token issued by your backend — auto-authenticates the user (Flow A, see Auth Flow A/B). Missing → error screen and widgetError with code missing_sign_token. Подписанный токен, выданный вашим бэкендом — авто-авторизует пользователя (Flow A, см. Авторизация A/B). Отсутствует → экран ошибки и widgetError с кодом missing_sign_token.
locale en | ru system language / en язык системы / en Widget UI language. Unsupported value → falls back to the default. Язык интерфейса виджета. Неподдерживаемое значение → fallback на дефолт.
theme light | dark prefers-color-scheme
(thenзатем light)
Visual theme. Missing → follows the user's OS theme (reactively). Invalid value → system. Тема оформления. Отсутствует → берётся системная тема ОС пользователя (реактивно). Невалидное значение → системная.
th-amount positive numberположительное число unsetне задан Pre-filled miner hashrate (TH). Empty/invalid/≤0 → ignored. Предзаполненная мощность майнера (TH). Пустое/невалидное/≤0 → игнорируется.
profile boolean attribute (present = true; false = false) boolean-атрибут (наличие = true; false = false) false true → a returning authenticated user with miners starts on the «My Miners» screen; otherwise always the Welcome start screen. true → вернувшийся авторизованный пользователь с майнерами стартует на экране «My Miners»; иначе всегда стартовый экран Welcome.
utm-source stringстрока unsetне задан UTM source tag, forwarded to analytics / the order. UTM-метка источника, пробрасывается в аналитику/заказ.
utm-campaign stringстрока unsetне задан UTM campaign tag. UTM-метка кампании.
force-mobile boolean attribute | false boolean-атрибут | false auto (by user-agent)авто (по user-agent) Override of mobile behavior (e.g. payment in the same tab). Usually only needed for tests / the demo stand — partners omit it. Override мобильного поведения (например, оплата в том же табе). Обычно нужен только для тестов/демо-стенда — партнёры опускают.
FrontendФронтенд

EventsСобытия

The widget emits DOM CustomEvents on the <gomining-widget> element itself. The payload lives in event.detail. Event names are in camelCase (as with Angular Elements outputs).

Виджет эмитит DOM-события CustomEvent на самом элементе <gomining-widget>. Полезная нагрузка лежит в event.detail. Имена событий — в camelCase (как у Angular Elements output'ов).

Subscribing to an eventПодписка на событие
const widget = document.querySelector('gomining-widget');

widget.addEventListener('purchaseComplete', (e) => {
  console.log(e.detail); // { orderId, thAmount, minerId }
});
EventСобытие event.detail WhenКогда
widgetReady {} Widget initialized, config valid, ready for interaction. Виджет инициализирован, конфиг валиден, готов к взаимодействию.
authComplete { userId, isNewUser, hasMiners }
(string, boolean, boolean)
User authenticated.Пользователь авторизован.
purchaseComplete { orderId, thAmount, minerId }
(string, number, string)
Miner purchase completed successfully.Покупка майнера успешно завершена.
purchaseError { orderId, errorCode }
(string, string)
Purchase failed.Покупка завершилась ошибкой.
paymentRedirect { orderId, paymentUrl, provider }
(string, string, string)
The widget leaves for the payment gateway.Виджет уходит на платёжный шлюз.
dashboardRedirect { transferToken } (string) «Go to dashboard» — handoff to the main GoMining app. «Перейти в кабинет» — handoff в основное приложение GoMining.
backToSite {} User pressed «back/close» on the start screen — return them to your site. Пользователь нажал «назад/закрыть» на стартовом экране — вернуть на свой сайт.
widgetError { code, message } (string, string) Config / widget error. Codes: invalid_partner_id, missing_sign_token, etc. Ошибка конфигурации/виджета. Коды: invalid_partner_id, missing_sign_token и др.
TODO
(depends on backendзависит от бэкенда) the exact payload contracts are still being finalized. In particular authComplete is not emitted yet until /auth/init starts returning the user fields (see TODO(PNP-AUTH) in the code). The production WebSocket host for realtime purchase notifications is also confirmed separately. точные контракты payload'ов ещё финализируются. В частности authComplete пока не эмитится до тех пор, пока /auth/init не начнёт возвращать поля пользователя (см. TODO(PNP-AUTH) в коде). Прод-хост WebSocket для realtime-уведомлений о покупке также подтверждается отдельно.
FrontendФронтенд

Theming & Shadow DOMТемизация и Shadow DOM

  • The theme attribute = light | dark. If unset, the widget follows the OS theme (prefers-color-scheme) and reacts to its change live.
  • The widget sets the result on its host as data-theme; all colors come from the GoMining DS --gm-* design tokens.
  • Shadow DOM isolation: your site's styles do not enter the widget, and its styles do not leak out. You don't need to reset or zero anything on your side.
  • Атрибут theme = light | dark. Если не задан — виджет следует системной теме ОС (prefers-color-scheme) и реагирует на её смену вживую.
  • Виджет ставит результат на свой host как data-theme; все цвета берутся из дизайн-токенов --gm-* GoMining DS.
  • Shadow DOM изоляция: стили вашего сайта не попадают внутрь виджета, а его стили не протекают наружу. Не нужно ничего сбрасывать/обнулять на своей стороне.
FrontendФронтенд

Size & heightРазмер и высота

The widget size is set from the outside — by the container or an inline style, not by an attribute. The widget stretches to its parent; width drives responsiveness (a narrow container → mobile layout).

Размер виджета задаётся снаружи — контейнером или inline-стилем, а не атрибутом. Виджет растягивается по родителю; ширина управляет адаптивом (узкий контейнер → мобильная раскладка).

  • Minimum height: the --gm-widget-min-height CSS variable on the element (default 380px). For example: <gomining-widget style="--gm-widget-min-height: 640px">.
  • Or set the container/element height directly via style="width:…;height:…" or a CSS class.
  • Минимальная высота: CSS-переменная --gm-widget-min-height на элементе (дефолт 380px). Например: <gomining-widget style="--gm-widget-min-height: 640px">.
  • Либо задайте высоту контейнера/элемента напрямую через style="width:…;height:…" или CSS-класс.
Controlling the heightУправление высотой
<!-- via the minimum-height CSS variable -->
<gomining-widget
  partner-id="your-partner-id"
  sign-token="…"
  style="--gm-widget-min-height: 640px"></gomining-widget>
FrontendФронтенд

Authentication: Flow A vs Flow BАвторизация: Flow A vs Flow B

The widget authenticates the user via the sign-token you generate on your backend. Which token the GoMining server returns in response to the sign-token determines the scenario:

Виджет авторизует пользователя через sign-token, который вы генерируете на своём бэкенде. То, какой токен вернёт сервер GoMining в ответ на sign-token, определяет сценарий:

Flow A — auto sign-in (known user)Flow A — авто-вход (известный пользователь)

The email from the sign-token already exists in the system → the backend returns a session (pnpToken) immediately. The user enters no code — they go straight into the purchase flow (or to «My Miners» when profile is set).

Email из sign-token уже существует в системе → бэкенд возвращает сессию (pnpToken) сразу. Пользователь не вводит код — попадает прямо в флоу покупки (или на «My Miners» при profile).

Flow B — email + OTP (new user)Flow B — email + OTP (новый пользователь)

The email is new → the backend returns a partnerToken, and at the purchase step the widget asks for a one-time code (OTP) sent to the email. After confirmation a session is created.

Email новый → бэкенд возвращает partnerToken, и виджет на шаге покупки запрашивает одноразовый код (OTP), отправленный на email. После подтверждения создаётся сессия.

In both cases the partner passes the same sign-token; the A/B branch is decided by the GoMining backend. The widget needs no passwords — it neither stores nor shows credentials.

В обоих случаях партнёр передаёт один и тот же sign-token; ветвление A/B решает бэкенд GoMining. Виджету не нужны пароли — он не хранит и не показывает учётные данные.