ReferenceReference by module

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

ActionNeedsWhat it does
data.add_columndata:manageAdd a field
data.add_computed_fielddata:manageAdd a lookup, rollup or formula
data.change_column_typedata:manageChange a field’s type
data.clear_record_valuesdata:deleteRemove a field group from a record
data.create_relationdata:manageLink to another table
data.create_tabledata:manageAdd a table
data.create_table_groupdata:manageAdd a table group
data.delete_rowdata:deleteDelete a record
data.delete_row_policydata:manageRemove a row rule
data.delete_rowsdata:deleteDelete several records
data.delete_tabledata:deleteDelete a table
data.delete_table_groupdata:manageDelete a table group
data.duplicate_tabledata:manageDuplicate a table
data.duplicate_table_groupdata:manageDuplicate a Base
data.export_rowsdata:exportExport records
data.insert_rowdata:writeAdd a record
data.insert_rowsdata:importImport records
data.link_recordsdata:writeLink records
data.move_rowdata:writeMove a record
data.move_tabledata:manageMove a table to a group
data.press_buttondata:writePress a button
data.purge_rowsdata:deleteClear a table’s records
data.remove_columndata:deleteRemove a field
data.rename_tabledata:manageEdit a table
data.rename_table_groupdata:manageRename a table group
data.set_display_fielddata:manageSet as display value
data.set_fielddata:writeSet a custom field
data.set_record_valuesdata:writeFill in extra fields
data.set_row_policydata:manageNarrow who sees which rows
data.set_select_optionsdata:manageEdit the choices
data.set_table_permissiondata:manageChange who may use a table
data.unlink_recordsdata:writeUnlink records
data.update_columndata:manageEdit a field
data.update_computed_fielddata:manageEdit a computed field
data.update_rowdata:writeEdit a record
data.update_rowsdata:writeEdit several records
data.upsert_rowdata:importAdd 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

POSThttps://app.getera.io/api/v1/actions/data.add_column
API key or OAuth token · data:manage

Input

FieldTypeRequiredNotes
dataTableIduuidyesTable · id of data_table
titlestringyesLabel · max 200
fieldKeystringyesKey · max 100
uiTypestringyesType · max 40
uiHintstringShown as · max 30
unitstringUnit · max 30
isRequiredbooleanRequired
isFilterablebooleanFilterable
isListablebooleanAvailable as a column
isPublicbooleanVisible on the storefront
helpTextstringHelp text · max 255
descriptionstringDescription · max 2000
colorstringColour · max 7
defaultValuestringDefault · max 500
sortOrdernumberOrder
referenceModuleCodestringPoints at · max 60
referenceRecordTypestringRecord type · max 60
validationobject / arrayValidation
optionsobject / arrayChoices
displayobject / arrayHow it is shown

Preconditions

The action is refused with 409 and one of these codes:

