> 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/advanced/download-pages.md).

# Download Pages

## List wallet download pages for the tenant

> Returns every \`pass\` and \`passList\` layout of the tenant, ordered by name.\
> &#x20;           \
> Layout files that cannot be parsed are left out: their \`type\` is precisely what cannot be read,\
> so there is no way to tell whether they are download pages. Reading one by name still reports it.

```json
{"openapi":"3.1.1","info":{"title":"Neostore internal API","version":"v1"},"tags":[{"name":"DownloadPages"}],"servers":[{"url":"https://app.neostore.cloud","description":"Production Server"},{"url":"https://app-qa.neostore.cloud","description":"Staging Server"}],"security":[{"admin-bearer":["tenant.passType: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":{"DownloadPageListItem":{"required":["localeResourceCount","name","type"],"type":"object","properties":{"name":{"type":"string","description":"Name of the page, unique within the tenant, and the last segment of its public URL."},"type":{"description":"Kind of page.","$ref":"#/components/schemas/DownloadPageType"},"passCreationFlow":{"type":["null","string"],"description":"Flow executed when the page has to create the pass it shows. Null when the page does not create\npasses, and always null for a `passList` page."},"localeResourceCount":{"type":"integer","description":"Number of locale resource directories the page pulls its translations from.","format":"int32"}},"additionalProperties":false,"description":"Download page returned by the list endpoint."},"DownloadPageType":{"enum":["pass","passList"],"type":"string","description":"Kind of download page."}}},"paths":{"/api/{tenantId}/admin/wallet/downloadPages":{"get":{"tags":["DownloadPages"],"summary":"List wallet download pages for the tenant","description":"Returns every `pass` and `passList` layout of the tenant, ordered by name.\n            \nLayout files that cannot be parsed are left out: their `type` is precisely what cannot be read,\nso there is no way to tell whether they are download pages. Reading one by name still reports it.","parameters":[{"name":"tenantId","in":"path","required":true,"schema":{"type":"string"}}],"responses":{"200":{"description":"Download pages returned.","content":{"text/plain":{"schema":{"type":"array","items":{"description":"Download page returned by the list endpoint.","$ref":"#/components/schemas/DownloadPageListItem"}}},"application/json":{"schema":{"type":"array","items":{"description":"Download page returned by the list endpoint.","$ref":"#/components/schemas/DownloadPageListItem"}}},"text/json":{"schema":{"type":"array","items":{"description":"Download page returned by the list endpoint.","$ref":"#/components/schemas/DownloadPageListItem"}}}}}}}}}}
```

## Create a wallet download page

> Writes a new \`layouts/{name}.yml\`. The name must be one the tenant configuration validator\
> accepts, so a new page cannot be the reason validation starts failing.\
> &#x20;           \
> Unless \`localization.resources\` says otherwise, the page is given a locale resource directory of\
> its own, \`/locales/{name}/\`. That is the convention the delete endpoint relies on to know a\
> directory can be removed with the page.

```json
{"openapi":"3.1.1","info":{"title":"Neostore internal API","version":"v1"},"tags":[{"name":"DownloadPages"}],"servers":[{"url":"https://app.neostore.cloud","description":"Production Server"},{"url":"https://app-qa.neostore.cloud","description":"Staging Server"}],"security":[{"admin-bearer":["tenant.passType: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":{"CreateDownloadPageRequest":{"required":["name","type"],"type":"object","properties":{"name":{"minLength":1,"type":"string","description":"Name of the page. Must contain only letters, digits, hyphens or underscores, from 1 to 50\ncharacters, because it becomes a file name and a public URL segment."},"type":{"description":"Kind of page. Cannot be changed afterwards.","$ref":"#/components/schemas/DownloadPageType"},"headerImage":{"type":["null","string"],"description":"Image shown in the header, as a URL."},"requireValidRedirectId":{"type":["null","boolean"],"description":"Whether the page refuses traffic that does not come through a valid short link."},"autoDownloadPass":{"type":["null","boolean"],"description":"Whether the pass is downloaded without the customer acting. `pass` pages only."},"passCreationFlow":{"type":["null","string"],"description":"Flow executed when the page has to create the pass it shows. `pass` pages only. Omitted\nmeans the page does not create passes."},"allowDownloadAllPasses":{"type":["null","boolean"],"description":"Whether a download-everything button is offered. `passList` pages only."},"showInactivePasses":{"type":["null","boolean"],"description":"Whether inactive passes are listed, undownloadable. `passList` pages only."},"localization":{"description":"Localization wiring. Omitting `resources` gives the page a directory of its own, named after\nit — which is what makes its translations safe to delete with it.","$ref":"#/components/schemas/SaveDownloadPageLocalization"},"yaml":{"type":["null","string"],"description":"Complete layout file to store, verbatim. Mutually exclusive with the typed fields. Translations\ncan still be sent alongside it, because they live in different files."}},"additionalProperties":false,"description":"Request body to create a download page."},"DownloadPageType":{"enum":["pass","passList"],"type":"string","description":"Kind of download page."},"SaveDownloadPageLocalization":{"type":"object","properties":{"resources":{"type":["null","array"],"items":{"type":"string"},"description":"Locale resource directories. Omitted keeps the stored directories; provided replaces them, so an\nempty list clears them. Changing them does not move the files already stored."},"translations":{"type":["null","object"],"additionalProperties":{"description":"Translated strings of one culture.","$ref":"#/components/schemas/DownloadPageTranslations"},"description":"Translated strings to store, keyed by culture. Cultures left out are not touched. Omitted\nentirely writes no resource file at all."}},"additionalProperties":false,"description":"Localization wiring to write."},"DownloadPageTranslations":{"type":"object","properties":{"mobile":{"description":"Phone strings. `pass` pages only.","$ref":"#/components/schemas/PassMobileTranslations"},"desktop":{"description":"Desktop strings. `pass` pages only.","$ref":"#/components/schemas/PassDesktopTranslations"},"layout":{"description":"Headline strings. `passList` pages only.","$ref":"#/components/schemas/PassListLayoutTranslations"},"qrCode":{"description":"QR code strings. `passList` pages only.","$ref":"#/components/schemas/PassListQrCodeTranslations"}},"additionalProperties":false,"description":"Translated strings of one culture."},"PassMobileTranslations":{"type":"object","properties":{"title":{"type":["null","string"],"description":"Headline of the page."},"subTitle":{"type":["null","string"],"description":"Text under the headline. May be HTML, prefixed with `$html`."},"postInstalled":{"description":"Strings shown once the pass has been added to the wallet.","$ref":"#/components/schemas/PassPostInstalledTranslations"}},"additionalProperties":false,"description":"Strings shown on a `pass` page opened on a phone."},"PassPostInstalledTranslations":{"type":"object","properties":{"title":{"type":["null","string"],"description":"Headline of the confirmation."},"description":{"type":["null","string"],"description":"Text under the confirmation headline."},"viewMyCard":{"type":["null","string"],"description":"Label of the button opening the installed pass."}},"additionalProperties":false,"description":"Strings shown on a `pass` page once the pass has been installed."},"PassDesktopTranslations":{"type":"object","properties":{"qrCode":{"description":"Strings around the QR code the customer scans with their phone.","$ref":"#/components/schemas/PassDesktopQrCodeTranslations"},"needHelpButton":{"type":["null","string"],"description":"Label of the button opening the scanning help."},"needHelpDialog":{"description":"Strings of the scanning help dialog.","$ref":"#/components/schemas/PassNeedHelpDialogTranslations"}},"additionalProperties":false,"description":"Strings shown on a `pass` page opened on a desktop browser."},"PassDesktopQrCodeTranslations":{"type":"object","properties":{"caption":{"type":["null","string"],"description":"Instruction above the QR code."},"passDescription":{"type":["null","string"],"description":"Text describing what scanning the QR code does."},"baseline":{"type":["null","string"],"description":"Supporting text under the QR code."}},"additionalProperties":false,"description":"Strings around the QR code on a `pass` page opened on a desktop browser."},"PassNeedHelpDialogTranslations":{"type":"object","properties":{"title":{"type":["null","string"],"description":"Title of the dialog."},"closeButton":{"type":["null","string"],"description":"Label of the button closing the dialog."}},"additionalProperties":false,"description":"Strings of the scanning help dialog on a `pass` page."},"PassListLayoutTranslations":{"type":"object","properties":{"title":{"type":["null","string"],"description":"Headline used for two or more passes."},"title_one":{"type":["null","string"],"description":"Headline used for exactly one pass."},"title_zero":{"type":["null","string"],"description":"Headline used when the customer holds no pass."},"subTitle":{"type":["null","string"],"description":"Text under the headline."},"subTitle_zero":{"type":["null","string"],"description":"Text under the headline when the customer holds no pass."},"individual":{"type":["null","string"],"description":"Label of the individual-passes section, for two or more."},"individual_one":{"type":["null","string"],"description":"Label of the individual-passes section, for exactly one."},"all":{"type":["null","string"],"description":"Label of the all-passes action, for two or more."},"all_one":{"type":["null","string"],"description":"Label of the all-passes action, for exactly one."},"tickets":{"type":["null","string"],"description":"Pass counter. Carries a `{count}` placeholder."}},"additionalProperties":false,"description":"Headline strings of a `passList` page."},"PassListQrCodeTranslations":{"type":"object","properties":{"seeQRCode":{"type":["null","string"],"description":"Label of the action revealing the QR code."},"scanQRCode":{"type":["null","string"],"description":"Title shown with the QR code."},"QRCodeInstructions":{"type":["null","string"],"description":"Scanning instructions. May be HTML, prefixed with `$html`."},"copyQRLink":{"type":["null","string"],"description":"Label of the action copying the QR code link."},"linkCopied":{"type":["null","string"],"description":"Confirmation shown once the link has been copied."}},"additionalProperties":false,"description":"Strings around the QR code on a `passList` page."},"DownloadPageDefinition":{"required":["localization","name","requireValidRedirectId","type","yaml"],"type":"object","properties":{"name":{"type":"string","description":"Name of the page."},"type":{"description":"Kind of page. Fixed at creation.","$ref":"#/components/schemas/DownloadPageType"},"headerImage":{"type":["null","string"],"description":"Image shown in the header, as a URL. `/public/…` for an image stored in the tenant\nconfiguration. Null when the page shows none."},"requireValidRedirectId":{"type":"boolean","description":"Whether the page refuses traffic that does not come through a valid short link."},"autoDownloadPass":{"type":["null","boolean"],"description":"Whether the pass is downloaded without the customer acting. `pass` pages only."},"passCreation":{"description":"Pass creation wiring. Null when the page does not create passes.","$ref":"#/components/schemas/DownloadPagePassCreation"},"allowDownloadAllPasses":{"type":["null","boolean"],"description":"Whether a download-everything button is offered. `passList` pages only."},"showInactivePasses":{"type":["null","boolean"],"description":"Whether inactive passes are listed, undownloadable. `passList` pages only."},"localization":{"description":"Localization wiring and translated strings.","$ref":"#/components/schemas/DownloadPageLocalization"},"yaml":{"type":"string","description":"The stored layout file, verbatim."}},"additionalProperties":false,"description":"Full definition of a download page, returned by the get/create/save endpoints."},"DownloadPagePassCreation":{"required":["flow","flowExists","flowHasPassStep"],"type":"object","properties":{"flow":{"type":"string","description":"Flow executed to create the pass."},"flowExists":{"type":"boolean","description":"Whether the flow still exists as a registration flow. False means the page cannot create a pass\nany more — the flow was renamed or deleted."},"flowHasPassStep":{"type":"boolean","description":"Whether the flow carries a `pass` step. False means the flow runs but creates no pass, so\nthe page will not show one. Advisory: the configuration is valid either way."}},"additionalProperties":false,"description":"How a `pass` page creates the pass it shows, when it is missing."},"DownloadPageLocalization":{"type":"object","properties":{"resources":{"type":"array","items":{"type":"string"},"description":"Locale resource directories, e.g. `/locales/myPage/`. Order matters when the same key is\ndefined in more than one directory. Translations are read from, and written to, the first one."},"directory":{"type":["null","string"],"description":"Directory the translations below are stored in, as a configuration path. Null when the page\ndeclares no resource directory, in which case translations cannot be stored."},"translations":{"type":"object","additionalProperties":{"description":"Translated strings of one culture.","$ref":"#/components/schemas/DownloadPageTranslations"},"description":"Translated strings, keyed by culture. Cultures with no stored file are absent."}},"additionalProperties":false,"description":"Localization wiring and translated strings of a download page."},"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}/admin/wallet/downloadPages":{"post":{"tags":["DownloadPages"],"summary":"Create a wallet download page","description":"Writes a new `layouts/{name}.yml`. The name must be one the tenant configuration validator\naccepts, so a new page cannot be the reason validation starts failing.\n            \nUnless `localization.resources` says otherwise, the page is given a locale resource directory of\nits own, `/locales/{name}/`. That is the convention the delete endpoint relies on to know a\ndirectory can be removed with the page.","parameters":[{"name":"tenantId","in":"path","required":true,"schema":{"type":"string"}}],"requestBody":{"content":{"application/json":{"schema":{"description":"Request body to create a download page.","$ref":"#/components/schemas/CreateDownloadPageRequest"}},"text/json":{"schema":{"description":"Request body to create a download page.","$ref":"#/components/schemas/CreateDownloadPageRequest"}},"application/*+json":{"schema":{"description":"Request body to create a download page.","$ref":"#/components/schemas/CreateDownloadPageRequest"}}},"required":true},"responses":{"201":{"description":"Download page created.","content":{"text/plain":{"schema":{"description":"Full definition of a download page, returned by the get/create/save endpoints.","$ref":"#/components/schemas/DownloadPageDefinition"}},"application/json":{"schema":{"description":"Full definition of a download page, returned by the get/create/save endpoints.","$ref":"#/components/schemas/DownloadPageDefinition"}},"text/json":{"schema":{"description":"Full definition of a download page, returned by the get/create/save endpoints.","$ref":"#/components/schemas/DownloadPageDefinition"}}}},"400":{"description":"Name, flow, culture or the resulting configuration is invalid.","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":"A layout with this name already exists.","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"}]}}}}}}}}}
```

## Get a wallet download page

> Returns the modelled properties of the page, its translations for every culture that has a stored\
> resource file, and the stored layout file verbatim in \`yaml\`.

```json
{"openapi":"3.1.1","info":{"title":"Neostore internal API","version":"v1"},"tags":[{"name":"DownloadPages"}],"servers":[{"url":"https://app.neostore.cloud","description":"Production Server"},{"url":"https://app-qa.neostore.cloud","description":"Staging Server"}],"security":[{"admin-bearer":["tenant.passType: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":{"DownloadPageDefinition":{"required":["localization","name","requireValidRedirectId","type","yaml"],"type":"object","properties":{"name":{"type":"string","description":"Name of the page."},"type":{"description":"Kind of page. Fixed at creation.","$ref":"#/components/schemas/DownloadPageType"},"headerImage":{"type":["null","string"],"description":"Image shown in the header, as a URL. `/public/…` for an image stored in the tenant\nconfiguration. Null when the page shows none."},"requireValidRedirectId":{"type":"boolean","description":"Whether the page refuses traffic that does not come through a valid short link."},"autoDownloadPass":{"type":["null","boolean"],"description":"Whether the pass is downloaded without the customer acting. `pass` pages only."},"passCreation":{"description":"Pass creation wiring. Null when the page does not create passes.","$ref":"#/components/schemas/DownloadPagePassCreation"},"allowDownloadAllPasses":{"type":["null","boolean"],"description":"Whether a download-everything button is offered. `passList` pages only."},"showInactivePasses":{"type":["null","boolean"],"description":"Whether inactive passes are listed, undownloadable. `passList` pages only."},"localization":{"description":"Localization wiring and translated strings.","$ref":"#/components/schemas/DownloadPageLocalization"},"yaml":{"type":"string","description":"The stored layout file, verbatim."}},"additionalProperties":false,"description":"Full definition of a download page, returned by the get/create/save endpoints."},"DownloadPageType":{"enum":["pass","passList"],"type":"string","description":"Kind of download page."},"DownloadPagePassCreation":{"required":["flow","flowExists","flowHasPassStep"],"type":"object","properties":{"flow":{"type":"string","description":"Flow executed to create the pass."},"flowExists":{"type":"boolean","description":"Whether the flow still exists as a registration flow. False means the page cannot create a pass\nany more — the flow was renamed or deleted."},"flowHasPassStep":{"type":"boolean","description":"Whether the flow carries a `pass` step. False means the flow runs but creates no pass, so\nthe page will not show one. Advisory: the configuration is valid either way."}},"additionalProperties":false,"description":"How a `pass` page creates the pass it shows, when it is missing."},"DownloadPageLocalization":{"type":"object","properties":{"resources":{"type":"array","items":{"type":"string"},"description":"Locale resource directories, e.g. `/locales/myPage/`. Order matters when the same key is\ndefined in more than one directory. Translations are read from, and written to, the first one."},"directory":{"type":["null","string"],"description":"Directory the translations below are stored in, as a configuration path. Null when the page\ndeclares no resource directory, in which case translations cannot be stored."},"translations":{"type":"object","additionalProperties":{"description":"Translated strings of one culture.","$ref":"#/components/schemas/DownloadPageTranslations"},"description":"Translated strings, keyed by culture. Cultures with no stored file are absent."}},"additionalProperties":false,"description":"Localization wiring and translated strings of a download page."},"DownloadPageTranslations":{"type":"object","properties":{"mobile":{"description":"Phone strings. `pass` pages only.","$ref":"#/components/schemas/PassMobileTranslations"},"desktop":{"description":"Desktop strings. `pass` pages only.","$ref":"#/components/schemas/PassDesktopTranslations"},"layout":{"description":"Headline strings. `passList` pages only.","$ref":"#/components/schemas/PassListLayoutTranslations"},"qrCode":{"description":"QR code strings. `passList` pages only.","$ref":"#/components/schemas/PassListQrCodeTranslations"}},"additionalProperties":false,"description":"Translated strings of one culture."},"PassMobileTranslations":{"type":"object","properties":{"title":{"type":["null","string"],"description":"Headline of the page."},"subTitle":{"type":["null","string"],"description":"Text under the headline. May be HTML, prefixed with `$html`."},"postInstalled":{"description":"Strings shown once the pass has been added to the wallet.","$ref":"#/components/schemas/PassPostInstalledTranslations"}},"additionalProperties":false,"description":"Strings shown on a `pass` page opened on a phone."},"PassPostInstalledTranslations":{"type":"object","properties":{"title":{"type":["null","string"],"description":"Headline of the confirmation."},"description":{"type":["null","string"],"description":"Text under the confirmation headline."},"viewMyCard":{"type":["null","string"],"description":"Label of the button opening the installed pass."}},"additionalProperties":false,"description":"Strings shown on a `pass` page once the pass has been installed."},"PassDesktopTranslations":{"type":"object","properties":{"qrCode":{"description":"Strings around the QR code the customer scans with their phone.","$ref":"#/components/schemas/PassDesktopQrCodeTranslations"},"needHelpButton":{"type":["null","string"],"description":"Label of the button opening the scanning help."},"needHelpDialog":{"description":"Strings of the scanning help dialog.","$ref":"#/components/schemas/PassNeedHelpDialogTranslations"}},"additionalProperties":false,"description":"Strings shown on a `pass` page opened on a desktop browser."},"PassDesktopQrCodeTranslations":{"type":"object","properties":{"caption":{"type":["null","string"],"description":"Instruction above the QR code."},"passDescription":{"type":["null","string"],"description":"Text describing what scanning the QR code does."},"baseline":{"type":["null","string"],"description":"Supporting text under the QR code."}},"additionalProperties":false,"description":"Strings around the QR code on a `pass` page opened on a desktop browser."},"PassNeedHelpDialogTranslations":{"type":"object","properties":{"title":{"type":["null","string"],"description":"Title of the dialog."},"closeButton":{"type":["null","string"],"description":"Label of the button closing the dialog."}},"additionalProperties":false,"description":"Strings of the scanning help dialog on a `pass` page."},"PassListLayoutTranslations":{"type":"object","properties":{"title":{"type":["null","string"],"description":"Headline used for two or more passes."},"title_one":{"type":["null","string"],"description":"Headline used for exactly one pass."},"title_zero":{"type":["null","string"],"description":"Headline used when the customer holds no pass."},"subTitle":{"type":["null","string"],"description":"Text under the headline."},"subTitle_zero":{"type":["null","string"],"description":"Text under the headline when the customer holds no pass."},"individual":{"type":["null","string"],"description":"Label of the individual-passes section, for two or more."},"individual_one":{"type":["null","string"],"description":"Label of the individual-passes section, for exactly one."},"all":{"type":["null","string"],"description":"Label of the all-passes action, for two or more."},"all_one":{"type":["null","string"],"description":"Label of the all-passes action, for exactly one."},"tickets":{"type":["null","string"],"description":"Pass counter. Carries a `{count}` placeholder."}},"additionalProperties":false,"description":"Headline strings of a `passList` page."},"PassListQrCodeTranslations":{"type":"object","properties":{"seeQRCode":{"type":["null","string"],"description":"Label of the action revealing the QR code."},"scanQRCode":{"type":["null","string"],"description":"Title shown with the QR code."},"QRCodeInstructions":{"type":["null","string"],"description":"Scanning instructions. May be HTML, prefixed with `$html`."},"copyQRLink":{"type":["null","string"],"description":"Label of the action copying the QR code link."},"linkCopied":{"type":["null","string"],"description":"Confirmation shown once the link has been copied."}},"additionalProperties":false,"description":"Strings around the QR code on a `passList` page."},"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}/admin/wallet/downloadPages/{name}":{"get":{"tags":["DownloadPages"],"summary":"Get a wallet download page","description":"Returns the modelled properties of the page, its translations for every culture that has a stored\nresource file, and the stored layout file verbatim in `yaml`.","parameters":[{"name":"name","in":"path","required":true,"schema":{"type":"string"}},{"name":"tenantId","in":"path","required":true,"schema":{"type":"string"}}],"responses":{"200":{"description":"Download page returned.","content":{"text/plain":{"schema":{"description":"Full definition of a download page, returned by the get/create/save endpoints.","$ref":"#/components/schemas/DownloadPageDefinition"}},"application/json":{"schema":{"description":"Full definition of a download page, returned by the get/create/save endpoints.","$ref":"#/components/schemas/DownloadPageDefinition"}},"text/json":{"schema":{"description":"Full definition of a download page, returned by the get/create/save endpoints.","$ref":"#/components/schemas/DownloadPageDefinition"}}}},"400":{"description":"Name is invalid.","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"}]}}}},"404":{"description":"Download page not found.","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":"The stored file cannot be parsed.","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"}]}}}}}}}}}
```

## Save a wallet download page

> Replaces the page identified by name. The name in the route is authoritative, and\
> neither the name nor the kind of page can be changed.\
> &#x20;           \
> A page whose stored YAML no longer parses can only be saved through \`yaml\`, which replaces the\
> whole file — the typed path has nothing it can safely merge into.

```json
{"openapi":"3.1.1","info":{"title":"Neostore internal API","version":"v1"},"tags":[{"name":"DownloadPages"}],"servers":[{"url":"https://app.neostore.cloud","description":"Production Server"},{"url":"https://app-qa.neostore.cloud","description":"Staging Server"}],"security":[{"admin-bearer":["tenant.passType: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":{"SaveDownloadPageRequest":{"type":"object","properties":{"headerImage":{"type":["null","string"],"description":"Image shown in the header, as a URL. Omitted keeps the stored image; an empty string removes it."},"requireValidRedirectId":{"type":["null","boolean"],"description":"Whether the page refuses traffic that does not come through a valid short link."},"autoDownloadPass":{"type":["null","boolean"],"description":"Whether the pass is downloaded without the customer acting. `pass` pages only."},"passCreationFlow":{"type":["null","string"],"description":"Flow executed when the page has to create the pass it shows. `pass` pages only. Omitted\nkeeps the stored flow; an empty string stops the page creating passes."},"allowDownloadAllPasses":{"type":["null","boolean"],"description":"Whether a download-everything button is offered. `passList` pages only."},"showInactivePasses":{"type":["null","boolean"],"description":"Whether inactive passes are listed, undownloadable. `passList` pages only."},"localization":{"description":"Localization wiring and translations to store.","$ref":"#/components/schemas/SaveDownloadPageLocalization"},"yaml":{"type":["null","string"],"description":"Complete layout file to store, verbatim. Mutually exclusive with the typed fields, and must keep\nthe kind of page unchanged. Translations can still be sent alongside it."}},"additionalProperties":false,"description":"Request body to save an existing download page."},"SaveDownloadPageLocalization":{"type":"object","properties":{"resources":{"type":["null","array"],"items":{"type":"string"},"description":"Locale resource directories. Omitted keeps the stored directories; provided replaces them, so an\nempty list clears them. Changing them does not move the files already stored."},"translations":{"type":["null","object"],"additionalProperties":{"description":"Translated strings of one culture.","$ref":"#/components/schemas/DownloadPageTranslations"},"description":"Translated strings to store, keyed by culture. Cultures left out are not touched. Omitted\nentirely writes no resource file at all."}},"additionalProperties":false,"description":"Localization wiring to write."},"DownloadPageTranslations":{"type":"object","properties":{"mobile":{"description":"Phone strings. `pass` pages only.","$ref":"#/components/schemas/PassMobileTranslations"},"desktop":{"description":"Desktop strings. `pass` pages only.","$ref":"#/components/schemas/PassDesktopTranslations"},"layout":{"description":"Headline strings. `passList` pages only.","$ref":"#/components/schemas/PassListLayoutTranslations"},"qrCode":{"description":"QR code strings. `passList` pages only.","$ref":"#/components/schemas/PassListQrCodeTranslations"}},"additionalProperties":false,"description":"Translated strings of one culture."},"PassMobileTranslations":{"type":"object","properties":{"title":{"type":["null","string"],"description":"Headline of the page."},"subTitle":{"type":["null","string"],"description":"Text under the headline. May be HTML, prefixed with `$html`."},"postInstalled":{"description":"Strings shown once the pass has been added to the wallet.","$ref":"#/components/schemas/PassPostInstalledTranslations"}},"additionalProperties":false,"description":"Strings shown on a `pass` page opened on a phone."},"PassPostInstalledTranslations":{"type":"object","properties":{"title":{"type":["null","string"],"description":"Headline of the confirmation."},"description":{"type":["null","string"],"description":"Text under the confirmation headline."},"viewMyCard":{"type":["null","string"],"description":"Label of the button opening the installed pass."}},"additionalProperties":false,"description":"Strings shown on a `pass` page once the pass has been installed."},"PassDesktopTranslations":{"type":"object","properties":{"qrCode":{"description":"Strings around the QR code the customer scans with their phone.","$ref":"#/components/schemas/PassDesktopQrCodeTranslations"},"needHelpButton":{"type":["null","string"],"description":"Label of the button opening the scanning help."},"needHelpDialog":{"description":"Strings of the scanning help dialog.","$ref":"#/components/schemas/PassNeedHelpDialogTranslations"}},"additionalProperties":false,"description":"Strings shown on a `pass` page opened on a desktop browser."},"PassDesktopQrCodeTranslations":{"type":"object","properties":{"caption":{"type":["null","string"],"description":"Instruction above the QR code."},"passDescription":{"type":["null","string"],"description":"Text describing what scanning the QR code does."},"baseline":{"type":["null","string"],"description":"Supporting text under the QR code."}},"additionalProperties":false,"description":"Strings around the QR code on a `pass` page opened on a desktop browser."},"PassNeedHelpDialogTranslations":{"type":"object","properties":{"title":{"type":["null","string"],"description":"Title of the dialog."},"closeButton":{"type":["null","string"],"description":"Label of the button closing the dialog."}},"additionalProperties":false,"description":"Strings of the scanning help dialog on a `pass` page."},"PassListLayoutTranslations":{"type":"object","properties":{"title":{"type":["null","string"],"description":"Headline used for two or more passes."},"title_one":{"type":["null","string"],"description":"Headline used for exactly one pass."},"title_zero":{"type":["null","string"],"description":"Headline used when the customer holds no pass."},"subTitle":{"type":["null","string"],"description":"Text under the headline."},"subTitle_zero":{"type":["null","string"],"description":"Text under the headline when the customer holds no pass."},"individual":{"type":["null","string"],"description":"Label of the individual-passes section, for two or more."},"individual_one":{"type":["null","string"],"description":"Label of the individual-passes section, for exactly one."},"all":{"type":["null","string"],"description":"Label of the all-passes action, for two or more."},"all_one":{"type":["null","string"],"description":"Label of the all-passes action, for exactly one."},"tickets":{"type":["null","string"],"description":"Pass counter. Carries a `{count}` placeholder."}},"additionalProperties":false,"description":"Headline strings of a `passList` page."},"PassListQrCodeTranslations":{"type":"object","properties":{"seeQRCode":{"type":["null","string"],"description":"Label of the action revealing the QR code."},"scanQRCode":{"type":["null","string"],"description":"Title shown with the QR code."},"QRCodeInstructions":{"type":["null","string"],"description":"Scanning instructions. May be HTML, prefixed with `$html`."},"copyQRLink":{"type":["null","string"],"description":"Label of the action copying the QR code link."},"linkCopied":{"type":["null","string"],"description":"Confirmation shown once the link has been copied."}},"additionalProperties":false,"description":"Strings around the QR code on a `passList` page."},"DownloadPageDefinition":{"required":["localization","name","requireValidRedirectId","type","yaml"],"type":"object","properties":{"name":{"type":"string","description":"Name of the page."},"type":{"description":"Kind of page. Fixed at creation.","$ref":"#/components/schemas/DownloadPageType"},"headerImage":{"type":["null","string"],"description":"Image shown in the header, as a URL. `/public/…` for an image stored in the tenant\nconfiguration. Null when the page shows none."},"requireValidRedirectId":{"type":"boolean","description":"Whether the page refuses traffic that does not come through a valid short link."},"autoDownloadPass":{"type":["null","boolean"],"description":"Whether the pass is downloaded without the customer acting. `pass` pages only."},"passCreation":{"description":"Pass creation wiring. Null when the page does not create passes.","$ref":"#/components/schemas/DownloadPagePassCreation"},"allowDownloadAllPasses":{"type":["null","boolean"],"description":"Whether a download-everything button is offered. `passList` pages only."},"showInactivePasses":{"type":["null","boolean"],"description":"Whether inactive passes are listed, undownloadable. `passList` pages only."},"localization":{"description":"Localization wiring and translated strings.","$ref":"#/components/schemas/DownloadPageLocalization"},"yaml":{"type":"string","description":"The stored layout file, verbatim."}},"additionalProperties":false,"description":"Full definition of a download page, returned by the get/create/save endpoints."},"DownloadPageType":{"enum":["pass","passList"],"type":"string","description":"Kind of download page."},"DownloadPagePassCreation":{"required":["flow","flowExists","flowHasPassStep"],"type":"object","properties":{"flow":{"type":"string","description":"Flow executed to create the pass."},"flowExists":{"type":"boolean","description":"Whether the flow still exists as a registration flow. False means the page cannot create a pass\nany more — the flow was renamed or deleted."},"flowHasPassStep":{"type":"boolean","description":"Whether the flow carries a `pass` step. False means the flow runs but creates no pass, so\nthe page will not show one. Advisory: the configuration is valid either way."}},"additionalProperties":false,"description":"How a `pass` page creates the pass it shows, when it is missing."},"DownloadPageLocalization":{"type":"object","properties":{"resources":{"type":"array","items":{"type":"string"},"description":"Locale resource directories, e.g. `/locales/myPage/`. Order matters when the same key is\ndefined in more than one directory. Translations are read from, and written to, the first one."},"directory":{"type":["null","string"],"description":"Directory the translations below are stored in, as a configuration path. Null when the page\ndeclares no resource directory, in which case translations cannot be stored."},"translations":{"type":"object","additionalProperties":{"description":"Translated strings of one culture.","$ref":"#/components/schemas/DownloadPageTranslations"},"description":"Translated strings, keyed by culture. Cultures with no stored file are absent."}},"additionalProperties":false,"description":"Localization wiring and translated strings of a download page."},"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}/admin/wallet/downloadPages/{name}":{"put":{"tags":["DownloadPages"],"summary":"Save a wallet download page","description":"Replaces the page identified by name. The name in the route is authoritative, and\nneither the name nor the kind of page can be changed.\n            \nA page whose stored YAML no longer parses can only be saved through `yaml`, which replaces the\nwhole file — the typed path has nothing it can safely merge into.","parameters":[{"name":"name","in":"path","required":true,"schema":{"type":"string"}},{"name":"tenantId","in":"path","required":true,"schema":{"type":"string"}}],"requestBody":{"content":{"application/json":{"schema":{"description":"Request body to save an existing download page.","$ref":"#/components/schemas/SaveDownloadPageRequest"}},"text/json":{"schema":{"description":"Request body to save an existing download page.","$ref":"#/components/schemas/SaveDownloadPageRequest"}},"application/*+json":{"schema":{"description":"Request body to save an existing download page.","$ref":"#/components/schemas/SaveDownloadPageRequest"}}},"required":true},"responses":{"200":{"description":"Download page saved.","content":{"text/plain":{"schema":{"description":"Full definition of a download page, returned by the get/create/save endpoints.","$ref":"#/components/schemas/DownloadPageDefinition"}},"application/json":{"schema":{"description":"Full definition of a download page, returned by the get/create/save endpoints.","$ref":"#/components/schemas/DownloadPageDefinition"}},"text/json":{"schema":{"description":"Full definition of a download page, returned by the get/create/save endpoints.","$ref":"#/components/schemas/DownloadPageDefinition"}}}},"400":{"description":"Flow, culture or the resulting configuration is invalid.","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"}]}}}},"404":{"description":"Download page not found.","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":"The stored file cannot be parsed and the request does not replace it entirely.","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"}]}}}}}}}}}
```

## Delete a wallet download page

> Removes \`layouts/{name}.yml\`, and the page's own locale resource directory when it provably\
> belongs to the page alone.\
> &#x20;           \
> \## This breaks passes that are already in customers' wallets\
> &#x20;           \
> A download page is served publicly at \`/{tenantId}/{name}\`. That URL is printed on QR codes,\
> embedded in campaigns and handed to partners, and short links created by the redirect engine resolve\
> to it by name at request time — from the redirect store, not from the configuration. None of that can\
> be enumerated here.\
> &#x20;           \
> What \*can\* be checked is refused with a conflict rather than silently broken:\
> &#x20;           \
> \- Pass templates that land on the page. A template names its page through \`passLayoutName\`, and a\
> &#x20; template that names none lands on \`pass\` — so deleting the page called \`pass\` breaks every\
> &#x20; template that never set the property. Nothing in tenant validation catches this, which is why it is\
> &#x20; checked here.\
> \- Layouts that use the page as their \`errorLayoutName\`, or send customers to it once registration\
> &#x20; completes.\
> &#x20;           \
> \## The locale resource directory\
> &#x20;           \
> It is removed only when it is named after the page — the directory creating a page gives it — and no\
> other layout and no pass template pulls translations from it. Otherwise it is left in place, because\
> removing it would take another page's translations with it.

```json
{"openapi":"3.1.1","info":{"title":"Neostore internal API","version":"v1"},"tags":[{"name":"DownloadPages"}],"servers":[{"url":"https://app.neostore.cloud","description":"Production Server"},{"url":"https://app-qa.neostore.cloud","description":"Staging Server"}],"security":[{"admin-bearer":["tenant.passType: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":{"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}/admin/wallet/downloadPages/{name}":{"delete":{"tags":["DownloadPages"],"summary":"Delete a wallet download page","description":"Removes `layouts/{name}.yml`, and the page's own locale resource directory when it provably\nbelongs to the page alone.\n            \n## This breaks passes that are already in customers' wallets\n            \nA download page is served publicly at `/{tenantId}/{name}`. That URL is printed on QR codes,\nembedded in campaigns and handed to partners, and short links created by the redirect engine resolve\nto it by name at request time — from the redirect store, not from the configuration. None of that can\nbe enumerated here.\n            \nWhat *can* be checked is refused with a conflict rather than silently broken:\n            \n- Pass templates that land on the page. A template names its page through `passLayoutName`, and a\n  template that names none lands on `pass` — so deleting the page called `pass` breaks every\n  template that never set the property. Nothing in tenant validation catches this, which is why it is\n  checked here.\n- Layouts that use the page as their `errorLayoutName`, or send customers to it once registration\n  completes.\n            \n## The locale resource directory\n            \nIt is removed only when it is named after the page — the directory creating a page gives it — and no\nother layout and no pass template pulls translations from it. Otherwise it is left in place, because\nremoving it would take another page's translations with it.","parameters":[{"name":"name","in":"path","required":true,"schema":{"type":"string"}},{"name":"tenantId","in":"path","required":true,"schema":{"type":"string"}}],"responses":{"204":{"description":"Download page deleted. Its public URL now returns 404."},"400":{"description":"Name is invalid.","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"}]}}}},"404":{"description":"Download page not found.","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":"Something still points at the page, or a file that would say so cannot be parsed.","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"}]}}}}}}}}}
```


---

# 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/api-reference/advanced/download-pages.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.
