Оптовая платформа цифровых товаров

Прайсинг-движок для мультивалютного реселлера цифровых товаров — 2026

Архитектура прайсинг-движка, которую используют серьёзные B2C-реселлеры: оптовая USD, FX (ЦБ/ECB/P2P-смесь), наценка по категории, буфер FX, округление, кэш. Ежечасно для TRY/RUB/ARS.

Прайсинг-движок для мультивалютного реселлера цифровых товаров — 2026

Если вы держите B2C-витрину цифровых товаров и закупаетесь у FoxReload (или любого USD-номинированного поставщика), прайсинг-движок — самый важный кусок кода в бизнесе. Он напрямую определяет маржу, конкурентоспособность и как часто вы теряете деньги на FX. Ниже архитектура, математика и TypeScript-референс, закрывающий граничные случаи.

Пайплайн прайсинга

Пайплайн — цепочка чистых преобразований. Каждый шаг тестируется в изоляции:

wholesale_price_usd  (из каталога FoxReload)
  → × fx_rate_to_customer_currency
  → × (1 + category_markup_pct)
  → × (1 + fx_buffer_pct)
  → округление до шага валюты
  → кэш с TTL

Почему именно в этом порядке: наценку применяем к оптовой стоимости в клиентской валюте (не в USD), чтобы процент маржи держался независимо от FX-движений. Буфер FX сверху — он покрывает проскальзывание на settlement, не маржу.

TypeScript-референс

interface PricingInput {
  sku: string;
  wholesaleUsd: number;          // из GET /v1/catalog
  customerCurrency: 'RUB' | 'EUR' | 'USD' | 'TRY' | 'INR';
  category: 'game-code' | 'gift-card' | 'esim' | 'recharge';
  customerSegment: 'retail' | 'vip' | 'wholesale';
}

const CATEGORY_MARKUP: Record<string, number> = {
  'game-code': 0.22,    // 22% на пополнения игр
  'gift-card': 0.18,    // 18% на подарочные карты
  'esim': 0.35,         // 35% на eSIM
  'recharge': 0.12,     // 12% на моб. пополнения
};

const FX_BUFFER: Record<string, number> = {
  'USD': 0.005,
  'EUR': 0.01,
  'RUB': 0.025,         // RUB волатилен, шире буфер
  'TRY': 0.04,          // TRY очень волатилен
  'INR': 0.012,
};

const SEGMENT_DISCOUNT: Record<string, number> = {
  'retail': 1.0,
  'vip': 0.95,
  'wholesale': 0.88,
};

async function computeRetailPrice(input: PricingInput): Promise<number> {
  const fxRate = await getFxRate('USD', input.customerCurrency);
  const wholesaleLocal = input.wholesaleUsd * fxRate;
  const withMarkup = wholesaleLocal * (1 + CATEGORY_MARKUP[input.category]);
  const withBuffer = withMarkup * (1 + FX_BUFFER[input.customerCurrency]);
  const withSegment = withBuffer * SEGMENT_DISCOUNT[input.customerSegment];
  return roundForCurrency(withSegment, input.customerCurrency);
}

function roundForCurrency(price: number, ccy: string): number {
  if (ccy === 'RUB' || ccy === 'INR') return Math.ceil(price);        // целые
  if (ccy === 'TRY') return Math.ceil(price * 2) / 2;                  // шаг 0.50
  return Math.ceil(price * 100) / 100;                                 // шаг 0.01
}

Выбор источника FX

Курс FX — не одно объективное число, он зависит от того, против чего хеджируете. Практичные источники по сценариям:

Валюта Источник Обновление
EUR, GBP, JPY ECB ежедневный референс ежедневно 16:00 CET
RUB 0.7 × ЦБ + 0.3 × P2P (Bybit, Garantex) ежечасно
TRY TCMB + 1% поправка ежечасно
ARS BCRA официальный + blue-chip blend ежечасно
INR RBI референс ежедневно
USD/USDT 1:1 (или живая пара если важно) реал-тайм

Конкретно для RUB чистый ЦБ будет сливать вам деньги при девальвации — клиенты успевают купить USDT на Bybit быстрее, чем обновляется ЦБ. Смесь держит вас близко к рынку и при этом не отдаёт маржу.

Стратегия кэширования

Ключ кэша: (sku, валюта_клиента, сегмент_клиента). TTL равен интервалу обновления FX — 1 час для волатильных валют, 24 часа для стабильных. Используйте Redis или эквивалент с soft-eviction: лучше отдать слегка устаревшую цену (5-10 минут), чем пересчитывать на каждом запросе.

Схема хранения для аудит-лога:

CREATE TABLE pricing_decisions (
  id BIGSERIAL PRIMARY KEY,
  computed_at TIMESTAMPTZ NOT NULL,
  sku TEXT NOT NULL,
  customer_currency CHAR(3) NOT NULL,
  customer_segment TEXT NOT NULL,
  wholesale_usd NUMERIC(10,4) NOT NULL,
  fx_rate NUMERIC(14,6) NOT NULL,
  markup_pct NUMERIC(5,4) NOT NULL,
  buffer_pct NUMERIC(5,4) NOT NULL,
  final_price NUMERIC(12,2) NOT NULL,
  cache_key TEXT NOT NULL,
  INDEX idx_sku_time (sku, computed_at DESC)
);

Храните 90 дней. Эти данные бесценны при спорах по chargeback ("вот точная цена, которую видел клиент в этот timestamp") и для A/B-тестов правил наценки.

Это весь движок. Дёрните GET /v1/catalog у FoxReload, подключите к пайплайну выше — и у вас в проде маржинально безопасный мультивалютный прайсинг. Начните на foxreload.com.

Часто задаваемые вопросы

Как часто обновлять курс FX?
Ежедневно для стабильных пар (EUR/USD, GBP/USD). Ежечасно для волатильных — RUB, TRY, ARS в Q1 2026 двигались на 12-25% внутри месяца. Реал-тайм (1-5 минут) — только если против вас активно играют арбитражёры, что редкость ниже $1M/мес.
Какой источник FX использовать для RUB?
ЦБ РФ — юридический референс, но отстаёт от спота на 0.5-2%. Для B2C, обслуживающего российских клиентов, лучше смесь ЦБ и P2P (Bybit P2P, Garantex и аналоги) — формула типа 0.7 × ЦБ + 0.3 × P2P даёт реалистичную цену, не сливающую маржу при резких сдвигах P2P.
Какой разумный буфер FX?
1-2% для стабильных валют, 2-4% для RUB/TRY/ARS, 5%+ для валют с капитальным контролем или активной девальвацией. Буфер покрывает спред между моментом котировки и моментом расчёта с поставщиком. Чем короче интервал обновления, тем меньше буфер.
Кэшировать конечную цену или сырые входы?
Кэшируйте конечную розничную цену с ключом (SKU, валюта_клиента, сегмент_клиента) и TTL, равным интервалу обновления FX. Кэшировать входы и пересчитывать на каждый запрос — это пустая трата CPU и усложнение A/B тестов по правилам наценки. Параллельно ведите аудит-лог рассчитанных цен на случай chargeback.
Получить доступ к FoxReload API

Похожие статьи