ReferenceReference by module

Organization API

Every Organization action (17) and data model (1): endpoints, scopes, input, preconditions, events and examples.

Your business, its workspaces, branding and the people in it.

Module code organizations · 17 actions · 1 data models · 19 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: organizations (everything), organizations:read (read only) or organizations:<capability>.

Resources

ResourceTableList and readPOSTPATCHDELETE
employeesemployee/api/v1/employees

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
organizations.create_workspaceorganizations:manageCreate workspace
organizations.delete_workspaceorganizations:manageDelete workspace
organizations.invite_memberorganizations:manageInvite member
organizations.remove_memberorganizations:manageRemove member
organizations.reorder_employeesorganizations:manageReorder the team
organizations.resend_inviteorganizations:manageResend invitation
organizations.revoke_inviteorganizations:manageRevoke invitation
organizations.save_first_runorganizations:manageSave first-run progress
organizations.save_onboarding_progressorganizations:manageSave setup progress
organizations.set_employee_visibleorganizations:manageShow or hide a staff profile
organizations.set_era_preferencesorganizations:readChoose Era preferences
organizations.set_interface_languageorganizations:readChoose interface language
organizations.set_member_statusorganizations:manageSuspend or reinstate a member
organizations.transfer_ownershiporganizations:manageTransfer ownership
organizations.updateorganizations:manageUpdate the organization
organizations.update_employee_profileorganizations:writeEdit a staff profile
organizations.update_workspaceorganizations:manageUpdate workspace

organizations.create_workspace

Create workspace — Opens a second workspace in this organization, with the six system roles.

Needs organizations:manage · removes or cannot be undone

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

Input

FieldTypeRequiredNotes
namestringyesName · max 120
slugstringyesURL name · Lowercase letters, numbers and hyphens. Used in links. · max 40

Preconditions

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

CodeRefused when
slug_formatThe URL name must start with a letter and contain only lowercase letters, numbers and hyphens.
slug_takenAnother workspace in this organization already uses that URL name.

Events it publishes: organizations.workspace_created

What it writes: workspace (insert) — Creates the workspace, its six system roles and its first member

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

const era = createEra({ apiKey: process.env.ERA_API_KEY })
const res = await era.actions.run("organizations.create_workspace", {
  name: "Name",
  slug: "URL name"
})
era organizations create_workspace \
  --name "Name" \
  --slug "URL name"
tools/call
{
  "name": "era__organizations__create_workspace",
  "arguments": {
    "name": "Name",
    "slug": "URL name"
  }
}

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

organizations.delete_workspace

Delete workspace — Deletes a workspace and everything inside it.

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

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

Input

FieldTypeRequiredNotes
workspace_iduuidyesWorkspace

Preconditions

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

CodeRefused when
last_workspace_protectedAn organization must keep at least one workspace.

Events it publishes: organizations.workspace_deleted

What it writes: workspace (delete) — Deletes the workspace and cascades to its data

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

const era = createEra({ apiKey: process.env.ERA_API_KEY })
const res = await era.actions.run("organizations.delete_workspace", {
  workspace_id: "WORKSPACE_ID"
})
era organizations delete_workspace \
  --workspace-id "WORKSPACE_ID"
tools/call
{
  "name": "era__organizations__delete_workspace",
  "arguments": {
    "workspace_id": "WORKSPACE_ID"
  }
}

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

organizations.invite_member

Invite member — Sends an invitation, to an address that does not need an account yet.

Needs organizations:manage · removes or cannot be undone

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

Input

FieldTypeRequiredNotes
emailemailyesEmail
org_rolestring (enum)yesOrganization role · Governs billing and membership. What they can reach is decided by the workspace role. · Allowed values: member, admin, owner
role_iduuidyesWorkspace role · id of role
expires_in_daysnumberExpires in · min 1 · max 30

Preconditions

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

