Гайд оператора
Содержание
Гайд ведёт от пустого сервера до первой продажи, а затем описывает ежедневную работу: заказы, возвраты, баланс, бэкапы, обновления. На настройку заложите час. Большая часть этого часа уходит на ожидание оптового аккаунта и DNS-записи.
Другие документы: обзор · гайд для агентов · онбординг · интеграции · SDK
1. Что вы поднимаете
https://esim.example.com
│
Caddy (80, 443, Let's Encrypt)
┌───────────────┼──────────────────────────────┐
│ │ │
store rails (/agents/*) node (/.well-known/ai-market.json, /ai-market/*)
покупают люди покупают агенты по x402 хабы находят ваши предложения
│ │
└──── ваш баланс в eSIM Access ────┘ платежи идут на ваши кошельки
- store — сайт: страницы стран, оплата, страница заказа с QR-кодом.
- rails — узел продавца для ИИ-агентов: бесплатные предложения, платные заказы по x402.
- node — это
aimarket node. Он сообщает хабам AIMarket, что вы продаёте, чтобы агенты вас нашли. Запускайте его последним, когда всё остальное работает. - Caddy получает и продлевает HTTPS-сертификат и раздаёт запросы трём сервисам.
store и rails покупают с одного оптового аккаунта. Ни один из них не держит деньги: покупатели платят на ваши адреса, а кит только читает сети, чтобы увидеть поступление.
2. Перед началом
| Что нужно | Примечание |
|---|---|
| Аккаунт в eSIM Access | Регистрация на esimaccess.com. Шаг 3. |
| От $50 на балансе | Первое пополнение — минимум $50 (карта, PayPal или Alipay; банковский перевод — от $3000). |
| Сервер на Linux | Docker Engine с плагином compose, публичный IPv4-адрес, открытые порты 80 и 443. Хватит 1 vCPU и 1 ГБ памяти. |
| Домен или поддомен | Например esim.example.com, с A-записью на сервер. |
| Адреса кошельков | EVM (один адрес на все семь EVM-сетей), Tron, Solana, TON. Подойдёт любой набор. |
| Условия продажи и политика конфиденциальности | Две публичные страницы. eSIM Access ждёт, что сайт каждого реселлера на них ссылается. |
| Необязательно: ключ Coinbase Developer Platform | Включает USDC в Base без газа для людей и заказы агентов по x402. Шаг 8. |
| Необязательно: Stripe | Включает карты. Шаг 8. |
3. Оптовый аккаунт
- Зарегистрируйтесь на esimaccess.com и подтвердите почту.
- Пополните баланс (в консоли: баланс, затем пополнение). Минимум — $50. Каждая проданная eSIM оплачивается с этого баланса по оптовой цене, так что это ваш товарный запас, а не комиссия.
- Откройте раздел разработчика (API) в консоли. Там два значения: AccessCode и SecretKey. Обращайтесь с SecretKey как с паролем.
Песочницы нет: каждый заказ через API настоящий. Два способа проверить дёшево:
- Закажите самый дешёвый тариф (несколько десятков центов) и отмените неиспользованный профиль. Неиспользованные профили возвращаются на баланс.
- До первого пополнения попросите в поддержке небольшой тестовый кредит: Customer Support, затем Submit ticket, тип «Top Up». Объясните, что подключаете API и вам нужно несколько долларов на тестовые заказы.
4. Сервер и домен
- Создайте A-запись домена на IPv4-адрес сервера. Проверьте со своего компьютера:
dig +short esim.example.com
- Установите Docker на сервер (docs.docker.com/engine/install) и проверьте, что compose работает:
docker compose version
- Откройте порты 80 и 443 в файрволе сервера и в панели хостинга. Let's Encrypt проверяет порт 80, прежде чем выдать сертификат.
5. Скачайте кит и настройте его
git clone https://github.com/alexar76/esim-operator-kit.git
cd esim-operator-kit
cp .env.example .env
nano .env
| Настройка | Что указать |
|---|---|
DOMAIN | Ваш домен, без https://. |
STORE_NAME | Название, которое покупатели видят в шапке, заголовке и в окне кошелька. |
PRODUCT_ID | Короткий идентификатор ваших предложений в федерации, например esim-mytravel. Буквы, цифры, дефисы. |
STORE_CONTACT | Почта, на которую пишут покупатели. Показывается в подвале. |
STORE_TERMS_URL, STORE_PRIVACY_URL | Ваши условия продажи и политика конфиденциальности. Ссылки стоят в подвале. |
MARGIN_PCT | Наценка на оптовую цену в процентах. 100 удваивает цену. |
MIN_MARGIN_USD | Минимальная наценка на одну eSIM в долларах. К дешёвым тарифам добавляется не меньше этой суммы. |
DEMO_MODE | 1 — баннер и никаких платежей. 0 — продажа. Держите 1 до шага 10. |
PAY_TO_EVM, PAY_TO_TON, PAY_TO_TRON, PAY_TO_SOLANA | Ваши адреса для приёма. Пустая строка выключает сеть. |
EVM_CHAINS | Какие EVM-сети предлагать, номерами сетей: 8453 Base, 1 Ethereum, 42161 Arbitrum, 10 OP, 137 Polygon, 56 BNB Chain, 43114 Avalanche. |
EVM_RPC_<номер сети>, SOLANA_RPC | Необязательно: ваши RPC-адреса. У публичных есть лимиты запросов. |
SUPPLIER | Откуда берутся eSIM: esimaccess (по умолчанию), airalo, esimgo или http для вашей собственной системы. См. интеграции. |
WEBHOOK_URL, WEBHOOK_SECRET_FILE | Необязательно: статус каждого заказа, с подписью, в вашу CRM, биллинг, Telegram или таблицу. См. интеграции. |
Как считается цена. Цена = опт × (1 + MARGIN_PCT/100), но не меньше опт + MIN_MARGIN_USD. Округление — вверх до цента. С настройками по умолчанию (100 % и $1.00) Франция 1 ГБ на 7 дней стоит $0.70 оптом и продаётся за $1.70. Тариф на 20 ГБ за $9.00 оптом продаётся за $18.00. Розничные eSIM-магазины обычно берут $4–8 за маленькие тарифы, так что запас есть.
Только адреса. Каждый PAY_TO_* — адрес, на который вы принимаете. Киту никогда не нужен приватный ключ или сид-фраза. Если инструкция или человек просит положить их в .env, это ошибка.
6. Положите ключи
Ключи лежат в secrets/, по одному значению в файле. Папка исключена из git и монтируется в контейнеры только для чтения. Введите значения так, чтобы они не попали в историю команд:
cd ~/esim-operator-kit
umask 077
printf 'AccessCode: '; read -rs v; printf %s "$v" > secrets/esimaccess_access_code; echo
printf 'SecretKey: '; read -rs v; printf %s "$v" > secrets/esimaccess_secret_key; echo
unset v
Контейнеры работают от пользователя 1000, поэтому отдайте ему файлы ключей и папки данных:
mkdir -p data/store data/rails data/node data/caddy
sudo chown 1000:1000 secrets/*
sudo chown -R 1000:1000 data/store data/rails data/node
ls -l secrets
Сама папка остаётся вашей, так что файлы можно добавлять и позже. Каждому новому файлу ключа нужны те же sudo chown 1000:1000 и chmod 600.
В secrets/README.md перечислены все необязательные файлы: ключ CDP, ключи tonapi и TronGrid, ключи Stripe.
7. Запуск в демо-режиме
docker compose up -d --build
docker compose ps
docker compose logs --tail 30 store rails
Первая сборка занимает несколько минут. Затем проверьте три вещи:
curl -s https://esim.example.com/agents/healthz
curl -s -X POST https://esim.example.com/agents/quote -H 'content-type: application/json' \
-d '{"country":"FR","min_gb":3,"min_days":7,"limit":3}'
- Проверка здоровья отвечает
"ok":trueи показывает число предложений, у eSIM Access их около 1700."demo":trueпока ожидаемо. - Запрос предложений возвращает настоящие тарифы по вашим ценам.
https://esim.example.com/показывает вашу витрину с демо-баннером. Откройте страну и пройдите оплату: каждый шаг оплаты отвечает «Демо-режим: оплата отключена».
Если проверка отвечает "ok":false, оптовые ключи неверны или не читаются. См. раздел 14.
Проверьте цены. Команда печатает баланс и лучшие предложения по любым странам с вашей наценкой, рядом с каждым — оптовая цена:
docker compose exec -T rails node scripts/catalog.mjs FR ES IT US JP TH
Поменяйте MARGIN_PCT или MIN_MARGIN_USD в .env и примените: docker compose up -d.
8. Платежи
Каждый способ включается, когда задан его адрес (и ключ, где он нужен). Включите те, которыми пользуются ваши покупатели. USDT в Tron — самый частый способ платить криптой; за ним идут USDT и USDC в EVM-сетях и USDT в TON.
| Способ | Что задать | Как платит покупатель | Как витрина подтверждает |
|---|---|---|---|
| USDC в Base без газа | PAY_TO_EVM + secrets/cdp_api_key.json | Подписывает одно сообщение в браузерном кошельке и не платит за газ. | Подпись проводит фасилитатор CDP. Сначала выдаётся eSIM, потом проводится платёж; если проведение не удалось, eSIM отменяется. |
| USDC / USDT в 7 EVM-сетях | PAY_TO_EVM (+ EVM_CHAINS) | Отправляет перевод из браузерного кошелька или из любого кошелька или биржи и вставляет хеш транзакции. | Читает квитанцию: перевод этого токена вам, не меньше цены, новее заказа. Ждёт подтверждений: 3 в Ethereum и BNB Chain, 10 в Polygon, 1 в остальных. Одна транзакция оплачивает один заказ. |
| USDT в Tron | PAY_TO_TRON (+ secrets/trongrid_key) | Отправляет ровно указанную сумму, из TronLink на странице или из любого кошелька. | Каждый заказ просит цену плюс несколько миллионных долларов (не больше $0.0099 сверху). Эта точная сумма и опознаёт заказ среди ваших подтверждённых переводов USDT. |
| USDC в Solana | PAY_TO_SOLANA (+ SOLANA_RPC) | Открывает ссылку Solana Pay или сканирует её QR-код (Phantom, Solflare, Backpack). | У каждого заказа свой ключ-референс, кошелёк добавляет его в перевод. Витрина находит транзакцию по нему. |
| USDT или TON в TON | PAY_TO_TON (+ secrets/tonapi_key) | Подключает Tonkeeper или другой кошелёк через TON Connect либо платит вручную с указанным комментарием. | Находит перевод по комментарию заказа через tonapi.io. |
| Карты | secrets/stripe_secret_key + secrets/stripe_webhook_secret | Stripe Checkout. | Вебхук Stripe. |
Отправленный платёж (все способы, кроме Base без газа и карт) ищется в течение 24 часов после создания заказа.
Ключ Coinbase Developer Platform. Он включает USDC в Base без газа для людей и заказы агентов по x402. Без него витрина всё равно принимает USDC в Base обычным переводом, но узел для агентов заказы не принимает.
- Войдите на portal.cdp.coinbase.com и создайте проект.
- API Keys: создайте секретный API-ключ и скачайте его JSON-файл.
- Скопируйте файл в
secrets/cdp_api_key.json(в нёмidиprivateKey), затем выполнитеsudo chown 1000:1000 secrets/cdp_api_key.json && sudo chmod 600 secrets/cdp_api_key.jsonиdocker compose up -d.
Stripe. В панели Stripe добавьте вебхук https://<ваш домен>/api/stripe/webhook с событиями checkout.session.completed и checkout.session.async_payment_succeeded. Секретный ключ (sk_live_…) положите в secrets/stripe_secret_key, а секрет подписи вебхука (whsec_…) — в secrets/stripe_webhook_secret.
Лимиты запросов. Публичных TronGrid, tonapi и RPC хватает небольшому магазину. Когда продажи станут регулярными, добавьте бесплатный ключ TronGrid и ключ tonapi, а EVM_RPC_<номер> и SOLANA_RPC направьте на своего провайдера.
9. Агенты и федерация
Узел rails уже отвечает агентам по адресу https://<ваш домен>/agents/. Чтобы агенты находили вас поиском на хабе, опишите узел для федерации и анонсируйте его.
- Сгенерируйте
node.tomlиз живого каталога. Подставьте своё название, домен иPRODUCT_ID:
docker compose exec -T rails node scripts/node-toml.mjs \
--name "My Travel eSIM" --url https://esim.example.com \
--product esim-mytravel --upstream http://rails:9490 > node.toml
head -20 node.toml
- Запустите узел:
docker compose --profile federation up -d --build node
curl -s https://esim.example.com/.well-known/ai-market.json | head -c 400; echo
- Проверьте его так, как проверит хаб, и анонсируйте:
docker compose exec node aimarket doctor --url https://esim.example.com
docker compose exec node aimarket node knock --config /node/node.toml --hub https://modelmarket.dev
Перед тем как внести вас в каталог, хаб вызывает esim.quote с настоящей страной. После этого агент, который ищет на хабе «eSIM France», получает ваши предложения. Оплата никогда не идёт через хаб: агент платит вашему узлу по x402, прямо на ваш кошелёк.
В data/node/ лежит ключ подписи узла — это его идентичность в федерации. Сделайте бэкап. Повторите пункт 1, когда в каталоге появятся новые страны.
10. Тестовый заказ и запуск продаж
- В
.envпоставьтеDEMO_MODE=0и ещё раз сверьте адресаPAY_TO_*символ за символом. - Примените:
docker compose up -d
curl -s https://esim.example.com/agents/healthz
Должно быть "demo":false. "paid_orders":true появляется, когда заданы ключ CDP и PAY_TO_EVM.
- Купите самый дешёвый тариф какой-нибудь страны в своей витрине, своим кошельком, в той сети, которой, по-вашему, чаще всего будут платить покупатели. QR-код должен появиться на странице заказа в течение минуты.
- Проверьте платёж в кошельке и заказ в консоли eSIM Access.
- Если eSIM вам не нужна, отмените неиспользованный профиль в консоли eSIM Access. Оптовая цена вернётся на баланс. Ваш платёж всё равно ушёл на ваш же кошелёк.
Повторите для каждой включённой сети. После этого вы в деле.
11. Ежедневная работа
Заказы. Витрина хранит их в data/store/orders.json. Список тех, что требуют вашего внимания:
sudo jq -r '.[] | select(.status=="refund_due" or .status=="underpaid")
| [.created_at, .id, .status, .method, (.price_cents/100), .payment.ref, (.payment.payer // "-"), (.error // "")] | @tsv' \
data/store/orders.json
| Статус | Значение | Что делать |
|---|---|---|
awaiting_payment | Заказ создан, денег пока нет. | Ничего. |
delivered | Оплачен, eSIM у покупателя. | Ничего. |
refund_due | Оплачен, но оптовик не выдал eSIM: кончился баланс или тариф сняли с продажи. | Верните деньги покупателю на payment.payer в той же сети или пополните баланс и продайте ему тариф вручную. |
underpaid | Пришло меньше цены. | Верните платёж или попросите покупателя доплатить и выдайте вручную. |
expired | За 24 часа ничего не пришло. | Ничего. Платёж, пришедший позже, не сопоставляется: вы увидите его в кошельке без заказа. |
Покупатели пишут на STORE_CONTACT. Просите у них номер заказа из адреса страницы (/o/<номер>). Не просите полную ссылку: в ней их токен.
Баланс. Держите оптовый баланс выше продаж за несколько дней. Когда его не хватает на заказ, оплата пишет «Тариф временно недоступен» и не берёт деньги. Проверить баланс:
docker compose exec -T rails node scripts/catalog.mjs | head -1
Логи.
docker compose logs -f --tail 100 store rails
В логах никогда нет кодов активации и ключей.
Бэкапы. Ежедневно сохраняйте data/ и secrets/ куда-нибудь вне сервера:
data/store/: заказы. Потеряете их — страницы заказов у покупателей перестанут работать.data/rails/: заказы агентов, ключ их статус-токенов и ключ подписи узла.data/node/: идентичность в федерации.data/caddy/: сертификаты. Их можно выпустить заново, но бэкап избавит от лимитов Let's Encrypt.
Обновления.
git pull
docker compose up -d --build
docker compose --profile federation up -d --build node # если запускаете узел федерации
Читайте заметки к выпуску, прежде чем обновлять магазин, который продаёт.
12. Заказы агентов
Агенты покупают через POST /agents/order (см. гайд для агентов). Узел проверяет платёж x402, покупает профиль и проводит платёж только после того, как профиль создан. Если проведение не удалось, профиль отменяется, а оптовая цена возвращается на баланс. Заказы агентов записываются в data/rails/orders.json, без кодов активации. USDC приходят на PAY_TO_EVM в сети Base.
13. Законы, налоги и условия
Это не юридическая и не налоговая консультация. Прежде чем продавать, спросите бухгалтера в своей стране.
- Продавец — вы. Покупатели покупают у вас, на ваших условиях. eSIM Access — ваш поставщик. Возвраты, поддержка и налоги — ваши.
- Условия и конфиденциальность. eSIM Access ждёт, что на вашем сайте опубликованы условия продажи и политика конфиденциальности. Задайте
STORE_TERMS_URLиSTORE_PRIVACY_URL. В условиях опишите возвраты (установленную eSIM обычно вернуть нельзя), совместимость устройства (разблокированный телефон с поддержкой eSIM) и момент начала действия. - НДС в ЕС. Телекоммуникационные услуги потребителям облагаются в стране покупателя. Единое окно OSS (One-Stop Shop) позволяет декларировать все страны ЕС одной декларацией. Вне ЕС правила другие.
- Крипта. Можно ли принимать криптовалюту и как её учитывать, зависит от вашей страны. Храните записи заказов: у витрины есть сеть, транзакция и сумма каждого платежа.
- Персональные данные. Витрина ничего не спрашивает у покупателей: ни имени, ни почты. Она хранит заказ (тариф, цена, способ) и платёж (транзакция и адрес плательщика). Адрес в блокчейне всё же может считаться персональными данными по GDPR, так что упомяните его в политике конфиденциальности.
14. Решение проблем
| Что видно | Причина | Что делать |
|---|---|---|
| Браузер говорит, что сертификат недействителен | DNS ещё не указывает сюда или закрыт порт 80 | dig +short <домен>, откройте порт 80, затем docker compose restart caddy и смотрите docker compose logs caddy. |
healthz показывает "ok":false или на витрине нет стран | Оптовые ключи неверны или пользователь 1000 не может их прочитать. В логах catalogue not loaded yet: <code>. | sudo rm secrets/esimaccess_*, запишите их заново, как в шаге 6, затем docker compose restart store rails. |
В логах EACCES или permission denied | Папки данных принадлежат не пользователю 1000 | sudo chown -R 1000:1000 data/store data/rails data/node |
| Оплата пишет «Тариф временно недоступен» | Оптового баланса не хватает на тариф | Пополните eSIM Access. |
| Каждый платёж отвечает «Демо-режим: оплата отключена» | DEMO_MODE=1 | Шаг 10. |
| Сети нет в оплате | Её PAY_TO_* пустой | Проверьте .env, затем docker compose up -d. |
| Витрина перезапускается снова и снова | Какой-то PAY_TO_* — неверный адрес: с ним витрина отказывается стартовать | docker compose logs store назовёт его. Исправьте .env. |
| Платёж в Tron не найден | Сумма была не точной, часто потому что биржа вычла из неё свою комиссию | Найдите перевод в кошельке и верните его или выдайте вручную. Просите покупателей отправлять точную сумму из кошелька. |
| Платёж в TON не найден | Комментарий не указан или изменён | Так же, как выше. С TON Connect кошелёк подставляет комментарий сам. |
aimarket doctor сообщает о приватном адресе | url в node.toml — не ваш публичный домен | Сгенерируйте node.toml заново (шаг 9) с --url https://<домен>. |
node не стартует: node.toml — это папка | Compose создал её, потому что файла не было | rmdir node.toml, сгенерируйте файл (шаг 9), запустите снова. |