> For the complete documentation index, see [llms.txt](https://docs.thewalletcrew.io/llms.txt). Markdown versions of documentation pages are available by appending `.md` to page URLs; this page is available as [Markdown](https://docs.thewalletcrew.io/api-reference/pass-management/pass.md).

# Pass

## List passes

> Filters: see Neo.Web.Api.Controllers.FilterModel. Sort: see Neo.Web.Api.Controllers.SortModel; without one the order is unspecified and may change between pages.\
> \`\`\`\
> GET /api/{tenantId}/passes?pageIndex=0\&pageSize=20\&filter\[0].field=passType\&filter\[0].operator=equals\&filter\[0].value=loyalty\&sortBy\[0].field=creationDate\&sortBy\[0].direction=DESC\
> \`\`\`

````json
{"openapi":"3.1.1","info":{"title":"Neostore internal API","version":"v1"},"tags":[{"name":"Pass"}],"servers":[{"url":"https://app.neostore.cloud","description":"Production Server"},{"url":"https://app-qa.neostore.cloud","description":"Staging Server"}],"security":[{"admin-bearer":["tenant.pass:read"]},{"apiKey":[]}],"components":{"securitySchemes":{"admin-bearer":{"type":"oauth2","flows":{"implicit":{"authorizationUrl":"https://auth.neostore.cloud/authorize?audience=https://app.neostore.cloud/api/","scopes":{}}}},"apiKey":{"type":"apiKey","name":"X-API-KEY","in":"header"}},"schemas":{"FilterModel":{"type":"object","properties":{"field":{"type":"string","description":"`id`, `passType`, `themeId`, `creationDate` and `lastUpdateDate` (UTC), `installationStatus` (installed wallets concatenated: `\"\"`, `\"apple\"`, `\"google\"` or `\"applegoogle\"`; test with `contains`), `identifiers.{key}`, or `metadata.{key}` (compared as the type the tenant's metadata configuration gives it)."},"operator":{"description":"Comparison operator. Required.","$ref":"#/components/schemas/FilterModelOperator"},"value":{"type":["null","array"],"items":{"type":"string"},"description":"Values to compare, as repeated `value` query parameters (several only for `in`/`notIn`). Numbers use `.` as decimal separator, booleans are `true`/`false`, dates are ISO 8601 with timezone.\nA value containing `{{`, `{%` or `{#` is first rendered as a Liquid template (`{{ 'now' | date: '%Y-%m-%d' }}`).\n<example>```\nGET /passes?filter[0].field=passType&filter[0].operator=in&filter[0].value=boarding&filter[0].value=loyalty\n```</example>"}},"additionalProperties":false,"description":"One condition on passes. Several conditions must all hold."},"FilterModelOperator":{"enum":["Contains","StartsWith","EndsWith","Equals","IsEmpty","IsNotEmpty","NotEquals","In","NotIn","GreaterThan","LessThan","GreaterThanOrEqual","LessThanOrEqual"],"type":"string","description":"How a pass filter compares the field with its value."},"SortModel":{"type":"object","properties":{"field":{"type":"string","description":"`id`, `passType`, `themeId`, `creationDate`, `lastUpdateDate`, `apple`,\n            `google` (installation data of that wallet), `identifiers.{key}` or `metadata.{key}`; a datetime\n            metadata field sorts chronologically. Any other field is refused with a 400."},"direction":{"description":"`ASC` or `DESC`.","$ref":"#/components/schemas/SortModelDirection"}},"additionalProperties":false,"description":"One sort key for pass queries. Several keys apply in order, the first one being the primary sort."},"SortModelDirection":{"enum":[0,1],"type":"integer","description":"Sort direction for pass list queries, sent as `ASC` or `DESC`.","format":"int32"},"Pass":{"type":"object","properties":{"id":{"type":"string","description":"Id assigned at creation, or set by a `neo.id` identifier."},"secret":{"type":"string","description":"Confidential per-pass secret."},"creationDate":{"oneOf":[{"type":"string","format":"date-time"},{"type":"integer","format":"int64"}],"description":"When the pass was issued, UTC. Accepts ISO 8601 date-time string or Unix epoch seconds in request inputs. Responses are serialized as ISO 8601 date-time strings."},"lastUpdateDate":{"oneOf":[{"type":"string","format":"date-time"},{"type":"integer","format":"int64"}],"description":"When the pass content last changed, UTC; equals `creationDate` when it never has. Accepts ISO 8601 date-time string or Unix epoch seconds in request inputs. Responses are serialized as ISO 8601 date-time strings."},"passType":{"type":"string","description":"Pass template the pass renders from."},"identifiers":{"type":"object","additionalProperties":{"type":"string"},"description":"Identifiers of the holder in other systems, keyed by system and field (`shopify.customerId`)."},"metadata":{"type":"object","additionalProperties":{},"description":"Fields computed from the pass by the tenant's metadata configuration, used by filters and sorts. Datetime values are ISO 8601 strings."},"additionalData":{"type":"object","additionalProperties":{},"description":"Free data stored with the pass by its creator and updates."},"providers":{"type":"object","additionalProperties":{},"description":"Wallets the pass is installed on: `apple` (first `installationDate` and `devices`) and `google` (`installationDate`), each present while installed."},"themeId":{"type":["null","string"],"description":"Theme applied to the pass; `null` when none."}},"additionalProperties":false,"description":"A pass as listed by `GET /passes`."},"ProblemDetails":{"type":"object","properties":{"type":{"type":["null","string"]},"title":{"type":["null","string"]},"status":{"type":["null","integer"],"format":"int32"},"detail":{"type":["null","string"]},"instance":{"type":["null","string"]}},"additionalProperties":{}},"HttpValidationProblemDetails":{"type":"object","allOf":[{"$ref":"#/components/schemas/ProblemDetails"}],"properties":{"errors":{"type":"object","additionalProperties":{"type":"array","items":{"type":"string"}}}},"additionalProperties":{}}}},"paths":{"/api/{tenantId}/passes":{"get":{"tags":["Pass"],"summary":"List passes","description":"Filters: see Neo.Web.Api.Controllers.FilterModel. Sort: see Neo.Web.Api.Controllers.SortModel; without one the order is unspecified and may change between pages.\n```\nGET /api/{tenantId}/passes?pageIndex=0&pageSize=20&filter[0].field=passType&filter[0].operator=equals&filter[0].value=loyalty&sortBy[0].field=creationDate&sortBy[0].direction=DESC\n```","parameters":[{"name":"pageIndex","in":"query","description":"Zero-based page index. Default 0.","schema":{"maximum":2147483647,"minimum":0,"type":"integer","format":"int32","default":0}},{"name":"pageSize","in":"query","description":"Passes per page. Default 20; 0 returns an empty page with the total still set.","schema":{"maximum":2147483647,"minimum":0,"type":"integer","format":"int32","default":20}},{"name":"filter","in":"query","description":"Query `filter[i].field`, `filter[i].operator`, `filter[i].value`: conditions a pass must all meet.","schema":{"type":"array","items":{"description":"One condition on passes. Several conditions must all hold.","$ref":"#/components/schemas/FilterModel"}}},{"name":"sortBy","in":"query","description":"Query `sortBy[i].field`, `sortBy[i].direction`: sort keys, primary first.","schema":{"type":"array","items":{"description":"One sort key for pass queries. Several keys apply in order, the first one being the primary sort.","$ref":"#/components/schemas/SortModel"}}},{"name":"tenantId","in":"path","required":true,"schema":{"type":"string"}}],"responses":{"200":{"description":"The page of passes; the total is in the `x-pagination-total` header.","content":{"text/plain":{"schema":{"type":"array","items":{"description":"A pass as listed by `GET /passes`.","$ref":"#/components/schemas/Pass"}}},"application/json":{"schema":{"type":"array","items":{"description":"A pass as listed by `GET /passes`.","$ref":"#/components/schemas/Pass"}}},"text/json":{"schema":{"type":"array","items":{"description":"A pass as listed by `GET /passes`.","$ref":"#/components/schemas/Pass"}}}}},"400":{"description":"A filter or sort names an unsupported field, a filter has no operator, or paging is negative.","content":{"text/plain":{"schema":{"oneOf":[{"$ref":"#/components/schemas/ProblemDetails"},{"$ref":"#/components/schemas/HttpValidationProblemDetails"}]}},"application/json":{"schema":{"oneOf":[{"$ref":"#/components/schemas/ProblemDetails"},{"$ref":"#/components/schemas/HttpValidationProblemDetails"}]}},"text/json":{"schema":{"oneOf":[{"$ref":"#/components/schemas/ProblemDetails"},{"$ref":"#/components/schemas/HttpValidationProblemDetails"}]}}}},"401":{"description":"The caller is not authenticated.","content":{"application/problem+json":{"schema":{"oneOf":[{"$ref":"#/components/schemas/ProblemDetails"},{"$ref":"#/components/schemas/HttpValidationProblemDetails"}]}}}},"403":{"description":"The caller lacks the <c>tenant.pass:read</c> scope, or the endpoint is not enabled for the tenant.","content":{"application/problem+json":{"schema":{"oneOf":[{"$ref":"#/components/schemas/ProblemDetails"},{"$ref":"#/components/schemas/HttpValidationProblemDetails"}]}}}},"429":{"description":"Over 1200 requests per minute to this endpoint for the tenant (default limit); retry after <c>Retry-After</c>.","headers":{"Retry-After":{"description":"Seconds to wait before retrying. Sent when the limiter knows it.","schema":{"type":"integer"}}},"content":{"application/problem+json":{"schema":{"oneOf":[{"$ref":"#/components/schemas/ProblemDetails"},{"$ref":"#/components/schemas/HttpValidationProblemDetails"}]}}}}}}}}}
````

## Issue a pass