CodeRefused when
already_memberThat address already belongs to this organization.
invite_openThat address already has an invitation waiting.
role_not_in_workspaceThat role belongs to a different workspace.
seat_limit_reachedThe organization must have a free seat on its plan.

Events it publishes: organizations.member_invited

What it writes: invitation (insert) — Creates the invitation and its single-use token

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

const era = createEra({ apiKey: process.env.ERA_API_KEY })
const res = await era.actions.run("organizations.invite_member", {
  email: "[email protected]",
  org_role: "member",
  role_id: "ROLE_ID"
})
era organizations invite_member \
  --email "[email protected]" \
  --org-role "member" \
  --role-id "ROLE_ID"
tools/call
{
  "name": "era__organizations__invite_member",
  "arguments": {
    "email": "[email protected]",
    "org_role": "member",
    "role_id": "ROLE_ID"
  }
}

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

organizations.remove_member

Remove member — Removes someone from the organization and hands their work to someone else.

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

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

Input

FieldTypeRequiredNotes
user_iduuidyesMember
reassign_touuidHand their work to · Required when they still own records. Nothing may be left unassigned. · id of app_user

Preconditions

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

CodeRefused when
cannot_remove_selfYou cannot remove yourself. Ask another owner.
not_a_memberThey are not a member of this organization.
last_owner_protectedAn organization must keep at least one active owner.
transfer_target_invalidTheir work can only be handed to another active member.

Events it publishes: organizations.member_removed, organizations.member_offboarded

What it writes: membership (delete) — Removes them from the organization and from every workspace in it; hands on or switches off what they own

curl -X POST https://app.getera.io/api/v1/actions/organizations.remove_member \
  -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": [
    "organizations.member_removed",
    "organizations.member_offboarded"
  ]
}
import { createEra } from "@getera/sdk"

const era = createEra({ apiKey: process.env.ERA_API_KEY })
const res = await era.actions.run("organizations.remove_member", {
  user_id: "USER_ID"
})
era organizations remove_member \
  --user-id "USER_ID"
tools/call
{
  "name": "era__organizations__remove_member",
  "arguments": {
    "user_id": "USER_ID"
  }
}

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

organizations.reorder_employees

Reorder the team — Sets the order staff appear in on the public team page.

Needs organizations:manage · removes or cannot be undone

POSThttps://app.getera.io/api/v1/employees/actions/reorder_employees
API key or OAuth token · organizations:manage
  • Canonical address: POST /api/v1/actions/organizations.reorder_employees

Input

FieldTypeRequiredNotes
orderobject / arrayyesOrder · The member ids, first to last.

Preconditions

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

CodeRefused when
unknown_memberEvery id must belong to somebody with a staff profile here.
duplicate_positionThe same person cannot appear twice in one order.

Events it publishes: organizations.profile_updated

What it writes: employee (update) — Rewrites sort_order for the listed profiles

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

const era = createEra({ apiKey: process.env.ERA_API_KEY })
const res = await era.employees.reorderEmployees({
  order: {}
})
era employees reorder_employees --data '{"order":{}}'
tools/call
{
  "name": "era__organizations__reorder_employees",
  "arguments": {
    "order": {}
  }
}

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

organizations.resend_invite

Resend invitation — Issues a fresh link for a waiting invitation and restarts its expiry. The old link stops working.

Needs organizations:manage · removes or cannot be undone

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

Input

FieldTypeRequiredNotes
invitation_iduuidyesInvitation
expires_in_daysnumberExpires in · min 1 · max 30

Preconditions

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

CodeRefused when
invite_not_foundThe invitation must exist in this organization.
already_acceptedThat invitation has already been accepted.
invite_revokedA revoked invitation is not re-sent; invite them again instead.

Events it publishes: organizations.invite_resent

What it writes: invitation (update) — Replaces the token and restarts the expiry

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

const era = createEra({ apiKey: process.env.ERA_API_KEY })
const res = await era.actions.run("organizations.resend_invite", {
  invitation_id: "INVITATION_ID"
})
era organizations resend_invite \
  --invitation-id "INVITATION_ID"
