> 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/developers-guides/integration-guides/wallet/batch-operations.md).

# Batch operations

## Batch operations

The Wallet Crew supports two mechanisms for updating passes in bulk: the push update API and SFTP flat file imports.

#### Push update API

The operation below triggers a push update on all passes that match a filter condition. This is the primary batch mechanism for API-connected systems.

The endpoint accepts the same `filter` array as the passes list endpoint. See Filter and query operators for the full filter reference.

## Push update for passes matching the filter.

> \*\*Authorization:\*\* Requires \`Pass.Write\` scope.\
> \
> \*\*Filtering:\*\* Same as GetPasses�identifiers, metadata, pass type, installation status.\
> \
> \*\*Async:\*\* Updates are queued. 200 response means scheduled, not complete. Monitor via statistics endpoint.\
> \
> \*\*Data Merge:\*\* Merged into each matching pass. Set \`UpdateMetadata=true\` for recomputation (slower). Adjust \`Throughput\` for concurrency.\
> \
> \*\*Bulk Operations:\*\* Ideal for campaigns, loyalty updates, seasonal offers. Use \`CorrelationId\` for tracking.\
> \
> \*\*Use Cases:\*\* Campaign push; loyalty tier changes; offer refresh; bulk metadata updates.\
> \
> \*\*Example — push a seasonal offer to all loyalty passes:\*\*\
> \`\`\`\
> POST /api/{tenantId}/passes/pushUpdate\
> &#x20;   ?filter\[0].field=passType\&filter\[0].operator=equals\&filter\[0].value=loyalty\
> &#x20;           \
> {\
> &#x20; "additionalData": { "offer": "summer2025", "discount": "20%" },\
> &#x20; "options": {\
> &#x20;   "updateMetadata": true,\
> &#x20;   "throughput": 12,\
> &#x20;   "correlationId": "campaign-summer-2025"\
> &#x20; }\
> }\
> \`\`\`

````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":["ScopedAuthorizeRequirement"]},{"apiKey":["ScopedAuthorizeRequirement"]}],"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":"Field to filter by (identifiers.*, metadata.*, passType, installationStatus)."},"operator":{"description":"Comparison operator to apply.","$ref":"#/components/schemas/FilterModelOperator"},"value":{"type":["null","array"],"items":{"type":"string"},"description":"Filter values. Single-element for most operators; multiple elements for `in` and `notIn`.\nThe query parameter name is `value` (repeated for multiple values).\n<example>\nSingle value (equals, contains, startsWith, …):\n```\nGET /passes?filter[0].field=passType&filter[0].operator=equals&filter[0].value=boarding\n```\nMultiple values (in / notIn):\n```\nGET /passes?filter[0].field=passType&filter[0].operator=in&filter[0].value=boarding&filter[0].value=loyalty\n```\nMultiple filters combined:\n```\nGET /passes?filter[0].field=passType&filter[0].operator=equals&filter[0].value=boarding\n           &filter[1].field=identifiers.customerId&filter[1].operator=startsWith&filter[1].value=CUST-\n```</example>"}},"additionalProperties":false,"description":"Filter specification for pass queries."},"FilterModelOperator":{"enum":["Contains","StartsWith","EndsWith","Equals","IsEmpty","IsNotEmpty","NotEquals","In","NotIn"],"type":"string","description":"Filter operators for pass list queries."},"MultipleUpdatePassData":{"type":"object","allOf":[{"$ref":"#/components/schemas/MultipleUpdatePassDataOptionsUpdatePassData"}],"additionalProperties":false,"description":"Data payload for multi-pass (bulk) update operations."},"MultipleUpdatePassDataOptionsUpdatePassData":{"type":"object","properties":{"identifiers":{"type":"object","additionalProperties":{"type":"string"},"description":"External identifiers of the customer for this pass. Keys must not start with `id.`; common examples are `y2.customerId` or `shopify.customerId`.\nUse an empty value to remove an identifier. Leave the collection empty to keep existing identifiers unchanged."},"additionalData":{"type":["null","object"],"additionalProperties":{"type":"null"},"description":"Arbitrary data to persist with the pass (for example, loyalty tier, store code, or campaign flags)."},"passType":{"type":["null","string"],"description":"Optional pass type to convert the pass to."},"updateMetadata":{"type":"boolean","description":"Specifies if passes metadata should be updated. Updating metadata is time consuming and could be avoided for notification only push update","default":false,"deprecated":true},"options":{"description":"Options for multi-pass (bulk) update operations.","$ref":"#/components/schemas/MultipleUpdatePassDataOptions"}},"additionalProperties":false},"MultipleUpdatePassDataOptions":{"type":"object","allOf":[{"$ref":"#/components/schemas/UpdatePassDataOptions"}],"properties":{"throughput":{"type":"number","description":"Desired throughput (passes per second) when scheduling updates. Default is 12. Throughput is best-effort and can vary. Values below 1 slowly pace updates.","format":"float"}},"additionalProperties":false,"description":"Options for multi-pass (bulk) update operations."},"UpdatePassDataOptions":{"type":"object","properties":{"updateMetadata":{"type":"boolean","description":"When true, recompute and persist pass metadata. Updating metadata is slower and is usually unnecessary for notification-only updates."},"correlationId":{"type":["null","string"],"description":"Groups related updates under the same correlationId. Useful for batch updates (for example nightly jobs) to make retries and logs traceable."}},"additionalProperties":false,"description":"Options used when updating passes."},"PushUpdateResult":{"type":"object","properties":{"passCount":{"type":"integer","description":"Count of passes scheduled for update.","format":"int32"}},"additionalProperties":false,"description":"Result returned after scheduling a bulk push update operation."}}},"paths":{"/api/{tenantId}/passes/pushUpdate":{"post":{"tags":["Pass"],"summary":"Push update for passes matching the filter.","description":"**Authorization:** Requires `Pass.Write` scope.\n\n**Filtering:** Same as GetPasses�identifiers, metadata, pass type, installation status.\n\n**Async:** Updates are queued. 200 response means scheduled, not complete. Monitor via statistics endpoint.\n\n**Data Merge:** Merged into each matching pass. Set `UpdateMetadata=true` for recomputation (slower). Adjust `Throughput` for concurrency.\n\n**Bulk Operations:** Ideal for campaigns, loyalty updates, seasonal offers. Use `CorrelationId` for tracking.\n\n**Use Cases:** Campaign push; loyalty tier changes; offer refresh; bulk metadata updates.\n\n**Example — push a seasonal offer to all loyalty passes:**\n```\nPOST /api/{tenantId}/passes/pushUpdate\n    ?filter[0].field=passType&filter[0].operator=equals&filter[0].value=loyalty\n            \n{\n  \"additionalData\": { \"offer\": \"summer2025\", \"discount\": \"20%\" },\n  \"options\": {\n    \"updateMetadata\": true,\n    \"throughput\": 12,\n    \"correlationId\": \"campaign-summer-2025\"\n  }\n}\n```","parameters":[{"name":"filter","in":"query","description":"Optional filters applied to select passes.","schema":{"type":"array","items":{"description":"Filter specification for pass queries.","$ref":"#/components/schemas/FilterModel"}}},{"name":"tenantId","in":"path","required":true,"schema":{"type":"string"}}],"requestBody":{"description":"Data to merge into each pass and options controlling metadata refresh and throughput.","content":{"application/json":{"schema":{"description":"Data payload for multi-pass (bulk) update operations.","$ref":"#/components/schemas/MultipleUpdatePassData"}},"text/json":{"schema":{"description":"Data payload for multi-pass (bulk) update operations.","$ref":"#/components/schemas/MultipleUpdatePassData"}},"application/*+json":{"schema":{"description":"Data payload for multi-pass (bulk) update operations.","$ref":"#/components/schemas/MultipleUpdatePassData"}}}},"responses":{"200":{"description":"Passes scheduled for update; returns the count in the response body.","content":{"text/plain":{"schema":{"description":"Result returned after scheduling a bulk push update operation.","$ref":"#/components/schemas/PushUpdateResult"}},"application/json":{"schema":{"description":"Result returned after scheduling a bulk push update operation.","$ref":"#/components/schemas/PushUpdateResult"}},"text/json":{"schema":{"description":"Result returned after scheduling a bulk push update operation.","$ref":"#/components/schemas/PushUpdateResult"}}}}}}}}}
````