> Without \`tenant.pass:write\`, each identifier must be proven (see Neo.Web.Api.Controllers.PassController.PassData.Identifiers); unproven ones are dropped and the request is refused when none is left. The identifiers of an authenticated holder are added. Nothing is sent to a device until the holder downloads the pass.\
> \`\`\`\
> POST /api/{tenantId}/passes?passType=loyalty\
> { "identifiers": { "shopify.customerId": "12345", "shopify.customerId.hmac": "{hmac}" }, "additionalData": { "loyaltyTier": "silver" } }\
> \`\`\`

````json
{"openapi":"3.1.1","info":{"title":"Neostore internal API","version":"v1"},"tags":[{"name":"Pass"}],"servers":[{"url":"https://app.neostore.cloud","description":"Production Server"},{"url":"https://app-qa.neostore.cloud","description":"Staging Server"}],"security":[{"admin-bearer":["tenant.pass:write"]},{"apiKey":[]},{}],"components":{"securitySchemes":{"admin-bearer":{"type":"oauth2","flows":{"implicit":{"authorizationUrl":"https://auth.neostore.cloud/authorize?audience=https://app.neostore.cloud/api/","scopes":{}}}},"apiKey":{"type":"apiKey","name":"X-API-KEY","in":"header"}},"schemas":{"CreatePassData":{"type":"object","allOf":[{"description":"Fields a caller can set on a pass, at creation or on update.","$ref":"#/components/schemas/PassData"}],"properties":{"extensions":{"type":["null","object"],"additionalProperties":{},"description":"Initial state of the pass's extensions, keyed by name (`apple`, `google`)."}},"additionalProperties":false,"description":"Content of a new pass."},"PassData":{"type":"object","properties":{"identifiers":{"type":"object","additionalProperties":{"type":"string"},"description":"Identifiers of the holder in other systems, keyed by system and field (`shopify.customerId`), matched by `findPass`, `id.{key}` lookups and filters. Avoid keys starting with `id.`."},"additionalData":{"type":["null","object"],"additionalProperties":{},"description":"Free data stored with the pass and available to its templates."},"themeId":{"type":["null","string"],"description":"Theme applied to the pass. Omit or `null` to leave it unchanged (none on create); an empty string removes it. An unknown id is refused with a 400."}},"additionalProperties":false,"description":"Fields a caller can set on a pass, at creation or on update."},"ProblemDetails":{"type":"object","properties":{"type":{"type":["null","string"]},"title":{"type":["null","string"]},"status":{"type":["null","integer"],"format":"int32"},"detail":{"type":["null","string"]},"instance":{"type":["null","string"]}},"additionalProperties":{}},"HttpValidationProblemDetails":{"type":"object","allOf":[{"$ref":"#/components/schemas/ProblemDetails"}],"properties":{"errors":{"type":"object","additionalProperties":{"type":"array","items":{"type":"string"}}}},"additionalProperties":{}}}},"paths":{"/api/{tenantId}/passes":{"post":{"tags":["Pass"],"summary":"Issue a pass","description":"Without `tenant.pass:write`, each identifier must be proven (see Neo.Web.Api.Controllers.PassController.PassData.Identifiers); unproven ones are dropped and the request is refused when none is left. The identifiers of an authenticated holder are added. Nothing is sent to a device until the holder downloads the pass.\n```\nPOST /api/{tenantId}/passes?passType=loyalty\n{ \"identifiers\": { \"shopify.customerId\": \"12345\", \"shopify.customerId.hmac\": \"{hmac}\" }, \"additionalData\": { \"loyaltyTier\": \"silver\" } }\n```","parameters":[{"name":"passType","in":"query","description":"Pass template to issue the pass from; matched exactly.","schema":{"type":"string"}},{"name":"tenantId","in":"path","required":true,"schema":{"type":"string"}}],"requestBody":{"description":"Identifiers, data and theme of the pass.","content":{"application/json":{"schema":{"description":"Content of a new pass.","$ref":"#/components/schemas/CreatePassData"}},"text/json":{"schema":{"description":"Content of a new pass.","$ref":"#/components/schemas/CreatePassData"}},"application/*+json":{"schema":{"description":"Content of a new pass.","$ref":"#/components/schemas/CreatePassData"}}}},"responses":{"200":{"description":"The pass was created; the body is its id.","content":{"text/plain":{"schema":{"type":"string"}},"application/json":{"schema":{"type":"string"}},"text/json":{"schema":{"type":"string"}}}},"400":{"description":"`passType` is missing, or it or `themeId` names a template or theme the tenant does not have.","content":{"text/plain":{"schema":{"oneOf":[{"$ref":"#/components/schemas/ProblemDetails"},{"$ref":"#/components/schemas/HttpValidationProblemDetails"}]}},"application/json":{"schema":{"oneOf":[{"$ref":"#/components/schemas/ProblemDetails"},{"$ref":"#/components/schemas/HttpValidationProblemDetails"}]}},"text/json":{"schema":{"oneOf":[{"$ref":"#/components/schemas/ProblemDetails"},{"$ref":"#/components/schemas/HttpValidationProblemDetails"}]}}}},"401":{"description":"The caller is not authenticated and no identifier could be verified.","content":{"text/plain":{"schema":{"oneOf":[{"$ref":"#/components/schemas/ProblemDetails"},{"$ref":"#/components/schemas/HttpValidationProblemDetails"}]}},"application/json":{"schema":{"oneOf":[{"$ref":"#/components/schemas/ProblemDetails"},{"$ref":"#/components/schemas/HttpValidationProblemDetails"}]}},"text/json":{"schema":{"oneOf":[{"$ref":"#/components/schemas/ProblemDetails"},{"$ref":"#/components/schemas/HttpValidationProblemDetails"}]}}}},"403":{"description":"Authenticated without `tenant.pass:write` and no identifier verified, or the action is not enabled for the tenant.","content":{"text/plain":{"schema":{"oneOf":[{"$ref":"#/components/schemas/ProblemDetails"},{"$ref":"#/components/schemas/HttpValidationProblemDetails"}]}},"application/json":{"schema":{"oneOf":[{"$ref":"#/components/schemas/ProblemDetails"},{"$ref":"#/components/schemas/HttpValidationProblemDetails"}]}},"text/json":{"schema":{"oneOf":[{"$ref":"#/components/schemas/ProblemDetails"},{"$ref":"#/components/schemas/HttpValidationProblemDetails"}]}}}},"429":{"description":"Over 1200 requests per minute to this endpoint for the tenant (default limit); retry after <c>Retry-After</c>.","headers":{"Retry-After":{"description":"Seconds to wait before retrying. Sent when the limiter knows it.","schema":{"type":"integer"}}},"content":{"application/problem+json":{"schema":{"oneOf":[{"$ref":"#/components/schemas/ProblemDetails"},{"$ref":"#/components/schemas/HttpValidationProblemDetails"}]}}}}}}}}}
````

## Update a pass by identifiers

> Same changes, delivery and responses as \`PATCH /passes/{passId}\`, addressing the pass by \`id\` or by external identifiers.\
> \`\`\`\
> PATCH /api/{tenantId}/passes?id.shopify.customerId=12345\
> { "additionalData": { "loyaltyTier": "gold" } }\
> \`\`\`

````json
{"openapi":"3.1.1","info":{"title":"Neostore internal API","version":"v1"},"tags":[{"name":"Pass"}],"servers":[{"url":"https://app.neostore.cloud","description":"Production Server"},{"url":"https://app-qa.neostore.cloud","description":"Staging Server"}],"security":[{"admin-bearer":["tenant.pass:write"]},{"apiKey":[]}],"components":{"securitySchemes":{"admin-bearer":{"type":"oauth2","flows":{"implicit":{"authorizationUrl":"https://auth.neostore.cloud/authorize?audience=https://app.neostore.cloud/api/","scopes":{}}}},"apiKey":{"type":"apiKey","name":"X-API-KEY","in":"header"}},"schemas":{"SingleUpdatePassData":{"type":"object","allOf":[{"description":"Changes to apply to an existing pass, with options.","$ref":"#/components/schemas/UpdatePassData_SingleUpdatePassDataOptions"}],"properties":{"bypassQueue":{"type":"boolean","description":"Replaced by `options.bypassQueue`.","default":false,"deprecated":true}},"additionalProperties":false,"description":"Changes to one pass. Omitted fields are left as they are."},"UpdatePassData_SingleUpdatePassDataOptions":{"type":"object","properties":{"identifiers":{"type":"object","additionalProperties":{"type":"string"},"description":"Identifiers of the holder in other systems, keyed by system and field (`shopify.customerId`), matched by `findPass`, `id.{key}` lookups and filters. Avoid keys starting with `id.`."},"additionalData":{"type":["null","object"],"additionalProperties":{},"description":"Free data stored with the pass and available to its templates."},"themeId":{"type":["null","string"],"description":"Theme applied to the pass. Omit or `null` to leave it unchanged (none on create); an empty string removes it. An unknown id is refused with a 400."},"passType":{"type":["null","string"],"description":"Pass template to move the pass to. Omitted or blank keeps the current one; an unknown name is refused with a 400."},"updateMetadata":{"type":"boolean","description":"Replaced by `options.updateMetadata`.","default":false,"deprecated":true},"options":{"description":"How the update is applied. Omitted, the defaults of each option apply.","$ref":"#/components/schemas/SingleUpdatePassDataOptions"}},"additionalProperties":false,"description":"Changes to apply to an existing pass, with options."},"SingleUpdatePassDataOptions":{"type":"object","allOf":[{"description":"How an update is applied.","$ref":"#/components/schemas/UpdatePassDataOptions"}],"properties":{"bypassQueue":{"type":"boolean","description":"Applies and pushes the update within the request (200) instead of queuing it (202).","default":false}},"additionalProperties":false,"description":"Options for a single pass update."},"UpdatePassDataOptions":{"type":"object","properties":{"updateMetadata":{"type":"boolean","description":"Recomputes the stored pass metadata read by filters and sorts. Slower; unneeded when only displayed content changes. Default `true`, except on a bulk update sent without a body."},"correlationId":{"type":["null","string"],"description":"Groups updates into one operation tracked by `GET /passes/pushUpdate/status` and stopped by `POST /passes/pushUpdate/{correlationId}/cancel`. Random when omitted; a synchronous update then records no progress."}},"additionalProperties":false,"description":"How an update is applied."},"ProblemDetails":{"type":"object","properties":{"type":{"type":["null","string"]},"title":{"type":["null","string"]},"status":{"type":["null","integer"],"format":"int32"},"detail":{"type":["null","string"]},"instance":{"type":["null","string"]}},"additionalProperties":{}},"HttpValidationProblemDetails":{"type":"object","allOf":[{"$ref":"#/components/schemas/ProblemDetails"}],"properties":{"errors":{"type":"object","additionalProperties":{"type":"array","items":{"type":"string"}}}},"additionalProperties":{}}}},"paths":{"/api/{tenantId}/passes":{"patch":{"tags":["Pass"],"summary":"Update a pass by identifiers","description":"Same changes, delivery and responses as `PATCH /passes/{passId}`, addressing the pass by `id` or by external identifiers.\n```\nPATCH /api/{tenantId}/passes?id.shopify.customerId=12345\n{ \"additionalData\": { \"loyaltyTier\": \"gold\" } }\n```","parameters":[{"name":"identifiers","in":"query","description":"Either `id={passId}` alone, or external identifiers prefixed with `id.` (`id.y2.customerId=1233332`), all of which a pass must carry. When several passes match, one is updated.","schema":{"type":"object","additionalProperties":{"type":"string"}}},{"name":"passType","in":"query","description":"Query: only a pass of this pass template matches. Use `passType` in the body to move the pass to another template.","schema":{"type":"string"}},{"name":"tenantId","in":"path","required":true,"schema":{"type":"string"}}],"requestBody":{"description":"The changes and how to apply them.","content":{"application/json":{"schema":{"description":"Changes to one pass. Omitted fields are left as they are.","$ref":"#/components/schemas/SingleUpdatePassData"}},"text/json":{"schema":{"description":"Changes to one pass. Omitted fields are left as they are.","$ref":"#/components/schemas/SingleUpdatePassData"}},"application/*+json":{"schema":{"description":"Changes to one pass. Omitted fields are left as they are.","$ref":"#/components/schemas/SingleUpdatePassData"}}}},"responses":{"200":{"description":"Applied and pushed within the request (`options.bypassQueue` true)."},"202":{"description":"Queued."},"400":{"description":"The body's `passType` or `themeId` names a template or theme the tenant does not have, or `id` is combined with other identifiers.","content":{"text/plain":{"schema":{"oneOf":[{"$ref":"#/components/schemas/ProblemDetails"},{"$ref":"#/components/schemas/HttpValidationProblemDetails"}]}},"application/json":{"schema":{"oneOf":[{"$ref":"#/components/schemas/ProblemDetails"},{"$ref":"#/components/schemas/HttpValidationProblemDetails"}]}},"text/json":{"schema":{"oneOf":[{"$ref":"#/components/schemas/ProblemDetails"},{"$ref":"#/components/schemas/HttpValidationProblemDetails"}]}}}},"401":{"description":"The caller is not authenticated.","content":{"application/problem+json":{"schema":{"oneOf":[{"$ref":"#/components/schemas/ProblemDetails"},{"$ref":"#/components/schemas/HttpValidationProblemDetails"}]}}}},"403":{"description":"The caller lacks the <c>tenant.pass:write</c> scope, or the endpoint is not enabled for the tenant.","content":{"application/problem+json":{"schema":{"oneOf":[{"$ref":"#/components/schemas/ProblemDetails"},{"$ref":"#/components/schemas/HttpValidationProblemDetails"}]}}}},"404":{"description":"No pass matches the identifiers, or no `id` or `id.` parameter is given.","content":{"text/plain":{"schema":{"oneOf":[{"$ref":"#/components/schemas/ProblemDetails"},{"$ref":"#/components/schemas/HttpValidationProblemDetails"}]}},"application/json":{"schema":{"oneOf":[{"$ref":"#/components/schemas/ProblemDetails"},{"$ref":"#/components/schemas/HttpValidationProblemDetails"}]}},"text/json":{"schema":{"oneOf":[{"$ref":"#/components/schemas/ProblemDetails"},{"$ref":"#/components/schemas/HttpValidationProblemDetails"}]}}}},"409":{"description":"Synchronous update only: the pass was changed concurrently; retry the request.","content":{"text/plain":{"schema":{"oneOf":[{"$ref":"#/components/schemas/ProblemDetails"},{"$ref":"#/components/schemas/HttpValidationProblemDetails"}]}},"application/json":{"schema":{"oneOf":[{"$ref":"#/components/schemas/ProblemDetails"},{"$ref":"#/components/schemas/HttpValidationProblemDetails"}]}},"text/json":{"schema":{"oneOf":[{"$ref":"#/components/schemas/ProblemDetails"},{"$ref":"#/components/schemas/HttpValidationProblemDetails"}]}}}},"429":{"description":"Over 50000 requests per minute to this endpoint for the tenant (default limit); retry after <c>Retry-After</c>.","headers":{"Retry-After":{"description":"Seconds to wait before retrying. Sent when the limiter knows it.","schema":{"type":"integer"}}},"content":{"application/problem+json":{"schema":{"oneOf":[{"$ref":"#/components/schemas/ProblemDetails"},{"$ref":"#/components/schemas/HttpValidationProblemDetails"}]}}}}}}}}}
````

