ReferenceReference by module

Security & Access API

Every Security & Access action (14) and data model (6): endpoints, scopes, input, preconditions, events and examples.

Roles, and what each role can see and do.

Module code security_access · 14 actions · 6 data models · 15 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: security_access (everything), security_access:read (read only) or security_access:<capability>.

Resources

ResourceTableList and readPOSTPATCHDELETE
access_grantsaccess_grant/api/v1/access_grants
blueprint_installsblueprint_install/api/v1/blueprint_installs
role_module_capabilitiesrole_module_capability/api/v1/role_module_capabilities
rolesrole/api/v1/rolessecurity_access.create_role
workspace_membersworkspace_member/api/v1/workspace_members
workspace_modulesworkspace_module/api/v1/workspace_modules

Lists take limit (up to 200), cursor, order (e.g. -created_at), fields and q; every other query parameter is a column filter: ?status=paid, ?total[gte]=100, ?id[in]=a,b, ?x=null.

Actions

ActionNeedsWhat it does
security_access.apply_blueprintsecurity_access:manageInstall a blueprint
security_access.create_rolesecurity_access:manageCreate role
security_access.delete_rolesecurity_access:deleteDelete role
security_access.grantsecurity_access:manageGrant access to one person
security_access.open_shopsecurity_access:manageOpen the shop
security_access.remove_blueprint_samplessecurity_access:manageRemove sample data
security_access.revokesecurity_access:manageRevoke a personal grant
security_access.set_capabilitysecurity_access:manageGrant or revoke a capability
security_access.set_masked_fieldssecurity_access:manageHide fields from one person
security_access.set_member_rolesecurity_access:manageChange a member’s role
security_access.set_reports_tosecurity_access:manageSet who a member reports to
security_access.set_role_channelssecurity_access:manageLimit a role to sales channels
security_access.toggle_featuresecurity_access:manageSwitch part of a module on or off
security_access.toggle_modulesecurity_access:manageSwitch a module on or off

security_access.apply_blueprint

Install a blueprint — Sets a workspace up for one kind of business — modules with their dependencies, words, settings, roles, services, pipeline, tax, shipping, fields, tags, dashboards, agents and, if asked, sample data — or re-applies it.

Needs security_access:manage · removes or cannot be undone

POSThttps://app.getera.io/api/v1/workspace_modules/actions/apply_blueprint
API key or OAuth token · security_access:manage
  • Canonical address: POST /api/v1/actions/security_access.apply_blueprint

Input

FieldTypeRequiredNotes
codestringyesBlueprint · max 41
choicesobject / arrayOnboarding choices · Answers, module switches, edited setup areas, agents, workflows, sample data.

Preconditions

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

CodeRefused when
unknown_blueprintThe blueprint, and every module it names, must exist in this build.
blueprint_downgradeA newer version than this build’s must not be overwritten with an older one.
invalid_choicesThe onboarding choices must be an object of lists and answers.
blueprint_step_failedEvery configuration step must pass its own action’s rules, or nothing is installed.

Events it publishes: security_access.blueprint_applied, security_access.module_enabled

What it writes: workspace_module (upsert) — Switches the pack’s modules on, and sets their sidebar order once; role (insert) — Creates the pack’s roles; role_module_capability (insert) — Grants those roles their starting capabilities; blueprint_install (upsert) — Records the version applied and the choices it was applied with

curl -X POST https://app.getera.io/api/v1/workspace_modules/actions/apply_blueprint \
  -H "Authorization: Bearer $ERA_API_KEY" \
  -H "Content-Type: application/json" \
  -H "Idempotency-Key: $(uuidgen)" \
  -d '{"code":"Blueprint"}'
Response
{
  "ok": true,
  "result": "…",
  "events": [
    "security_access.blueprint_applied",
    "security_access.module_enabled"
  ]
}
import { createEra } from "@getera/sdk"

const era = createEra({ apiKey: process.env.ERA_API_KEY })
const res = await era.workspaceModules.applyBlueprint({
  code: "Blueprint"
})
era workspace_modules apply_blueprint \
  --code "Blueprint"
tools/call
{
  "name": "era__security_access__apply_blueprint",
  "arguments": {
    "code": "Blueprint"
  }
}

Errors: 401 no or expired credential · 403 the credential does not hold security_access:manage · 404 the record or module is outside what it may reach · 422 invalid input (problems[]) · 409 unknown_blueprint, blueprint_downgrade, invalid_choices, blueprint_step_failed · 429 slow down

security_access.create_role

