> For the complete documentation index, see [llms.txt](https://docs.pandium.com/llms.txt). Markdown versions of documentation pages are available by appending `.md` to page URLs; this page is available as [Markdown](https://docs.pandium.com/getting-started/pandium-integration-tutorial/pokemon-of-the-day-part-2/add-dynamic-configs.md).

# Add Dynamic Configs

Power dynamic configs for “Pokémon of the Day” by adding an initSync flow that saves Slack user and Pokémon type options to tenant metadata, populating tenant dropdowns automatically.

Your updated Connections Settings page has the new configs you need. Now we're going to write an init sync flow to populate options for each of those configs.

A Pandium integration can be run in normal mode or init mode. The initSync flow is for the init mode.

The goal in this initSync flow is to print a standard out with data that will be saved to the tenant's metadata and populate the options for our two [dynamic configurations:](/getting-started/anatomy-of-an-integration/pandium.yaml-spec/tenant-metadata.md#using-metadata-to-populate-dynamic-configs)

* The Slack user to receive the Pokémon of the day message.
* The type of Pokémon allowed for Pokémon of the day.

To do this we will need to:

* [ ] Fetch the users from Slack and the Pokémon types from PokéAPI.
* [ ] Reformat each Slack user to be in the form expected for a OneOf Option.
* [ ] Print a standard out that lists all the options for `pokemon_types` and `slack_users`.

1. Within src/processLogic add initSync.ts.

Now your file structure should now look like this:

```
  ├── build 
  ├── node_modules 
  ├── src
  │  ├── processLogic
  │  │  ├── initSync.ts
  │  │  └── pokemonSync.ts
  │  ├── index.ts
  │  ├──  lib.ts
  │  └── transformations.ts 
  ├── package.json
  ├── PANDIUM.yaml
  └── tsconfig.json
```

2. Within src/processLogic/initSync.ts get a logger for the file and add the shell of an asynchronous `initSync` function.

```typescript
import log4js from 'log4js'

const logger = log4js.getLogger('initSync')

export const initSync = async () => {
    logger.info('------------------------INIT SYNC------------------------')
}
```

3. Within src/index.ts import `initSync` and invoke it within the `main` function when the run mode is init.

The src/index.ts should look something like this:

```typescript
import * as dotenv from 'dotenv'
dotenv.config({ quiet: true })
import log4js from 'log4js'
import { WebClient } from '@slack/web-api'
import Pokedex from 'pokedex-promise-v2'
import { Pandium } from './lib.js'
import { pokemonSync } from './processLogic/pokemonSync.js'
import { initSync } from './processLogic/initSync.js'

const logger = log4js.getLogger('index')

const main = async () => {
    const pandium = Pandium.fromEnv()
    logger.info(`This run is in mode: ${pandium.runMode()}`)
    logger.info(`Tenant configs: ${JSON.stringify(pandium.config)}`)

    const pokeClient = new Pokedex()
    const slackClient = new WebClient(pandium.secrets.slack_oauth_access_token)

    if (pandium.runMode() === 'normal') {
        const metadata = await pokemonSync(pokeClient, slackClient, pandium)
        pandium.updateMetadata(metadata)
    } else {
        await initSync()
    }
}

main().then(
    () => {},
    () => {
        process.exitCode = 1
    }
)
```

The CLI runs your tenant in normal mode by default. To run in init mode, pass the `--mode` option.

4. Run `pandium local build && pandium local run <tenant-id> --mode init`.

You should see the following logged, which shows that `initSync` is running:

```
[2026-09-08 11:02:17:455] [index] INFO: This run is in mode: init
[2026-09-08 11:02:17:456] [index] INFO: Tenant configs: {}
[2026-09-08 11:02:17:456] [initSync] INFO: ------------------------INIT SYNC------------------------
```

5. Fetch the Slack users by doing the following:
   * [ ] In src/index.ts pass the `slackClient` to `initSync`.
   * [ ] In src/processLogic/initSync.ts add `slackClient` as an argument to `initSync`.
   * [ ] In src/processLogic/initSync.ts import the `WebClient` from the Slack library and use it to define the type of the `slackClient`.
   * [ ] In `initSync` use `slackClient.users.list` to fetch slack users.
   * [ ] Log out the results of that fetch.

The initSync.ts file should look something like this:

```typescript
import log4js from 'log4js'
import { WebClient } from '@slack/web-api'

const logger = log4js.getLogger('initSync')

export const initSync = async (slackClient: WebClient) => {
    logger.info('------------------------INIT SYNC------------------------')
    const response = await slackClient.users.list({})
    logger.info(response.members)
}
```

6. Run `pandium local build && pandium local run <tenant-id> --mode init`.

You should see the same information logged as before - except that now an array of Slack members from your workspace has also been printed. This confirms the Slack client within `initSync` is working.

You may recall from the work on the PANDIUM.yaml that the `slack_users` metadata should be a list of objects with only the properties `const` and `title`. This means the elements of the Slack members array will need to be transformed to the proper `const` and `title` format.

7. Create a Typescript interface for `OneOfOption`.
   * [ ] Add models.ts to the src folder.
   * [ ] Within src/models.ts define `OneOfOption`.
   * [ ] Import `OneOfOption` to src/processLogic/initSync.ts.

```typescript
export interface OneOfOption {
    const: string
    title: string
}
```

8. Print the slack user options to the standard out.
   * [ ] When looping through the members list reformat any active and non bot user to be a `OneOfOption`. Then add it to a list of `slackUsers`.
   * [ ] Make `initSync` return a metadata object that includes the `slack_users` list.
   * [ ] In src/index.ts pass the object returned by `initSync` to `pandium.updateMetadata`, just like the one returned by `pokemonSync`.

The initSync.ts should now look like this:

```typescript
import log4js from 'log4js'
import { WebClient } from '@slack/web-api'
import { OneOfOption } from '../models.js'

const logger = log4js.getLogger('initSync')

export const initSync = async (slackClient: WebClient) => {
    logger.info('------------------------INIT SYNC------------------------')

    const slackUsers: OneOfOption[] = []
    const response = await slackClient.users.list({})

    response.members?.forEach((user) => {
        if (
            user.deleted ||
            user.is_bot ||
            !user.is_email_confirmed ||
            !user.id ||
            !user.name
        )
            return

        slackUsers.push({
            const: user.id,
            title: user.name,
        })
    })

    return {
        slack_users: slackUsers,
    }
}
```

9. Run `pandium local build && pandium local run <tenant-id> --mode init`. The logs should look something like this:

```
[2026-09-08 11:10:42:031] [index] INFO: This run is in mode: init
[2026-09-08 11:10:42:032] [index] INFO: Tenant configs: {}
[2026-09-08 11:10:42:032] [initSync] INFO: ------------------------INIT SYNC------------------------
[2026-09-08 11:10:42:688] [lib] INFO: updating metadata with {"slack_users":[{"const":"UCEGPFQRX","title":"Jeff"},{"const":"UCEMD4QCX","title":"Juanita"},...]}
{"slack_users":[{"const":"UCEGPFQRX","title":"Jeff"},{"const":"UCEMD4QCX","title":"Juanita"},... other Slack users fetched from your Slack workspace.]}
```

During the work on the PANDIUM.yaml this is exactly what we'd said needed to be printed to the init sync standard out to populate options for the `slack_user` config.

Now do the same for the Pokémon types!

10. Fetch the Pokémon types by doing the following:
    * [ ] In src/index.ts pass the `pokeClient` to `initSync`.
    * [ ] In src/processLogic/initSync.ts add `pokeClient` as an argument to `initSync`.
    * [ ] Import the `Pokedex` to initSync.ts and use it to define the `pokeClient` type.
    * [ ] In `intSync` use `pokeClient.getTypesList` to fetch Pokémon types.
    * [ ] Log out the results of that fetch.

The initSync.ts file should look something like this:

```typescript
import log4js from 'log4js'
import { WebClient } from '@slack/web-api'
import Pokedex from 'pokedex-promise-v2'
import { OneOfOption } from '../models.js'

const logger = log4js.getLogger('initSync')

export const initSync = async (pokeClient: Pokedex, slackClient: WebClient) => {
    logger.info('------------------------INIT SYNC------------------------')

    const { results: types } = await pokeClient.getTypesList()
    logger.info(types)

    const slackUsers: OneOfOption[] = []
    const response = await slackClient.users.list({})

    response.members?.forEach((user) => {
        if (
            user.deleted ||
            user.is_bot ||
            !user.is_email_confirmed ||
            !user.id ||
            !user.name
        )
            return

        slackUsers.push({
            const: user.id,
            title: user.name,
        })
    })

    return {
        slack_users: slackUsers,
    }
}
```

11. Run `pandium local build && pandium local run <tenant-id> --mode init`. You should see the same information logged as before - except that there should now also be an array of Pokémon types. This confirms the `PokeClient` within `initSync` is working.
12. Loop through each of the Pokémon types list and add its name to a list of `pokemonTypes`. Then add the `pokemon_types` to the metadata object returned by `initSync`.
13. Run `pandium local build && pandium local run <tenant-id> --mode init`. The logs should look something like this:

    ```
    [2026-09-08 11:18:09:774] [index] INFO: This run is in mode: init
    [2026-09-08 11:18:09:775] [index] INFO: Tenant configs: {}
    [2026-09-08 11:18:09:775] [initSync] INFO: ------------------------INIT SYNC------------------------
    [2026-09-08 11:18:10:502] [lib] INFO: updating metadata with {"slack_users":[...],"pokemon_types":[...]}
    {"slack_users":[{"const":"UCEGPFQRX","title":"Jeff"},{"const":"UCEMD4QCX","title":"Juanita"},... other slack users fetched from your Slack workspace.],"pokemon_types":["normal","fighting","flying","poison","ground","rock","bug","ghost","steel","fire","water","grass","electric","psychic","ice","dragon","dark","fairy","stellar","unknown","shadow"]}
    ```

    The standard out of the `initSync` now lists options for both the `slack_user` and `pokemon_type` configs.

{% hint style="info" %}
Running an init sync locally doesn't update the tenant's metadata, so the options on the Integration Hub won't change until you run the init sync on Pandium.
{% endhint %}

The initSync.ts should now look like [this](https://github.com/pandium/sample_integrations/blob/master/POKEMON_OF_THE_DAY/src/processLogic/initSync.ts).

Let's take a look at how this standard out of this new init mode affects the options on the tenant setting page!


---

# 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.pandium.com/getting-started/pandium-integration-tutorial/pokemon-of-the-day-part-2/add-dynamic-configs.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.