## Download a pass

> \`GET /api/{tenantId}/passes/xK9mP2nQr7sT?device=apple\&neo.src=email-campaign|email\`

```json
{"openapi":"3.1.1","info":{"title":"Neostore internal API","version":"v1"},"tags":[{"name":"Pass"}],"servers":[{"url":"https://app.neostore.cloud","description":"Production Server"},{"url":"https://app-qa.neostore.cloud","description":"Staging Server"}],"paths":{"/api/{tenantId}/passes/{passId}":{"get":{"tags":["Pass"],"summary":"Download a pass","description":"`GET /api/{tenantId}/passes/xK9mP2nQr7sT?device=apple&neo.src=email-campaign|email`","parameters":[{"name":"passId","in":"path","description":"Pass id.","required":true,"schema":{"pattern":"^[\\w-]{5,50}$","type":"string"}},{"name":"device","in":"query","description":"Required. `apple`: the `.pkpass` file. `google`: a JWT that saves the pass to Google Wallet. `preview`: the rendered Apple texts and colors as JSON. `auto`: redirect to `?device=apple` on an iPhone, else to `/passes/{passId}/view`.","schema":{"type":"string"}},{"name":"Tags","in":"query","description":"Comma-separated campaign tags, the first segment of `neo.src`; duplicates are dropped.","schema":{"type":"array","items":{"type":"string"}}},{"name":"Medium","in":"query","description":"Channel the link was sent through (for example `email`, `sms`), the second segment.","schema":{"type":"string"}},{"name":"Origin","in":"query","description":"Page or system the holder came from, the third segment; defaults to the `Referer` header.","schema":{"type":"string"}},{"name":"UserAgent","in":"query","description":"Taken from the request's `User-Agent` header, not from `neo.src`.","schema":{"type":"string"}},{"name":"tenantId","in":"path","required":true,"schema":{"type":"string"}}],"responses":{"200":{"description":"The pass content."},"302":{"description":"`device=auto`: redirect to the Apple download or the pass page."},"400":{"description":"`device` is missing or not one of the supported values.","content":{"text/plain":{"schema":{"oneOf":[{"$ref":"#/components/schemas/ProblemDetails"},{"$ref":"#/components/schemas/HttpValidationProblemDetails"}]}},"application/json":{"schema":{"oneOf":[{"$ref":"#/components/schemas/ProblemDetails"},{"$ref":"#/components/schemas/HttpValidationProblemDetails"}]}},"text/json":{"schema":{"oneOf":[{"$ref":"#/components/schemas/ProblemDetails"},{"$ref":"#/components/schemas/HttpValidationProblemDetails"}]}}}},"403":{"description":"The endpoint is not enabled for the tenant.","content":{"application/problem+json":{"schema":{"oneOf":[{"$ref":"#/components/schemas/ProblemDetails"},{"$ref":"#/components/schemas/HttpValidationProblemDetails"}]}}}},"404":{"description":"`device` is `apple`, `google` or `preview` and no pass has this id.","content":{"text/plain":{"schema":{"oneOf":[{"$ref":"#/components/schemas/ProblemDetails"},{"$ref":"#/components/schemas/HttpValidationProblemDetails"}]}},"application/json":{"schema":{"oneOf":[{"$ref":"#/components/schemas/ProblemDetails"},{"$ref":"#/components/schemas/HttpValidationProblemDetails"}]}},"text/json":{"schema":{"oneOf":[{"$ref":"#/components/schemas/ProblemDetails"},{"$ref":"#/components/schemas/HttpValidationProblemDetails"}]}}}},"409":{"description":"`device=apple`: the pass template lacks an image Apple Wallet requires, such as the icon.","content":{"text/plain":{"schema":{"oneOf":[{"$ref":"#/components/schemas/ProblemDetails"},{"$ref":"#/components/schemas/HttpValidationProblemDetails"}]}},"application/json":{"schema":{"oneOf":[{"$ref":"#/components/schemas/ProblemDetails"},{"$ref":"#/components/schemas/HttpValidationProblemDetails"}]}},"text/json":{"schema":{"oneOf":[{"$ref":"#/components/schemas/ProblemDetails"},{"$ref":"#/components/schemas/HttpValidationProblemDetails"}]}}}},"429":{"description":"Over 500 requests per minute to this endpoint for the tenant (default limit); retry after <c>Retry-After</c>.","headers":{"Retry-After":{"description":"Seconds to wait before retrying. Sent when the limiter knows it.","schema":{"type":"integer"}}},"content":{"application/problem+json":{"schema":{"oneOf":[{"$ref":"#/components/schemas/ProblemDetails"},{"$ref":"#/components/schemas/HttpValidationProblemDetails"}]}}}}}}}},"components":{"schemas":{"ProblemDetails":{"type":"object","properties":{"type":{"type":["null","string"]},"title":{"type":["null","string"]},"status":{"type":["null","integer"],"format":"int32"},"detail":{"type":["null","string"]},"instance":{"type":["null","string"]}},"additionalProperties":{}},"HttpValidationProblemDetails":{"type":"object","allOf":[{"$ref":"#/components/schemas/ProblemDetails"}],"properties":{"errors":{"type":"object","additionalProperties":{"type":"array","items":{"type":"string"}}}},"additionalProperties":{}}}}}
```

## Update a pass

> Identifiers and \`additionalData\` are merged (a blank identifier or \`null\` data value removes its key; omitted keys are kept); \`passType\` and \`themeId\` replace the current ones when sent. Queued by default (202); with \`options.bypassQueue\` pushed within the request (200).\
> \`\`\`\
> PATCH /api/{tenantId}/passes/xK9mP2nQr7sT\
> { "additionalData": { "points": 5000 }, "options": { "updateMetadata": true } }\
> \`\`\`

````json
{"openapi":"3.1.1","info":{"title":"Neostore internal API","version":"v1"},"tags":[{"name":"Pass"}],"servers":[{"url":"https://app.neostore.cloud","description":"Production Server"},{"url":"https://app-qa.neostore.cloud","description":"Staging Server"}],"security":[{"admin-bearer":["tenant.pass:write"]},{"apiKey":[]}],"components":{"securitySchemes":{"admin-bearer":{"type":"oauth2","flows":{"implicit":{"authorizationUrl":"https://auth.neostore.cloud/authorize?audience=https://app.neostore.cloud/api/","scopes":{}}}},"apiKey":{"type":"apiKey","name":"X-API-KEY","in":"header"}},"schemas":{"SingleUpdatePassData":{"type":"object","allOf":[{"description":"Changes to apply to an existing pass, with options.","$ref":"#/components/schemas/UpdatePassData_SingleUpdatePassDataOptions"}],"properties":{"bypassQueue":{"type":"boolean","description":"Replaced by `options.bypassQueue`.","default":false,"deprecated":true}},"additionalProperties":false,"description":"Changes to one pass. Omitted fields are left as they are."},"UpdatePassData_SingleUpdatePassDataOptions":{"type":"object","properties":{"identifiers":{"type":"object","additionalProperties":{"type":"string"},"description":"Identifiers of the holder in other systems, keyed by system and field (`shopify.customerId`), matched by `findPass`, `id.{key}` lookups and filters. Avoid keys starting with `id.`."},"additionalData":{"type":["null","object"],"additionalProperties":{},"description":"Free data stored with the pass and available to its templates."},"themeId":{"type":["null","string"],"description":"Theme applied to the pass. Omit or `null` to leave it unchanged (none on create); an empty string removes it. An unknown id is refused with a 400."},"passType":{"type":["null","string"],"description":"Pass template to move the pass to. Omitted or blank keeps the current one; an unknown name is refused with a 400."},"updateMetadata":{"type":"boolean","description":"Replaced by `options.updateMetadata`.","default":false,"deprecated":true},"options":{"description":"How the update is applied. Omitted, the defaults of each option apply.","$ref":"#/components/schemas/SingleUpdatePassDataOptions"}},"additionalProperties":false,"description":"Changes to apply to an existing pass, with options."},"SingleUpdatePassDataOptions":{"type":"object","allOf":[{"description":"How an update is applied.","$ref":"#/components/schemas/UpdatePassDataOptions"}],"properties":{"bypassQueue":{"type":"boolean","description":"Applies and pushes the update within the request (200) instead of queuing it (202).","default":false}},"additionalProperties":false,"description":"Options for a single pass update."},"UpdatePassDataOptions":{"type":"object","properties":{"updateMetadata":{"type":"boolean","description":"Recomputes the stored pass metadata read by filters and sorts. Slower; unneeded when only displayed content changes. Default `true`, except on a bulk update sent without a body."},"correlationId":{"type":["null","string"],"description":"Groups updates into one operation tracked by `GET /passes/pushUpdate/status` and stopped by `POST /passes/pushUpdate/{correlationId}/cancel`. Random when omitted; a synchronous update then records no progress."}},"additionalProperties":false,"description":"How an update is applied."},"ProblemDetails":{"type":"object","properties":{"type":{"type":["null","string"]},"title":{"type":["null","string"]},"status":{"type":["null","integer"],"format":"int32"},"detail":{"type":["null","string"]},"instance":{"type":["null","string"]}},"additionalProperties":{}},"HttpValidationProblemDetails":{"type":"object","allOf":[{"$ref":"#/components/schemas/ProblemDetails"}],"properties":{"errors":{"type":"object","additionalProperties":{"type":"array","items":{"type":"string"}}}},"additionalProperties":{}}}},"paths":{"/api/{tenantId}/passes/{passId}":{"patch":{"tags":["Pass"],"summary":"Update a pass","description":"Identifiers and `additionalData` are merged (a blank identifier or `null` data value removes its key; omitted keys are kept); `passType` and `themeId` replace the current ones when sent. Queued by default (202); with `options.bypassQueue` pushed within the request (200).\n```\nPATCH /api/{tenantId}/passes/xK9mP2nQr7sT\n{ \"additionalData\": { \"points\": 5000 }, \"options\": { \"updateMetadata\": true } }\n```","parameters":[{"name":"passId","in":"path","description":"Pass id.","required":true,"schema":{"pattern":"^[\\w-]{5,50}$","type":"string"}},{"name":"passType","in":"query","description":"Query: only a pass of this pass template matches. Use `passType` in the body to move the pass to another template.","schema":{"type":"string"}},{"name":"tenantId","in":"path","required":true,"schema":{"type":"string"}}],"requestBody":{"description":"The changes and how to apply them.","content":{"application/json":{"schema":{"description":"Changes to one pass. Omitted fields are left as they are.","$ref":"#/components/schemas/SingleUpdatePassData"}},"text/json":{"schema":{"description":"Changes to one pass. Omitted fields are left as they are.","$ref":"#/components/schemas/SingleUpdatePassData"}},"application/*+json":{"schema":{"description":"Changes to one pass. Omitted fields are left as they are.","$ref":"#/components/schemas/SingleUpdatePassData"}}}},"responses":{"200":{"description":"Applied and pushed within the request (`options.bypassQueue` true)."},"202":{"description":"Queued."},"400":{"description":"The body's `passType` or `themeId` names a template or theme the tenant does not have.","content":{"text/plain":{"schema":{"oneOf":[{"$ref":"#/components/schemas/ProblemDetails"},{"$ref":"#/components/schemas/HttpValidationProblemDetails"}]}},"application/json":{"schema":{"oneOf":[{"$ref":"#/components/schemas/ProblemDetails"},{"$ref":"#/components/schemas/HttpValidationProblemDetails"}]}},"text/json":{"schema":{"oneOf":[{"$ref":"#/components/schemas/ProblemDetails"},{"$ref":"#/components/schemas/HttpValidationProblemDetails"}]}}}},"401":{"description":"The caller is not authenticated.","content":{"application/problem+json":{"schema":{"oneOf":[{"$ref":"#/components/schemas/ProblemDetails"},{"$ref":"#/components/schemas/HttpValidationProblemDetails"}]}}}},"403":{"description":"The caller lacks the <c>tenant.pass:write</c> scope, or the endpoint is not enabled for the tenant.","content":{"application/problem+json":{"schema":{"oneOf":[{"$ref":"#/components/schemas/ProblemDetails"},{"$ref":"#/components/schemas/HttpValidationProblemDetails"}]}}}},"404":{"description":"No pass has this id, or the pass is not of the pass template given in `passType`.","content":{"text/plain":{"schema":{"oneOf":[{"$ref":"#/components/schemas/ProblemDetails"},{"$ref":"#/components/schemas/HttpValidationProblemDetails"}]}},"application/json":{"schema":{"oneOf":[{"$ref":"#/components/schemas/ProblemDetails"},{"$ref":"#/components/schemas/HttpValidationProblemDetails"}]}},"text/json":{"schema":{"oneOf":[{"$ref":"#/components/schemas/ProblemDetails"},{"$ref":"#/components/schemas/HttpValidationProblemDetails"}]}}}},"409":{"description":"Synchronous update only: the pass was changed concurrently; retry the request.","content":{"text/plain":{"schema":{"oneOf":[{"$ref":"#/components/schemas/ProblemDetails"},{"$ref":"#/components/schemas/HttpValidationProblemDetails"}]}},"application/json":{"schema":{"oneOf":[{"$ref":"#/components/schemas/ProblemDetails"},{"$ref":"#/components/schemas/HttpValidationProblemDetails"}]}},"text/json":{"schema":{"oneOf":[{"$ref":"#/components/schemas/ProblemDetails"},{"$ref":"#/components/schemas/HttpValidationProblemDetails"}]}}}},"429":{"description":"Over 50000 requests per minute to this endpoint for the tenant (default limit); retry after <c>Retry-After</c>.","headers":{"Retry-After":{"description":"Seconds to wait before retrying. Sent when the limiter knows it.","schema":{"type":"integer"}}},"content":{"application/problem+json":{"schema":{"oneOf":[{"$ref":"#/components/schemas/ProblemDetails"},{"$ref":"#/components/schemas/HttpValidationProblemDetails"}]}}}}}}}}}
````