Create role — Defines a role for this workspace, starting with no access to anything but the person’s own Era Station rows.

Needs security_access:manage · removes or cannot be undone

POSThttps://app.getera.io/api/v1/roles/actions/create_role
API key or OAuth token · security_access:manage
  • REST alias: POST /api/v1/roles
  • Canonical address: POST /api/v1/actions/security_access.create_role

Input

FieldTypeRequiredNotes
codestringyesCode · max 40
labelstringyesName · max 80
descriptionstringDescription · max 500

Preconditions

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

CodeRefused when
code_formatThe code must start with a letter and contain only lowercase letters, numbers and underscores.
code_takenA role with that code already exists in this workspace.

Events it publishes: security_access.role_created

What it writes: role (insert) — Creates the role; role_module_capability (insert) — Grants the personal modules (each person’s own Era Station rows), by trigger (sql/818)

curl -X POST https://app.getera.io/api/v1/roles/actions/create_role \
  -H "Authorization: Bearer $ERA_API_KEY" \
  -H "Content-Type: application/json" \
  -H "Idempotency-Key: $(uuidgen)" \
  -d '{"code":"Code","label":"Name"}'
Response
{
  "ok": true,
  "result": "…",
  "events": [
    "security_access.role_created"
  ]
}
import { createEra } from "@getera/sdk"

const era = createEra({ apiKey: process.env.ERA_API_KEY })
const res = await era.roles.create({
  code: "Code",
  label: "Name"
})
era roles create \
  --code "Code" \
  --label "Name"
tools/call
{
  "name": "era__security_access__create_role",
  "arguments": {
    "code": "Code",
    "label": "Name"
  }
}

Errors: 401 no or expired credential · 403 the credential does not hold security_access:manage · 404 the record or module is outside what it may reach · 422 invalid input (problems[]) · 409 code_format, code_taken · 429 slow down

security_access.delete_role

Delete role — Removes a role nobody holds.

Needs security_access:delete · removes or cannot be undone · asks a person to confirm when Era runs it

POSThttps://app.getera.io/api/v1/roles/actions/delete_role
API key or OAuth token · security_access:delete
  • Canonical address: POST /api/v1/actions/security_access.delete_role

Input

FieldTypeRequiredNotes
role_iduuidyesRole

Preconditions

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

CodeRefused when
system_role_protectedThe six system roles cannot be deleted.
role_in_useMembers still hold this role. Move them first.

Events it publishes: security_access.role_deleted

What it writes: role (delete) — Deletes the role and its capability rows

curl -X POST https://app.getera.io/api/v1/roles/actions/delete_role \
  -H "Authorization: Bearer $ERA_API_KEY" \
  -H "Content-Type: application/json" \
  -H "Idempotency-Key: $(uuidgen)" \
  -d '{"role_id":"ROLE_ID"}'
Response
{
  "ok": true,
  "result": "…",
  "events": [
    "security_access.role_deleted"
  ]
}
import { createEra } from "@getera/sdk"

const era = createEra({ apiKey: process.env.ERA_API_KEY })
const res = await era.roles.deleteRole({
  role_id: "ROLE_ID"
})
era roles delete_role \
  --role-id "ROLE_ID"
tools/call
{
  "name": "era__security_access__delete_role",
  "arguments": {
    "role_id": "ROLE_ID"
  }
}

Errors: 401 no or expired credential · 403 the credential does not hold security_access:delete · 404 the record or module is outside what it may reach · 422 invalid input (problems[]) · 409 system_role_protected, role_in_use · 429 slow down

security_access.grant

Grant access to one person — Gives one person access to one thing, optionally narrowed or with fields hidden.

Needs security_access:manage · removes or cannot be undone

POSThttps://app.getera.io/api/v1/access_grants/actions/grant
API key or OAuth token · security_access:manage
  • Canonical address: POST /api/v1/actions/security_access.grant

Input

FieldTypeRequiredNotes
user_iduuidyesMember
subject_typestring (enum)yesKind · Allowed values: module, report, view
subject_keystringyesWhich one · max 80
capabilitystringyesCapability · max 24
row_scopestring (enum)Rows they see · Allowed values: all, own_records, own_and_reports
masked_fieldsobject / arrayMeasures to hide · Names of measures this grant must not show. Only meaningful for a report.
channel_idsobject / arrayAllowed sales channels · Retail only: null = all, empty array = none. Narrows the role scope.
expires_atdate-timeExpires

Preconditions

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

