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

# Super: Programmatic Access & Automation

This section covers the most powerful features of Information Hub: direct API access, key generators, form pre-filling, the audit log, webhooks, and dynamic file paths. These features are aimed at users who want to automate workflows, integrate with external systems, or process data programmatically.

{% hint style="info" %}
This section assumes you have completed the previous tutorials and have the **Fynbos in Siberia** project with tables, forms, and dashboards already set up.
{% endhint %}

***

## Step 1: Create an API key

To access data programmatically, you need an API key.

1. Click your profile icon and go to **Settings**.
2. Navigate to the **API Keys** card.
3. Click **Create**.
4. Give it a name (e.g., **Fynbos Analysis Script**).
5. Copy the generated key immediately - it will not be shown again.

{% hint style="warning" %}
Treat your API key like a password. Do not share it publicly or commit it to version control.
{% endhint %}

***

## Step 2: Query data via the GraphQL API

Information Hub exposes a GraphQL API at `https://app.informationhub.io/graphql`. You can use it to read and write data programmatically.

### Query the Species Observations table

Using a tool like `curl`, Postman, or any GraphQL client, send the following query:

```graphql
query {
  queryTable(
    request: {
      tableId: "YOUR_TABLE_ID"
    }
  ) {
    data
  }
}
```

Include your API key in the request headers:

```
Authorization: Bearer YOUR_API_KEY
```

**Using curl:**

```bash
curl -X POST https://app.informationhub.io/graphql \
  -H "Content-Type: application/json" \
  -H "Authorization: Bearer YOUR_API_KEY" \
  -d '{
    "query": "query { queryTable(request: { tableId: \"YOUR_TABLE_ID\" }) { data } }"
  }'
```

The response contains all rows from the Species Observations table as JSON.

### Find your table ID

The table ID is visible in the URL when you open a table in the browser. For example, if the URL is `https://app.informationhub.io/project/abc123/tables/tbl_456`, then `tbl_456` is the table ID.

***

## Step 3: Insert data via the GraphQL API

You can also add new rows programmatically. This is useful for integrating with sensors, scripts, or external data sources.

```graphql
mutation {
  insertData(
    request: {
      tableId: "YOUR_TABLE_ID"
      data: [
        {
          species_name: "Protea siberica"
          site: "Site Alpha"
          height_cm: 52.3
          leaf_count: 42
          soil_ph: 5.8
          observation_date: "2026-04-01"
          observer: "Automated Sensor"
        }
      ]
    }
  ) {
    data
  }
}
```

**Using curl:**

```bash
curl -X POST https://app.informationhub.io/graphql \
  -H "Content-Type: application/json" \
  -H "Authorization: Bearer YOUR_API_KEY" \
  -d '{
    "query": "mutation { insertData(request: { tableId: \"YOUR_TABLE_ID\", data: [{ species_name: \"Protea siberica\", site: \"Site Alpha\", height_cm: 52.3, leaf_count: 42, soil_ph: 5.8, observation_date: \"2026-04-01\", observer: \"Automated Sensor\" }] }) { data } }"
  }'
```

After running this mutation, open the Species Observations table in the browser - the new row should be there.

***

## Step 4: Generate R and Python analysis scripts

The Analyse tool can generate starter scripts pre-configured with your table ID and API key.

1. Open the **Species Observations** table.
2. Click **Analyse** in the toolbar.
3. Click the language toggle to switch between **Python** and **R**.
4. Click the **copy** icon to copy the generated script.

### Example generated Python script

```python
import requests
import pandas as pd

API_URL = "https://app.informationhub.io/graphql"
API_KEY = "YOUR_API_KEY"
TABLE_ID = "YOUR_TABLE_ID"

headers = {
    "Content-Type": "application/json",
    "Authorization": f"Bearer {API_KEY}"
}

query = """
query {
  queryTable(request: { tableId: "%s" }) {
    data
  }
}
""" % TABLE_ID

response = requests.post(API_URL, json={"query": query}, headers=headers)
data = response.json()["data"]["queryTable"]["data"]

df = pd.DataFrame(data)
result = df.groupby("species_name")["height_cm"].mean()
print(result)
```

### Example generated R script

```r
library(httr)
library(jsonlite)

api_url <- "https://app.informationhub.io/graphql"
api_key <- "YOUR_API_KEY"
table_id <- "YOUR_TABLE_ID"

query <- sprintf('{
  "query": "query { queryTable(request: { tableId: \\"%s\\" }) { data } }"
}', table_id)

response <- POST(
  api_url,
  add_headers(
    "Content-Type" = "application/json",
    "Authorization" = paste("Bearer", api_key)
  ),
  body = query
)

data <- fromJSON(content(response, "text"))$data$queryTable$data
df <- as.data.frame(data)

aggregate(height_cm ~ species_name, data = df, FUN = mean)
```