## GET /api/{tenantId}/passes/{passId}/connect

> Get pass WebSocket URL

```json
{"openapi":"3.1.1","info":{"title":"Neostore internal API","version":"v1"},"tags":[{"name":"Pass"}],"servers":[{"url":"https://app.neostore.cloud","description":"Production Server"},{"url":"https://app-qa.neostore.cloud","description":"Staging Server"}],"paths":{"/api/{tenantId}/passes/{passId}/connect":{"get":{"tags":["Pass"],"summary":"Get pass WebSocket URL","parameters":[{"name":"passId","in":"path","description":"Pass id.","required":true,"schema":{"pattern":"^[\\w-]{5,50}$","type":"string"}},{"name":"tenantId","in":"path","required":true,"schema":{"type":"string"}}],"responses":{"200":{"description":"The WebSocket URL.","content":{"text/plain":{"schema":{"description":"Where to listen for live changes of one pass.","$ref":"#/components/schemas/PassConnectResponse"}},"application/json":{"schema":{"description":"Where to listen for live changes of one pass.","$ref":"#/components/schemas/PassConnectResponse"}},"text/json":{"schema":{"description":"Where to listen for live changes of one pass.","$ref":"#/components/schemas/PassConnectResponse"}}}},"403":{"description":"The endpoint is not enabled for the tenant.","content":{"application/problem+json":{"schema":{"oneOf":[{"$ref":"#/components/schemas/ProblemDetails"},{"$ref":"#/components/schemas/HttpValidationProblemDetails"}]}}}},"404":{"description":"No pass has this id.","content":{"text/plain":{"schema":{"oneOf":[{"$ref":"#/components/schemas/ProblemDetails"},{"$ref":"#/components/schemas/HttpValidationProblemDetails"}]}},"application/json":{"schema":{"oneOf":[{"$ref":"#/components/schemas/ProblemDetails"},{"$ref":"#/components/schemas/HttpValidationProblemDetails"}]}},"text/json":{"schema":{"oneOf":[{"$ref":"#/components/schemas/ProblemDetails"},{"$ref":"#/components/schemas/HttpValidationProblemDetails"}]}}}},"429":{"description":"Over 500 requests per minute to this endpoint for the tenant (default limit); retry after <c>Retry-After</c>.","headers":{"Retry-After":{"description":"Seconds to wait before retrying. Sent when the limiter knows it.","schema":{"type":"integer"}}},"content":{"application/problem+json":{"schema":{"oneOf":[{"$ref":"#/components/schemas/ProblemDetails"},{"$ref":"#/components/schemas/HttpValidationProblemDetails"}]}}}}}}}},"components":{"schemas":{"PassConnectResponse":{"type":"object","properties":{"url":{"type":"string","description":"WebSocket URL for live changes of the pass. It expires: request a new one to reconnect."}},"additionalProperties":false,"description":"Where to listen for live changes of one pass."},"ProblemDetails":{"type":"object","properties":{"type":{"type":["null","string"]},"title":{"type":["null","string"]},"status":{"type":["null","integer"],"format":"int32"},"detail":{"type":["null","string"]},"instance":{"type":["null","string"]}},"additionalProperties":{}},"HttpValidationProblemDetails":{"type":"object","allOf":[{"$ref":"#/components/schemas/ProblemDetails"}],"properties":{"errors":{"type":"object","additionalProperties":{"type":"array","items":{"type":"string"}}}},"additionalProperties":{}}}}}
```

## GET /api/{tenantId}/passes/{passId}/data

> Get pass template data

```json
{"openapi":"3.1.1","info":{"title":"Neostore internal API","version":"v1"},"tags":[{"name":"Pass"}],"servers":[{"url":"https://app.neostore.cloud","description":"Production Server"},{"url":"https://app-qa.neostore.cloud","description":"Staging Server"}],"paths":{"/api/{tenantId}/passes/{passId}/data":{"get":{"tags":["Pass"],"summary":"Get pass template data","parameters":[{"name":"passId","in":"path","description":"Pass id.","required":true,"schema":{"pattern":"^[\\w-]{5,50}$","type":"string"}},{"name":"tenantId","in":"path","required":true,"schema":{"type":"string"}}],"responses":{"200":{"description":"The data the pass's templates render from, as a JSON object."},"403":{"description":"The endpoint is not enabled for the tenant.","content":{"application/problem+json":{"schema":{"oneOf":[{"$ref":"#/components/schemas/ProblemDetails"},{"$ref":"#/components/schemas/HttpValidationProblemDetails"}]}}}},"429":{"description":"Over 1200 requests per minute to this endpoint for the tenant (default limit); retry after <c>Retry-After</c>.","headers":{"Retry-After":{"description":"Seconds to wait before retrying. Sent when the limiter knows it.","schema":{"type":"integer"}}},"content":{"application/problem+json":{"schema":{"oneOf":[{"$ref":"#/components/schemas/ProblemDetails"},{"$ref":"#/components/schemas/HttpValidationProblemDetails"}]}}}}}}}},"components":{"schemas":{"ProblemDetails":{"type":"object","properties":{"type":{"type":["null","string"]},"title":{"type":["null","string"]},"status":{"type":["null","integer"],"format":"int32"},"detail":{"type":["null","string"]},"instance":{"type":["null","string"]}},"additionalProperties":{}},"HttpValidationProblemDetails":{"type":"object","allOf":[{"$ref":"#/components/schemas/ProblemDetails"}],"properties":{"errors":{"type":"object","additionalProperties":{"type":"array","items":{"type":"string"}}}},"additionalProperties":{}}}}}
```

## GET /api/{tenantId}/passes/{passId}/data/raw

> Get raw pass

```json
{"openapi":"3.1.1","info":{"title":"Neostore internal API","version":"v1"},"tags":[{"name":"Pass"}],"servers":[{"url":"https://app.neostore.cloud","description":"Production Server"},{"url":"https://app-qa.neostore.cloud","description":"Staging Server"}],"paths":{"/api/{tenantId}/passes/{passId}/data/raw":{"get":{"tags":["Pass"],"summary":"Get raw pass","parameters":[{"name":"passId","in":"path","description":"Pass id.","required":true,"schema":{"pattern":"^[\\w-]{5,50}$","type":"string"}},{"name":"tenantId","in":"path","required":true,"schema":{"type":"string"}}],"responses":{"200":{"description":"The stored pass, as a JSON object."},"403":{"description":"The endpoint is not enabled for the tenant.","content":{"application/problem+json":{"schema":{"oneOf":[{"$ref":"#/components/schemas/ProblemDetails"},{"$ref":"#/components/schemas/HttpValidationProblemDetails"}]}}}},"404":{"description":"No pass has this id.","content":{"text/plain":{"schema":{"oneOf":[{"$ref":"#/components/schemas/ProblemDetails"},{"$ref":"#/components/schemas/HttpValidationProblemDetails"}]}},"application/json":{"schema":{"oneOf":[{"$ref":"#/components/schemas/ProblemDetails"},{"$ref":"#/components/schemas/HttpValidationProblemDetails"}]}},"text/json":{"schema":{"oneOf":[{"$ref":"#/components/schemas/ProblemDetails"},{"$ref":"#/components/schemas/HttpValidationProblemDetails"}]}}}},"429":{"description":"Over 1200 requests per minute to this endpoint for the tenant (default limit); retry after <c>Retry-After</c>.","headers":{"Retry-After":{"description":"Seconds to wait before retrying. Sent when the limiter knows it.","schema":{"type":"integer"}}},"content":{"application/problem+json":{"schema":{"oneOf":[{"$ref":"#/components/schemas/ProblemDetails"},{"$ref":"#/components/schemas/HttpValidationProblemDetails"}]}}}}}}}},"components":{"schemas":{"ProblemDetails":{"type":"object","properties":{"type":{"type":["null","string"]},"title":{"type":["null","string"]},"status":{"type":["null","integer"],"format":"int32"},"detail":{"type":["null","string"]},"instance":{"type":["null","string"]}},"additionalProperties":{}},"HttpValidationProblemDetails":{"type":"object","allOf":[{"$ref":"#/components/schemas/ProblemDetails"}],"properties":{"errors":{"type":"object","additionalProperties":{"type":"array","items":{"type":"string"}}}},"additionalProperties":{}}}}}
```

## Notify a pass holder by pass id