CodeRefused when
channel_scope_invalidChannel scope must contain channels from this workspace and target retail.
not_a_memberThey are not a member of this workspace.
subject_not_foundA report grant must name a report the registry declares.
measure_not_maskableA report may only be asked to hide a measure it actually shows.

Events it publishes: security_access.access_granted

What it writes: access_grant (upsert) — Records the grant

curl -X POST https://app.getera.io/api/v1/access_grants/actions/grant \
  -H "Authorization: Bearer $ERA_API_KEY" \
  -H "Content-Type: application/json" \
  -H "Idempotency-Key: $(uuidgen)" \
  -d '{"user_id":"USER_ID","subject_type":"module","subject_key":"Which one","capability":"Capability"}'
Response
{
  "ok": true,
  "result": "…",
  "events": [
    "security_access.access_granted"
  ]
}
import { createEra } from "@getera/sdk"

const era = createEra({ apiKey: process.env.ERA_API_KEY })
const res = await era.accessGrants.grant({
  user_id: "USER_ID",
  subject_type: "module",
  subject_key: "Which one",
  capability: "Capability"
})
era access_grants grant \
  --user-id "USER_ID" \
  --subject-type "module" \
  --subject-key "Which one" \
  --capability "Capability"
tools/call
{
  "name": "era__security_access__grant",
  "arguments": {
    "user_id": "USER_ID",
    "subject_type": "module",
    "subject_key": "Which one",
    "capability": "Capability"
  }
}

Errors: 401 no or expired credential · 403 the credential does not hold security_access:manage · 404 the record or module is outside what it may reach · 422 invalid input (problems[]) · 409 channel_scope_invalid, not_a_member, subject_not_found, measure_not_maskable · 429 slow down

security_access.open_shop

Open the shop — One call for a workspace with no shop: switches the shop modules on (retail and what it needs) and opens a sales channel named after the workspace, in TRY. Era calls it after "Mağazan yok — açayım mı?" is answered yes.

Needs security_access:manage · removes or cannot be undone

POSThttps://app.getera.io/api/v1/workspace_modules/actions/open_shop
API key or OAuth token · security_access:manage
  • Canonical address: POST /api/v1/actions/security_access.open_shop

Input

FieldTypeRequiredNotes
namestringName · Empty = the workspace name. · max 250
currencyCodestringCurrency · ISO-4217. Empty = TRY. · max 3
defaultCountrystringDefault country · Empty = TR. · max 2

Preconditions

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

CodeRefused when
module_limit_reachedThe workspace must have room for the shop modules on its plan.
invalid_currencyThe currency must be an ISO-4217 code.

Events it publishes: security_access.module_enabled, security_access.shop_opened

What it writes: workspace_module (upsert) — Switches retail and its dependencies on; retail’s opening code then opens the shop channel, as a seed would

curl -X POST https://app.getera.io/api/v1/workspace_modules/actions/open_shop \
  -H "Authorization: Bearer $ERA_API_KEY" \
  -H "Content-Type: application/json" \
  -H "Idempotency-Key: $(uuidgen)" \
  -d '{"name":"Name"}'
Response
{
  "ok": true,
  "result": "…",
  "events": [
    "security_access.module_enabled",
    "security_access.shop_opened"
  ]
}
import { createEra } from "@getera/sdk"

const era = createEra({ apiKey: process.env.ERA_API_KEY })
const res = await era.workspaceModules.openShop({
  name: "Name"
})
era workspace_modules open_shop \
  --name "Name"
tools/call
{
  "name": "era__security_access__open_shop",
  "arguments": {
    "name": "Name"
  }
}

Errors: 401 no or expired credential · 403 the credential does not hold security_access:manage · 404 the record or module is outside what it may reach · 422 invalid input (problems[]) · 409 module_limit_reached, invalid_currency · 429 slow down

security_access.remove_blueprint_samples

Remove sample data — Removes only records written by the blueprint installer, through each record’s module action. Safe to run again.

Needs security_access:manage · removes or cannot be undone · asks a person to confirm when Era runs it

POSThttps://app.getera.io/api/v1/blueprint_installs/actions/remove_blueprint_samples
API key or OAuth token · security_access:manage
  • Canonical address: POST /api/v1/actions/security_access.remove_blueprint_samples

Input

This action takes no input.

What it writes: blueprint_install (update) — Marks successfully handled sample records removed

curl -X POST https://app.getera.io/api/v1/blueprint_installs/actions/remove_blueprint_samples \
  -H "Authorization: Bearer $ERA_API_KEY" \
  -H "Content-Type: application/json" \
  -H "Idempotency-Key: $(uuidgen)" \
  -d '{}'
