Meetings API
Every Meetings action (33) and data model (4): endpoints, scopes, input, preconditions, events and examples.
Era joins your meetings — with a notetaker bot or botless from your computer — briefs you before, and after writes the notes, tasks, follow-up email and next steps.
Module code meetings · 33 actions · 4 data models · 16 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: meetings (everything), meetings:read (read only) or meetings:<capability>.
Resources
| Resource | Table | List and read | POST | PATCH | DELETE |
|---|---|---|---|---|---|
meeting_action_items | meeting_action_item | /api/v1/meeting_action_items | |||
meeting_calendars | meeting_calendar | /api/v1/meeting_calendars | |||
meeting_speaker_aliases | meeting_speaker_alias | /api/v1/meeting_speaker_aliases | |||
meetings | meeting | /api/v1/meetings | meetings.update | meetings.delete |
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 |
|---|---|---|
meetings.accept_action_item | meetings:write | Turn an action item into a task |
meetings.accept_next_meeting | meetings:write | Book the suggested next meeting |
meetings.accept_stage | meetings:write | Move the deal to the suggested stage |
meetings.add_action_item | meetings:write | Add an action item to a meeting |
meetings.approve_follow_up | meetings:write | Approve and send the follow-up email |
meetings.connect_calendar | meetings:write | Connect a calendar to meetings |
meetings.delete | meetings:delete | Delete a meeting |
meetings.discard_follow_up | meetings:write | Discard the follow-up email |
meetings.disconnect_calendar | meetings:write | Disconnect a meeting calendar |
meetings.dismiss_action_item | meetings:write | Dismiss an action item |
meetings.dismiss_suggestion | meetings:write | Dismiss a suggestion |
meetings.edit_follow_up | meetings:write | Edit the follow-up email |
meetings.expire_audio | meetings:write | Delete a meeting’s recording |
meetings.fail | meetings:handle | A meeting could not be processed |
meetings.file_notes | meetings:handle | File a meeting’s notes |
meetings.file_transcript | meetings:handle | File a meeting’s transcript |
meetings.forget_speaker | meetings:write | Forget a remembered speaker name |
meetings.link_invite | meetings:handle | Record the calendar invite |
meetings.link_task | meetings:handle | Link an action item to its task |
meetings.mark_follow_up_sent | meetings:handle | Record the follow-up’s delivery |
meetings.record_capture | meetings:handle | Note how a recording is going |
meetings.record_on_desktop | meetings:write | Record a meeting on my computer |
meetings.rename_speaker | meetings:write | Say who a speaker is |
meetings.save_brief | meetings:handle | Save a meeting brief |
meetings.schedule | meetings:write | Add a meeting |
meetings.send_bot | meetings:write | Send Era’s notetaker to a meeting |
meetings.send_invite | meetings:write | Send the calendar invite |
meetings.set_sharing | meetings:write | Choose who sees a meeting |
meetings.skip | meetings:write | Don’t record a meeting |
meetings.sync_calendar | meetings:handle | Read a calendar’s meetings |
meetings.update | meetings:write | Change a meeting |
meetings.update_action_item | meetings:write | Change an action item |
meetings.update_calendar | meetings:write | Change a meeting calendar |
meetings.accept_action_item
Turn an action item into a task — The commitment becomes a task for its owner (or you), with its due date, linked to the deal or customer.
Needs meetings:write · changes data
https://app.getera.io/api/v1/meeting_action_items/{id}/actions/accept_action_item- Canonical address:
POST /api/v1/actions/meetings.accept_action_item
Input
| Field | Type | Required | Notes |
|---|---|---|---|
id | uuid | yes | Filled from the path {id} · Action item · id of meeting_action_item |
assigneeUserId | uuid | Who · id of app_user | |
dueAt | date-time | By when |
Preconditions
The action is refused with 409 and one of these codes:
| Code | Refused when |
|---|---|
item_not_found | The item must exist here. |
item_closed | An item becomes a task once. |
not_member | A task goes to a member. |
Events it publishes: meetings.action_item_accepted
What it writes: meeting_action_item (update) — proposed → accepted (the task follows)
curl -X POST https://app.getera.io/api/v1/meeting_action_items/MEETING_ACTION_ITEM_ID/actions/accept_action_item \
-H "Authorization: Bearer $ERA_API_KEY" \
-H "Content-Type: application/json" \
-H "Idempotency-Key: $(uuidgen)" \
-d '{"assigneeUserId":"APP_USER_ID"}'{
"ok": true,
"result": "…",
"events": [
"meetings.action_item_accepted"
]
}import { createEra } from "@getera/sdk"
const era = createEra({ apiKey: process.env.ERA_API_KEY })
const res = await era.meetingActionItems.acceptActionItem("MEETING_ACTION_ITEM_ID", {
assigneeUserId: "APP_USER_ID"
})era meeting_action_items accept_action_item MEETING_ACTION_ITEM_ID \
--assignee-user-id "APP_USER_ID"{
"name": "era__meetings__accept_action_item",
"arguments": {
"id": "MEETING_ACTION_ITEM_ID",
"assigneeUserId": "APP_USER_ID"
}
}Errors: 401 no or expired credential · 403 the credential does not hold meetings:write · 404 the record or module is outside what it may reach · 422 invalid input (problems[]) · 409 item_not_found, item_closed, not_member · 429 slow down
meetings.accept_next_meeting
Book the suggested next meeting — Adds the next meeting Era heard agreed — same people, same deal — so Era joins and prepares for it too.
Needs meetings:write · changes data
https://app.getera.io/api/v1/meetings/{id}/actions/accept_next_meeting- Canonical address:
POST /api/v1/actions/meetings.accept_next_meeting
Input
| Field | Type | Required | Notes |
|---|---|---|---|
id | uuid | yes | Filled from the path {id} · Meeting · id of meeting |
startsAt | date-time | When | |
title | string | Name · max 300 | |
joinUrl | string | Meeting link · max 2000 |
Preconditions
The action is refused with 409 and one of these codes:
| Code | Refused when |
|---|---|
meeting_not_found | The meeting must exist here. |
no_suggestion | There must be a suggestion. |
suggestion_closed | A suggestion is answered once. |
bad_time | The next meeting needs a time. |
bad_join_url | A link must be an https address. |
Events it publishes: meetings.scheduled, meetings.next_meeting_booked
What it writes: meeting (insert) — Writes the next meeting; meeting (update) — suggestion → accepted
curl -X POST https://app.getera.io/api/v1/meetings/MEETING_ID/actions/accept_next_meeting \
-H "Authorization: Bearer $ERA_API_KEY" \
-H "Content-Type: application/json" \
-H "Idempotency-Key: $(uuidgen)" \
-d '{"startsAt":"2026-11-02T09:00:00Z"}'{
"ok": true,
"result": "…",
"events": [
"meetings.scheduled",
"meetings.next_meeting_booked"
]
}import { createEra } from "@getera/sdk"
const era = createEra({ apiKey: process.env.ERA_API_KEY })
const res = await era.meetings.acceptNextMeeting("MEETING_ID", {
startsAt: "2026-11-02T09:00:00Z"
})era meetings accept_next_meeting MEETING_ID \
--starts-at "2026-11-02T09:00:00Z"{
"name": "era__meetings__accept_next_meeting",
"arguments": {
"id": "MEETING_ID",
"startsAt": "2026-11-02T09:00:00Z"
}
}Errors: 401 no or expired credential · 403 the credential does not hold meetings:write · 404 the record or module is outside what it may reach · 422 invalid input (problems[]) · 409 meeting_not_found, no_suggestion, suggestion_closed, bad_time, bad_join_url · 429 slow down
meetings.accept_stage
Move the deal to the suggested stage — Era read the meeting and suggests the deal’s next stage; this moves it.
Needs meetings:write · changes data
https://app.getera.io/api/v1/meetings/{id}/actions/accept_stage- Canonical address:
POST /api/v1/actions/meetings.accept_stage
Input
| Field | Type | Required | Notes |
|---|---|---|---|
id | uuid | yes | Filled from the path {id} · Meeting · id of meeting |
Preconditions
The action is refused with 409 and one of these codes:
| Code | Refused when |
|---|---|
meeting_not_found | The meeting must exist here. |
no_suggestion | There must be a suggestion. |
suggestion_closed | A suggestion is answered once. |
Events it publishes: meetings.stage_accepted
What it writes: meeting (update) — suggestion → accepted (the stage change follows)
curl -X POST https://app.getera.io/api/v1/meetings/MEETING_ID/actions/accept_stage \
-H "Authorization: Bearer $ERA_API_KEY" \
-H "Content-Type: application/json" \
-H "Idempotency-Key: $(uuidgen)" \
-d '{}'{
"ok": true,
"result": "…",
"events": [
"meetings.stage_accepted"
]
}import { createEra } from "@getera/sdk"
const era = createEra({ apiKey: process.env.ERA_API_KEY })
const res = await era.meetings.acceptStage("MEETING_ID")era meetings accept_stage MEETING_ID{
"name": "era__meetings__accept_stage",
"arguments": {
"id": "MEETING_ID"
}
}Errors: 401 no or expired credential · 403 the credential does not hold meetings:write · 404 the record or module is outside what it may reach · 422 invalid input (problems[]) · 409 meeting_not_found, no_suggestion, suggestion_closed · 429 slow down
meetings.add_action_item
Add an action item to a meeting — Something Era missed — who does what, by when.
Needs meetings:write · changes data
https://app.getera.io/api/v1/meeting_action_items/actions/add_action_item- Canonical address:
POST /api/v1/actions/meetings.add_action_item
Input
| Field | Type | Required | Notes |
|---|---|---|---|
meetingId | uuid | yes | Meeting · id of meeting |
text | string | yes | What · max 1000 |
assigneeUserId | uuid | Who · id of app_user | |
dueAt | date-time | By when |
Preconditions
The action is refused with 409 and one of these codes:
| Code | Refused when |
|---|---|
meeting_not_found | The meeting must exist here. |
empty_text | An item says what to do. |
not_member | The owner must be a member. |
Events it publishes: meetings.action_item_created
What it writes: meeting_action_item (insert) — Writes the item (proposed)
curl -X POST https://app.getera.io/api/v1/meeting_action_items/actions/add_action_item \
-H "Authorization: Bearer $ERA_API_KEY" \
-H "Content-Type: application/json" \
-H "Idempotency-Key: $(uuidgen)" \
-d '{"meetingId":"MEETING_ID","text":"What"}'{
"ok": true,
"result": "…",
"events": [
"meetings.action_item_created"
]
}import { createEra } from "@getera/sdk"
const era = createEra({ apiKey: process.env.ERA_API_KEY })
const res = await era.meetingActionItems.addActionItem({
meetingId: "MEETING_ID",
text: "What"
})era meeting_action_items add_action_item \
--meeting-id "MEETING_ID" \
--text "What"{
"name": "era__meetings__add_action_item",
"arguments": {
"meetingId": "MEETING_ID",
"text": "What"
}
}Errors: 401 no or expired credential · 403 the credential does not hold meetings:write · 404 the record or module is outside what it may reach · 422 invalid input (problems[]) · 409 meeting_not_found, empty_text, not_member · 429 slow down
meetings.approve_follow_up
Approve and send the follow-up email — The email Era drafted goes out from your own Gmail or Outlook when you connected one (as you), otherwise from your business’s sender.
Needs meetings:write · reaches outside (sends, publishes or charges) · asks a person to confirm when Era runs it
https://app.getera.io/api/v1/meetings/{id}/actions/approve_follow_up- Canonical address:
POST /api/v1/actions/meetings.approve_follow_up
Input
| Field | Type | Required | Notes |
|---|---|---|---|
id | uuid | yes | Filled from the path {id} · Meeting · id of meeting |
Preconditions
The action is refused with 409 and one of these codes:
| Code | Refused when |
|---|---|
meeting_not_found | The meeting must exist here. |
no_follow_up | There must be a draft. |
follow_up_closed | An email is sent once. |
invalid_recipient | It needs a recipient. |
send_from_unusable | A chosen mailbox must be usable by the approver. |
Events it publishes: meetings.follow_up_approved
What it writes: meeting (update) — draft → approved (the send follows)
curl -X POST https://app.getera.io/api/v1/meetings/MEETING_ID/actions/approve_follow_up \
-H "Authorization: Bearer $ERA_API_KEY" \
-H "Content-Type: application/json" \
-H "Idempotency-Key: $(uuidgen)" \
-d '{}'{
"ok": true,
"result": "…",
"events": [
"meetings.follow_up_approved"
]
}import { createEra } from "@getera/sdk"
const era = createEra({ apiKey: process.env.ERA_API_KEY })
const res = await era.meetings.approveFollowUp("MEETING_ID")era meetings approve_follow_up MEETING_ID{
"name": "era__meetings__approve_follow_up",
"arguments": {
"id": "MEETING_ID"
}
}Errors: 401 no or expired credential · 403 the credential does not hold meetings:write · 404 the record or module is outside what it may reach · 422 invalid input (problems[]) · 409 meeting_not_found, no_follow_up, follow_up_closed, invalid_recipient, send_from_unusable · 429 slow down
meetings.connect_calendar
Connect a calendar to meetings — Era reads your Google or Outlook calendar, prepares a brief for each meeting and joins the ones your rule picks.
Needs meetings:write · changes data
https://app.getera.io/api/v1/meeting_calendars/actions/connect_calendar- Canonical address:
POST /api/v1/actions/meetings.connect_calendar
Input
| Field | Type | Required | Notes |
|---|---|---|---|
provider | string (enum) | yes | Calendar · Allowed values: google, microsoft |
credentialId | string | yes | Connected account · max 200 |
calendarId | string | Calendar id · max 300 | |
label | string | Name · max 120 | |
accountEmail | string | Account · max 320 | |
joinRule | string (enum) | Era joins · Allowed values: all, external, organised, off | |
captureMode | string (enum) | How · Allowed values: auto, bot, desktop | |
knowledgeBaseId | uuid | Notes go to |
Preconditions
The action is refused with 409 and one of these codes:
| Code | Refused when |
|---|---|
calendar_connected | A calendar is connected once per person. |
Events it publishes: meetings.calendar_connected
What it writes: meeting_calendar (insert) — Writes the calendar and its rule
curl -X POST https://app.getera.io/api/v1/meeting_calendars/actions/connect_calendar \
-H "Authorization: Bearer $ERA_API_KEY" \
-H "Content-Type: application/json" \
-H "Idempotency-Key: $(uuidgen)" \
-d '{"provider":"google","credentialId":"Connected account"}'{
"ok": true,
"result": "…",
"events": [
"meetings.calendar_connected"
]
}import { createEra } from "@getera/sdk"
const era = createEra({ apiKey: process.env.ERA_API_KEY })
const res = await era.meetingCalendars.connectCalendar({
provider: "google",
credentialId: "Connected account"
})era meeting_calendars connect_calendar \
--provider "google" \
--credential-id "Connected account"{
"name": "era__meetings__connect_calendar",
"arguments": {
"provider": "google",
"credentialId": "Connected account"
}
}Errors: 401 no or expired credential · 403 the credential does not hold meetings:write · 404 the record or module is outside what it may reach · 422 invalid input (problems[]) · 409 calendar_connected · 429 slow down
meetings.delete
Delete a meeting — Removes the meeting, its transcript, notes and action items (the right to be forgotten). Tasks already made stay.
Needs meetings:delete · removes or cannot be undone · asks a person to confirm when Era runs it
https://app.getera.io/api/v1/meetings/{id}/actions/delete- REST alias:
DELETE /api/v1/meetings/{id} - Canonical address:
POST /api/v1/actions/meetings.delete
Input
| Field | Type | Required | Notes |
|---|---|---|---|
id | uuid | yes | Filled from the path {id} · Meeting · id of meeting |
Preconditions
The action is refused with 409 and one of these codes:
| Code | Refused when |
|---|---|
meeting_not_found | The meeting must exist here. |
meeting_live | A meeting being recorded cannot be deleted. |
Events it publishes: meetings.deleted
What it writes: meeting (delete) — Removes the meeting; meeting_action_item (delete) — Its action items go with it
curl -X POST https://app.getera.io/api/v1/meetings/MEETING_ID/actions/delete \
-H "Authorization: Bearer $ERA_API_KEY" \
-H "Content-Type: application/json" \
-H "Idempotency-Key: $(uuidgen)" \
-d '{}'{
"ok": true,
"result": "…",
"events": [
"meetings.deleted"
]
}import { createEra } from "@getera/sdk"
const era = createEra({ apiKey: process.env.ERA_API_KEY })
const res = await era.meetings.delete("MEETING_ID")era meetings delete MEETING_ID{
"name": "era__meetings__delete",
"arguments": {
"id": "MEETING_ID"
}
}Errors: 401 no or expired credential · 403 the credential does not hold meetings:delete · 404 the record or module is outside what it may reach · 422 invalid input (problems[]) · 409 meeting_not_found, meeting_live · 429 slow down
meetings.discard_follow_up
Discard the follow-up email — No email for this meeting.
Needs meetings:write · changes data
https://app.getera.io/api/v1/meetings/{id}/actions/discard_follow_up- Canonical address:
POST /api/v1/actions/meetings.discard_follow_up
Input
| Field | Type | Required | Notes |
|---|---|---|---|
id | uuid | yes | Filled from the path {id} · Meeting · id of meeting |
Preconditions
The action is refused with 409 and one of these codes:
| Code | Refused when |
|---|---|
meeting_not_found | The meeting must exist here. |
no_follow_up | There must be a draft. |
follow_up_closed | Only a draft. |
What it writes: meeting (update) — draft → discarded
curl -X POST https://app.getera.io/api/v1/meetings/MEETING_ID/actions/discard_follow_up \
-H "Authorization: Bearer $ERA_API_KEY" \
-H "Content-Type: application/json" \
-H "Idempotency-Key: $(uuidgen)" \
-d '{}'{
"ok": true,
"result": "…",
"events": []
}import { createEra } from "@getera/sdk"
const era = createEra({ apiKey: process.env.ERA_API_KEY })
const res = await era.meetings.discardFollowUp("MEETING_ID")era meetings discard_follow_up MEETING_ID{
"name": "era__meetings__discard_follow_up",
"arguments": {
"id": "MEETING_ID"
}
}Errors: 401 no or expired credential · 403 the credential does not hold meetings:write · 404 the record or module is outside what it may reach · 422 invalid input (problems[]) · 409 meeting_not_found, no_follow_up, follow_up_closed · 429 slow down
meetings.disconnect_calendar
Disconnect a meeting calendar — Era stops reading it; its upcoming meetings are dropped, past notes stay.
Needs meetings:write · removes or cannot be undone · asks a person to confirm when Era runs it
https://app.getera.io/api/v1/meeting_calendars/{id}/actions/disconnect_calendar- Canonical address:
POST /api/v1/actions/meetings.disconnect_calendar
Input
| Field | Type | Required | Notes |
|---|---|---|---|
id | uuid | yes | Filled from the path {id} · Calendar · id of meeting_calendar |
Preconditions
The action is refused with 409 and one of these codes:
| Code | Refused when |
|---|---|
calendar_not_found | The calendar must be connected here. |
not_your_calendar | Its owner (or a manager) disconnects it. |
What it writes: meeting_calendar (delete) — Removes the calendar; meeting (update) — Its unrecorded upcoming meetings → cancelled
curl -X POST https://app.getera.io/api/v1/meeting_calendars/MEETING_CALENDAR_ID/actions/disconnect_calendar \
-H "Authorization: Bearer $ERA_API_KEY" \
-H "Content-Type: application/json" \
-H "Idempotency-Key: $(uuidgen)" \
-d '{}'{
"ok": true,
"result": "…",
"events": []
}import { createEra } from "@getera/sdk"
const era = createEra({ apiKey: process.env.ERA_API_KEY })
const res = await era.meetingCalendars.disconnectCalendar("MEETING_CALENDAR_ID")era meeting_calendars disconnect_calendar MEETING_CALENDAR_ID{
"name": "era__meetings__disconnect_calendar",
"arguments": {
"id": "MEETING_CALENDAR_ID"
}
}Errors: 401 no or expired credential · 403 the credential does not hold meetings:write · 404 the record or module is outside what it may reach · 422 invalid input (problems[]) · 409 calendar_not_found, not_your_calendar · 429 slow down
meetings.dismiss_action_item
Dismiss an action item — Era heard a commitment that was not one.
Needs meetings:write · changes data
https://app.getera.io/api/v1/meeting_action_items/{id}/actions/dismiss_action_item- Canonical address:
POST /api/v1/actions/meetings.dismiss_action_item
Input
| Field | Type | Required | Notes |
|---|---|---|---|
id | uuid | yes | Filled from the path {id} · Action item · id of meeting_action_item |
Preconditions
The action is refused with 409 and one of these codes:
| Code | Refused when |
|---|---|
item_not_found | The item must exist here. |
item_closed | Only a proposed item. |
What it writes: meeting_action_item (update) — → dismissed
curl -X POST https://app.getera.io/api/v1/meeting_action_items/MEETING_ACTION_ITEM_ID/actions/dismiss_action_item \
-H "Authorization: Bearer $ERA_API_KEY" \
-H "Content-Type: application/json" \
-H "Idempotency-Key: $(uuidgen)" \
-d '{}'{
"ok": true,
"result": "…",
"events": []
}import { createEra } from "@getera/sdk"
const era = createEra({ apiKey: process.env.ERA_API_KEY })
const res = await era.meetingActionItems.dismissActionItem("MEETING_ACTION_ITEM_ID")era meeting_action_items dismiss_action_item MEETING_ACTION_ITEM_ID{
"name": "era__meetings__dismiss_action_item",
"arguments": {
"id": "MEETING_ACTION_ITEM_ID"
}
}Errors: 401 no or expired credential · 403 the credential does not hold meetings:write · 404 the record or module is outside what it may reach · 422 invalid input (problems[]) · 409 item_not_found, item_closed · 429 slow down
meetings.dismiss_suggestion
Dismiss a suggestion — Keep the deal where it is, or don’t book the next meeting.
Needs meetings:write · changes data
https://app.getera.io/api/v1/meetings/{id}/actions/dismiss_suggestion- Canonical address:
POST /api/v1/actions/meetings.dismiss_suggestion
Input
| Field | Type | Required | Notes |
|---|---|---|---|
id | uuid | yes | Filled from the path {id} · Meeting · id of meeting |
kind | string (enum) | yes | Which · Allowed values: stage, next_meeting |
Preconditions
The action is refused with 409 and one of these codes:
| Code | Refused when |
|---|---|
meeting_not_found | The meeting must exist here. |
no_suggestion | There must be a suggestion. |
suggestion_closed | A suggestion is answered once. |
What it writes: meeting (update) — suggestion → dismissed
curl -X POST https://app.getera.io/api/v1/meetings/MEETING_ID/actions/dismiss_suggestion \
-H "Authorization: Bearer $ERA_API_KEY" \
-H "Content-Type: application/json" \
-H "Idempotency-Key: $(uuidgen)" \
-d '{"kind":"stage"}'{
"ok": true,
"result": "…",
"events": []
}import { createEra } from "@getera/sdk"
const era = createEra({ apiKey: process.env.ERA_API_KEY })
const res = await era.meetings.dismissSuggestion("MEETING_ID", {
kind: "stage"
})era meetings dismiss_suggestion MEETING_ID \
--kind "stage"{
"name": "era__meetings__dismiss_suggestion",
"arguments": {
"id": "MEETING_ID",
"kind": "stage"
}
}Errors: 401 no or expired credential · 403 the credential does not hold meetings:write · 404 the record or module is outside what it may reach · 422 invalid input (problems[]) · 409 meeting_not_found, no_suggestion, suggestion_closed · 429 slow down
meetings.edit_follow_up
Edit the follow-up email — The recipient, subject or text of the email Era drafted after the meeting.
Needs meetings:write · changes data
https://app.getera.io/api/v1/meetings/{id}/actions/edit_follow_up- Canonical address:
POST /api/v1/actions/meetings.edit_follow_up
Input
| Field | Type | Required | Notes |
|---|---|---|---|
id | uuid | yes | Filled from the path {id} · Meeting · id of meeting |
to | string | To · max 320 | |
subject | string | Subject · max 300 | |
body | string | Message · max 20000 | |
sendFrom | string | Send from · max 64 |
Preconditions
The action is refused with 409 and one of these codes:
| Code | Refused when |
|---|---|
meeting_not_found | The meeting must exist here. |
no_follow_up | There must be a draft. |
follow_up_closed | A sent or discarded email is not edited. |
invalid_recipient | The recipient is an email address. |
invalid_send_from | Send from auto, era, mine, workspace or a connection. |
What it writes: meeting (update) — Rewrites the draft
curl -X POST https://app.getera.io/api/v1/meetings/MEETING_ID/actions/edit_follow_up \
-H "Authorization: Bearer $ERA_API_KEY" \
-H "Content-Type: application/json" \
-H "Idempotency-Key: $(uuidgen)" \
-d '{"to":"To"}'{
"ok": true,
"result": "…",
"events": []
}import { createEra } from "@getera/sdk"
const era = createEra({ apiKey: process.env.ERA_API_KEY })
const res = await era.meetings.editFollowUp("MEETING_ID", {
to: "To"
})era meetings edit_follow_up MEETING_ID \
--to "To"{
"name": "era__meetings__edit_follow_up",
"arguments": {
"id": "MEETING_ID",
"to": "To"
}
}Errors: 401 no or expired credential · 403 the credential does not hold meetings:write · 404 the record or module is outside what it may reach · 422 invalid input (problems[]) · 409 meeting_not_found, no_follow_up, follow_up_closed, invalid_recipient, invalid_send_from · 429 slow down
meetings.expire_audio
Delete a meeting’s recording — The audio goes now (the owner asked) or after the retention period; the transcript and notes stay.
Needs meetings:write · changes data
https://app.getera.io/api/v1/meetings/{id}/actions/expire_audio- Canonical address:
POST /api/v1/actions/meetings.expire_audio
Input
| Field | Type | Required | Notes |
|---|---|---|---|
id | uuid | yes | Filled from the path {id} · Meeting · id of meeting |
Preconditions
The action is refused with 409 and one of these codes:
| Code | Refused when |
|---|---|
meeting_not_found | The meeting must exist here. |
no_recording | There must be a recording. |
What it writes: meeting (update) — Drops the recording link
curl -X POST https://app.getera.io/api/v1/meetings/MEETING_ID/actions/expire_audio \
-H "Authorization: Bearer $ERA_API_KEY" \
-H "Content-Type: application/json" \
-H "Idempotency-Key: $(uuidgen)" \
-d '{}'{
"ok": true,
"result": "…",
"events": []
}import { createEra } from "@getera/sdk"
const era = createEra({ apiKey: process.env.ERA_API_KEY })
const res = await era.meetings.expireAudio("MEETING_ID")era meetings expire_audio MEETING_ID{
"name": "era__meetings__expire_audio",
"arguments": {
"id": "MEETING_ID"
}
}Errors: 401 no or expired credential · 403 the credential does not hold meetings:write · 404 the record or module is outside what it may reach · 422 invalid input (problems[]) · 409 meeting_not_found, no_recording · 429 slow down
meetings.fail
A meeting could not be processed — The recording could not be fetched or read; the reservation is given back. Machine-only.
Needs meetings:handle · changes data
403 machine_only).https://app.getera.io/api/v1/meetings/{id}/actions/fail- Canonical address:
POST /api/v1/actions/meetings.fail
Input
| Field | Type | Required | Notes |
|---|---|---|---|
id | uuid | yes | Filled from the path {id} · Meeting · id of meeting |
error | string | yes | Why · max 600 |
Preconditions
The action is refused with 409 and one of these codes:
| Code | Refused when |
|---|---|
meeting_not_found | The meeting must exist here. |
already_filed | A finished meeting is not failed afterwards. |
Events it publishes: meetings.capture_failed
What it writes: meeting (update) — → failed, released
Errors: 401 no or expired credential · 403 the credential does not hold meetings:handle · 404 the record or module is outside what it may reach · 422 invalid input (problems[]) · 409 meeting_not_found, already_filed · 429 slow down
meetings.file_notes
File a meeting’s notes — Summary, decisions, action items, the follow-up draft and the suggestions — and tells workflows the meeting ended. Machine-only.
Needs meetings:handle · changes data
403 machine_only).https://app.getera.io/api/v1/meetings/{id}/actions/file_notes- Canonical address:
POST /api/v1/actions/meetings.file_notes
Input
| Field | Type | Required | Notes |
|---|---|---|---|
id | uuid | yes | Filled from the path {id} · Meeting · id of meeting |
summary | string | yes | Summary · max 4000 |
decisions | object / array | Decisions | |
actionItems | object / array | Action items | |
followUp | object / array | Follow-up email | |
stageSuggestion | object / array | Deal stage suggestion | |
nextMeeting | object / array | Next meeting suggestion | |
customerId | uuid | Customer · id of customer | |
leadId | uuid | Deal · id of lead | |
conversationId | uuid | Inbox conversation · id of conversation | |
participants | object / array | Who took part | |
brainRef | string | Brain source · max 255 | |
notesCostUsd | number | Notes cost · min 0 |
Preconditions
The action is refused with 409 and one of these codes:
| Code | Refused when |
|---|---|
meeting_not_found | The meeting must exist here. |
no_transcript | Notes are written from a transcript. |
invalid_payload | A summary and lists. |
Events it publishes: meetings.ended, meetings.action_item_created
What it writes: meeting (update) — → ready, with the notes and proposals; meeting_action_item (insert) — One row per commitment (proposed)
Errors: 401 no or expired credential · 403 the credential does not hold meetings:handle · 404 the record or module is outside what it may reach · 422 invalid input (problems[]) · 409 meeting_not_found, no_transcript, invalid_payload · 429 slow down
meetings.file_transcript
File a meeting’s transcript — What was said, the length and the recording; meters the notetaker’s real minutes. Machine-only.
Needs meetings:handle · changes data
403 machine_only).https://app.getera.io/api/v1/meetings/{id}/actions/file_transcript- Canonical address:
POST /api/v1/actions/meetings.file_transcript
Input
| Field | Type | Required | Notes |
|---|---|---|---|
id | uuid | yes | Filled from the path {id} · Meeting · id of meeting |
transcript | object / array | yes | Transcript |
durationSec | number | yes | Length (seconds) · min 0 · max 86400 |
recordingFileId | uuid | Recording · id of file | |
language | string | Language · max 8 | |
sttCostUsd | number | Speech-to-text cost · min 0 | |
sourceKind | string (enum) | Who paid · Allowed values: native, byos, byok | |
mode | string (enum) | How it arrived · Allowed values: upload | |
speakers | object / array | Who spoke | |
ownNotes | string | My notes during the call · max 20000 |
Preconditions
The action is refused with 409 and one of these codes:
| Code | Refused when |
|---|---|
meeting_not_found | The meeting must exist here. |
already_filed | A finished meeting is re-run, not re-filed. |
invalid_payload | The transcript is a list. |
no_transcript | Something must have been said. |
What it writes: meeting (update) — → processing, with transcript, length and cost
Errors: 401 no or expired credential · 403 the credential does not hold meetings:handle · 404 the record or module is outside what it may reach · 422 invalid input (problems[]) · 409 meeting_not_found, already_filed, invalid_payload, no_transcript · 429 slow down
meetings.forget_speaker
Forget a remembered speaker name — Era stops putting this name on that voice in later meetings.
Needs meetings:write · removes or cannot be undone
https://app.getera.io/api/v1/meeting_speaker_aliases/{id}/actions/forget_speaker- Canonical address:
POST /api/v1/actions/meetings.forget_speaker
Input
| Field | Type | Required | Notes |
|---|---|---|---|
id | uuid | yes | Filled from the path {id} · Remembered name · id of meeting_speaker_alias |
Preconditions
The action is refused with 409 and one of these codes:
| Code | Refused when |
|---|---|
alias_not_found | The name must be remembered here. |
What it writes: meeting_speaker_alias (delete) — Removes it
curl -X POST https://app.getera.io/api/v1/meeting_speaker_aliases/MEETING_SPEAKER_ALIASE_ID/actions/forget_speaker \
-H "Authorization: Bearer $ERA_API_KEY" \
-H "Content-Type: application/json" \
-H "Idempotency-Key: $(uuidgen)" \
-d '{}'{
"ok": true,
"result": "…",
"events": []
}import { createEra } from "@getera/sdk"
const era = createEra({ apiKey: process.env.ERA_API_KEY })
const res = await era.meetingSpeakerAliases.forgetSpeaker("MEETING_SPEAKER_ALIASE_ID")era meeting_speaker_aliases forget_speaker MEETING_SPEAKER_ALIASE_ID{
"name": "era__meetings__forget_speaker",
"arguments": {
"id": "MEETING_SPEAKER_ALIASE_ID"
}
}Errors: 401 no or expired credential · 403 the credential does not hold meetings:write · 404 the record or module is outside what it may reach · 422 invalid input (problems[]) · 409 alias_not_found · 429 slow down
meetings.link_invite
Record the calendar invite — The event Google or Outlook made (and its video link), or why it could not. Machine-only.
Needs meetings:handle · changes data
403 machine_only).https://app.getera.io/api/v1/meetings/{id}/actions/link_invite- Canonical address:
POST /api/v1/actions/meetings.link_invite
Input
| Field | Type | Required | Notes |
|---|---|---|---|
id | uuid | yes | Filled from the path {id} · Meeting · id of meeting |
externalEventId | string | Calendar event · max 500 | |
joinUrl | string | Meeting link · max 2000 | |
error | string | Why not · max 600 |
Preconditions
The action is refused with 409 and one of these codes:
| Code | Refused when |
|---|---|
meeting_not_found | The meeting must exist here. |
no_invite | There must be an invite to record. |
Events it publishes: meetings.invite_sent
What it writes: meeting (update) — invite → sent / failed, with the event id
Errors: 401 no or expired credential · 403 the credential does not hold meetings:handle · 404 the record or module is outside what it may reach · 422 invalid input (problems[]) · 409 meeting_not_found, no_invite · 429 slow down
meetings.link_task
Link an action item to its task — Records the task an accepted item became. Machine-only.
Needs meetings:handle · changes data
403 machine_only).https://app.getera.io/api/v1/meeting_action_items/{id}/actions/link_task- Canonical address:
POST /api/v1/actions/meetings.link_task
Input
| Field | Type | Required | Notes |
|---|---|---|---|
id | uuid | yes | Filled from the path {id} · Action item · id of meeting_action_item |
taskId | uuid | yes | Task · id of ai_task |
Preconditions
The action is refused with 409 and one of these codes:
| Code | Refused when |
|---|---|
item_not_found | The item must exist here. |
What it writes: meeting_action_item (update) — Writes the task id
Errors: 401 no or expired credential · 403 the credential does not hold meetings:handle · 404 the record or module is outside what it may reach · 422 invalid input (problems[]) · 409 item_not_found · 429 slow down
meetings.mark_follow_up_sent
Record the follow-up’s delivery — Queued with the sender, or refused. Machine-only.
Needs meetings:handle · changes data
403 machine_only).https://app.getera.io/api/v1/meetings/{id}/actions/mark_follow_up_sent- Canonical address:
POST /api/v1/actions/meetings.mark_follow_up_sent
Input
| Field | Type | Required | Notes |
|---|---|---|---|
id | uuid | yes | Filled from the path {id} · Meeting · id of meeting |
deliveryId | uuid | Delivery | |
error | string | Why not · max 600 |
Preconditions
The action is refused with 409 and one of these codes:
| Code | Refused when |
|---|---|
meeting_not_found | The meeting must exist here. |
no_follow_up | There must be a follow-up. |
Events it publishes: meetings.follow_up_sent
What it writes: meeting (update) — approved → sent / failed
Errors: 401 no or expired credential · 403 the credential does not hold meetings:handle · 404 the record or module is outside what it may reach · 422 invalid input (problems[]) · 409 meeting_not_found, no_follow_up · 429 slow down
meetings.record_capture
Note how a recording is going — Joining, waiting room, recording, ended or failed — from the bot provider or Era Desktop. Machine-only.
Needs meetings:handle · changes data
403 machine_only).https://app.getera.io/api/v1/meetings/{id}/actions/record_capture- Canonical address:
POST /api/v1/actions/meetings.record_capture
Input
| Field | Type | Required | Notes |
|---|---|---|---|
id | uuid | yes | Filled from the path {id} · Meeting · id of meeting |
state | string (enum) | yes | State · Allowed values: none, requested, joining, waiting_room, recording, ended, failed |
botId | string | Bot · max 200 | |
deviceJobId | string | Desktop job · max 100 | |
error | string | Why it failed · max 600 | |
consentMessage | string | Notice posted · max 1000 |
Preconditions
The action is refused with 409 and one of these codes:
| Code | Refused when |
|---|---|
meeting_not_found | The meeting must exist here. |
invalid_state | A known state, on a meeting not yet filed. |
Events it publishes: meetings.started, meetings.capture_failed
What it writes: meeting (update) — Moves the capture state; a failure releases the reservation
Errors: 401 no or expired credential · 403 the credential does not hold meetings:handle · 404 the record or module is outside what it may reach · 422 invalid input (problems[]) · 409 meeting_not_found, invalid_state · 429 slow down
meetings.record_on_desktop
Record a meeting on my computer — Era Desktop records the meeting’s sound and your microphone on your own computer — nobody sees a bot. You confirm you told everyone.
Needs meetings:write · changes data
https://app.getera.io/api/v1/meetings/{id}/actions/record_on_desktop- Canonical address:
POST /api/v1/actions/meetings.record_on_desktop
Input
| Field | Type | Required | Notes |
|---|---|---|---|
id | uuid | yes | Filled from the path {id} · Meeting · id of meeting |
deviceId | uuid | yes | Era Desktop |
consentConfirmed | boolean | I told everyone it is recorded | |
askOnDevice | boolean | Ask on the computer first |
Preconditions
The action is refused with 409 and one of these codes:
| Code | Refused when |
|---|---|
meeting_not_found | The meeting must exist here. |
not_upcoming | Only a meeting that has not finished. |
already_capturing | One recording per meeting. |
consent_required | The recording notice is confirmed first. |
What it writes: meeting (update) — capture → requested on the device, consent noted
curl -X POST https://app.getera.io/api/v1/meetings/MEETING_ID/actions/record_on_desktop \
-H "Authorization: Bearer $ERA_API_KEY" \
-H "Content-Type: application/json" \
-H "Idempotency-Key: $(uuidgen)" \
-d '{"deviceId":"DEVICE_ID"}'{
"ok": true,
"result": "…",
"events": []
}import { createEra } from "@getera/sdk"
const era = createEra({ apiKey: process.env.ERA_API_KEY })
const res = await era.meetings.recordOnDesktop("MEETING_ID", {
deviceId: "DEVICE_ID"
})era meetings record_on_desktop MEETING_ID \
--device-id "DEVICE_ID"{
"name": "era__meetings__record_on_desktop",
"arguments": {
"id": "MEETING_ID",
"deviceId": "DEVICE_ID"
}
}Errors: 401 no or expired credential · 403 the credential does not hold meetings:write · 404 the record or module is outside what it may reach · 422 invalid input (problems[]) · 409 meeting_not_found, not_upcoming, already_capturing, consent_required · 429 slow down
meetings.rename_speaker
Say who a speaker is — Names a voice in the transcript (a teammate, the customer, anyone). A name the meeting platform gave is remembered for later meetings.
Needs meetings:write · changes data
https://app.getera.io/api/v1/meetings/{id}/actions/rename_speaker- Canonical address:
POST /api/v1/actions/meetings.rename_speaker
Input
| Field | Type | Required | Notes |
|---|---|---|---|
id | uuid | yes | Filled from the path {id} · Meeting · id of meeting |
speakerKey | string | yes | Speaker · max 140 |
name | string | yes | Who it is · max 120 |
email | string | Email · max 320 | |
userId | uuid | Teammate · id of app_user | |
customerId | uuid | Customer · id of customer | |
remember | boolean | Remember for next time |
Preconditions
The action is refused with 409 and one of these codes:
| Code | Refused when |
|---|---|
meeting_not_found | The meeting must exist here and be visible to you. |
empty_name | A speaker gets a name. |
invalid_recipient | An email must be an email address. |
speaker_not_found | The voice must be in the meeting. |
not_member | A teammate is a member. |
What it writes: meeting (update) — The speaker and every turn of it get the name; meeting_speaker_alias (insert) — The platform’s name for them is remembered
curl -X POST https://app.getera.io/api/v1/meetings/MEETING_ID/actions/rename_speaker \
-H "Authorization: Bearer $ERA_API_KEY" \
-H "Content-Type: application/json" \
-H "Idempotency-Key: $(uuidgen)" \
-d '{"speakerKey":"Speaker","name":"Who it is"}'{
"ok": true,
"result": "…",
"events": []
}import { createEra } from "@getera/sdk"
const era = createEra({ apiKey: process.env.ERA_API_KEY })
const res = await era.meetings.renameSpeaker("MEETING_ID", {
speakerKey: "Speaker",
name: "Who it is"
})era meetings rename_speaker MEETING_ID \
--speaker-key "Speaker" \
--name "Who it is"{
"name": "era__meetings__rename_speaker",
"arguments": {
"id": "MEETING_ID",
"speakerKey": "Speaker",
"name": "Who it is"
}
}Errors: 401 no or expired credential · 403 the credential does not hold meetings:write · 404 the record or module is outside what it may reach · 422 invalid input (problems[]) · 409 meeting_not_found, empty_name, invalid_recipient, speaker_not_found, not_member · 429 slow down
meetings.save_brief
Save a meeting brief — Who is coming, what they care about, what we promised, what to watch out for, the deal — written before the call. Machine-only.
Needs meetings:handle · changes data
403 machine_only).https://app.getera.io/api/v1/meetings/{id}/actions/save_brief- Canonical address:
POST /api/v1/actions/meetings.save_brief
Input
| Field | Type | Required | Notes |
|---|---|---|---|
id | uuid | yes | Filled from the path {id} · Meeting · id of meeting |
brief | object / array | yes | Brief |
Preconditions
The action is refused with 409 and one of these codes:
| Code | Refused when |
|---|---|
meeting_not_found | The meeting must exist here. |
invalid_payload | The brief’s shape. |
Events it publishes: meetings.brief_ready
What it writes: meeting (update) — Writes the brief
Errors: 401 no or expired credential · 403 the credential does not hold meetings:handle · 404 the record or module is outside what it may reach · 422 invalid input (problems[]) · 409 meeting_not_found, invalid_payload · 429 slow down
meetings.schedule
Add a meeting — A meeting Era should join or prepare for — paste its Zoom, Meet or Teams link, or leave it empty for a call in person.
Needs meetings:write · changes data
https://app.getera.io/api/v1/meetings/actions/schedule- Canonical address:
POST /api/v1/actions/meetings.schedule
Input
| Field | Type | Required | Notes |
|---|---|---|---|
title | string | yes | Name · max 300 |
startsAt | date-time | Starts | |
endsAt | date-time | Ends | |
joinUrl | string | Meeting link · max 2000 | |
captureMode | string (enum) | How Era takes notes · Allowed values: auto, bot, desktop, none | |
ownerUserId | uuid | Whose meeting · id of app_user | |
customerId | uuid | Customer · id of customer | |
leadId | uuid | Deal · id of lead | |
conversationId | uuid | Inbox conversation · id of conversation | |
knowledgeBaseId | uuid | Knowledge base for the notes | |
participants | object / array | Who takes part | |
source | string (enum) | Added by · Allowed values: manual, era |
Preconditions
The action is refused with 409 and one of these codes:
| Code | Refused when |
|---|---|
empty_title | A meeting needs a name. |
bad_join_url | A link must be an https address. |
bad_time | Times must be real and the end after the start. |
not_member | The owner must be a member. |
invalid_payload | Participants are a list of names and emails. |
Events it publishes: meetings.scheduled
What it writes: meeting (insert) — Writes the meeting
curl -X POST https://app.getera.io/api/v1/meetings/actions/schedule \
-H "Authorization: Bearer $ERA_API_KEY" \
-H "Content-Type: application/json" \
-H "Idempotency-Key: $(uuidgen)" \
-d '{"title":"Name"}'{
"ok": true,
"result": "…",
"events": [
"meetings.scheduled"
]
}import { createEra } from "@getera/sdk"
const era = createEra({ apiKey: process.env.ERA_API_KEY })
const res = await era.meetings.schedule({
title: "Name"
})era meetings schedule \
--title "Name"{
"name": "era__meetings__schedule",
"arguments": {
"title": "Name"
}
}Errors: 401 no or expired credential · 403 the credential does not hold meetings:write · 404 the record or module is outside what it may reach · 422 invalid input (problems[]) · 409 empty_title, bad_join_url, bad_time, not_member, invalid_payload · 429 slow down
meetings.send_bot
Send Era’s notetaker to a meeting — A bot joins the Zoom, Meet, Teams or Webex call, posts the recording notice in the chat, and records on your own notetaker account. Minutes are checked first.
Needs meetings:write · reaches outside (sends, publishes or charges)
https://app.getera.io/api/v1/meetings/{id}/actions/send_bot- Canonical address:
POST /api/v1/actions/meetings.send_bot
Input
| Field | Type | Required | Notes |
|---|---|---|---|
id | uuid | yes | Filled from the path {id} · Meeting · id of meeting |
Preconditions
The action is refused with 409 and one of these codes:
| Code | Refused when |
|---|---|
meeting_not_found | The meeting must exist here. |
not_upcoming | Only a meeting that has not finished. |
already_capturing | One notetaker per meeting. |
no_join_link | The bot needs the meeting link. |
unsupported_platform | Zoom, Meet, Teams, Webex and GoTo only. |
no_bot_key | The bot needs the business’s own notetaker key. |
bot_minutes_used_up | The month’s notetaker minutes. |
What it writes: meeting (update) — capture → requested
curl -X POST https://app.getera.io/api/v1/meetings/MEETING_ID/actions/send_bot \
-H "Authorization: Bearer $ERA_API_KEY" \
-H "Content-Type: application/json" \
-H "Idempotency-Key: $(uuidgen)" \
-d '{}'{
"ok": true,
"result": "…",
"events": []
}import { createEra } from "@getera/sdk"
const era = createEra({ apiKey: process.env.ERA_API_KEY })
const res = await era.meetings.sendBot("MEETING_ID")era meetings send_bot MEETING_ID{
"name": "era__meetings__send_bot",
"arguments": {
"id": "MEETING_ID"
}
}Errors: 401 no or expired credential · 403 the credential does not hold meetings:write · 404 the record or module is outside what it may reach · 422 invalid input (problems[]) · 409 meeting_not_found, not_upcoming, already_capturing, no_join_link, unsupported_platform, no_bot_key, bot_minutes_used_up · 429 slow down
meetings.send_invite
Send the calendar invite — Writes the meeting into your Google or Outlook calendar with everyone on it invited (a Meet or Teams link is made when it has none).
Needs meetings:write · reaches outside (sends, publishes or charges)
https://app.getera.io/api/v1/meetings/{id}/actions/send_invite- Canonical address:
POST /api/v1/actions/meetings.send_invite
Input
| Field | Type | Required | Notes |
|---|---|---|---|
id | uuid | yes | Filled from the path {id} · Meeting · id of meeting |
Preconditions
The action is refused with 409 and one of these codes:
| Code | Refused when |
|---|---|
meeting_not_found | The meeting must exist here. |
not_upcoming | An upcoming meeting with a time. |
invite_sent | An invite is written once. |
no_attendees | Someone with an email to invite. |
no_calendar | A connected calendar to write into. |
What it writes: meeting (update) — invite → pending (the calendar write follows)
curl -X POST https://app.getera.io/api/v1/meetings/MEETING_ID/actions/send_invite \
-H "Authorization: Bearer $ERA_API_KEY" \
-H "Content-Type: application/json" \
-H "Idempotency-Key: $(uuidgen)" \
-d '{}'{
"ok": true,
"result": "…",
"events": []
}import { createEra } from "@getera/sdk"
const era = createEra({ apiKey: process.env.ERA_API_KEY })
const res = await era.meetings.sendInvite("MEETING_ID")era meetings send_invite MEETING_ID{
"name": "era__meetings__send_invite",
"arguments": {
"id": "MEETING_ID"
}
}Errors: 401 no or expired credential · 403 the credential does not hold meetings:write · 404 the record or module is outside what it may reach · 422 invalid input (problems[]) · 409 meeting_not_found, not_upcoming, invite_sent, no_attendees, no_calendar · 429 slow down
meetings.set_sharing
Choose who sees a meeting — Its owner always; also whoever can open its customer or deal (default), only you, or everyone in the workspace.
Needs meetings:write · changes data
https://app.getera.io/api/v1/meetings/{id}/actions/set_sharing- Canonical address:
POST /api/v1/actions/meetings.set_sharing
Input
| Field | Type | Required | Notes |
|---|---|---|---|
id | uuid | yes | Filled from the path {id} · Meeting · id of meeting |
sharing | string (enum) | yes | Who sees it · Allowed values: record, private, workspace |
Preconditions
The action is refused with 409 and one of these codes:
| Code | Refused when |
|---|---|
meeting_not_found | The meeting must exist here. |
invalid_payload | A known choice. |
not_your_meeting | Its owner or a manager decides. |
What it writes: meeting (update) — Writes who sees it
curl -X POST https://app.getera.io/api/v1/meetings/MEETING_ID/actions/set_sharing \
-H "Authorization: Bearer $ERA_API_KEY" \
-H "Content-Type: application/json" \
-H "Idempotency-Key: $(uuidgen)" \
-d '{"sharing":"record"}'{
"ok": true,
"result": "…",
"events": []
}import { createEra } from "@getera/sdk"
const era = createEra({ apiKey: process.env.ERA_API_KEY })
const res = await era.meetings.setSharing("MEETING_ID", {
sharing: "record"
})era meetings set_sharing MEETING_ID \
--sharing "record"{
"name": "era__meetings__set_sharing",
"arguments": {
"id": "MEETING_ID",
"sharing": "record"
}
}Errors: 401 no or expired credential · 403 the credential does not hold meetings:write · 404 the record or module is outside what it may reach · 422 invalid input (problems[]) · 409 meeting_not_found, invalid_payload, not_your_meeting · 429 slow down
meetings.skip
Don’t record a meeting — Era stays out of this meeting: no bot, no recording. The brief stays.
Needs meetings:write · changes data
https://app.getera.io/api/v1/meetings/{id}/actions/skip- Canonical address:
POST /api/v1/actions/meetings.skip
Input
| Field | Type | Required | Notes |
|---|---|---|---|
id | uuid | yes | Filled from the path {id} · Meeting · id of meeting |
Preconditions
The action is refused with 409 and one of these codes:
| Code | Refused when |
|---|---|
meeting_not_found | The meeting must exist here. |
not_upcoming | Only a meeting that has not started can be skipped. |
Events it publishes: meetings.skipped
What it writes: meeting (update) — upcoming → skipped
curl -X POST https://app.getera.io/api/v1/meetings/MEETING_ID/actions/skip \
-H "Authorization: Bearer $ERA_API_KEY" \
-H "Content-Type: application/json" \
-H "Idempotency-Key: $(uuidgen)" \
-d '{}'{
"ok": true,
"result": "…",
"events": [
"meetings.skipped"
]
}import { createEra } from "@getera/sdk"
const era = createEra({ apiKey: process.env.ERA_API_KEY })
const res = await era.meetings.skip("MEETING_ID")era meetings skip MEETING_ID{
"name": "era__meetings__skip",
"arguments": {
"id": "MEETING_ID"
}
}Errors: 401 no or expired credential · 403 the credential does not hold meetings:write · 404 the record or module is outside what it may reach · 422 invalid input (problems[]) · 409 meeting_not_found, not_upcoming · 429 slow down
meetings.sync_calendar
Read a calendar’s meetings — The next days’ events from Google or Outlook become meetings, each with the calendar’s join rule applied. Machine-only.
Needs meetings:handle · changes data
403 machine_only).https://app.getera.io/api/v1/meeting_calendars/{id}/actions/sync_calendar- Canonical address:
POST /api/v1/actions/meetings.sync_calendar
Input
| Field | Type | Required | Notes |
|---|---|---|---|
calendarId | uuid | yes | Filled from the path {id} · Calendar · id of meeting_calendar |
events | object / array | Events | |
error | string | Why it could not be read · max 600 | |
internalDomains | object / array | Company email domains |
Preconditions
The action is refused with 409 and one of these codes:
| Code | Refused when |
|---|---|
calendar_not_found | The calendar must be connected here. |
invalid_payload | Events are a list with ids. |
Events it publishes: meetings.scheduled
What it writes: meeting (insert) — New events become meetings; meeting (update) — Moved or cancelled events follow; meeting_calendar (update) — Last read time / error
Errors: 401 no or expired credential · 403 the credential does not hold meetings:handle · 404 the record or module is outside what it may reach · 422 invalid input (problems[]) · 409 calendar_not_found, invalid_payload · 429 slow down
meetings.update
Change a meeting — Name, time, link, how Era records it, and which customer, deal, conversation and knowledge base it belongs to.
Needs meetings:write · changes data
https://app.getera.io/api/v1/meetings/{id}/actions/update- REST alias:
PATCH /api/v1/meetings/{id} - Canonical address:
POST /api/v1/actions/meetings.update
Input
| Field | Type | Required | Notes |
|---|---|---|---|
id | uuid | yes | Filled from the path {id} · Meeting · id of meeting |
title | string | Name · max 300 | |
startsAt | date-time | Starts | |
endsAt | date-time | Ends | |
joinUrl | string | Meeting link · max 2000 | |
captureMode | string (enum) | How Era takes notes · Allowed values: auto, bot, desktop, none | |
ownerUserId | uuid | Whose meeting · id of app_user | |
customerId | uuid | Customer · id of customer | |
leadId | uuid | Deal · id of lead | |
conversationId | uuid | Inbox conversation · id of conversation | |
knowledgeBaseId | uuid | Knowledge base for the notes | |
participants | object / array | Who takes part |
Preconditions
The action is refused with 409 and one of these codes:
| Code | Refused when |
|---|---|
meeting_not_found | The meeting must exist here. |
empty_title | A meeting needs a name. |
bad_join_url | A link must be an https address. |
bad_time | Times must be real and the end after the start. |
not_member | The owner must be a member. |
not_upcoming | How Era records changes only before the meeting. |
invalid_payload | Participants are a list of names and emails. |
Events it publishes: meetings.updated
What it writes: meeting (update) — Rewrites the meeting’s details and links
curl -X POST https://app.getera.io/api/v1/meetings/MEETING_ID/actions/update \
-H "Authorization: Bearer $ERA_API_KEY" \
-H "Content-Type: application/json" \
-H "Idempotency-Key: $(uuidgen)" \
-d '{"title":"Name"}'{
"ok": true,
"result": "…",
"events": [
"meetings.updated"
]
}import { createEra } from "@getera/sdk"
const era = createEra({ apiKey: process.env.ERA_API_KEY })
const res = await era.meetings.update("MEETING_ID", {
title: "Name"
})era meetings update MEETING_ID \
--title "Name"{
"name": "era__meetings__update",
"arguments": {
"id": "MEETING_ID",
"title": "Name"
}
}Errors: 401 no or expired credential · 403 the credential does not hold meetings:write · 404 the record or module is outside what it may reach · 422 invalid input (problems[]) · 409 meeting_not_found, empty_title, bad_join_url, bad_time, not_member, not_upcoming, invalid_payload · 429 slow down
meetings.update_action_item
Change an action item — Before it becomes a task: the wording, who does it, by when.
Needs meetings:write · changes data
https://app.getera.io/api/v1/meeting_action_items/{id}/actions/update_action_item- Canonical address:
POST /api/v1/actions/meetings.update_action_item
Input
| Field | Type | Required | Notes |
|---|---|---|---|
id | uuid | yes | Filled from the path {id} · Action item · id of meeting_action_item |
text | string | What · max 1000 | |
assigneeUserId | uuid | Who · id of app_user | |
dueAt | date-time | By when |
Preconditions
The action is refused with 409 and one of these codes:
| Code | Refused when |
|---|---|
item_not_found | The item must exist here. |
item_closed | Only a proposed item changes here. |
empty_text | An item says what to do. |
not_member | The owner must be a member. |
What it writes: meeting_action_item (update) — Rewrites the item
curl -X POST https://app.getera.io/api/v1/meeting_action_items/MEETING_ACTION_ITEM_ID/actions/update_action_item \
-H "Authorization: Bearer $ERA_API_KEY" \
-H "Content-Type: application/json" \
-H "Idempotency-Key: $(uuidgen)" \
-d '{"text":"What"}'{
"ok": true,
"result": "…",
"events": []
}import { createEra } from "@getera/sdk"
const era = createEra({ apiKey: process.env.ERA_API_KEY })
const res = await era.meetingActionItems.updateActionItem("MEETING_ACTION_ITEM_ID", {
text: "What"
})era meeting_action_items update_action_item MEETING_ACTION_ITEM_ID \
--text "What"{
"name": "era__meetings__update_action_item",
"arguments": {
"id": "MEETING_ACTION_ITEM_ID",
"text": "What"
}
}Errors: 401 no or expired credential · 403 the credential does not hold meetings:write · 404 the record or module is outside what it may reach · 422 invalid input (problems[]) · 409 item_not_found, item_closed, empty_text, not_member · 429 slow down
meetings.update_calendar
Change a meeting calendar — Who Era joins, how it records, where the notes go, or pause the calendar.
Needs meetings:write · changes data
https://app.getera.io/api/v1/meeting_calendars/{id}/actions/update_calendar- Canonical address:
POST /api/v1/actions/meetings.update_calendar
Input
| Field | Type | Required | Notes |
|---|---|---|---|
id | uuid | yes | Filled from the path {id} · Calendar · id of meeting_calendar |
joinRule | string (enum) | Era joins · Allowed values: all, external, organised, off | |
captureMode | string (enum) | How · Allowed values: auto, bot, desktop | |
knowledgeBaseId | uuid | Notes go to | |
enabled | boolean | On | |
label | string | Name · max 120 |
Preconditions
The action is refused with 409 and one of these codes:
| Code | Refused when |
|---|---|
calendar_not_found | The calendar must be connected here. |
not_your_calendar | Its owner (or a manager) changes it. |
What it writes: meeting_calendar (update) — Rewrites the rule
curl -X POST https://app.getera.io/api/v1/meeting_calendars/MEETING_CALENDAR_ID/actions/update_calendar \
-H "Authorization: Bearer $ERA_API_KEY" \
-H "Content-Type: application/json" \
-H "Idempotency-Key: $(uuidgen)" \
-d '{"joinRule":"all"}'{
"ok": true,
"result": "…",
"events": []
}import { createEra } from "@getera/sdk"
const era = createEra({ apiKey: process.env.ERA_API_KEY })
const res = await era.meetingCalendars.updateCalendar("MEETING_CALENDAR_ID", {
joinRule: "all"
})era meeting_calendars update_calendar MEETING_CALENDAR_ID \
--join-rule "all"{
"name": "era__meetings__update_calendar",
"arguments": {
"id": "MEETING_CALENDAR_ID",
"joinRule": "all"
}
}Errors: 401 no or expired credential · 403 the credential does not hold meetings:write · 404 the record or module is outside what it may reach · 422 invalid input (problems[]) · 409 calendar_not_found, not_your_calendar · 429 slow down
Data models
MeetingActionItem
Table meeting_action_item · Resource meeting_action_items
GET /api/v1/meeting_action_itemsGET /api/v1/meeting_action_items/{id}
| Column | Type | Nullable | Allowed values | References |
|---|---|---|---|---|
id | string (uuid) · uuid | |||
organization_id | string (uuid) · uuid | organization | ||
workspace_id | string (uuid) · uuid | workspace | ||
meeting_id | string (uuid) · uuid | meeting | ||
text | string · text | |||
assignee_user_id | string (uuid) · uuid | yes | app_user | |
assignee_name | string · text | yes | ||
due_at | string (date-time) · timestamptz | yes | ||
status | string · text | proposed, accepted, done, dismissed | ||
task_id | string (uuid) · uuid | yes | ai_task | |
position | integer · int4 | |||
created_by | string (uuid) · uuid | yes | app_user | |
created_at | string (date-time) · timestamptz | |||
updated_at | string (date-time) · timestamptz |
Primary key: id
Checks:
CHECK (((assignee_name IS NULL) OR (length(assignee_name) <= 120)))CHECK (((length(text) >= 1) AND (length(text) <= 1000)))
MeetingCalendar
Table meeting_calendar · Resource meeting_calendars
GET /api/v1/meeting_calendarsGET /api/v1/meeting_calendars/{id}
| Column | Type | Nullable | Allowed values | References |
|---|---|---|---|---|
id | string (uuid) · uuid | |||
organization_id | string (uuid) · uuid | organization | ||
workspace_id | string (uuid) · uuid | workspace | ||
user_id | string (uuid) · uuid | app_user | ||
provider | string · text | google, microsoft | ||
calendar_id | string · text | |||
label | string · text | yes | ||
account_email | string · text | yes | ||
join_rule | string · text | all, external, organised, off | ||
capture_mode | string · text | auto, bot, desktop | ||
knowledge_base_id | string (uuid) · uuid | yes | ||
is_enabled | boolean · bool | |||
last_synced_at | string (date-time) · timestamptz | yes | ||
sync_error | string · text | yes | ||
created_at | string (date-time) · timestamptz | |||
updated_at | string (date-time) · timestamptz |
Primary key: id
Checks:
CHECK (((account_email IS NULL) OR (length(account_email) <= 320)))CHECK (((length(calendar_id) >= 1) AND (length(calendar_id) <= 300)))CHECK (((label IS NULL) OR (length(label) <= 120)))CHECK (((sync_error IS NULL) OR (length(sync_error) <= 600)))
MeetingSpeakerAlias
Table meeting_speaker_alias · Resource meeting_speaker_aliases
GET /api/v1/meeting_speaker_aliasesGET /api/v1/meeting_speaker_aliases/{id}
| Column | Type | Nullable | Allowed values | References |
|---|---|---|---|---|
id | string (uuid) · uuid | |||
organization_id | string (uuid) · uuid | organization | ||
workspace_id | string (uuid) · uuid | workspace | ||
label_key | string · text | |||
label | string · text | |||
name | string · text | |||
email | string · text | yes | ||
user_id | string (uuid) · uuid | yes | app_user | |
customer_id | string (uuid) · uuid | yes | customer | |
created_by | string (uuid) · uuid | yes | app_user | |
created_at | string (date-time) · timestamptz | |||
updated_at | string (date-time) · timestamptz |
Primary key: id
Checks:
CHECK (((email IS NULL) OR (length(email) <= 320)))CHECK (((length(label) >= 1) AND (length(label) <= 120)))CHECK (((length(label_key) >= 1) AND (length(label_key) <= 120)))CHECK (((length(name) >= 1) AND (length(name) <= 120)))
Meeting
Table meeting · Resource meetings
GET /api/v1/meetingsGET /api/v1/meetings/{id}PATCH /api/v1/meetings/{id}→meetings.updateDELETE /api/v1/meetings/{id}→meetings.delete
| Column | Type | Nullable | Allowed values | References |
|---|---|---|---|---|
id | string (uuid) · uuid | |||
organization_id | string (uuid) · uuid | organization | ||
workspace_id | string (uuid) · uuid | workspace | ||
owner_user_id | string (uuid) · uuid | yes | app_user | |
calendar_id | string (uuid) · uuid | yes | meeting_calendar | |
external_event_id | string · text | yes | ||
title | string · text | |||
starts_at | string (date-time) · timestamptz | yes | ||
ends_at | string (date-time) · timestamptz | yes | ||
join_url | string · text | yes | ||
platform | string · text | zoom, google_meet, teams, webex, goto, in_person, other | ||
source | string · text | manual, calendar, upload, desktop, era | ||
status | string · text | upcoming, capturing, processing, ready, failed, cancelled, skipped | ||
capture_mode | string · text | auto, bot, desktop, upload, none | ||
capture_state | string · text | none, requested, joining, waiting_room, recording, ended, failed | ||
capture_error | string · text | yes | ||
bot_provider | string · text | yes | ||
bot_id | string · text | yes | ||
bot_payer | string · text | yes | ||
device_id | string (uuid) · uuid | yes | ||
device_job_id | string · text | yes | ||
consent | object · jsonb | |||
participants | object · jsonb | |||
customer_id | string (uuid) · uuid | yes | customer | |
lead_id | string (uuid) · uuid | yes | lead | |
conversation_id | string (uuid) · uuid | yes | conversation | |
knowledge_base_id | string (uuid) · uuid | yes | ||
recording_file_id | string (uuid) · uuid | yes | file | |
started_at | string (date-time) · timestamptz | yes | ||
ended_at | string (date-time) · timestamptz | yes | ||
duration_sec | integer · int4 | |||
language | string · text | yes | ||
transcript | object · jsonb | |||
summary | string · text | yes | ||
decisions | object · jsonb | |||
brief | object · jsonb | yes | ||
brief_at | string (date-time) · timestamptz | yes | ||
follow_up | object · jsonb | yes | ||
stage_suggestion | object · jsonb | yes | ||
next_meeting | object · jsonb | yes | ||
brain_ref | string · text | yes | ||
cost_usd | string (decimal) · numeric | |||
source_kind | string · text | yes | ||
error | string · text | yes | ||
created_by | string (uuid) · uuid | yes | app_user | |
created_at | string (date-time) · timestamptz | |||
updated_at | string (date-time) · timestamptz | |||
speakers | object · jsonb | |||
sharing | string · text | record, private, workspace | ||
invite | object · jsonb | yes | ||
audio_expires_at | string (date-time) · timestamptz | yes | ||
audio_deleted_at | string (date-time) · timestamptz | yes | ||
own_notes | string · text | yes |
Primary key: id
Checks:
CHECK (((bot_id IS NULL) OR (length(bot_id) <= 200)))CHECK (((bot_payer IS NULL) OR (bot_payer = 'own_key'::text))) NOT VALIDCHECK (((bot_provider IS NULL) OR (bot_provider = ANY (ARRAY['recall'::text, 'meetingbaas'::text, 'skribby'::text, 'mock'::text]))))CHECK (((capture_error IS NULL) OR (length(capture_error) <= 600)))CHECK ((jsonb_typeof(consent) = 'object'::text))CHECK ((jsonb_typeof(decisions) = 'array'::text))CHECK ((duration_sec >= 0))CHECK (((error IS NULL) OR (length(error) <= 600)))CHECK (((external_event_id IS NULL) OR (length(external_event_id) <= 500)))CHECK (((join_url IS NULL) OR ((join_url ~ '^https://'::text) AND (length(join_url) <= 2000))))CHECK (((language IS NULL) OR (language ~ '^[a-z]{2}(-[A-Z]{2})?$'::text)))CHECK (((own_notes IS NULL) OR (length(own_notes) <= 20000)))CHECK ((jsonb_typeof(participants) = 'array'::text))CHECK (((source_kind IS NULL) OR (source_kind = ANY (ARRAY['native'::text, 'byos'::text, 'byok'::text])))) NOT VALIDCHECK ((jsonb_typeof(speakers) = 'array'::text))CHECK (((summary IS NULL) OR (length(summary) <= 4000)))CHECK (((ends_at IS NULL) OR (starts_at IS NULL) OR (ends_at >= starts_at)))CHECK (((length(title) >= 1) AND (length(title) <= 300)))CHECK ((jsonb_typeof(transcript) = 'array'::text))
Events
Workflows and webhooks react to these events.
| Event | What happens | Payload |
|---|---|---|
meetings.action_item_accepted | An action item was accepted — it becomes a task. | id, meetingId, meetingTitle, text, assigneeUserId, dueAt, recordType, recordId, recipientUserId |
meetings.action_item_created | Era (or a person) noted a commitment made in a meeting. | id, meetingId, customerId, leadId, text, assigneeUserId, dueAt, recipientUserId |
meetings.brief_ready | Era wrote the brief for an upcoming meeting. | id, title, startsAt, recipientUserId |
meetings.calendar_connected | A member connected a calendar to meetings. | id, provider, userId |
meetings.capture_failed | Era could not record or process a meeting. | id, title, error, recipientUserId |
meetings.deleted | A meeting and its notes were deleted. | id, recordingFileId |
meetings.ended | A meeting ended and its notes are ready: summary, decisions, action items, follow-up draft. | id, title, ownerUserId, summary, recipientUserId, customerId, leadId, conversationId, actionItems, hasFollowUp |
meetings.follow_up_approved | A person approved the follow-up email — it is sent from their mailbox or the business sender. | id, to, subject, text, customerId, leadId, fromConnection, approvedBy |
meetings.follow_up_sent | The follow-up email went to the sender. | id, to, customerId, leadId |
meetings.invite_sent | Era wrote a meeting into the Google or Outlook calendar and invited its people. | id, title, startsAt, attendees, recipientUserId |
meetings.next_meeting_booked | The next meeting Era heard agreed was booked; its calendar invite follows. | id, fromMeetingId, title, startsAt, endsAt, ownerUserId, attendees, invite |
meetings.scheduled | A meeting was added — from a calendar, by a person, or booked as the next meeting. | id, title, startsAt, ownerUserId, customerId, leadId |
meetings.skipped | Someone told Era not to record a meeting. | id, botProvider, botId |
meetings.stage_accepted | A person accepted the deal stage Era suggested after a meeting. | id, leadId, stageId, stageName |
meetings.started | Era started recording a meeting. | id, title, ownerUserId, mode |
meetings.updated | A meeting’s details or links changed. | id |