# Designing and managing templates Design and manage Wallet pass templates. # Design a template > Configure a template's appearance and fields. After you [create a new template](https://www.airship.com/docs/guides/wallet/getting-started/project-template/), you are prompted to start building the template design. Also follow these steps when editing an existing template. > **Note:** The sample images on this page are for Google Wallet templates. Please refer to each step's linked documentation for full detail for both Apple Wallet and Google Wallet template options. If you just created a new template and clicked **Start Building**, your screen will be open to the template editor. If not, first open an existing template: Go to *Templates*, click anywhere in a template's row to see its expanded view, then click **Edit Design**. Now you can design your template: 1. Configure the **general settings** that apply to the entire template rather than to a single field. Available properties vary per pass type. Return to these settings at any time by clicking the paintbrush icon in the upper right corner of the pass preview. [Read more about general settings.](https://www.airship.com/docs/guides/wallet/user-guide/ui/template-editor/#general-settings) ![Configuring general settings in the template editor](https://www.airship.com/docs/images/editor-layout_hu_c76615f5d5dd69e7.webp) *Configuring general settings in the template editor* 1. Add **images**. Click in the preview to select each image. A modal window will open, specifying requirements and options. [Read more about images.](https://www.airship.com/docs/guides/wallet/user-guide/ui/template-editor/#images) ![Adding images to a pass template](https://www.airship.com/docs/images/pass-editor-image_hu_437c0313e53cad31.webp) *Adding images to a pass template* 1. Edit the content and placement of the pass **fields**. Click in the preview to select a field and its configuration pane will display on the right side of the screen. You can edit the field ID, delete the field, change the position of the field on the pass, or remove the field from the layout. [Read more about pass fields.](https://www.airship.com/docs/guides/wallet/user-guide/ui/template-editor/#fields) ![Editing a pass field in the template editor](https://www.airship.com/docs/images/pass-editor-field_hu_112ad09088f27f19.webp) *Editing a pass field in the template editor* > **Important:** Google Wallet *Class* fields are edited inline in the preview. Clicking on a class field > will not expose a configuration pane. See: > [Template Editor Overview: Google Class Fields](https://www.airship.com/docs/guides/wallet/user-guide/ui/template-editor/#class-fields). 1. Click **Save** at any point in the design process. Now that you have a saved template, you are ready for the next steps: * **Send the pass to yourself** so you can preview it on a mobile device. See: [Send a Test Pass](https://www.airship.com/docs/guides/wallet/user-guide/design-template/test-pass/). * **Generate pass links** based on your template. See: [About Adaptive Links](https://www.airship.com/docs/guides/wallet/user-guide/create-links/adaptive-links/). * **Set the sharing policy** for your passes. See: [Set the sharing policy for a Wallet pass ](https://www.airship.com/docs/guides/wallet/user-guide/design-template/manage/#set-the-sharing-policy-for-a-wallet-pass) in *Manage Wallet templates*. ## Editing Template Designs When you modify the design of a template, any new passes created from the template use the new and updated design, but you only affect currently installed passes if: * You add or remove a field on the pass. Airship automatically pushes the template update to installed passes to ensure that all passes contain the same fields as the template. * You [publish your template changes](#publish) to installed passes. You can schedule this operation or publish changes immediately, but this operation updates currently-installed passes to match the template. > **Note:** Contact your Airship account manager if you want to update your template design but *do not* want new passes to use the new design yet (e.g., scheduling a branding change). ### Publish Template Updates to Passes {#publish} When updating a template, if you don't add or remove a field, your changes do not modify passes that were already generated from the template. To update current passes to match your template, you must publish changes to passes. To publish template design changes to your existing passes: 1. Click **Templates** and select the template you want to edit. 1. Click **Publish**. 1. Select the audience of passes you want to affect. You can publish your template design update to all users or a segment of passes. 1. Determine when to publish template design updates — now, or a date and time in the future. 1. Click **Confirm Publish**. ### Use the Wallet API to Publish Template Updates After you update a template, you can publish template design updates to existing passes using the wallet API. * Publish immediately: use the `/template/{template_id}/passes` API. * Schedule Updates: use the `/schedules/{project_id}` API. You update field values on passes when you publish changes to a template. However, because you're updating fields on an audience of passes, you should restrict field updates to information that you want to be uniform across passes in your audience segment. **Publish a template update immediately** ```http PUT /v1/template/(templateId)/passes HTTP/1.1 Content-Type: application/json Authorization: Basic Api-Revision: 1.2 { "fields": { "Loyalty Name": { "value": "Cool new loyalty program" } } } ``` **Publish a template update on a schedule** ```http POST /v1/schedules/12345 HTTP/1.1 Authorization: Basic Content-Type: application/json Api-Revision: 1.2 { "template": "12345", "name": "Loyalty program rebrand", "schedule": { "scheduled_time": "2020-07-25T00:00:00" }, "update": { "audience": { "tag": "TZ_ET" }, "pass": { "fields": { "Loyalty Name": { "value": "Cool new loyalty program" } } } } } ``` # Boarding pass overrides > Boarding pass overrides customize the placement and order of fields in Google boarding passes. You can configure boarding pass overrides through the [wallet template editor](https://www.airship.com/docs/guides/wallet/user-guide/ui/template-editor/) or the [Wallet API](https://www.airship.com/docs/developer/rest-api/wallet/). > **Note:** Boarding pass overrides only work with Google passes. Apple passes do not support this functionality. If you are using the Update Template API to override the layout of a pass, it may help you to first view the template in the template editor to better understand its current layout. ## Google Pass Layout Google passes are organized into sections, each of which has a default layout. You can pass `overrides` when creating your boarding pass template to customize the labels and layout of fields in the sections listed below. When you override the label or position of a field in one of these sections, you must override all the fields in that section. ![Boarding pass template sections that support overrides](https://www.airship.com/docs/images/walletTemplateOverview_hu_5d9fafff706bee67.webp) *Boarding pass template sections that support overrides* You can override the following sections: 1. `cardTemplate`: Supports 2 rows, 3 columns of information. You can override the area in this part of the template. 1. `barcodeSection`: The barcode area of the template. 1. `detailsTemplate`: A list of pass details below the barcode. 1. `listTemplate`: The pass details that users see in their wallet before they open their pass. ### The Card Title **You cannot override fields in the Card Title section of a boarding pass template**. This includes the fields shown below. In the case of the `departureAirport`, and `arrivalAirport`, we show both the `label` and `value` on the pass. Fields on the card template are all populated from the flight object — either in the `/flights` API or as a part of an object within an array of `payload.flights` in an adaptive link request. The table below lists the items on the template and the flight object values that populate the template field when you create a pass. *Required* items in the table below represent the required properties in the adaptive link payload, and are therefore required to be on a pass. While other fields may not be required, and you can hide them if empty, you may want to leave them blank and populate them as the `departureTime` approaches so your passengers know where to look on the pass to find new information. Moving a template on a field moves both the `label` and `value` keys, if both keys exist, for a flight or passenger. > **Note:** While the API allows for `label` values at the template field and flight object level, Google does not typically allow you to override field labels for boarding passes. In most cases, `label` overrides at the flight level apply to Apple Wallet passes only. The table below relates template field names to the keys that populate the template in the adaptive link `payload.flights[]` array of objects. ![The Card Title section of a boarding pass](https://www.airship.com/docs/images/boardingpass-cardtitle_hu_4eab106e9387240.webp) *The Card Title section of a boarding pass* | # | Template field | Adaptive Link key
`payload.flights[]` | Required | | --- | --- | --- | :---: | | 1 | `image` | | ✓ | | 2 | `airlineName` | `fields.airlineName.value` | ✓ | | 3 | `flightNumber`1 | `fields.flightNumber.value` | ✓ | | 4 | `departureAirport` | `fields.departureAirport.label`2 | ✓ | | 5 | ↳ | `fields.departureAirport.value` | ✓ | | 6 | `arrivalAirport` | `fields.arrivalAirport.label`2 | ✓ | | 7 | ↳ | `fields.arrivalAirport.value` | ✓ | {class="table-col-1-compact"} 1 This field also appears in the `detailsTemplate`. You can override this field to change its placement elsewhere on the pass, but you cannot remove or change its placement on the card title. 2 Typically set by the corresponding `value` property. You can override the Airport name using the `label` field, but you don't have to set this value manually when creating flights. ### The Card Template The Card Template consists of 2 rows. The first row supports three columns. The second row supports 2 columns. All `row`/`col` combinations support `subcol`, allowing for 2 template fields per rectangle in the image below. *Required* items in the table below represent the required properties in the adaptive link payload, and are therefore required to be on a pass. While other fields may not be required, and you can hide them if empty, you may want to leave them blank and populate them as the `departureTime` approaches so your passengers know where to look on the pass to find new information. Moving a template on a field moves both the `label` and `value` keys, if both keys exist, for a flight or passenger. > **Note:** While the API allows for `label` values at the template field and flight object level, Google does not typically allow you to override field labels for boarding passes. In most cases, `label` overrides at the flight level apply to Apple Wallet passes only. The table below relates template field names to the keys that populate the template in the adaptive link `payload.flights[]` array of objects. ![The Card Template section of a boarding pass](https://www.airship.com/docs/images/boardingPass-cardTemplate_hu_eb857978da8a3666.webp) *The Card Template section of a boarding pass* | # | Template field | Adaptive Link key
`payload.flights[]` | Default label | Required | | --- | --- | --- | :---: | :---: | | 1 | `departureTerminal` | `fields.departureTerminal.label` | TERMINAL | | | 2 | ↳ | `fields.departureTerminal.value` | | | | 3 | `departureGate` | `fields.departureGate.label` | GATE | | | 4 | ↳ | `fields.departureGate.value` | | | | 5 | `seatClassPolicy`1 | `fields.seatClass.label` | CABIN | | | 6 | `seatClass` | `passengers[].fields.seatClass` | | | | 7 | `boardingTime`2 | `fields.boardingTime.label` | | | | 8 | ↳ | `fields.boardingTime.value` | | | | 9 | `passengerName` | `passengers[].fields.passengerName.label` | PASSENGER | | | 10 | ↳ | `passengers[].fields.passengerName.value` | | ✓ | | 11 | `boardingGroup` | `passengers[].fields.boardingGroup.label` | GROUP | | | 12 | ↳ | `passengers[].fields.boardingGroup.value` | | | | 13 | `seatNumber` | `passengers[].fields.seatNumber.label` | SEAT | | | 14 | ↳ | `passengers[].fields.seatNumber` | | | {class="table-col-1-compact"} 1 The label changes based on the `seatClassPolicy` set on the flight. 2 This field also appears on the `detailsTemplate`. ### The Barcode Template The barcode template consists of four rows. You can set default values for a few items on the template, but the barcode value itself is populated from the `headers` in your template or adaptive link with a `confirmationCode` value set for each passenger. *Required* items in the table below represent the required properties in the adaptive link payload, and are therefore required to be on a pass. While other fields may not be required, and you can hide them if empty, you may want to leave them blank and populate them as the `departureTime` approaches so your passengers know where to look on the pass to find new information. Moving a template on a field moves both the `label` and `value` keys, if both keys exist, for a flight or passenger. > **Note:** While the API allows for `label` values at the template field and flight object level, Google does not typically allow you to override field labels for boarding passes. In most cases, `label` overrides at the flight level apply to Apple Wallet passes only. The table below relates template field names to the keys that populate the template in the adaptive link `payload.flights[]` array of objects. ![The Barcode section of a boarding pass](https://www.airship.com/docs/images/boardingPass-barcodeTemplate_hu_4ecab8947d957625.webp) *The Barcode section of a boarding pass* | # | Template field | Adaptive Link key
`payload.flights[]` | Required | | --- | --- | --- | :---: | | 1 | `headers.securityProgramLogo` | | | | 2 | `headers.boardingPrivilegeImage` | | | | 3 | `headers.barcode_value` | `passengers[].fields.confirmationCode` | ✓ | | 4 | | `headers.barcodeAltText` | | | 5 | `headers.airlineAllianceLogo` | `fields.airlineAllianceLogo` | | {class="table-col-1-compact"} ### The Details Template The `detailsTemplate` supports a number of single-column rows, each supporting `subcol` — two items separated by a `/`. Generally, website and image rows on the details template, are set at the template level, though you can set them within an adaptive link payload by providing a field object (with `label` and/or `value` keys) outside of the flights object. *Required* items in the table below represent the required properties in the flight or passenger objects when creating adaptive links, and are therefore required to be on a pass. While other fields may not be required, and you can hide them if empty, you may want to populate these fields as the `departureTime` approaches. Moving a template on a field moves both the `label` and `value` keys, if both keys exist, for a flight or passenger. > **Note:** While the API allows for `label` values at the template field and flight object level, Google does not typically allow you to override field labels for boarding passes. In most cases, `label` overrides at the flight level apply to Apple Wallet passes only. The table below relates template field names to the keys that populate the template in the adaptive link `payload.flights[]` array of objects. ![The Details Template section of a boarding pass](https://www.airship.com/docs/images/boardingPasses-detailsTemplate_hu_4419d9287677511.webp) *The Details Template section of a boarding pass* | # | Template field | Adaptive Link key
`payload.flights[]` | Default label | Required | | --- | --- | --- | :---: | :---: | | 1 | `boardingPosition` | | Position | | | 2 | ↳ | `passengers[].fields.boardingPosition.value` | | | | 3 | `sequenceNumber` | | Sequence | | | 4 | ↳ | `passengers[].fields.sequenceNumber.value` | | | | 5 | `boardingDoor` | | Boarding Door | | | 6 | ↳ | `passengers[].fields.boardingDoor.value` | | | | 7 | `flightNumber` | | Flight Number | | | 8 | ↳ | `fields.flightNumber.value` | | ✓ | | 9 | `confirmationCode` | | Confirmation Code | | | 10 | ↳ | `passengers[].fields.confirmationCode.value` | | ✓ | | 11 | `eticketNumber` | | Ticket Number | | | 12 | ↳ | `passengers[].fields.eticketNumber.value` | | ✓ | | 13 | `frequentFlyerNumber`
`frequentFlyerProgramName` | | Frequent Flyer Number1 | | | 14 | ↳ | `passengers[].fields.frequentFlyerProgramName.value`
`passengers[].fields.frequentFlyerNumber.value` | | | | 15 | `boardingTime` | `fields.boardingTime.label` | Boarding Time | | | 16 | ↳ | `fields.boardingTime.value` | | | | 17 | `gateClosingTime` | `fields.gateClosingTime.label` | Gate Closes | | | 18 | ↳ | `fields.gateClosingTime.value` | | | | 19 | `departureTime` | `fields.departureTime.label` | Scheduled | | | 20 | ↳ | `fields.departureTime.value` | | | | 21 | `actualDepartureTime` | `fields.actualDepartureTime.label` | Estimated Departure | | | 22 | ↳ | `fields.actualDepartureTime.value` | | | | 23 | `arrivalTime` | `fields.arrivalTime.label` | Scheduled | | | 24 | ↳ | `fields.arrivalTime.value` | | | | 25 | `actualArrivalTime` | `fields.actualArrivalTime.label` | Estimated Arrival | | | 26 | ↳ | `fields.actualArrivalTime.value` | | | | 27 | `arrivalTerminal` | `fields.arrivalTerminal.label` | Arrival Terminal | | | 28 | ↳ | `fields.arrivalTerminal.value` | | | | 29 | `arrivalGate` | `fields.arrivalGate.label` | Gate | | | 30 | ↳ | `fields.arrivalGate.value` | | | | 31 | `boardingPrivilegeImage` | | | | | 32 | `Random Information`1 | | | | | 33 | `Website`1 | | | | {class="table-col-1-compact"} 1 These fields are part of default templates created through the Airship user interface. You can set their values at the template level or set them at the adaptive link level, if you want the value(s) should change. ### Template Overrides You can override the order of items in a section of your template, or the information in a template section, by specifying an `overrides` object. This object contains the section(s) that you want a field to appear in and the order or placement of a field in that section using `row`, `col`, and `subcol` properties. Two fields can occupy the same `row` and `col`. Use the `subcol` to determine the order of fields in the same row and column positions. In the example below, we'll move the `boardingTime` and `departureGate` to the second row (index 1) and first column on the card template. Because these two fields will occupy the same space on the template, we'll also set the `subcol` to ensure that the boarding time appears first. > **Note:** If you override a field in a template section, you must set overrides for all fields in that section. Fields without an override in a section that uses overrides will not appear in a section or on your passes. **Set overrides for boarding pass fields** ```json { "boardingTime": { "fieldType": "flightModule", "value": "", "formatType": "String", "label": "", "hideEmpty": false, "required": false, "overrides": { "cardTemplate": { "row": 1, "col": 0, "subCol": 0, "dateStyle": "timeOnly" } } }, "departureGate": { "fieldType": "flightModule", "value": "", "formatType": "String", "label": "", "hideEmpty": false, "required": false, "overrides": { "cardTemplate": { "row": 1, "col": 0, "subCol": 1 } } } } ``` | | | | --- | --- | | ![Boarding pass with default fields](https://www.airship.com/docs/images/boardingPassWithoutOverride_hu_72001ab3a982d93f.webp) *Boarding pass with default fields* | ![Boarding pass with overrides applied](https://www.airship.com/docs/images/boardingPassWithOverride_hu_fabdfb08484b67a5.webp) *Boarding pass with overrides applied* | {class="table-bare"} ## Override a Template The card template consists of up to two rows, with up to three items per row (left, center, and right). You can add or move fields around the `cardTemplate` to better organize your passes. > **Note:** We recommend testing overrides with a duplicate template before modifying a template that is associated with live passes. The steps here include duplication, creating an [Adaptive Link](https://www.airship.com/docs/reference/glossary/#adaptive_link), and viewing the passes on local devices to verify that your overrides perform the way you expect. > > You must have at least one Apple Wallet and one Google Wallet template to create an adaptive link. 1. Duplicate an Apple Wallet or Google Wallet template you want to override, and use its `templateId` in the following steps. 1. Use the [/templates](https://www.airship.com/docs/developer/rest-api/wallet/operations/templates/#gettemplate) API to get your template payload. This call, as opposed to the `/v1/template` endpoints, returns a template payload in exactly the same format as you would use in a `POST` or `PUT` operation. **Get template payload** ```http GET /templates/160571 HTTP/1.1 Authorization: Basic Content-Type: application/json ``` 1. Update your template with `overrides` using a `PATCH` against the [/templates/{templateId}](https://www.airship.com/docs/developer/rest-api/wallet/operations/templates/#patchtemplates) endpoint. In the payload, you only need to provide the fields in your template that you want to override. > **Note:** If your template contains fields that aren't a part of the default template design, like `fareType` or `departureGate`, they must contain `label` and `value` keys. You can set empty strings in your template and replace these values when you generate passes, but failing to set `label` or `value` keys will prevent those fields from rendering properly on your pass. **Update template with overrides** ```http PATCH /templates/ HTTP/1.1 Authorization: Basic Content-Type: application/json { "fields": { "passengerInfo": { "fieldType": "infoModuleData", "value": "First/Last", "formatType": "String", "label": "PASSENGER", "order": 5, "overrides": { "cardTemplate": { "row": 0, "col": 0 } } }, "boardingPosition": { "fieldType": "flightModule", "value": "___", "formatType": "String", "label": "POSITION", "hideEmpty": false, "required": false, "overrides": { "cardTemplate": { "row": 0, "col": 1 } } }, "departureGate": { "fieldType": "flightModule", "value": "__", "formatType": "String", "label": "", "hideEmpty": false, "required": false, "overrides": { "cardTemplate": { "row": 0, "col": 2 } } }, "fareType": { "fieldType": "infoModuleData", "value": "__", "formatType": "String", "label": "FARE", "hideEmpty": false, "required": false, "order": 2, "overrides": { "cardTemplate": { "row": 1, "col": 0 } } }, "boardsOrEmptyInfo": { "fieldType": "infoModuleData", "value": "", "formatType": "String", "label": "BOARDS", "hideEmpty": false, "required": false, "order": 6, "overrides": { "cardTemplate": { "row": 1, "col": 1 } } }, "boardsOrSecurityInfo": { "fieldType": "infoModuleData", "value": "__", "formatType": "String", "label": "__", "hideEmpty": false, "required": false, "order": 7, "overrides": { "cardTemplate": { "row": 1, "col": 2 } } } } } ``` 1. Repeat steps 2 and 3 for the other platform so that you have will have updated templates for both Apple Wallet and Google Wallet. 1. Create an adaptive link for the updated template IDs, [using the API](https://www.airship.com/docs/guides/wallet/user-guide/create-links/api/) or [dashboard](https://www.airship.com/docs/guides/wallet/user-guide/create-links/dashboard/). Your adaptive link must include passenger information: * For `passengers`, both `passengerName` and `confirmationCode` are required fields. * For `flights`, `departureTime`, `departureAirport`, `arrivalAirport`, `flightNumber`, and `airlineCode` are required fields. 1. Paste the adaptive link in local Android and iOS devices, save the passes, and confirm they appear as you expected. 1. If the passes appear as expected, repeat steps 1-2 for your original templates. 1. (Optional) Confirm the appearance of the passes based on your original templates, and delete the duplicate templates you used for testing. ## Reverting Boarding Pass Template Overrides {#revert} If you want to revert a template section to the default layout, update your template with an empty `overrides` object. **Empty overrides object using default layout** ```json { "departureGate": { "fieldType": "flightModule", "value": "", "formatType": "String", "label": "", "hideEmpty": false, "required": false, "overrides": {} } } ``` ## Override properties The `overrides` object contains properties that represent an individual override for the field. Properties with Integer values are 0-indexed. `overrides`: an object with child properties for each section where a field will appears on a pass. Supported child objects: `cardTemplate`, `barcodeSection`, `detailsTemplate`, `listTemplate`. Set an empty object to reset a field to the default layout. `row`: Integer; the row the field should appear in. The number of available rows depends on the template `type`. `col`: Integer; the column the field should appear in. There are three columns in the card template, 0 is the left column, 1 is the center, and 2 is the right column. `subcol`: Integer, 0 or 1; when multiple fields use the same `row` and `col`, this determines whether a field appears on the left or the right in the column. `dateStyle`: String; for fields that take ISO date-times, use `dateStyle` to override the default format for dates and times. Different fields have different default date styles. Accepted values: * `date-time`: Show both date and time * `dateOnly`: Display only the date * `timeOnly`: Display only the time * `dateTimeYear`: Display the date, time, and year * `dateYear`: Display the date and year **Example field override** ```json { "boardingTime": { "fieldType": "flightModule", "value": "", "formatType": "String", "label": "", "hideEmpty": false, "required": false, "overrides": { "cardTemplate": { "col": 0, "row": 1, "subcol": 0, "dateStyle": "timeOnly" } } } } ``` ### Date and Time Styles Several fields in the flight object take date-time string values. By default board pass templates shape date-time values to fit their placement on the pass. For example, `boardingTime` only shows the time when the user boards a plane, rather than the full date and time. However, you can override the default date-time format for any field using the `dateStyle` key in an override object setting the following styles: * `date-time`: Show both date and time * `dateOnly`: Display only the date * `timeOnly`: Display only the time * `dateTimeYear`: Display the date, time, and year * `dateYear`: Display the date and year > **Important:** If you override the `dateStyle` for a field, you must also set overrides for all of the fields within a template section. You can use `dateStyle` with the following boarding pass fields. | Field | Default style | |---|---| |`boardingTime`|`timeOnly`| |`arrivalTime`|`date-time`| |`actualArrivalTime`|`timeOnly`| |`departureTime`|`date-time`| |`actualDepartureTime`|`timeOnly`| # Send a Test Pass > After saving your pass template, send yourself a test pass and verify its content and appearance. ## Send an Apple Wallet Test Pass {#test-apple} You will send the pass to your email address, then install the pass on an iOS device. 1. Go to *Templates*. 1. Click anywhere in a template's row to see its expanded view, then click **Edit Design**. If you have only one template in the project, the initial view is already expanded. 1. Click **Test Pass** in the project header. 1. Enter your email address and click **Send**. 1. Open your mail app on your iOS device, and open the "New Pass Generated..." email. 1. Tap the wallet attachment to view the pass, then tap *Add* to install it to your iOS Wallet. 1. Open the Wallet app on your device and open your test pass. ## Send a Google Wallet Test Pass {#test-google} You will save the pass to Google Wallet on the web, then view the pass on your Android device. Make sure you are first logged in to your Google account before attempting to save the pass. 1. Go to *Templates*. 1. Click anywhere in a template's row to see its expanded view and click **Edit Design**. If you have only one template in the project, the initial view is already expanded. 1. Click **Test Pass** in the project header,then click the *Save the pass to your Google Wallet App* link in the confirmation box that appears. ![Saving a test pass to Google Wallet](https://www.airship.com/docs/images/reach-test-android_hu_98bb11b470e2bbbc.webp) *Saving a test pass to Google Wallet* The pass will open in Google Wallet in a new browser tab. If not yet logged in, Google will prompt you to do so. 1. Click **Save** to save the pass to your Google Wallet app. ![Confirming the test pass in Google Wallet](https://www.airship.com/docs/images/reach-test-android-save-1_hu_e043deff8c5e1c3c.webp) *Confirming the test pass in Google Wallet* ![Test pass saved to Google Wallet](https://www.airship.com/docs/images/reach-test-android-save-2_hu_7c6dc4617f38be98.webp) *Test pass saved to Google Wallet* 1. Open the Google Wallet app on your device. 1. Open your saved test pass. # Manage Wallet templates > Manage your Wallet templates. ## Edit a Wallet template name or description Change the name or description of a template: 1. Go to **Templates** and select the template you want to edit. 1. Select **Update** for Name or Description. 1. Make your changes and click **Save**. ## Set a Wallet template custom ID Provide a custom ID that overrides the template's auto-generated default ID: 1. Go to **Templates** and select the template you want to edit. 1. Select **Update** for Custom ID. 1. Check the box for **Use a Custom ID** and enter your ID. 1. Select **Save**. ## Set the sharing policy for a Wallet pass