CodeRefused when
table_not_foundThe table must exist.
invalid_field_keyA key has no spaces — it is a key in a filter.
unknown_ui_typeThe type must be one the engine understands.
field_key_takenTwo fields in one group may not share a key.
field_key_taken_on_targetTwo groups may not add the same key to the same kind of record.
key_shadows_standard_fieldA custom field may not take the name of a standard one.
enum_without_optionsA choice field needs choices.
invalid_display_optionA display option must be one the field type has, with a valid value.
reference_module_disabledThe module it points at must be switched on.
required_without_default_on_existing_rowsMaking 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"}'
Response
{
  "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"
tools/call
{
  "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

POSThttps://app.getera.io/api/v1/actions/data.add_computed_field
API key or OAuth token · data:manage

Input

FieldTypeRequiredNotes
dataTableIduuidyesTable · id of data_table
kindstring (enum)yesKind · Allowed values: lookup, rollup, formula, count, barcode, qr_code, button, created_time, last_modified_time, created_by, last_modified_by, auto_number
titlestringyesName · max 200
fieldKeystringKey · max 100
relationColumnIduuidThrough the link · id of data_column
targetColumnIduuidField of the linked table · id of data_column
fnstring (enum)Summary · Allowed values: count, sum, avg, min, max, countDistinct, sumDistinct, avgDistinct
formulastringFormula · max 2000
sourceColumnIduuidField the code carries · id of data_column
buttonActionstring (enum)When clicked · Allowed values: url, workflow
buttonUrlstringLink · max 2000
buttonLabelstringButton text · max 60
buttonColorstringButton colour · max 7

Preconditions

The action is refused with 409 and one of these codes:

CodeRefused when
table_not_foundThe table must exist.
wrong_table_kindA field group has no rows to compute over.
unknown_ui_typeOnly the computed kinds are added here.
invalid_button_urlA link button needs a web address to open.
title_requiredThe field needs a name.
invalid_field_keyA key has no spaces — it is a key in a filter.
field_key_takenTwo fields in one table may not share a key.
not_a_link_fieldA lookup or rollup reads through a link field of this table.
column_not_foundThe field looked up must be one of the linked table’s.
invalid_formulaA 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"}'
Response
{
  "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"
tools/call
{
  "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

POSThttps://app.getera.io/api/v1/actions/data.change_column_type
API key or OAuth token · data:manage

Input

FieldTypeRequiredNotes
iduuidyesField · id of data_column
uiTypestringyesNew type · max 40

Preconditions

The action is refused with 409 and one of these codes:

CodeRefused when
column_not_foundThe field must exist.
unknown_ui_typeThe type must be one the engine understands.
no_changeThe new type has to differ from the old one.
incompatible_valuesStored 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"}'
Response
{
  "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"
tools/call
{
  "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

POSThttps://app.getera.io/api/v1/actions/data.clear_record_values
API key or OAuth token · data:delete

Input

FieldTypeRequiredNotes
dataTableIduuidyesField group · id of data_table
recordTypestringyesRecord type · max 60
recordIduuidyesRecord

Preconditions

The action is refused with 409 and one of these codes:

CodeRefused when
table_not_foundThe field group must exist.
wrong_table_kindA table that owns its rows is not removed this way.
nothing_to_purgeThere 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"}'
Response
{
  "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"
tools/call
{
  "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

POSThttps://app.getera.io/api/v1/actions/data.create_relation
API key or OAuth token · data:manage

Input

FieldTypeRequiredNotes
dataTableIduuidyesTable · id of data_table
targetTableIduuidyesLinks to · id of data_table
kindstring (enum)yesEach record here… · Allowed values: has_many, belongs_to, many_to_many, one_to_one
titlestringyesField name here · max 200
targetTitlestringField name on the other table · max 200
onDeletestring (enum)When a parent record is deleted · Allowed values: unlink, restrict, cascade

Preconditions

The action is refused with 409 and one of these codes:

CodeRefused when
table_not_foundThe table must exist.
target_table_not_foundThe table to link to must exist.
wrong_table_kindOnly tables with records of their own can be linked.
invalid_on_deleteA many-to-many link has no parent to cascade from.
title_requiredThe link field needs a name.
field_key_takenThe 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"}'
Response
{
  "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"
tools/call
{
  "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

POSThttps://app.getera.io/api/v1/actions/data.create_table
API key or OAuth token · data:manage

Input

FieldTypeRequiredNotes
codestringyesSystem name · max 60
titlestringyesDisplay name · max 200
descriptionstringDescription · max 2000
iconstringIcon · max 40
kindstring (enum)Kind · Allowed values: table, extension
extendsModuleCodestringAttach to · max 60
extendsRecordTypestringRecord type · max 60
maxRowsnumberRecord limit · min 1

Preconditions

The action is refused with 409 and one of these codes:

CodeRefused when
title_requiredA table needs a display name.
invalid_codeThe system name must be snake_case.
code_takenTwo tables may not share a system name.
extends_unknown_moduleThe module it attaches to must exist.
extends_module_disabledThat module must be switched on here.
table_limit_reachedA 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"}'
Response
{
  "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"
tools/call
{
  "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

POSThttps://app.getera.io/api/v1/actions/data.create_table_group
API key or OAuth token · data:manage

Input

FieldTypeRequiredNotes
namestringyesName · max 120

Preconditions

The action is refused with 409 and one of these codes:

CodeRefused when
group_name_requiredA group needs a name.
group_name_takenTwo 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"}'
Response
{
  "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"
tools/call
{
  "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

POSThttps://app.getera.io/api/v1/actions/data.delete_row
API key or OAuth token · data:delete

Input

FieldTypeRequiredNotes
iduuidyesRecord · id of data_row

Preconditions

The action is refused with 409 and one of these codes:

CodeRefused when
row_not_foundThe record must exist.
row_policy_deniesA row rule can put a record out of your reach.
referenced_by_relationA 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"}'
Response
{
  "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"
tools/call
{
  "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

POSThttps://app.getera.io/api/v1/actions/data.delete_row_policy
API key or OAuth token · data:manage

Input

FieldTypeRequiredNotes
policyIduuidyesRule

Preconditions

The action is refused with 409 and one of these codes:

CodeRefused when
policy_not_foundThe 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"}'
Response
{
  "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"
tools/call
{
  "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

POSThttps://app.getera.io/api/v1/actions/data.delete_rows
API key or OAuth token · data:delete

Input

FieldTypeRequiredNotes
dataTableIduuidyesTable · id of data_table
idsobject / arrayRecords
conditionsobject / arrayFilter

Preconditions

The action is refused with 409 and one of these codes:

CodeRefused when
table_not_foundThe table must exist.
wrong_table_kindA field group has no rows of its own.
filter_matches_nothingThe selection or filter must reach at least one record.
filter_too_broadA bulk delete needs a selection or a filter, and is capped.
row_policy_deniesEvery record deleted must be one your row rules let you delete.
invalid_filterA filter that cannot compile is refused.
referenced_by_relationA 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"}'
Response
{
  "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"
tools/call
{
  "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

POSThttps://app.getera.io/api/v1/actions/data.delete_table
API key or OAuth token · data:delete

Input

FieldTypeRequiredNotes
iduuidyesTable · id of data_table

Preconditions

The action is refused with 409 and one of these codes:

CodeRefused when
table_not_foundThe table must exist.
has_rowsIts records must be cleared first, and it says how many.
referenced_by_relationAnother 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"}'
Response
{
  "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"
tools/call
{
  "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

POSThttps://app.getera.io/api/v1/actions/data.delete_table_group
API key or OAuth token · data:manage

Input

FieldTypeRequiredNotes
iduuidyesGroup

Preconditions

The action is refused with 409 and one of these codes:

CodeRefused when
table_group_not_foundThe 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"}'
Response
{
  "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"
tools/call
{
  "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

POSThttps://app.getera.io/api/v1/actions/data.duplicate_table
API key or OAuth token · data:manage

Input

FieldTypeRequiredNotes
iduuidyesTable · id of data_table
titlestringName of the copy · max 200
withRowsbooleanCopy the records too

Preconditions

The action is refused with 409 and one of these codes:

CodeRefused when
table_not_foundThe 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"}'
Response
{
  "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"
tools/call
{
  "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

POSThttps://app.getera.io/api/v1/actions/data.duplicate_table_group
API key or OAuth token · data:manage

Input

FieldTypeRequiredNotes
iduuidyesBase
namestringyesCopy name · max 120
withRowsbooleanCopy records

Preconditions

The action is refused with 409 and one of these codes:

CodeRefused when
table_group_not_foundThe source Base must exist.
group_name_requiredThe copy needs a name.
group_name_takenThe copy name must be available.
table_not_foundEvery 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"}'
Response
{
  "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"
tools/call
{
  "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)

POSThttps://app.getera.io/api/v1/actions/data.export_rows
API key or OAuth token · data:export

Input

FieldTypeRequiredNotes
dataTableIduuidyesTable · id of data_table
conditionsobject / arrayFilter
searchstringSearch · max 200
limitnumberLimit · min 1

Preconditions

The action is refused with 409 and one of these codes:

CodeRefused when
table_not_foundThe table must exist.
wrong_table_kindA field group has no rows to export.
invalid_filterA filter that cannot compile is refused.
unknown_fieldA 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"}'
Response
{
  "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"
tools/call
{
  "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

POSThttps://app.getera.io/api/v1/actions/data.insert_row
API key or OAuth token · data:write

Input

FieldTypeRequiredNotes
dataTableIduuidyesTable · id of data_table
dataobject / arrayyesValues

Preconditions

The action is refused with 409 and one of these codes:

CodeRefused when
table_not_foundThe table must exist.
wrong_table_kindExtension tables have no rows of their own.
row_limit_reachedA table has a record ceiling; reading carries on.
unknown_fieldEvery key must be a field on the table.
required_field_missingRequired fields must be filled in.
type_mismatchA value must be readable as its field’s type.
not_a_memberA User field holds one of this workspace’s members.
readonly_fieldA read-only field cannot be written.
invalid_field_formatA value must match its field format when validation is enabled.
row_policy_deniesA 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":{}}'
Response
{
  "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":{}}'
tools/call
{
  "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

POSThttps://app.getera.io/api/v1/actions/data.insert_rows
API key or OAuth token · data:import

Input

FieldTypeRequiredNotes
dataTableIduuidyesTable · id of data_table
rowsobject / arrayyesRecords
dryRunbooleanOnly check the file
skipInvalidbooleanSkip rows with problems

Preconditions

The action is refused with 409 and one of these codes:

CodeRefused when
table_not_foundThe table must exist.
wrong_table_kindExtension tables have no rows of their own.
nothing_to_importThe batch must contain something.
import_batch_too_largeA batch is capped, and the client splits the file.
row_limit_reachedThe whole batch must fit under the table’s ceiling.
unknown_fieldEvery column in the file must be a field on the table.
required_field_missingRequired fields must be filled in.
type_mismatchA value must be readable as its field’s type.
not_a_memberA User field holds one of this workspace’s members.
readonly_fieldA read-only field cannot be written.
invalid_field_formatA 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":{}}'
Response
{
  "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":{}}'
tools/call
{
  "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

Link records — Links records of the other table to this record through one link field.

Needs data:write · changes data

POSThttps://app.getera.io/api/v1/actions/data.link_records
API key or OAuth token · data:write
FieldTypeRequiredNotes
columnIduuidyesLink field · id of data_column
rowIduuidyesRecord · id of data_row
targetRowIdsobject / arrayyesRecords to link

The action is refused with 409 and one of these codes:

CodeRefused when
column_not_foundThe link field must exist.
not_a_link_fieldThe field must be a link to another table.
row_not_foundThe record must be in this table.
row_policy_deniesA row rule can put a record out of your reach.
link_target_invalidEvery record linked must be in the other table.
link_cardinalityA 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":{}}'
Response
{
  "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":{}}'
tools/call
{
  "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

POSThttps://app.getera.io/api/v1/actions/data.move_row
API key or OAuth token · data:write

Input

FieldTypeRequiredNotes
iduuidyesRecord · id of data_row
afterIduuidAfter record · Empty to move it to the top. · id of data_row

Preconditions

The action is refused with 409 and one of these codes:

CodeRefused when
row_not_foundThe record, and the one it goes after, must exist in the same table.
row_policy_deniesA 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"}'
Response
{
  "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"
tools/call
{
  "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

POSThttps://app.getera.io/api/v1/actions/data.move_table
API key or OAuth token · data:manage

Input

FieldTypeRequiredNotes
iduuidyesTable · id of data_table
groupIduuidGroup

Preconditions

The action is refused with 409 and one of these codes:

CodeRefused when
table_not_foundThe table must exist.
table_group_not_foundThe 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"}'
Response
{
  "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"
tools/call
{
  "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

POSThttps://app.getera.io/api/v1/actions/data.press_button
API key or OAuth token · data:write

Input

FieldTypeRequiredNotes
columnIduuidyesButton · id of data_column
rowIduuidyesRecord · id of data_row

Preconditions

The action is refused with 409 and one of these codes:

CodeRefused when
column_not_foundThe button must exist.
not_a_buttonOnly a button that starts a workflow can be pressed.
row_not_foundThe 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"}'
Response
{
  "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"
tools/call
{
  "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

POSThttps://app.getera.io/api/v1/actions/data.purge_rows
API key or OAuth token · data:delete

Input

FieldTypeRequiredNotes
iduuidyesTable · id of data_table

Preconditions

The action is refused with 409 and one of these codes:

CodeRefused when
table_not_foundThe table must exist.
nothing_to_purgeThere must be something to clear.
referenced_by_relationA 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"}'
Response
{
  "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"
tools/call
{
  "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

POSThttps://app.getera.io/api/v1/actions/data.remove_column
API key or OAuth token · data:delete

Input

FieldTypeRequiredNotes
iduuidyesField · id of data_column

Preconditions

The action is refused with 409 and one of these codes:

CodeRefused when
column_not_foundThe field must exist.
is_primary_displayThe field a record is named by cannot be removed.
used_by_saved_viewA saved view filtering on it would silently empty.
used_by_formulaA formula reading it would go blank for ever.
used_by_relationA 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"}'
Response
{
  "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"
tools/call
{
  "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

POSThttps://app.getera.io/api/v1/actions/data.rename_table
API key or OAuth token · data:manage

Input

FieldTypeRequiredNotes
iduuidyesTable · id of data_table
codestringSystem name · max 60
titlestringDisplay name · max 200
descriptionstringDescription · max 2000
iconstringIcon · max 40

Preconditions

The action is refused with 409 and one of these codes:

CodeRefused when
table_not_foundThe table must exist.
code_takenTwo tables may not share a system name.
invalid_codeThe system name must be snake_case.
no_changeSomething 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"}'
Response
{
  "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"
tools/call
{
  "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

POSThttps://app.getera.io/api/v1/actions/data.rename_table_group
API key or OAuth token · data:manage

Input

FieldTypeRequiredNotes
iduuidyesGroup
namestringName · max 120
sortOrdernumberPosition

Preconditions

The action is refused with 409 and one of these codes:

CodeRefused when
table_group_not_foundThe group must exist.
group_name_requiredA group needs a name.
group_name_takenTwo 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"}'
Response
{
  "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"
tools/call
{
  "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

POSThttps://app.getera.io/api/v1/actions/data.set_display_field
API key or OAuth token · data:manage

Input

FieldTypeRequiredNotes
iduuidyesField · id of data_column

Preconditions

The action is refused with 409 and one of these codes:

CodeRefused when
column_not_foundThe field must exist.
display_type_unsupportedA 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"}'
Response
{
  "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"
tools/call
{
  "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

POSThttps://app.getera.io/api/v1/actions/data.set_field
API key or OAuth token · data:write

Input

FieldTypeRequiredNotes
recordTypestringyesRecord type · max 60
recordIduuidyesRecord
fieldstringyesField · max 200
valuestringValue · Empty clears the field. Several choices: "A, B". · max 5000

Preconditions

The action is refused with 409 and one of these codes:

CodeRefused when
field_not_foundThe record type must have a field by that key or label.
option_not_availableA choice must be one the field offers.
extends_module_disabledA switched-off module takes no new values.
required_field_missingA required field cannot be cleared.
type_mismatchA value must be readable as its field’s type.
readonly_fieldA read-only field cannot be written.
not_a_memberA person field must name a member of this workspace.
invalid_field_formatA 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"}'
Response
{
  "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"
tools/call
{
  "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

POSThttps://app.getera.io/api/v1/actions/data.set_record_values
API key or OAuth token · data:write

Input

FieldTypeRequiredNotes
dataTableIduuidyesField group · id of data_table
recordTypestringyesRecord type · max 60
recordIduuidyesRecord
valuesobject / arrayyesValues
completebooleanWhole 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:

CodeRefused when
table_not_foundThe field group must exist.
wrong_table_kindA table that owns its rows takes a row, not values.
not_a_memberA person field must name a member of this workspace.
record_type_mismatchThe group must belong to that kind of record.
extends_module_disabledA switched-off module takes no new values.
unknown_fieldEvery key must be a field in the group.
required_field_missingRequired fields must be filled in.
type_mismatchA value must be readable as its field’s type.
readonly_fieldA read-only field cannot be written.
option_not_availableA choice must be one the field still offers.
invalid_field_formatA 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":{}}'
Response
{
  "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":{}}'
tools/call
{
  "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

POSThttps://app.getera.io/api/v1/actions/data.set_row_policy
API key or OAuth token · data:manage

Input

FieldTypeRequiredNotes
dataTableIduuidyesTable · id of data_table
policyIduuidRule
namestringyesName · max 120
permissionstring (enum)yesApplies to · Allowed values: read, write, delete
conditionsobject / arrayCondition
subjectsobject / arrayyesWho it is for
isActivebooleanActive

Preconditions

The action is refused with 409 and one of these codes:

CodeRefused when
table_not_foundThe table must exist.
wrong_table_kindA field group has no rows of its own to narrow.
title_requiredA rule refusing an edit has to be nameable.
policy_needs_subjectA rule with nobody on it would hide the table.
subject_not_foundA subject must be a real role or workspace member.
invalid_filterA condition that cannot compile is refused at save time.
unknown_fieldA condition may only name fields the table has.
policy_not_foundEditing a rule needs the rule to exist.
name_takenTwo 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":{}}'
Response
{
  "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":{}}'
tools/call
{
  "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

POSThttps://app.getera.io/api/v1/actions/data.set_select_options
API key or OAuth token · data:manage

Input

FieldTypeRequiredNotes
dataColumnIduuidyesField · id of data_column
optionsobject / arrayyesChoices

Preconditions

The action is refused with 409 and one of these codes:

CodeRefused when
column_not_foundThe field must exist.
column_not_enumThe field must be one that offers choices.
option_in_useAn 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":{}}'
Response
{
  "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":{}}'
tools/call
{
  "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

POSThttps://app.getera.io/api/v1/actions/data.set_table_permission
API key or OAuth token · data:manage

Input

FieldTypeRequiredNotes
dataTableIduuidyesTable · id of data_table
roleIduuidyesRole
permissionstring (enum)yesPermission · Allowed values: TABLE_RECORD_READ, TABLE_RECORD_ADD, TABLE_RECORD_UPDATE, TABLE_RECORD_DELETE, FIELD_EDIT
grantedbooleanyesGranted

Preconditions

The action is refused with 409 and one of these codes:

CodeRefused when
table_not_foundThe table must exist.
role_not_foundThe role must exist.
cannot_lock_out_ownerThe 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}'
Response
{
  "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
tools/call
{
  "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

Unlink records — Removes links from this record. The linked records themselves stay.

Needs data:write · changes data

POSThttps://app.getera.io/api/v1/actions/data.unlink_records
API key or OAuth token · data:write
FieldTypeRequiredNotes
columnIduuidyesLink field · id of data_column
rowIduuidyesRecord · id of data_row
targetRowIdsobject / arrayyesRecords to unlink

The action is refused with 409 and one of these codes:

CodeRefused when
column_not_foundThe link field must exist.
not_a_link_fieldThe field must be a link to another table.
row_not_foundThe record must be in this table.
row_policy_deniesA row rule can put a record out of your reach.
nothing_to_unlinkAt 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":{}}'
Response
{
  "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":{}}'
tools/call
{
  "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

POSThttps://app.getera.io/api/v1/actions/data.update_column
API key or OAuth token · data:manage

Input

FieldTypeRequiredNotes
iduuidyesField · id of data_column
titlestringLabel · max 200
uiHintstringShown as · max 30
unitstringUnit · max 30
isRequiredbooleanRequired
isFilterablebooleanFilterable
isListablebooleanAvailable as a column
isPublicbooleanVisible on the storefront
helpTextstringHelp text · max 255
descriptionstringDescription · max 2000
colorstringColour · max 7
defaultValuestringDefault · max 500
sortOrdernumberOrder
displayobject / arrayHow it is shown
validationobject / arrayValidation
archivedbooleanArchived · Hidden from forms, lists and filters; its answers are kept.

Preconditions

The action is refused with 409 and one of these codes:

CodeRefused when
column_not_foundThe field must exist.
required_without_default_on_existing_rowsMaking a field required on records that already exist needs a default.
invalid_display_optionA 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"}'
Response
{
  "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"
tools/call
{
  "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

POSThttps://app.getera.io/api/v1/actions/data.update_computed_field
API key or OAuth token · data:manage

Input

FieldTypeRequiredNotes
iduuidyesField · id of data_column
titlestringName · max 200
formulastringFormula · max 2000
fnstring (enum)Summary · Allowed values: count, sum, avg, min, max, countDistinct, sumDistinct, avgDistinct
targetColumnIduuidField of the linked table · id of data_column
sourceColumnIduuidField the code carries · id of data_column
buttonActionstring (enum)When clicked · Allowed values: url, workflow
buttonUrlstringLink · max 2000
buttonLabelstringButton text · max 60
buttonColorstringButton colour · max 7

Preconditions

The action is refused with 409 and one of these codes:

CodeRefused when
column_not_foundThe field must exist.
not_a_computed_fieldA stored field is edited with the ordinary field editor.
invalid_button_urlA link button needs a web address to open.
invalid_formulaA formula that cannot be read is refused at save time.
formula_cycleA 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"}'
Response
{
  "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"
tools/call
{
  "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

POSThttps://app.getera.io/api/v1/actions/data.update_row
API key or OAuth token · data:write

Input

FieldTypeRequiredNotes
iduuidyesRecord · id of data_row
dataobject / arrayyesValues

Preconditions

The action is refused with 409 and one of these codes:

CodeRefused when
row_not_foundThe record must exist.
unknown_fieldEvery key must be a field on the table.
type_mismatchA value must be readable as its field’s type.
not_a_memberA User field holds one of this workspace’s members.
readonly_fieldA read-only field cannot be written.
required_field_missingA required field cannot be cleared.
row_policy_deniesA row rule can put a record out of your reach.
invalid_filterA row rule whose condition cannot compile blocks, never skips.
invalid_field_formatA 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":{}}'
Response
{
  "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":{}}'
tools/call
{
  "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

POSThttps://app.getera.io/api/v1/actions/data.update_rows
API key or OAuth token · data:write

Input

FieldTypeRequiredNotes
dataTableIduuidyesTable · id of data_table
rowsobject / arrayPer-record values
idsobject / arrayRecords
conditionsobject / arrayFilter
dataobject / arrayValues

Preconditions

The action is refused with 409 and one of these codes:

CodeRefused when
table_not_foundThe table must exist.
wrong_table_kindA field group has no rows of its own.
nothing_to_updateThere has to be something to change.
filter_matches_nothingThe selection or filter must reach at least one record.
filter_too_broadA bulk edit needs a selection or a filter, and is capped.
row_not_foundEvery record pasted into must be in this table.
row_policy_deniesEvery record touched must be one your row rules let you edit.
invalid_filterA filter that cannot compile is refused.
unknown_fieldEvery key must be a field on the table.
type_mismatchA value must be readable as its field’s type.
readonly_fieldA read-only or computed field cannot be written.
invalid_field_formatA value must match its field format when validation is enabled.
not_a_memberA 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"}'
Response
{
  "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"
tools/call
{
  "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

POSThttps://app.getera.io/api/v1/actions/data.upsert_row
API key or OAuth token · data:import

Input

FieldTypeRequiredNotes
dataTableIduuidyesTable · id of data_table
matchKeystringyesMatch on · max 100
dataobject / arrayValues
rowsobject / arrayRecords

Preconditions

The action is refused with 409 and one of these codes:

CodeRefused when
table_not_foundThe table must exist.
wrong_table_kindA field group has no rows of its own.
no_match_keyThe match field must be a stored field, and filled in.
match_ambiguousTwo records answering to one value is refused, not updated twice.
nothing_to_importThe batch must contain something.
import_batch_too_largeA batch is capped, and the client splits the file.
row_limit_reachedNew records must fit under the table’s ceiling.
required_field_missingA new record must fill its required fields.
row_policy_deniesAn update must be to a record your row rules let you edit.
unknown_fieldEvery key must be a field on the table.
type_mismatchA value must be readable as its field’s type.
readonly_fieldA read-only or computed field cannot be written.
invalid_field_formatA value must match its field format when validation is enabled.
not_a_memberA 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"}'
Response
{
  "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"
tools/call
{
  "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.

EventWhat happensPayload
data.button_pressedSomebody pressed a workflow button on a record.id, dataTableId, columnId, button, pressedBy
data.column_addedA field was defined.id, dataTableId, uiType
data.column_changedA field was edited or retyped.id, uiType
data.column_removedA field was deleted.id, dataTableId
data.options_changedA choice list changed.id
data.permission_changedWho may use a table changed.dataTableId, roleId
data.record_values_changedExtra fields on another module’s record were written or cleared.dataTableId, recordType, recordId, written
data.records_linkedRecords were linked to a record.columnId, rowId, count
data.records_unlinkedLinks were removed from a record.columnId, rowId, count
data.relation_createdTwo tables were linked.id, kind, sourceTableId, targetTableId
data.row_createdA record was added.id, dataTableId
data.row_deletedA record was deleted.id, dataTableId
data.row_policy_changedA rule narrowing which rows somebody sees was written or removed.dataTableId, policyId
data.row_updatedA record was edited.id, dataTableId
data.rows_deletedSeveral records were deleted in one go.dataTableId, count
data.rows_exportedRecords were taken out of the platform.dataTableId, count
data.rows_importedA batch of records was imported.dataTableId, count
data.rows_purgedA table’s records were cleared.id, count
data.rows_updatedSeveral records were edited in one go.dataTableId, count
data.table_createdA table or field group was opened.id, kind, extendsModuleCode
data.table_deletedA table was deleted.id, code
data.table_duplicatedA table was copied, with or without its records.id, sourceId, rows
data.table_group_createdA table group was added.id
data.table_group_deletedA table group was deleted; its tables were ungrouped.id
data.table_group_renamedA table group was renamed or moved.id
data.table_movedA table was put in a group or taken out of one.id, groupId
data.table_renamedA table was edited.id
Was this page helpful?