Each matching pass is queued for update independently. The platform resolves all matching pass IDs in-request, then enqueues them as a single command containing N individual per-pass tasks. The `200` response means the batch was accepted and scheduled — not that it has completed.

There is no hard limit on the number of passes a single call can match. `bypassQueue` is not available on this endpoint.

{% hint style="info" %}
You can supply a `correlationId` in the request body. The platform attaches it to each queued task, allowing you to track processing progress through the statistics endpoint. There is no completion webhook at the batch level.
{% endhint %}

**Partial failures**

Each pass is processed independently. A failure on one pass — for example, a connector error or a pass not found — does not affect the other passes in the batch. Failed passes are not retried automatically unless the underlying error is transient.

#### SFTP flat file imports

SFTP imports allow you to update additional data, identifiers, pass templates, and metadata across many passes by uploading a CSV file. This method is designed for legacy systems that cannot call the API directly.

{% hint style="warning" %}
SFTP imports are a last resort. Use the push update API for any system that supports HTTP calls. SFTP is an optional feature — contact The Wallet Crew to enable it on your tenant.
{% endhint %}

Each row in the CSV targets a single pass. Passes are updated asynchronously after the file is detected on the SFTP server. Like the push update API, operations are per-pass and independent.

For the full file format, column reference, SFTP credentials, and custom mapping scripts, see [Update pass using flat files](https://docs.thewalletcrew.io/configuration/wallet/import-and-export/update-pass-using-flat-files) in the Configuration space.

#### Choosing between the two approaches

|                   | Push update API                                     | SFTP flat file                                                           |
| ----------------- | --------------------------------------------------- | ------------------------------------------------------------------------ |
| Best for          | Real-time or scheduled integrations with API access | Legacy systems with flat file exports only                               |
| Targeting         | Filter conditions (any pass data field)             | Identifier per row (explicit list)                                       |
| Data updated      | Triggers connector re-fetch via push                | Updates `additionalData`, `identifiers`, `passType`, `metadata` directly |
| Setup             | No extra configuration required                     | Optional feature — must be enabled per tenant                            |
| Progress tracking | `correlationId` + statistics endpoint               | Fire-and-forget                                                          |

#### Tracking batch progress in the console

The admin console provides a real-time view of all batch operations. Open **Settings → Monitoring → Wallet updates**.

The page shows all push update operations with the following columns:

| Column        | Description                                     |
| ------------- | ----------------------------------------------- |
| Start         | When the batch was queued                       |
| Last activity | Most recent processing event                    |
| Operation     | Internal operation name                         |
| Correlation   | The `correlationId` supplied in the API request |
| Passes        | Total passes in the batch                       |
| Completed     | Passes successfully processed                   |
| Errors        | Passes that failed processing                   |
| Apple         | Apple Wallet deliveries                         |
| Google        | Google Wallet deliveries                        |
| Status        | Overall batch status, such as `Completed`       |

To correlate an API call with a row, supply a `correlationId` in the push-update operation. The value appears in the **Correlation** column, making the batch easy to find among concurrent operations.

{% hint style="info" %}
Running operations can be cancelled from this page. There is no completion webhook at the batch level. Use this view for operational monitoring.
{% endhint %}


---

# 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 dynamically by asking a question.

Perform an HTTP GET request on the current page URL with the `ask` query parameter, and the optional `goal` query parameter:

```
GET https://docs.thewalletcrew.io/developers-guides/integration-guides/wallet/batch-operations.md?ask=<question>&goal=<endgoal>
```

`ask` is the immediate question: it should be specific, self-contained, and written in natural language.
`goal` is optional and describes the broader end goal you are ultimately trying to accomplish on behalf of the user. GitBook uses it to tailor the answer towards what is most useful for that goal.

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.