Response
{
  "ok": true,
  "result": "…",
  "events": []
}
import { createEra } from "@getera/sdk"

const era = createEra({ apiKey: process.env.ERA_API_KEY })
const res = await era.blueprintInstalls.removeBlueprintSamples()
era blueprint_installs remove_blueprint_samples
tools/call
{
  "name": "era__security_access__remove_blueprint_samples",
  "arguments": {}
}

Errors: 401 no or expired credential · 403 the credential does not hold security_access:manage · 404 the record or module is outside what it may reach · 422 invalid input (problems[]) · 429 slow down

security_access.revoke

Revoke a personal grant — Takes back access given to one person directly.

Needs security_access:manage · removes or cannot be undone

POSThttps://app.getera.io/api/v1/access_grants/actions/revoke
API key or OAuth token · security_access:manage
  • Canonical address: POST /api/v1/actions/security_access.revoke

Input

FieldTypeRequiredNotes
grant_iduuidyesGrant

Preconditions

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

CodeRefused when
grant_not_foundThat grant no longer exists.

Events it publishes: security_access.access_revoked

What it writes: access_grant (delete) — Removes the grant

curl -X POST https://app.getera.io/api/v1/access_grants/actions/revoke \
  -H "Authorization: Bearer $ERA_API_KEY" \
  -H "Content-Type: application/json" \
  -H "Idempotency-Key: $(uuidgen)" \
  -d '{"grant_id":"GRANT_ID"}'
Response
{
  "ok": true,
  "result": "…",
  "events": [
    "security_access.access_revoked"
  ]
}
import { createEra } from "@getera/sdk"

const era = createEra({ apiKey: process.env.ERA_API_KEY })
const res = await era.accessGrants.revoke({
  grant_id: "GRANT_ID"
})
era access_grants revoke \
  --grant-id "GRANT_ID"
tools/call
{
  "name": "era__security_access__revoke",
  "arguments": {
    "grant_id": "GRANT_ID"
  }
}

Errors: 401 no or expired credential · 403 the credential does not hold security_access:manage · 404 the record or module is outside what it may reach · 422 invalid input (problems[]) · 409 grant_not_found · 429 slow down

security_access.set_capability

Grant or revoke a capability — Decides what one role may do in one module.

Needs security_access:manage · removes or cannot be undone

POSThttps://app.getera.io/api/v1/role_module_capabilities/actions/set_capability
API key or OAuth token · security_access:manage
  • Canonical address: POST /api/v1/actions/security_access.set_capability

Input

FieldTypeRequiredNotes
role_iduuidyesRole · id of role
module_codestringyesModule · max 41
capabilitystringyesCapability · max 24
grantedbooleanyesGranted
own_records_scopestring (enum)Reaches · Only meaningful for “own records only”. · Allowed values: self_only, self_and_reports

Preconditions

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

CodeRefused when
system_role_protectedThe owner role always reaches everything.
module_not_enabledThat module is not switched on in this workspace.
capability_not_declaredThat module does not offer that capability.
last_owner_protectedSomeone must keep access to roles.

Events it publishes: security_access.capability_granted, security_access.capability_revoked

What it writes: role_module_capability (upsert) — Adds or removes the matrix row

curl -X POST https://app.getera.io/api/v1/role_module_capabilities/actions/set_capability \
  -H "Authorization: Bearer $ERA_API_KEY" \
  -H "Content-Type: application/json" \
  -H "Idempotency-Key: $(uuidgen)" \
  -d '{"role_id":"ROLE_ID","module_code":"Module","capability":"Capability","granted":true}'
Response
{
  "ok": true,
  "result": "…",
  "events": [
    "security_access.capability_granted",
    "security_access.capability_revoked"
  ]
}
import { createEra } from "@getera/sdk"

const era = createEra({ apiKey: process.env.ERA_API_KEY })
const res = await era.roleModuleCapabilities.setCapability({
  role_id: "ROLE_ID",
  module_code: "Module",
  capability: "Capability",
  granted: true
})
era role_module_capabilities set_capability \
  --role-id "ROLE_ID" \
  --module-code "Module" \
  --capability "Capability" \
  --granted true
tools/call
{
  "name": "era__security_access__set_capability",
  "arguments": {
    "role_id": "ROLE_ID",
    "module_code": "Module",
    "capability": "Capability",
    "granted": true
  }
}