By default, templates allow pass sharing across users and devices. You can change the sharing policy for templates from the Templates menu for a mobile wallet project.

Apple Wallet and Google Wallet support slightly different sharing settings.

Sharing policy Apple Google
Multiple users and devices (Default)
One user on multiple devices
One user on one device 1

1. Intended for use in limited circumstances. Contact Airship Support for additional information.

1. Go to **Templates** and select the template you want to edit. 1. Select **Update** for Sharing Policy. 1. Choose a sharing policy. 1. Select **Save**. ## Duplicate a Wallet template Copy a template to the same project or to another project of the same pass type. When duplicating a template with an [External ID](https://www.airship.com/docs/guides/wallet/user-guide/basics/#external-or-custom-ids) set, the external ID is not copied to the new template. 1. Go to **Dashboard** and select the duplicate icon ( ) for a template. 1. Select where to save the new template. If duplicating to another project, also select the project name. 1. Select **Continue** and enter a name for the new template. 1. Select **Duplicate**. 1. Follow the link to open the duplicate in the template editor or select **Finish**. ## Delete a Wallet template Remove a template from a project. > **Important:** Before you can delete a template, you must expire or delete all passes associated with the template. See: > > * [Wallet API: Update Pass](https://www.airship.com/docs/developer/rest-api/wallet/operations/passes/#updatepass) > * [Wallet API: Delete Pass](https://www.airship.com/docs/developer/rest-api/wallet/operations/passes/#deletepass) 1. Go to **Templates** and select the template you want to edit. 1. Select **Delete**. # Enable NFC Support for your Passes > Enable NFC support so that users can redeem passes by tapping their device to your card readers and other terminals. [Near-field communication (NFC)](https://en.wikipedia.org/wiki/Near-field_communication) enables pass holders to tap their device on a compatible reader or terminal to redeem passes, consume point balances, use coupons, scan boarding passes, and more. You can add NFC settings at the project level to support both your Apple and Google passes. While Airship combines most of your NFC-enablement settings into a single object at the project level, you must make sure that your Google/Apple accounts are set up to use NFC, and make sure that your terminals are set up with appropriate private keys to decode NFC communications from your Airship-generated passes. Airship supports NFC communications for: * **Apple**: All pass types * **Google**: All pass types ## Apple Wallet NFC requirements You enable NFC support by requesting an NFC-enabled certificate from Apple. Providing your NFC-enabled certificate to Airship automatically enables NFC support for your iOS passes. You set your private key on your terminal and provide your public key to Airship. You can provide your public key with NFC messages, and your terminal will decode the message using the private key. Because iOS supports NFC at the certificate level, and iOS provides your public/private keys, you can only have one active NFC merchant configuration for your project. Airship will let you add multiple NFC merchants for Apple but will only use the most recently added NFC merchant configuration. However, you can provide the public key your terminal uses at the pass/message level to override your project's global public NFC encryption key. You may want to do this if you support multiple vendors from a single Loyalty pass. **Example object to override project's global public key at pass level** ```json { "fields" : {}, "nfc": { "message": "", "encryptionPublicKey":"" } } ``` ## Google Wallet NFC requirements To enable NFC support for Google passes, you must send a `POST` to `/v1/project/{projectId}/nfcMerchants` or `/v1/projects/id/{projectExternalId}/nfcMerchants` with your merchant information. When you set up your account with Google, Google assigns you an Issuer ID and a Collector ID. As long as you have a valid Google Pay certificate, Airship will return the correct issuer and collector identifiers. You can also use your own public/private encryption key pair or have Airship generate a key pair for you. If you already have a key pair, and your private key is already set up at your terminals, provide your public key when you set up NFC information. If you have not set up a key pair yet, do not provide a `publicKeyPem` in your `/nfcMerchants` payload, and Airship will generate both keys for you. > **Note:** Airship only returns the private key with your `POST` payload. You cannot retrieve the private key or modify your key pair later, so be sure to copy it immediately. **Enable NFC support for Google passes** ```http POST /v1/project/13137/23c0da58-3b79-4d44-9191-b69faef7b24c HTTP/1.1 Authorization: Basic Content-Type: application/json { "vendor": "GOOGLE", "merchantName": "testMerchant5", "merchantEmail": "test@example.com", "terminalProvider": "Verifone", "keyVersion": 1, "publicKeyPem": "" } ``` Unlike iOS, you can have multiple NFC merchant configurations per project. You may want to do this if your pass supports terminals in different businesses — like a loyalty program that supports multiple stores under the same parent organization. If merchant terminal is already configured and there is a pre-existing `smartTapIssuerId` (also known as a redemption issuerId), it can be shared across clients, which can use the existing `smartTapIssuerId` to configure other projects using the following API call: **Share a pre-existing `smartTapIssuerId` across clients** ```http POST /v1/project/{secondProjectId}/nfcMerchants HTTP/1.1 Authorization: Basic Content-Type: application/json { "vendor": "GOOGLE", "smartTapIssuerId": "1234567890" } ``` ## Adding NFC support to your project These examples use standard project IDs. If your project has an external ID, use the corresponding `/v1/project/id/{projectExternalId}/` endpoints. For Apple, before you begin, make sure that you have requested certificate(s) supporting NFC and uploaded those certificates to Airship. 1. Make a call to the `/v1/project/{projectId}/nfcMerchants` API to add NFC information to your project. 1. Go to your Wallet dashboard and click **Templates**. 1. Select your template, click **Edit Design**, and then click **Save**. Despite making no changes, your template will now support NFC. 1. Update passes with NFC messages. The `nfc.message` contains values that your terminals and backend systems will use to identify and take actions against the pass, like a loyalty or coupon number. **Update pass with NFC message** ```http PUT /v1/pass/123 HTTP/1.1 Content-Type: application/json Authorization: Basic Api-Revision: 1.2 { "fields" : {}, "nfc": { "message": "" } } ``` ### Terminals and Encryption keys NFC uses SSL to authenticate transactions. You provide Airship your public key, and your terminals must have the private key. You can provide your public key to Airship when you create an NFC merchant using `publicKeyPem`. If you exclude `publicKeyPem` from the payload, Airship will generate public and private SSL keys for you. If you let Airship generate keys for you, you must copy your private key from the response; Airship will not return your private key in any other payload. For Google, you can add an NFC merchant for each key pair that you have. So, if you have a single pass that works at different merchants belonging to the same company, your project can contain all the different keys that you use across different NFC terminals. For Apple, your project can contain a single NFC merchant. You should expect to use the same key pair across your terminals. Or, when you add an NFC message to a pass, you can override your `publicKeyPem` with an `encryptionPublicKey` whenever you set an NFC message on your pass. **Override `publicKeyPem` with an `encryptionPublicKey` by adding an NFC message to a pass** ```http PUT /v1/pass/123 HTTP/1.1 Content-Type: application/json Authorization: Basic Api-Revision: 1.2 { "fields": {}, "nfc": { "message": "125855|8BD29F182DE29848E5A02FAE749DA545", "encryptionPublicKey": "MDkwEwYHKoZIzj0CAQYIKoZIzj0DAQcDIgAD0TDG7WzxFXJc9FZ0rE8qG5n6Z5voU5axJYDV5nViYEM=" } } ``` ### The NFC message After you set up NFC merchants in Airship and your terminals, you can assign a `message` to your passes. The `message` conveys information that your terminal and/or backend systems use to identify and take advantage of the pass. While the `message` takes a string, this can be any kind of delimited string or JSON string and may contain multiple values that are relevant to you. For example, if you have a loyalty program, you may want the `message` to contain a value with the pass ID, loyalty points, and/or the loyalty ID for the pass. When a user taps their device to the appropriate terminal, the terminal gets this message and decodes it to perform actions with or against the pass. You can apply NFC messages to passes using the `/pass` APIs. **Set a comma-delimited NFC message on a pass** ```http PUT /v1/pass/123 HTTP/1.1 Content-Type: application/json Authorization: Basic Api-Revision: 1.2 { "fields": {}, "nfc": { "message": ",,", } } ```