> Queued by default: 202 means accepted, not yet sent. \`options.bypassQueue\` sends synchronously (200). The message appears on the pass in the wallet: Apple devices also refresh the whole pass; Google passes get the message added.

```json
{"openapi":"3.1.1","info":{"title":"Neostore internal API","version":"v1"},"tags":[{"name":"Pass"}],"servers":[{"url":"https://app.neostore.cloud","description":"Production Server"},{"url":"https://app-qa.neostore.cloud","description":"Staging Server"}],"security":[{"admin-bearer":["tenant.pass:write"]},{"apiKey":[]}],"components":{"securitySchemes":{"admin-bearer":{"type":"oauth2","flows":{"implicit":{"authorizationUrl":"https://auth.neostore.cloud/authorize?audience=https://app.neostore.cloud/api/","scopes":{}}}},"apiKey":{"type":"apiKey","name":"X-API-KEY","in":"header"}},"schemas":{"NotifyRequest":{"type":"object","properties":{"content":{"type":["null","string"],"description":"Message for devices whose language has no entry in `localizedContent`. Optional when `localizedContent` has text; defaults to the tenant's default language entry, else the first language in ordinal order."},"localizedContent":{"type":["null","object"],"additionalProperties":{"type":"string"},"description":"Message per device language. Keys are a lowercase ISO 639-1 code, optionally with an uppercase\nregion (`en`, `fr-FR`). Entries with blank text are not sent.","propertyNames":{"pattern":"^[a-z]{2}(-[A-Z]{2})?$"}},"options":{"description":"Delivery options. Omitted, the notification is queued without refreshing pass data.","$ref":"#/components/schemas/NotifyRequestOptions"}},"additionalProperties":false,"description":"The message to show the holder, in one or several languages."},"NotifyRequestOptions":{"type":"object","properties":{"updateData":{"type":"boolean","description":"Also refreshes the Google Wallet pass content with the message. Apple always refreshes the whole pass.","default":false},"correlationId":{"maxLength":100,"minLength":10,"type":["null","string"],"description":"Caller-chosen id for tracing, such as a campaign or batch. 10 to 100 characters after trimming, otherwise 400."},"bypassQueue":{"type":"boolean","description":"Sends within the request (200) instead of queuing (202), for urgent low-volume messages.","default":false}},"additionalProperties":false,"description":"How the notification is delivered."},"ProblemDetails":{"type":"object","properties":{"type":{"type":["null","string"]},"title":{"type":["null","string"]},"status":{"type":["null","integer"],"format":"int32"},"detail":{"type":["null","string"]},"instance":{"type":["null","string"]}},"additionalProperties":{}},"HttpValidationProblemDetails":{"type":"object","allOf":[{"$ref":"#/components/schemas/ProblemDetails"}],"properties":{"errors":{"type":"object","additionalProperties":{"type":"array","items":{"type":"string"}}}},"additionalProperties":{}}}},"paths":{"/api/{tenantId}/passes/{passId}/notification":{"put":{"tags":["Pass"],"summary":"Notify a pass holder by pass id","description":"Queued by default: 202 means accepted, not yet sent. `options.bypassQueue` sends synchronously (200). The message appears on the pass in the wallet: Apple devices also refresh the whole pass; Google passes get the message added.","parameters":[{"name":"passId","in":"path","description":"Pass id assigned by the platform.","required":true,"schema":{"type":"string"}},{"name":"tenantId","in":"path","required":true,"schema":{"type":"string"}}],"requestBody":{"description":"The message and delivery options.","content":{"application/json":{"schema":{"description":"The message to show the holder, in one or several languages.","$ref":"#/components/schemas/NotifyRequest"}},"text/json":{"schema":{"description":"The message to show the holder, in one or several languages.","$ref":"#/components/schemas/NotifyRequest"}},"application/*+json":{"schema":{"description":"The message to show the holder, in one or several languages.","$ref":"#/components/schemas/NotifyRequest"}}}},"responses":{"200":{"description":"Notification sent synchronously (`options.bypassQueue` true)."},"202":{"description":"Notification queued for delivery."},"400":{"description":"Neither `content` nor `localizedContent` has text, or `correlationId` is outside 10 to 100 characters.","content":{"text/plain":{"schema":{"oneOf":[{"$ref":"#/components/schemas/ProblemDetails"},{"$ref":"#/components/schemas/HttpValidationProblemDetails"}]}},"application/json":{"schema":{"oneOf":[{"$ref":"#/components/schemas/ProblemDetails"},{"$ref":"#/components/schemas/HttpValidationProblemDetails"}]}},"text/json":{"schema":{"oneOf":[{"$ref":"#/components/schemas/ProblemDetails"},{"$ref":"#/components/schemas/HttpValidationProblemDetails"}]}}}},"401":{"description":"The caller is not authenticated.","content":{"application/problem+json":{"schema":{"oneOf":[{"$ref":"#/components/schemas/ProblemDetails"},{"$ref":"#/components/schemas/HttpValidationProblemDetails"}]}}}},"403":{"description":"The caller lacks the <c>tenant.pass:write</c> scope.","content":{"application/problem+json":{"schema":{"oneOf":[{"$ref":"#/components/schemas/ProblemDetails"},{"$ref":"#/components/schemas/HttpValidationProblemDetails"}]}}}},"404":{"description":"No pass has this id.","content":{"text/plain":{"schema":{"oneOf":[{"$ref":"#/components/schemas/ProblemDetails"},{"$ref":"#/components/schemas/HttpValidationProblemDetails"}]}},"application/json":{"schema":{"oneOf":[{"$ref":"#/components/schemas/ProblemDetails"},{"$ref":"#/components/schemas/HttpValidationProblemDetails"}]}},"text/json":{"schema":{"oneOf":[{"$ref":"#/components/schemas/ProblemDetails"},{"$ref":"#/components/schemas/HttpValidationProblemDetails"}]}}}},"429":{"description":"Over 50000 requests per minute to this endpoint for the tenant (default limit); retry after <c>Retry-After</c>.","headers":{"Retry-After":{"description":"Seconds to wait before retrying. Sent when the limiter knows it.","schema":{"type":"integer"}}},"content":{"application/problem+json":{"schema":{"oneOf":[{"$ref":"#/components/schemas/ProblemDetails"},{"$ref":"#/components/schemas/HttpValidationProblemDetails"}]}}}}}}}}}
```

## Open pass page

> Forwards the query parameters to the download page, with \`id\` set to the pass id.

```json
{"openapi":"3.1.1","info":{"title":"Neostore internal API","version":"v1"},"tags":[{"name":"Pass"}],"servers":[{"url":"https://app.neostore.cloud","description":"Production Server"},{"url":"https://app-qa.neostore.cloud","description":"Staging Server"}],"paths":{"/api/{tenantId}/passes/{passId}/view":{"get":{"tags":["Pass"],"summary":"Open pass page","description":"Forwards the query parameters to the download page, with `id` set to the pass id.","parameters":[{"name":"passId","in":"path","description":"Pass id.","required":true,"schema":{"type":"string"}},{"name":"tenantId","in":"path","required":true,"schema":{"type":"string"}}],"responses":{"302":{"description":"Redirect to the download page of the pass's pass template."},"403":{"description":"The endpoint is not enabled for the tenant.","content":{"application/problem+json":{"schema":{"oneOf":[{"$ref":"#/components/schemas/ProblemDetails"},{"$ref":"#/components/schemas/HttpValidationProblemDetails"}]}}}},"404":{"description":"No pass has this id.","content":{"text/plain":{"schema":{"oneOf":[{"$ref":"#/components/schemas/ProblemDetails"},{"$ref":"#/components/schemas/HttpValidationProblemDetails"}]}},"application/json":{"schema":{"oneOf":[{"$ref":"#/components/schemas/ProblemDetails"},{"$ref":"#/components/schemas/HttpValidationProblemDetails"}]}},"text/json":{"schema":{"oneOf":[{"$ref":"#/components/schemas/ProblemDetails"},{"$ref":"#/components/schemas/HttpValidationProblemDetails"}]}}}},"429":{"description":"Over 1200 requests per minute to this endpoint for the tenant (default limit); retry after <c>Retry-After</c>.","headers":{"Retry-After":{"description":"Seconds to wait before retrying. Sent when the limiter knows it.","schema":{"type":"integer"}}},"content":{"application/problem+json":{"schema":{"oneOf":[{"$ref":"#/components/schemas/ProblemDetails"},{"$ref":"#/components/schemas/HttpValidationProblemDetails"}]}}}}}}}},"components":{"schemas":{"ProblemDetails":{"type":"object","properties":{"type":{"type":["null","string"]},"title":{"type":["null","string"]},"status":{"type":["null","integer"],"format":"int32"},"detail":{"type":["null","string"]},"instance":{"type":["null","string"]}},"additionalProperties":{}},"HttpValidationProblemDetails":{"type":"object","allOf":[{"$ref":"#/components/schemas/ProblemDetails"}],"properties":{"errors":{"type":"object","additionalProperties":{"type":"array","items":{"type":"string"}}}},"additionalProperties":{}}}}}
```

## GET /api/{tenantId}/passes/{passIds}

> Download several passes

```json
{"openapi":"3.1.1","info":{"title":"Neostore internal API","version":"v1"},"tags":[{"name":"Pass"}],"servers":[{"url":"https://app.neostore.cloud","description":"Production Server"},{"url":"https://app-qa.neostore.cloud","description":"Staging Server"}],"paths":{"/api/{tenantId}/passes/{passIds}":{"get":{"tags":["Pass"],"summary":"Download several passes","parameters":[{"name":"passIds","in":"path","description":"At least two comma-separated pass ids, each 5 to 50 letters, digits, `_` or `-`.","required":true,"schema":{"pattern":"^[\\w-]{5,50},([\\w-]{5,50},?)+$","type":"array","items":{"type":"string"},"description":"Pass ids read from a comma-separated route segment; blank entries are dropped."}},{"name":"device","in":"query","description":"`apple` or `google`.","schema":{"type":"string"}},{"name":"Tags","in":"query","description":"Comma-separated campaign tags, the first segment of `neo.src`; duplicates are dropped.","schema":{"type":"array","items":{"type":"string"}}},{"name":"Medium","in":"query","description":"Channel the link was sent through (for example `email`, `sms`), the second segment.","schema":{"type":"string"}},{"name":"Origin","in":"query","description":"Page or system the holder came from, the third segment; defaults to the `Referer` header.","schema":{"type":"string"}},{"name":"UserAgent","in":"query","description":"Taken from the request's `User-Agent` header, not from `neo.src`.","schema":{"type":"string"}},{"name":"tenantId","in":"path","required":true,"schema":{"type":"string"}}],"responses":{"200":{"description":"The `.pkpasses` bundle, or the Google Wallet JWT."},"400":{"description":"`device` is not `apple` or `google`.","content":{"text/plain":{"schema":{"oneOf":[{"$ref":"#/components/schemas/ProblemDetails"},{"$ref":"#/components/schemas/HttpValidationProblemDetails"}]}},"application/json":{"schema":{"oneOf":[{"$ref":"#/components/schemas/ProblemDetails"},{"$ref":"#/components/schemas/HttpValidationProblemDetails"}]}},"text/json":{"schema":{"oneOf":[{"$ref":"#/components/schemas/ProblemDetails"},{"$ref":"#/components/schemas/HttpValidationProblemDetails"}]}}}},"403":{"description":"The endpoint is not enabled for the tenant.","content":{"application/problem+json":{"schema":{"oneOf":[{"$ref":"#/components/schemas/ProblemDetails"},{"$ref":"#/components/schemas/HttpValidationProblemDetails"}]}}}},"404":{"description":"A listed id has no pass.","content":{"text/plain":{"schema":{"oneOf":[{"$ref":"#/components/schemas/ProblemDetails"},{"$ref":"#/components/schemas/HttpValidationProblemDetails"}]}},"application/json":{"schema":{"oneOf":[{"$ref":"#/components/schemas/ProblemDetails"},{"$ref":"#/components/schemas/HttpValidationProblemDetails"}]}},"text/json":{"schema":{"oneOf":[{"$ref":"#/components/schemas/ProblemDetails"},{"$ref":"#/components/schemas/HttpValidationProblemDetails"}]}}}},"429":{"description":"Over 1200 requests per minute to this endpoint for the tenant (default limit); retry after <c>Retry-After</c>.","headers":{"Retry-After":{"description":"Seconds to wait before retrying. Sent when the limiter knows it.","schema":{"type":"integer"}}},"content":{"application/problem+json":{"schema":{"oneOf":[{"$ref":"#/components/schemas/ProblemDetails"},{"$ref":"#/components/schemas/HttpValidationProblemDetails"}]}}}}}}}},"components":{"schemas":{"ProblemDetails":{"type":"object","properties":{"type":{"type":["null","string"]},"title":{"type":["null","string"]},"status":{"type":["null","integer"],"format":"int32"},"detail":{"type":["null","string"]},"instance":{"type":["null","string"]}},"additionalProperties":{}},"HttpValidationProblemDetails":{"type":"object","allOf":[{"$ref":"#/components/schemas/ProblemDetails"}],"properties":{"errors":{"type":"object","additionalProperties":{"type":"array","items":{"type":"string"}}}},"additionalProperties":{}}}}}
```

## GET /api/{tenantId}/passes/findPass

> Find a pass

```json
{"openapi":"3.1.1","info":{"title":"Neostore internal API","version":"v1"},"tags":[{"name":"Pass"}],"servers":[{"url":"https://app.neostore.cloud","description":"Production Server"},{"url":"https://app-qa.neostore.cloud","description":"Staging Server"}],"paths":{"/api/{tenantId}/passes/findPass":{"get":{"tags":["Pass"],"summary":"Find a pass","parameters":[{"name":"identifiers","in":"query","description":"Every other query parameter, as `{key}={value}`; a pass must carry all of them. Without `tenant.pass:read`, each needs a `{key}.hmac` or `{key}.secret` proof; unproven ones are ignored.","schema":{"type":"object","additionalProperties":{"type":"string"}}},{"name":"passType","in":"query","description":"Restricts the search to this pass template.","schema":{"type":"string"}},{"name":"tenantId","in":"path","required":true,"schema":{"type":"string"}}],"responses":{"200":{"description":"The id of the most recently created matching pass.","content":{"text/plain":{"schema":{"type":"string"}},"application/json":{"schema":{"type":"string"}},"text/json":{"schema":{"type":"string"}}}},"204":{"description":"No pass matches the identifiers."},"401":{"description":"The caller is not authenticated and no identifier could be verified.","content":{"text/plain":{"schema":{"oneOf":[{"$ref":"#/components/schemas/ProblemDetails"},{"$ref":"#/components/schemas/HttpValidationProblemDetails"}]}},"application/json":{"schema":{"oneOf":[{"$ref":"#/components/schemas/ProblemDetails"},{"$ref":"#/components/schemas/HttpValidationProblemDetails"}]}},"text/json":{"schema":{"oneOf":[{"$ref":"#/components/schemas/ProblemDetails"},{"$ref":"#/components/schemas/HttpValidationProblemDetails"}]}}}},"403":{"description":"Authenticated without `tenant.pass:read` and no identifier verified, or the action is not enabled for the tenant.","content":{"text/plain":{"schema":{"oneOf":[{"$ref":"#/components/schemas/ProblemDetails"},{"$ref":"#/components/schemas/HttpValidationProblemDetails"}]}},"application/json":{"schema":{"oneOf":[{"$ref":"#/components/schemas/ProblemDetails"},{"$ref":"#/components/schemas/HttpValidationProblemDetails"}]}},"text/json":{"schema":{"oneOf":[{"$ref":"#/components/schemas/ProblemDetails"},{"$ref":"#/components/schemas/HttpValidationProblemDetails"}]}}}},"429":{"description":"Over 1200 requests per minute to this endpoint for the tenant (default limit); retry after <c>Retry-After</c>.","headers":{"Retry-After":{"description":"Seconds to wait before retrying. Sent when the limiter knows it.","schema":{"type":"integer"}}},"content":{"application/problem+json":{"schema":{"oneOf":[{"$ref":"#/components/schemas/ProblemDetails"},{"$ref":"#/components/schemas/HttpValidationProblemDetails"}]}}}}}}}},"components":{"schemas":{"ProblemDetails":{"type":"object","properties":{"type":{"type":["null","string"]},"title":{"type":["null","string"]},"status":{"type":["null","integer"],"format":"int32"},"detail":{"type":["null","string"]},"instance":{"type":["null","string"]}},"additionalProperties":{}},"HttpValidationProblemDetails":{"type":"object","allOf":[{"$ref":"#/components/schemas/ProblemDetails"}],"properties":{"errors":{"type":"object","additionalProperties":{"type":"array","items":{"type":"string"}}}},"additionalProperties":{}}}}}
```

## Find several passes

> \<b>Direct:\</b>\
> \`ids=id1,id2\` returns one item per id. \<b>Supplier:\</b>\`ids.{provider}={key}\` (\`ids.shopify=ORDER-12345\`) asks that connector for the passes of the key, creating missing ones; it may require \`ids.{provider}.hmac\` or \`.secret\` proof.

```json
{"openapi":"3.1.1","info":{"title":"Neostore internal API","version":"v1"},"tags":[{"name":"Pass"}],"servers":[{"url":"https://app.neostore.cloud","description":"Production Server"},{"url":"https://app-qa.neostore.cloud","description":"Staging Server"}],"paths":{"/api/{tenantId}/passes/findPasses":{"get":{"tags":["Pass"],"summary":"Find several passes","description":"<b>Direct:</b>\n`ids=id1,id2` returns one item per id. <b>Supplier:</b>`ids.{provider}={key}` (`ids.shopify=ORDER-12345`) asks that connector for the passes of the key, creating missing ones; it may require `ids.{provider}.hmac` or `.secret` proof.","parameters":[{"name":"identifiers","in":"query","description":"The query parameters: `ids={csv}`, or a single `ids.{provider}={key}` with its optional proof.\n`ids` takes precedence over `ids.*` parameters.","schema":{"type":"object","additionalProperties":{"type":"string"}}},{"name":"includePreview","in":"query","description":"Adds `title`, `subTitle`, `backgroundColor`, `foregroundColor`, `headerText` and `isEnabled`, rendered from the Apple pass.","schema":{"type":"boolean","default":false}},{"name":"tenantId","in":"path","required":true,"schema":{"type":"string"}}],"responses":{"200":{"description":"One item per pass, with its `serialNumber` (the pass id).","content":{"text/plain":{"schema":{"type":"array","items":{}}},"application/json":{"schema":{"type":"array","items":{}}},"text/json":{"schema":{"type":"array","items":{}}}}},"400":{"description":"Neither `ids` nor an `ids.{provider}` parameter, several providers, an empty provider value, or a provider with no connector.","content":{"text/plain":{"schema":{"oneOf":[{"$ref":"#/components/schemas/ProblemDetails"},{"$ref":"#/components/schemas/HttpValidationProblemDetails"}]}},"application/json":{"schema":{"oneOf":[{"$ref":"#/components/schemas/ProblemDetails"},{"$ref":"#/components/schemas/HttpValidationProblemDetails"}]}},"text/json":{"schema":{"oneOf":[{"$ref":"#/components/schemas/ProblemDetails"},{"$ref":"#/components/schemas/HttpValidationProblemDetails"}]}}}},"403":{"description":"The endpoint is not enabled for the tenant.","content":{"application/problem+json":{"schema":{"oneOf":[{"$ref":"#/components/schemas/ProblemDetails"},{"$ref":"#/components/schemas/HttpValidationProblemDetails"}]}}}},"429":{"description":"Over 1200 requests per minute to this endpoint for the tenant (default limit); retry after <c>Retry-After</c>.","headers":{"Retry-After":{"description":"Seconds to wait before retrying. Sent when the limiter knows it.","schema":{"type":"integer"}}},"content":{"application/problem+json":{"schema":{"oneOf":[{"$ref":"#/components/schemas/ProblemDetails"},{"$ref":"#/components/schemas/HttpValidationProblemDetails"}]}}}}}}}},"components":{"schemas":{"ProblemDetails":{"type":"object","properties":{"type":{"type":["null","string"]},"title":{"type":["null","string"]},"status":{"type":["null","integer"],"format":"int32"},"detail":{"type":["null","string"]},"instance":{"type":["null","string"]}},"additionalProperties":{}},"HttpValidationProblemDetails":{"type":"object","allOf":[{"$ref":"#/components/schemas/ProblemDetails"}],"properties":{"errors":{"type":"object","additionalProperties":{"type":"array","items":{"type":"string"}}}},"additionalProperties":{}}}}}
```

## Notify a pass holder by identifiers

> Same body, delivery and responses as \`PUT /passes/{passId}/notification\`, for a pass found by identifiers.

```json
{"openapi":"3.1.1","info":{"title":"Neostore internal API","version":"v1"},"tags":[{"name":"Pass"}],"servers":[{"url":"https://app.neostore.cloud","description":"Production Server"},{"url":"https://app-qa.neostore.cloud","description":"Staging Server"}],"security":[{"admin-bearer":["tenant.pass:write"]},{"apiKey":[]}],"components":{"securitySchemes":{"admin-bearer":{"type":"oauth2","flows":{"implicit":{"authorizationUrl":"https://auth.neostore.cloud/authorize?audience=https://app.neostore.cloud/api/","scopes":{}}}},"apiKey":{"type":"apiKey","name":"X-API-KEY","in":"header"}},"schemas":{"NotifyRequest":{"type":"object","properties":{"content":{"type":["null","string"],"description":"Message for devices whose language has no entry in `localizedContent`. Optional when `localizedContent` has text; defaults to the tenant's default language entry, else the first language in ordinal order."},"localizedContent":{"type":["null","object"],"additionalProperties":{"type":"string"},"description":"Message per device language. Keys are a lowercase ISO 639-1 code, optionally with an uppercase\nregion (`en`, `fr-FR`). Entries with blank text are not sent.","propertyNames":{"pattern":"^[a-z]{2}(-[A-Z]{2})?$"}},"options":{"description":"Delivery options. Omitted, the notification is queued without refreshing pass data.","$ref":"#/components/schemas/NotifyRequestOptions"}},"additionalProperties":false,"description":"The message to show the holder, in one or several languages."},"NotifyRequestOptions":{"type":"object","properties":{"updateData":{"type":"boolean","description":"Also refreshes the Google Wallet pass content with the message. Apple always refreshes the whole pass.","default":false},"correlationId":{"maxLength":100,"minLength":10,"type":["null","string"],"description":"Caller-chosen id for tracing, such as a campaign or batch. 10 to 100 characters after trimming, otherwise 400."},"bypassQueue":{"type":"boolean","description":"Sends within the request (200) instead of queuing (202), for urgent low-volume messages.","default":false}},"additionalProperties":false,"description":"How the notification is delivered."},"ProblemDetails":{"type":"object","properties":{"type":{"type":["null","string"]},"title":{"type":["null","string"]},"status":{"type":["null","integer"],"format":"int32"},"detail":{"type":["null","string"]},"instance":{"type":["null","string"]}},"additionalProperties":{}},"HttpValidationProblemDetails":{"type":"object","allOf":[{"$ref":"#/components/schemas/ProblemDetails"}],"properties":{"errors":{"type":"object","additionalProperties":{"type":"array","items":{"type":"string"}}}},"additionalProperties":{}}}},"paths":{"/api/{tenantId}/passes/notification":{"put":{"tags":["Pass"],"summary":"Notify a pass holder by identifiers","description":"Same body, delivery and responses as `PUT /passes/{passId}/notification`, for a pass found by identifiers.","parameters":[{"name":"identifiers","in":"query","description":"Query selecting the pass. Either `id={passId}` alone, or external identifiers prefixed with `id.` (`id.y2.customerId=1233332`), all of which a pass must carry. When several passes match, one is notified.","schema":{"type":"object","additionalProperties":{"type":"string"}}},{"name":"tenantId","in":"path","required":true,"schema":{"type":"string"}}],"requestBody":{"description":"The message and delivery options.","content":{"application/json":{"schema":{"description":"The message to show the holder, in one or several languages.","$ref":"#/components/schemas/NotifyRequest"}},"text/json":{"schema":{"description":"The message to show the holder, in one or several languages.","$ref":"#/components/schemas/NotifyRequest"}},"application/*+json":{"schema":{"description":"The message to show the holder, in one or several languages.","$ref":"#/components/schemas/NotifyRequest"}}}},"responses":{"200":{"description":"Notification sent synchronously (`options.bypassQueue` true)."},"202":{"description":"Notification queued for delivery."},"400":{"description":"Neither `content` nor `localizedContent` has text, `correlationId` is outside 10 to 100 characters, or `id` is combined with other identifiers.","content":{"text/plain":{"schema":{"oneOf":[{"$ref":"#/components/schemas/ProblemDetails"},{"$ref":"#/components/schemas/HttpValidationProblemDetails"}]}},"application/json":{"schema":{"oneOf":[{"$ref":"#/components/schemas/ProblemDetails"},{"$ref":"#/components/schemas/HttpValidationProblemDetails"}]}},"text/json":{"schema":{"oneOf":[{"$ref":"#/components/schemas/ProblemDetails"},{"$ref":"#/components/schemas/HttpValidationProblemDetails"}]}}}},"401":{"description":"The caller is not authenticated.","content":{"application/problem+json":{"schema":{"oneOf":[{"$ref":"#/components/schemas/ProblemDetails"},{"$ref":"#/components/schemas/HttpValidationProblemDetails"}]}}}},"403":{"description":"The caller lacks the <c>tenant.pass:write</c> scope.","content":{"application/problem+json":{"schema":{"oneOf":[{"$ref":"#/components/schemas/ProblemDetails"},{"$ref":"#/components/schemas/HttpValidationProblemDetails"}]}}}},"404":{"description":"No pass matches the identifiers, or no `id` or `id.` parameter is given.","content":{"text/plain":{"schema":{"oneOf":[{"$ref":"#/components/schemas/ProblemDetails"},{"$ref":"#/components/schemas/HttpValidationProblemDetails"}]}},"application/json":{"schema":{"oneOf":[{"$ref":"#/components/schemas/ProblemDetails"},{"$ref":"#/components/schemas/HttpValidationProblemDetails"}]}},"text/json":{"schema":{"oneOf":[{"$ref":"#/components/schemas/ProblemDetails"},{"$ref":"#/components/schemas/HttpValidationProblemDetails"}]}}}},"429":{"description":"Over 50000 requests per minute to this endpoint for the tenant (default limit); retry after <c>Retry-After</c>.","headers":{"Retry-After":{"description":"Seconds to wait before retrying. Sent when the limiter knows it.","schema":{"type":"integer"}}},"content":{"application/problem+json":{"schema":{"oneOf":[{"$ref":"#/components/schemas/ProblemDetails"},{"$ref":"#/components/schemas/HttpValidationProblemDetails"}]}}}}}}}}}
```

## Update passes in bulk

> Applies one change to every pass matching the filters (same fields and operators as \`GET /passes\`; no filter selects every pass) and pushes each to its holder's devices. Each pass is queued as its own update, spread by \`options.throughput\`: a 200 means scheduled, not done. Follow progress with \`GET /passes/pushUpdate/status\` under \`options.correlationId\`, stop it with \`POST /passes/pushUpdate/{correlationId}/cancel\`. \`additionalData\` is merged and \`passType\` replaces the template when sent; \`themeId\` omitted keeps each pass's theme, an empty string removes it. Identifiers are not changed.\
> \`\`\`\
> POST /api/{tenantId}/passes/pushUpdate?filter\[0].field=passType\&filter\[0].operator=equals\&filter\[0].value=loyalty\
> { "additionalData": { "offer": "summer2025" }, "options": { "throughput": 12, "correlationId": "campaign-summer-2025" } }\
> \`\`\`

````json
{"openapi":"3.1.1","info":{"title":"Neostore internal API","version":"v1"},"tags":[{"name":"Pass"}],"servers":[{"url":"https://app.neostore.cloud","description":"Production Server"},{"url":"https://app-qa.neostore.cloud","description":"Staging Server"}],"security":[{"admin-bearer":["tenant.pass:pushUpdate"]},{"apiKey":[]}],"components":{"securitySchemes":{"admin-bearer":{"type":"oauth2","flows":{"implicit":{"authorizationUrl":"https://auth.neostore.cloud/authorize?audience=https://app.neostore.cloud/api/","scopes":{}}}},"apiKey":{"type":"apiKey","name":"X-API-KEY","in":"header"}},"schemas":{"FilterModel":{"type":"object","properties":{"field":{"type":"string","description":"`id`, `passType`, `themeId`, `creationDate` and `lastUpdateDate` (UTC), `installationStatus` (installed wallets concatenated: `\"\"`, `\"apple\"`, `\"google\"` or `\"applegoogle\"`; test with `contains`), `identifiers.{key}`, or `metadata.{key}` (compared as the type the tenant's metadata configuration gives it)."},"operator":{"description":"Comparison operator. Required.","$ref":"#/components/schemas/FilterModelOperator"},"value":{"type":["null","array"],"items":{"type":"string"},"description":"Values to compare, as repeated `value` query parameters (several only for `in`/`notIn`). Numbers use `.` as decimal separator, booleans are `true`/`false`, dates are ISO 8601 with timezone.\nA value containing `{{`, `{%` or `{#` is first rendered as a Liquid template (`{{ 'now' | date: '%Y-%m-%d' }}`).\n<example>```\nGET /passes?filter[0].field=passType&filter[0].operator=in&filter[0].value=boarding&filter[0].value=loyalty\n```</example>"}},"additionalProperties":false,"description":"One condition on passes. Several conditions must all hold."},"FilterModelOperator":{"enum":["Contains","StartsWith","EndsWith","Equals","IsEmpty","IsNotEmpty","NotEquals","In","NotIn","GreaterThan","LessThan","GreaterThanOrEqual","LessThanOrEqual"],"type":"string","description":"How a pass filter compares the field with its value."},"MultipleUpdatePassData":{"type":"object","allOf":[{"description":"Changes to apply to an existing pass, with options.","$ref":"#/components/schemas/UpdatePassData_MultipleUpdatePassDataOptions"}],"additionalProperties":false,"description":"Changes applied to every matched pass. Omitted fields are left as they are."},"UpdatePassData_MultipleUpdatePassDataOptions":{"type":"object","properties":{"identifiers":{"type":"object","additionalProperties":{"type":"string"},"description":"Identifiers of the holder in other systems, keyed by system and field (`shopify.customerId`), matched by `findPass`, `id.{key}` lookups and filters. Avoid keys starting with `id.`."},"additionalData":{"type":["null","object"],"additionalProperties":{},"description":"Free data stored with the pass and available to its templates."},"themeId":{"type":["null","string"],"description":"Theme applied to the pass. Omit or `null` to leave it unchanged (none on create); an empty string removes it. An unknown id is refused with a 400."},"passType":{"type":["null","string"],"description":"Pass template to move the pass to. Omitted or blank keeps the current one; an unknown name is refused with a 400."},"updateMetadata":{"type":"boolean","description":"Replaced by `options.updateMetadata`.","default":false,"deprecated":true},"options":{"description":"How the update is applied. Omitted, the defaults of each option apply.","$ref":"#/components/schemas/MultipleUpdatePassDataOptions"}},"additionalProperties":false,"description":"Changes to apply to an existing pass, with options."},"MultipleUpdatePassDataOptions":{"type":"object","allOf":[{"$ref":"#/components/schemas/UpdatePassDataOptions"}],"properties":{"throughput":{"type":"number","description":"Passes updated per second, greater than 0 and at most 1000. Default 12; best effort.","format":"float"}},"additionalProperties":false,"description":"Options for a bulk update."},"UpdatePassDataOptions":{"type":"object","properties":{"updateMetadata":{"type":"boolean","description":"Recomputes the stored pass metadata read by filters and sorts. Slower; unneeded when only displayed content changes. Default `true`, except on a bulk update sent without a body."},"correlationId":{"type":["null","string"],"description":"Groups updates into one operation tracked by `GET /passes/pushUpdate/status` and stopped by `POST /passes/pushUpdate/{correlationId}/cancel`. Random when omitted; a synchronous update then records no progress."}},"additionalProperties":false,"description":"How an update is applied."},"PushUpdateResult":{"type":"object","properties":{"passCount":{"type":"integer","description":"Passes matched by the filters and queued for the update; 0 when none matched.","format":"int32"}},"additionalProperties":false,"description":"What a bulk update scheduled."},"ProblemDetails":{"type":"object","properties":{"type":{"type":["null","string"]},"title":{"type":["null","string"]},"status":{"type":["null","integer"],"format":"int32"},"detail":{"type":["null","string"]},"instance":{"type":["null","string"]}},"additionalProperties":{}},"HttpValidationProblemDetails":{"type":"object","allOf":[{"$ref":"#/components/schemas/ProblemDetails"}],"properties":{"errors":{"type":"object","additionalProperties":{"type":"array","items":{"type":"string"}}}},"additionalProperties":{}}}},"paths":{"/api/{tenantId}/passes/pushUpdate":{"post":{"tags":["Pass"],"summary":"Update passes in bulk","description":"Applies one change to every pass matching the filters (same fields and operators as `GET /passes`; no filter selects every pass) and pushes each to its holder's devices. Each pass is queued as its own update, spread by `options.throughput`: a 200 means scheduled, not done. Follow progress with `GET /passes/pushUpdate/status` under `options.correlationId`, stop it with `POST /passes/pushUpdate/{correlationId}/cancel`. `additionalData` is merged and `passType` replaces the template when sent; `themeId` omitted keeps each pass's theme, an empty string removes it. Identifiers are not changed.\n```\nPOST /api/{tenantId}/passes/pushUpdate?filter[0].field=passType&filter[0].operator=equals&filter[0].value=loyalty\n{ \"additionalData\": { \"offer\": \"summer2025\" }, \"options\": { \"throughput\": 12, \"correlationId\": \"campaign-summer-2025\" } }\n```","parameters":[{"name":"filter","in":"query","description":"Query `filter[i].field`, `filter[i].operator`, `filter[i].value`: conditions a pass must all meet.","schema":{"type":"array","items":{"description":"One condition on passes. Several conditions must all hold.","$ref":"#/components/schemas/FilterModel"}}},{"name":"tenantId","in":"path","required":true,"schema":{"type":"string"}}],"requestBody":{"description":"The change applied to each pass, and options. Omitted, each pass is pushed as it is, without recomputing metadata, at the tenant's default throughput.","content":{"application/json":{"schema":{"description":"Changes applied to every matched pass. Omitted fields are left as they are.","$ref":"#/components/schemas/MultipleUpdatePassData"}},"text/json":{"schema":{"description":"Changes applied to every matched pass. Omitted fields are left as they are.","$ref":"#/components/schemas/MultipleUpdatePassData"}},"application/*+json":{"schema":{"description":"Changes applied to every matched pass. Omitted fields are left as they are.","$ref":"#/components/schemas/MultipleUpdatePassData"}}}},"responses":{"200":{"description":"The passes are scheduled; the body gives how many.","content":{"text/plain":{"schema":{"description":"What a bulk update scheduled.","$ref":"#/components/schemas/PushUpdateResult"}},"application/json":{"schema":{"description":"What a bulk update scheduled.","$ref":"#/components/schemas/PushUpdateResult"}},"text/json":{"schema":{"description":"What a bulk update scheduled.","$ref":"#/components/schemas/PushUpdateResult"}}}},"400":{"description":"`passType` or `themeId` names a template or theme the tenant does not have, a filter names an unsupported field, or a filter has no operator.","content":{"text/plain":{"schema":{"oneOf":[{"$ref":"#/components/schemas/ProblemDetails"},{"$ref":"#/components/schemas/HttpValidationProblemDetails"}]}},"application/json":{"schema":{"oneOf":[{"$ref":"#/components/schemas/ProblemDetails"},{"$ref":"#/components/schemas/HttpValidationProblemDetails"}]}},"text/json":{"schema":{"oneOf":[{"$ref":"#/components/schemas/ProblemDetails"},{"$ref":"#/components/schemas/HttpValidationProblemDetails"}]}}}},"401":{"description":"The caller is not authenticated.","content":{"application/problem+json":{"schema":{"oneOf":[{"$ref":"#/components/schemas/ProblemDetails"},{"$ref":"#/components/schemas/HttpValidationProblemDetails"}]}}}},"403":{"description":"The caller lacks the <c>tenant.pass:pushUpdate</c> scope, or the endpoint is not enabled for the tenant.","content":{"application/problem+json":{"schema":{"oneOf":[{"$ref":"#/components/schemas/ProblemDetails"},{"$ref":"#/components/schemas/HttpValidationProblemDetails"}]}}}},"429":{"description":"Over 1200 requests per minute to this endpoint for the tenant (default limit); retry after <c>Retry-After</c>.","headers":{"Retry-After":{"description":"Seconds to wait before retrying. Sent when the limiter knows it.","schema":{"type":"integer"}}},"content":{"application/problem+json":{"schema":{"oneOf":[{"$ref":"#/components/schemas/ProblemDetails"},{"$ref":"#/components/schemas/HttpValidationProblemDetails"}]}}}}}}}}}
````