Errors: 401 no or expired credential · 403 the credential does not hold security_access:manage · 404 the record or module is outside what it may reach · 422 invalid input (problems[]) · 409 system_role_protected, module_not_enabled, capability_not_declared, last_owner_protected · 429 slow down

security_access.set_masked_fields

Hide fields from one person — Keeps the rows visible and the named fields hidden.

Needs security_access:manage · removes or cannot be undone

POSThttps://app.getera.io/api/v1/access_grants/actions/set_masked_fields
API key or OAuth token · security_access:manage
  • Canonical address: POST /api/v1/actions/security_access.set_masked_fields

Input

FieldTypeRequiredNotes
grant_iduuidyesGrant
fieldsstringFields to hide · Comma separated.

Preconditions

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

CodeRefused when
grant_not_foundThat grant no longer exists.
measure_not_maskableA report grant may only hide a measure that report actually shows.

Events it publishes: security_access.access_granted

What it writes: access_grant (update) — Updates the hidden field list

curl -X POST https://app.getera.io/api/v1/access_grants/actions/set_masked_fields \
  -H "Authorization: Bearer $ERA_API_KEY" \
  -H "Content-Type: application/json" \
  -H "Idempotency-Key: $(uuidgen)" \
  -d '{"grant_id":"GRANT_ID"}'
Response
{
  "ok": true,
  "result": "…",
  "events": [
    "security_access.access_granted"
  ]
}
import { createEra } from "@getera/sdk"

const era = createEra({ apiKey: process.env.ERA_API_KEY })
const res = await era.accessGrants.setMaskedFields({
  grant_id: "GRANT_ID"
})
era access_grants set_masked_fields \
  --grant-id "GRANT_ID"
tools/call
{
  "name": "era__security_access__set_masked_fields",
  "arguments": {
    "grant_id": "GRANT_ID"
  }
}

Errors: 401 no or expired credential · 403 the credential does not hold security_access:manage · 404 the record or module is outside what it may reach · 422 invalid input (problems[]) · 409 grant_not_found, measure_not_maskable · 429 slow down

security_access.set_member_role

Change a member’s role — Moves someone to a different role in this workspace.

Needs security_access:manage · removes or cannot be undone

POSThttps://app.getera.io/api/v1/workspace_members/actions/set_member_role
API key or OAuth token · security_access:manage
  • Canonical address: POST /api/v1/actions/security_access.set_member_role

Input

FieldTypeRequiredNotes
user_iduuidyesMember
role_iduuidyesRole · id of role

Preconditions

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

CodeRefused when
cannot_change_own_roleYou cannot change your own role.
role_not_in_workspaceThat role belongs to a different workspace.
not_a_memberThey are not a member of this workspace.

Events it publishes: security_access.role_changed

What it writes: workspace_member (update) — Points the member at the new role

curl -X POST https://app.getera.io/api/v1/workspace_members/actions/set_member_role \
  -H "Authorization: Bearer $ERA_API_KEY" \
  -H "Content-Type: application/json" \
  -H "Idempotency-Key: $(uuidgen)" \
  -d '{"user_id":"USER_ID","role_id":"ROLE_ID"}'
Response
{
  "ok": true,
  "result": "…",
  "events": [
    "security_access.role_changed"
  ]
}
import { createEra } from "@getera/sdk"

const era = createEra({ apiKey: process.env.ERA_API_KEY })
const res = await era.workspaceMembers.setMemberRole({
  user_id: "USER_ID",
  role_id: "ROLE_ID"
})
era workspace_members set_member_role \
  --user-id "USER_ID" \
  --role-id "ROLE_ID"
tools/call
{
  "name": "era__security_access__set_member_role",
  "arguments": {
    "user_id": "USER_ID",
    "role_id": "ROLE_ID"
  }
}

Errors: 401 no or expired credential · 403 the credential does not hold security_access:manage · 404 the record or module is outside what it may reach · 422 invalid input (problems[]) · 409 cannot_change_own_role, role_not_in_workspace, not_a_member · 429 slow down

security_access.set_reports_to

Set who a member reports to — Builds the line a “their own and their reports’” role follows.

Needs security_access:manage · removes or cannot be undone

POSThttps://app.getera.io/api/v1/workspace_members/actions/set_reports_to
API key or OAuth token · security_access:manage
  • Canonical address: POST /api/v1/actions/security_access.set_reports_to

Input

FieldTypeRequiredNotes
user_iduuidyesMember
reports_touuidReports to · id of app_user

Preconditions

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

