feat: add PayKilla payment provider
This commit is contained in:
@@ -16,7 +16,7 @@ Remnawave Minishop - Telegram-бот и Web App (Mini App) для продажи
|
||||
- Web App / Mini App с входом через Telegram или email;
|
||||
- встроенные инструкции установки в Mini App: личный экран `/install` и публичная ссылка `/s/<token>` для передачи инструкции;
|
||||
- пробный период, промокоды и реферальная программа;
|
||||
- оплата через YooKassa, FreeKassa, Platega, SeverPay, Wata, CryptoPay, Heleket и Telegram Stars;
|
||||
- оплата через YooKassa, FreeKassa, Platega, SeverPay, Wata, CryptoPay, Heleket, PayKilla и Telegram Stars;
|
||||
- тикеты поддержки в Web App и внешняя ссылка на поддержку;
|
||||
- раздел "Мои устройства" при включенном `MY_DEVICES_SECTION_ENABLED`.
|
||||
|
||||
|
||||
@@ -369,7 +369,7 @@ SETTINGS_MANIFEST: List[SettingField] = [
|
||||
"string",
|
||||
"payments",
|
||||
"Порядок методов оплаты",
|
||||
"Через запятую: severpay,freekassa,yookassa,platega,stars,cryptopay,heleket",
|
||||
"Через запятую: severpay,freekassa,yookassa,platega,stars,cryptopay,heleket,paykilla",
|
||||
subsection="common",
|
||||
),
|
||||
# ─── Trial ─────────────────────────────────────────────────────
|
||||
|
||||
File diff suppressed because it is too large
Load Diff
@@ -2,7 +2,7 @@ from __future__ import annotations
|
||||
|
||||
from typing import Any, Dict, Iterable, List, Mapping, Optional
|
||||
|
||||
from . import cryptopay, freekassa, heleket, platega, severpay, stars, wata, yookassa
|
||||
from . import cryptopay, freekassa, heleket, paykilla, platega, severpay, stars, wata, yookassa
|
||||
from .base import (
|
||||
PaymentProviderPresentation,
|
||||
PaymentProviderSpec,
|
||||
@@ -21,6 +21,7 @@ PAYMENT_PROVIDER_SPECS: tuple[PaymentProviderSpec, ...] = (
|
||||
stars.SPEC,
|
||||
cryptopay.SPEC,
|
||||
heleket.SPEC,
|
||||
paykilla.SPEC,
|
||||
)
|
||||
|
||||
|
||||
|
||||
@@ -14,6 +14,7 @@ class PaymentContextMixin:
|
||||
"severpay": "SeverPay",
|
||||
"wata": "Wata",
|
||||
"cryptopay": "Crypto Pay",
|
||||
"paykilla": "PayKilla",
|
||||
"telegram_stars": "Telegram Stars",
|
||||
}
|
||||
|
||||
|
||||
@@ -305,7 +305,7 @@ class Settings(BaseSettings):
|
||||
STARS_ADMIN_ONLY_ENABLED: bool = Field(default=False)
|
||||
PAYMENT_METHODS_ORDER: Optional[str] = Field(
|
||||
default=None,
|
||||
description="Comma-separated list of payment methods to show (e.g., severpay,wata,freekassa,yookassa,platega,stars,cryptopay)", # noqa: E501
|
||||
description="Comma-separated list of payment methods to show (e.g., severpay,wata,freekassa,yookassa,platega,stars,cryptopay,heleket,paykilla)", # noqa: E501
|
||||
)
|
||||
SUBSCRIPTION_PURCHASE_DESCRIPTION_ENABLED: bool = Field(
|
||||
default=True,
|
||||
@@ -1026,6 +1026,7 @@ class Settings(BaseSettings):
|
||||
"stars",
|
||||
"cryptopay",
|
||||
"heleket",
|
||||
"paykilla",
|
||||
]
|
||||
# Make sure default_order itself includes every registered spec.
|
||||
for sid in spec_ids:
|
||||
|
||||
@@ -75,6 +75,7 @@ SUPPORTED_REMNASHOP_PROVIDER_TYPES = {
|
||||
"TELEGRAM_STARS",
|
||||
"YOOKASSA",
|
||||
"HELEKET",
|
||||
"PAYKILLA",
|
||||
"CRYPTOPAY",
|
||||
"FREEKASSA",
|
||||
"PLATEGA",
|
||||
@@ -93,6 +94,7 @@ PAYMENT_WEBHOOK_PATHS = {
|
||||
"wata": "/webhook/wata",
|
||||
"cryptopay": "/webhook/cryptopay",
|
||||
"heleket": "/webhook/heleket",
|
||||
"paykilla": "/webhook/paykilla",
|
||||
"freekassa": "/webhook/freekassa",
|
||||
"platega": "/webhook/platega",
|
||||
}
|
||||
@@ -477,6 +479,26 @@ def remnashop_payment_gateway_overrides(
|
||||
)
|
||||
return _provider_mapping_result(gateway_type, ["heleket"], overrides, warnings)
|
||||
|
||||
if gateway_type == "PAYKILLA":
|
||||
_add_override(overrides, "PAYKILLA_ENABLED", active)
|
||||
_add_override(
|
||||
overrides,
|
||||
"PAYKILLA_API_KEY",
|
||||
settings.get("api_key") or settings.get("public_key") or settings.get("publicKey"),
|
||||
)
|
||||
_add_override(
|
||||
overrides,
|
||||
"PAYKILLA_SECRET_KEY",
|
||||
settings.get("secret_key") or settings.get("secretKey"),
|
||||
)
|
||||
if currency and currency != "RUB":
|
||||
warnings.append(
|
||||
f"PayKilla source currency was {currency}; Minishop keeps payment currency "
|
||||
"controlled by tariffs/default currency. Configure PAYKILLA_CURRENCY and "
|
||||
"PAYKILLA_PAYMENT_CURRENCIES manually if this instance needs a different default."
|
||||
)
|
||||
return _provider_mapping_result(gateway_type, ["paykilla"], overrides, warnings)
|
||||
|
||||
if gateway_type == "FREEKASSA":
|
||||
_add_override(overrides, "FREEKASSA_ENABLED", active)
|
||||
_add_override(overrides, "FREEKASSA_MERCHANT_ID", settings.get("shop_id"))
|
||||
@@ -539,6 +561,7 @@ def remnashop_post_migration_actions(
|
||||
"wata": "WATA merchant dashboard -> webhook/callback URL",
|
||||
"cryptopay": "CryptoBot/Crypto Pay app -> webhook URL",
|
||||
"heleket": "Heleket merchant dashboard -> payment webhook/callback URL",
|
||||
"paykilla": "PayKilla Dashboard -> Settings -> Webhooks",
|
||||
"freekassa": "FreeKassa shop settings -> notification/result URL",
|
||||
"platega": "Platega merchant/project settings -> webhook URL",
|
||||
}.get(provider_id, "Payment provider dashboard -> webhook/callback URL"),
|
||||
|
||||
@@ -197,7 +197,7 @@
|
||||
|
||||
| Переменная | Назначение |
|
||||
| --- | --- |
|
||||
| `PAYMENT_METHODS_ORDER` | Порядок кнопок оплаты: `severpay,wata,freekassa,platega,yookassa,stars,cryptopay,heleket`. |
|
||||
| `PAYMENT_METHODS_ORDER` | Порядок кнопок оплаты: `severpay,wata,freekassa,platega,yookassa,stars,cryptopay,heleket,paykilla`. |
|
||||
| `SUBSCRIPTION_PURCHASE_DESCRIPTION_ENABLED` | Показывать описание подписки перед выбором срока. |
|
||||
| `SUBSCRIPTION_PURCHASE_DESCRIPTION_RU` / `SUBSCRIPTION_PURCHASE_DESCRIPTION_EN` | Локализованное описание подписки. |
|
||||
| `PAYMENT_<METHOD>_WEBAPP_LABEL_RU` / `PAYMENT_<METHOD>_WEBAPP_LABEL_EN` | Текст кнопки провайдера в Web App. |
|
||||
@@ -213,6 +213,7 @@
|
||||
| `WATA_ENABLED` | Включает Wata. |
|
||||
| `CRYPTOPAY_ENABLED` | Включает CryptoPay. |
|
||||
| `HELEKET_ENABLED` | Включает Heleket. |
|
||||
| `PAYKILLA_ENABLED` | Включает PayKilla. |
|
||||
|
||||
Конкретные ключи отображения:
|
||||
|
||||
@@ -271,6 +272,12 @@ PAYMENT_HELEKET_WEBAPP_ICON
|
||||
PAYMENT_HELEKET_TELEGRAM_LABEL_RU
|
||||
PAYMENT_HELEKET_TELEGRAM_LABEL_EN
|
||||
PAYMENT_HELEKET_TELEGRAM_EMOJI
|
||||
PAYMENT_PAYKILLA_WEBAPP_LABEL_RU
|
||||
PAYMENT_PAYKILLA_WEBAPP_LABEL_EN
|
||||
PAYMENT_PAYKILLA_WEBAPP_ICON
|
||||
PAYMENT_PAYKILLA_TELEGRAM_LABEL_RU
|
||||
PAYMENT_PAYKILLA_TELEGRAM_LABEL_EN
|
||||
PAYMENT_PAYKILLA_TELEGRAM_EMOJI
|
||||
```
|
||||
|
||||
### YooKassa
|
||||
@@ -357,6 +364,33 @@ PAYMENT_HELEKET_TELEGRAM_EMOJI
|
||||
| `HELEKET_VERIFY_WEBHOOK_SIGNATURE` | Проверять подпись webhook. |
|
||||
| `HELEKET_TRUSTED_IPS` | Список доверенных IP webhook-источников. |
|
||||
|
||||
### PayKilla
|
||||
|
||||
Для приема оплат нужен API key типа **HMAC** с правом **INVOICE**. Право **WITHDRAWAL** для оплаты подписок не требуется; включайте его только для отдельной интеграции выплат.
|
||||
|
||||
Webhook настраивается в PayKilla Dashboard: **Settings -> Webhooks**. Укажите `WEBHOOK_BASE_URL` + `/webhook/paykilla`, например `https://bot.example.com/webhook/paykilla`. Включите события `INVOICE_PAID` и `INVOICE_EXPIRED` как минимум. Рекомендуемый набор галочек: `INVOICE_PAID`, `PAYMENT_COMPLETED`, `PAYMENT_FAILED`, `PAYMENT_OVERPAID`, `PAYMENT_UNDERPAID`, `PAYMENT_PARTIAL`, `INVOICE_EXPIRED`, `COMPLIANCE_FAILED`. Если хотите видеть промежуточные статусы в логах PayKilla, дополнительно включите `INVOICE_CREATED`, `PAYMENT_PENDING`, `TRANSACTION_CONFIRMED` и `TRANSACTION_FINAL`.
|
||||
|
||||
| Переменная | Назначение |
|
||||
| --- | --- |
|
||||
| `PAYKILLA_BASE_URL` | Базовый URL API, по умолчанию `https://account-api.paykilla.com`. |
|
||||
| `PAYKILLA_WIDGET_URL` | URL hosted checkout, по умолчанию `https://gopay.paykilla.com`. |
|
||||
| `PAYKILLA_API_KEY` / `PAYKILLA_V2_API_KEY` | Public HMAC key с правом `INVOICE`. |
|
||||
| `PAYKILLA_SECRET_KEY` / `PAYKILLA_V2_SECRET_KEY` | Secret HMAC key для подписи API-запросов и проверки webhook. |
|
||||
| `PAYKILLA_CURRENCY` | Валюта инвойса. Для RUB/USD/EUR/AED/GBP используется `FIAT_BASED`, для остальных - `FIXED_AMOUNT`. |
|
||||
| `PAYKILLA_PAYMENT_CURRENCIES` | Crypto tickers для оплаты, например `USDTTRC,BTC,ETH`. |
|
||||
| `PAYKILLA_SUPPORTED_CURRENCIES` | Валюты инвойса, разрешенные в этом магазине. |
|
||||
| `PAYKILLA_INVOICE_TYPE` | Необязательный override: `FIAT_BASED`, `FIXED_AMOUNT` или `OPEN_AMOUNT`. |
|
||||
| `PAYKILLA_RETURN_URL` | URL кнопки возврата на checkout-странице. |
|
||||
| `PAYKILLA_SUCCESS_URL` | URL после успешной оплаты; используется с auto-redirect. |
|
||||
| `PAYKILLA_CANCEL_URL` | URL после отмены оплаты. |
|
||||
| `PAYKILLA_LIFETIME_SECONDS` | TTL инвойса, отправляется как `expiredAt`. |
|
||||
| `PAYKILLA_RECV_WINDOW_MS` | `recvWindow` для подписанных API-запросов. |
|
||||
| `PAYKILLA_USER_PAYS_SERVICE_FEE` | `true`, если пользователь оплачивает service fee. |
|
||||
| `PAYKILLA_USER_PAYS_NETWORK_FEE` | `true`, если пользователь оплачивает network fee. |
|
||||
| `PAYKILLA_VERIFY_WEBHOOK_SIGNATURE` | Проверять `X-API-SIGN` по raw body webhook. |
|
||||
| `PAYKILLA_WEBHOOK_URL` | Точный публичный webhook URL для проверки подписи, если он отличается от `WEBHOOK_BASE_URL` + `/webhook/paykilla`. |
|
||||
| `PAYKILLA_TRUSTED_IPS` | Необязательный список доверенных IP webhook-источников. |
|
||||
|
||||
## Тарифы и legacy-цены
|
||||
|
||||
Рекомендуемый способ настройки тарифов - раздел **Система -> Тарифы** в админке. Он сохраняет JSON в `TARIFFS_CONFIG_PATH`.
|
||||
|
||||
@@ -31,6 +31,7 @@
|
||||
| Wata | `WEBHOOK_BASE_URL` + `/webhook/wata` | Если включена проверка подписи, настройте `WATA_WEBHOOK_VERIFY_SIGNATURE` и `WATA_PUBLIC_KEY`. |
|
||||
| CryptoPay | `WEBHOOK_BASE_URL` + `/webhook/cryptopay` | Указывается в настройках Crypto Bot / CryptoPay webhook. |
|
||||
| Heleket | `WEBHOOK_BASE_URL` + `/webhook/heleket` | При необходимости включите `HELEKET_VERIFY_WEBHOOK_SIGNATURE` и `HELEKET_TRUSTED_IPS`. |
|
||||
| PayKilla | `WEBHOOK_BASE_URL` + `/webhook/paykilla` | Указывается в PayKilla Dashboard -> Settings -> Webhooks; включите события оплаты инвойсов. |
|
||||
| Telegram Stars | Отдельный платежный webhook не нужен | Stars-события приходят через webhook Telegram-бота: `WEBHOOK_BASE_URL` + `/tg/webhook`. |
|
||||
|
||||
После настройки сделайте тестовый платеж и проверьте, что в логах `backend` видно входящий `POST` на нужный путь. Если провайдер сообщает, что адрес недоступен, сначала проверьте DNS/HTTPS и reverse proxy для `WEBHOOK_BASE_URL`, затем убедитесь, что путь начинается ровно с `/webhook/...` без `/api`, `/auth` и frontend-домена.
|
||||
@@ -153,6 +154,37 @@ Heleket используется для крипто-инвойсов с отд
|
||||
|
||||
Справочник переменных: [Heleket](../configuration/env-vars.md#heleket).
|
||||
|
||||
## PayKilla
|
||||
|
||||
PayKilla используется для крипто-инвойсов V2 через hosted checkout `https://gopay.paykilla.com/{invoice_id}`. API-запросы подписываются HMAC-SHA256, webhook проверяется по заголовку `X-API-SIGN` и raw body.
|
||||
|
||||
Какие полномочия нужны API key:
|
||||
|
||||
1. В PayKilla Dashboard откройте **Settings -> API keys**.
|
||||
2. Создайте ключ типа **HMAC**.
|
||||
3. Для приема оплат включите permission **INVOICE**.
|
||||
4. Permission **WITHDRAWAL** не нужен для Minishop-платежей; не включайте его без отдельной необходимости выплат.
|
||||
5. Сохраните `publicKey` в `PAYKILLA_API_KEY`, а `secretKey` в `PAYKILLA_SECRET_KEY`.
|
||||
|
||||
Как настроить webhook в PayKilla:
|
||||
|
||||
1. Откройте **Settings -> Webhooks**.
|
||||
2. В URL укажите `WEBHOOK_BASE_URL` + `/webhook/paykilla`, например `https://bot.example.com/webhook/paykilla`.
|
||||
3. Минимальные галочки: `INVOICE_PAID`, `INVOICE_EXPIRED`.
|
||||
4. Рекомендуемые галочки для production: `INVOICE_PAID`, `PAYMENT_COMPLETED`, `PAYMENT_FAILED`, `PAYMENT_OVERPAID`, `PAYMENT_UNDERPAID`, `PAYMENT_PARTIAL`, `INVOICE_EXPIRED`, `COMPLIANCE_FAILED`.
|
||||
5. Опционально включите `INVOICE_CREATED`, `PAYMENT_PENDING`, `TRANSACTION_CONFIRMED` и `TRANSACTION_FINAL`, если нужны промежуточные события в логах.
|
||||
6. Оставьте `PAYKILLA_VERIFY_WEBHOOK_SIGNATURE=True`. Если публичный URL у PayKilla отличается от `WEBHOOK_BASE_URL` + `/webhook/paykilla`, задайте точное значение в `PAYKILLA_WEBHOOK_URL`.
|
||||
|
||||
Что настроить в Minishop:
|
||||
|
||||
1. Включите `PAYKILLA_ENABLED`.
|
||||
2. Укажите `PAYKILLA_API_KEY` и `PAYKILLA_SECRET_KEY`.
|
||||
3. Проверьте `PAYKILLA_CURRENCY` и `PAYKILLA_PAYMENT_CURRENCIES`, например `USDTTRC,BTC,ETH`.
|
||||
4. При необходимости задайте `PAYKILLA_SUCCESS_URL`, `PAYKILLA_RETURN_URL` и `PAYKILLA_CANCEL_URL`.
|
||||
5. Добавьте `paykilla` в `PAYMENT_METHODS_ORDER`, если хотите задать явный порядок кнопок.
|
||||
|
||||
Справочник переменных: [PayKilla](../configuration/env-vars.md#paykilla).
|
||||
|
||||
## Telegram Stars
|
||||
|
||||
Telegram Stars используются напрямую и поддерживаются в legacy-ценах и JSON-каталоге тарифов.
|
||||
|
||||
@@ -46,7 +46,7 @@ App, а не веб-кабинетом Remnashop. В Minishop `SUBSCRIPTION_MINI
|
||||
|
||||
Платежные провайдеры берутся из таблицы Remnashop `payment_gateways`.
|
||||
Поддерживаются и автоматически маппятся: Telegram Stars, YooKassa, WATA,
|
||||
CryptoPay, Heleket, FreeKassa и Platega. Для них importer переносит флаги
|
||||
CryptoPay, Heleket, PayKilla, FreeKassa и Platega. Для них importer переносит флаги
|
||||
включения, API-ключи/merchant IDs и прямые технические параметры, без которых
|
||||
провайдер не сможет работать: YooKassa receipt email/VAT, FreeKassa second
|
||||
secret/payment method/server IP и Platega payment method.
|
||||
@@ -55,7 +55,8 @@ Provider currency и supported-currency ограничения не перено
|
||||
в Minishop валюта платежа управляется тарифами и `DEFAULT_CURRENCY_SYMBOL`.
|
||||
Если старый gateway Remnashop был настроен на нестандартную валюту, importer
|
||||
оставит предупреждение в JSON-сводке; проверьте `CRYPTOPAY_ASSET`,
|
||||
`HELEKET_CURRENCY`, `HELEKET_SUPPORTED_CURRENCIES` или
|
||||
`HELEKET_CURRENCY`, `HELEKET_SUPPORTED_CURRENCIES`, `PAYKILLA_CURRENCY`,
|
||||
`PAYKILLA_PAYMENT_CURRENCIES` или
|
||||
`PLATEGA_SUPPORTED_CURRENCIES` вручную.
|
||||
|
||||
Провайдеры YooMoney, Cryptomus, MulenPay, PayMaster, RoboKassa и UrlPay сейчас
|
||||
@@ -77,6 +78,7 @@ Remnashop может хранить секреты в формате `enc_...`.
|
||||
- WATA webhook/callback URL: `WEBHOOK_BASE_URL` + `/webhook/wata`;
|
||||
- CryptoBot/Crypto Pay webhook URL: `WEBHOOK_BASE_URL` + `/webhook/cryptopay`;
|
||||
- Heleket payment webhook/callback URL: `WEBHOOK_BASE_URL` + `/webhook/heleket`;
|
||||
- PayKilla webhook URL: `WEBHOOK_BASE_URL` + `/webhook/paykilla`;
|
||||
- FreeKassa notification/result URL: `WEBHOOK_BASE_URL` + `/webhook/freekassa`;
|
||||
- Platega webhook URL: `WEBHOOK_BASE_URL` + `/webhook/platega`;
|
||||
- Telegram webhook `WEBHOOK_BASE_URL` + `/tg/webhook` выставляется ботом
|
||||
|
||||
@@ -479,6 +479,11 @@ export const DEMO_DATASET = {
|
||||
name: "Heleket",
|
||||
icon: "CreditCard",
|
||||
},
|
||||
{
|
||||
id: "paykilla",
|
||||
name: "PayKilla",
|
||||
icon: "Bitcoin",
|
||||
},
|
||||
],
|
||||
referral: {
|
||||
code: "DEMO0001",
|
||||
|
||||
@@ -650,7 +650,7 @@
|
||||
"section_order": 4,
|
||||
"subsection": "common",
|
||||
"label": "Порядок методов оплаты",
|
||||
"description": "Через запятую: severpay,freekassa,yookassa,platega,stars,cryptopay,heleket",
|
||||
"description": "Через запятую: severpay,freekassa,yookassa,platega,stars,cryptopay,heleket,paykilla",
|
||||
"i18n_label_key": "admin_settings_field_payment_methods_order_label",
|
||||
"i18n_description_key": "admin_settings_field_payment_methods_order_description",
|
||||
"i18n_subsection_key": "admin_settings_subsection_common",
|
||||
@@ -3839,6 +3839,692 @@
|
||||
"overridden": false,
|
||||
"updated_at": null,
|
||||
"webhook_base_url_configured": false
|
||||
},
|
||||
{
|
||||
"key": "PAYKILLA_ENABLED",
|
||||
"type": "bool",
|
||||
"section": "payments",
|
||||
"section_order": 4,
|
||||
"subsection": "PayKilla",
|
||||
"label": "Enabled",
|
||||
"description": "",
|
||||
"i18n_label_key": "admin_settings_field_paykilla_enabled_label",
|
||||
"i18n_description_key": null,
|
||||
"i18n_subsection_key": "admin_settings_subsection_paykilla",
|
||||
"i18n_placeholder_key": null,
|
||||
"placeholder": "",
|
||||
"optional": true,
|
||||
"secret": false,
|
||||
"mutually_exclusive_key": "PAYKILLA_ADMIN_ONLY_ENABLED",
|
||||
"provider_id": "paykilla",
|
||||
"provider_label": "PayKilla",
|
||||
"webhook_provider_id": "paykilla",
|
||||
"webhook_path": "/webhook/paykilla",
|
||||
"webhook_requires_base_url": false,
|
||||
"value": "",
|
||||
"overridden": false,
|
||||
"updated_at": null,
|
||||
"webhook_base_url_configured": false
|
||||
},
|
||||
{
|
||||
"key": "PAYKILLA_API_KEY",
|
||||
"type": "string",
|
||||
"section": "payments",
|
||||
"section_order": 4,
|
||||
"subsection": "PayKilla",
|
||||
"label": "API key",
|
||||
"description": "PayKilla public HMAC key with INVOICE permission.",
|
||||
"i18n_label_key": "admin_settings_field_paykilla_api_key_label",
|
||||
"i18n_description_key": "admin_settings_field_paykilla_api_key_description",
|
||||
"i18n_subsection_key": "admin_settings_subsection_paykilla",
|
||||
"i18n_placeholder_key": null,
|
||||
"placeholder": "",
|
||||
"optional": true,
|
||||
"secret": true,
|
||||
"provider_id": "paykilla",
|
||||
"provider_label": "PayKilla",
|
||||
"webhook_provider_id": "paykilla",
|
||||
"webhook_path": "/webhook/paykilla",
|
||||
"webhook_requires_base_url": false,
|
||||
"value": "",
|
||||
"overridden": false,
|
||||
"updated_at": null,
|
||||
"has_value": false,
|
||||
"webhook_base_url_configured": false
|
||||
},
|
||||
{
|
||||
"key": "PAYKILLA_SECRET_KEY",
|
||||
"type": "string",
|
||||
"section": "payments",
|
||||
"section_order": 4,
|
||||
"subsection": "PayKilla",
|
||||
"label": "Secret key",
|
||||
"description": "PayKilla HMAC secret key. Never expose it client-side.",
|
||||
"i18n_label_key": "admin_settings_field_paykilla_secret_key_label",
|
||||
"i18n_description_key": "admin_settings_field_paykilla_secret_key_description",
|
||||
"i18n_subsection_key": "admin_settings_subsection_paykilla",
|
||||
"i18n_placeholder_key": null,
|
||||
"placeholder": "",
|
||||
"optional": true,
|
||||
"secret": true,
|
||||
"provider_id": "paykilla",
|
||||
"provider_label": "PayKilla",
|
||||
"webhook_provider_id": "paykilla",
|
||||
"webhook_path": "/webhook/paykilla",
|
||||
"webhook_requires_base_url": false,
|
||||
"value": "",
|
||||
"overridden": false,
|
||||
"updated_at": null,
|
||||
"has_value": false,
|
||||
"webhook_base_url_configured": false
|
||||
},
|
||||
{
|
||||
"key": "PAYKILLA_BASE_URL",
|
||||
"type": "url",
|
||||
"section": "payments",
|
||||
"section_order": 4,
|
||||
"subsection": "PayKilla",
|
||||
"label": "Base URL",
|
||||
"description": "",
|
||||
"i18n_label_key": "admin_settings_field_paykilla_base_url_label",
|
||||
"i18n_description_key": null,
|
||||
"i18n_subsection_key": "admin_settings_subsection_paykilla",
|
||||
"i18n_placeholder_key": "admin_settings_field_paykilla_base_url_placeholder",
|
||||
"placeholder": "https://account-api.paykilla.com",
|
||||
"optional": true,
|
||||
"secret": false,
|
||||
"provider_id": "paykilla",
|
||||
"provider_label": "PayKilla",
|
||||
"webhook_provider_id": "paykilla",
|
||||
"webhook_path": "/webhook/paykilla",
|
||||
"webhook_requires_base_url": false,
|
||||
"value": "",
|
||||
"overridden": false,
|
||||
"updated_at": null,
|
||||
"webhook_base_url_configured": false
|
||||
},
|
||||
{
|
||||
"key": "PAYKILLA_WIDGET_URL",
|
||||
"type": "url",
|
||||
"section": "payments",
|
||||
"section_order": 4,
|
||||
"subsection": "PayKilla",
|
||||
"label": "Widget URL",
|
||||
"description": "",
|
||||
"i18n_label_key": "admin_settings_field_paykilla_widget_url_label",
|
||||
"i18n_description_key": null,
|
||||
"i18n_subsection_key": "admin_settings_subsection_paykilla",
|
||||
"i18n_placeholder_key": "admin_settings_field_paykilla_widget_url_placeholder",
|
||||
"placeholder": "https://gopay.paykilla.com",
|
||||
"optional": true,
|
||||
"secret": false,
|
||||
"provider_id": "paykilla",
|
||||
"provider_label": "PayKilla",
|
||||
"webhook_provider_id": "paykilla",
|
||||
"webhook_path": "/webhook/paykilla",
|
||||
"webhook_requires_base_url": false,
|
||||
"value": "",
|
||||
"overridden": false,
|
||||
"updated_at": null,
|
||||
"webhook_base_url_configured": false
|
||||
},
|
||||
{
|
||||
"key": "PAYKILLA_CURRENCY",
|
||||
"type": "string",
|
||||
"section": "payments",
|
||||
"section_order": 4,
|
||||
"subsection": "PayKilla",
|
||||
"label": "Invoice currency",
|
||||
"description": "Fiat or crypto invoice currency. FIAT_BASED is selected for RUB/USD/EUR/AED/GBP.",
|
||||
"i18n_label_key": "admin_settings_field_paykilla_currency_label",
|
||||
"i18n_description_key": "admin_settings_field_paykilla_currency_description",
|
||||
"i18n_subsection_key": "admin_settings_subsection_paykilla",
|
||||
"i18n_placeholder_key": "admin_settings_field_paykilla_currency_placeholder",
|
||||
"placeholder": "RUB",
|
||||
"optional": true,
|
||||
"secret": false,
|
||||
"provider_id": "paykilla",
|
||||
"provider_label": "PayKilla",
|
||||
"webhook_provider_id": "paykilla",
|
||||
"webhook_path": "/webhook/paykilla",
|
||||
"webhook_requires_base_url": false,
|
||||
"value": "",
|
||||
"overridden": false,
|
||||
"updated_at": null,
|
||||
"webhook_base_url_configured": false
|
||||
},
|
||||
{
|
||||
"key": "PAYKILLA_SUPPORTED_CURRENCIES",
|
||||
"type": "string",
|
||||
"section": "payments",
|
||||
"section_order": 4,
|
||||
"subsection": "PayKilla",
|
||||
"label": "Supported invoice currencies",
|
||||
"description": "Comma-separated invoice currencies allowed for PayKilla in this shop.",
|
||||
"i18n_label_key": "admin_settings_field_paykilla_supported_currencies_label",
|
||||
"i18n_description_key": "admin_settings_field_paykilla_supported_currencies_description",
|
||||
"i18n_subsection_key": "admin_settings_subsection_paykilla",
|
||||
"i18n_placeholder_key": "admin_settings_field_paykilla_supported_currencies_placeholder",
|
||||
"placeholder": "RUB,USD,EUR,AED,GBP,BTC,ETH,TRX,TON,USDTTRC,USDTETH,USDTBSC,USDCETH,USDCBSC,DAIETH,DAIBSC,BNBBSC,ETHBSC,LINKETH,LINKBSC,USDTTON,AAVEETH,MANAETH,SHIBETH",
|
||||
"optional": true,
|
||||
"secret": false,
|
||||
"provider_id": "paykilla",
|
||||
"provider_label": "PayKilla",
|
||||
"webhook_provider_id": "paykilla",
|
||||
"webhook_path": "/webhook/paykilla",
|
||||
"webhook_requires_base_url": false,
|
||||
"value": "",
|
||||
"overridden": false,
|
||||
"updated_at": null,
|
||||
"webhook_base_url_configured": false
|
||||
},
|
||||
{
|
||||
"key": "PAYKILLA_PAYMENT_CURRENCIES",
|
||||
"type": "string",
|
||||
"section": "payments",
|
||||
"section_order": 4,
|
||||
"subsection": "PayKilla",
|
||||
"label": "Accepted crypto tickers",
|
||||
"description": "Comma-separated PayKilla tickers sent as paymentCurrencies, e.g. USDTTRC,BTC,ETH.",
|
||||
"i18n_label_key": "admin_settings_field_paykilla_payment_currencies_label",
|
||||
"i18n_description_key": "admin_settings_field_paykilla_payment_currencies_description",
|
||||
"i18n_subsection_key": "admin_settings_subsection_paykilla",
|
||||
"i18n_placeholder_key": "admin_settings_field_paykilla_payment_currencies_placeholder",
|
||||
"placeholder": "USDTTRC,BTC,ETH",
|
||||
"optional": true,
|
||||
"secret": false,
|
||||
"provider_id": "paykilla",
|
||||
"provider_label": "PayKilla",
|
||||
"webhook_provider_id": "paykilla",
|
||||
"webhook_path": "/webhook/paykilla",
|
||||
"webhook_requires_base_url": false,
|
||||
"value": "",
|
||||
"overridden": false,
|
||||
"updated_at": null,
|
||||
"webhook_base_url_configured": false
|
||||
},
|
||||
{
|
||||
"key": "PAYKILLA_INVOICE_TYPE",
|
||||
"type": "string",
|
||||
"section": "payments",
|
||||
"section_order": 4,
|
||||
"subsection": "PayKilla",
|
||||
"label": "Invoice type",
|
||||
"description": "Optional override: FIAT_BASED, FIXED_AMOUNT, or OPEN_AMOUNT.",
|
||||
"i18n_label_key": "admin_settings_field_paykilla_invoice_type_label",
|
||||
"i18n_description_key": "admin_settings_field_paykilla_invoice_type_description",
|
||||
"i18n_subsection_key": "admin_settings_subsection_paykilla",
|
||||
"i18n_placeholder_key": null,
|
||||
"placeholder": "",
|
||||
"optional": true,
|
||||
"secret": false,
|
||||
"provider_id": "paykilla",
|
||||
"provider_label": "PayKilla",
|
||||
"webhook_provider_id": "paykilla",
|
||||
"webhook_path": "/webhook/paykilla",
|
||||
"webhook_requires_base_url": false,
|
||||
"choices": [
|
||||
{
|
||||
"value": "",
|
||||
"label": "Auto",
|
||||
"i18n_label_key": "admin_settings_field_paykilla_invoice_type_choice_default"
|
||||
},
|
||||
{
|
||||
"value": "FIAT_BASED",
|
||||
"label": "FIAT_BASED",
|
||||
"i18n_label_key": "admin_settings_field_paykilla_invoice_type_choice_fiat_based"
|
||||
},
|
||||
{
|
||||
"value": "FIXED_AMOUNT",
|
||||
"label": "FIXED_AMOUNT",
|
||||
"i18n_label_key": "admin_settings_field_paykilla_invoice_type_choice_fixed_amount"
|
||||
},
|
||||
{
|
||||
"value": "OPEN_AMOUNT",
|
||||
"label": "OPEN_AMOUNT",
|
||||
"i18n_label_key": "admin_settings_field_paykilla_invoice_type_choice_open_amount"
|
||||
}
|
||||
],
|
||||
"value": "",
|
||||
"overridden": false,
|
||||
"updated_at": null,
|
||||
"webhook_base_url_configured": false
|
||||
},
|
||||
{
|
||||
"key": "PAYKILLA_RETURN_URL",
|
||||
"type": "url",
|
||||
"section": "payments",
|
||||
"section_order": 4,
|
||||
"subsection": "PayKilla",
|
||||
"label": "Return URL",
|
||||
"description": "",
|
||||
"i18n_label_key": "admin_settings_field_paykilla_return_url_label",
|
||||
"i18n_description_key": null,
|
||||
"i18n_subsection_key": "admin_settings_subsection_paykilla",
|
||||
"i18n_placeholder_key": null,
|
||||
"placeholder": "",
|
||||
"optional": true,
|
||||
"secret": false,
|
||||
"provider_id": "paykilla",
|
||||
"provider_label": "PayKilla",
|
||||
"webhook_provider_id": "paykilla",
|
||||
"webhook_path": "/webhook/paykilla",
|
||||
"webhook_requires_base_url": false,
|
||||
"value": "",
|
||||
"overridden": false,
|
||||
"updated_at": null,
|
||||
"webhook_base_url_configured": false
|
||||
},
|
||||
{
|
||||
"key": "PAYKILLA_SUCCESS_URL",
|
||||
"type": "url",
|
||||
"section": "payments",
|
||||
"section_order": 4,
|
||||
"subsection": "PayKilla",
|
||||
"label": "Success URL",
|
||||
"description": "",
|
||||
"i18n_label_key": "admin_settings_field_paykilla_success_url_label",
|
||||
"i18n_description_key": null,
|
||||
"i18n_subsection_key": "admin_settings_subsection_paykilla",
|
||||
"i18n_placeholder_key": null,
|
||||
"placeholder": "",
|
||||
"optional": true,
|
||||
"secret": false,
|
||||
"provider_id": "paykilla",
|
||||
"provider_label": "PayKilla",
|
||||
"webhook_provider_id": "paykilla",
|
||||
"webhook_path": "/webhook/paykilla",
|
||||
"webhook_requires_base_url": false,
|
||||
"value": "",
|
||||
"overridden": false,
|
||||
"updated_at": null,
|
||||
"webhook_base_url_configured": false
|
||||
},
|
||||
{
|
||||
"key": "PAYKILLA_CANCEL_URL",
|
||||
"type": "url",
|
||||
"section": "payments",
|
||||
"section_order": 4,
|
||||
"subsection": "PayKilla",
|
||||
"label": "Cancel URL",
|
||||
"description": "",
|
||||
"i18n_label_key": "admin_settings_field_paykilla_cancel_url_label",
|
||||
"i18n_description_key": null,
|
||||
"i18n_subsection_key": "admin_settings_subsection_paykilla",
|
||||
"i18n_placeholder_key": null,
|
||||
"placeholder": "",
|
||||
"optional": true,
|
||||
"secret": false,
|
||||
"provider_id": "paykilla",
|
||||
"provider_label": "PayKilla",
|
||||
"webhook_provider_id": "paykilla",
|
||||
"webhook_path": "/webhook/paykilla",
|
||||
"webhook_requires_base_url": false,
|
||||
"value": "",
|
||||
"overridden": false,
|
||||
"updated_at": null,
|
||||
"webhook_base_url_configured": false
|
||||
},
|
||||
{
|
||||
"key": "PAYKILLA_LIFETIME_SECONDS",
|
||||
"type": "int",
|
||||
"section": "payments",
|
||||
"section_order": 4,
|
||||
"subsection": "PayKilla",
|
||||
"label": "Invoice lifetime (seconds)",
|
||||
"description": "Used to send expiredAt to PayKilla.",
|
||||
"i18n_label_key": "admin_settings_field_paykilla_lifetime_seconds_label",
|
||||
"i18n_description_key": "admin_settings_field_paykilla_lifetime_seconds_description",
|
||||
"i18n_subsection_key": "admin_settings_subsection_paykilla",
|
||||
"i18n_placeholder_key": null,
|
||||
"placeholder": "",
|
||||
"optional": true,
|
||||
"secret": false,
|
||||
"min": 300,
|
||||
"max": 2592000,
|
||||
"provider_id": "paykilla",
|
||||
"provider_label": "PayKilla",
|
||||
"webhook_provider_id": "paykilla",
|
||||
"webhook_path": "/webhook/paykilla",
|
||||
"webhook_requires_base_url": false,
|
||||
"value": "",
|
||||
"overridden": false,
|
||||
"updated_at": null,
|
||||
"webhook_base_url_configured": false
|
||||
},
|
||||
{
|
||||
"key": "PAYKILLA_RECV_WINDOW_MS",
|
||||
"type": "int",
|
||||
"section": "payments",
|
||||
"section_order": 4,
|
||||
"subsection": "PayKilla",
|
||||
"label": "Request recvWindow (ms)",
|
||||
"description": "Validity window for signed PayKilla API requests.",
|
||||
"i18n_label_key": "admin_settings_field_paykilla_recv_window_ms_label",
|
||||
"i18n_description_key": "admin_settings_field_paykilla_recv_window_ms_description",
|
||||
"i18n_subsection_key": "admin_settings_subsection_paykilla",
|
||||
"i18n_placeholder_key": null,
|
||||
"placeholder": "",
|
||||
"optional": true,
|
||||
"secret": false,
|
||||
"min": 1000,
|
||||
"max": 60000,
|
||||
"provider_id": "paykilla",
|
||||
"provider_label": "PayKilla",
|
||||
"webhook_provider_id": "paykilla",
|
||||
"webhook_path": "/webhook/paykilla",
|
||||
"webhook_requires_base_url": false,
|
||||
"value": "",
|
||||
"overridden": false,
|
||||
"updated_at": null,
|
||||
"webhook_base_url_configured": false
|
||||
},
|
||||
{
|
||||
"key": "PAYKILLA_USER_PAYS_SERVICE_FEE",
|
||||
"type": "bool",
|
||||
"section": "payments",
|
||||
"section_order": 4,
|
||||
"subsection": "PayKilla",
|
||||
"label": "User pays service fee",
|
||||
"description": "",
|
||||
"i18n_label_key": "admin_settings_field_paykilla_user_pays_service_fee_label",
|
||||
"i18n_description_key": null,
|
||||
"i18n_subsection_key": "admin_settings_subsection_paykilla",
|
||||
"i18n_placeholder_key": null,
|
||||
"placeholder": "",
|
||||
"optional": true,
|
||||
"secret": false,
|
||||
"provider_id": "paykilla",
|
||||
"provider_label": "PayKilla",
|
||||
"webhook_provider_id": "paykilla",
|
||||
"webhook_path": "/webhook/paykilla",
|
||||
"webhook_requires_base_url": false,
|
||||
"value": "",
|
||||
"overridden": false,
|
||||
"updated_at": null,
|
||||
"webhook_base_url_configured": false
|
||||
},
|
||||
{
|
||||
"key": "PAYKILLA_USER_PAYS_NETWORK_FEE",
|
||||
"type": "bool",
|
||||
"section": "payments",
|
||||
"section_order": 4,
|
||||
"subsection": "PayKilla",
|
||||
"label": "User pays network fee",
|
||||
"description": "",
|
||||
"i18n_label_key": "admin_settings_field_paykilla_user_pays_network_fee_label",
|
||||
"i18n_description_key": null,
|
||||
"i18n_subsection_key": "admin_settings_subsection_paykilla",
|
||||
"i18n_placeholder_key": null,
|
||||
"placeholder": "",
|
||||
"optional": true,
|
||||
"secret": false,
|
||||
"provider_id": "paykilla",
|
||||
"provider_label": "PayKilla",
|
||||
"webhook_provider_id": "paykilla",
|
||||
"webhook_path": "/webhook/paykilla",
|
||||
"webhook_requires_base_url": false,
|
||||
"value": "",
|
||||
"overridden": false,
|
||||
"updated_at": null,
|
||||
"webhook_base_url_configured": false
|
||||
},
|
||||
{
|
||||
"key": "PAYKILLA_VERIFY_WEBHOOK_SIGNATURE",
|
||||
"type": "bool",
|
||||
"section": "payments",
|
||||
"section_order": 4,
|
||||
"subsection": "PayKilla",
|
||||
"label": "Verify webhook signature",
|
||||
"description": "",
|
||||
"i18n_label_key": "admin_settings_field_paykilla_verify_webhook_signature_label",
|
||||
"i18n_description_key": null,
|
||||
"i18n_subsection_key": "admin_settings_subsection_paykilla",
|
||||
"i18n_placeholder_key": null,
|
||||
"placeholder": "",
|
||||
"optional": true,
|
||||
"secret": false,
|
||||
"provider_id": "paykilla",
|
||||
"provider_label": "PayKilla",
|
||||
"webhook_provider_id": "paykilla",
|
||||
"webhook_path": "/webhook/paykilla",
|
||||
"webhook_requires_base_url": false,
|
||||
"value": "",
|
||||
"overridden": false,
|
||||
"updated_at": null,
|
||||
"webhook_base_url_configured": false
|
||||
},
|
||||
{
|
||||
"key": "PAYKILLA_WEBHOOK_URL",
|
||||
"type": "url",
|
||||
"section": "payments",
|
||||
"section_order": 4,
|
||||
"subsection": "PayKilla",
|
||||
"label": "Exact webhook URL",
|
||||
"description": "Optional override for signature verification. Leave empty to use WEBHOOK_BASE_URL + /webhook/paykilla.",
|
||||
"i18n_label_key": "admin_settings_field_paykilla_webhook_url_label",
|
||||
"i18n_description_key": "admin_settings_field_paykilla_webhook_url_description",
|
||||
"i18n_subsection_key": "admin_settings_subsection_paykilla",
|
||||
"i18n_placeholder_key": null,
|
||||
"placeholder": "",
|
||||
"optional": true,
|
||||
"secret": false,
|
||||
"provider_id": "paykilla",
|
||||
"provider_label": "PayKilla",
|
||||
"webhook_provider_id": "paykilla",
|
||||
"webhook_path": "/webhook/paykilla",
|
||||
"webhook_requires_base_url": false,
|
||||
"value": "",
|
||||
"overridden": false,
|
||||
"updated_at": null,
|
||||
"webhook_base_url_configured": false
|
||||
},
|
||||
{
|
||||
"key": "PAYKILLA_TRUSTED_IPS",
|
||||
"type": "string",
|
||||
"section": "payments",
|
||||
"section_order": 4,
|
||||
"subsection": "PayKilla",
|
||||
"label": "Trusted IPs",
|
||||
"description": "Optional comma-separated IP addresses accepted for PayKilla webhooks.",
|
||||
"i18n_label_key": "admin_settings_field_paykilla_trusted_ips_label",
|
||||
"i18n_description_key": "admin_settings_field_paykilla_trusted_ips_description",
|
||||
"i18n_subsection_key": "admin_settings_subsection_paykilla",
|
||||
"i18n_placeholder_key": null,
|
||||
"placeholder": "",
|
||||
"optional": true,
|
||||
"secret": false,
|
||||
"provider_id": "paykilla",
|
||||
"provider_label": "PayKilla",
|
||||
"webhook_provider_id": "paykilla",
|
||||
"webhook_path": "/webhook/paykilla",
|
||||
"webhook_requires_base_url": false,
|
||||
"value": "",
|
||||
"overridden": false,
|
||||
"updated_at": null,
|
||||
"webhook_base_url_configured": false
|
||||
},
|
||||
{
|
||||
"key": "PAYMENT_PAYKILLA_WEBAPP_LABEL_RU",
|
||||
"type": "string",
|
||||
"section": "payments",
|
||||
"section_order": 4,
|
||||
"subsection": "PayKilla",
|
||||
"label": "WebApp button text (RU)",
|
||||
"description": "Custom Russian text shown in the Web App payment method button.",
|
||||
"i18n_label_key": "admin_settings_field_payment_paykilla_webapp_label_ru_label",
|
||||
"i18n_description_key": "admin_settings_field_payment_paykilla_webapp_label_ru_description",
|
||||
"i18n_subsection_key": "admin_settings_subsection_paykilla",
|
||||
"i18n_placeholder_key": "admin_settings_field_payment_paykilla_webapp_label_ru_placeholder",
|
||||
"placeholder": "PayKilla",
|
||||
"optional": true,
|
||||
"secret": false,
|
||||
"default": "PayKilla",
|
||||
"provider_id": "paykilla",
|
||||
"provider_label": "PayKilla",
|
||||
"webhook_provider_id": "paykilla",
|
||||
"webhook_path": "/webhook/paykilla",
|
||||
"webhook_requires_base_url": false,
|
||||
"value": "",
|
||||
"overridden": false,
|
||||
"updated_at": null,
|
||||
"webhook_base_url_configured": false
|
||||
},
|
||||
{
|
||||
"key": "PAYMENT_PAYKILLA_WEBAPP_LABEL_EN",
|
||||
"type": "string",
|
||||
"section": "payments",
|
||||
"section_order": 4,
|
||||
"subsection": "PayKilla",
|
||||
"label": "WebApp button text (EN)",
|
||||
"description": "Custom English text shown in the Web App payment method button.",
|
||||
"i18n_label_key": "admin_settings_field_payment_paykilla_webapp_label_en_label",
|
||||
"i18n_description_key": "admin_settings_field_payment_paykilla_webapp_label_en_description",
|
||||
"i18n_subsection_key": "admin_settings_subsection_paykilla",
|
||||
"i18n_placeholder_key": "admin_settings_field_payment_paykilla_webapp_label_en_placeholder",
|
||||
"placeholder": "PayKilla",
|
||||
"optional": true,
|
||||
"secret": false,
|
||||
"default": "PayKilla",
|
||||
"provider_id": "paykilla",
|
||||
"provider_label": "PayKilla",
|
||||
"webhook_provider_id": "paykilla",
|
||||
"webhook_path": "/webhook/paykilla",
|
||||
"webhook_requires_base_url": false,
|
||||
"value": "",
|
||||
"overridden": false,
|
||||
"updated_at": null,
|
||||
"webhook_base_url_configured": false
|
||||
},
|
||||
{
|
||||
"key": "PAYMENT_PAYKILLA_WEBAPP_ICON",
|
||||
"type": "icon",
|
||||
"section": "payments",
|
||||
"section_order": 4,
|
||||
"subsection": "PayKilla",
|
||||
"label": "WebApp button icon",
|
||||
"description": "Lucide icon name rendered inside the Web App payment method button.",
|
||||
"i18n_label_key": "admin_settings_field_payment_paykilla_webapp_icon_label",
|
||||
"i18n_description_key": "admin_settings_field_payment_paykilla_webapp_icon_description",
|
||||
"i18n_subsection_key": "admin_settings_subsection_paykilla",
|
||||
"i18n_placeholder_key": "admin_settings_field_payment_paykilla_webapp_icon_placeholder",
|
||||
"placeholder": "Bitcoin",
|
||||
"optional": true,
|
||||
"secret": false,
|
||||
"default": "Bitcoin",
|
||||
"provider_id": "paykilla",
|
||||
"provider_label": "PayKilla",
|
||||
"webhook_provider_id": "paykilla",
|
||||
"webhook_path": "/webhook/paykilla",
|
||||
"webhook_requires_base_url": false,
|
||||
"value": "",
|
||||
"overridden": false,
|
||||
"updated_at": null,
|
||||
"webhook_base_url_configured": false
|
||||
},
|
||||
{
|
||||
"key": "PAYMENT_PAYKILLA_TELEGRAM_LABEL_RU",
|
||||
"type": "string",
|
||||
"section": "payments",
|
||||
"section_order": 4,
|
||||
"subsection": "PayKilla",
|
||||
"label": "Telegram button text (RU)",
|
||||
"description": "Custom Russian text shown in Telegram bot payment buttons.",
|
||||
"i18n_label_key": "admin_settings_field_payment_paykilla_telegram_label_ru_label",
|
||||
"i18n_description_key": "admin_settings_field_payment_paykilla_telegram_label_ru_description",
|
||||
"i18n_subsection_key": "admin_settings_subsection_paykilla",
|
||||
"i18n_placeholder_key": "admin_settings_field_payment_paykilla_telegram_label_ru_placeholder",
|
||||
"placeholder": "PayKilla",
|
||||
"optional": true,
|
||||
"secret": false,
|
||||
"default": "PayKilla",
|
||||
"provider_id": "paykilla",
|
||||
"provider_label": "PayKilla",
|
||||
"webhook_provider_id": "paykilla",
|
||||
"webhook_path": "/webhook/paykilla",
|
||||
"webhook_requires_base_url": false,
|
||||
"value": "",
|
||||
"overridden": false,
|
||||
"updated_at": null,
|
||||
"webhook_base_url_configured": false
|
||||
},
|
||||
{
|
||||
"key": "PAYMENT_PAYKILLA_TELEGRAM_LABEL_EN",
|
||||
"type": "string",
|
||||
"section": "payments",
|
||||
"section_order": 4,
|
||||
"subsection": "PayKilla",
|
||||
"label": "Telegram button text (EN)",
|
||||
"description": "Custom English text shown in Telegram bot payment buttons.",
|
||||
"i18n_label_key": "admin_settings_field_payment_paykilla_telegram_label_en_label",
|
||||
"i18n_description_key": "admin_settings_field_payment_paykilla_telegram_label_en_description",
|
||||
"i18n_subsection_key": "admin_settings_subsection_paykilla",
|
||||
"i18n_placeholder_key": "admin_settings_field_payment_paykilla_telegram_label_en_placeholder",
|
||||
"placeholder": "PayKilla",
|
||||
"optional": true,
|
||||
"secret": false,
|
||||
"default": "PayKilla",
|
||||
"provider_id": "paykilla",
|
||||
"provider_label": "PayKilla",
|
||||
"webhook_provider_id": "paykilla",
|
||||
"webhook_path": "/webhook/paykilla",
|
||||
"webhook_requires_base_url": false,
|
||||
"value": "",
|
||||
"overridden": false,
|
||||
"updated_at": null,
|
||||
"webhook_base_url_configured": false
|
||||
},
|
||||
{
|
||||
"key": "PAYMENT_PAYKILLA_TELEGRAM_EMOJI",
|
||||
"type": "string",
|
||||
"section": "payments",
|
||||
"section_order": 4,
|
||||
"subsection": "PayKilla",
|
||||
"label": "Telegram button emoji",
|
||||
"description": "Emoji prepended to the Telegram bot payment button when customized.",
|
||||
"i18n_label_key": "admin_settings_field_payment_paykilla_telegram_emoji_label",
|
||||
"i18n_description_key": "admin_settings_field_payment_paykilla_telegram_emoji_description",
|
||||
"i18n_subsection_key": "admin_settings_subsection_paykilla",
|
||||
"i18n_placeholder_key": null,
|
||||
"placeholder": "",
|
||||
"optional": true,
|
||||
"secret": false,
|
||||
"default": "",
|
||||
"provider_id": "paykilla",
|
||||
"provider_label": "PayKilla",
|
||||
"webhook_provider_id": "paykilla",
|
||||
"webhook_path": "/webhook/paykilla",
|
||||
"webhook_requires_base_url": false,
|
||||
"value": "",
|
||||
"overridden": false,
|
||||
"updated_at": null,
|
||||
"webhook_base_url_configured": false
|
||||
},
|
||||
{
|
||||
"key": "PAYKILLA_ADMIN_ONLY_ENABLED",
|
||||
"type": "bool",
|
||||
"section": "payments",
|
||||
"section_order": 4,
|
||||
"subsection": "PayKilla",
|
||||
"label": "Only for admins",
|
||||
"description": "Shows this payment method only to users from ADMIN_IDS. Webhooks and provider services remain active for admin test payments.",
|
||||
"i18n_label_key": "admin_settings_provider_admin_only_label",
|
||||
"i18n_description_key": "admin_settings_provider_admin_only_description",
|
||||
"i18n_subsection_key": "admin_settings_subsection_paykilla",
|
||||
"i18n_placeholder_key": null,
|
||||
"placeholder": "",
|
||||
"optional": true,
|
||||
"secret": false,
|
||||
"mutually_exclusive_key": "PAYKILLA_ENABLED",
|
||||
"provider_id": "paykilla",
|
||||
"provider_label": "PayKilla",
|
||||
"webhook_provider_id": "paykilla",
|
||||
"webhook_path": "/webhook/paykilla",
|
||||
"webhook_requires_base_url": false,
|
||||
"value": "",
|
||||
"overridden": false,
|
||||
"updated_at": null,
|
||||
"webhook_base_url_configured": false
|
||||
}
|
||||
]
|
||||
},
|
||||
|
||||
@@ -874,6 +874,7 @@ remnashop_webhook_checklist() {
|
||||
printf ' WATA merchant dashboard -> webhook/callback URL: %s/webhook/wata\n' "$base_url"
|
||||
printf ' CryptoBot/Crypto Pay app -> webhook URL: %s/webhook/cryptopay\n' "$base_url"
|
||||
printf ' Heleket merchant dashboard -> payment webhook/callback URL: %s/webhook/heleket\n' "$base_url"
|
||||
printf ' PayKilla Dashboard -> Settings -> Webhooks URL: %s/webhook/paykilla\n' "$base_url"
|
||||
printf ' FreeKassa shop settings -> notification/result URL: %s/webhook/freekassa\n' "$base_url"
|
||||
printf ' Platega merchant/project settings -> webhook URL: %s/webhook/platega\n' "$base_url"
|
||||
printf ' Telegram webhook: %s/tg/webhook (configured automatically on bot startup)\n' "$base_url"
|
||||
|
||||
@@ -175,6 +175,7 @@ class BuildServicesWiringTests(unittest.TestCase):
|
||||
"severpay_service",
|
||||
"wata_service",
|
||||
"heleket_service",
|
||||
"paykilla_service",
|
||||
}
|
||||
self.assertEqual(set(services), expected_keys)
|
||||
|
||||
|
||||
@@ -76,6 +76,7 @@ def test_shell_installer_prints_remnashop_webhook_checklist():
|
||||
assert "/webhook/wata" in script
|
||||
assert "/webhook/cryptopay" in script
|
||||
assert "/webhook/heleket" in script
|
||||
assert "/webhook/paykilla" in script
|
||||
assert "/webhook/freekassa" in script
|
||||
assert "/webhook/platega" in script
|
||||
assert "/tg/webhook" in script
|
||||
|
||||
@@ -203,6 +203,7 @@ class RemnashopMigrationDocumentationFactsTests(unittest.TestCase):
|
||||
"/webhook/wata",
|
||||
"/webhook/cryptopay",
|
||||
"/webhook/heleket",
|
||||
"/webhook/paykilla",
|
||||
"/webhook/freekassa",
|
||||
"/webhook/platega",
|
||||
"/tg/webhook",
|
||||
|
||||
@@ -64,6 +64,7 @@ _PROVIDER_MODULES = {
|
||||
"stars": "StarsService",
|
||||
"wata": "WataService",
|
||||
"heleket": "HeleketService",
|
||||
"paykilla": "PaykillaService",
|
||||
}
|
||||
|
||||
|
||||
@@ -125,6 +126,7 @@ def test_service_keys_and_statuses_come_from_provider_specs():
|
||||
"stars_service",
|
||||
"cryptopay_service",
|
||||
"heleket_service",
|
||||
"paykilla_service",
|
||||
}
|
||||
assert set(pending_statuses()) >= {
|
||||
"pending",
|
||||
@@ -136,6 +138,7 @@ def test_service_keys_and_statuses_come_from_provider_specs():
|
||||
"pending_cryptopay",
|
||||
"pending_stars",
|
||||
"pending_heleket",
|
||||
"pending_paykilla",
|
||||
}
|
||||
|
||||
|
||||
@@ -152,6 +155,7 @@ def test_provider_labels_and_emojis_include_storage_keys_and_method_aliases():
|
||||
assert emojis["stars"] == get_provider_spec("stars").default_telegram_emoji
|
||||
assert emojis["telegram_stars"] == get_provider_spec("stars").default_telegram_emoji
|
||||
assert emojis["cryptopay"] == get_provider_spec("cryptopay").default_telegram_emoji
|
||||
assert labels["paykilla"] == "PayKilla"
|
||||
|
||||
|
||||
def test_provider_presentation_resolves_defaults_and_overrides():
|
||||
|
||||
@@ -27,6 +27,7 @@ _PROVIDERS_FROM_CALLERS = {
|
||||
"severpay",
|
||||
"wata",
|
||||
"cryptopay",
|
||||
"paykilla",
|
||||
"telegram_stars",
|
||||
}
|
||||
|
||||
|
||||
@@ -185,6 +185,22 @@ def test_remnashop_crypto_provider_currency_is_not_imported_as_setting_override(
|
||||
}
|
||||
assert "HELEKET_CURRENCY" not in heleket["overrides"]
|
||||
|
||||
paykilla = remnashop_payment_gateway_overrides(
|
||||
{
|
||||
"type": "PAYKILLA",
|
||||
"currency": "USD",
|
||||
"is_active": True,
|
||||
"settings": {"public_key": "public", "secret_key": "secret"},
|
||||
}
|
||||
)
|
||||
assert paykilla["overrides"] == {
|
||||
"PAYKILLA_ENABLED": True,
|
||||
"PAYKILLA_API_KEY": "public",
|
||||
"PAYKILLA_SECRET_KEY": "secret",
|
||||
}
|
||||
assert "PAYKILLA_CURRENCY" not in paykilla["overrides"]
|
||||
assert any("source currency was USD" in warning for warning in paykilla["warnings"])
|
||||
|
||||
|
||||
def test_remnashop_unsupported_gateway_is_reported_without_overrides():
|
||||
result = remnashop_payment_gateway_overrides(
|
||||
|
||||
@@ -1,6 +1,7 @@
|
||||
import hashlib
|
||||
import hmac
|
||||
import json
|
||||
import time
|
||||
import unittest
|
||||
from types import SimpleNamespace
|
||||
from unittest.mock import AsyncMock, patch
|
||||
@@ -19,6 +20,12 @@ from bot.app.web.webapp_auth import (
|
||||
from bot.payment_providers.cryptopay import CryptoPayService
|
||||
from bot.payment_providers.freekassa import FreeKassaService
|
||||
from bot.payment_providers.heleket import HeleketConfig, HeleketService, _compute_signature
|
||||
from bot.payment_providers.paykilla import (
|
||||
PaykillaConfig,
|
||||
PaykillaService,
|
||||
_sign_query,
|
||||
_webhook_signature,
|
||||
)
|
||||
from bot.payment_providers.yookassa import yookassa_webhook_route
|
||||
from bot.services.email_templates import render_login_code
|
||||
from bot.utils.request_security import request_client_ip
|
||||
@@ -199,6 +206,79 @@ class HeleketServiceTests(unittest.TestCase):
|
||||
self.assertFalse(service._verify_signature({"order_id": "435", "sign": "bad"}))
|
||||
|
||||
|
||||
class PaykillaServiceTests(unittest.TestCase):
|
||||
def _make_service(self, *, webhook_url: str = "https://shop.example/webhook/paykilla"):
|
||||
service = PaykillaService.__new__(PaykillaService)
|
||||
service.config = PaykillaConfig(
|
||||
ENABLED=True,
|
||||
API_KEY="public-key",
|
||||
SECRET_KEY="secret-key",
|
||||
WEBHOOK_URL=webhook_url,
|
||||
)
|
||||
service.settings = SimpleNamespace(
|
||||
WEBHOOK_BASE_URL="https://shop.example",
|
||||
trusted_proxies=["127.0.0.1"],
|
||||
)
|
||||
return service
|
||||
|
||||
def test_sign_query_uses_timestamp_and_recv_window_only(self):
|
||||
query, signature = _sign_query(1738800000000, 5000, "secret-key")
|
||||
expected = hmac.new(
|
||||
b"secret-key",
|
||||
b"timestamp=1738800000000&recvWindow=5000",
|
||||
hashlib.sha256,
|
||||
).hexdigest()
|
||||
|
||||
self.assertEqual(query, "timestamp=1738800000000&recvWindow=5000")
|
||||
self.assertEqual(signature, expected)
|
||||
|
||||
def test_verify_webhook_signature_accepts_raw_body_signature(self):
|
||||
service = self._make_service()
|
||||
raw_body = (
|
||||
b'{"id":"evt_1","priority":"HIGH","eventType":"INVOICE_PAID",'
|
||||
b'"data":{"id":"inv_1","clientOrderId":"42"}}'
|
||||
)
|
||||
timestamp = str(int(time.time() * 1000))
|
||||
signature = _webhook_signature(
|
||||
timestamp=timestamp,
|
||||
method="POST",
|
||||
url="https://shop.example/webhook/paykilla",
|
||||
raw_body=raw_body,
|
||||
secret_key="secret-key",
|
||||
)
|
||||
request = SimpleNamespace(
|
||||
headers={
|
||||
"X-API-KEY": "public-key",
|
||||
"X-API-TIMESTAMP": timestamp,
|
||||
"X-API-RECV-WINDOW": "5000",
|
||||
"X-API-SIGN": signature,
|
||||
},
|
||||
method="POST",
|
||||
scheme="https",
|
||||
host="shop.example",
|
||||
path_qs="/webhook/paykilla",
|
||||
)
|
||||
|
||||
self.assertTrue(service._verify_webhook_signature(request, raw_body))
|
||||
|
||||
def test_verify_webhook_signature_rejects_invalid_signature(self):
|
||||
service = self._make_service()
|
||||
request = SimpleNamespace(
|
||||
headers={
|
||||
"X-API-KEY": "public-key",
|
||||
"X-API-TIMESTAMP": str(int(time.time() * 1000)),
|
||||
"X-API-RECV-WINDOW": "5000",
|
||||
"X-API-SIGN": "bad",
|
||||
},
|
||||
method="POST",
|
||||
scheme="https",
|
||||
host="shop.example",
|
||||
path_qs="/webhook/paykilla",
|
||||
)
|
||||
|
||||
self.assertFalse(service._verify_webhook_signature(request, b"{}"))
|
||||
|
||||
|
||||
class WebAppSecurityTests(unittest.IsolatedAsyncioTestCase):
|
||||
class _AsyncSessionFactory:
|
||||
def __call__(self):
|
||||
|
||||
Reference in New Issue
Block a user