# API PassKit для Apple Wallet

API PassKit Designer позволяет программно создавать, обновлять, загружать и управлять [картами Apple Wallet](/ru/product/messaging-channels/apple-wallet-passes/). Он поддерживает те же операции, что и конструктор карт в Control Panel. Используйте его для выпуска карт лояльности, купонов, билетов на мероприятия, посадочных талонов и карт магазинов, а также для отправки обновлений в реальном времени на карты, уже установленные на устройствах ваших пользователей.

<Aside type="note" title="Предварительное условие: сертификат PassKit">
Прежде чем вы сможете создавать карты для приложения, для этого приложения должен быть настроен сертификат подписи iOS PassKit. Сертификат управляется в Pushwoosh Control Panel. Без него запросы `create` и `update` завершатся ошибкой. См. [Настройка карт Apple Wallet для iOS](/ru/developer/first-steps/connect-messaging-services/ios-configuration/ios-wallet-pass-configuration/).
</Aside>

## Базовый URL

```
https://apple-passkit.svc-nue.pushwoosh.com
```

Все эндпоинты обслуживаются по HTTPS. Запросы и ответы используют `application/json`, если не указано иное.

## Аутентификация

Каждый запрос должен включать заголовок `Authorization` с вашим [токеном доступа к API Pushwoosh](/ru/developer/api-reference/api-access-token/):

```
Authorization: Token <api-token>
```

Аккаунт, которому принадлежит токен, должен владеть приложением, на которое ссылается `applicationCode`. Запрос для приложения, принадлежащего другому аккаунту, вернет `403 Forbidden`.

## Соглашения

*   **Именование полей:** Поля JSON используют `lowerCamelCase` (например, `passTypeIdentifier`, `serialNumber`, `backgroundColor`).
*   **Незаполненные поля:** ответы включают все поля, даже если они пустые или имеют нулевое значение.
*   **Бинарные данные:** поля типа `bytes`, такие как `pkpassData` и `data` изображений, являются строками в формате Base64 в JSON.
*   **Серийные номера:** `serialNumber` всегда присваивается сервером при создании карты. Любое значение, которое вы отправляете при создании, игнорируется; он идентифицирует карту для всех последующих операций.

### Ответы об ошибках

API сопоставляет внутренние коды состояния с кодами состояния HTTP:

| Код состояния HTTP | Значение |
| :---- | :---- |
| `400 Bad Request` | Неверный аргумент — обязательное поле отсутствует или имеет неверный формат. |
| `401 Unauthorized` | Отсутствует или недействителен заголовок `Authorization`. |
| `403 Forbidden` | Приложение не принадлежит аккаунту вызывающей стороны. |
| `404 Not Found` | Карта, шаблон или приложение не найдены. |
| `503 Service Unavailable` | Сервис перегружен или временно недоступен. |

## Эндпоинты

| Метод | Путь | Описание |
| :---- | :---- | :---- |
| `POST` | `/api/pass/validate` | Проверить конфигурацию карты |
| `POST` | `/api/pass/create` | Создать новый `.pkpass` |
| `POST` | `/api/pass/update/{serialNumber}` | Обновить существующую карту и уведомить устройства |
| `GET` | `/api/passes` | Получить список всех карт для приложения |
| `GET` | `/api/pass/{applicationCode}/{serialNumber}` | Получить одну карту |
| `GET` | `/api/pass/{applicationCode}/{serialNumber}/download` | Загрузить `.pkpass` существующей карты |
| `DELETE` | `/api/pass/{applicationCode}/{serialNumber}` | Удалить карту |
| `GET` | `/api/pass/{serialNumber}/registrations` | Получить список устройств, зарегистрированных для карты |
| `GET` | `/api/config` | Получить конфигурацию PassKit для приложения |
| `GET` | `/api/templates` | Получить список доступных шаблонов карт |
| `GET` | `/api/templates/{filename}` | Получить один шаблон |


## Создать карту

Генерирует, подписывает и сохраняет новую карту, а затем возвращает присвоенный сервером серийный номер.

`POST` `/api/pass/create`