CodeRefused when
cannot_report_to_selfSomeone cannot report to themselves.
would_create_cycleThat would make two people report to each other.
not_a_memberBoth must be members of this workspace.

Events it publishes: security_access.reports_to_changed

What it writes: workspace_member (update) — Sets the reporting line

curl -X POST https://app.getera.io/api/v1/workspace_members/actions/set_reports_to \
  -H "Authorization: Bearer $ERA_API_KEY" \
  -H "Content-Type: application/json" \
  -H "Idempotency-Key: $(uuidgen)" \
  -d '{"user_id":"USER_ID"}'
Response
{
  "ok": true,
  "result": "…",
  "events": [
    "security_access.reports_to_changed"
  ]
}
import { createEra } from "@getera/sdk"

const era = createEra({ apiKey: process.env.ERA_API_KEY })
const res = await era.workspaceMembers.setReportsTo({
  user_id: "USER_ID"
})
era workspace_members set_reports_to \
  --user-id "USER_ID"
tools/call
{
  "name": "era__security_access__set_reports_to",
  "arguments": {
    "user_id": "USER_ID"
  }
}

Errors: 401 no or expired credential · 403 the credential does not hold security_access:manage · 404 the record or module is outside what it may reach · 422 invalid input (problems[]) · 409 cannot_report_to_self, would_create_cycle, not_a_member · 429 slow down

security_access.set_role_channels

Limit a role to sales channels — Restricts shop access to selected channels; an empty selection grants no channels.

Needs security_access:manage · removes or cannot be undone

POSThttps://app.getera.io/api/v1/roles/{id}/actions/set_role_channels
API key or OAuth token · security_access:manage
  • Canonical address: POST /api/v1/actions/security_access.set_role_channels

Input

FieldTypeRequiredNotes
role_iduuidyesFilled from the path {id} · Role · id of role
restrictedbooleanyesRestrict channels
channel_idsobject / arrayChannels

Preconditions

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

CodeRefused when
system_role_protectedThe owner role cannot be restricted.
channel_scope_invalidEvery selected channel must belong to this workspace.

Events it publishes: security_access.role_channels_changed

What it writes: role (update) — Sets the sales channel scope of this role

curl -X POST https://app.getera.io/api/v1/roles/ROLE_ID/actions/set_role_channels \
  -H "Authorization: Bearer $ERA_API_KEY" \
  -H "Content-Type: application/json" \
  -H "Idempotency-Key: $(uuidgen)" \
  -d '{"restricted":true}'
Response
{
  "ok": true,
  "result": "…",
  "events": [
    "security_access.role_channels_changed"
  ]
}
import { createEra } from "@getera/sdk"

const era = createEra({ apiKey: process.env.ERA_API_KEY })
const res = await era.roles.setRoleChannels("ROLE_ID", {
  restricted: true
})
era roles set_role_channels ROLE_ID \
  --restricted true
tools/call
{
  "name": "era__security_access__set_role_channels",
  "arguments": {
    "role_id": "ROLE_ID",
    "restricted": true
  }
}

Errors: 401 no or expired credential · 403 the credential does not hold security_access:manage · 404 the record or module is outside what it may reach · 422 invalid input (problems[]) · 409 system_role_protected, channel_scope_invalid · 429 slow down

security_access.toggle_feature

Switch part of a module on or off — Turns one part of a module on — appointments, group classes, packages.

Needs security_access:manage · removes or cannot be undone

POSThttps://app.getera.io/api/v1/workspace_modules/actions/toggle_feature
API key or OAuth token · security_access:manage
  • Canonical address: POST /api/v1/actions/security_access.toggle_feature

Input

FieldTypeRequiredNotes
module_codestringyesModule · max 41
featurestringyesPart · max 41
enabledbooleanyesEnabled

Preconditions

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

CodeRefused when
module_not_enabledThe module itself is switched off.
unknown_featureThat module has no such part.

Events it publishes: security_access.feature_enabled, security_access.feature_disabled

What it writes: workspace_module (update) — Updates the enabled parts

curl -X POST https://app.getera.io/api/v1/workspace_modules/actions/toggle_feature \
  -H "Authorization: Bearer $ERA_API_KEY" \
  -H "Content-Type: application/json" \
  -H "Idempotency-Key: $(uuidgen)" \
  -d '{"module_code":"Module","feature":"Part","enabled":true}'
Response
{
  "ok": true,
  "result": "…",
  "events": [
    "security_access.feature_enabled",
    "security_access.feature_disabled"
  ]
}
import { createEra } from "@getera/sdk"