tools/call
{
  "name": "era__organizations__resend_invite",
  "arguments": {
    "invitation_id": "INVITATION_ID"
  }
}

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

organizations.revoke_invite

Revoke invitation — Withdraws an invitation that has not been accepted.

Needs organizations:manage · removes or cannot be undone

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

Input

FieldTypeRequiredNotes
invitation_iduuidyesInvitation

Preconditions

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

CodeRefused when
already_acceptedThat invitation has already been accepted.

Events it publishes: organizations.invite_revoked

What it writes: invitation (update) — Marks the invitation revoked

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

const era = createEra({ apiKey: process.env.ERA_API_KEY })
const res = await era.actions.run("organizations.revoke_invite", {
  invitation_id: "INVITATION_ID"
})
era organizations revoke_invite \
  --invitation-id "INVITATION_ID"
tools/call
{
  "name": "era__organizations__revoke_invite",
  "arguments": {
    "invitation_id": "INVITATION_ID"
  }
}

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

organizations.save_first_run

Save first-run progress — Keeps which first-run stages were put off or finished, so the same progress shows on the web, the desktop and the phone.

Needs organizations:manage · removes or cannot be undone

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

Input

FieldTypeRequiredNotes
skipobject / arrayPut off
unskipobject / arrayTake back up
setobject / arrayValues · { eraChatId }
finishedbooleanFinished
hoststringHost · max 20

Events it publishes: organizations.first_run_saved

What it writes: org_onboarding (update) — Saves the first-run journey beside the setup draft

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

const era = createEra({ apiKey: process.env.ERA_API_KEY })
const res = await era.actions.run("organizations.save_first_run", {
  skip: {}
})
era organizations save_first_run --data '{"skip":{}}'
tools/call
{
  "name": "era__organizations__save_first_run",
  "arguments": {
    "skip": {}
  }
}

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

organizations.save_onboarding_progress

Save setup progress — Keeps the current onboarding screen and answers so setup resumes on any device.

Needs organizations:manage · removes or cannot be undone

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

Input

FieldTypeRequiredNotes
stepstringyesStep · max 40
codestringBusiness blueprint · max 80
choicesobject / arrayAnswers
donebooleanCompleted

Events it publishes: organizations.onboarding_progress_saved

What it writes: org_onboarding (update) — Saves or completes the organization setup draft

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

const era = createEra({ apiKey: process.env.ERA_API_KEY })
const res = await era.actions.run("organizations.save_onboarding_progress", {
  step: "Step"
})
era organizations save_onboarding_progress \
  --step "Step"
tools/call
{
  "name": "era__organizations__save_onboarding_progress",
  "arguments": {
    "step": "Step"
  }
}

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

organizations.set_employee_visible

Show or hide a staff profile — Whether this person appears on the public team page and in the staff pickers.

Needs organizations:manage · removes or cannot be undone

POSThttps://app.getera.io/api/v1/employees/actions/set_employee_visible
API key or OAuth token · organizations:manage
  • Canonical address: POST /api/v1/actions/organizations.set_employee_visible

Input

FieldTypeRequiredNotes
user_iduuidyesMember
is_activebooleanyesShown

Preconditions

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

CodeRefused when
member_not_foundThey must have a staff profile in this workspace.
no_changeThey are already in that state.

Events it publishes: organizations.employee_hidden, organizations.employee_shown

What it writes: employee (update) — Flips the profile’s visibility

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

const era = createEra({ apiKey: process.env.ERA_API_KEY })
const res = await era.employees.setEmployeeVisible({
  user_id: "USER_ID",
  is_active: true
})
era employees set_employee_visible \
  --user-id "USER_ID" \
  --is-active true
tools/call
{
  "name": "era__organizations__set_employee_visible",
  "arguments": {
    "user_id": "USER_ID",
    "is_active": true
  }
}

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

