Skip to content

Внешние мерчанты (/ext)

Динамический роутинг внешних уведомлений и покупок:

  • Путь: /ext/:api_type/:merchant/:action
  • Поддержка методов: GET и POST (зависит от мерчанта)
  • Авторизация: выполняется обработчиком мерчанта (подпись/секреты), пользователь не требуется

merchant в URL — это ключ профиля из infrastructure.platforms.<api_type>.merchant_profiles. Например, /ext/32/xsolla_ptr/token использует профиль xsolla_ptr, а /ext/32/xsolla/token сопоставляется с merchant_profiles.default, если отдельный ключ xsolla не задан.

Мерчанты и действия

  • exe:
    • buy: action=get_item|buy_item, параметры form или query, подпись sig (MD5 отсортированных полей + secret_key)
  • fs:
    • buy: form priceFmCents, itemId, transactionId, userId, sig (MD5)
  • gm:
    • buy: query merchant_param (JSON c item_id), sum, tid, uid, sign (MD5)
  • mm:
    • buy: query mailiki_price, service_id, transaction_id, uid, sig (MD5)
  • vk:
    • buy: form или query notification_type, user_id|receiver_id, order_id, item, item_price, sig (MD5)
    • subscription: form или query notification_type=subscription_status_change, status=active|cancelled, subscription_id, item_id, item_price, sig (MD5)
  • ok:
    • buy: query amount, product_code, transaction_id, uid, sig (MD5). Ошибки - XML (Invocation-error: 2, <error_code>2</error_code>)
    • refund: query amount, product_code, transaction_id, uid, sig (MD5); создаёт транзакцию типа refund
  • beeline:
    • buy: JSON {id,status,productId,price,phone,externalId}; при status=success создаёт транзакцию
  • dr:
    • buy: query price, sid, id, uid; ответы "OK"/"RETRY"
  • play_deck:
    • buy: JSON payment.successful, payment.externalId (<product_id>|<tx>), payment.amount, payment.telegramId
  • mobage:
    • buy: form-параметры; дискриминатор cmd = getItemInfo|updateInventory (buyer_sns_id, sku_id, sku_unit_price, order_id). Входящая авторизация — платформенная OAuth-верификация; подпись ответа signature — HMAC-SHA1
  • orbit:
    • buy: query item_id, tg_id, tx_id; подпись ed25519 в query-параметре signature (base64url без паддинга). Подписываемая строка — отсортированные пары key=value (кроме signature), склеенные через \n; проверяется публичным ключом платформы
  • fb (Facebook):
    • data_deletion: POST signed_request (GDPR-callback); возвращает url + confirmation_code
    • buy: POST-webhook ack
  • xsolla:
    • webhook: заголовок Authorization: Signature <sha1(body+webhook_secret)> (плоский SHA1, не HMAC); notification_type = user_validation|payment|refund|create_subscription|cancel_subscription|update_subscription|order_paid
    • token: JSON с api_type, api_uid -> проксирует запрос к Xsolla

Подписи (кратко)

Общий шаблон для exe/fs/gm/mm/vk/ok: берутся все параметры запроса (кроме поля подписи), сортируются по ключу, склеиваются как key=value (без разделителей), в конец дописывается секрет, и от строки берётся MD5.

  • exe: sig = md5(concat(sorted("key=value")) + secret_key) над параметрами (form или query)
  • fs: sig = md5(concat(sorted("key=value")) + secret_key) над form-параметрами (исключая sig)
  • gm: sign = md5(concat(sorted("key=value")) + secret_key) над query-параметрами (исключая sign)
  • mm: sig = md5(concat(sorted("key=value")) + secret_key) над query-параметрами (исключая sig)
  • vk: sig = md5(concat(sorted("key=value")) + secret_key) над form-параметрами (исключая sig)
  • ok: sig = md5(concat(sorted("key=value")) + secret_key) над query-параметрами (исключая sig)
  • mobage: входящий запрос проверяется платформенной OAuth-верификацией (VerifyAuthToken); подпись ответа — HMAC-SHA1 над RFC3986-нормализованной строкой параметров (signature)
  • orbit: ed25519.Verify(public_key, join(sorted("key=value"), "\n"), base64url_raw(signature)) над query (исключая signature)
  • fb: Facebook signed_requestHMAC-SHA256(payload, app_secret) сверяется с подписью из запроса
  • xsolla: Webhook — плоский sha1(body + webhook_secret) (не HMAC) в заголовке Authorization: Signature <hex>

Важно: конкретный набор полей и порядок могут отличаться; см. отдельные обработчики interfaces/api/controllers/ext/merchant_*.go.

Проверка конфигурации

Маршрут отклоняется (404), если мерчант не включён для указанного api_type в конфигурации infrastructure.platforms.<api_type> (см. основной конфиг).

Коды/ответы (важные случаи)

  • gm/mm: {"error_code":700,"status":2} при ошибке подписи; {"error_code":703,"status":2} при неверной цене
  • vk: {"error":{"error_code":10|11|21,"critical":true}}
  • ok: XML‑ошибки с Invocation-error: 2
  • exe: {"error":{"code":10|11|20}} либо {"response":{"order_id":...}}
  • mobage: {"returnCode":"OK|ERROR","returnMessage":"..."} + signature

Traffic Flows Webhook

  • Путь: POST /ext/traffic-flows/webhook
  • Авторизация: если в конфигурации задан app.security.traffic_flow_webhook_secret, запрос должен содержать заголовок X-Webhook-Secret с этим значением; иначе — ответ { "error": "unauthorized" }. Если секрет не задан, заголовок не проверяется.
  • Типы:
    • test_connection - ответ { "ready": true, "traffic_flow": {...} }
    • connected - отмечает участие как connected; ответ { "connected": true }
    • completed - создаёт сообщение и отмечает участие как completed. Ответ { "completed": true, "awarded": true }, если награда была выдана; { "completed": true } (без awarded), если награда уже была выдана ранее.
  • Поиск флоу: по key среди включённых OUTGOING.