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.

Ключ Тип Назначение
validFromstring?ISO-8601 · не раньше этого момента
validUntilstring?ISO-8601 · не позже (срок билета / проездного)
startedAtstring?ISO-8601 · активация поездки (trip); от неё считается окно пересадок
validForSecondsnumber?Длительность окна после startedAt (напр. 5400 = 90 мин)
unlimitedTransfersboolean?Безлимитные пересадки в окне
zonestring?Код зоны / тарифной зоны
ridesRemainingnumber?Остаток поездок; опустить или null при безлимите
memberIdstring?ID участника (membership)
accessstring?Уровень доступа (pass), напр. full
codestringЗначение для QR/штрихкода / BLE (aliases: barcode, qr)

Правило trip: now ∈ [startedAt, startedAt + validForSeconds] и now ∈ [validFrom, validUntil] (если заданы). Face может показать те же данные человекочитаемо через started / primaryValue, но проверка смотрит только на ISO/числа.

Поля dat (face)

Ключ Тип Назначение
layoutstringevent (по умолчанию) · boarding · coupon · transport · membership · discount · pass
modestring?Только для transport: trip (по умолчанию) · season (проездной; aliases: pass, seasonPass)
startedstring?Только face («21:04»). Для проверки используйте startedAt
backgroundColorstring#RGB / #RRGGBB / rgb()
foregroundColorstringТекст
labelColorstringАкцент (logo, primary)
logoTextstringТекст бренда в шапке
logoImagestring?HTTPS URL · иконка рядом с logoText
stripImagestring?HTTPS URL · полоса / hero на лице (aliases: stripUrl, heroImage)
descriptionstring?Короткая метка справа в шапке
titlestringГлавный заголовок (или code)
subtitlestring?
fieldsarray?{ label, value } · вторичные строки (сетка 2 колонки)
primaryLabelstring?Подпись крупного значения внизу (по умолчанию: Место / Выход / Офер / Срок / ID / Доступ)
primaryValuestring?Крупное значение (место, gate, скидка…) · alias seat
codestringКод входа / штрихкод (aliases: barcode, qr)

Обратная совместимость: если fields нет, бумажник собирает сетку из legacy-ключей when, city, venue, gate. Ключи html / template игнорируются. Картинки только по https://.

Layouts

  • eventклассический билет: шапка, опциональный strip, title, сетка fields, футер primary + code.
  • boardingstrip сверху; первые два 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. Выдаётся так же, как остальные утверждения: организация подписывает и отдаёт в бумажник пользователя. Как устроить выдачу — в руководстве по интеграции. Попробовать демо.