## Cancel a bulk update

> Skips the operation's pass updates not yet run; applied ones stay applied and one running now may still complete.

```json
{"openapi":"3.1.1","info":{"title":"Neostore internal API","version":"v1"},"tags":[{"name":"Pass"}],"servers":[{"url":"https://app.neostore.cloud","description":"Production Server"},{"url":"https://app-qa.neostore.cloud","description":"Staging Server"}],"security":[{"admin-bearer":["tenant.pass:pushUpdate"]},{"apiKey":[]}],"components":{"securitySchemes":{"admin-bearer":{"type":"oauth2","flows":{"implicit":{"authorizationUrl":"https://auth.neostore.cloud/authorize?audience=https://app.neostore.cloud/api/","scopes":{}}}},"apiKey":{"type":"apiKey","name":"X-API-KEY","in":"header"}},"schemas":{"ProblemDetails":{"type":"object","properties":{"type":{"type":["null","string"]},"title":{"type":["null","string"]},"status":{"type":["null","integer"],"format":"int32"},"detail":{"type":["null","string"]},"instance":{"type":["null","string"]}},"additionalProperties":{}},"HttpValidationProblemDetails":{"type":"object","allOf":[{"$ref":"#/components/schemas/ProblemDetails"}],"properties":{"errors":{"type":"object","additionalProperties":{"type":"array","items":{"type":"string"}}}},"additionalProperties":{}}}},"paths":{"/api/{tenantId}/passes/pushUpdate/{correlationId}/cancel":{"post":{"tags":["Pass"],"summary":"Cancel a bulk update","description":"Skips the operation's pass updates not yet run; applied ones stay applied and one running now may still complete.","parameters":[{"name":"correlationId","in":"path","description":"The operation's correlation id, as sent in `options.correlationId` or listed as `operationData`.","required":true,"schema":{"type":"string"}},{"name":"tenantId","in":"path","required":true,"schema":{"type":"string"}}],"responses":{"204":{"description":"The operation is marked cancelled."},"401":{"description":"The caller is not authenticated.","content":{"application/problem+json":{"schema":{"oneOf":[{"$ref":"#/components/schemas/ProblemDetails"},{"$ref":"#/components/schemas/HttpValidationProblemDetails"}]}}}},"403":{"description":"The caller lacks the <c>tenant.pass:pushUpdate</c> scope, or the endpoint is not enabled for the tenant.","content":{"application/problem+json":{"schema":{"oneOf":[{"$ref":"#/components/schemas/ProblemDetails"},{"$ref":"#/components/schemas/HttpValidationProblemDetails"}]}}}},"429":{"description":"Over 1200 requests per minute to this endpoint for the tenant (default limit); retry after <c>Retry-After</c>.","headers":{"Retry-After":{"description":"Seconds to wait before retrying. Sent when the limiter knows it.","schema":{"type":"integer"}}},"content":{"application/problem+json":{"schema":{"oneOf":[{"$ref":"#/components/schemas/ProblemDetails"},{"$ref":"#/components/schemas/HttpValidationProblemDetails"}]}}}}}}}}}
```