const era = createEra({ apiKey: process.env.ERA_API_KEY })
const res = await era.workspaceModules.toggleFeature({
  module_code: "Module",
  feature: "Part",
  enabled: true
})
era workspace_modules toggle_feature \
  --module-code "Module" \
  --feature "Part" \
  --enabled true
tools/call
{
  "name": "era__security_access__toggle_feature",
  "arguments": {
    "module_code": "Module",
    "feature": "Part",
    "enabled": true
  }
}

Errors: 401 no or expired credential · 403 the credential does not hold security_access:manage · 404 the record or module is outside what it may reach · 422 invalid input (problems[]) · 409 module_not_enabled, unknown_feature · 429 slow down

security_access.toggle_module

Switch a module on or off — Adds a module to this workspace, or takes it away without deleting its data.

Needs security_access:manage · removes or cannot be undone

POSThttps://app.getera.io/api/v1/workspace_modules/actions/toggle_module
API key or OAuth token · security_access:manage
  • Canonical address: POST /api/v1/actions/security_access.toggle_module

Input

FieldTypeRequiredNotes
module_codestringyesModule · max 41
enabledbooleanyesEnabled
with_dependenciesbooleanInstall what it needs too · Switches on every missing dependency first, in the same transaction.

Preconditions

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

CodeRefused when
shell_moduleThis is part of the shell and is always on.
missing_dependencyThis module needs another one that is switched off.
dependents_enabledOther modules that are switched on depend on this one.
module_limit_reachedThe workspace must have room for the module and its dependencies on its plan.

Events it publishes: security_access.module_enabled, security_access.module_disabled

What it writes: workspace_module (upsert) — Switches the module on or off

curl -X POST https://app.getera.io/api/v1/workspace_modules/actions/toggle_module \
  -H "Authorization: Bearer $ERA_API_KEY" \
  -H "Content-Type: application/json" \
  -H "Idempotency-Key: $(uuidgen)" \
  -d '{"module_code":"Module","enabled":true}'
Response
{
  "ok": true,
  "result": "…",
  "events": [
    "security_access.module_enabled",
    "security_access.module_disabled"
  ]
}
import { createEra } from "@getera/sdk"

const era = createEra({ apiKey: process.env.ERA_API_KEY })
const res = await era.workspaceModules.toggleModule({
  module_code: "Module",
  enabled: true
})
era workspace_modules toggle_module \
  --module-code "Module" \
  --enabled true
tools/call
{
  "name": "era__security_access__toggle_module",
  "arguments": {
    "module_code": "Module",
    "enabled": true
  }
}

Errors: 401 no or expired credential · 403 the credential does not hold security_access:manage · 404 the record or module is outside what it may reach · 422 invalid input (problems[]) · 409 shell_module, missing_dependency, dependents_enabled, module_limit_reached · 429 slow down

Data models

AccessGrant

Table access_grant · Resource access_grants

  • GET /api/v1/access_grants
  • GET /api/v1/access_grants/{id}
ColumnTypeNullableAllowed valuesReferences
idstring (uuid) · uuid
organization_idstring (uuid) · uuidorganization
workspace_idstring (uuid) · uuidworkspace
user_idstring (uuid) · uuidapp_user
subject_typestring · textmodule, report, view
subject_keystring · text
capabilitystring · text
row_scopestring · textall, own_records, own_and_reports
masked_fieldsstring[] · text[]
granted_bystring (uuid) · uuidyesapp_user
expires_atstring (date-time) · timestamptzyes
created_atstring (date-time) · timestamptz
updated_atstring (date-time) · timestamptz
channel_idsstring[] · uuid[]yes

Primary key: id

Unique: workspace_id, user_id, subject_type, subject_key, capability

BlueprintInstall

Table blueprint_install · Resource blueprint_installs

  • GET /api/v1/blueprint_installs
  • GET /api/v1/blueprint_installs/{id}
ColumnTypeNullableAllowed valuesReferences
idstring (uuid) · uuid
organization_idstring (uuid) · uuidorganization
workspace_idstring (uuid) · uuidworkspace
blueprint_codestring · text
versioninteger · int4
modulesstring[] · text[]
applied_by_user_idstring (uuid) · uuidyesapp_user
first_applied_atstring (date-time) · timestamptz
applied_atstring (date-time) · timestamptz
apply_countinteger · int4
choicesobject · jsonbyes
sample_recordsobject · jsonb

Primary key: id

Unique: workspace_id, blueprint_code