organizations.set_era_preferences

Choose Era preferences — Era’s voice, reading answers aloud, which AI answers, coding permissions and the theme — the same on your computer and the web.

Needs organizations:read · changes data

POSThttps://app.getera.io/api/v1/actions/organizations.set_era_preferences
API key or OAuth token · organizations:read

Input

FieldTypeRequiredNotes
prefsobject / arrayPreferences · { voice, speak, source, permissionMode, theme } — null forgets a key.
languagestring (enum)Language · Allowed values: en, tr

Events it publishes: organizations.era_preferences_changed

What it writes: app_user (update) — Remembers your Era preferences for every device

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

const era = createEra({ apiKey: process.env.ERA_API_KEY })
const res = await era.actions.run("organizations.set_era_preferences", {
  prefs: {}
})
era organizations set_era_preferences --data '{"prefs":{}}'
tools/call
{
  "name": "era__organizations__set_era_preferences",
  "arguments": {
    "prefs": {}
  }
}

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

organizations.set_interface_language

Choose interface language — The language menus, buttons and messages are shown to you in. Leave empty to follow the workspace.

Needs organizations:read · changes data

POSThttps://app.getera.io/api/v1/actions/organizations.set_interface_language
API key or OAuth token · organizations:read

Input

FieldTypeRequiredNotes
localestring (enum)Interface language · Allowed values: en, tr

Events it publishes: organizations.interface_language_changed

What it writes: app_user (update) — Remembers your interface language

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

const era = createEra({ apiKey: process.env.ERA_API_KEY })
const res = await era.actions.run("organizations.set_interface_language", {
  locale: "en"
})
era organizations set_interface_language \
  --locale "en"
tools/call
{
  "name": "era__organizations__set_interface_language",
  "arguments": {
    "locale": "en"
  }
}

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

organizations.set_member_status

Suspend or reinstate a member — Locks someone out without removing them, and lets them back in.

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

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

Input

FieldTypeRequiredNotes
user_iduuidyesMember
statusstring (enum)yesStatus · Suspending keeps their records and their history; removing them does not. · Allowed values: active, suspended

Preconditions

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

CodeRefused when
cannot_suspend_selfYou cannot suspend yourself. Ask another owner.
not_a_memberThey are not a member of this organization.
last_owner_protectedAn organization must keep at least one active owner.
already_setThey are already in that state.

Events it publishes: organizations.member_status_changed

What it writes: membership (update) — Sets the organization membership status

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

const era = createEra({ apiKey: process.env.ERA_API_KEY })
const res = await era.actions.run("organizations.set_member_status", {
  user_id: "USER_ID",
  status: "active"
})
era organizations set_member_status \
  --user-id "USER_ID" \
  --status "active"
tools/call
{
  "name": "era__organizations__set_member_status",
  "arguments": {
    "user_id": "USER_ID",
    "status": "active"
  }
}

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

organizations.transfer_ownership

Transfer ownership — Hands the organization to another member. You become an admin.

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

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

Input

FieldTypeRequiredNotes
user_iduuidyesNew owner

Preconditions

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

CodeRefused when
not_a_memberThe new owner must already be an active member.
already_ownerThey are already the owner.
not_ownerOnly the current owner can hand the organization on.

Events it publishes: organizations.ownership_transferred

What it writes: membership (update) — Swaps the two organization roles

curl -X POST https://app.getera.io/api/v1/actions/organizations.transfer_ownership \
  -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": [
    "organizations.ownership_transferred"
  ]
}
import { createEra } from "@getera/sdk"

const era = createEra({ apiKey: process.env.ERA_API_KEY })
const res = await era.actions.run("organizations.transfer_ownership", {
  user_id: "USER_ID"
})
era organizations transfer_ownership \
  --user-id "USER_ID"
tools/call
{
  "name": "era__organizations__transfer_ownership",
  "arguments": {
    "user_id": "USER_ID"
  }
}

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

