# SmartPass API Integration

##### CHANGELOG

<table id="bkmrk-version-date-changes"><thead><tr><th>Version</th><th>Date</th><th>Changes</th></tr></thead><tbody><tr><td>v1.0</td><td>2026-10-09</td><td>Initial release.</td></tr></tbody></table>

##### SMARTPASS API INTEGRATION

SmartPass lets you issue digital passes, such as event tickets, membership cards, business cards or vouchers, that your users save to Apple Wallet and Google Wallet. Sparados generates and signs the passes for both platforms, hosts the wallet web services, keeps saved passes up to date on users' devices, and handles expiry and voiding. You only decide who gets a pass and what is printed on it.

The work is split between the Sparados Corporate Panel and the Sparados API:

- **Pass templates are created in the Corporate Panel** (SmartPass &gt; Campaigns). A template defines the look of the pass, its texts and languages, the barcode format and which fields are filled per pass. Templates cannot be created or edited through the API; the API gives read access to them.
- **Passes can be issued in three ways:** in the Corporate Panel one by one (Issue pass), in the Corporate Panel in bulk from a CSV file (Bulk issue), or through the Sparados API, either one at a time or as a batch. This article describes the API.

SmartPass API allows partners to:

- list pass templates and read their field definitions
- issue a single pass or many passes in one batch
- deliver passes by Sparados email or through your own channel using add-to-wallet links and QR codes
- check whether a pass has been saved to Apple Wallet or Google Wallet
- update a pass that is already in the user's wallet
- void a pass or let it expire automatically