## List bulk update progress

> An operation is every pass update scheduled under one correlation id: bulk, queued single, or synchronous with a correlation id.

```json
{"openapi":"3.1.1","info":{"title":"Neostore internal API","version":"v1"},"tags":[{"name":"Pass"}],"servers":[{"url":"https://app.neostore.cloud","description":"Production Server"},{"url":"https://app-qa.neostore.cloud","description":"Staging Server"}],"security":[{"admin-bearer":["tenant.pass:read"]},{"apiKey":[]}],"components":{"securitySchemes":{"admin-bearer":{"type":"oauth2","flows":{"implicit":{"authorizationUrl":"https://auth.neostore.cloud/authorize?audience=https://app.neostore.cloud/api/","scopes":{}}}},"apiKey":{"type":"apiKey","name":"X-API-KEY","in":"header"}},"schemas":{"PushUpdateStatistics":{"type":"object","properties":{"id":{"type":"string","description":"Id of the progress record."},"operationName":{"type":"string","description":"Kind of operation that first scheduled updates under this correlation id."},"operationData":{"type":"string","description":"The correlation id: the value to pass to `POST /passes/pushUpdate/{correlationId}/cancel`."},"startDate":{"type":"string","description":"When the first update was scheduled.","format":"date-time"},"lastActivity":{"type":["null","string"],"description":"When a pass of the operation last progressed; `null` before any did.","format":"date-time"},"passCount":{"type":"integer","description":"Pass updates scheduled under the operation.","format":"int32"},"completed":{"type":"integer","description":"Pass updates that finished, successfully or not.","format":"int32"},"errors":{"type":"integer","description":"Pass updates that failed.","format":"int32"},"apple":{"type":"integer","description":"Pass updates pushed to Apple devices.","format":"int32"},"google":{"type":"integer","description":"Pass updates sent to Google Wallet.","format":"int32"},"isCanceled":{"type":"boolean","description":"The operation was cancelled: its pass updates not yet run are skipped."}},"additionalProperties":false,"description":"Progress of one update operation: every pass update queued or applied under the same correlation id."},"ProblemDetails":{"type":"object","properties":{"type":{"type":["null","string"]},"title":{"type":["null","string"]},"status":{"type":["null","integer"],"format":"int32"},"detail":{"type":["null","string"]},"instance":{"type":["null","string"]}},"additionalProperties":{}},"HttpValidationProblemDetails":{"type":"object","allOf":[{"$ref":"#/components/schemas/ProblemDetails"}],"properties":{"errors":{"type":"object","additionalProperties":{"type":"array","items":{"type":"string"}}}},"additionalProperties":{}}}},"paths":{"/api/{tenantId}/passes/pushUpdate/status":{"get":{"tags":["Pass"],"summary":"List bulk update progress","description":"An operation is every pass update scheduled under one correlation id: bulk, queued single, or synchronous with a correlation id.","parameters":[{"name":"tenantId","in":"path","required":true,"schema":{"type":"string"}}],"responses":{"200":{"description":"The operations.","content":{"text/plain":{"schema":{"type":"array","items":{"description":"Progress of one update operation: every pass update queued or applied under the same correlation id.","$ref":"#/components/schemas/PushUpdateStatistics"}}},"application/json":{"schema":{"type":"array","items":{"description":"Progress of one update operation: every pass update queued or applied under the same correlation id.","$ref":"#/components/schemas/PushUpdateStatistics"}}},"text/json":{"schema":{"type":"array","items":{"description":"Progress of one update operation: every pass update queued or applied under the same correlation id.","$ref":"#/components/schemas/PushUpdateStatistics"}}}}},"401":{"description":"The caller is not authenticated.","content":{"application/problem+json":{"schema":{"oneOf":[{"$ref":"#/components/schemas/ProblemDetails"},{"$ref":"#/components/schemas/HttpValidationProblemDetails"}]}}}},"403":{"description":"The caller lacks the <c>tenant.pass:read</c> scope, or the endpoint is not enabled for the tenant.","content":{"application/problem+json":{"schema":{"oneOf":[{"$ref":"#/components/schemas/ProblemDetails"},{"$ref":"#/components/schemas/HttpValidationProblemDetails"}]}}}},"429":{"description":"Over 1200 requests per minute to this endpoint for the tenant (default limit); retry after <c>Retry-After</c>.","headers":{"Retry-After":{"description":"Seconds to wait before retrying. Sent when the limiter knows it.","schema":{"type":"integer"}}},"content":{"application/problem+json":{"schema":{"oneOf":[{"$ref":"#/components/schemas/ProblemDetails"},{"$ref":"#/components/schemas/HttpValidationProblemDetails"}]}}}}}}}}}
```