Checks:

  • CHECK ((apply_count > 0))
  • CHECK ((blueprint_code ~ '^[a-z][a-z0-9_]{1,40}$'::text))
  • CHECK (((choices IS NULL) OR (jsonb_typeof(choices) = 'object'::text)))
  • CHECK ((jsonb_typeof(sample_records) = 'array'::text))
  • CHECK ((version > 0))

RoleModuleCapability

Table role_module_capability · Resource role_module_capabilities

  • GET /api/v1/role_module_capabilities
  • GET /api/v1/role_module_capabilities/{id}
ColumnTypeNullableAllowed valuesReferences
idstring (uuid) · uuid
organization_idstring (uuid) · uuidorganization
workspace_idstring (uuid) · uuidworkspace
role_idstring (uuid) · uuidrole
module_codestring · textmodule
capabilitystring · textread, write, delete, manage, approve, export, comment, handle, import, impersonate, own_records_only, computer_use, computer_control
own_records_scopestring · textself_only, self_and_reports

Primary key: id

Unique: role_id, module_code, capability

Checks:

  • CHECK (((capability = 'own_records_only'::text) OR (own_records_scope = 'self_only'::text)))

Role

Table role · Resource roles

ColumnTypeNullableAllowed valuesReferences
idstring (uuid) · uuid
organization_idstring (uuid) · uuidorganization
workspace_idstring (uuid) · uuidworkspace
codestring · text
labelstring · text
descriptionstring · textyes
is_systemboolean · bool
created_atstring (date-time) · timestamptz
sort_orderinteger · int4
updated_atstring (date-time) · timestamptz
channel_idsstring[] · uuid[]yes

Primary key: id

Unique: workspace_id, code

Checks:

  • CHECK ((code ~ '^[a-z][a-z0-9_]{1,40}$'::text))

WorkspaceMember

Table workspace_member · Resource workspace_members

  • GET /api/v1/workspace_members
  • GET /api/v1/workspace_members/{id}
ColumnTypeNullableAllowed valuesReferences
idstring (uuid) · uuid
organization_idstring (uuid) · uuidorganization
workspace_idstring (uuid) · uuidworkspace
user_idstring (uuid) · uuidapp_user
role_idstring (uuid) · uuidrole
created_atstring (date-time) · timestamptz
statusstring · textactive, suspended
updated_atstring (date-time) · timestamptz
reports_tostring (uuid) · uuidyesapp_user
colorstring · textyes

Primary key: id

Unique: workspace_id, user_id

Checks:

  • CHECK (((color IS NULL) OR (color ~ '^#[0-9A-Fa-f]{6}$'::text)))
  • CHECK (((reports_to IS NULL) OR (reports_to <> user_id)))

WorkspaceModule

Table workspace_module · Resource workspace_modules

  • GET /api/v1/workspace_modules
  • GET /api/v1/workspace_modules/{id}
ColumnTypeNullableAllowed valuesReferences
idstring (uuid) · uuid
organization_idstring (uuid) · uuidorganization
workspace_idstring (uuid) · uuidworkspace
module_codestring · textmodule
enabledboolean · bool
sidebar_groupstring · textyes
sidebar_orderinteger · int4
enabled_atstring (date-time) · timestamptz
enabled_featuresstring[] · text[]
updated_atstring (date-time) · timestamptz

Primary key: id

Unique: workspace_id, module_code

Events

Workflows and webhooks react to these events.

EventWhat happensPayload
security_access.access_grantedAccess was granted to one person directly.user_id, subject_type, subject_key
security_access.access_revokedA personal grant was revoked.grant_id
security_access.blueprint_appliedAn industry blueprint was installed or re-applied.blueprint_code, version, installed, first
security_access.capability_grantedA capability was granted to a role.role_id, module_code, capability
security_access.capability_revokedA capability was taken away from a role.role_id, module_code, capability
security_access.feature_disabledPart of a module was switched off.module_code, feature
security_access.feature_enabledPart of a module was switched on.module_code, feature
security_access.module_disabledA module was switched off.module_code
security_access.module_enabledA module was switched on for the workspace.module_code
security_access.reports_to_changedA reporting line changed.user_id, reports_to
security_access.role_changedA member’s role was changed.user_id, role_id
security_access.role_channels_changedThe sales channel scope of a role changed.role_id, channel_ids
security_access.role_createdA workspace role was created.role_id, code
security_access.role_deletedA workspace role was deleted.role_id, code
security_access.shop_openedThe shop was opened in one step: shop modules on, a sales channel open.channelId, name, currency, installed
Was this page helpful?