Tables API
Every Tables action (37) and data model (0): endpoints, scopes, input, preconditions, events and examples.
Tables of your own, and extra fields on any record.
Module code data · 37 actions · 0 data models · 27 events. A key or token never does more here than the person behind it can; row-level security applies exactly as in the app. Scopes: data (everything), data:read (read only) or data:<capability>.
Actions
| Action | Needs | What it does |
|---|---|---|
data.add_column | data:manage | Add a field |
data.add_computed_field | data:manage | Add a lookup, rollup or formula |
data.change_column_type | data:manage | Change a field’s type |
data.clear_record_values | data:delete | Remove a field group from a record |
data.create_relation | data:manage | Link to another table |
data.create_table | data:manage | Add a table |
data.create_table_group | data:manage | Add a table group |
data.delete_row | data:delete | Delete a record |
data.delete_row_policy | data:manage | Remove a row rule |
data.delete_rows | data:delete | Delete several records |
data.delete_table | data:delete | Delete a table |
data.delete_table_group | data:manage | Delete a table group |
data.duplicate_table | data:manage | Duplicate a table |
data.duplicate_table_group | data:manage | Duplicate a Base |
data.export_rows | data:export | Export records |
data.insert_row | data:write | Add a record |
data.insert_rows | data:import | Import records |
data.link_records | data:write | Link records |
data.move_row | data:write | Move a record |
data.move_table | data:manage | Move a table to a group |
data.press_button | data:write | Press a button |
data.purge_rows | data:delete | Clear a table’s records |
data.remove_column | data:delete | Remove a field |
data.rename_table | data:manage | Edit a table |
data.rename_table_group | data:manage | Rename a table group |
data.set_display_field | data:manage | Set as display value |
data.set_field | data:write | Set a custom field |
data.set_record_values | data:write | Fill in extra fields |
data.set_row_policy | data:manage | Narrow who sees which rows |
data.set_select_options | data:manage | Edit the choices |
data.set_table_permission | data:manage | Change who may use a table |
data.unlink_records | data:write | Unlink records |
data.update_column | data:manage | Edit a field |
data.update_computed_field | data:manage | Edit a computed field |
data.update_row | data:write | Edit a record |
data.update_rows | data:write | Edit several records |
data.upsert_row | data:import | Add or update records |
data.add_column
Add a field — Defines a field — its type, whether it is required, and what it offers.
Needs data:manage · changes data
https://app.getera.io/api/v1/actions/data.add_columnInput
| Field | Type | Required | Notes |
|---|---|---|---|
dataTableId | uuid | yes | Table · id of data_table |
title | string | yes | Label · max 200 |
fieldKey | string | yes | Key · max 100 |
uiType | string | yes | Type · max 40 |
uiHint | string | Shown as · max 30 | |
unit | string | Unit · max 30 | |
isRequired | boolean | Required | |
isFilterable | boolean | Filterable | |
isListable | boolean | Available as a column | |
isPublic | boolean | Visible on the storefront | |
helpText | string | Help text · max 255 | |
description | string | Description · max 2000 | |
color | string | Colour · max 7 | |
defaultValue | string | Default · max 500 | |
sortOrder | number | Order | |
referenceModuleCode | string | Points at · max 60 | |
referenceRecordType | string | Record type · max 60 | |
validation | object / array | Validation | |
options | object / array | Choices | |
display | object / array | How it is shown |
Preconditions
The action is refused with 409 and one of these codes:
| Code | Refused when |
|---|---|
table_not_found | The table must exist. |
invalid_field_key | A key has no spaces — it is a key in a filter. |
unknown_ui_type | The type must be one the engine understands. |
field_key_taken | Two fields in one group may not share a key. |
field_key_taken_on_target | Two groups may not add the same key to the same kind of record. |
key_shadows_standard_field | A custom field may not take the name of a standard one. |
enum_without_options | A choice field needs choices. |
invalid_display_option | A display option must be one the field type has, with a valid value. |
reference_module_disabled | The module it points at must be switched on. |
required_without_default_on_existing_rows | Making a field required on records that already exist needs a default. |
Events it publishes: data.column_added
What it writes: data_column (insert) — Defines the field; data_select_option (upsert) — Writes its choices
curl -X POST https://app.getera.io/api/v1/actions/data.add_column \
-H "Authorization: Bearer $ERA_API_KEY" \
-H "Content-Type: application/json" \
-H "Idempotency-Key: $(uuidgen)" \
-d '{"dataTableId":"DATA_TABLE_ID","title":"Label","fieldKey":"Key","uiType":"Type"}'{
"ok": true,
"result": "…",
"events": [
"data.column_added"
]
}import { createEra } from "@getera/sdk"
const era = createEra({ apiKey: process.env.ERA_API_KEY })
const res = await era.actions.run("data.add_column", {
dataTableId: "DATA_TABLE_ID",
title: "Label",
fieldKey: "Key",
uiType: "Type"
})era data add_column \
--data-table-id "DATA_TABLE_ID" \
--title "Label" \
--field-key "Key" \
--ui-type "Type"{
"name": "era__data__add_column",
"arguments": {
"dataTableId": "DATA_TABLE_ID",
"title": "Label",
"fieldKey": "Key",
"uiType": "Type"
}
}Errors: 401 no or expired credential · 403 the credential does not hold data:manage · 404 the record or module is outside what it may reach · 422 invalid input (problems[]) · 409 table_not_found, invalid_field_key, unknown_ui_type, field_key_taken, field_key_taken_on_target, key_shadows_standard_field, enum_without_options, invalid_display_option, reference_module_disabled, required_without_default_on_existing_rows · 429 slow down
data.add_computed_field
Add a lookup, rollup or formula — Adds a field whose value is computed — from linked records, or from this record’s own fields.
Needs data:manage · changes data
https://app.getera.io/api/v1/actions/data.add_computed_fieldInput
| Field | Type | Required | Notes |
|---|---|---|---|
dataTableId | uuid | yes | Table · id of data_table |
kind | string (enum) | yes | Kind · Allowed values: lookup, rollup, formula, count, barcode, qr_code, button, created_time, last_modified_time, created_by, last_modified_by, auto_number |
title | string | yes | Name · max 200 |
fieldKey | string | Key · max 100 | |
relationColumnId | uuid | Through the link · id of data_column | |
targetColumnId | uuid | Field of the linked table · id of data_column | |
fn | string (enum) | Summary · Allowed values: count, sum, avg, min, max, countDistinct, sumDistinct, avgDistinct | |
formula | string | Formula · max 2000 | |
sourceColumnId | uuid | Field the code carries · id of data_column | |
buttonAction | string (enum) | When clicked · Allowed values: url, workflow | |
buttonUrl | string | Link · max 2000 | |
buttonLabel | string | Button text · max 60 | |
buttonColor | string | Button colour · max 7 |
Preconditions
The action is refused with 409 and one of these codes:
| Code | Refused when |
|---|---|
table_not_found | The table must exist. |
wrong_table_kind | A field group has no rows to compute over. |
unknown_ui_type | Only the computed kinds are added here. |
invalid_button_url | A link button needs a web address to open. |
title_required | The field needs a name. |
invalid_field_key | A key has no spaces — it is a key in a filter. |
field_key_taken | Two fields in one table may not share a key. |
not_a_link_field | A lookup or rollup reads through a link field of this table. |
column_not_found | The field looked up must be one of the linked table’s. |
invalid_formula | A formula that cannot be read is refused at save time. |
Events it publishes: data.column_added
What it writes: data_column (insert) — Defines the computed field
curl -X POST https://app.getera.io/api/v1/actions/data.add_computed_field \
-H "Authorization: Bearer $ERA_API_KEY" \
-H "Content-Type: application/json" \
-H "Idempotency-Key: $(uuidgen)" \
-d '{"dataTableId":"DATA_TABLE_ID","kind":"lookup","title":"Name"}'{
"ok": true,
"result": "…",
"events": [
"data.column_added"
]
}import { createEra } from "@getera/sdk"
const era = createEra({ apiKey: process.env.ERA_API_KEY })
const res = await era.actions.run("data.add_computed_field", {
dataTableId: "DATA_TABLE_ID",
kind: "lookup",
title: "Name"
})era data add_computed_field \
--data-table-id "DATA_TABLE_ID" \
--kind "lookup" \
--title "Name"{
"name": "era__data__add_computed_field",
"arguments": {
"dataTableId": "DATA_TABLE_ID",
"kind": "lookup",
"title": "Name"
}
}Errors: 401 no or expired credential · 403 the credential does not hold data:manage · 404 the record or module is outside what it may reach · 422 invalid input (problems[]) · 409 table_not_found, wrong_table_kind, unknown_ui_type, invalid_button_url, title_required, invalid_field_key, field_key_taken, not_a_link_field, column_not_found, invalid_formula · 429 slow down
data.change_column_type
Change a field’s type — Retypes a field, and refuses with a count rather than blanking what will not convert.
Needs data:manage · reaches outside (sends, publishes or charges) · asks a person to confirm when Era runs it
https://app.getera.io/api/v1/actions/data.change_column_typeInput
| Field | Type | Required | Notes |
|---|---|---|---|
id | uuid | yes | Field · id of data_column |
uiType | string | yes | New type · max 40 |
Preconditions
The action is refused with 409 and one of these codes:
| Code | Refused when |
|---|---|
column_not_found | The field must exist. |
unknown_ui_type | The type must be one the engine understands. |
no_change | The new type has to differ from the old one. |
incompatible_values | Stored values that cannot be read as the new type stop the change. |
Events it publishes: data.column_changed
What it writes: data_column (update) — Retypes the field; data_value (update) — Moves values to the right column
curl -X POST https://app.getera.io/api/v1/actions/data.change_column_type \
-H "Authorization: Bearer $ERA_API_KEY" \
-H "Content-Type: application/json" \
-H "Idempotency-Key: $(uuidgen)" \
-d '{"id":"DATA_COLUMN_ID","uiType":"New type"}'{
"ok": true,
"result": "…",
"events": [
"data.column_changed"
]
}import { createEra } from "@getera/sdk"
const era = createEra({ apiKey: process.env.ERA_API_KEY })
const res = await era.actions.run("data.change_column_type", {
id: "DATA_COLUMN_ID",
uiType: "New type"
})era data change_column_type \
--id "DATA_COLUMN_ID" \
--ui-type "New type"{
"name": "era__data__change_column_type",
"arguments": {
"id": "DATA_COLUMN_ID",
"uiType": "New type"
}
}Errors: 401 no or expired credential · 403 the credential does not hold data:manage · 404 the record or module is outside what it may reach · 422 invalid input (problems[]) · 409 column_not_found, unknown_ui_type, no_change, incompatible_values · 429 slow down
data.clear_record_values
Remove a field group from a record — Takes a whole group of extra fields off one record.
Needs data:delete · removes or cannot be undone · asks a person to confirm when Era runs it
https://app.getera.io/api/v1/actions/data.clear_record_valuesInput
| Field | Type | Required | Notes |
|---|---|---|---|
dataTableId | uuid | yes | Field group · id of data_table |
recordType | string | yes | Record type · max 60 |
recordId | uuid | yes | Record |
Preconditions
The action is refused with 409 and one of these codes:
| Code | Refused when |
|---|---|
table_not_found | The field group must exist. |
wrong_table_kind | A table that owns its rows is not removed this way. |
nothing_to_purge | There must be something stored to remove. |
Events it publishes: data.record_values_changed
What it writes: data_value (delete) — Deletes the group’s values
curl -X POST https://app.getera.io/api/v1/actions/data.clear_record_values \
-H "Authorization: Bearer $ERA_API_KEY" \
-H "Content-Type: application/json" \
-H "Idempotency-Key: $(uuidgen)" \
-d '{"dataTableId":"DATA_TABLE_ID","recordType":"Record type","recordId":"RECORD_ID"}'{
"ok": true,
"result": "…",
"events": [
"data.record_values_changed"
]
}import { createEra } from "@getera/sdk"
const era = createEra({ apiKey: process.env.ERA_API_KEY })
const res = await era.actions.run("data.clear_record_values", {
dataTableId: "DATA_TABLE_ID",
recordType: "Record type",
recordId: "RECORD_ID"
})era data clear_record_values \
--data-table-id "DATA_TABLE_ID" \
--record-type "Record type" \
--record-id "RECORD_ID"{
"name": "era__data__clear_record_values",
"arguments": {
"dataTableId": "DATA_TABLE_ID",
"recordType": "Record type",
"recordId": "RECORD_ID"
}
}Errors: 401 no or expired credential · 403 the credential does not hold data:delete · 404 the record or module is outside what it may reach · 422 invalid input (problems[]) · 409 table_not_found, wrong_table_kind, nothing_to_purge · 429 slow down
data.create_relation
Link to another table — Adds a link field here and its partner on the other table — has many, belongs to, many to many or one to one.
Needs data:manage · changes data
https://app.getera.io/api/v1/actions/data.create_relationInput
| Field | Type | Required | Notes |
|---|---|---|---|
dataTableId | uuid | yes | Table · id of data_table |
targetTableId | uuid | yes | Links to · id of data_table |
kind | string (enum) | yes | Each record here… · Allowed values: has_many, belongs_to, many_to_many, one_to_one |
title | string | yes | Field name here · max 200 |
targetTitle | string | Field name on the other table · max 200 | |
onDelete | string (enum) | When a parent record is deleted · Allowed values: unlink, restrict, cascade |
Preconditions
The action is refused with 409 and one of these codes:
| Code | Refused when |
|---|---|
table_not_found | The table must exist. |
target_table_not_found | The table to link to must exist. |
wrong_table_kind | Only tables with records of their own can be linked. |
invalid_on_delete | A many-to-many link has no parent to cascade from. |
title_required | The link field needs a name. |
field_key_taken | The link field’s key must be free on this table. |
Events it publishes: data.relation_created
What it writes: data_relation (insert) — Records the relation; data_column (insert) — Adds a link field on each side
curl -X POST https://app.getera.io/api/v1/actions/data.create_relation \
-H "Authorization: Bearer $ERA_API_KEY" \
-H "Content-Type: application/json" \
-H "Idempotency-Key: $(uuidgen)" \
-d '{"dataTableId":"DATA_TABLE_ID","targetTableId":"DATA_TABLE_ID","kind":"has_many","title":"Field name here"}'{
"ok": true,
"result": "…",
"events": [
"data.relation_created"
]
}import { createEra } from "@getera/sdk"
const era = createEra({ apiKey: process.env.ERA_API_KEY })
const res = await era.actions.run("data.create_relation", {
dataTableId: "DATA_TABLE_ID",
targetTableId: "DATA_TABLE_ID",
kind: "has_many",
title: "Field name here"
})era data create_relation \
--data-table-id "DATA_TABLE_ID" \
--target-table-id "DATA_TABLE_ID" \
--kind "has_many" \
--title "Field name here"{
"name": "era__data__create_relation",
"arguments": {
"dataTableId": "DATA_TABLE_ID",
"targetTableId": "DATA_TABLE_ID",
"kind": "has_many",
"title": "Field name here"
}
}Errors: 401 no or expired credential · 403 the credential does not hold data:manage · 404 the record or module is outside what it may reach · 422 invalid input (problems[]) · 409 table_not_found, target_table_not_found, wrong_table_kind, invalid_on_delete, title_required, field_key_taken · 429 slow down
data.create_table
Add a table — Opens a table of your own, or a set of extra fields for another module’s records.
Needs data:manage · changes data
https://app.getera.io/api/v1/actions/data.create_tableInput
| Field | Type | Required | Notes |
|---|---|---|---|
code | string | yes | System name · max 60 |
title | string | yes | Display name · max 200 |
description | string | Description · max 2000 | |
icon | string | Icon · max 40 | |
kind | string (enum) | Kind · Allowed values: table, extension | |
extendsModuleCode | string | Attach to · max 60 | |
extendsRecordType | string | Record type · max 60 | |
maxRows | number | Record limit · min 1 |
Preconditions
The action is refused with 409 and one of these codes:
| Code | Refused when |
|---|---|
title_required | A table needs a display name. |
invalid_code | The system name must be snake_case. |
code_taken | Two tables may not share a system name. |
extends_unknown_module | The module it attaches to must exist. |
extends_module_disabled | That module must be switched on here. |
table_limit_reached | A workspace has a ceiling on tables. |
Events it publishes: data.table_created
What it writes: data_table (insert) — Opens the table
curl -X POST https://app.getera.io/api/v1/actions/data.create_table \
-H "Authorization: Bearer $ERA_API_KEY" \
-H "Content-Type: application/json" \
-H "Idempotency-Key: $(uuidgen)" \
-d '{"code":"System name","title":"Display name"}'{
"ok": true,
"result": "…",
"events": [
"data.table_created"
]
}import { createEra } from "@getera/sdk"
const era = createEra({ apiKey: process.env.ERA_API_KEY })
const res = await era.actions.run("data.create_table", {
code: "System name",
title: "Display name"
})era data create_table \
--code "System name" \
--title "Display name"{
"name": "era__data__create_table",
"arguments": {
"code": "System name",
"title": "Display name"
}
}Errors: 401 no or expired credential · 403 the credential does not hold data:manage · 404 the record or module is outside what it may reach · 422 invalid input (problems[]) · 409 title_required, invalid_code, code_taken, extends_unknown_module, extends_module_disabled, table_limit_reached · 429 slow down
data.create_table_group
Add a table group — A folder in the Tables list, to keep related tables together.
Needs data:manage · changes data
https://app.getera.io/api/v1/actions/data.create_table_groupInput
| Field | Type | Required | Notes |
|---|---|---|---|
name | string | yes | Name · max 120 |
Preconditions
The action is refused with 409 and one of these codes:
| Code | Refused when |
|---|---|
group_name_required | A group needs a name. |
group_name_taken | Two groups may not share a name. |
Events it publishes: data.table_group_created
What it writes: data_table_group (insert) — Adds the group
curl -X POST https://app.getera.io/api/v1/actions/data.create_table_group \
-H "Authorization: Bearer $ERA_API_KEY" \
-H "Content-Type: application/json" \
-H "Idempotency-Key: $(uuidgen)" \
-d '{"name":"Name"}'{
"ok": true,
"result": "…",
"events": [
"data.table_group_created"
]
}import { createEra } from "@getera/sdk"
const era = createEra({ apiKey: process.env.ERA_API_KEY })
const res = await era.actions.run("data.create_table_group", {
name: "Name"
})era data create_table_group \
--name "Name"{
"name": "era__data__create_table_group",
"arguments": {
"name": "Name"
}
}Errors: 401 no or expired credential · 403 the credential does not hold data:manage · 404 the record or module is outside what it may reach · 422 invalid input (problems[]) · 409 group_name_required, group_name_taken · 429 slow down
data.delete_row
Delete a record — Removes a row from a table that owns its records.
Needs data:delete · removes or cannot be undone · asks a person to confirm when Era runs it
https://app.getera.io/api/v1/actions/data.delete_rowInput
| Field | Type | Required | Notes |
|---|---|---|---|
id | uuid | yes | Record · id of data_row |
Preconditions
The action is refused with 409 and one of these codes:
| Code | Refused when |
|---|---|
row_not_found | The record must exist. |
row_policy_denies | A row rule can put a record out of your reach. |
referenced_by_relation | A link set to block deletion keeps a parent while it has children. |
Events it publishes: data.row_deleted
What it writes: data_row (delete) — Deletes the row, and its children where a link cascades
curl -X POST https://app.getera.io/api/v1/actions/data.delete_row \
-H "Authorization: Bearer $ERA_API_KEY" \
-H "Content-Type: application/json" \
-H "Idempotency-Key: $(uuidgen)" \
-d '{"id":"DATA_ROW_ID"}'{
"ok": true,
"result": "…",
"events": [
"data.row_deleted"
]
}import { createEra } from "@getera/sdk"
const era = createEra({ apiKey: process.env.ERA_API_KEY })
const res = await era.actions.run("data.delete_row", {
id: "DATA_ROW_ID"
})era data delete_row \
--id "DATA_ROW_ID"{
"name": "era__data__delete_row",
"arguments": {
"id": "DATA_ROW_ID"
}
}Errors: 401 no or expired credential · 403 the credential does not hold data:delete · 404 the record or module is outside what it may reach · 422 invalid input (problems[]) · 409 row_not_found, row_policy_denies, referenced_by_relation · 429 slow down
data.delete_row_policy
Remove a row rule — Deletes one row rule. The rows it was hiding come back.
Needs data:manage · removes or cannot be undone · asks a person to confirm when Era runs it
https://app.getera.io/api/v1/actions/data.delete_row_policyInput
| Field | Type | Required | Notes |
|---|---|---|---|
policyId | uuid | yes | Rule |
Preconditions
The action is refused with 409 and one of these codes:
| Code | Refused when |
|---|---|
policy_not_found | The rule must exist. |
Events it publishes: data.row_policy_changed
What it writes: data_table_policy (delete) — Deletes the rule and its subjects
curl -X POST https://app.getera.io/api/v1/actions/data.delete_row_policy \
-H "Authorization: Bearer $ERA_API_KEY" \
-H "Content-Type: application/json" \
-H "Idempotency-Key: $(uuidgen)" \
-d '{"policyId":"POLICY_ID"}'{
"ok": true,
"result": "…",
"events": [
"data.row_policy_changed"
]
}import { createEra } from "@getera/sdk"
const era = createEra({ apiKey: process.env.ERA_API_KEY })
const res = await era.actions.run("data.delete_row_policy", {
policyId: "POLICY_ID"
})era data delete_row_policy \
--policy-id "POLICY_ID"{
"name": "era__data__delete_row_policy",
"arguments": {
"policyId": "POLICY_ID"
}
}Errors: 401 no or expired credential · 403 the credential does not hold data:manage · 404 the record or module is outside what it may reach · 422 invalid input (problems[]) · 409 policy_not_found · 429 slow down
data.delete_rows
Delete several records — Deletes the selected or filtered records in one go, following each link’s delete rule.
Needs data:delete · removes or cannot be undone · asks a person to confirm when Era runs it
https://app.getera.io/api/v1/actions/data.delete_rowsInput
| Field | Type | Required | Notes |
|---|---|---|---|
dataTableId | uuid | yes | Table · id of data_table |
ids | object / array | Records | |
conditions | object / array | Filter |
Preconditions
The action is refused with 409 and one of these codes:
| Code | Refused when |
|---|---|
table_not_found | The table must exist. |
wrong_table_kind | A field group has no rows of its own. |
filter_matches_nothing | The selection or filter must reach at least one record. |
filter_too_broad | A bulk delete needs a selection or a filter, and is capped. |
row_policy_denies | Every record deleted must be one your row rules let you delete. |
invalid_filter | A filter that cannot compile is refused. |
referenced_by_relation | A link set to block deletion keeps a parent while it has children. |
Events it publishes: data.rows_deleted
What it writes: data_row (delete) — Deletes the records
curl -X POST https://app.getera.io/api/v1/actions/data.delete_rows \
-H "Authorization: Bearer $ERA_API_KEY" \
-H "Content-Type: application/json" \
-H "Idempotency-Key: $(uuidgen)" \
-d '{"dataTableId":"DATA_TABLE_ID"}'{
"ok": true,
"result": "…",
"events": [
"data.rows_deleted"
]
}import { createEra } from "@getera/sdk"
const era = createEra({ apiKey: process.env.ERA_API_KEY })
const res = await era.actions.run("data.delete_rows", {
dataTableId: "DATA_TABLE_ID"
})era data delete_rows \
--data-table-id "DATA_TABLE_ID"{
"name": "era__data__delete_rows",
"arguments": {
"dataTableId": "DATA_TABLE_ID"
}
}Errors: 401 no or expired credential · 403 the credential does not hold data:delete · 404 the record or module is outside what it may reach · 422 invalid input (problems[]) · 409 table_not_found, wrong_table_kind, filter_matches_nothing, filter_too_broad, row_policy_denies, invalid_filter, referenced_by_relation · 429 slow down
data.delete_table
Delete a table — Removes a table and its field definitions — once it holds nothing.
Needs data:delete · removes or cannot be undone · asks a person to confirm when Era runs it
https://app.getera.io/api/v1/actions/data.delete_tableInput
| Field | Type | Required | Notes |
|---|---|---|---|
id | uuid | yes | Table · id of data_table |
Preconditions
The action is refused with 409 and one of these codes:
| Code | Refused when |
|---|---|
table_not_found | The table must exist. |
has_rows | Its records must be cleared first, and it says how many. |
referenced_by_relation | Another table linking here must drop its link field first. |
Events it publishes: data.table_deleted
What it writes: data_table (delete) — Deletes the table and its columns
curl -X POST https://app.getera.io/api/v1/actions/data.delete_table \
-H "Authorization: Bearer $ERA_API_KEY" \
-H "Content-Type: application/json" \
-H "Idempotency-Key: $(uuidgen)" \
-d '{"id":"DATA_TABLE_ID"}'{
"ok": true,
"result": "…",
"events": [
"data.table_deleted"
]
}import { createEra } from "@getera/sdk"
const era = createEra({ apiKey: process.env.ERA_API_KEY })
const res = await era.actions.run("data.delete_table", {
id: "DATA_TABLE_ID"
})era data delete_table \
--id "DATA_TABLE_ID"{
"name": "era__data__delete_table",
"arguments": {
"id": "DATA_TABLE_ID"
}
}Errors: 401 no or expired credential · 403 the credential does not hold data:delete · 404 the record or module is outside what it may reach · 422 invalid input (problems[]) · 409 table_not_found, has_rows, referenced_by_relation · 429 slow down
data.delete_table_group
Delete a table group — Removes the folder. Its tables stay, outside any group.
Needs data:manage · removes or cannot be undone · asks a person to confirm when Era runs it
https://app.getera.io/api/v1/actions/data.delete_table_groupInput
| Field | Type | Required | Notes |
|---|---|---|---|
id | uuid | yes | Group |
Preconditions
The action is refused with 409 and one of these codes:
| Code | Refused when |
|---|---|
table_group_not_found | The group must exist. |
Events it publishes: data.table_group_deleted
What it writes: data_table (update) — Takes its tables out of the group; data_table_group (delete) — Deletes the group
curl -X POST https://app.getera.io/api/v1/actions/data.delete_table_group \
-H "Authorization: Bearer $ERA_API_KEY" \
-H "Content-Type: application/json" \
-H "Idempotency-Key: $(uuidgen)" \
-d '{"id":"ID_ID"}'{
"ok": true,
"result": "…",
"events": [
"data.table_group_deleted"
]
}import { createEra } from "@getera/sdk"
const era = createEra({ apiKey: process.env.ERA_API_KEY })
const res = await era.actions.run("data.delete_table_group", {
id: "ID_ID"
})era data delete_table_group \
--id "ID_ID"{
"name": "era__data__delete_table_group",
"arguments": {
"id": "ID_ID"
}
}Errors: 401 no or expired credential · 403 the credential does not hold data:manage · 404 the record or module is outside what it may reach · 422 invalid input (problems[]) · 409 table_group_not_found · 429 slow down
data.duplicate_table
Duplicate a table — Copies a table’s fields and choices — and its records, if you ask — into a new table.
Needs data:manage · changes data
https://app.getera.io/api/v1/actions/data.duplicate_tableInput
| Field | Type | Required | Notes |
|---|---|---|---|
id | uuid | yes | Table · id of data_table |
title | string | Name of the copy · max 200 | |
withRows | boolean | Copy the records too |
Preconditions
The action is refused with 409 and one of these codes:
| Code | Refused when |
|---|---|
table_not_found | The table must exist. |
Events it publishes: data.table_duplicated
What it writes: data_table (insert) — Opens the copy; data_column (insert) — Copies the fields; data_select_option (insert) — Copies the choices; data_row (insert) — Copies the records, when asked
curl -X POST https://app.getera.io/api/v1/actions/data.duplicate_table \
-H "Authorization: Bearer $ERA_API_KEY" \
-H "Content-Type: application/json" \
-H "Idempotency-Key: $(uuidgen)" \
-d '{"id":"DATA_TABLE_ID"}'{
"ok": true,
"result": "…",
"events": [
"data.table_duplicated"
]
}import { createEra } from "@getera/sdk"
const era = createEra({ apiKey: process.env.ERA_API_KEY })
const res = await era.actions.run("data.duplicate_table", {
id: "DATA_TABLE_ID"
})era data duplicate_table \
--id "DATA_TABLE_ID"{
"name": "era__data__duplicate_table",
"arguments": {
"id": "DATA_TABLE_ID"
}
}Errors: 401 no or expired credential · 403 the credential does not hold data:manage · 404 the record or module is outside what it may reach · 422 invalid input (problems[]) · 409 table_not_found · 429 slow down
data.duplicate_table_group
Duplicate a Base — Copies a Base folder and its tables, with optional records. External links and automations stay with the original.
Needs data:manage · changes data
https://app.getera.io/api/v1/actions/data.duplicate_table_groupInput
| Field | Type | Required | Notes |
|---|---|---|---|
id | uuid | yes | Base |
name | string | yes | Copy name · max 120 |
withRows | boolean | Copy records |
Preconditions
The action is refused with 409 and one of these codes:
| Code | Refused when |
|---|---|
table_group_not_found | The source Base must exist. |
group_name_required | The copy needs a name. |
group_name_taken | The copy name must be available. |
table_not_found | Every source table must remain available. |
Events it publishes: data.table_group_created, data.table_duplicated
What it writes: data_table_group (insert) — Creates the copied Base; data_table (insert) — Copies its tables; data_table (update) — Places copies in the new Base; data_column (insert) — Copies independent fields; data_select_option (insert) — Copies choices; data_row (insert) — Copies records if selected; data_column (update) — Remaps computed field configurations; data_relation (insert) — Copies internal relations; data_row_link (insert) — Copies internal record links
curl -X POST https://app.getera.io/api/v1/actions/data.duplicate_table_group \
-H "Authorization: Bearer $ERA_API_KEY" \
-H "Content-Type: application/json" \
-H "Idempotency-Key: $(uuidgen)" \
-d '{"id":"ID_ID","name":"Copy name"}'{
"ok": true,
"result": "…",
"events": [
"data.table_group_created",
"data.table_duplicated"
]
}import { createEra } from "@getera/sdk"
const era = createEra({ apiKey: process.env.ERA_API_KEY })
const res = await era.actions.run("data.duplicate_table_group", {
id: "ID_ID",
name: "Copy name"
})era data duplicate_table_group \
--id "ID_ID" \
--name "Copy name"{
"name": "era__data__duplicate_table_group",
"arguments": {
"id": "ID_ID",
"name": "Copy name"
}
}Errors: 401 no or expired credential · 403 the credential does not hold data:manage · 404 the record or module is outside what it may reach · 422 invalid input (problems[]) · 409 table_group_not_found, group_name_required, group_name_taken, table_not_found · 429 slow down
data.export_rows
Export records — Returns every record the filter and your row rules leave, not just the page on screen.
Needs data:export · reaches outside (sends, publishes or charges)
https://app.getera.io/api/v1/actions/data.export_rowsInput
| Field | Type | Required | Notes |
|---|---|---|---|
dataTableId | uuid | yes | Table · id of data_table |
conditions | object / array | Filter | |
search | string | Search · max 200 | |
limit | number | Limit · min 1 |
Preconditions
The action is refused with 409 and one of these codes:
| Code | Refused when |
|---|---|
table_not_found | The table must exist. |
wrong_table_kind | A field group has no rows to export. |
invalid_filter | A filter that cannot compile is refused. |
unknown_field | A filter may only name fields the table has. |
Events it publishes: data.rows_exported
curl -X POST https://app.getera.io/api/v1/actions/data.export_rows \
-H "Authorization: Bearer $ERA_API_KEY" \
-H "Content-Type: application/json" \
-H "Idempotency-Key: $(uuidgen)" \
-d '{"dataTableId":"DATA_TABLE_ID"}'{
"ok": true,
"result": "…",
"events": [
"data.rows_exported"
]
}import { createEra } from "@getera/sdk"
const era = createEra({ apiKey: process.env.ERA_API_KEY })
const res = await era.actions.run("data.export_rows", {
dataTableId: "DATA_TABLE_ID"
})era data export_rows \
--data-table-id "DATA_TABLE_ID"{
"name": "era__data__export_rows",
"arguments": {
"dataTableId": "DATA_TABLE_ID"
}
}Errors: 401 no or expired credential · 403 the credential does not hold data:export · 404 the record or module is outside what it may reach · 422 invalid input (problems[]) · 409 table_not_found, wrong_table_kind, invalid_filter, unknown_field · 429 slow down
data.insert_row
Add a record — Writes a row into a table that owns its records.
Needs data:write · changes data
https://app.getera.io/api/v1/actions/data.insert_rowInput
| Field | Type | Required | Notes |
|---|---|---|---|
dataTableId | uuid | yes | Table · id of data_table |
data | object / array | yes | Values |
Preconditions
The action is refused with 409 and one of these codes:
| Code | Refused when |
|---|---|
table_not_found | The table must exist. |
wrong_table_kind | Extension tables have no rows of their own. |
row_limit_reached | A table has a record ceiling; reading carries on. |
unknown_field | Every key must be a field on the table. |
required_field_missing | Required fields must be filled in. |
type_mismatch | A value must be readable as its field’s type. |
not_a_member | A User field holds one of this workspace’s members. |
readonly_field | A read-only field cannot be written. |
invalid_field_format | A value must match its field format when validation is enabled. |
row_policy_denies | A row rule that would hide the new record from its author refuses the write. |
Events it publishes: data.row_created
What it writes: data_row (insert) — Writes the row
curl -X POST https://app.getera.io/api/v1/actions/data.insert_row \
-H "Authorization: Bearer $ERA_API_KEY" \
-H "Content-Type: application/json" \
-H "Idempotency-Key: $(uuidgen)" \
-d '{"dataTableId":"DATA_TABLE_ID","data":{}}'{
"ok": true,
"result": "…",
"events": [
"data.row_created"
]
}import { createEra } from "@getera/sdk"
const era = createEra({ apiKey: process.env.ERA_API_KEY })
const res = await era.actions.run("data.insert_row", {
dataTableId: "DATA_TABLE_ID",
data: {}
})era data insert_row --data '{"dataTableId":"DATA_TABLE_ID","data":{}}'{
"name": "era__data__insert_row",
"arguments": {
"dataTableId": "DATA_TABLE_ID",
"data": {}
}
}Errors: 401 no or expired credential · 403 the credential does not hold data:write · 404 the record or module is outside what it may reach · 422 invalid input (problems[]) · 409 table_not_found, wrong_table_kind, row_limit_reached, unknown_field, required_field_missing, type_mismatch, not_a_member, readonly_field, invalid_field_format, row_policy_denies · 429 slow down
data.insert_rows
Import records — Writes a batch of records into a table, all of them or none.
Needs data:import · reaches outside (sends, publishes or charges) · asks a person to confirm when Era runs it
https://app.getera.io/api/v1/actions/data.insert_rowsInput
| Field | Type | Required | Notes |
|---|---|---|---|
dataTableId | uuid | yes | Table · id of data_table |
rows | object / array | yes | Records |
dryRun | boolean | Only check the file | |
skipInvalid | boolean | Skip rows with problems |
Preconditions
The action is refused with 409 and one of these codes:
| Code | Refused when |
|---|---|
table_not_found | The table must exist. |
wrong_table_kind | Extension tables have no rows of their own. |
nothing_to_import | The batch must contain something. |
import_batch_too_large | A batch is capped, and the client splits the file. |
row_limit_reached | The whole batch must fit under the table’s ceiling. |
unknown_field | Every column in the file must be a field on the table. |
required_field_missing | Required fields must be filled in. |
type_mismatch | A value must be readable as its field’s type. |
not_a_member | A User field holds one of this workspace’s members. |
readonly_field | A read-only field cannot be written. |
invalid_field_format | A value must match its field format when validation is enabled. |
Events it publishes: data.rows_imported
What it writes: data_row (insert) — Writes the batch
curl -X POST https://app.getera.io/api/v1/actions/data.insert_rows \
-H "Authorization: Bearer $ERA_API_KEY" \
-H "Content-Type: application/json" \
-H "Idempotency-Key: $(uuidgen)" \
-d '{"dataTableId":"DATA_TABLE_ID","rows":{}}'{
"ok": true,
"result": "…",
"events": [
"data.rows_imported"
]
}import { createEra } from "@getera/sdk"
const era = createEra({ apiKey: process.env.ERA_API_KEY })
const res = await era.actions.run("data.insert_rows", {
dataTableId: "DATA_TABLE_ID",
rows: {}
})era data insert_rows --data '{"dataTableId":"DATA_TABLE_ID","rows":{}}'{
"name": "era__data__insert_rows",
"arguments": {
"dataTableId": "DATA_TABLE_ID",
"rows": {}
}
}Errors: 401 no or expired credential · 403 the credential does not hold data:import · 404 the record or module is outside what it may reach · 422 invalid input (problems[]) · 409 table_not_found, wrong_table_kind, nothing_to_import, import_batch_too_large, row_limit_reached, unknown_field, required_field_missing, type_mismatch, not_a_member, readonly_field, invalid_field_format · 429 slow down
data.link_records
Link records — Links records of the other table to this record through one link field.
Needs data:write · changes data
https://app.getera.io/api/v1/actions/data.link_recordsInput
| Field | Type | Required | Notes |
|---|---|---|---|
columnId | uuid | yes | Link field · id of data_column |
rowId | uuid | yes | Record · id of data_row |
targetRowIds | object / array | yes | Records to link |
Preconditions
The action is refused with 409 and one of these codes:
| Code | Refused when |
|---|---|
column_not_found | The link field must exist. |
not_a_link_field | The field must be a link to another table. |
row_not_found | The record must be in this table. |
row_policy_denies | A row rule can put a record out of your reach. |
link_target_invalid | Every record linked must be in the other table. |
link_cardinality | A has-many child has one parent; a one-to-one has one of each. |
Events it publishes: data.records_linked
What it writes: data_row_link (insert) — Writes the links
curl -X POST https://app.getera.io/api/v1/actions/data.link_records \
-H "Authorization: Bearer $ERA_API_KEY" \
-H "Content-Type: application/json" \
-H "Idempotency-Key: $(uuidgen)" \
-d '{"columnId":"DATA_COLUMN_ID","rowId":"DATA_ROW_ID","targetRowIds":{}}'{
"ok": true,
"result": "…",
"events": [
"data.records_linked"
]
}import { createEra } from "@getera/sdk"
const era = createEra({ apiKey: process.env.ERA_API_KEY })
const res = await era.actions.run("data.link_records", {
columnId: "DATA_COLUMN_ID",
rowId: "DATA_ROW_ID",
targetRowIds: {}
})era data link_records --data '{"columnId":"DATA_COLUMN_ID","rowId":"DATA_ROW_ID","targetRowIds":{}}'{
"name": "era__data__link_records",
"arguments": {
"columnId": "DATA_COLUMN_ID",
"rowId": "DATA_ROW_ID",
"targetRowIds": {}
}
}Errors: 401 no or expired credential · 403 the credential does not hold data:write · 404 the record or module is outside what it may reach · 422 invalid input (problems[]) · 409 column_not_found, not_a_link_field, row_not_found, row_policy_denies, link_target_invalid, link_cardinality · 429 slow down
data.move_row
Move a record — Puts a record in another place in its table’s manual order — right after another record, or at the top.
Needs data:write · changes data
https://app.getera.io/api/v1/actions/data.move_rowInput
| Field | Type | Required | Notes |
|---|---|---|---|
id | uuid | yes | Record · id of data_row |
afterId | uuid | After record · Empty to move it to the top. · id of data_row |
Preconditions
The action is refused with 409 and one of these codes:
| Code | Refused when |
|---|---|
row_not_found | The record, and the one it goes after, must exist in the same table. |
row_policy_denies | A row rule can put a record out of your reach. |
Events it publishes: data.row_updated
What it writes: data_row (update) — Sets the record’s manual order
curl -X POST https://app.getera.io/api/v1/actions/data.move_row \
-H "Authorization: Bearer $ERA_API_KEY" \
-H "Content-Type: application/json" \
-H "Idempotency-Key: $(uuidgen)" \
-d '{"id":"DATA_ROW_ID"}'{
"ok": true,
"result": "…",
"events": [
"data.row_updated"
]
}import { createEra } from "@getera/sdk"
const era = createEra({ apiKey: process.env.ERA_API_KEY })
const res = await era.actions.run("data.move_row", {
id: "DATA_ROW_ID"
})era data move_row \
--id "DATA_ROW_ID"{
"name": "era__data__move_row",
"arguments": {
"id": "DATA_ROW_ID"
}
}Errors: 401 no or expired credential · 403 the credential does not hold data:write · 404 the record or module is outside what it may reach · 422 invalid input (problems[]) · 409 row_not_found, row_policy_denies · 429 slow down
data.move_table
Move a table to a group — Puts a table in a group, or takes it out of one.
Needs data:manage · changes data
https://app.getera.io/api/v1/actions/data.move_tableInput
| Field | Type | Required | Notes |
|---|---|---|---|
id | uuid | yes | Table · id of data_table |
groupId | uuid | Group |
Preconditions
The action is refused with 409 and one of these codes:
| Code | Refused when |
|---|---|
table_not_found | The table must exist. |
table_group_not_found | The group must exist. |
Events it publishes: data.table_moved
What it writes: data_table (update) — Sets the table’s group
curl -X POST https://app.getera.io/api/v1/actions/data.move_table \
-H "Authorization: Bearer $ERA_API_KEY" \
-H "Content-Type: application/json" \
-H "Idempotency-Key: $(uuidgen)" \
-d '{"id":"DATA_TABLE_ID"}'{
"ok": true,
"result": "…",
"events": [
"data.table_moved"
]
}import { createEra } from "@getera/sdk"
const era = createEra({ apiKey: process.env.ERA_API_KEY })
const res = await era.actions.run("data.move_table", {
id: "DATA_TABLE_ID"
})era data move_table \
--id "DATA_TABLE_ID"{
"name": "era__data__move_table",
"arguments": {
"id": "DATA_TABLE_ID"
}
}Errors: 401 no or expired credential · 403 the credential does not hold data:manage · 404 the record or module is outside what it may reach · 422 invalid input (problems[]) · 409 table_not_found, table_group_not_found · 429 slow down
data.press_button
Press a button — Starts the workflows that listen to this button, with the record it was pressed on.
Needs data:write · changes data
https://app.getera.io/api/v1/actions/data.press_buttonInput
| Field | Type | Required | Notes |
|---|---|---|---|
columnId | uuid | yes | Button · id of data_column |
rowId | uuid | yes | Record · id of data_row |
Preconditions
The action is refused with 409 and one of these codes:
| Code | Refused when |
|---|---|
column_not_found | The button must exist. |
not_a_button | Only a button that starts a workflow can be pressed. |
row_not_found | The record must exist and be visible to you. |
Events it publishes: data.button_pressed
curl -X POST https://app.getera.io/api/v1/actions/data.press_button \
-H "Authorization: Bearer $ERA_API_KEY" \
-H "Content-Type: application/json" \
-H "Idempotency-Key: $(uuidgen)" \
-d '{"columnId":"DATA_COLUMN_ID","rowId":"DATA_ROW_ID"}'{
"ok": true,
"result": "…",
"events": [
"data.button_pressed"
]
}import { createEra } from "@getera/sdk"
const era = createEra({ apiKey: process.env.ERA_API_KEY })
const res = await era.actions.run("data.press_button", {
columnId: "DATA_COLUMN_ID",
rowId: "DATA_ROW_ID"
})era data press_button \
--column-id "DATA_COLUMN_ID" \
--row-id "DATA_ROW_ID"{
"name": "era__data__press_button",
"arguments": {
"columnId": "DATA_COLUMN_ID",
"rowId": "DATA_ROW_ID"
}
}Errors: 401 no or expired credential · 403 the credential does not hold data:write · 404 the record or module is outside what it may reach · 422 invalid input (problems[]) · 409 column_not_found, not_a_button, row_not_found · 429 slow down
data.purge_rows
Clear a table’s records — Throws away everything stored against a table, keeping the fields.
Needs data:delete · removes or cannot be undone · asks a person to confirm when Era runs it
https://app.getera.io/api/v1/actions/data.purge_rowsInput
| Field | Type | Required | Notes |
|---|---|---|---|
id | uuid | yes | Table · id of data_table |
Preconditions
The action is refused with 409 and one of these codes:
| Code | Refused when |
|---|---|
table_not_found | The table must exist. |
nothing_to_purge | There must be something to clear. |
referenced_by_relation | A link set to block deletion stops the purge. |
Events it publishes: data.rows_purged
What it writes: data_row (delete) — Deletes the rows; data_value (delete) — Deletes the values
curl -X POST https://app.getera.io/api/v1/actions/data.purge_rows \
-H "Authorization: Bearer $ERA_API_KEY" \
-H "Content-Type: application/json" \
-H "Idempotency-Key: $(uuidgen)" \
-d '{"id":"DATA_TABLE_ID"}'{
"ok": true,
"result": "…",
"events": [
"data.rows_purged"
]
}import { createEra } from "@getera/sdk"
const era = createEra({ apiKey: process.env.ERA_API_KEY })
const res = await era.actions.run("data.purge_rows", {
id: "DATA_TABLE_ID"
})era data purge_rows \
--id "DATA_TABLE_ID"{
"name": "era__data__purge_rows",
"arguments": {
"id": "DATA_TABLE_ID"
}
}Errors: 401 no or expired credential · 403 the credential does not hold data:delete · 404 the record or module is outside what it may reach · 422 invalid input (problems[]) · 409 table_not_found, nothing_to_purge, referenced_by_relation · 429 slow down
data.remove_column
Remove a field — Deletes a field definition and everything recorded against it.
Needs data:delete · removes or cannot be undone · asks a person to confirm when Era runs it
https://app.getera.io/api/v1/actions/data.remove_columnInput
| Field | Type | Required | Notes |
|---|---|---|---|
id | uuid | yes | Field · id of data_column |
Preconditions
The action is refused with 409 and one of these codes:
| Code | Refused when |
|---|---|
column_not_found | The field must exist. |
is_primary_display | The field a record is named by cannot be removed. |
used_by_saved_view | A saved view filtering on it would silently empty. |
used_by_formula | A formula reading it would go blank for ever. |
used_by_relation | A lookup or rollup through it would lose its source. |
Events it publishes: data.column_removed
What it writes: data_column (delete) — Deletes the field and its values
curl -X POST https://app.getera.io/api/v1/actions/data.remove_column \
-H "Authorization: Bearer $ERA_API_KEY" \
-H "Content-Type: application/json" \
-H "Idempotency-Key: $(uuidgen)" \
-d '{"id":"DATA_COLUMN_ID"}'{
"ok": true,
"result": "…",
"events": [
"data.column_removed"
]
}import { createEra } from "@getera/sdk"
const era = createEra({ apiKey: process.env.ERA_API_KEY })
const res = await era.actions.run("data.remove_column", {
id: "DATA_COLUMN_ID"
})era data remove_column \
--id "DATA_COLUMN_ID"{
"name": "era__data__remove_column",
"arguments": {
"id": "DATA_COLUMN_ID"
}
}Errors: 401 no or expired credential · 403 the credential does not hold data:delete · 404 the record or module is outside what it may reach · 422 invalid input (problems[]) · 409 column_not_found, is_primary_display, used_by_saved_view, used_by_formula, used_by_relation · 429 slow down
data.rename_table
Edit a table — Changes what a table is called and how it is described.
Needs data:manage · changes data
https://app.getera.io/api/v1/actions/data.rename_tableInput
| Field | Type | Required | Notes |
|---|---|---|---|
id | uuid | yes | Table · id of data_table |
code | string | System name · max 60 | |
title | string | Display name · max 200 | |
description | string | Description · max 2000 | |
icon | string | Icon · max 40 |
Preconditions
The action is refused with 409 and one of these codes:
| Code | Refused when |
|---|---|
table_not_found | The table must exist. |
code_taken | Two tables may not share a system name. |
invalid_code | The system name must be snake_case. |
no_change | Something has to change. |
Events it publishes: data.table_renamed
What it writes: data_table (update) — Renames the table
curl -X POST https://app.getera.io/api/v1/actions/data.rename_table \
-H "Authorization: Bearer $ERA_API_KEY" \
-H "Content-Type: application/json" \
-H "Idempotency-Key: $(uuidgen)" \
-d '{"id":"DATA_TABLE_ID"}'{
"ok": true,
"result": "…",
"events": [
"data.table_renamed"
]
}import { createEra } from "@getera/sdk"
const era = createEra({ apiKey: process.env.ERA_API_KEY })
const res = await era.actions.run("data.rename_table", {
id: "DATA_TABLE_ID"
})era data rename_table \
--id "DATA_TABLE_ID"{
"name": "era__data__rename_table",
"arguments": {
"id": "DATA_TABLE_ID"
}
}Errors: 401 no or expired credential · 403 the credential does not hold data:manage · 404 the record or module is outside what it may reach · 422 invalid input (problems[]) · 409 table_not_found, code_taken, invalid_code, no_change · 429 slow down
data.rename_table_group
Rename a table group — Changes a group’s name or its place in the list.
Needs data:manage · changes data
https://app.getera.io/api/v1/actions/data.rename_table_groupInput
| Field | Type | Required | Notes |
|---|---|---|---|
id | uuid | yes | Group |
name | string | Name · max 120 | |
sortOrder | number | Position |
Preconditions
The action is refused with 409 and one of these codes:
| Code | Refused when |
|---|---|
table_group_not_found | The group must exist. |
group_name_required | A group needs a name. |
group_name_taken | Two groups may not share a name. |
Events it publishes: data.table_group_renamed
What it writes: data_table_group (update) — Renames the group
curl -X POST https://app.getera.io/api/v1/actions/data.rename_table_group \
-H "Authorization: Bearer $ERA_API_KEY" \
-H "Content-Type: application/json" \
-H "Idempotency-Key: $(uuidgen)" \
-d '{"id":"ID_ID"}'{
"ok": true,
"result": "…",
"events": [
"data.table_group_renamed"
]
}import { createEra } from "@getera/sdk"
const era = createEra({ apiKey: process.env.ERA_API_KEY })
const res = await era.actions.run("data.rename_table_group", {
id: "ID_ID"
})era data rename_table_group \
--id "ID_ID"{
"name": "era__data__rename_table_group",
"arguments": {
"id": "ID_ID"
}
}Errors: 401 no or expired credential · 403 the credential does not hold data:manage · 404 the record or module is outside what it may reach · 422 invalid input (problems[]) · 409 table_group_not_found, group_name_required, group_name_taken · 429 slow down
data.set_display_field
Set as display value — Makes a field the one each record is named by — in link chips, headings and the first column.
Needs data:manage · changes data
https://app.getera.io/api/v1/actions/data.set_display_fieldInput
| Field | Type | Required | Notes |
|---|---|---|---|
id | uuid | yes | Field · id of data_column |
Preconditions
The action is refused with 409 and one of these codes:
| Code | Refused when |
|---|---|
column_not_found | The field must exist. |
display_type_unsupported | A choice, file, link or computed field cannot name a record. |
Events it publishes: data.column_changed
What it writes: data_column (update) — Moves the display flag to this field
curl -X POST https://app.getera.io/api/v1/actions/data.set_display_field \
-H "Authorization: Bearer $ERA_API_KEY" \
-H "Content-Type: application/json" \
-H "Idempotency-Key: $(uuidgen)" \
-d '{"id":"DATA_COLUMN_ID"}'{
"ok": true,
"result": "…",
"events": [
"data.column_changed"
]
}import { createEra } from "@getera/sdk"
const era = createEra({ apiKey: process.env.ERA_API_KEY })
const res = await era.actions.run("data.set_display_field", {
id: "DATA_COLUMN_ID"
})era data set_display_field \
--id "DATA_COLUMN_ID"{
"name": "era__data__set_display_field",
"arguments": {
"id": "DATA_COLUMN_ID"
}
}Errors: 401 no or expired credential · 403 the credential does not hold data:manage · 404 the record or module is outside what it may reach · 422 invalid input (problems[]) · 409 column_not_found, display_type_unsupported · 429 slow down
data.set_field
Set a custom field — Writes one custom field on a record, named by its key or label; a choice can be named by its title.
Needs data:write · changes data
https://app.getera.io/api/v1/actions/data.set_fieldInput
| Field | Type | Required | Notes |
|---|---|---|---|
recordType | string | yes | Record type · max 60 |
recordId | uuid | yes | Record |
field | string | yes | Field · max 200 |
value | string | Value · Empty clears the field. Several choices: "A, B". · max 5000 |
Preconditions
The action is refused with 409 and one of these codes:
| Code | Refused when |
|---|---|
field_not_found | The record type must have a field by that key or label. |
option_not_available | A choice must be one the field offers. |
extends_module_disabled | A switched-off module takes no new values. |
required_field_missing | A required field cannot be cleared. |
type_mismatch | A value must be readable as its field’s type. |
readonly_field | A read-only field cannot be written. |
not_a_member | A person field must name a member of this workspace. |
invalid_field_format | A value must match its field format when validation is enabled. |
Events it publishes: data.record_values_changed
What it writes: data_value (upsert) — Writes the value
curl -X POST https://app.getera.io/api/v1/actions/data.set_field \
-H "Authorization: Bearer $ERA_API_KEY" \
-H "Content-Type: application/json" \
-H "Idempotency-Key: $(uuidgen)" \
-d '{"recordType":"Record type","recordId":"RECORD_ID","field":"Field"}'{
"ok": true,
"result": "…",
"events": [
"data.record_values_changed"
]
}import { createEra } from "@getera/sdk"
const era = createEra({ apiKey: process.env.ERA_API_KEY })
const res = await era.actions.run("data.set_field", {
recordType: "Record type",
recordId: "RECORD_ID",
field: "Field"
})era data set_field \
--record-type "Record type" \
--record-id "RECORD_ID" \
--field "Field"{
"name": "era__data__set_field",
"arguments": {
"recordType": "Record type",
"recordId": "RECORD_ID",
"field": "Field"
}
}Errors: 401 no or expired credential · 403 the credential does not hold data:write · 404 the record or module is outside what it may reach · 422 invalid input (problems[]) · 409 field_not_found, option_not_available, extends_module_disabled, required_field_missing, type_mismatch, readonly_field, not_a_member, invalid_field_format · 429 slow down
data.set_record_values
Fill in extra fields — Writes one field group’s values onto another module’s record.
Needs data:write · changes data
https://app.getera.io/api/v1/actions/data.set_record_valuesInput
| Field | Type | Required | Notes |
|---|---|---|---|
dataTableId | uuid | yes | Field group · id of data_table |
recordType | string | yes | Record type · max 60 |
recordId | uuid | yes | Record |
values | object / array | yes | Values |
complete | boolean | Whole form · The record is being created or saved as a whole: every required field must be answered (a default counts). |
Preconditions
The action is refused with 409 and one of these codes:
| Code | Refused when |
|---|---|
table_not_found | The field group must exist. |
wrong_table_kind | A table that owns its rows takes a row, not values. |
not_a_member | A person field must name a member of this workspace. |
record_type_mismatch | The group must belong to that kind of record. |
extends_module_disabled | A switched-off module takes no new values. |
unknown_field | Every key must be a field in the group. |
required_field_missing | Required fields must be filled in. |
type_mismatch | A value must be readable as its field’s type. |
readonly_field | A read-only field cannot be written. |
option_not_available | A choice must be one the field still offers. |
invalid_field_format | A value must match its field format when validation is enabled. |
Events it publishes: data.record_values_changed
What it writes: data_value (upsert) — Writes the values
curl -X POST https://app.getera.io/api/v1/actions/data.set_record_values \
-H "Authorization: Bearer $ERA_API_KEY" \
-H "Content-Type: application/json" \
-H "Idempotency-Key: $(uuidgen)" \
-d '{"dataTableId":"DATA_TABLE_ID","recordType":"Record type","recordId":"RECORD_ID","values":{}}'{
"ok": true,
"result": "…",
"events": [
"data.record_values_changed"
]
}import { createEra } from "@getera/sdk"
const era = createEra({ apiKey: process.env.ERA_API_KEY })
const res = await era.actions.run("data.set_record_values", {
dataTableId: "DATA_TABLE_ID",
recordType: "Record type",
recordId: "RECORD_ID",
values: {}
})era data set_record_values --data '{"dataTableId":"DATA_TABLE_ID","recordType":"Record type","recordId":"RECORD_ID","values":{}}'{
"name": "era__data__set_record_values",
"arguments": {
"dataTableId": "DATA_TABLE_ID",
"recordType": "Record type",
"recordId": "RECORD_ID",
"values": {}
}
}Errors: 401 no or expired credential · 403 the credential does not hold data:write · 404 the record or module is outside what it may reach · 422 invalid input (problems[]) · 409 table_not_found, wrong_table_kind, not_a_member, record_type_mismatch, extends_module_disabled, unknown_field, required_field_missing, type_mismatch, readonly_field, option_not_available, invalid_field_format · 429 slow down
data.set_row_policy
Narrow who sees which rows — Writes one row rule — its condition and everyone it applies to — in one go.
Needs data:manage · changes data
https://app.getera.io/api/v1/actions/data.set_row_policyInput
| Field | Type | Required | Notes |
|---|---|---|---|
dataTableId | uuid | yes | Table · id of data_table |
policyId | uuid | Rule | |
name | string | yes | Name · max 120 |
permission | string (enum) | yes | Applies to · Allowed values: read, write, delete |
conditions | object / array | Condition | |
subjects | object / array | yes | Who it is for |
isActive | boolean | Active |
Preconditions
The action is refused with 409 and one of these codes:
| Code | Refused when |
|---|---|
table_not_found | The table must exist. |
wrong_table_kind | A field group has no rows of its own to narrow. |
title_required | A rule refusing an edit has to be nameable. |
policy_needs_subject | A rule with nobody on it would hide the table. |
subject_not_found | A subject must be a real role or workspace member. |
invalid_filter | A condition that cannot compile is refused at save time. |
unknown_field | A condition may only name fields the table has. |
policy_not_found | Editing a rule needs the rule to exist. |
name_taken | Two rules on one table may not share a name. |
Events it publishes: data.row_policy_changed
What it writes: data_table_policy (upsert) — Writes the rule; data_table_policy_subject (upsert) — Names who it is for
curl -X POST https://app.getera.io/api/v1/actions/data.set_row_policy \
-H "Authorization: Bearer $ERA_API_KEY" \
-H "Content-Type: application/json" \
-H "Idempotency-Key: $(uuidgen)" \
-d '{"dataTableId":"DATA_TABLE_ID","name":"Name","permission":"read","subjects":{}}'{
"ok": true,
"result": "…",
"events": [
"data.row_policy_changed"
]
}import { createEra } from "@getera/sdk"
const era = createEra({ apiKey: process.env.ERA_API_KEY })
const res = await era.actions.run("data.set_row_policy", {
dataTableId: "DATA_TABLE_ID",
name: "Name",
permission: "read",
subjects: {}
})era data set_row_policy --data '{"dataTableId":"DATA_TABLE_ID","name":"Name","permission":"read","subjects":{}}'{
"name": "era__data__set_row_policy",
"arguments": {
"dataTableId": "DATA_TABLE_ID",
"name": "Name",
"permission": "read",
"subjects": {}
}
}Errors: 401 no or expired credential · 403 the credential does not hold data:manage · 404 the record or module is outside what it may reach · 422 invalid input (problems[]) · 409 table_not_found, wrong_table_kind, title_required, policy_needs_subject, subject_not_found, invalid_filter, unknown_field, policy_not_found, name_taken · 429 slow down
data.set_select_options
Edit the choices — Rewrites a choice field’s option list, refusing to drop one somebody has answered.
Needs data:manage · changes data
https://app.getera.io/api/v1/actions/data.set_select_optionsInput
| Field | Type | Required | Notes |
|---|---|---|---|
dataColumnId | uuid | yes | Field · id of data_column |
options | object / array | yes | Choices |
Preconditions
The action is refused with 409 and one of these codes:
| Code | Refused when |
|---|---|
column_not_found | The field must exist. |
column_not_enum | The field must be one that offers choices. |
option_in_use | An option records still answer is closed, not deleted. |
Events it publishes: data.options_changed
What it writes: data_select_option (upsert) — Writes the option list
curl -X POST https://app.getera.io/api/v1/actions/data.set_select_options \
-H "Authorization: Bearer $ERA_API_KEY" \
-H "Content-Type: application/json" \
-H "Idempotency-Key: $(uuidgen)" \
-d '{"dataColumnId":"DATA_COLUMN_ID","options":{}}'{
"ok": true,
"result": "…",
"events": [
"data.options_changed"
]
}import { createEra } from "@getera/sdk"
const era = createEra({ apiKey: process.env.ERA_API_KEY })
const res = await era.actions.run("data.set_select_options", {
dataColumnId: "DATA_COLUMN_ID",
options: {}
})era data set_select_options --data '{"dataColumnId":"DATA_COLUMN_ID","options":{}}'{
"name": "era__data__set_select_options",
"arguments": {
"dataColumnId": "DATA_COLUMN_ID",
"options": {}
}
}Errors: 401 no or expired credential · 403 the credential does not hold data:manage · 404 the record or module is outside what it may reach · 422 invalid input (problems[]) · 409 column_not_found, column_not_enum, option_in_use · 429 slow down
data.set_table_permission
Change who may use a table — Grants or removes one permission on one table for one role.
Needs data:manage · changes data
https://app.getera.io/api/v1/actions/data.set_table_permissionInput
| Field | Type | Required | Notes |
|---|---|---|---|
dataTableId | uuid | yes | Table · id of data_table |
roleId | uuid | yes | Role |
permission | string (enum) | yes | Permission · Allowed values: TABLE_RECORD_READ, TABLE_RECORD_ADD, TABLE_RECORD_UPDATE, TABLE_RECORD_DELETE, FIELD_EDIT |
granted | boolean | yes | Granted |
Preconditions
The action is refused with 409 and one of these codes:
| Code | Refused when |
|---|---|
table_not_found | The table must exist. |
role_not_found | The role must exist. |
cannot_lock_out_owner | The owner keeps access, or nobody can undo it. |
Events it publishes: data.permission_changed
What it writes: data_table_permission (upsert) — Writes the permission; data_table_permission_subject (upsert) — Names the role it applies to
curl -X POST https://app.getera.io/api/v1/actions/data.set_table_permission \
-H "Authorization: Bearer $ERA_API_KEY" \
-H "Content-Type: application/json" \
-H "Idempotency-Key: $(uuidgen)" \
-d '{"dataTableId":"DATA_TABLE_ID","roleId":"ROLE_ID","permission":"TABLE_RECORD_READ","granted":true}'{
"ok": true,
"result": "…",
"events": [
"data.permission_changed"
]
}import { createEra } from "@getera/sdk"
const era = createEra({ apiKey: process.env.ERA_API_KEY })
const res = await era.actions.run("data.set_table_permission", {
dataTableId: "DATA_TABLE_ID",
roleId: "ROLE_ID",
permission: "TABLE_RECORD_READ",
granted: true
})era data set_table_permission \
--data-table-id "DATA_TABLE_ID" \
--role-id "ROLE_ID" \
--permission "TABLE_RECORD_READ" \
--granted true{
"name": "era__data__set_table_permission",
"arguments": {
"dataTableId": "DATA_TABLE_ID",
"roleId": "ROLE_ID",
"permission": "TABLE_RECORD_READ",
"granted": true
}
}Errors: 401 no or expired credential · 403 the credential does not hold data:manage · 404 the record or module is outside what it may reach · 422 invalid input (problems[]) · 409 table_not_found, role_not_found, cannot_lock_out_owner · 429 slow down
data.unlink_records
Unlink records — Removes links from this record. The linked records themselves stay.
Needs data:write · changes data
https://app.getera.io/api/v1/actions/data.unlink_recordsInput
| Field | Type | Required | Notes |
|---|---|---|---|
columnId | uuid | yes | Link field · id of data_column |
rowId | uuid | yes | Record · id of data_row |
targetRowIds | object / array | yes | Records to unlink |
Preconditions
The action is refused with 409 and one of these codes:
| Code | Refused when |
|---|---|
column_not_found | The link field must exist. |
not_a_link_field | The field must be a link to another table. |
row_not_found | The record must be in this table. |
row_policy_denies | A row rule can put a record out of your reach. |
nothing_to_unlink | At least one of those records must be linked here. |
Events it publishes: data.records_unlinked
What it writes: data_row_link (delete) — Removes the links
curl -X POST https://app.getera.io/api/v1/actions/data.unlink_records \
-H "Authorization: Bearer $ERA_API_KEY" \
-H "Content-Type: application/json" \
-H "Idempotency-Key: $(uuidgen)" \
-d '{"columnId":"DATA_COLUMN_ID","rowId":"DATA_ROW_ID","targetRowIds":{}}'{
"ok": true,
"result": "…",
"events": [
"data.records_unlinked"
]
}import { createEra } from "@getera/sdk"
const era = createEra({ apiKey: process.env.ERA_API_KEY })
const res = await era.actions.run("data.unlink_records", {
columnId: "DATA_COLUMN_ID",
rowId: "DATA_ROW_ID",
targetRowIds: {}
})era data unlink_records --data '{"columnId":"DATA_COLUMN_ID","rowId":"DATA_ROW_ID","targetRowIds":{}}'{
"name": "era__data__unlink_records",
"arguments": {
"columnId": "DATA_COLUMN_ID",
"rowId": "DATA_ROW_ID",
"targetRowIds": {}
}
}Errors: 401 no or expired credential · 403 the credential does not hold data:write · 404 the record or module is outside what it may reach · 422 invalid input (problems[]) · 409 column_not_found, not_a_link_field, row_not_found, row_policy_denies, nothing_to_unlink · 429 slow down
data.update_column
Edit a field — Changes a field’s label, help text, colour, order and flags.
Needs data:manage · changes data
https://app.getera.io/api/v1/actions/data.update_columnInput
| Field | Type | Required | Notes |
|---|---|---|---|
id | uuid | yes | Field · id of data_column |
title | string | Label · max 200 | |
uiHint | string | Shown as · max 30 | |
unit | string | Unit · max 30 | |
isRequired | boolean | Required | |
isFilterable | boolean | Filterable | |
isListable | boolean | Available as a column | |
isPublic | boolean | Visible on the storefront | |
helpText | string | Help text · max 255 | |
description | string | Description · max 2000 | |
color | string | Colour · max 7 | |
defaultValue | string | Default · max 500 | |
sortOrder | number | Order | |
display | object / array | How it is shown | |
validation | object / array | Validation | |
archived | boolean | Archived · Hidden from forms, lists and filters; its answers are kept. |
Preconditions
The action is refused with 409 and one of these codes:
| Code | Refused when |
|---|---|
column_not_found | The field must exist. |
required_without_default_on_existing_rows | Making a field required on records that already exist needs a default. |
invalid_display_option | A display option must be one the field type has, with a valid value. |
Events it publishes: data.column_changed
What it writes: data_column (update) — Edits the field
curl -X POST https://app.getera.io/api/v1/actions/data.update_column \
-H "Authorization: Bearer $ERA_API_KEY" \
-H "Content-Type: application/json" \
-H "Idempotency-Key: $(uuidgen)" \
-d '{"id":"DATA_COLUMN_ID"}'{
"ok": true,
"result": "…",
"events": [
"data.column_changed"
]
}import { createEra } from "@getera/sdk"
const era = createEra({ apiKey: process.env.ERA_API_KEY })
const res = await era.actions.run("data.update_column", {
id: "DATA_COLUMN_ID"
})era data update_column \
--id "DATA_COLUMN_ID"{
"name": "era__data__update_column",
"arguments": {
"id": "DATA_COLUMN_ID"
}
}Errors: 401 no or expired credential · 403 the credential does not hold data:manage · 404 the record or module is outside what it may reach · 422 invalid input (problems[]) · 409 column_not_found, required_without_default_on_existing_rows, invalid_display_option · 429 slow down
data.update_computed_field
Edit a computed field — Changes a formula, a rollup’s summary, the field a lookup or a code reads, or what a button does.
Needs data:manage · changes data
https://app.getera.io/api/v1/actions/data.update_computed_fieldInput
| Field | Type | Required | Notes |
|---|---|---|---|
id | uuid | yes | Field · id of data_column |
title | string | Name · max 200 | |
formula | string | Formula · max 2000 | |
fn | string (enum) | Summary · Allowed values: count, sum, avg, min, max, countDistinct, sumDistinct, avgDistinct | |
targetColumnId | uuid | Field of the linked table · id of data_column | |
sourceColumnId | uuid | Field the code carries · id of data_column | |
buttonAction | string (enum) | When clicked · Allowed values: url, workflow | |
buttonUrl | string | Link · max 2000 | |
buttonLabel | string | Button text · max 60 | |
buttonColor | string | Button colour · max 7 |
Preconditions
The action is refused with 409 and one of these codes:
| Code | Refused when |
|---|---|
column_not_found | The field must exist. |
not_a_computed_field | A stored field is edited with the ordinary field editor. |
invalid_button_url | A link button needs a web address to open. |
invalid_formula | A formula that cannot be read is refused at save time. |
formula_cycle | A formula may not end up reading itself. |
Events it publishes: data.column_changed
What it writes: data_column (update) — Rewrites what the field computes
curl -X POST https://app.getera.io/api/v1/actions/data.update_computed_field \
-H "Authorization: Bearer $ERA_API_KEY" \
-H "Content-Type: application/json" \
-H "Idempotency-Key: $(uuidgen)" \
-d '{"id":"DATA_COLUMN_ID"}'{
"ok": true,
"result": "…",
"events": [
"data.column_changed"
]
}import { createEra } from "@getera/sdk"
const era = createEra({ apiKey: process.env.ERA_API_KEY })
const res = await era.actions.run("data.update_computed_field", {
id: "DATA_COLUMN_ID"
})era data update_computed_field \
--id "DATA_COLUMN_ID"{
"name": "era__data__update_computed_field",
"arguments": {
"id": "DATA_COLUMN_ID"
}
}Errors: 401 no or expired credential · 403 the credential does not hold data:manage · 404 the record or module is outside what it may reach · 422 invalid input (problems[]) · 409 column_not_found, not_a_computed_field, invalid_button_url, invalid_formula, formula_cycle · 429 slow down
data.update_row
Edit a record — Merges values into a row — the fields it does not mention keep what they had, and a field sent as null is cleared.
Needs data:write · changes data
https://app.getera.io/api/v1/actions/data.update_rowInput
| Field | Type | Required | Notes |
|---|---|---|---|
id | uuid | yes | Record · id of data_row |
data | object / array | yes | Values |
Preconditions
The action is refused with 409 and one of these codes:
| Code | Refused when |
|---|---|
row_not_found | The record must exist. |
unknown_field | Every key must be a field on the table. |
type_mismatch | A value must be readable as its field’s type. |
not_a_member | A User field holds one of this workspace’s members. |
readonly_field | A read-only field cannot be written. |
required_field_missing | A required field cannot be cleared. |
row_policy_denies | A row rule can put a record out of your reach. |
invalid_filter | A row rule whose condition cannot compile blocks, never skips. |
invalid_field_format | A value must match its field format when validation is enabled. |
Events it publishes: data.row_updated
What it writes: data_row (update) — Merges the values in; a null clears the field
curl -X POST https://app.getera.io/api/v1/actions/data.update_row \
-H "Authorization: Bearer $ERA_API_KEY" \
-H "Content-Type: application/json" \
-H "Idempotency-Key: $(uuidgen)" \
-d '{"id":"DATA_ROW_ID","data":{}}'{
"ok": true,
"result": "…",
"events": [
"data.row_updated"
]
}import { createEra } from "@getera/sdk"
const era = createEra({ apiKey: process.env.ERA_API_KEY })
const res = await era.actions.run("data.update_row", {
id: "DATA_ROW_ID",
data: {}
})era data update_row --data '{"id":"DATA_ROW_ID","data":{}}'{
"name": "era__data__update_row",
"arguments": {
"id": "DATA_ROW_ID",
"data": {}
}
}Errors: 401 no or expired credential · 403 the credential does not hold data:write · 404 the record or module is outside what it may reach · 422 invalid input (problems[]) · 409 row_not_found, unknown_field, type_mismatch, not_a_member, readonly_field, required_field_missing, row_policy_denies, invalid_filter, invalid_field_format · 429 slow down
data.update_rows
Edit several records — Gives selected or filtered records the same values, or pastes a block of cells — all of it or none.
Needs data:write · reaches outside (sends, publishes or charges) · asks a person to confirm when Era runs it
https://app.getera.io/api/v1/actions/data.update_rowsInput
| Field | Type | Required | Notes |
|---|---|---|---|
dataTableId | uuid | yes | Table · id of data_table |
rows | object / array | Per-record values | |
ids | object / array | Records | |
conditions | object / array | Filter | |
data | object / array | Values |
Preconditions
The action is refused with 409 and one of these codes:
| Code | Refused when |
|---|---|
table_not_found | The table must exist. |
wrong_table_kind | A field group has no rows of its own. |
nothing_to_update | There has to be something to change. |
filter_matches_nothing | The selection or filter must reach at least one record. |
filter_too_broad | A bulk edit needs a selection or a filter, and is capped. |
row_not_found | Every record pasted into must be in this table. |
row_policy_denies | Every record touched must be one your row rules let you edit. |
invalid_filter | A filter that cannot compile is refused. |
unknown_field | Every key must be a field on the table. |
type_mismatch | A value must be readable as its field’s type. |
readonly_field | A read-only or computed field cannot be written. |
invalid_field_format | A value must match its field format when validation is enabled. |
not_a_member | A User field holds one of this workspace’s members. |
Events it publishes: data.rows_updated
What it writes: data_row (update) — Merges the values into each record
curl -X POST https://app.getera.io/api/v1/actions/data.update_rows \
-H "Authorization: Bearer $ERA_API_KEY" \
-H "Content-Type: application/json" \
-H "Idempotency-Key: $(uuidgen)" \
-d '{"dataTableId":"DATA_TABLE_ID"}'{
"ok": true,
"result": "…",
"events": [
"data.rows_updated"
]
}import { createEra } from "@getera/sdk"
const era = createEra({ apiKey: process.env.ERA_API_KEY })
const res = await era.actions.run("data.update_rows", {
dataTableId: "DATA_TABLE_ID"
})era data update_rows \
--data-table-id "DATA_TABLE_ID"{
"name": "era__data__update_rows",
"arguments": {
"dataTableId": "DATA_TABLE_ID"
}
}Errors: 401 no or expired credential · 403 the credential does not hold data:write · 404 the record or module is outside what it may reach · 422 invalid input (problems[]) · 409 table_not_found, wrong_table_kind, nothing_to_update, filter_matches_nothing, filter_too_broad, row_not_found, row_policy_denies, invalid_filter, unknown_field, type_mismatch, readonly_field, invalid_field_format, not_a_member · 429 slow down
data.upsert_row
Add or update records — Updates the record whose match field has this value, or adds one when none does.
Needs data:import · changes data
https://app.getera.io/api/v1/actions/data.upsert_rowInput
| Field | Type | Required | Notes |
|---|---|---|---|
dataTableId | uuid | yes | Table · id of data_table |
matchKey | string | yes | Match on · max 100 |
data | object / array | Values | |
rows | object / array | Records |
Preconditions
The action is refused with 409 and one of these codes:
| Code | Refused when |
|---|---|
table_not_found | The table must exist. |
wrong_table_kind | A field group has no rows of its own. |
no_match_key | The match field must be a stored field, and filled in. |
match_ambiguous | Two records answering to one value is refused, not updated twice. |
nothing_to_import | The batch must contain something. |
import_batch_too_large | A batch is capped, and the client splits the file. |
row_limit_reached | New records must fit under the table’s ceiling. |
required_field_missing | A new record must fill its required fields. |
row_policy_denies | An update must be to a record your row rules let you edit. |
unknown_field | Every key must be a field on the table. |
type_mismatch | A value must be readable as its field’s type. |
readonly_field | A read-only or computed field cannot be written. |
invalid_field_format | A value must match its field format when validation is enabled. |
not_a_member | A User field holds one of this workspace’s members. |
Events it publishes: data.row_created, data.row_updated, data.rows_imported
What it writes: data_row (upsert) — Adds the record, or merges into the one matched
curl -X POST https://app.getera.io/api/v1/actions/data.upsert_row \
-H "Authorization: Bearer $ERA_API_KEY" \
-H "Content-Type: application/json" \
-H "Idempotency-Key: $(uuidgen)" \
-d '{"dataTableId":"DATA_TABLE_ID","matchKey":"Match on"}'{
"ok": true,
"result": "…",
"events": [
"data.row_created",
"data.row_updated",
"data.rows_imported"
]
}import { createEra } from "@getera/sdk"
const era = createEra({ apiKey: process.env.ERA_API_KEY })
const res = await era.actions.run("data.upsert_row", {
dataTableId: "DATA_TABLE_ID",
matchKey: "Match on"
})era data upsert_row \
--data-table-id "DATA_TABLE_ID" \
--match-key "Match on"{
"name": "era__data__upsert_row",
"arguments": {
"dataTableId": "DATA_TABLE_ID",
"matchKey": "Match on"
}
}Errors: 401 no or expired credential · 403 the credential does not hold data:import · 404 the record or module is outside what it may reach · 422 invalid input (problems[]) · 409 table_not_found, wrong_table_kind, no_match_key, match_ambiguous, nothing_to_import, import_batch_too_large, row_limit_reached, required_field_missing, row_policy_denies, unknown_field, type_mismatch, readonly_field, invalid_field_format, not_a_member · 429 slow down
Events
Workflows and webhooks react to these events.
| Event | What happens | Payload |
|---|---|---|
data.button_pressed | Somebody pressed a workflow button on a record. | id, dataTableId, columnId, button, pressedBy |
data.column_added | A field was defined. | id, dataTableId, uiType |
data.column_changed | A field was edited or retyped. | id, uiType |
data.column_removed | A field was deleted. | id, dataTableId |
data.options_changed | A choice list changed. | id |
data.permission_changed | Who may use a table changed. | dataTableId, roleId |
data.record_values_changed | Extra fields on another module’s record were written or cleared. | dataTableId, recordType, recordId, written |
data.records_linked | Records were linked to a record. | columnId, rowId, count |
data.records_unlinked | Links were removed from a record. | columnId, rowId, count |
data.relation_created | Two tables were linked. | id, kind, sourceTableId, targetTableId |
data.row_created | A record was added. | id, dataTableId |
data.row_deleted | A record was deleted. | id, dataTableId |
data.row_policy_changed | A rule narrowing which rows somebody sees was written or removed. | dataTableId, policyId |
data.row_updated | A record was edited. | id, dataTableId |
data.rows_deleted | Several records were deleted in one go. | dataTableId, count |
data.rows_exported | Records were taken out of the platform. | dataTableId, count |
data.rows_imported | A batch of records was imported. | dataTableId, count |
data.rows_purged | A table’s records were cleared. | id, count |
data.rows_updated | Several records were edited in one go. | dataTableId, count |
data.table_created | A table or field group was opened. | id, kind, extendsModuleCode |
data.table_deleted | A table was deleted. | id, code |
data.table_duplicated | A table was copied, with or without its records. | id, sourceId, rows |
data.table_group_created | A table group was added. | id |
data.table_group_deleted | A table group was deleted; its tables were ungrouped. | id |
data.table_group_renamed | A table group was renamed or moved. | id |
data.table_moved | A table was put in a group or taken out of one. | id, groupId |
data.table_renamed | A table was edited. | id |