organizations.update

Update the organization — Its name, legal details, billing address and the defaults every workspace inherits.

Needs organizations:manage · removes or cannot be undone

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

Input

FieldTypeRequiredNotes
namestringName · What it is called in the app. · max 120
descriptionstringDescription · max 500
legal_namestringLegal name · The registered company name, for invoices and contracts. · max 200
tax_idstringTax number · max 64
primary_emailemailContact email
billing_emailemailBilling email
phonephonePhone
address_line1stringAddress · max 200
address_line2stringAddress line 2 · max 200
citystringCity · max 100
postal_codestringPostcode · max 20
regionstringRegion · max 100
default_countrystringCountry · Two-letter code. Tax and shipping rules key off it. · max 2
default_currencystringCurrency · Three-letter code. A sales channel may override it. · max 3
default_localestringLanguage · max 10
timezonestringTime zone · max 64
logo_file_iduuidLogo · A wide image. Shown in emails and, when the site has none, on the site. · id of file
icon_file_iduuidIcon · A square image. Shown in the sidebar and on Home. · id of file

Preconditions

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

CodeRefused when
not_an_imageA logo or icon must be an image file in this workspace.
invalid_countryThe country must be a two-letter code, such as TR or DE.
invalid_currencyThe currency must be a three-letter code, such as TRY or EUR.
nothing_to_changeNo fields were given.

Events it publishes: organizations.updated

What it writes: organization (update) — Updates the organization profile

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

const era = createEra({ apiKey: process.env.ERA_API_KEY })
const res = await era.actions.run("organizations.update", {
  name: "Name"
})
era organizations update \
  --name "Name"
tools/call
{
  "name": "era__organizations__update",
  "arguments": {
    "name": "Name"
  }
}

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

organizations.update_employee_profile

Edit a staff profile — The position, biography, experience, schooling, links and specialities shown for a person.

Needs organizations:write · changes data

POSThttps://app.getera.io/api/v1/employees/actions/update_employee_profile
API key or OAuth token · organizations:write
  • Canonical address: POST /api/v1/actions/organizations.update_employee_profile

Input

FieldTypeRequiredNotes
user_iduuidyesMember
positionstringPosition / title · max 100
biostringBiography · max 4000
experience_yearsnumberYears of experience · max 80
educationstringEducation · max 2000
social_linksobject / arraySocial links · Platform to address, one pair at a time — linkedin, instagram, x.
expertise_areasobject / arraySpecialities · Free-text labels for the public team page. Not the same thing as which services somebody may perform.

Preconditions

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

CodeRefused when
member_not_foundThey must be a member of this workspace.
not_self_without_manageEditing somebody else’s profile needs the Configure capability.
experience_negativeYears of experience cannot be negative.
social_links_not_objectSocial links are platform-and-address pairs, not a list.
social_link_url_invalidEvery social link must be an http or https address.

Events it publishes: organizations.profile_updated

What it writes: employee (upsert) — Creates or updates the staff profile

curl -X POST https://app.getera.io/api/v1/employees/actions/update_employee_profile \
  -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": [
    "organizations.profile_updated"
  ]
}
import { createEra } from "@getera/sdk"

const era = createEra({ apiKey: process.env.ERA_API_KEY })
const res = await era.employees.updateEmployeeProfile({
  user_id: "USER_ID"
})
era employees update_employee_profile \
  --user-id "USER_ID"
tools/call
{
  "name": "era__organizations__update_employee_profile",
  "arguments": {
    "user_id": "USER_ID"
  }
}

Errors: 401 no or expired credential · 403 the credential does not hold organizations:write · 404 the record or module is outside what it may reach · 422 invalid input (problems[]) · 409 member_not_found, not_self_without_manage, experience_negative, social_links_not_object, social_link_url_invalid · 429 slow down

organizations.update_workspace

Update workspace — Its name, URL name and the currency, language and time zone it works in.

