# Flights and boarding passes

Set up flights and boarding passes using Adaptive Links.

Managing boarding passes in a wallet project
involves some unique differences from other pass types. This document covers
information about flights, passengers, and boarding passes.

> **Note:** While you can create and modify boarding pass templates from the dashboard,
> all other operations — flight creation, creating adaptive links with flight and passenger information, etc. — are performed through the API.


## Boarding Pass Composition

A boarding pass is an [Adaptive Link](https://www.airship.com/docs/reference/glossary/#adaptive_link) that references a
boarding pass template, populated with one or more flights and one or more
passengers per flight.

While boarding passes resemble adaptive links for other pass types, you cannot create
a boarding pass using the standard dashboard or `/links/adaptive`
methods. You must use the `/links/adaptive/multiple/project` endpoints instead.

A boarding pass works much like a standard adaptive link, with the following differences.

* Boarding pass templates are referenced by ID. You must include at least one of `iosTemplate` or `googleTemplate` (or external ID equivalents `iosTemplateExternalId`, `androidTemplateExternalId`) in an adaptive link payload.

* The adaptive link payload references a `flightId`, `flightExternalId`, or contains a complete [flight object](https://www.airship.com/docs/developer/rest-api/wallet/schemas/flights-and-boarding-passes/#flightrequest).

* Each flight in a boarding pass adaptive link request includes an array of `passengers`. The request generates an adaptive link for each passenger in the array.

* Assets referenced by ID (templates, flights, etc.) must belong to the same project; you cannot use combinations of flights or templates across projects to create a boarding pass.

## Flights

You can create flights either:

* Using the `POST` method for the `/flights` endpoint. The `/flights` endpoint is a convenient way to create and modify flight information, independent of adaptive links and pass holders.

* By providing a flight payload when creating adaptive links.

In both cases, the result of your request is a `flightId` or `flightExternalId`that
you can use to reference the event — either to create boarding passes or to modify flight information from the `/flights` endpoint.

Any changes you make to an flight — moving the gate, changing departure or arrival times, etc. — automatically propagate to boarding passes (adaptive links) that
reference the flight.

**Flight request example**


```http
POST /v1/flights/project/<projectId> HTTP/1.1
Authorization: Basic <authorization string>
Content-Type: application/json

{
    "fields": {
        "flightNumber": {
            "value": "815"
        },
        "airlineCode": {
            "value": "OA"
        },
        "airlineName": {
            "value": "Sabine Airlines"
        },
        "departureAirport": {
            "label": "San Francisco",
            "value": "SFO"
        },
        "departureGate": {
            "label": "Gate #",
            "value": "25"
        },
        "boardingTime": {
            "value": "2018-07-30T08:35:00"
        },
        "departureTime": {
            "value": "2018-07-30T09:00:00"
        },
        "arrivalAirport": {
            "label": "Portland",
            "value": "PDX"
        },
        "arrivalTime": {
            "value": "2018-07-30T11:00:00"
        },
        "flightStatus": {
            "value": "scheduled"
        }
    },
    "passGroups": [
        "sfo-pdx-20180730"
    ]
}
```


### External IDs for Flights

You can create a flight with a custom identifier using the `/v1/flights/project/id/{projectExternalId}/id/{flightExternalId}` 
endpoint. A request specifying an external
flight ID returns the custom identifier as `flightExternalId`, and you reference flights
using this external identifier in lieu of the standard `flightId` in subsequent payloads,
including the request to create boarding pass adaptive links.

### Pass Groups for Flights and Boarding Passes {#pass-groups}

You can group flights together, so that you can modify multiple flights simultaneously — something you might need to do for flights with multiple stops.

To do this, you can assign flights to `passGroups` — plain text strings, similar to tags for passes. You can assign pass groups in any payload where you create a flight or after you create a flight using `/passgroups` endpoints.

**Add a pass group to an existing flight with an external ID**

```http
POST /v1/flights/project/id/<projectExternalId>/id/<flightExternalId>/passGroups HTTP/1.1
Authorization: Basic <authorization string>
Content-Type: application/json

{
  "passGroups" :["sfo-pdx-20180730", "pdx-yvr-20180730"]
}
```


You can then return a list of all flights bearing the `passGroup` string, or modify the group. When you modify a pass group, you only need to provide the individual fields that you want to update for all flights in the pass group. Any passes generated from flights in the group are automatically updated accordingly.

**Update all flights in a pass group**

```http
PUT /v1/flights/project/12345/passGroups/sfo-pdx-20180730 HTTP/1.1
Authorization: Basic <authorization string>
Content-Type: application/json

{
  "fields": {
    "departureTime": {
      "value": "2018-08-30T10:00:00"
    }
  }
}
```


## Passengers

The `passengers` array represents pass holders. Each object in the array is an individual pass holder and results in adaptive link. The `passengers` array appears within a flight object when creating boarding passes.

**Example boarding pass request with an array of passengers**

```http
POST /v1/links/adaptive/multiple/project/<projectId> HTTP/1.1
Authorization: Basic <authorization string>
Content-Type: application/json

{
  "iosTemplateExternalId": "boardingPass-ios",
  "androidTemplateExternalId": "boardingPass-android",
  "payload":{
    "flights":[
      {
        "flightExternalId": "sfo-tac-2018-08-30",
        "passengers": [
          {
            "fields": {
              "passengerName": { "value": "SMITH/JOE" },
              "seatNumber": { "value": "13A" },
              "seatClass": { "value": "Economy" },
              "boardingGroup": { "value": "5" },
              "securityProgram": { "value": "tsaPrecheck" },
              "confirmationCode": { "value": "E4583B" },
              "eticketNumber": { "value": "20595923485" },
              "frequentFlyerProgramName": { "value": "Rapid Rewards®" },
              "frequentFlyerNumber": { "value": "34525" },
              "drinkCoupon":  { "label": "Drink Coupon", "value": "Premium Drink" },
              "fareType": { "label": "Fare Type", "value": "Business Select" },
              "specialAssistance": { "label": "Special Assistance", "value": "Wheelchair" }
            }
          }
        ]
      }
    ]
  }
}
```


## Google Wallet Boarding Pass Templates

Google boarding pass templates are not as customizable as other template types. Many
of the fields on a boarding pass are required, like seat number, gate number,
etc. These fields cannot have default values, nor can they be moved or
customized in any way.

![The boarding pass template in the dashboard](https://www.airship.com/docs/images/boarding-pass-ui_hu_c1c84c921ca6b6f7.webp)

*The boarding pass template in the dashboard*

You can set colors, logos, and otherwise customize the general feel of your
boarding pass. But with boarding passes, more so than other pass types, you
will focus less on templates, and much more on modifying the information that
populates adaptive links built from those templates.

> **Important:** The flight information you enter when creating your template is only to help you design your template and send test passes; it is overwritten by a [flight object](https://www.airship.com/docs/developer/rest-api/wallet/schemas/flights-and-boarding-passes/#flightrequest) when you create boarding passes. See the [Boarding Pass Request object](https://www.airship.com/docs/developer/rest-api/wallet/schemas/flights-and-boarding-passes/#boardingpassrequest) for information about the flight object or ID you must provide when creating passes.

> **Note:** The Google Wallet boarding pass type supports airline boarding passes only. It does not support ferry, bus, or train tickets.


## Apple Wallet Boarding Pass Templates

While `flight` and `passenger` fields are native to Google Wallet templates, they are not native to Apple Wallet templates. You must name fields on your Apple Wallet template according to the `flight` and `passenger` schemas to support event ticket adaptive links. See [Flight and Boarding Pass Objects](https://www.airship.com/docs/developer/rest-api/wallet/schemas/flights-and-boarding-passes/) for a complete list of the field names your template should use.

* If you create your Apple Wallet Boarding Pass template through the dashboard: you must rename fields on your template to match `flight` and `passenger` object fields through the API.
* If you create your Apple Wallet Boarding Pass template through the API: you must name fields identically to `flight` and `passenger` objects.

> **Important:** The flight information you enter when creating your template is only to help you design your template and send test passes; it is overwritten by a [flight object](https://www.airship.com/docs/developer/rest-api/wallet/schemas/flights-and-boarding-passes/#flightrequest) when you create boarding passes. See the [Boarding Pass Request object](https://www.airship.com/docs/developer/rest-api/wallet/schemas/flights-and-boarding-passes/#boardingpassrequest) for information about the flight object or ID you must provide when creating passes.

> **Note:** For date-time fields on iOS boarding pass templates, you may want to set
> set `ignoresTimeZone: true`. Date-times for flights are set local to an airport terminal.
> Setting `ignoresTimeZone: true` prevents Apple Wallet from modifying times based on
> recipients' time zones.


**Example default Apple Wallet field names and supported boarding pass equivalents**

| Default field name | Rename field to |
|--------------------|-------------------------------------|
| `Seat` | `seatNumber` |
| `Depart Time` | `departureTime` |
| `Departure Airport` | `departureAirport` |
| `Class` | `seatClass` |
| `Arrival Airport` | `arrivalAirport` |
| `Passenger` | `passengerName` |
| `Ticket #` | `eticketNumber` |
| `Terminal Gate` | `departureTerminal` |
| `Flight #` | `flightNumber` |

## Adaptive Links for Boarding Passes

A boarding pass adaptive link is an adaptive link that generates or returns
platform-appropriate passes of the boarding pass type. It is created from
boarding pass templates and associated with `flights` and `passengers`.

> **Note:** You must use the `/links/adaptive/multiple/project/` endpoint to create boarding
> passes. While a boarding pass adaptive link has a similar request structure to other
> adaptive links, you cannot create boarding pass adaptive links through the standard
> `/links/adaptive` endpoint.


When you create an adaptive link, you can specify flights by `flightId` — the
identifier from a successful POST to the `/flights` endpoint. Templates and flights
referenced by ID must belong to the same project.

Within each flight, you will specify `passengers` — an array of objects, each
object representing an individual passenger with information like their
seat number, boarding group, etc.

**Example adaptive link request**


```http
POST /v1/links/adaptive/multiple/project/id/<projectExternalId> HTTP/1.1
Authorization: Basic <authorization string>
Content-Type: application/json

{
  "availablePasses": 1,
  "iosTemplateExternalId": "<iosTemplateExternalId>",
  "androidTemplateExternalId": "<androidTemplateExternalId>",
  "payload": {
    "isEventTicketUpdatePermitted": false,
    "flights": [
      {
        "flightId": "<flightId1>",
        "passengers": [
          {
            "adaptiveLinkExternalId": "<adaptiveLinkExternalId1>",
            "fields": {
              "seatNumber": { "value": "13A" },
              "confirmationCode": { "value": "E4583B" },
              "passengerName": { "value": "SMITH/JOE" },
              "specialAssistance": { "label": "Special Assistance", "value": "Wheelchair" }
            }
          },
          {
            "adaptiveLinkExternalId": "<adaptiveLinkExternalId2>",
            "fields": {
              "seatNumber": { "value": "13B" },
              "confirmationCode": { "value": "E4583B" },
              "passengerName": { "value": "SMITH/SALLY" }
            }
          },
          {
            "adaptiveLinkExternalId": "<adaptiveLinkExternalId2>",
            "fields": {
              "seatNumber": { "value": "13C" },
              "confirmationCode": { "value": "E4583B" },
              "passengerName": { "value": "SMITH/SAM" }
            }
          }
        ]
      }
    ]
  }
}
```


**Adaptive link response**


```http
HTTP/1.1 201 Created
Content-Type: application/json; charset=utf-8

[
  {
      "status": 201,
      "adaptiveLinkId": "<uaAdaptiveLinkId1>",
      "adaptiveLinkExternalId": "<adaptiveLinkExternalId1>",
      "iosTemplateId": "<iosTemplateId>",
      "iosTemplateExternalId": "<iosTemplateExternalId>",
      "androidTemplateId": "<androidTemplateId>",
      "androidTemplateExternalId": "<androidTemplateExternalId>",
      "url": "https://wallet-api.urbanairship.com/v1/pass/<adaptiveLinkSerialNumber1>",
      "iosUrl": "https://wallet-api.urbanairship.com/v1/pass/<adaptiveLinkSerialNumbe1r>/ios",
      "androidUrl": "https://wallet-api.urbanairship.com/v1/pass/<adaptiveLinkSerialNumber1>/android",
      "createdAt": "2018-07-05T09:12:32Z",
      "updatedAt": "2018-07-05T09:12:32Z",
      "isPersonalized": "false",
      "availablePasses": 1000000,
      "flightId": 465,
      "flightExternalId": "<flightExternalId1>",
      "iosPassLinkId": "eb94e8e0-4353-4e0b-bfe9-cfd21c52a540",
      "androidPassLinkId": "41c1ea48-f469-4968-b610-a98629ea19bc"
  }
]
```



## Modifying Flights and Passengers

Any endpoint supporting a `flight` payload will return a `flightId`. You can
look up, modify, or delete a flight using this ID in the path of the `/v1/flights`
endpoint, regardless of whether you created the flight using the `/v1/flights` endpoint or provided all flight information directly in an adaptive link payload.

If you assigned your flights to [Pass Groups](https://www.airship.com/docs/reference/glossary/#pass_groups), you can target the pass group to modify a common field across multiple flights in a group. For example, if you need to update `departureTime` for a group of flights, you could target the group and with a single update rather than updating each flight individually. When you update flights in a pass group, boarding passes associated with flights in the group are all updated accordingly.

**Modify all flights belonging to a pass group**


```http
PUT /v1/flights/project/12345/passGroups/sfo-pdx-20180730 HTTP/1.1
Authorization: Basic <authorization string>
Content-Type: application/json

{
  "fields": {
    "departureTime": {
      "value": "2018-08-30T10:00:00"
    }
  }
}
```


Passenger objects exist on adaptive links (boarding passes). If you want to modify
passengers on a flight (if a passenger moves seats, or cancels their ticket), you
will do so by modifying adaptive links directly.

You can also modify a flight at the same time you modify corresponding boarding passes, using a `POST` to `/v1/links/adaptive/multiple/project/id/{externalProjectId}`
specifying both an existing flight and the existing `adaptiveLinkExternalId` for the boarding passes you want to modify in the payload

## Modifying, Looking-up, and Deleting Boarding Passes

You can modify boarding passes using a POST to `/v1/links/adaptive/multiple/project/id/{externalProjectId}`
specifying both an existing flight and the existing `adaptiveLinkExternalId` for the boarding passes you want to modify in the payload; Airship treats this call as a `PUT` and updates boarding passes for the specified adaptive links. You cannot do the
same with standard `adaptiveLinkId`. Therefore, you should expect to set external
IDs for your adaptive links.

You can look up and delete boarding pass adaptive links using the standard GET and
DELETE methods for the `/v1/links/adaptive/{adaptiveLinkId}` and `/v1/links/adaptive/id/{adaptiveLinkExternalId}`
endpoints.

**Update the seat number for a passenger to 25A**


```http
POST /v1/links/adaptive/multiple/project/7341 HTTP/1.1
Authorization: Basic <authorization string>
Content-Type: application/json

{
  "iosTemplateId": 140633,
  "androidTemplateId": 122802,
  "projectId": 7341,
  "payload": {
    "flights": [
      {
        "flightId": 17385,
        "passengers": [
          {
            "adaptiveLinkExternalId": "test_user-1011",
            "fields": { "seatNumber": {"value": "25A"} }
          }
        ]
      }
    ]
  }
}
```


## Related Links

> * [Wallet API: Flights](https://www.airship.com/docs/developer/rest-api/wallet/operations/flights/)
> * [Wallet API: Adaptive Links for Boarding Passes](https://www.airship.com/docs/developer/rest-api/wallet/operations/adaptive-links/#createboardingpassoreventticketadaptivelinks)