Replace the placeholder values with your actual API key and table ID, then run the script in your local environment.

***

## Step 5: Key generators

A **key generator** auto-populates a table's primary key column with values based on a template pattern. Instead of auto-incrementing integers (1, 2, 3...), rows get human-readable IDs like `OBS-20260501-042`.

Key generators are project-level resources - create one and reuse it across multiple tables.

### Create a key generator

1. Click **Tables** in the project sidebar.
2. Click the **Key Generators** button in the toolbar (top-right area of the tables list page).
3. Click **+** to create a new generator.
4. Enter the name **Observation ID**.
5. In the **Template** field, enter: `OBS-{date:YYYYMMDD}-{autoincrement}`
6. Click **Create**.

### Assign it to the primary key column

1. Open the **Species Observations** table.
2. Click the **pencil icon** on the `id` column header to edit it.
3. In the **Key Generator** dropdown, select **Observation ID**.
4. Click **Save**.

New rows added to this table will now receive primary keys like `OBS-20260501-29` instead of plain integers. Existing rows keep their original IDs.

### Token reference

Templates are strings that mix literal text with tokens in `{...}` syntax.

| Token             | Output                                  | Example                                |
| ----------------- | --------------------------------------- | -------------------------------------- |
| `{autoincrement}` | Incrementing integer                    | `42`                                   |
| `{uuid}`          | Random v4 UUID                          | `f47ac10b-58cc-4372-a567-0e02b2c3d479` |
| `{cuid}`          | Collision-resistant unique ID           | `clh3z8k0v0000qzrm...`                 |
| `{date}`          | Current date as `YYYY-MM-DD`            | `2026-05-26`                           |
| `{date:FORMAT}`   | Date in a custom moment.js format       | `{date:YYYYMMDD}` → `20260526`         |
| `{time}`          | Current time as `HH:mm:ss`              | `14:32:07`                             |
| `{time:FORMAT}`   | Time in a custom format                 | `{time:HHmm}` → `1432`                 |
| `{datetime}`      | Date and time (ISO 8601)                | `2026-05-26T14:32:07+00:00`            |
| `{columnId}`      | Value of another column in the same row | `Site Alpha`                           |

**Slicing:** add `[start:end]` after the token name to take only part of the value:

* `{uuid[0:8]}` - first 8 characters of a UUID
* `{cuid[0:12]}` - first 12 characters of a CUID

**Formatters:** add `:lower`, `:upper`, or (for column references) `:slug`:

* `{uuid:upper}` - UUID in uppercase
* `{myColumnId:slug}` - column value lowercased with spaces replaced by hyphens

### Working examples

**Simple sequential IDs**

```
OBS-{autoincrement}
```

Produces: `OBS-1`, `OBS-2`, `OBS-3`

**Date-prefixed with short UUID**

```
{date:YYYYMMDD}-{uuid[0:8]:upper}
```

Produces: `20260526-F47AC10B`, `20260526-A3B2C1D0`

**Site-prefixed sequential ID** (replace `clm8abc123def456xyz` with your actual site column ID)

```
{clm8abc123def456xyz:slug}-{autoincrement}
```

Produces: `site-alpha-1`, `site-beta-2`

**Short CUID**

```
SP-{cuid[0:8]}
```

Produces: `SP-clh3z8k0`, `SP-clh4a9m1`

{% hint style="info" %}
To find a column's ID for use in a template, look at the URL when editing the column in the table settings. Column IDs are 20-40 alphanumeric characters.
{% endhint %}

{% hint style="warning" %}
Key generators can only be assigned to **primary key columns**. They apply to new rows only - existing rows keep their original primary keys.
{% endhint %}

***

## Step 6: URL query parameter pre-filling

Dr. Mwangi sends her two field teams to different sites each day. Instead of asking each team member to select their site from a dropdown, she sends them a pre-filled link where the site is already set.

### Configure the question

1. Open the **Field Observation Form** in the form builder.
2. Click the **pencil icon** on the **site** question to edit it.
3. Click the **cog icon** to open the expanded configuration panel.
4. Enter `site` in the **URL Query Param Key** field.
5. Click **Save**.

### Create pre-filled links

Now append the parameter to the share link:

* For Site Alpha: `https://app.informationhub.io/form/YOUR_FORM_ID?site=Site+Alpha`
* For Site Beta: `https://app.informationhub.io/form/YOUR_FORM_ID?site=Site+Beta`

When Dr. Tanaka opens the Site Alpha link, the **site** field is pre-filled with `Site Alpha`. She can still change it if needed (unless the question is also set to **Locked**).

### Combining multiple parameters

You can pre-fill multiple fields at once by chaining parameters:

