Persona Pass
Persona Pass
Утверждение с typ =
pass.ticket рисуется как нативная карточка Persona Pass. В dat передаёте
цвета, layout, произвольные поля и опциональные HTTPS-картинки — без HTML.
Что проверяется автоматически
Подпись issuer’а и сроки жизни самого claim — на оболочке Persona (iat / nbf / exp + sig). Face-поля вроде title, fields[].label, primaryValue —
только для отображения, их нельзя использовать как источник истины на турникете.
Для продуктовой проверки (окно пересадок, срок проездного, зона) кладите машиночитаемые
ключи ниже в dat.
| Ключ | Тип | Назначение |
|---|---|---|
| validFrom | string? | ISO-8601 · не раньше этого момента |
| validUntil | string? | ISO-8601 · не позже (срок билета / проездного) |
| startedAt | string? | ISO-8601 · активация поездки (trip); от неё считается окно пересадок |
| validForSeconds | number? | Длительность окна после startedAt (напр. 5400 = 90 мин) |
| unlimitedTransfers | boolean? | Безлимитные пересадки в окне |
| zone | string? | Код зоны / тарифной зоны |
| ridesRemaining | number? | Остаток поездок; опустить или null при безлимите |
| memberId | string? | ID участника (membership) |
| access | string? | Уровень доступа (pass), напр. full |
| code | string | Значение для QR/штрихкода / BLE (aliases: barcode, qr) |
Правило trip: now ∈ [startedAt, startedAt + validForSeconds] и now ∈ [validFrom, validUntil] (если заданы). Face может показать те же данные
человекочитаемо через started / primaryValue, но проверка
смотрит только на ISO/числа.
Поля dat (face)
| Ключ | Тип | Назначение |
|---|---|---|
| layout | string | event (по умолчанию) · boarding · coupon · transport · membership · discount · pass |
| mode | string? | Только для transport: trip (по умолчанию) · season (проездной; aliases: pass, seasonPass) |
| started | string? | Только face («21:04»). Для проверки используйте startedAt |
| backgroundColor | string | #RGB / #RRGGBB / rgb() |
| foregroundColor | string | Текст |
| labelColor | string | Акцент (logo, primary) |
| logoText | string | Текст бренда в шапке |
| logoImage | string? | HTTPS URL · иконка рядом с logoText |
| stripImage | string? | HTTPS URL · полоса / hero на лице (aliases: stripUrl, heroImage) |
| description | string? | Короткая метка справа в шапке |
| title | string | Главный заголовок (или code) |
| subtitle | string? | — |
| fields | array? | { label, value } · вторичные строки (сетка 2 колонки) |
| primaryLabel | string? | Подпись крупного значения внизу (по умолчанию: Место / Выход / Офер / Срок / ID / Доступ) |
| primaryValue | string? | Крупное значение (место, gate, скидка…) · alias seat |
| code | string | Код входа / штрихкод (aliases: barcode, qr) |
Обратная совместимость: если fields нет, бумажник собирает сетку из
legacy-ключей when, city, venue, gate. Ключи html / template игнорируются.
Картинки только по https://.
Layouts
- event — классический билет: шапка, опциональный strip, title, сетка fields, футер primary + code.
- boarding — strip сверху; первые два fields — крупные «ноги» (From/To); остальные в сетке; футер как у event.
- coupon — акцент на primaryValue (скидка/офер); fields компактно; code на всю ширину внизу.
- transport — городской транспорт.
mode: trip(по умолчанию) — старт поездки (started) + окно безлимитных пересадок (primaryValue, напр. «90 мин»); Zone/Class в fields; code внизу.mode: season— проездной с крупным Valid. - membership — членская карта: крупный ID по центру; fields (tier / expires); code внизу на всю ширину.
- discount — скидка или накопительная: тот же face, что coupon (primary = % / баланс баллов).
- pass — ключи / пропуск: иконка ключа, Access как primary, code на всю ширину для BLE/QR.
Примеры
event
{
"layout": "event",
"backgroundColor": "#141218",
"foregroundColor": "#fff7ea",
"labelColor": "#d4a04a",
"logoText": "Persona Claims",
"logoImage": "https://cdn.example.com/logo.png",
"stripImage": "https://cdn.example.com/strip.jpg",
"description": "Концерт",
"title": "Persona Night",
"subtitle": "Летняя сессия на крыше",
"primaryLabel": "Место",
"primaryValue": "VIP · A-12",
"fields": [
{
"label": "Когда",
"value": "21 авг · 21:00"
},
{
"label": "Город",
"value": "Москва"
},
{
"label": "Площадка",
"value": "Skyline Hall"
},
{
"label": "Вход",
"value": "Вход 3"
}
],
"code": "PN-AB12C"
}boarding
{
"layout": "boarding",
"backgroundColor": "#0c1a24",
"foregroundColor": "#e8f4ff",
"labelColor": "#5eb0e8",
"logoText": "Nordic Air",
"stripImage": "https://cdn.example.com/boarding-strip.jpg",
"title": "NA 482",
"subtitle": "Эконом · 14C",
"primaryLabel": "Выход",
"primaryValue": "B12",
"fields": [
{
"label": "Откуда",
"value": "LED"
},
{
"label": "Куда",
"value": "SVO"
},
{
"label": "Дата",
"value": "12 сен"
},
{
"label": "Посадка",
"value": "09:40"
}
],
"code": "NA482-14C"
}coupon
{
"layout": "coupon",
"backgroundColor": "#101812",
"foregroundColor": "#eef6ea",
"labelColor": "#7cbc6a",
"logoText": "Green Market",
"description": "Для участников",
"title": "Кофе на выходные",
"subtitle": "Любой размер · одна чашка",
"primaryLabel": "Скидка",
"primaryValue": "−30%",
"fields": [
{
"label": "Срок",
"value": "сб–вс"
},
{
"label": "Магазины",
"value": "Все кафе"
}
],
"code": "COFFEE30"
}transport · поездка
{
"layout": "transport",
"mode": "trip",
"backgroundColor": "#0f1419",
"foregroundColor": "#eef3f8",
"labelColor": "#6bb3ff",
"logoText": "Метро",
"description": "Разовая поездка",
"title": "Билет на 90 минут",
"subtitle": "Безлимитные пересадки",
"startedAt": "2026-07-21T21:04:00+02:00",
"validForSeconds": 5400,
"unlimitedTransfers": true,
"zone": "A+B",
"validFrom": "2026-07-21T00:00:00+02:00",
"validUntil": "2026-07-21T23:59:59+02:00",
"primaryLabel": "Срок",
"fields": [
{
"label": "Тариф",
"value": "Взрослый"
}
],
"code": "MTR-2A-8841"
}transport · проездной
{
"layout": "transport",
"mode": "season",
"backgroundColor": "#0f1419",
"foregroundColor": "#eef3f8",
"labelColor": "#6bb3ff",
"logoText": "Метро",
"description": "Проездной",
"title": "Единый · 30 дней",
"subtitle": "Все виды транспорта",
"primaryLabel": "Срок",
"validFrom": "2026-07-22T00:00:00+02:00",
"validUntil": "2026-08-21T23:59:59+02:00",
"unlimitedTransfers": true,
"zone": "A+B",
"fields": [
{
"label": "Тариф",
"value": "Взрослый"
}
],
"code": "PASS-30-8841"
}membership
{
"layout": "membership",
"backgroundColor": "#16120f",
"foregroundColor": "#f7f0e8",
"labelColor": "#c9a26b",
"logoText": "Sky Club",
"description": "Участник",
"title": "Анна Петрова",
"subtitle": "Gold · с 2024",
"primaryLabel": "ID",
"primaryValue": "SC-10482",
"memberId": "SC-10482",
"validFrom": "2024-01-01T00:00:00Z",
"validUntil": "2026-12-31T23:59:59Z",
"fields": [
{
"label": "Уровень",
"value": "Gold"
}
],
"code": "SC-10482"
}discount
{
"layout": "discount",
"backgroundColor": "#141018",
"foregroundColor": "#f4eef8",
"labelColor": "#b388ff",
"logoText": "Retail+",
"description": "Лояльность",
"title": "Баланс баллов",
"subtitle": "1 балл = 1 ₽",
"primaryLabel": "Баланс",
"primaryValue": "1 240 баллов",
"fields": [
{
"label": "Уровень",
"value": "Серебро"
},
{
"label": "До Gold",
"value": "260 до Gold"
}
],
"code": "RTL-ANNA-91"
}pass
{
"layout": "pass",
"backgroundColor": "#101418",
"foregroundColor": "#eef4f8",
"labelColor": "#5ec4a8",
"logoText": "Офис",
"description": "Доступ",
"title": "Корпус B · этаж 4",
"subtitle": "Служебный вход",
"primaryLabel": "Доступ",
"primaryValue": "Полный · BLE",
"access": "full",
"validFrom": "2026-01-01T00:00:00Z",
"validUntil": "2026-12-31T23:59:59Z",
"fields": [
{
"label": "Дверь",
"value": "B-4-Main"
}
],
"code": "KEY-B4-77A2"
}Выдача
Карточка — обычный подписанный claim с typ: "pass.ticket" и объектом выше в dat. Выдаётся так же, как остальные утверждения: организация подписывает и
отдаёт в бумажник пользователя. Как устроить выдачу — в руководстве по интеграции. Попробовать демо.