Needs organizations:manage · removes or cannot be undone

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

Input

FieldTypeRequiredNotes
workspace_iduuidyesWorkspace
namestringName · max 120
slugstringURL name · Lowercase letters, numbers and hyphens. Changing it changes existing links. · max 40
descriptionstringDescription · max 500
currencystringCurrency · Three letters. Leave empty to use the organization’s. · max 3
localestringLanguage · max 10
timezonestringTime zone · max 64
logo_file_iduuidLogo · A wide image. Shown in emails and, when the site has none, on the site. · id of file
icon_file_iduuidIcon · A square image. Shown in the sidebar and on Home. · id of file

Preconditions

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

CodeRefused when
not_an_imageA logo or icon must be an image file in this workspace.
not_foundThat workspace is not in this organization.
slug_formatThe URL name must start with a letter and contain only lowercase letters, numbers and hyphens.
slug_takenAnother workspace in this organization already uses that URL name.
invalid_currencyThe currency must be a three-letter code, such as TRY or EUR.
nothing_to_changeNo fields were given.

Events it publishes: organizations.workspace_updated

What it writes: workspace (update) — Updates the workspace profile

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

const era = createEra({ apiKey: process.env.ERA_API_KEY })
const res = await era.actions.run("organizations.update_workspace", {
  workspace_id: "WORKSPACE_ID"
})
era organizations update_workspace \
  --workspace-id "WORKSPACE_ID"
tools/call
{
  "name": "era__organizations__update_workspace",
  "arguments": {
    "workspace_id": "WORKSPACE_ID"
  }
}

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

Data models

Employee

Table employee · Resource employees

  • GET /api/v1/employees
  • GET /api/v1/employees/{id}
ColumnTypeNullableAllowed valuesReferences
organization_idstring (uuid) · uuidorganization
workspace_idstring (uuid) · uuidworkspace
user_idstring (uuid) · uuidapp_user
biostring · textyes
positionstring · textyes
social_linksobject · jsonb
expertise_areasstring[] · text[]
experience_yearsinteger · int4
educationstring · textyes
is_activeboolean · bool
sort_orderinteger · int4
updated_atstring (date-time) · timestamptz

Primary key: workspace_id, user_id

Checks:

  • CHECK ((experience_years >= 0))
  • CHECK ((jsonb_typeof(social_links) = 'object'::text))

Events

Workflows and webhooks react to these events.

EventWhat happensPayload
organizations.employee_hiddenA staff profile was taken off the public team page.user_id
organizations.employee_shownA staff profile was put back on the public team page.user_id
organizations.era_preferences_changedSomebody changed their Era preferences (voice, speaking, AI source, permissions, theme).user_id, keys
organizations.first_run_savedEra’s first run was saved: stages put off, taken back up or finished (O1).skipped, finished
organizations.interface_language_changedSomebody chose the language the product speaks to them in.user_id, locale
organizations.invite_resentA waiting invitation was sent again with a fresh link.email, invitation_id
organizations.invite_revokedAn invitation was withdrawn.email
organizations.member_invitedAn invitation was sent.email, org_role
organizations.member_joinedSomeone accepted an invitation.user_id, org_role
organizations.member_offboardedWhat a departing member owned was handed on or switched off.user_id, transferred_to, ownerUserId, result
organizations.member_removedSomeone was removed from the organization.user_id
organizations.member_status_changedSomeone was suspended or reinstated.user_id, status
organizations.onboarding_progress_savedThe first-run business setup was saved or completed.step, completed
organizations.ownership_transferredThe organization changed hands.from, to
organizations.profile_updatedSomebody’s staff profile was written.user_id
organizations.updatedThe organization profile was changed.field
organizations.workspace_createdA new workspace was created.workspace_id, name
organizations.workspace_deletedA workspace was deleted.workspace_id
organizations.workspace_updatedA workspace profile was changed.workspace_id, field