Finance OS / API

B2B API - Introduction

B2B API позволяет партнёрам Finance OS управлять своими конечными пользователями через единый набор endpoints: создавать managed-customers, проводить им KYC-верификацию, инициировать платежи и подписываться на webhook-события.

Регуляторное предусловие
B2B-режим - не self-service. Он включается только после подписания договора с Finance OS (агентская модель + соглашение об обработке данных). До этого момента API-ключи получают 403 B2B_ACCESS_REQUIRED на любой /api/v1/customers/* endpoint. Свяжитесь с admin@fin-os.io, чтобы инициировать процесс.

Две модели работы

Merchant API покрывает два разных сценария. Выберите тот, который описывает ваш продукт - от этого зависит, какие разделы документации вам нужны.

Классический мерчант клиенты и кошельки optional
Вы ведёте на платформе своих конечных пользователей: заводите клиентов, выдаёте им крипто-адреса, принимаете депозиты, выводите средства, рассчитываетесь с ними и проверяете адреса на комплаенс. Расчёты платформы с вами идут через мастер-счёт - предоплатный сервисный баланс вашей учётной записи. Это основной сценарий, и о нём вся документация ниже.
Партнёр по приёму платежей payin optional
Отдельный контур приёма рублёвых платежей с расчётом в USDT - собственные эндпоинты, статусы и события. Описан в разделе Payment Gateway (RUB) и подключается по отдельному договору.

Что входит в контур классического мерчанта

  • Клиенты - ваши конечные пользователи: создание по телефону, поиск, блокировка, единая история операций.
  • Крипто-кошельки клиентов - адреса пополнения по сетям, депозиты, выводы на внешние адреса, расчёты charge / payout.
  • Мастер-счёт - предоплатный сервисный баланс: пополнение, леджер, витрина тарифа и лимитов.
  • AML-проверки - скоринг блокчейн-адресов с отчётом в JSON и PDF, оплата с мастер-счёта.
  • Верификация - KYC физических лиц и KYB компаний.
  • Платежи - покупка и продажа криптовалюты за рубли, баланс клиента.
  • Вебхуки - асинхронные события с HMAC-подписью и повторами доставки.
  • Песочница - изолированное окружение: ключи sk_test_ не двигают реальных денег.
Мастер-счёт нужен до первого платного вызова
Услуги платформы (например AML-проверки) и выплаты клиентам списываются с мастер-счёта. Пополните его до запуска в бой, иначе первый же платный вызов вернёт 402. Порог низкого остатка и вебхук о нём - в разделе Merchant Balance.

Модель доступа

B2B endpoints проверяют стек middleware в таком порядке:

  1. API Key auth - обычная аутентификация через Authorization: Bearer sk_(live|test)_xxx. См. Authentication.
  2. B2B gate - проверка флага users.b2b_enabled = true на учётке владельца ключа. Включается админом Finance OS вручную после договора.
  3. Environment isolation - sk_test_ ключ видит только env='sandbox' customers, sk_live_ - только env='live'. Попытка cross-env → 404 (намеренно, не 403: чтобы не утечь существование).

Сквозной пример интеграции

Шаги для полной интеграции нового партнёра:

  1. Партнёр регистрируется на fin-os.io, проходит свой собственный KYC.
  2. Партнёр и Finance OS подписывают B2B-договор, флаг b2b_enabled поднимается админом.
  3. Партнёр генерирует sk_live_ и sk_test_ ключи в Личном Кабинете → API ключи.
  4. Партнёр подписывает webhook-endpoint через POST /api/v1/webhooks и сохраняет полученный одноразовый секрет.
  5. Партнёр пополняет мастер-счёт: с него оплачиваются услуги платформы и выплаты клиентам.
  6. Для каждого своего end-user'а:
    1. Партнёр собирает консент end-user'а на обработку его данных в Finance OS.
    2. POST /api/v1/customers - создать клиента (телефон в E.164 обязателен).
    3. POST /api/v1/customers/{uuid}/consent - зафиксировать факт получения консента (IP + timestamp).
    4. POST /api/v1/customers/{uuid}/wallet/addresses - выдать адрес пополнения в нужной сети.
    5. Депозиты, выводы и расчёты - по событиям вебхуков, без опроса.
    6. Для фиатных операций дополнительно проводится KYC; после kyc_status='verified' доступны платежи.

Логика данных

Finance OS - это прокси-фасад поверх внутренних провайдеров (платежи, KYC). Партнёр взаимодействует только с Finance OS API; внутренняя инфраструктура провайдеров скрыта.

  • Customer state хранится у Finance OS: kyc_status, kyc_level, балансы.
  • Документы KYC хранятся у Finance OS, переадресуются провайдеру для верификации.
  • Платежи (СБП) идут через расчётный счёт Finance OS; Finance OS внутренне маркирует операцию customer'ом и обновляет баланс customer'а.
  • Webhook delivery - Finance OS подписывает HMAC и пушит на партнёрский URL с retry-логикой.

Что дальше

  • Customers - модель клиента, идемпотентное создание, поиск, блокировка, история
  • Customer Wallets - адреса, депозиты, выводы, расчёты charge / payout
  • Merchant Balance - мастер-счёт, леджер, тариф и лимиты
  • AML Screening - проверка адресов, отчёты, тарификация
  • KYC Verification - полный flow с примерами
  • Payments - buy/sell/deposit/withdraw
  • Webhooks - подписка, подпись, повторы доставки
  • Sandbox - тестирование без реальных операций
  • Error Codes - полный реестр кодов и стратегия повторов

Примеры кода

# Проверка B2B доступа: список customers
curl -X GET https://fin-os.io/api/v1/customers \
  -H "Authorization: Bearer sk_test_..." \
  -H "Accept: application/json"

# 403 если b2b_enabled=false:
# {
#   "message": "B2B access is not enabled for this account...",
#   "error_code": "B2B_ACCESS_REQUIRED",
#   "docs": "https://fin-os.io/docs/b2b"
# }

# 200 если включено:
# {
#   "data": [],
#   "meta": { "total": 0, ... }
# }
const FINOS_API = 'https://fin-os.io/api/v1';
const SECRET    = process.env.FINOS_SECRET_KEY; // sk_test_ или sk_live_

async function checkB2bAccess() {
  const res = await fetch(`${FINOS_API}/customers`, {
    headers: { 'Authorization': `Bearer ${SECRET}` },
  });
  if (res.status === 403) {
    const err = await res.json();
    throw new Error(`B2B not enabled: ${err.docs}`);
  }
  return res.json();
}
$response = Http::withToken(config('services.finos.secret_key'))
    ->acceptJson()
    ->get('https://fin-os.io/api/v1/customers');

if ($response->status() === 403) {
    throw new \RuntimeException(
        'B2B access required: ' . $response->json('docs')
    );
}
$customers = $response->json('data');
import requests, os

resp = requests.get(
    'https://fin-os.io/api/v1/customers',
    headers={'Authorization': f"Bearer {os.environ['FINOS_SECRET_KEY']}"},
)
if resp.status_code == 403:
    raise RuntimeError(f"B2B not enabled. See {resp.json()['docs']}")
customers = resp.json()['data']