MMeerPartners docs

API: Auth

Эндпоинты аутентификации MeerPartners: обмен MeerID, ротация и отзыв токенов, S2S token-exchange, активация партнёра и создание бизнеса.

Группа /api/v1/auth/* отвечает за вход людей и онбординг ролей. Вход — только через MeerID (единый OIDC SSO): email/пароля/OTP нет. Базовые механизмы и подпись HMAC описаны на странице Аутентификация.

POST /auth/meerid/exchange

POST/api/v1/auth/meerid/exchange🔒

Первая сессия: обмен результата авторизации MeerID на локальную JWT-пару. Поддерживает два потока — popup/redirect (по code + PKCE) и FedCM (по idToken). Передавайте поля ровно одного потока.

codestringoptional
Authorization code из popup/redirect-флоу MeerID. Обязателен для popup.
codeVerifierstringoptional
PKCE code_verifier. Обязателен для popup.
redirectUristringoptional
redirect_uri, использованный при авторизации. Обязателен для popup.
idTokenstringoptional
ID-токен из FedCM-флоу. Обязателен для FedCM.
noncestringoptional
nonce, связанный с FedCM-запросом. Обязателен для FedCM.
Ответ 200
{
  "access_token": "eyJhbGciOiJIUzI1NiIsInR5cCI6...",
  "refresh_token": "eyJhbGciOiJIUzI1NiIsInR5cCI6...",
  "token_type": "bearer",
  "expires_in": 900,
  "meerid_id_token": "eyJhbGciOiJSUzI1NiIs...",
  "user": {
    "user_id": 1042,
    "email": "creator@example.com",
    "display_name": "Аня",
    "is_affiliate": true,
    "affiliate_id": 88,
    "memberships": [
      { "tenant_id": 17, "role": "merchant_owner" }
    ]
  }
}

expires_in — TTL access-токена в секундах (900 = 15 минут). meerid_id_token нужен BFF-у как id_token_hint при выходе через MeerID (только в popup-флоу; FedCM его не выдаёт). Лимит: 20 запросов в минуту на IP — см. Лимиты.

Ошибки: MEERID_TOKEN_ERROR (401), MEERID_IDTOKEN_INVALID (401), MEERID_IDTOKEN_NONCE (401), MEERID_ACCESS_DENIED (403 — бан/удаление), MEERID_USERINFO_ERROR (401), MEERID_UNAVAILABLE (502), RATE_LIMIT_EXCEEDED (429).

POST /auth/refresh

POST/api/v1/auth/refresh🔒

Ротация refresh-токена: возвращает новую пару, старый refresh помечается использованным (одноразовый, с grace-окном на гонку параллельных рефрешей). Если у пользователя привязан MeerID refresh — платформа параллельно проверяет его и при бане/удалении аккаунта отзывает все локальные сессии.

refresh_tokenstringrequired
Действующий refresh-токен (минимум 10 символов).
Ответ 200
{
  "access_token": "eyJhbGciOiJIUzI1NiIs...",
  "refresh_token": "eyJhbGciOiJIUzI1NiIs...",
  "token_type": "bearer",
  "expires_in": 900
}

Ошибки: TOKEN_WRONG_TYPE (401), TOKEN_REVOKED (401), TOKEN_EXPIRED (401), TOKEN_INVALID (401), ACCESS_REVOKED (401 — аккаунт MeerID заблокирован/удалён).

Refresh одноразовый

После успешного refresh старый refresh-токен больше не действителен — сохраните новый. Повторный запрос с уже использованным токеном в пределах короткого grace-окна вернёт ту же свежую пару; за окном — TOKEN_REVOKED.

POST /auth/logout

POST/api/v1/auth/logout🔒 Bearer JWT

Отзыв текущей сессии (конкретного refresh-JTI). Access-токен доживает свой TTL. Идемпотентно: невалидный/уже отозванный токен всё равно вернёт успех.

refresh_tokenstringrequired
Refresh-токен сессии, которую закрываем.
Ответ 200
{ "message": "Выход выполнен" }

POST /auth/logout-all

POST/api/v1/auth/logout-all🔒 Bearer JWT

Отзыв всех сессий пользователя. Требует полный (не embed-scoped) токен.

Ответ 200
{ "message": "Отозвано сессий: 3" }

Ошибки: EMBED_SCOPE_DENIED (403 — вызвано scoped embed-токеном).

POST /auth/token-exchange

POST/api/v1/auth/token-exchange🔒 HMAC

S2S-обмен (RFC 8693-style): сервер бизнеса меняет внешний идентификатор своего пользователя на scoped affiliate-токен для embed-SDK. Аутентификация — подпись tenant_api_key со скоупом sso. tenant_id берётся только из ключа в БД; одноимённое поле в теле игнорируется (анти-IDOR).

subject_tokenstringrequired
Внешний идентификатор пользователя в системе бизнеса (1–255 символов). Хранится как opaque-строка.
subject_token_typestringoptional
Тип идентификатора. По умолчанию external_user_id.
grant_typestringoptional
Зарезервировано: urn:ietf:params:oauth:grant-type:token-exchange.
subject_profileobjectoptional
Необязательный профиль (email, display_name, locale). Недоверенный — применяется только при первом создании пользователя.
Ответ 200
{
  "access_token": "eyJhbGciOiJIUzI1NiIs...",
  "refresh_token": "eyJhbGciOiJIUzI1NiIs...",
  "token_type": "bearer",
  "expires_in": 600,
  "scope": "affiliate:embed",
  "affiliate_id": 88,
  "tenant_id": 17
}

Scoped-токен (scope: affiliate:embed, TTL 10 минут) даёт доступ только к чтению данных своего affiliate_id в группе Affiliate; мутации профиля/KYC и методов вывода через него запрещены.

Ошибки: TENANT_API_KEY_INVALID (401), TENANT_API_KEY_SCOPE_DENIED (403), EXCHANGE_DENIED (401), EXCHANGE_REPLAY (401), USER_BANNED (403), SERVICE_UNAVAILABLE (503).

POST /auth/affiliate/activate

POST/api/v1/auth/affiliate/activate🔒 Bearer JWT

Явный шаг «стать партнёром»: создаёт affiliate-профиль для текущего пользователя. Идемпотентно — повторный вызов вернёт тот же профиль. Требует полный Bearer-токен.

ref_codestringoptional
Необязательный реферальный код пригласителя (до 16 символов).
Ответ 200
{ "message": "Партнёрский профиль активирован (affiliate_id=88)" }

Ошибки: UNAUTHORIZED (401), EMBED_SCOPE_DENIED (403).

POST /auth/merchant/create-business

POST/api/v1/auth/merchant/create-business🔒 Bearer JWT

Атомарная регистрация бизнеса: создаёт tenant + аккаунт мерчанта + нулевой эскроу-баланс + членство merchant_owner в одной транзакции. Личность берётся из Bearer-токена (без email/OTP). Требует полный токен.

company_namestringrequired
Название компании (1–160 символов).
tenant_slugstringrequired
Уникальный идентификатор бизнеса. Шаблон ^[a-z0-9][a-z0-9_-]{1,63}$ (строчные латинские буквы, цифры, _, -).
default_currencystringoptional
Валюта по умолчанию, ISO-код. По умолчанию RUB.
display_namestringoptional
Отображаемое имя (до 160 символов).
Ответ 201
{
  "tenant_id": 17,
  "tenant_slug": "acme",
  "merchant_account_id": 21,
  "role": "merchant_owner",
  "message": "Бизнес создан."
}

Ошибки: TENANT_SLUG_TAKEN (409 — slug занят), VALIDATION_ERROR (422), USER_NOT_FOUND (404).

Один аккаунт — много бизнесов

Один и тот же пользователь MeerID может владеть несколькими бизнесами. Если у вас несколько tenant, при обращении к Merchant API указывайте активный через заголовок X-Tenant-Id.

Что дальше