```
.../form/YOUR_FORM_ID?site=Site+Alpha&observer=Dr.+Tanaka
```

This requires a **URL Query Param Key** set on each question you want to pre-fill. Parameters that do not match any key are silently ignored.

**Use cases:**

* Send site-specific links to each field team so the site is never wrong
* Pre-fill the observer name for each team member's personal link
* Pre-fill a batch ID from an external system by embedding it in a redirect URL

***

## Step 7: Table audit log and rollback

Every change to a row in a table is recorded in the audit log. This gives you a full history of edits and the ability to roll back a row to any previous state.

### View the audit log

1. Open the **Species Observations** table.
2. Click the **Settings** button in the toolbar.
3. The settings page has an **Audit Log** link in the sidebar - click it. (Alternatively, navigate to `/project/:id/tables/:tableId/audit` directly.)
4. The log shows one entry per row change, with the before and after values of each field. Click an entry to expand and see the field-level diff.

### Roll back a row

If Dr. Volkov accidentally overwrites a correct observation with wrong values, he can roll it back:

1. Find the history entry for the incorrect edit - it shows the timestamp, the user who made the change, and which fields changed.
2. Click **Rollback** on that entry.
3. The row is restored to the state it was in just before that edit.

{% hint style="info" %}
Rollback requires the appropriate permission (`tables.data.rollback` or equivalent in the project's role configuration). Check with your project administrator if the button is not visible.
{% endhint %}

***

## Step 8: Dynamic file upload paths

When forms include file upload questions, uploaded files go to Storage. By default, they all land in the same folder. Dynamic paths let you organise uploads automatically by the values in other form fields.

1. Open the **Field Observation Form** in the form builder.
2. Click the **pencil icon** on the **Plant Photo** question.
3. In the column picker, the linked column (`plant_photo`) has a **path template** configuration. Set it to:

```
observations/{site}/{species_name}/{observation_date}
```

Now when a field worker uploads a photo:

* An observation at Site Alpha for Protea siberica on 2026-04-01 saves to: `observations/Site Alpha/Protea siberica/2026-04-01/`
* An observation at Site Beta for Erica glacialis on 2026-04-02 saves to: `observations/Site Beta/Erica glacialis/2026-04-02/`

The template can reference any column in the linked table. This keeps Storage organised as the volume of uploads grows.

***

## Step 9: Webhooks - trigger external actions

Webhooks let you notify an external system every time a form is submitted. Dr. Mwangi wants to send each new observation to a data processing pipeline.

### Configure the webhook

1. Open the **Field Observation Form** and click **Settings** in the toolbar.
2. In the **General settings** section, find the **Webhook** field.
3. Enter the webhook URL (e.g., `https://your-api.example.com/observations/webhook`).
4. Click **Save**.

### How it works

Every time someone submits the form, Information Hub sends an HTTP POST request to the webhook URL with the submitted data as a JSON body. The payload includes all field values from the submission.

Example payload:

```json
{
  "species_name": "Protea siberica",
  "site": "Site Alpha",
  "height_cm": 52.3,
  "leaf_count": 42,
  "soil_ph": 5.8,
  "observation_date": "2026-04-01",
  "observer": "Dr. Lena Mwangi"
}
```

**What you can do with webhooks:**

* Send data to a cloud function for processing or validation
* Trigger notifications in Slack, Teams, or email
* Push data to an external database or analytics platform
* Start an automated analysis pipeline

***

## What you have learned

* How to create and manage API keys for programmatic access
* How to query and insert table data via the GraphQL API
* How to generate and run R and Python analysis scripts
* How to create key generators with all supported tokens, slices, and formatters
* How to assign a key generator to a primary key column for human-readable row IDs
* How to configure URL query param keys to pre-fill form fields from links
* How to use the table audit log to review row history and roll back edits
* How to configure dynamic file upload paths for automatic Storage organisation
* How to set up webhooks to trigger external systems on form submission

***

## Congratulations

You have completed the full Information Hub tutorial. You now know how to:

* **Collect data** with tables, forms, Location questions, File Upload, QR codes, offline mode, and update forms
* **Organise** your team with organisations, groups, and role-based permissions
* **Analyse and visualise** data with the built-in tools, dashboards, and external scripts
* **Share** your work through apps, shared forms, public wiki pages, and the Marketplace
* **Automate** with the GraphQL API, key generators, URL pre-filling, webhooks, and dynamic configuration
* **Audit** your data with row history and rollback

For detailed reference on any feature, see the [Home](/home.md) and [Project](/project.md) documentation sections.


---

# 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:

```
GET https://docs.informationhub.io/tutorial/super.md?ask=<question>
```

The question should be specific, self-contained, and written in natural language.
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.
