Документация для разработчиков
Единый вход, публичный каталог мероприятий и мастеров, продажа билетов, пользовательские данные и вебхуки. Одна интеграция — весь YFG.
Что такое YFG ID
YFG ID — провайдер входа по OAuth 2.0 / OpenID Connect и публичная платформа данных YFG. Партнёр может впустить пользователя на свой сайт, показать афишу и каталог мастеров, продать билет во встроенном виджете и получать изменения через вебхуки.
Вход и профиль
Authorization Code + PKCE, ID token, userinfo. Пользователь сам подтверждает доступ.
Витрина и продажи
Публичный каталог, остатки по типам билетов, статус отмены и виджеты покупки.
События в реальном времени
Вебхуки с подписью HMAC-SHA256: создание, публикация, изменение и отмена.
Базовые адреса
| Назначение | Адрес |
|---|---|
| Issuer | https://yfg.su/id |
| Discovery | https://yfg.su/id/.well-known/openid-configuration |
| JWKS | https://yfg.su/id/.well-known/jwks.json |
| Публичный API | https://yfg.su/id/api |
| OpenAPI 3.1 | https://yfg.su/id/api/openapi.json |
| Кабинет приложений | /id/apps |
client_credentials или HTTP Basic
с client_id и client_secret. Пользовательская
сессия нужна только для /api/me/*.
Запросы из браузера к /id/api/* разрешены только с origin,
добавленных в «Разрешённые адреса» приложения. Для остальных origin
CORS-заголовки не возвращаются.
Быстрый старт
-
Создайте приложение в кабинете YFG ID.
Укажите название, сайт,
redirect_uriи разрешённые origin для виджетов. Секрет показывается один раз — сохраните его на сервере. -
Выберите сценарий. Вход пользователя — Authorization Code + PKCE.
Серверная витрина —
client_credentialsили Basic. Встраивание на страницу — виджет. - Получите токен или авторизуйте приложение. Для каталога достаточно Basic, для пользовательских данных нужен access token.
-
Вызовите API. Каталог —
https://yfg.su/id/api/eventsи/api/masters; данные пользователя —/api/me/*. - Подпишитесь на вебхуки в карточке приложения, чтобы получать изменения мероприятий без polling.
Сервер-сервер за минуту
curl -X POST https://yfg.su/id/token \
-d grant_type=client_credentials \
-d client_id=YOUR_CLIENT_ID \
-d client_secret=YOUR_CLIENT_SECRET \
-d scope="events:read masters:read"
curl "https://yfg.su/id/api/events?when=upcoming&per_page=20" \
-H "Authorization: Bearer $ACCESS_TOKEN"
Basic-авторизация работает только для публичного каталога и только для
конфиденциальных приложений. client_secret никогда не попадает в браузер.
Вход и OAuth 2.0
Провайдер поддерживает Authorization Code, Refresh Token и Client Credentials. Для браузерных приложений используйте Authorization Code с PKCE S256; implicit flow намеренно не поддерживается.
| Метод | Endpoint | Назначение |
|---|---|---|
| GET | /authorize | Экран входа и согласия |
| POST | /token | Код, refresh или машинный токен |
| GET | /userinfo | Профиль по access token |
| GET | /.well-known/openid-configuration | Метаданные OIDC |
| GET | /.well-known/jwks.json | Публичные ключи RS256 |
| GET | /client/<client_id> | Публичная карточка приложения |
| POST | /revoke_token | Отзыв access или refresh |
| POST | /introspect | Проверка состояния токена |
| GET | /end_session | Выход из YFG ID |
Шаг 1. Отправьте пользователя на вход
https://yfg.su/id/authorize?response_type=code
&client_id=YOUR_CLIENT_ID
&redirect_uri=https://partner.example/callback
&scope=openid%20profile%20email
&state=RANDOM_STATE
&nonce=RANDOM_NONCE
&code_challenge=BASE64URL_SHA256_VERIFIER
&code_challenge_method=S256
response_type— толькоcode.stateобязателен для защиты от CSRF,nonce— для ID token.prompt=consentилиforce_confirm=1повторно показывает согласие;login_hintподсказывает логин.- Код живёт 5 минут, одноразовый и привязан к
client_id,redirect_uriи PKCE.
Шаг 2. Обменяйте код на токены
curl -X POST https://yfg.su/id/token \
-u "YOUR_CLIENT_ID:YOUR_CLIENT_SECRET" \
-d grant_type=authorization_code \
-d code=CODE_FROM_CALLBACK \
-d redirect_uri=https://partner.example/callback \
-d code_verifier=ORIGINAL_VERIFIER
{
"access_token": "yfg_at_...",
"token_type": "Bearer",
"expires_in": 3600,
"refresh_token": "yfg_rt_...",
"scope": "openid profile email",
"id_token": "eyJhbGciOiJSUzI1NiIs..."
}
Публичное приложение не отправляет секрет, но обязано передать
client_id и code_verifier. Поле
scope возвращается, если выданных прав меньше, чем у приложения;
id_token приходит при scope openid.
Шаг 3. Прочитайте профиль
curl https://yfg.su/id/userinfo \
-H "Authorization: Bearer $ACCESS_TOKEN"
Ответ содержит стандартные OIDC-поля и совместимые с Яндекс ID
id, login, display_name,
default_email, emails, is_avatar_empty —
в пределах выданных scope.
Client Credentials
Только для конфиденциальных приложений и только для
events:read / masters:read. Пользовательские
права в машинном токене запрещены. Refresh-токен не выдаётся.
curl -X POST https://yfg.su/id/token \
-d grant_type=client_credentials \
-d client_id=YOUR_CLIENT_ID \
-d client_secret=YOUR_CLIENT_SECRET \
-d scope="events:read masters:read"
Если scope не передан, выдаётся пересечение разрешённых
приложению каталоговых прав. Для Basic-авторизации каталога токен не нужен:
-u "client_id:client_secret".
https://yfg.su/id/.well-known/jwks.json; также проверяйте iss,
aud, exp и nonce. Не доверяйте
данным из токена, пока подпись не проверена.
Токены и профиль
| Токен | Срок | Особенности |
|---|---|---|
| Код авторизации | 5 минут | Одноразовый; повторное использование отзывает всю семью токенов |
| Access token | 1 час | В базе только SHA-256-хеш; передаётся в Authorization: Bearer |
| Refresh token | 30 дней | Ротация при каждом обновлении; повторное использование — признак кражи |
| Машинный access token | 1 час | client_credentials, без refresh и без /api/me/* |
| ID token (JWT) | 1 час | RS256, kid в заголовке, ключи в JWKS |
Обновление и отзыв
curl -X POST https://yfg.su/id/token \
-u "YOUR_CLIENT_ID:YOUR_CLIENT_SECRET" \
-d grant_type=refresh_token \
-d refresh_token=YOUR_REFRESH_TOKEN
При обновлении сохраните новый refresh token — старый сразу становится
недействительным. Отзыв: POST https://yfg.su/id/revoke_token с
token и token_type_hint. Выход из YFG ID:
GET https://yfg.su/id/end_session с id_token_hint и
post_logout_redirect_uri.
Пользователь может посмотреть и отозвать доступы в кабинете YFG ID → «Подключённые приложения». После отзыва все токены приложения перестают работать.
Права доступа
Права запрашиваются через scope и проверяются на каждом
endpoint. Неизвестное право — ошибка invalid_scope, а не
молчаливое отбрасывание.
| Scope | Группа | Что открывает | Claims |
|---|---|---|---|
openid | Вход | Идентификатор пользователя sub | sub |
profile | Вход | Имя, ник, аватар, город, статусы проверки | name, preferred_username, picture, locale, organizer_verified, master_verified |
email | Вход | Почта аккаунта | email, email_verified |
events:read | Мероприятия | Каталог, карточки, остатки по типам, отмена | — |
tickets:read | Билеты | Проверка статуса билета по коду | — |
tickets:sell | Билеты | Встраиваемая продажа билетов | — |
tickets:list | Билеты | Билеты пользователя | — |
resale:read | Билеты | Лоты вторичной продажи пользователя | — |
masters:read | Маркетплейс | Каталог мастеров, анкета, услуги, портфолио, слоты | master_verified |
orders:read | Маркетплейс | Заказы пользователя как клиента или мастера | — |
waitlist:read | Мероприятия | Записи в листе ожидания | — |
Псевдонимы принимаются для совместимости с Яндекс ID:
login:info, login:email, login:avatar,
login:birthday, login:default_phone,
user:read, default, basic,
events, tickets. Они приводятся к каноническим
правам до выдачи согласия.
events:read и masters:read. Для
/api/me/* нужен пользовательский access token.
Каталог мероприятий
Публичные мероприятия: published, completed и
cancelled. Черновики, модерация и удалённые записи не
отдаются. По умолчанию — ближайшие опубликованные.
| Метод | Endpoint | Назначение |
|---|---|---|
| GET | /api/events | Список с фильтрами и пагинацией |
| GET | /api/events/<id> | Полная карточка |
| GET | /api/events/<id>/availability | Быстрые остатки по типам |
Фильтры списка
| Параметр | Значения |
|---|---|
q | Поиск по названию, описанию, городу и адресу |
category | Категория мероприятия |
location | Город, подстрока |
when | upcoming (по умолчанию), past, all |
status | published (по умолчанию), completed, cancelled, all |
date_from, date_to | Дата или ISO-время; только дата — московские сутки |
price_min, price_max | Цена, рубли |
available | 1 — только с доступными билетами |
updated_since | ISO-время для инкрементальной синхронизации |
sort, dir | date, price, title, views, sales, updated |
page, per_page | Страница и размер, до 100 |
curl -u "$YFGID_CLIENT_ID:$YFGID_CLIENT_SECRET" \
"https://yfg.su/id/api/events?when=upcoming&status=all&per_page=20"
{
"id": 123,
"title": "Ночь настольных игр",
"status": "published",
"cancelled": false,
"date": "2026-11-15T20:00:00+03:00",
"date_label": "15.11.2026 20:00",
"location": "Москва",
"price": 1200,
"price_label": "от 1 200 руб.",
"sold_out": false,
"ticket_counts": {
"total": 100, "available": 37, "sold": 63, "sold_out": false
},
"ticket_types": [
{"id": 1, "name": "Стандарт", "quota": 80, "available": 37,
"sold": 43, "is_active": true, "sold_out": false},
{"id": 2, "name": "VIP", "quota": 20, "available": 0,
"sold": 20, "is_active": true, "sold_out": true}
]
}
ticket_counts считается по активным типам; если типов нет —
по агрегатам мероприятия. sold не бывает отрицательным.
Для отменённого события cancelled: true и заполнен
cancelled_at; причина отмены — внутренняя и в API не отдаётся.
Списки поддерживают ETag и If-None-Match (304),
Link, X-Total-Count и
X-RateLimit-*. Ответы кэшируются как
private, max-age=30.
Каталог мастеров
Только активные, проверенные модерацией мастера с активным аккаунтом. Скрытые и забаненные пользователи не попадают в каталог.
| Метод | Endpoint | Назначение |
|---|---|---|
| GET | /api/masters | Список с фильтрами |
| GET | /api/masters/<id> | Анкета, услуги, портфолио, слоты |
Фильтры
| Параметр | Значения |
|---|---|
q | Имя, ник, заголовок, описание, город |
specialization | Ключ специализации, например artist |
language | Ключ языка, например ru |
city | Город, подстрока |
available, verified | 1 — только доступные / проверенные |
rating | Минимальный рейтинг |
price_min, price_max | Цена услуг, рубли |
updated_since | ISO-время для синхронизации |
sort, dir | rating, reviews, orders, price, created, name, updated |
{
"id": 7,
"user_id": 42,
"username": "master",
"display_name": "Мастер",
"headline": "Иллюстрации и персонажи",
"specializations": ["artist"],
"rating": 4.9,
"review_count": 12,
"is_verified": true,
"is_available": true,
"price_from": 1500,
"price_label": "от 1 500 руб.",
"services_count": 3,
"url": "https://yfg.su/user/42"
}
Детальная карточка добавляет services,
portfolio (до 24 работ), slots (до 30 будущих
свободных окон), review_summary, время ответа и ссылки на
соцсети. Email и другие приватные данные не отдаются.
Данные пользователя
Пять ресурсов /api/me/* требуют пользовательский Bearer-токен
и соответствующий scope. Машинные токены и Basic здесь не работают.
| Endpoint | Scope | Что возвращает |
|---|---|---|
/api/me/tickets | tickets:list | Билеты: событие, тип, статус, цена |
/api/me/master | masters:read | Анкета мастера и активные услуги; без пагинации |
/api/me/orders | orders:read | Заказы как клиента и как мастера |
/api/me/waitlist | waitlist:read | Лист ожидания пользователя |
/api/me/resales | resale:read | Лоты вторичной продажи |
curl "https://yfg.su/id/api/me/tickets?page=1&per_page=50" \
-H "Authorization: Bearer $USER_ACCESS_TOKEN"
Коллекции поддерживают page и per_page (до 100,
по умолчанию 100 для обратной совместимости). Ответ:
items + pagination + meta.api_version.
/api/me/master возвращает объект {"master": ...}
или {"master": null}.
Виджеты
Виджет — самый быстрый способ показать афишу, билет, кнопку входа или
профиль. Покупка открывается в попапе YFG: деньги и билеты остаются на
стороне YFG, а сайт получает событие purchase.
<script src="https://yfg.su/static/js/yfgid_widget.js"
data-yfgid-client="YOUR_CLIENT_ID"
data-yfgid-theme="auto"></script>
<div data-yfgid-events="123,456" data-yfgid-columns="2"></div>
<div data-yfgid-buy="123" data-yfgid-label="Купить билет"></div>
<div data-yfgid-login></div>
| Атрибут | Назначение |
|---|---|
data-yfgid-event | Карточка одного мероприятия с покупкой |
data-yfgid-events | Витрина из нескольких id через запятую |
data-yfgid-buy | Компактная кнопка «Купить билет» |
data-yfgid-login | Кнопка входа; варианты light, dark, icon |
data-yfgid-profile | Карточка профиля после YFGID.setToken() |
data-yfgid-shape | card или ticket — вид билета с перфорацией |
data-yfgid-size | s, m, l |
data-yfgid-theme | light, dark, auto |
data-yfgid-columns | Колонки витрины, 1–4 |
data-yfgid-client | client_id, если не задан на <script> |
data-yfgid-scope | Scope для кнопки входа |
data-yfgid-login-url | Свой адрес входа вместо стандартного |
JavaScript API
| Метод | Назначение |
|---|---|
YFGID.renderAll() | Отрисовать все блоки на странице |
YFGID.refresh() | Сбросить кэш и перечитать данные |
YFGID.on('purchase', fn) | Успешная или неуспешная покупка в попапе |
YFGID.on('login', fn) | Перехват входа; return false отменяет стандартный переход |
YFGID.setToken(token) | Передать access token для профиля |
YFGID.openCheckout(id) | Открыть покупку программно |
YFGID.loginUrl(host) | Получить URL входа |
YFGID.on('purchase', function (payload) {
console.log('покупка', payload.event_id, payload.ok);
});
YFGID.on('login', function () { /* свой сценарий входа */ });
YFGID.refresh();
Домен страницы должен быть в «Разрешённых адресах» приложения. В консоли браузера виджет подскажет точный origin, который нужно добавить.
Вебхуки
Подписки настраиваются в карточке приложения. До 5 endpoint'ов на
приложение, только HTTPS. Секрет whsec_... показывается
один раз и хранится в зашифрованном виде. Там же можно повернуть
секрет, удалить подписку и посмотреть последние доставки.
| Событие | Когда приходит |
|---|---|
event.created | Мероприятие создано и опубликовано |
event.published | Черновик опубликован |
event.updated | Изменены публичные поля |
event.cancelled | Мероприятие отменено |
event.completed | Мероприятие завершено |
event.deleted | Мероприятие удалено |
{
"id": "evt_...",
"type": "event.cancelled",
"api_version": "1",
"created_at": "2026-10-28T00:00:00+03:00",
"data": { "id": 123, "status": "cancelled", "cancelled": true, "...": "..." }
}
| Заголовок | Значение |
|---|---|
X-YFG-Event | Тип события |
X-YFG-Delivery | ID доставки |
X-YFG-Timestamp | Unix-время подписи |
X-YFG-Signature | sha256=... от строки timestamp.body |
X-YFG-Api-Version | 1 |
import hashlib
import hmac
message = f"{timestamp}.{raw_body}".encode("utf-8")
expected = "sha256=" + hmac.new(
secret.encode("utf-8"), message, hashlib.sha256
).hexdigest()
assert hmac.compare_digest(expected, signature)
Отвечайте 2xx быстро; тело можно обрабатывать асинхронно.
410 Gone отключает endpoint. Ошибки и таймауты повторяются
до 8 попыток; паузы — 60 секунд, 5, 30 минут, 2, 6, 12 и 24 часа.
После 20 последовательных сбоев подписка отключается.
Лимиты и ошибки
| Операция | Лимит |
|---|---|
Каталог и /api/me/* | 240 запросов / 10 минут на приложение |
| Authorize | 120 / 10 минут на IP, 60 — на клиента |
| Token | 60 / 10 минут на IP, 120 — на клиента |
| Userinfo | 240 / 10 минут на клиента |
| Виджет | 600 / 10 минут на origin |
| Покупка в попапе | 30 / 10 минут, до 50 билетов за раз |
Каждый ответ API содержит X-RateLimit-Limit,
X-RateLimit-Remaining, X-RateLimit-Reset и
X-RateLimit-Window. При 429 приходит
Retry-After.
| Код | Когда | Что делать |
|---|---|---|
invalid_request | Нет параметра или он некорректен | Исправить запрос |
invalid_client | Неверный client_id или секрет | Проверить ключи |
invalid_grant | Код/refresh истёк или отозван | Начать вход заново |
invalid_scope | Право неизвестно или не разрешено | Исправить scope в кабинете |
invalid_token | Токен истёк, отозван или не тот тип | Обновить токен |
insufficient_scope | Нет нужного права | Запросить право у пользователя |
not_found | Объект скрыт или не существует | Не повторять запрос |
temporarily_unavailable | Rate limit или перегрузка | Повторить после Retry-After |
Ошибки API имеют вид
{"error": "...", "error_description": "...", "request_id": "..."}.
При обращении к API сохраняйте request_id — по нему быстрее
разобрать инцидент.
Версии и поддержка
Текущая версия API — 1. Она передаётся в
X-API-Version, meta.api_version и
X-YFG-Api-Version вебхуков. Обратно совместимые изменения
(новые поля и фильтры) выходят без смены версии; ломающие — только в
новой версии API.
- Машинный контракт: OpenAPI 3.1.
- Метаданные OIDC: discovery.
- Исходный код и примеры: GitHub YFG-CodeBase.
- Кабинет и выпуск секретов: YFG ID → Приложения.
Ограничения версии 1
Вебхуки сейчас покрывают только мероприятия; управление подписками —
через кабинет, без публичного API. Каталог только для чтения.
Пагинация — page/per_page, без cursor-режима.
Песочницы нет: для тестов используйте отдельное приложение и реальные
тестовые мероприятия.