# Building dashboard delivery in Embeddable

**URL:** <https://community.embeddable.com/t/building-dashboard-delivery-in-embeddable/121>\
**Category:** FAQs\
**Created:** [May 26, 2025, 8:43am UTC](https://community.embeddable.com/t/building-dashboard-delivery-in-embeddable/121 "2025-05-26T08:43:43Z")\
**Posts on this page:** 1\
**Page:** 1

<div class="post-metadata">

**Author:** ![ella-embeddable](https://dub1.discourse-cdn.com/flex013/user_avatar/community.embeddable.com/ella-embeddable/32/15_2.png) [@ella-embeddable](https://community.embeddable.com/u/ella-embeddable)\
**Post date:** [May 26, 2025, 8:43am UTC](https://community.embeddable.com/t/building-dashboard-delivery-in-embeddable/121/1 "2025-05-26T08:43:43Z")

</div>

Example implementation of dashboard delivery:

1. We built a UI page thats called reports - this allows users to select an “Embeddable” to display. On that page we built a Nav with a button called “Export”. Clicking this button will open a dialog that supports the ability to add in some emails / cadence time that is recored in our DB. e.g [john@gmail.com](mailto:john@gmail.com)/Twice a week/3pm.

2. We wrote a client in the backend that will query Embeddable API’s using `/web-component/v1/query` and builds up a payload - see below a short `api-documentation` that shows how we achieved this for one component - but the logic is repeatable for what ever components you want to choose. To query the api you can just follow the [documentation](https://docs.embeddable.com/deployment/tokens-api) to get your security token and then build your CSV from the attached .md

3. We then pop that payload into a Pub/Sub - Scheduler - Cron job ( How ever you want to achieve it ) and then hit what ever SMTP service provider you want to use to send the email

# Web Component Query API Documentation

## Step 1: Retrieve Widget Information

### API Endpoint

- URL: `https://app-api.eu.embeddable.com/web-component/v1/embeddable`
- Method: GET

### curl Command

```bash
curl 'https://app-api.eu.embeddable.com/web-component/v1/embeddable' \
  -H 'accept: */*' \
  -H 'accept-language: en-GB,en-US;q=0.9,en;q=0.8' \
  -H 'authorization: Bearer [YOUR_ACCESS_TOKEN]' \
  -H 'origin: [YOUR_ORIGIN]' \
  -H 'referer: [YOUR_REFERER]' \
  -H 'sec-ch-ua: "Not;A=Brand";v="24", "Chromium";v="128"' \
  -H 'sec-ch-ua-mobile: ?0' \
  -H 'sec-ch-ua-platform: "macOS"' \
  -H 'sec-fetch-dest: empty' \
  -H 'sec-fetch-mode: cors' \
  -H 'sec-fetch-site: cross-site' \
  -H 'user-agent: Mozilla/5.0 (Macintosh; Intel Mac OS X 10_15_7) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/128.0.0.0 Safari/537.36'

```

### Response Structure

```json
{
  "embeddable": {
    "widgets": [
      {
        "id": "component_id",
        "inputConfiguration": {
          // ... other properties ...
        }
      }
    ]
  }
}

```

## Step 2: Extract Required Data

From the response, extract the following information for each widget:

1. `componentId`: `widgets[i].id`
2. `limit`: `widgets[i].inputConfiguration.limit.value`
3. `datasetId`: `widgets[i].inputConfiguration.ds.value.datasetId`
4. `inputName`: `widgets[i].inputConfiguration.columns.inputMeta.config.dataset`
5. `dimensions`: Extract all `name` properties from `widgets[i].inputConfiguration.columns.value`
6. `order`:
  - Start with `widgets[i].inputConfiguration.defaultSort.value.name` as the first item
  - Add remaining dimensions in the order they appear in `widgets[i].inputConfiguration.columns.value`

Example Python code to extract dimensions:

```python
dimensions = [item['name'] for item in widget['inputConfiguration']['columns']['value']]

```

### Explanation of the `order` parameter

The `order` parameter is an array of arrays, where each inner array contains two elements:

1. The dimension name
2. The sort direction (“desc” for descending or “asc” for ascending)

The first item in the `order` array should always be the default sort dimension, which is specified by `inputConfiguration.defaultSort.value.name`. The remaining items should be the other dimensions in the order they appear in `inputConfiguration.columns.value`.

For example, if `balances.account_id` is the default sort, the `order` array would look like this:

```json
[
  ["balances.account_id", "desc"],
  ["balances.account_number", "desc"],
  ["balances.country", "desc"],
  ["balances.account_code", "desc"],
  ["balances.amount", "desc"],
  ["balances.currency", "desc"],
  ["balances.balance_date", "desc"]
]

```

Example to construct this `order` array programmatically:

1. Start with the default sort dimension:

2. Add the remaining dimensions:

## Step 3: Construct Query Payload

Using the extracted data, construct a payload for the query API:

```json
{
  "inputName": "<extracted_input_name>",
  "datasetId": "<extracted_dataset_id>",
  "dimensions": ["<dimension1>", "<dimension2>", ...],
  "order": [
    ["<default_sort_dimension>", "desc"],
    ["<dimension1>", "desc"],
    ["<dimension2>", "desc"],
    ...
  ],
  "offset": 0,
  "limit": <extracted_limit>,
  "componentId": "<extracted_component_id>",
  "timezone": "Europe/Amsterdam"
}

```

## Step 4: Query Data

### API Endpoint

- URL: `https://app-api.eu.embeddable.com/web-component/v1/query`
- Method: POST

### curl Command

```bash
curl 'https://app-api.eu.embeddable.com/web-component/v1/query?' \
  -H 'accept: */*' \
  -H 'accept-language: en-GB,en-US;q=0.9,en;q=0.8' \
  -H 'authorization: Bearer [YOUR_ACCESS_TOKEN]' \
  -H 'content-type: application/json' \
  -H 'origin: [YOUR_ORIGIN]' \
  -H 'referer: [YOUR_REFERER]' \
  -H 'sec-ch-ua: "Not;A=Brand";v="24", "Chromium";v="128"' \
  -H 'sec-ch-ua-mobile: ?0' \
  -H 'sec-ch-ua-platform: "macOS"' \
  -H 'sec-fetch-dest: empty' \
  -H 'sec-fetch-mode: cors' \
  -H 'sec-fetch-site: cross-site' \
  -H 'user-agent: Mozilla/5.0 (Macintosh; Intel Mac OS X 10_15_7) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/128.0.0.0 Safari/537.36' \
  --data-raw '{
    "inputName": "ds",
    "datasetId": "[DATASET_ID]",
    "dimensions": [
        "balances.account_number",
        "balances.country",
        "balances.account_code",
        "balances.account_id",
        "balances.amount",
        "balances.currency",
        "balances.balance_date"
    ],
    "order": [
        ["balances.account_id", "desc"],
        ["balances.account_number", "desc"],
        ["balances.country", "desc"],
        ["balances.account_code", "desc"],
        ["balances.amount", "desc"],
        ["balances.currency", "desc"],
        ["balances.balance_date", "desc"]
    ],
    "offset": 0,
    "limit": 1000,
    "componentId": "[COMPONENT_ID]",
    "timezone": "Europe/Amsterdam"
  }'

```

### Example Payload

```json
{
  "inputName": "ds",
  "datasetId": "[DATASET_ID]",
  "dimensions": [
    "balances.account_number",
    "balances.country",
    "balances.account_code",
    "balances.account_id",
    "balances.amount",
    "balances.currency",
    "balances.balance_date"
  ],
  "order": [
    ["balances.account_id", "desc"],
    ["balances.account_number", "desc"],
    ["balances.country", "desc"],
    ["balances.account_code", "desc"],
    ["balances.amount", "desc"],
    ["balances.currency", "desc"],
    ["balances.balance_date", "desc"]
  ],
  "offset": 0,
  "limit": 1000,
  "componentId": "[COMPONENT_ID]",
  "timezone": "Europe/Amsterdam"
}

```

### Explanation of the Example Payload:

1. `inputName`: Set to “ds” as specified in the original data.
2. `datasetId`: Taken from the `inputConfiguration.ds.value.datasetId`.
3. `dimensions`: List of all dimension names from `inputConfiguration.columns.value`.
4. `order`:
  - The first item is “balances.account\_id”, assuming it was the `defaultSort.value.name`.
  - The remaining items are all other dimensions, in the order they appear in `dimensions`.
  - All are set to “desc” (descending) order.

5. `offset`: Set to 0 to start from the beginning of the dataset.
6. `limit`: Set to 1000, as specified in the original `inputConfiguration.limit.value`.
7. `componentId`: Taken from the `id` field of the widget.
8. `timezone`: Set to “Europe/Amsterdam” as a default value.

## Notes

- Filters are automatically applied by the API and don’t need to be included in the query payload - the data returned will be filtered automatically.
- The `timezone` and `variableValues` fields in the query payload are optional.
- Replace all placeholder values (marked with [BRACKETS]) with your actual values.