Only issued passes count toward your SmartPass pass limit. Updating a pass, sending wallet notifications and creating templates do not use the limit, and access to SmartPass API has no extra fee. SmartPass can be used on its own or together with Sparados virtual cards, for example to show a card budget on a pass next to the payment card in the same wallet. More about the product: [sparados.com/smartpass](https://www.sparados.com/smartpass).

Before using SmartPass API, the partner must complete onboarding with Sparados, sign the cooperation agreement, configure Mutual TLS authentication for the selected environment, and create at least one pass template in the Corporate Panel.

**API Endpoints**

<table id="bkmrk-api-beta-prod-smartp"><thead><tr><th>API</th><th>BETA</th><th>PROD</th></tr></thead><tbody><tr><td>SmartPass API, Passes ([swagger](https://sp-api.verestro.dev/docs?urls.primaryName=External#/Passes))</td><td>https://sp-api.secure-verestro.dev</td><td>https://sp-api.secure-verestro.com</td></tr></tbody></table>

##### 1. SERVER-TO-SERVER SECURITY

All SmartPass API requests require Mutual TLS (mTLS), the same as the other Sparados server-to-server APIs. Instructions for generating the CSR and configuring the client certificate are available in [Connecting to server-to-server APIs](https://developer.sparados.com/books/sparados-api-documentation/page/connecting-to-server-to-server-apis).

##### 2. HOW SMARTPASS WORKS

**How it works**

1. An administrator creates a pass template in the Corporate Panel: layout, colors, logo and icon, texts in the supported languages, barcode format, and the fields shown on the pass. Each field is either the same for everyone, or filled per pass under a value key such as `holderName`.
2. Your backend reads the template with `GET /secure/passes/templates/{id}` to learn which value keys each pass must provide.
3. Your backend issues passes with `POST /secure/passes/` (one pass) or `POST /secure/passes/batches/` (many passes).
4. The pass reaches the holder either by an email sent by Sparados (`sendEmail: true`), or through your own channel using the add-to-wallet links and QR codes returned by the API.
5. The holder adds the pass to Apple Wallet or Google Wallet. Sparados records this as adoption, which you can read from the API.
6. Later you can update the pass with `PATCH /secure/passes/{id}`, and the change is pushed to the holder's device, or void it with `POST /secure/passes/{id}/void`. A pass with `expiresAt` is voided automatically when that time passes.

**Sequence diagram**

![SmartPass API sequence diagram](https://developer.sparados.com/uploads/images/gallery/2026-10/embedded-image-yg4eoz5p.png)

##### 3. KEY CONCEPTS

<table id="bkmrk-concept-corporate-pa"><thead><tr><th>Concept</th><th>Corporate Panel</th><th>Description</th></tr></thead><tbody><tr><td>Template</td><td>Campaign</td><td>Design and structure of a pass. Created and edited only in the Corporate Panel. Identified by `templateId`.</td></tr><tr><td>Pass</td><td>Pass</td><td>One pass issued to one holder, identified by `id`. The pass `id` is also the pass serial number used by Apple Wallet and Google Wallet.</td></tr><tr><td>Batch</td><td>Batch</td><td>A bulk issuing job created from a list of rows (API) or a CSV file (Corporate Panel). Processed in the background.</td></tr><tr><td>Field values</td><td>Filled per pass</td><td>Per-pass values sent in `fieldValues`, keyed by the value keys defined in the template.</td></tr><tr><td>Adoption</td><td>Wallets (Apple / Google icons)</td><td>Whether the holder has saved the pass to Apple Wallet or Google Wallet.</td></tr><tr><td>Void</td><td>Void</td><td>Final deactivation of a pass. The pass stays on the list and is shown as voided in the wallet.</td></tr></tbody></table>

**Field groups**

Fields of a template are placed in zones. The zone decides where the field is displayed on the pass:

<table id="bkmrk-zone-%28api%29-corporate"><thead><tr><th>Zone (API)</th><th>Corporate Panel</th><th>Where it is displayed</th></tr></thead><tbody><tr><td>`header`</td><td>Header</td><td>Small text in the top right corner, next to the logo.</td></tr><tr><td>`primary`</td><td>Primary</td><td>Large text, typically the holder's name.</td></tr><tr><td>`secondary`</td><td>Secondary</td><td>Row below the primary fields.</td></tr><tr><td>`auxiliary`</td><td>Auxiliary</td><td>Extra row below the secondary fields.</td></tr><tr><td>`back`</td><td>Back / details</td><td>Back of the pass in Apple Wallet, details view in Google Wallet.</td></tr></tbody></table>

**Field source**

Each field has a `source` that decides where its value comes from:

<table id="bkmrk-source.type-corporat"><thead><tr><th>source.type</th><th>Corporate Panel</th><th>Description</th></tr></thead><tbody><tr><td>`static`</td><td>Same for everyone</td><td>The text is set in the template (`source.value`, per language) and shared by all passes.</td></tr><tr><td>`field_values`</td><td>Filled per pass</td><td>Each pass supplies its own value in `fieldValues` under `source.key`. In the Corporate Panel CSV this key is also the column name.</td></tr></tbody></table>

Example field definitions returned in `fieldGroups`:

```json
{
  "primary": [
    {
      "key": "holder",
      "label": { "en": "Holder" },
      "source": { "type": "field_values", "key": "holderName" },
      "notifyOnChange": false
    }
  ],
  "secondary": [
    {
      "key": "event",
      "label": { "en": "Event" },
      "source": { "type": "static", "value": { "en": "Sparados Developer Day" } },
      "notifyOnChange": false
    }
  ]
}
```

When `notifyOnChange` is `true`, the holder receives a wallet notification whenever the value of this field changes. `changeMessage` can define the notification text per language.

##### 4. VALUES USED IN SMARTPASS API

Detailed Swagger documentation is available at the end of this document.

**Date format**

All dates use ISO 8601 date-time format in UTC:

```
2026-12-31T23:59:00Z
```

The Corporate Panel displays dates in the local time zone of the administrator, so `2026-12-31T23:59:00Z` is shown as `2027-01-01 00:59` in Poland in winter.

**Identifiers**

Templates, passes and batches are identified by UUIDs.

**Languages**

Texts such as `organizationName`, `passTitle`, field labels and static values are returned as objects keyed by language code, for example `{ "en": "Holder", "pl": "Posiadacz" }`. Each template has a `defaultLanguage`, used when a translation is missing, and a list of `supportedLanguages`. The `language` parameter used when issuing passes selects the language of the email sent to the holder.

<p class="callout warning">TO CONFIRM: exact language code format (for example `en` or `EN`) before publishing.</p>

**Barcode formats**

The barcode format is set in the template: `QR`, `PDF417`, `AZTEC` or `CODE128`. The content of the barcode is set per pass in `barcodeMessage`, and an optional text displayed under the barcode in `barcodeAltText`. A pass without `barcodeMessage` has no barcode.

**Layouts**

The API returns the template layout as one of: `boardingPass`, `storeCard`, `eventTicket`, `coupon`, `generic`. The Corporate Panel currently creates templates with the `eventTicket` layout.

**Pagination and sorting**

List endpoints use cursor-based pagination. Pass the `nextCursor` value from the previous response as `cursor` to fetch the next page. When `nextCursor` is `null`, there are no more results.

<table id="bkmrk-parameter-type-descr"><thead><tr><th>Parameter</th><th>Type</th><th>Description</th></tr></thead><tbody><tr><td>cursor</td><td>string</td><td>Opaque cursor from a previous response's `nextCursor`.</td></tr><tr><td>limit</td><td>integer</td><td>Max results per page. Default 20, up to 100. For batch rows: default 100, up to 1000.</td></tr><tr><td>orderBy</td><td>string</td><td>Sorting field. Default `createdAt`. Available values depend on the endpoint.</td></tr><tr><td>orderDirection</td><td>string</td><td>`asc` or `desc`. Default `desc`.</td></tr></tbody></table>

**Errors**

When a template, pass or batch does not exist, the API returns `404 Not Found`:

```json
{
  "reason": "RESOURCE_NOT_FOUND",
  "detail": "Pass not found"
}
```

##### 5. PASS TEMPLATES

Templates are created in the Corporate Panel. Through the API you can list them and read their structure.

**Template API Methods**

<table id="bkmrk-method-endpoint-desc"><thead><tr><th>Method</th><th>Endpoint</th><th>Description</th></tr></thead><tbody><tr><td>GET</td><td>/secure/passes/templates/</td><td>Retrieves the list of pass templates.</td></tr><tr><td>GET</td><td>/secure/passes/templates/{id}</td><td>Retrieves details of a specific template, including `fieldGroups`.</td></tr></tbody></table>

**LIST TEMPLATES**

```
GET /secure/passes/templates/
```

Query parameters

<table id="bkmrk-field-type-descripti"><thead><tr><th>Field</th><th>Type</th><th>Description</th></tr></thead><tbody><tr><td>name</td><td>string</td><td>Filter by template name.</td></tr><tr><td>layout</td><td>string</td><td>Filter by layout: `boardingPass`, `storeCard`, `eventTicket`, `coupon`, `generic`.</td></tr><tr><td>createdAtFrom / createdAtTo</td><td>string (date-time)</td><td>Filter by creation date.</td></tr><tr><td>updatedAtFrom / updatedAtTo</td><td>string (date-time)</td><td>Filter by last update date.</td></tr><tr><td>orderBy</td><td>string</td><td>`createdAt`, `updatedAt`, `name`, `id`. Default `createdAt`.</td></tr><tr><td>orderDirection, cursor, limit</td><td> </td><td>See Pagination and sorting.</td></tr></tbody></table>

**GET TEMPLATE DETAILS**

```
GET /secure/passes/templates/{id}
```

Returns the template with its `fieldGroups`. Every key referenced by a field with source type `field_values` must be sent in the `fieldValues` of each pass issued from this template.

Example response:

```json
{
  "id": "6f1c2a9e-4b7d-4c1e-9a3f-2d5e8b7c1a40",
  "corporationId": "1b2c3d4e-5f60-4718-8293-a4b5c6d7e8f9",
  "name": "Developer Day 2026",
  "layout": "eventTicket",
  "organizationName": { "en": "Sparados" },
  "passTitle": { "en": "Developer Zone Pass" },
  "backgroundColor": "#0B1D33",
  "foregroundColor": "#FFFFFF",
  "labelColor": "#8FB4FF",
  "barcodeFormat": "QR",
  "emailTemplate": null,
  "defaultLanguage": "en",
  "supportedLanguages": ["en"],
  "fieldGroups": {
    "header": [],
    "primary": [
      {
        "key": "holder",
        "label": { "en": "Holder" },
        "source": { "type": "field_values", "key": "holderName" },
        "notifyOnChange": false
      }
    ],
    "secondary": [
      {
        "key": "event",
        "label": { "en": "Event" },
        "source": { "type": "static", "value": { "en": "Sparados Developer Day" } },
        "notifyOnChange": false
      }
    ],
    "auxiliary": [],
    "back": []
  },
  "logoUrl": "https://<assets-host>/logo.png",
  "iconUrl": "https://<assets-host>/icon.png",
  "stripImageUrl": null,
  "createdAt": "2026-10-09T14:29:00Z",
  "updatedAt": "2026-10-09T14:29:00Z",
  "activePassCount": 2,
  "adoptedPassCount": 0,
  "totalPassCount": 3
}
```

Response fields

<table id="bkmrk-field-type-descripti-1"><thead><tr><th>Field</th><th>Type</th><th>Description</th></tr></thead><tbody><tr><td>id</td><td>string (uuid)</td><td>Template ID. Use it as `templateId` when issuing passes.</td></tr><tr><td>name</td><td>string</td><td>Internal template name (Campaign name in the Corporate Panel). Never shown to pass holders.</td></tr><tr><td>layout</td><td>string</td><td>Pass layout.</td></tr><tr><td>organizationName</td><td>object</td><td>Issuer name per language. Apple: shown in notifications. Google: small title at the top of the pass.</td></tr><tr><td>passTitle</td><td>object, nullable</td><td>Card heading per language. Google Wallet only.</td></tr><tr><td>backgroundColor</td><td>string, nullable</td><td>Background color, Apple and Google.</td></tr><tr><td>foregroundColor / labelColor</td><td>string, nullable</td><td>Text and label colors, Apple Wallet only.</td></tr><tr><td>barcodeFormat</td><td>string, nullable</td><td>`QR`, `PDF417`, `AZTEC` or `CODE128`.</td></tr><tr><td>emailTemplate</td><td>string, nullable</td><td>Custom email template for the issued-pass email. `null` uses the default email.</td></tr><tr><td>defaultLanguage / supportedLanguages</td><td>string / array</td><td>Default language and all languages the texts are available in.</td></tr><tr><td>fieldGroups</td><td>object</td><td>Field definitions per zone: `header`, `primary`, `secondary`, `auxiliary`, `back`. See Key concepts.</td></tr><tr><td>logoUrl / iconUrl / stripImageUrl</td><td>string, nullable</td><td>Public URLs of the template images.</td></tr><tr><td>activePassCount</td><td>integer</td><td>Number of active passes issued from this template.</td></tr><tr><td>adoptedPassCount</td><td>integer</td><td>Number of active passes saved to Apple Wallet or Google Wallet.</td></tr><tr><td>totalPassCount</td><td>integer</td><td>Number of all passes issued from this template, including voided.</td></tr></tbody></table>

##### 6. ISSUE A PASS

To issue a single pass, use:

```
POST /secure/passes/
```

To issue many passes from one template, use `POST /secure/passes/batches/` instead of calling this endpoint once per pass. See section 11.

Request body example:

```json
{
  "templateId": "6f1c2a9e-4b7d-4c1e-9a3f-2d5e8b7c1a40",
  "userEmail": "john.smith@example.com",
  "fieldValues": {
    "holderName": "John Smith"
  },
  "barcodeMessage": "TICKET-000123",
  "barcodeAltText": "TICKET-000123",
  "expiresAt": "2026-12-31T23:59:00Z",
  "language": "en",
  "sendEmail": true
}
```

Request body fields:

<table id="bkmrk-field-type-descripti-2"><thead><tr><th>Field</th><th>Type</th><th>Description</th></tr></thead><tbody><tr><td>templateId\*</td><td>string, uuid</td><td>ID of the template the pass is issued from.</td></tr><tr><td>userEmail\*</td><td>string, email</td><td>Email address of the pass holder. Used for the issued-pass email and for searching passes.</td></tr><tr><td>fieldValues</td><td>object</td><td>Per-pass values keyed by the value keys of the template. Must contain every key referenced by a `field_values` field. Default `{}`.</td></tr><tr><td>barcodeMessage</td><td>string, nullable</td><td>Data encoded in the barcode. Without it the pass has no barcode.</td></tr><tr><td>barcodeAltText</td><td>string, nullable</td><td>Text displayed under the barcode.</td></tr><tr><td>expiresAt</td><td>string (date-time), nullable</td><td>Expiry time of the pass. When it passes, the pass is voided automatically. Omit for a pass that does not expire.</td></tr><tr><td>language</td><td>string</td><td>Language of the issued-pass email.</td></tr><tr><td>sendEmail</td><td>boolean</td><td>When `true`, Sparados emails the holder the `.pkpass` file and add-to-wallet links for both platforms. Default `false`.</td></tr></tbody></table>

Additional properties are not accepted by the API.

Example response (`201 Created`):

```json
{
  "id": "9c4e7b1a-2f3d-4a5b-8c6d-7e8f9a0b1c2d",
  "corporationId": "1b2c3d4e-5f60-4718-8293-a4b5c6d7e8f9",
  "templateId": "6f1c2a9e-4b7d-4c1e-9a3f-2d5e8b7c1a40",
  "templateName": "Developer Day 2026",
  "userEmail": "john.smith@example.com",
  "fieldValues": { "holderName": "John Smith" },
  "barcodeMessage": "TICKET-000123",
  "barcodeAltText": "TICKET-000123",
  "expiresAt": "2026-12-31T23:59:00Z",
  "googleObjectId": "<issuerId>.9c4e7b1a-2f3d-4a5b-8c6d-7e8f9a0b1c2d",
  "status": "active",
  "voidedAt": null,
  "adoption": {
    "apple": { "devices": [] },
    "google": { "savedAt": null, "deletedAt": null }
  },
  "createdAt": "2026-10-09T14:31:00Z",
  "updatedAt": "2026-10-09T14:31:00Z",
  "links": {
    "apple": {
      "saveUrl": "https://<pass-host>/passes/9c4e7b1a-2f3d-4a5b-8c6d-7e8f9a0b1c2d.pkpass",
      "qrUrl": "https://<pass-host>/passes/9c4e7b1a-2f3d-4a5b-8c6d-7e8f9a0b1c2d/qr/apple"
    },
    "google": {
      "saveUrl": "https://pay.google.com/gp/v/save/<signed-token>",
      "qrUrl": "https://<pass-host>/passes/9c4e7b1a-2f3d-4a5b-8c6d-7e8f9a0b1c2d/qr/google"
    }
  }
}
```

<p class="callout warning">TO CONFIRM: `<pass-host>` and the exact link formats for BETA and PROD before publishing.</p>

Response fields

<table id="bkmrk-field-type-descripti-3"><thead><tr><th>Field</th><th>Type</th><th>Description</th></tr></thead><tbody><tr><td>id</td><td>string (uuid)</td><td>Pass ID, also the pass serial number. Store it to update or void the pass later.</td></tr><tr><td>templateId / templateName</td><td>string</td><td>Template the pass was issued from.</td></tr><tr><td>userEmail</td><td>string</td><td>Pass holder's email.</td></tr><tr><td>fieldValues</td><td>object</td><td>Per-pass field values.</td></tr><tr><td>barcodeMessage / barcodeAltText</td><td>string, nullable</td><td>Barcode content and text under the barcode.</td></tr><tr><td>expiresAt</td><td>string (date-time), nullable</td><td>Expiry time, or `null` if the pass does not expire.</td></tr><tr><td>googleObjectId</td><td>string, nullable</td><td>ID of the pass object in Google Wallet.</td></tr><tr><td>status</td><td>string</td><td>`active` or `voided`.</td></tr><tr><td>voidedAt</td><td>string (date-time), nullable</td><td>When the pass was voided.</td></tr><tr><td>adoption</td><td>object</td><td>Wallet save status. See section 8.</td></tr><tr><td>links</td><td>object</td><td>Add-to-wallet links (`saveUrl`) and QR code images (`qrUrl`) for Apple and Google. `null` for a platform the pass was not issued on. Returned by `POST /secure/passes/` and `GET /secure/passes/{id}`.</td></tr><tr><td>createdAt / updatedAt</td><td>string (date-time)</td><td>Creation and last update time.</td></tr></tbody></table>

##### 7. DELIVERING THE PASS TO THE HOLDER

There are two ways to get the pass to the holder. You can use one or both.

**Email sent by Sparados**

Set `sendEmail: true` when issuing. Sparados sends an email to `userEmail` with the `.pkpass` file attached and add-to-wallet links for Apple Wallet and Google Wallet. The email uses the template's `emailTemplate` if one is configured, otherwise the default Sparados email, in the language selected by `language`.

**Your own channel**

Use the `links` returned by `POST /secure/passes/` or `GET /secure/passes/{id}`:

<table id="bkmrk-link-use-links.apple"><thead><tr><th>Link</th><th>Use</th></tr></thead><tbody><tr><td>links.apple.saveUrl</td><td>Opens or downloads the pass for Apple Wallet. Show it as an Add to Apple Wallet button on iOS.</td></tr><tr><td>links.google.saveUrl</td><td>Opens the Google Wallet save page. Show it as an Add to Google Wallet button on Android.</td></tr><tr><td>links.apple.qrUrl / links.google.qrUrl</td><td>Image of a QR code that leads to the matching `saveUrl`. Useful on desktop, on printed materials or on a screen at an event, where the user scans it with a phone.</td></tr></tbody></table>

The links and QR codes are public and scoped to a single pass. Share them only with the pass holder.

##### 8. TRACKING WALLET ADOPTION

The `adoption` object shows whether the holder has saved the pass:

<table id="bkmrk-field-type-descripti-4"><thead><tr><th>Field</th><th>Type</th><th>Description</th></tr></thead><tbody><tr><td>adoption.apple.devices</td><td>array</td><td>Apple devices on which the pass is saved. Each item contains `deviceLibraryIdentifier` and `registeredAt`. Empty when the pass is not in Apple Wallet.</td></tr><tr><td>adoption.google.savedAt</td><td>string (date-time), nullable</td><td>When the pass was saved to Google Wallet.</td></tr><tr><td>adoption.google.deletedAt</td><td>string (date-time), nullable</td><td>When the pass was removed from Google Wallet.</td></tr></tbody></table>

To find passes that were or were not saved, use `GET /secure/passes/?adopted=true` or `adopted=false`. The filter considers active passes only. A pass counts as adopted when it is registered on an Apple device or saved and not deleted in Google Wallet. Per-template totals are available in `adoptedPassCount`.

SmartPass API does not send webhook notifications. To react to adoption, query the passes periodically.

##### 9. UPDATE A PASS

To change a pass that has already been issued, use:

```
PATCH /secure/passes/{id}
```

The change is applied to the pass on both platforms, including passes already saved in the holder's wallet. Send only the fields you want to change.

Request body example:

```json
{
  "fieldValues": {
    "holderName": "John A. Smith"
  },
  "barcodeMessage": "TICKET-000123-B",
  "expiresAt": null,
  "notify": false
}
```

Request body fields:

<table id="bkmrk-field-type-descripti-5"><thead><tr><th>Field</th><th>Type</th><th>Description</th></tr></thead><tbody><tr><td>fieldValues</td><td>object</td><td>New per-pass field values.</td></tr><tr><td>barcodeMessage</td><td>string, nullable</td><td>New barcode content.</td></tr><tr><td>barcodeAltText</td><td>string, nullable</td><td>New text under the barcode.</td></tr><tr><td>expiresAt</td><td>string (date-time), nullable</td><td>New expiry time. Sets the native expiration in Apple Wallet and the validity period and expiry notification in Google Wallet. Send `null` to remove the expiry.</td></tr><tr><td>notify</td><td>boolean</td><td>Default `true`. Set `false` to skip the wallet notification for fields with `notifyOnChange`, for example for a typo fix that should not alert the holder.</td></tr></tbody></table>

The API returns `200 OK` with the updated pass. A voided pass cannot be updated.

##### 10. VOID A PASS

To deactivate a pass, use:

```
POST /secure/passes/{id}/void
```

The pass is marked as void on both platforms and is shown as voided in the holder's wallet. The record stays available in the API with `status: "voided"` and `voidedAt` set.

Voiding is final and cannot be undone. Further updates of a voided pass are rejected. To give the holder a new pass, issue a new one.

Passes with `expiresAt` are voided automatically in the same way when the expiry time passes.

##### 11. LIST AND GET PASSES

**LIST PASSES**

```
GET /secure/passes/
```

Query parameters

<table id="bkmrk-field-type-descripti-6"><thead><tr><th>Field</th><th>Type</th><th>Description</th></tr></thead><tbody><tr><td>id</td><td>string (uuid)</td><td>Filter by pass ID.</td></tr><tr><td>templateId</td><td>string (uuid)</td><td>Filter by template.</td></tr><tr><td>userEmail</td><td>string</td><td>Filter by holder's email, substring match.</td></tr><tr><td>status</td><td>string</td><td>`active` or `voided`.</td></tr><tr><td>adopted</td><td>string</td><td>`true`: saved to a wallet. `false`: issued but not saved. Active passes only.</td></tr><tr><td>createdAtFrom / createdAtTo</td><td>string (date-time)</td><td>Filter by creation date.</td></tr><tr><td>updatedAtFrom / updatedAtTo</td><td>string (date-time)</td><td>Filter by last update date.</td></tr><tr><td>expiresAtFrom / expiresAtTo</td><td>string (date-time)</td><td>Filter by expiry date.</td></tr><tr><td>voidedAtFrom / voidedAtTo</td><td>string (date-time)</td><td>Filter by void date.</td></tr><tr><td>orderBy</td><td>string</td><td>`createdAt`, `updatedAt`, `userEmail`, `expiresAt`, `voidedAt`, `id`. Default `createdAt`.</td></tr><tr><td>orderDirection, cursor, limit</td><td> </td><td>See Pagination and sorting.</td></tr></tbody></table>

The response contains `data` (list of passes, same fields as in section 6 without `links`) and `nextCursor`.

**GET PASS DETAILS**

```
GET /secure/passes/{id}
```

Returns the pass together with its full `template` object and the current `links`. Use it to get the add-to-wallet links again, for example to resend them to the holder.

##### 12. BULK ISSUING

To issue many passes from one template, use:

```
POST /secure/passes/batches/
```

Sparados validates every row first. If any row is invalid, nothing is issued and the API returns `422 Unprocessable Entity` listing the invalid rows. If all rows are valid, the API returns `202 Accepted` and issues the passes in the background. The request body can be up to 15 MB.

<p class="callout warning">TO CONFIRM: exact body of the 422 response listing invalid rows.</p>

Request body example:

```json
{
  "templateId": "6f1c2a9e-4b7d-4c1e-9a3f-2d5e8b7c1a40",
  "sendEmail": true,
  "language": "en",
  "rows": [
    {
      "userEmail": "anna.nowak@example.com",
      "fieldValues": { "holderName": "Anna Nowak" },
      "barcodeMessage": "TICKET-000124",
      "expiresAt": "2026-12-31T23:59:00Z"
    },
    {
      "userEmail": "piotr.kowalski@example.com",
      "fieldValues": { "holderName": "Piotr Kowalski" },
      "barcodeMessage": "TICKET-000125"
    }
  ]
}
```

Request body fields:

<table id="bkmrk-field-type-descripti-7"><thead><tr><th>Field</th><th>Type</th><th>Description</th></tr></thead><tbody><tr><td>templateId\*</td><td>string, uuid</td><td>ID of the template all passes are issued from.</td></tr><tr><td>rows\*</td><td>array</td><td>One object per pass, at least one. See row fields below.</td></tr><tr><td>sendEmail</td><td>boolean</td><td>When `true`, every successfully issued pass is emailed to its `userEmail` once the batch completes. Default `false`.</td></tr><tr><td>language</td><td>string</td><td>Language of the issued-pass emails.</td></tr></tbody></table>

Row fields:

<table id="bkmrk-field-type-descripti-8"><thead><tr><th>Field</th><th>Type</th><th>Description</th></tr></thead><tbody><tr><td>userEmail\*</td><td>string, email</td><td>Pass holder's email.</td></tr><tr><td>fieldValues\*</td><td>object</td><td>Every value key the template references.</td></tr><tr><td>barcodeMessage</td><td>string</td><td>Data encoded in the barcode.</td></tr><tr><td>barcodeAltText</td><td>string</td><td>Text under the barcode.</td></tr><tr><td>expiresAt</td><td>string (date-time)</td><td>Expiry time, must be in the future.</td></tr></tbody></table>

Example response (`202 Accepted`):

```json
{
  "batchId": "952ec638-20ee-47d5-a132-408807101e26",
  "totalRows": 2
}
```

**CHECKING BATCH PROGRESS**

```
GET /secure/passes/batches/{id}
```

Returns the batch status and counters. When `pendingCount` reaches 0 and `status` is `completed`, every row has been processed.

Example response:

```json
{
  "id": "952ec638-20ee-47d5-a132-408807101e26",
  "corporationId": "1b2c3d4e-5f60-4718-8293-a4b5c6d7e8f9",
  "templateId": "6f1c2a9e-4b7d-4c1e-9a3f-2d5e8b7c1a40",
  "templateName": "Developer Day 2026",
  "authorEmail": null,
  "status": "completed",
  "totalRows": 2,
  "successCount": 2,
  "failureCount": 0,
  "pendingCount": 0,
  "sendEmail": true,
  "language": "en",
  "createdAt": "2026-10-09T14:31:00Z",
  "updatedAt": "2026-10-09T14:31:05Z",
  "completedAt": "2026-10-09T14:31:05Z"
}
```

<table id="bkmrk-field-type-descripti-9"><thead><tr><th>Field</th><th>Type</th><th>Description</th></tr></thead><tbody><tr><td>status</td><td>string</td><td>`pending`, `processing`, `completed` or `failed`.</td></tr><tr><td>totalRows</td><td>integer</td><td>Number of rows in the batch.</td></tr><tr><td>successCount / failureCount / pendingCount</td><td>integer</td><td>Rows issued, rows failed, rows not processed yet.</td></tr><tr><td>authorEmail</td><td>string, nullable</td><td>Administrator who uploaded the batch in the Corporate Panel. `null` for batches created through the API.</td></tr><tr><td>completedAt</td><td>string (date-time), nullable</td><td>When processing finished.</td></tr></tbody></table>

**BATCH ROW RESULTS**

```
GET /secure/passes/batches/{id}/rows
```

Returns the rows in submission order with their outcome. Use `status=failed` to list only the failures. Supports `cursor` and `limit` (default 100, up to 1000).

Example response:

```json
{
  "data": [
    {
      "rowNumber": 1,
      "userEmail": "anna.nowak@example.com",
      "status": "success",
      "error": null,
      "passId": "0d1e2f3a-4b5c-4d6e-8f70-819a2b3c4d5e"
    },
    {
      "rowNumber": 2,
      "userEmail": "piotr.kowalski@example.com",
      "status": "success",
      "error": null,
      "passId": "5e4d3c2b-1a09-4f8e-a7d6-c5b4a3928170"
    }
  ],
  "nextCursor": null
}
```

Store `passId` for each row so you can update or void the passes later.

**LIST BATCHES**

```
GET /secure/passes/batches/
```

Lists batches created through the API and in the Corporate Panel. Filters: `templateId`, `status`, `createdAtFrom` / `createdAtTo`, `updatedAtFrom` / `updatedAtTo`. Sorting by `createdAt`, `updatedAt` or `id`.

**Bulk issuing in the Corporate Panel**

The same batch can be created without the API in the Corporate Panel (SmartPass &gt; Campaign &gt; Bulk issue). The CSV file needs the column `userEmail` and one column per value key (for example `holderName`), with optional columns `barcodeMessage`, `barcodeAltText` and `expiresAt`. UTF-8, comma, semicolon or tab separated, up to 5 MB. Batches created in the panel are also visible through the API.

##### 13. API SWAGGER DOCUMENTATION

Detailed API documentation is available here:

<table id="bkmrk-api-documentation-li"><thead><tr><th>API Documentation</th><th>link</th></tr></thead><tbody><tr><td>SmartPass API Swagger (Passes)</td><td>[https://sp-api.verestro.dev/docs?urls.primaryName=External#/Passes](https://sp-api.verestro.dev/docs?urls.primaryName=External#/Passes)</td></tr><tr><td>Connecting to server-to-server APIs</td><td>[https://developer.sparados.com/books/sparados-api-documentation/page/connecting-to-server-to-server-apis](https://developer.sparados.com/books/sparados-api-documentation/page/connecting-to-server-to-server-apis)</td></tr><tr><td>SmartPass product page</td><td>[https://www.sparados.com/smartpass](https://www.sparados.com/smartpass)</td></tr></tbody></table>

Use the Swagger documentation as the source of detailed endpoint schemas, request parameters, response formats, and available enum values.