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Зона ответственности партнёра
- generate a
signTokenper session (Backend → signToken); - receive a conversion webhook on success/failure (Backend → webhooks);
- embed the widget (Frontend → embedding).
- генерировать
signTokenна каждую сессию (Бекенд → signToken); - принимать вебхук о конверсии при успехе/ошибке (Бекенд → вебхуки);
- встроить виджет (Фронтенд → встраивание).
Everything else needs no partner work.
Всё остальное не требует работы со стороны партнёра.
Integration at a glanceИнтеграция в двух словах
Four phases, in order.
Четыре этапа по порядку.
PhasesЭтапы
-
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. -
Backend —
signTokengeneration + a conversion-webhook receiver. - Frontend — embed the widget.
- Test & go live — security + go-live checklist.
-
Онбординг — разовая настройка: сгенерировать пару
RSA-ключей, отправить в GoMining публичный ключ + URL вебхука + список
майнеров для продажи, получить свой
partnerId+ окружения + секрет подписи вебхуков. -
Бэкенд — генерация
signToken+ приёмник вебхука о конверсии. - Фронтенд — встроить виджет.
- Тест и запуск — безопасность + чек-лист запуска.
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 их проверять.
# 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) |
The SPKI public key from "Generate an RSA key pair". Never the private key. Публичный ключ SPKI из «Сгенерируйте пару RSA-ключей». Никогда не приватный. |
|
Webhook endpoint URL |
HTTPS endpoint that receives the webhooks. HTTPS-эндпоинт, принимающий вебхуки. |
|
Miners to offer |
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 включает виджет после завершения онбординга.
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.
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.
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 |
String UUID — your partner identifier. Строка UUID — идентификатор партнёра. |
jti |
String, unique per token (UUID). Single-use — reuse is rejected. Строка, уникальная на токен (UUID). Одноразовый — повторное использование отклоняется. |
email |
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 мин).
|
{
"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
iatmay 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 install jsonwebtoken
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)
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.
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
<!-- 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>
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 будет подтверждён отдельно (есть открытый
бэкенд-вопрос по хостингу бандла).
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 |
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 |
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 мобильного поведения (например, оплата в том же табе). Обычно нужен только для тестов/демо-стенда — партнёры опускают. |
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'ов).
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
и др.
|
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-уведомлений о покупке также подтверждается отдельно.
Theming & Shadow DOMТемизация и Shadow DOM
-
The
themeattribute =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 изоляция: стили вашего сайта не попадают внутрь виджета, а его стили не протекают наружу. Не нужно ничего сбрасывать/обнулять на своей стороне.
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-heightCSS variable on the element (default380px). 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-класс.
<!-- via the minimum-height CSS variable --> <gomining-widget partner-id="your-partner-id" sign-token="…" style="--gm-widget-min-height: 640px"></gomining-widget>
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. Виджету не
нужны пароли — он не хранит и не показывает учётные данные.