## Count passes

> Issued passes and passes currently installed on Apple Wallet and Google Wallet. For trends and breakdowns use the Insights API.

```json
{"openapi":"3.1.1","info":{"title":"Neostore internal API","version":"v1"},"tags":[{"name":"Pass"}],"servers":[{"url":"https://app.neostore.cloud","description":"Production Server"},{"url":"https://app-qa.neostore.cloud","description":"Staging Server"}],"security":[{"admin-bearer":["tenant.pass:read"]},{"apiKey":[]}],"components":{"securitySchemes":{"admin-bearer":{"type":"oauth2","flows":{"implicit":{"authorizationUrl":"https://auth.neostore.cloud/authorize?audience=https://app.neostore.cloud/api/","scopes":{}}}},"apiKey":{"type":"apiKey","name":"X-API-KEY","in":"header"}},"schemas":{"PassStatistic":{"type":"object","properties":{"count":{"description":"Issued and installed pass counts.","$ref":"#/components/schemas/PassStatisticCount"}},"additionalProperties":false,"description":"Pass statistics for the tenant, or for one pass template."},"PassStatisticCount":{"type":"object","properties":{"total":{"type":"integer","description":"Passes issued, installed or not.","format":"int32"},"active":{"type":"integer","description":"Passes installed on at least one device, in either wallet.","format":"int32"},"apple":{"type":"integer","description":"Passes registered on at least one Apple device right now.","format":"int32"},"google":{"type":"integer","description":"Passes currently saved in Google Wallet.","format":"int32"}},"additionalProperties":false,"description":"Pass counts at the time of the request. A pass installed on both wallets counts once in\n`active` and once in each of `apple` and `google`."},"ProblemDetails":{"type":"object","properties":{"type":{"type":["null","string"]},"title":{"type":["null","string"]},"status":{"type":["null","integer"],"format":"int32"},"detail":{"type":["null","string"]},"instance":{"type":["null","string"]}},"additionalProperties":{}},"HttpValidationProblemDetails":{"type":"object","allOf":[{"$ref":"#/components/schemas/ProblemDetails"}],"properties":{"errors":{"type":"object","additionalProperties":{"type":"array","items":{"type":"string"}}}},"additionalProperties":{}}}},"paths":{"/api/{tenantId}/passes/stats":{"get":{"tags":["Pass"],"summary":"Count passes","description":"Issued passes and passes currently installed on Apple Wallet and Google Wallet. For trends and breakdowns use the Insights API.","parameters":[{"name":"passType","in":"query","description":"Restricts the counts to passes of this pass template. Matched exactly; a name with no pass yields zeros.","schema":{"type":"string"}},{"name":"tenantId","in":"path","required":true,"schema":{"type":"string"}}],"responses":{"200":{"description":"The counts.","content":{"text/plain":{"schema":{"description":"Pass statistics for the tenant, or for one pass template.","$ref":"#/components/schemas/PassStatistic"}},"application/json":{"schema":{"description":"Pass statistics for the tenant, or for one pass template.","$ref":"#/components/schemas/PassStatistic"}},"text/json":{"schema":{"description":"Pass statistics for the tenant, or for one pass template.","$ref":"#/components/schemas/PassStatistic"}}}},"401":{"description":"The caller is not authenticated.","content":{"application/problem+json":{"schema":{"oneOf":[{"$ref":"#/components/schemas/ProblemDetails"},{"$ref":"#/components/schemas/HttpValidationProblemDetails"}]}}}},"403":{"description":"The caller lacks the <c>tenant.pass:read</c> scope, or the endpoint is not enabled for the tenant.","content":{"application/problem+json":{"schema":{"oneOf":[{"$ref":"#/components/schemas/ProblemDetails"},{"$ref":"#/components/schemas/HttpValidationProblemDetails"}]}}}},"429":{"description":"Over 1200 requests per minute to this endpoint for the tenant (default limit); retry after <c>Retry-After</c>.","headers":{"Retry-After":{"description":"Seconds to wait before retrying. Sent when the limiter knows it.","schema":{"type":"integer"}}},"content":{"application/problem+json":{"schema":{"oneOf":[{"$ref":"#/components/schemas/ProblemDetails"},{"$ref":"#/components/schemas/HttpValidationProblemDetails"}]}}}}}}}}}
```


---

# Agent Instructions
This documentation is published with GitBook. GitBook is the documentation platform designed so that both humans and AI agents can read, navigate, and reason over technical content effectively. Learn more at gitbook.com.

## Querying This Documentation
If you need additional information that is not directly available in this page, you can query the documentation by asking a question.

Perform an HTTP GET request on the following URL with the `ask` and `goal` query parameters:

```
GET https://docs.thewalletcrew.io/api-reference/pass-management/pass.md?ask=<question>&goal=<user_goal>
```

`ask` is the immediate question: it should be specific, self-contained, and written in natural language.
`goal` is what the user is ultimately trying to achieve, the reason they need the answer. Sharing it helps GitBook give you a better, more relevant answer. A goal is most helpful when it describes the outcome the user wants rather than restating the question. For example, with `ask=how do I create an API token`, a goal like `automate deployments from our CI pipeline` lets GitBook tailor the answer to that use case.

The response will contain a direct answer to the question and relevant excerpts and sources from the documentation.

Use this mechanism when the answer is not explicitly present in the current page, you need clarification or additional context, or you want to retrieve related documentation sections.
