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
| Resource | Table | List and read | POST | PATCH | DELETE |
|---|---|---|---|---|---|
employees | employee | /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
| Action | Needs | What it does |
|---|---|---|
organizations.create_workspace | organizations:manage | Create workspace |
organizations.delete_workspace | organizations:manage | Delete workspace |
organizations.invite_member | organizations:manage | Invite member |
organizations.remove_member | organizations:manage | Remove member |
organizations.reorder_employees | organizations:manage | Reorder the team |
organizations.resend_invite | organizations:manage | Resend invitation |
organizations.revoke_invite | organizations:manage | Revoke invitation |
organizations.save_first_run | organizations:manage | Save first-run progress |
organizations.save_onboarding_progress | organizations:manage | Save setup progress |
organizations.set_employee_visible | organizations:manage | Show or hide a staff profile |
organizations.set_era_preferences | organizations:read | Choose Era preferences |
organizations.set_interface_language | organizations:read | Choose interface language |
organizations.set_member_status | organizations:manage | Suspend or reinstate a member |
organizations.transfer_ownership | organizations:manage | Transfer ownership |
organizations.update | organizations:manage | Update the organization |
organizations.update_employee_profile | organizations:write | Edit a staff profile |
organizations.update_workspace | organizations:manage | Update 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
https://app.getera.io/api/v1/actions/organizations.create_workspaceInput
| Field | Type | Required | Notes |
|---|---|---|---|
name | string | yes | Name · max 120 |
slug | string | yes | URL name · Lowercase letters, numbers and hyphens. Used in links. · max 40 |
Preconditions
The action is refused with 409 and one of these codes:
| Code | Refused when |
|---|---|
slug_format | The URL name must start with a letter and contain only lowercase letters, numbers and hyphens. |
slug_taken | Another 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"}'{
"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"{
"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
https://app.getera.io/api/v1/actions/organizations.delete_workspaceInput
| Field | Type | Required | Notes |
|---|---|---|---|
workspace_id | uuid | yes | Workspace |
Preconditions
The action is refused with 409 and one of these codes:
| Code | Refused when |
|---|---|
last_workspace_protected | An 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"}'{
"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"{
"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
https://app.getera.io/api/v1/actions/organizations.invite_memberInput
| Field | Type | Required | Notes |
|---|---|---|---|
email | yes | ||
org_role | string (enum) | yes | Organization role · Governs billing and membership. What they can reach is decided by the workspace role. · Allowed values: member, admin, owner |
role_id | uuid | yes | Workspace role · id of role |
expires_in_days | number | Expires in · min 1 · max 30 |
Preconditions
The action is refused with 409 and one of these codes:
| Code | Refused when |
|---|---|
already_member | That address already belongs to this organization. |
invite_open | That address already has an invitation waiting. |
role_not_in_workspace | That role belongs to a different workspace. |
seat_limit_reached | The 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"}'{
"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"{
"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
https://app.getera.io/api/v1/actions/organizations.remove_memberInput
| Field | Type | Required | Notes |
|---|---|---|---|
user_id | uuid | yes | Member |
reassign_to | uuid | Hand 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:
| Code | Refused when |
|---|---|
cannot_remove_self | You cannot remove yourself. Ask another owner. |
not_a_member | They are not a member of this organization. |
last_owner_protected | An organization must keep at least one active owner. |
transfer_target_invalid | Their 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"}'{
"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"{
"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
https://app.getera.io/api/v1/employees/actions/reorder_employees- Canonical address:
POST /api/v1/actions/organizations.reorder_employees
Input
| Field | Type | Required | Notes |
|---|---|---|---|
order | object / array | yes | Order · The member ids, first to last. |
Preconditions
The action is refused with 409 and one of these codes:
| Code | Refused when |
|---|---|
unknown_member | Every id must belong to somebody with a staff profile here. |
duplicate_position | The 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":{}}'{
"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":{}}'{
"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
https://app.getera.io/api/v1/actions/organizations.resend_inviteInput
| Field | Type | Required | Notes |
|---|---|---|---|
invitation_id | uuid | yes | Invitation |
expires_in_days | number | Expires in · min 1 · max 30 |
Preconditions
The action is refused with 409 and one of these codes:
| Code | Refused when |
|---|---|
invite_not_found | The invitation must exist in this organization. |
already_accepted | That invitation has already been accepted. |
invite_revoked | A 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"}'{
"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"{
"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
https://app.getera.io/api/v1/actions/organizations.revoke_inviteInput
| Field | Type | Required | Notes |
|---|---|---|---|
invitation_id | uuid | yes | Invitation |
Preconditions
The action is refused with 409 and one of these codes:
| Code | Refused when |
|---|---|
already_accepted | That 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"}'{
"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"{
"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
https://app.getera.io/api/v1/actions/organizations.save_first_runInput
| Field | Type | Required | Notes |
|---|---|---|---|
skip | object / array | Put off | |
unskip | object / array | Take back up | |
set | object / array | Values · { eraChatId } | |
finished | boolean | Finished | |
host | string | Host · 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":{}}'{
"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":{}}'{
"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
https://app.getera.io/api/v1/actions/organizations.save_onboarding_progressInput
| Field | Type | Required | Notes |
|---|---|---|---|
step | string | yes | Step · max 40 |
code | string | Business blueprint · max 80 | |
choices | object / array | Answers | |
done | boolean | Completed |
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"}'{
"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"{
"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
https://app.getera.io/api/v1/employees/actions/set_employee_visible- Canonical address:
POST /api/v1/actions/organizations.set_employee_visible
Input
| Field | Type | Required | Notes |
|---|---|---|---|
user_id | uuid | yes | Member |
is_active | boolean | yes | Shown |
Preconditions
The action is refused with 409 and one of these codes:
| Code | Refused when |
|---|---|
member_not_found | They must have a staff profile in this workspace. |
no_change | They 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}'{
"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{
"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
https://app.getera.io/api/v1/actions/organizations.set_era_preferencesInput
| Field | Type | Required | Notes |
|---|---|---|---|
prefs | object / array | Preferences · { voice, speak, source, permissionMode, theme } — null forgets a key. | |
language | string (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":{}}'{
"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":{}}'{
"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
https://app.getera.io/api/v1/actions/organizations.set_interface_languageInput
| Field | Type | Required | Notes |
|---|---|---|---|
locale | string (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"}'{
"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"{
"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
https://app.getera.io/api/v1/actions/organizations.set_member_statusInput
| Field | Type | Required | Notes |
|---|---|---|---|
user_id | uuid | yes | Member |
status | string (enum) | yes | Status · 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:
| Code | Refused when |
|---|---|
cannot_suspend_self | You cannot suspend yourself. Ask another owner. |
not_a_member | They are not a member of this organization. |
last_owner_protected | An organization must keep at least one active owner. |
already_set | They 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"}'{
"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"{
"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
https://app.getera.io/api/v1/actions/organizations.transfer_ownershipInput
| Field | Type | Required | Notes |
|---|---|---|---|
user_id | uuid | yes | New owner |
Preconditions
The action is refused with 409 and one of these codes:
| Code | Refused when |
|---|---|
not_a_member | The new owner must already be an active member. |
already_owner | They are already the owner. |
not_owner | Only 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"}'{
"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"{
"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
https://app.getera.io/api/v1/actions/organizations.updateInput
| Field | Type | Required | Notes |
|---|---|---|---|
name | string | Name · What it is called in the app. · max 120 | |
description | string | Description · max 500 | |
legal_name | string | Legal name · The registered company name, for invoices and contracts. · max 200 | |
tax_id | string | Tax number · max 64 | |
primary_email | Contact email | ||
billing_email | Billing email | ||
phone | phone | Phone | |
address_line1 | string | Address · max 200 | |
address_line2 | string | Address line 2 · max 200 | |
city | string | City · max 100 | |
postal_code | string | Postcode · max 20 | |
region | string | Region · max 100 | |
default_country | string | Country · Two-letter code. Tax and shipping rules key off it. · max 2 | |
default_currency | string | Currency · Three-letter code. A sales channel may override it. · max 3 | |
default_locale | string | Language · max 10 | |
timezone | string | Time zone · max 64 | |
logo_file_id | uuid | Logo · A wide image. Shown in emails and, when the site has none, on the site. · id of file | |
icon_file_id | uuid | Icon · 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:
| Code | Refused when |
|---|---|
not_an_image | A logo or icon must be an image file in this workspace. |
invalid_country | The country must be a two-letter code, such as TR or DE. |
invalid_currency | The currency must be a three-letter code, such as TRY or EUR. |
nothing_to_change | No 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"}'{
"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"{
"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
https://app.getera.io/api/v1/employees/actions/update_employee_profile- Canonical address:
POST /api/v1/actions/organizations.update_employee_profile
Input
| Field | Type | Required | Notes |
|---|---|---|---|
user_id | uuid | yes | Member |
position | string | Position / title · max 100 | |
bio | string | Biography · max 4000 | |
experience_years | number | Years of experience · max 80 | |
education | string | Education · max 2000 | |
social_links | object / array | Social links · Platform to address, one pair at a time — linkedin, instagram, x. | |
expertise_areas | object / array | Specialities · 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:
| Code | Refused when |
|---|---|
member_not_found | They must be a member of this workspace. |
not_self_without_manage | Editing somebody else’s profile needs the Configure capability. |
experience_negative | Years of experience cannot be negative. |
social_links_not_object | Social links are platform-and-address pairs, not a list. |
social_link_url_invalid | Every 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"}'{
"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"{
"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
https://app.getera.io/api/v1/actions/organizations.update_workspaceInput
| Field | Type | Required | Notes |
|---|---|---|---|
workspace_id | uuid | yes | Workspace |
name | string | Name · max 120 | |
slug | string | URL name · Lowercase letters, numbers and hyphens. Changing it changes existing links. · max 40 | |
description | string | Description · max 500 | |
currency | string | Currency · Three letters. Leave empty to use the organization’s. · max 3 | |
locale | string | Language · max 10 | |
timezone | string | Time zone · max 64 | |
logo_file_id | uuid | Logo · A wide image. Shown in emails and, when the site has none, on the site. · id of file | |
icon_file_id | uuid | Icon · 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:
| Code | Refused when |
|---|---|
not_an_image | A logo or icon must be an image file in this workspace. |
not_found | That workspace is not in this organization. |
slug_format | The URL name must start with a letter and contain only lowercase letters, numbers and hyphens. |
slug_taken | Another workspace in this organization already uses that URL name. |
invalid_currency | The currency must be a three-letter code, such as TRY or EUR. |
nothing_to_change | No 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"}'{
"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"{
"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/employeesGET /api/v1/employees/{id}
| Column | Type | Nullable | Allowed values | References |
|---|---|---|---|---|
organization_id | string (uuid) · uuid | organization | ||
workspace_id | string (uuid) · uuid | workspace | ||
user_id | string (uuid) · uuid | app_user | ||
bio | string · text | yes | ||
position | string · text | yes | ||
social_links | object · jsonb | |||
expertise_areas | string[] · text[] | |||
experience_years | integer · int4 | |||
education | string · text | yes | ||
is_active | boolean · bool | |||
sort_order | integer · int4 | |||
updated_at | string (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.
| Event | What happens | Payload |
|---|---|---|
organizations.employee_hidden | A staff profile was taken off the public team page. | user_id |
organizations.employee_shown | A staff profile was put back on the public team page. | user_id |
organizations.era_preferences_changed | Somebody changed their Era preferences (voice, speaking, AI source, permissions, theme). | user_id, keys |
organizations.first_run_saved | Era’s first run was saved: stages put off, taken back up or finished (O1). | skipped, finished |
organizations.interface_language_changed | Somebody chose the language the product speaks to them in. | user_id, locale |
organizations.invite_resent | A waiting invitation was sent again with a fresh link. | email, invitation_id |
organizations.invite_revoked | An invitation was withdrawn. | email |
organizations.member_invited | An invitation was sent. | email, org_role |
organizations.member_joined | Someone accepted an invitation. | user_id, org_role |
organizations.member_offboarded | What a departing member owned was handed on or switched off. | user_id, transferred_to, ownerUserId, result |
organizations.member_removed | Someone was removed from the organization. | user_id |
organizations.member_status_changed | Someone was suspended or reinstated. | user_id, status |
organizations.onboarding_progress_saved | The first-run business setup was saved or completed. | step, completed |
organizations.ownership_transferred | The organization changed hands. | from, to |
organizations.profile_updated | Somebody’s staff profile was written. | user_id |
organizations.updated | The organization profile was changed. | field |
organizations.workspace_created | A new workspace was created. | workspace_id, name |
organizations.workspace_deleted | A workspace was deleted. | workspace_id |
organizations.workspace_updated | A workspace profile was changed. | workspace_id, field |