# Append to app table

Append input records' row values to an Strive per-app user table.

## When to use it

Append input row values to a user table owned by the app. Confirm the table and its column definitions first. This operation adds rows; it does not independently approve their source evidence.

## Add and configure

1. Add **Append to app table** from the workflow step picker.
2. Give the step a recognisable name and connect its required inputs.
3. Set the options below. Nested names identify fields within an object or a list item.
4. Validate the recipe, inspect the test result, then run it on the intended data.

The step identifier used in the editor’s code view is `user_table_append`.

## Settings

| Setting | Accepted value | Required | Default | What it controls |
| --- | --- | --- | --- | --- |
| App Id (`app_id`) | string; minimum characters 1; maximum characters 100 | Yes | Not specified | Strive app slug that owns the target user table. |
| Batch Size (`batch_size`) | integer; minimum 1; maximum 1000 | No | 500 | Rows per append request, up to 1,000. Your organisation can impose a lower batch cap; reduce the batch when a request is too large. |
| Record Type (`record_type`) | string | No | "user_table_row" | record_type stamp for the emitted row-reference records. |
| Table Id (`table_id`) | string; format uuid or null | No | null | The user table's id (Strive UUID), fixed at authoring time. |
| Table Id From Input (`table_id_from_input`) | boolean | No | false | Resolve the table id per run from the step's input records instead of static config — the blueprint contract, where the table is created AT RUNTIME (proposal accepted → createTable → trigger): the FIRST input record carrying a `table_id` key supplies it (string UUID). When set, `table_id` must be omitted. A missing or invalid input id fails the run with a config-style (invalid_input) error. The carrier record may be the same one carrying `fields` for extract_anchored; lacking a `values_key` dict, it is never appended as a row. |
| Timeout Seconds (`timeout_seconds`) | integer; minimum 1; maximum 300 | No | 30 | Time limit in seconds for the configured processing operation. Inspect its saved outcome before retrying after a timeout. |
| Values Key (`values_key`) | string; minimum characters 1; maximum characters 256 | No | "values" | Input-record field holding the row values dict ({<column key>: value}); records without a non-empty dict there are skipped. |

## Inputs and outputs

| Direction | Port | Content | Required | Multiple records |
| --- | --- | --- | --- | --- |
| Inputs | `in` | records | Yes | Yes |
| Outputs | `out` | records | Yes | Yes |

## Effects, testing, and recovery

Writes information inside Strive.

The declared preview behaviour is to skip this step. Configuration can affect preview behaviour; HTTP GET is a notable exception. Read [dry runs](/docs/workflows/dry-runs) before using a preview with live connections.

No duplicate-prevention key is declared for this step. Do not assume that manually repeating the step is free of repeated effects.

## Example: Append extracted rows to a fixed table

Step settings:

```json
{
  "app_id": "expense-reports",
  "table_id": "7c1d2e3f-4a5b-4c6d-8e7f-9a0b1c2d3e4f"
}
```

Input records:

```json
[
  {
    "values": {
      "amount": 1250.0,
      "vendor": "Acme"
    }
  }
]
```

## Example: Append to the table the run's carrier names

Step settings:

```json
{
  "app_id": "expense-reports",
  "batch_size": 250,
  "table_id_from_input": true,
  "values_key": "row"
}
```

Input records:

```json
[
  {
    "table_id": "7c1d2e3f-4a5b-4c6d-8e7f-9a0b1c2d3e4f"
  },
  {
    "row": {
      "amount": 1250.0,
      "vendor": "Acme"
    }
  }
]
```

## Check the result

Inspect the selected run’s status, counts, errors, and output records. An empty collection can be a valid result, and a completed step can contain per-record failures where the step defines that behaviour. Check the next step’s expected record shape before publishing or delivering the result.