<Aside type="tip">
Чтобы получить сам файл `.pkpass`, вызовите [Загрузить карту](#download-a-pass) (или создайте [ссылку для установки / QR-код](#share-a-pass-as-a-qr-code)) с возвращенным серийным номером.
</Aside>


### Тело запроса

| Параметр | Тип | Обязательный | Описание |
| :---- | :---- | :---- | :---- |
| `pass` | object | Да | [Объект карты](#pass-object), описывающий карту. |
| `images` | array of objects | Нет | [Изображения карты](#pass-image-object) (icon, logo и т.д.). `icon` и `logo` обязательны для действительной карты. |
| `userId` | string | Да | User ID в Pushwoosh, которому выдана карта. |
| `applicationCode` | string | Да | [Код приложения Pushwoosh](/ru/developer/api-reference/api-identifiers/#application-code). |

<Aside type="note">
При создании, если `teamIdentifier`, `passTypeIdentifier` или `organizationName` опущены, они по умолчанию принимают значения из настроенного сертификата приложения. `formatVersion` по умолчанию равен `1`. `serialNumber` присваивается на стороне сервера.
</Aside>

##### Пример запроса

```json
{
  "applicationCode": "XXXXX-XXXXX",
  "userId": "user-123",
  "pass": {
    "description": "Acme loyalty card",
    "logoText": "Acme",
    "backgroundColor": "rgb(60, 65, 76)",
    "foregroundColor": "rgb(255, 255, 255)",
    "labelColor": "rgb(255, 255, 255)",
    "storeCard": {
      "primaryFields": [
        { "key": "balance", "label": "BALANCE", "value": "1200 pts" }
      ],
      "secondaryFields": [
        { "key": "member", "label": "MEMBER", "value": "Jane Doe" }
      ]
    },
    "barcodes": [
      {
        "format": "PKBarcodeFormatQR",
        "message": "1234567890",
        "messageEncoding": "iso-8859-1"
      }
    ]
  },
  "images": [
    { "imageType": "icon", "data": "<base64>", "contentType": "image/png" },
    { "imageType": "logo", "data": "<base64>", "contentType": "image/png" }
  ]
}
```

### Ответ

| Поле | Тип | Описание |
| :---- | :---- | :---- |
| `serialNumber` | string | Присвоенный сервером уникальный идентификатор созданной карты. Используйте его для получения карты ([Получить карту](#get-a-pass)) или загрузки `.pkpass` ([Загрузить карту](#download-a-pass)). |
| `message` | string | Сообщение о результате. |

##### Пример ответа

```json
{
  "serialNumber": "a1b2c3d4-1234-5678-9abc-def012345678",
  "message": "Карта успешно создана"
}
```

## Проверить карту

Проверяет конфигурацию карты на соответствие спецификациям Apple без создания файла. Полезно вызывать перед созданием.

`POST` `/api/pass/validate`

### Тело запроса

| Параметр | Тип | Обязательный | Описание |
| :---- | :---- | :---- | :---- |
| `pass` | object | Да | [Объект карты](#pass-object) для проверки. |

### Ответ

| Поле | Тип | Описание |
| :---- | :---- | :---- |
| `valid` | boolean | Проходит ли карта проверку. |
| `errors` | array of strings | Блокирующие проблемы, которые необходимо исправить. |
| `warnings` | array of strings | Неблокирующие рекомендации. |



## Обновить карту

Повторно генерирует карту с новым содержимым, переподписывает ее, увеличивает ее тег обновления и отправляет **тихое push-уведомление** на каждое устройство, зарегистрировавшее карту. Затем iOS извлекает и устанавливает обновленную версию в фоновом режиме.

`POST` `/api/pass/update/{serialNumber}`

### Параметры пути

| Параметр | Тип | Описание |
| :---- | :---- | :---- |
| `serialNumber` | string | Серийный номер, возвращенный при создании карты. |

### Тело запроса

| Параметр | Тип | Обязательный | Описание |
| :---- | :---- | :---- | :---- |
| `updates` | object | Да | Полный [объект карты](#pass-object) с новым содержимым. |
| `applicationCode` | string | Да | Код приложения Pushwoosh. |

`serialNumber` (из пути) и токен аутентификации карты сохраняются сервером независимо от того, что вы отправляете.

### Ответ

| Поле | Тип | Описание |
| :---- | :---- | :---- |
| `success` | boolean | Успешно ли прошло обновление. |
| `updateTag` | integer | Новый тег обновления (временная метка Unix). |
| `message` | string | Сообщение о результате. |



## Получить список карт

Возвращает постраничный, отсортированный список карт, хранящихся для приложения.

`GET` `/api/passes?applicationCode=XXXXX-XXXXX&page=0&perPage=20`

### Параметры запроса

| Параметр | Тип | Обязательный | Описание |
| :---- | :---- | :---- | :---- |
| `applicationCode` | string | Да | Код приложения Pushwoosh. |
| `orderBy` | string | Нет | Поле сортировки: `UPDATED` (по умолчанию) или `CREATED`. |
| `orderDirection` | string | Нет | Направление сортировки: `DESC` (по умолчанию, сначала новые) или `ASC`. |
| `page` | integer | Нет | Индекс страницы, начиная с нуля. По умолчанию `0`. |
| `perPage` | integer | Нет | Размер страницы. `0` или пропущенное значение использует значение по умолчанию сервера. |

### Ответ

| Поле | Тип | Описание |
| :---- | :---- | :---- |
| `passes` | array of objects | Текущая страница [записей карт](#pass-record-object). |
| `page` | integer | Возвращенный индекс страницы. |
| `perPage` | integer | Размер страницы, использованный для этого ответа. |
| `total` | integer | Общее количество карт для приложения на всех страницах. |

##### Пример ответа

```json
{
  "passes": [ /* pass records */ ],
  "page": 0,
  "perPage": 20,
  "total": 137
}
```


## Получить карту

Возвращает одну сохраненную карту, включая ее полный объект карты.

`GET` `/api/pass/{applicationCode}/{serialNumber}`

### Параметры пути

| Параметр | Тип | Описание |
| :---- | :---- | :---- |
| `applicationCode` | string | Код приложения Pushwoosh. |
| `serialNumber` | string | Серийный номер карты. |

### Ответ

Возвращает `{ "pass": { ... } }`, одну [запись карты](#pass-record-object).


## Загрузить карту

Возвращает сохраненный файл `.pkpass` существующей карты.

`GET` `/api/pass/{applicationCode}/{serialNumber}/download`

### Ответ

| Поле | Тип | Описание |
| :---- | :---- | :---- |
| `pkpassData` | string (Base64) | Файл `.pkpass`. |
| `filename` | string | Предлагаемое имя файла. |


## Удалить карту

Удаляет запись карты и ее сохраненный файл `.pkpass`.

`DELETE` `/api/pass/{applicationCode}/{serialNumber}`

### Ответ

| Поле | Тип | Описание |
| :---- | :---- | :---- |
| `success` | boolean | Была ли карта удалена. |
| `message` | string | Сообщение о результате. |



## Получить регистрации карты

Возвращает список устройств, которые добавили карту и зарегистрированы для получения обновлений.

`GET` `/api/pass/{serialNumber}/registrations?applicationCode=XXXXX-XXXXX`

### Ответ

Возвращает `{ "registrations": [ ... ] }`, где каждый элемент имеет:

| Поле | Тип | Описание |
| :---- | :---- | :---- |
| `deviceLibraryIdentifier` | string | Идентификатор библиотеки устройств Apple. |
| `pushToken` | string | Push-токен карты для устройства. |



## Получить конфигурацию

Возвращает конфигурацию PassKit, определенную для приложения из его сертификата.

`GET` `/api/config?applicationCode=XXXXX-XXXXX`

### Ответ

| Поле | Тип | Описание |
| :---- | :---- | :---- |
| `teamIdentifier` | string | Apple Team ID из сертификата. |
| `passTypeIdentifier` | string | Pass Type ID из сертификата. |
| `organizationName` | string | Название организации из сертификата. |
| `hasCertificate` | boolean | Настроен ли сертификат. |
| `webServiceUrl` | string | Базовый URL веб-сервиса карт. Клиенты создают ссылку для установки, добавляя `/v1/passes/{passType}/{serial}?token={authToken}`. |



## Шаблоны

Получите список доступных шаблонов карт или загрузите один из них как [объект карты](#pass-object), который можно использовать в качестве отправной точки.

`GET` `/api/templates` — возвращает `{ "templates": [ { "filename", "name", "description", "style" } ] }`.

`GET` `/api/templates/{filename}` — возвращает `{ "template": { ...объект карты... } }`.



## Поделиться картой с помощью QR-кода

Чтобы пользователи могли добавить карту, отсканировав QR-код (или нажав на ссылку), закодируйте **URL для установки** карты в QR-код. URL-адрес создается из значений, которые вы уже получаете от API:

```
{webServiceUrl}/v1/passes/{passTypeIdentifier}/{serialNumber}?token={authenticationToken}
```

| Часть URL | Где получить |
| :---- | :---- |
| `webServiceUrl` | [`GET /api/config`](#get-configuration) → `webServiceUrl` |
| `passTypeIdentifier` | [запись карты](#pass-record-object) → `pass.passTypeIdentifier` (из списка/получения) |
| `serialNumber` | [запись карты](#pass-record-object) → `serialNumber` |
| `authenticationToken` | [запись карты](#pass-record-object) → `pass.authenticationToken` |

Пример:

```
https://apple-passkit.svc-nue.pushwoosh.com/v1/passes/pass.com.acme.loyalty/a1b2c3d4-1234-5678-9abc-def012345678?token=AbC123XyZ
```

Преобразуйте этот URL в QR-код с помощью любой библиотеки для QR-кодов. Когда пользователь сканирует его, его устройство открывает ссылку, загружает последнюю версию `.pkpass`, и Wallet предлагает добавить его, что также регистрирует устройство для получения обновлений.



## Справочник объектов

### Объект карты

| Поле | Тип | Описание |
| :---- | :---- | :---- |
| `formatVersion` | integer | Версия формата карты. По умолчанию `1`. |
| `passTypeIdentifier` | string | Apple Pass Type ID (`pass.com.yourcompany.passtype`). По умолчанию берется из сертификата. |
| `serialNumber` | string | Присваивается сервером при создании; идентифицирует карту. |
| `teamIdentifier` | string | Apple Team ID. По умолчанию берется из сертификата. |
| `organizationName` | string | Организация, отображаемая на карте. По умолчанию берется из сертификата. |
| `description` | string | Человекочитаемое описание (требуется Apple). |
| `boardingPass` / `coupon` / `eventTicket` / `storeCard` / `generic` | object | Стиль карты. Должен быть установлен **ровно один**. См. [группы полей](#field-group-object). |
| `backgroundColor` | string | Цвет фона, `rgb(r, g, b)`. |
| `foregroundColor` | string | Цвет переднего плана (текста), `rgb(r, g, b)`. |
| `labelColor` | string | Цвет метки поля, `rgb(r, g, b)`. |
| `logoText` | string | Текст, отображаемый рядом с логотипом. |
| `suppressStripShine` | boolean | Отключить эффект блеска на изображении-полосе. |
| `barcodes` | array | [Штрих-коды](#barcode-object), отображаемые на карте. |
| `locations` | array | [Местоположения](#location-object), которые делают карту релевантной. |
| `beacons` | array | [Маячки](#beacon-object), которые делают карту релевантной. |
| `relevantDate` | string | Дата в формате ISO 8601, когда карта становится релевантной. |
| `maxDistance` | integer | Максимальное расстояние (в метрах) для релевантности по местоположению. |
| `expirationDate` | string | Дата истечения срока действия в формате ISO 8601. |
| `voided` | boolean | Помечает карту как недействительную. |
| `groupingIdentifier` | string | Группирует связанные карты (билеты на мероприятия/посадочные талоны). |
| `userInfo` | object (map) | Произвольные данные приложения в формате ключ/значение. |

<Aside type="note">
`authenticationToken` и `webServiceUrl` управляются сервисом и не требуют установки клиентами API.
</Aside>

### Объект группы полей

Каждый стиль карты (`boardingPass`, `coupon`, `eventTicket`, `storeCard`, `generic`) группирует [поля](#field-object) по областям:

| Поле | Тип | Описание |
| :---- | :---- | :---- |
| `headerFields` | array | Отображается в заголовке карты (видно, когда карты сложены в стопку в Wallet). |
| `primaryFields` | array | Наиболее заметные поля. |
| `secondaryFields` | array | Под основными полями. |
| `auxiliaryFields` | array | Дополнительные поля под второстепенными. |
| `backFields` | array | Отображается на обратной стороне карты. |

`boardingPass` дополнительно имеет `transitType` (`PKTransitTypeAir`, `PKTransitTypeTrain`, `PKTransitTypeBus`, `PKTransitTypeBoat` или `PKTransitTypeGeneric`).

### Объект поля

| Поле | Тип | Описание |
| :---- | :---- | :---- |
| `key` | string | Уникальный ключ поля в пределах карты. |
| `label` | string | Метка поля. |
| `value` | string | Значение поля (текст или число в виде строки). |
| `changeMessage` | string | Сообщение, отображаемое при изменении значения (используйте `%@` в качестве заполнителя). |
| `textAlignment` | string | Значение `PKTextAlignment`. |
| `dateStyle` / `timeStyle` | string | `PKDateStyle` для форматирования даты/времени. |
| `isRelative` | boolean | Показывать дату относительно текущего момента. |
| `numberStyle` | string | `PKNumberStyle` для форматирования чисел. |
| `currencyCode` | string | Код валюты по ISO 4217. |
| `dataDetectorTypes` | array of strings | Детекторы данных для применения к значению. |

### Объект штрих-кода

| Поле | Тип | Описание |
| :---- | :---- | :---- |
| `format` | string | `PKBarcodeFormatQR`, `PKBarcodeFormatPDF417`, `PKBarcodeFormatAztec` или `PKBarcodeFormatCode128`. |
| `message` | string | Данные, закодированные в штрих-коде. |
| `messageEncoding` | string | Кодировка текста, обычно `iso-8859-1`. |
| `altText` | string | Текст, отображаемый под штрих-кодом. |

### Объект местоположения

| Поле | Тип | Описание |
| :---- | :---- | :---- |
| `latitude` | number | Широта. |
| `longitude` | number | Долгота. |
| `altitude` | number | Высота в метрах. |
| `relevantText` | string | Текст, отображаемый на экране блокировки рядом с этим местоположением. |

### Объект маячка

| Поле | Тип | Описание |
| :---- | :---- | :---- |
| `proximityUuid` | string | UUID приближения iBeacon. |
| `major` | integer | Основное значение (Major). |
| `minor` | integer | Дополнительное значение (Minor). |
| `relevantText` | string | Текст, отображаемый на экране блокировки рядом с этим маячком. |

### Объект изображения карты

| Поле | Тип | Описание |
| :---- | :---- | :---- |
| `imageType` | string | Одно из: `icon`, `logo`, `strip`, `background`, `footer`, `thumbnail`. `icon` и `logo` обязательны. |
| `data` | string (Base64) | Байты изображения. |
| `contentType` | string | MIME-тип, например `image/png`. |

### Объект записи карты

Возвращается эндпоинтами получения списка/одной записи.

| Поле | Тип | Описание |
| :---- | :---- | :---- |
| `serialNumber` | string | Серийный номер карты. |
| `passTypeIdentifier` | string | Pass Type ID. |
| `organizationName` | string | Название организации. |
| `description` | string | Описание карты. |
| `createdAt` | string | Временная метка создания (RFC 3339). |
| `updatedAt` | string | Временная метка последнего обновления (RFC 3339). |
| `updateTag` | integer | Текущий тег обновления. |
| `pass` | object | Полный [объект карты](#pass-object) для редактирования. |
| `userId` | string | User ID в Pushwoosh, которому была выдана карта. |