ReferenceReference by module

Era insights API

Every Era insights action (6) and data model (2): endpoints, scopes, input, preconditions, events and examples.

Era tells you before you ask: what changed in your work, with sources, caveats and the next step — yours only.

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

Resources

ResourceTableList and readPOSTPATCHDELETE
insight_settingsmember_insight_setting/api/v1/insight_settings
insightsmember_insight/api/v1/insights

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

Actions

ActionNeedsWhat it does
insights.ackinsights:writeMark an insight
insights.feedbackinsights:writeWas this useful?
insights.mark_deliveredinsights:writeMark an insight delivered
insights.muteinsights:writeMute this kind
insights.recordinsights:writeNote an insight for me
insights.update_settingsinsights:writeInsight settings

insights.ack

Mark an insight — Seen, done or dismissed (or expired, when the situation resolved).

Needs insights:write · changes data

POSThttps://app.getera.io/api/v1/insights/{id}/actions/ack
API key or OAuth token · insights:write
  • Canonical address: POST /api/v1/actions/insights.ack

Input

FieldTypeRequiredNotes
iduuidyesFilled from the path {id} · Insight · id of member_insight
statusstring (enum)Status · Allowed values: seen, done, dismissed, expired

Preconditions

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

CodeRefused when
bad_statusThe status is seen, done, dismissed or expired.
insight_not_foundThe insight must be one of yours.

What it writes: member_insight (update) — Saves the status

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

const era = createEra({ apiKey: process.env.ERA_API_KEY })
const res = await era.insights.ack("INSIGHT_ID", {
  status: "seen"
})
era insights ack INSIGHT_ID \
  --status "seen"
tools/call
{
  "name": "era__insights__ack",
  "arguments": {
    "id": "INSIGHT_ID",
    "status": "seen"
  }
}

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

insights.feedback

Was this useful? — Useful or not useful — Era ranks that kind higher or lower for you.

Needs insights:write · changes data

POSThttps://app.getera.io/api/v1/insights/{id}/actions/feedback
API key or OAuth token · insights:write
  • Canonical address: POST /api/v1/actions/insights.feedback

Input

FieldTypeRequiredNotes
iduuidyesFilled from the path {id} · Insight · id of member_insight
verdictstring (enum)yesVerdict · Allowed values: useful, not_useful

Preconditions

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

CodeRefused when
bad_verdictThe verdict is useful or not useful.
insight_not_foundThe insight must be one of yours.

What it writes: member_insight (update) — Saves your verdict; member_insight_setting (update) — Moves that kind’s rank for you

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

const era = createEra({ apiKey: process.env.ERA_API_KEY })
const res = await era.insights.feedback("INSIGHT_ID", {
  verdict: "useful"
})
era insights feedback INSIGHT_ID \
  --verdict "useful"
tools/call
{
  "name": "era__insights__feedback",
  "arguments": {
    "id": "INSIGHT_ID",
    "verdict": "useful"
  }
}

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

insights.mark_delivered

Mark an insight delivered — A surface (the bell, the desktop chat, a desktop notification) says it showed the insight.

Needs insights:write · changes data

POSThttps://app.getera.io/api/v1/insights/{id}/actions/mark_delivered
API key or OAuth token · insights:write
  • Canonical address: POST /api/v1/actions/insights.mark_delivered

Input

FieldTypeRequiredNotes
iduuidyesFilled from the path {id} · Insight · id of member_insight
channelstring (enum)yesChannel · Allowed values: desktop_chat, desktop_notification, bell, digest_email, digest_whatsapp

Preconditions

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

CodeRefused when
bad_channelThe channel is one insights go to.
insight_not_foundThe insight must be one of yours.

What it writes: member_insight (update) — Stamps where it was shown

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

const era = createEra({ apiKey: process.env.ERA_API_KEY })
const res = await era.insights.markDelivered("INSIGHT_ID", {
  channel: "desktop_chat"
})
era insights mark_delivered INSIGHT_ID \
  --channel "desktop_chat"
tools/call
{
  "name": "era__insights__mark_delivered",
  "arguments": {
    "id": "INSIGHT_ID",
    "channel": "desktop_chat"
  }
}

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

insights.mute

Mute this kind — Stop (or resume) one kind of insight for you.

Needs insights:write · changes data

POSThttps://app.getera.io/api/v1/insight_settings/actions/mute
API key or OAuth token · insights:write
  • Canonical address: POST /api/v1/actions/insights.mute

Input

FieldTypeRequiredNotes
kindstring (enum)yesKind · Allowed values: assigned_to_me, dependency_changed, blocker, deadline, customer_complaint, order_late, invoice_overdue, conflicting_facts, asked_of_me, today_open_questions
mutedbooleanMuted · false resumes it

Preconditions

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

CodeRefused when
unknown_kindThe kind is one Era knows.

What it writes: member_insight_setting (update) — Switches the kind off or on for you; member_insight (update) — Dismisses what was waiting of that kind

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

const era = createEra({ apiKey: process.env.ERA_API_KEY })
const res = await era.insightSettings.mute({
  kind: "assigned_to_me"
})
era insight_settings mute \
  --kind "assigned_to_me"
tools/call
{
  "name": "era__insights__mute",
  "arguments": {
    "kind": "assigned_to_me"
  }
}

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

insights.record

Note an insight for me — Era’s sweep notes one thing that matters to you, with its sources, what it could not verify and the next step.

Needs insights:write · changes data

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

Input

FieldTypeRequiredNotes
kindstring (enum)yesKind · Allowed values: assigned_to_me, dependency_changed, blocker, deadline, customer_complaint, order_late, invoice_overdue, conflicting_facts, asked_of_me, today_open_questions
dedupeKeystringyesSame-situation key · max 300
titlestringyesTitle · max 200
bodystringMessage · max 4000
severitystring (enum)How pressing · Allowed values: info, attention, urgent
scorenumberRank · min -10 · max 10
factsobject / arrayFacts it was drawn from
sourcesobject / arraySources · [{label, href, kind, ref}]
unverifiedobject / arrayWhat could not be verified
actionsobject / arrayNext steps · [{kind: open|reply|create_task|ask, label, href}]
localestring (enum)Language · Allowed values: tr, en
composedByobject / arrayWritten by
deliverAfterdate-timeHold until
expiresAtdate-timeExpires

Preconditions

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

CodeRefused when
unknown_kindAn insight is one of the kinds Era knows.
empty_titleAn insight needs a title.
invalid_evidenceSources, facts, caveats and next steps are short lists of the right shape.
already_notedThe same situation in the same state is told once.

What it writes: member_insight (insert) — Adds the insight, for you only

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

const era = createEra({ apiKey: process.env.ERA_API_KEY })
const res = await era.insights.record({
  kind: "assigned_to_me",
  dedupeKey: "Same-situation key",
  title: "Title"
})
era insights record \
  --kind "assigned_to_me" \
  --dedupe-key "Same-situation key" \
  --title "Title"
tools/call
{
  "name": "era__insights__record",
  "arguments": {
    "kind": "assigned_to_me",
    "dedupeKey": "Same-situation key",
    "title": "Title"
  }
}

Errors: 401 no or expired credential · 403 the credential does not hold insights:write · 404 the record or module is outside what it may reach · 422 invalid input (problems[]) · 409 unknown_kind, empty_title, invalid_evidence, already_noted · 429 slow down

insights.update_settings

Insight settings — Turn Era’s insights on or off, choose kinds, quiet hours, channels and a daily limit.

Needs insights:write · changes data

POSThttps://app.getera.io/api/v1/insight_settings/actions/update_settings
API key or OAuth token · insights:write
  • Canonical address: POST /api/v1/actions/insights.update_settings

Input

FieldTypeRequiredNotes
enabledbooleanOn
kindsobject / arrayKinds · {kind: true|false}
quietStartnumberQuiet from (hour) · min 0 · max 23
quietEndnumberQuiet until (hour) · min 0 · max 23
timezonestringTime zone · max 64
channelsobject / arrayChannels · desktop_chat · desktop_notification · bell · digest_email · digest_whatsapp
dailyCapnumberAt most per day · min 0 · max 20

Preconditions

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

CodeRefused when
bad_hoursQuiet hours are whole hours in a known time zone.
bad_capThe daily limit is 0 to 20.
bad_switchesKinds and channels are known names with on/off values.

What it writes: member_insight_setting (update) — Saves your insight settings

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

const era = createEra({ apiKey: process.env.ERA_API_KEY })
const res = await era.insightSettings.updateSettings({
  enabled: true
})
era insight_settings update_settings \
  --enabled true
tools/call
{
  "name": "era__insights__update_settings",
  "arguments": {
    "enabled": true
  }
}

Errors: 401 no or expired credential · 403 the credential does not hold insights:write · 404 the record or module is outside what it may reach · 422 invalid input (problems[]) · 409 bad_hours, bad_cap, bad_switches · 429 slow down

Data models

MemberInsightSetting

Table member_insight_setting · Resource insight_settings

  • GET /api/v1/insight_settings
  • GET /api/v1/insight_settings/{id}
ColumnTypeNullableAllowed valuesReferences
idstring (uuid) · uuid
organization_idstring (uuid) · uuidorganization
workspace_idstring (uuid) · uuidworkspace
user_idstring (uuid) · uuidapp_user
enabledboolean · bool
kindsobject · jsonb
weightsobject · jsonb
quiet_startinteger · int2
quiet_endinteger · int2
timezonestring · text
channelsobject · jsonb
daily_capinteger · int2
watermarkstring (int64) · int8
last_swept_atstring (date-time) · timestamptzyes
created_atstring (date-time) · timestamptz
updated_atstring (date-time) · timestamptz

Primary key: id

Unique: workspace_id, user_id

Checks:

  • CHECK ((jsonb_typeof(channels) = 'object'::text))
  • CHECK (((daily_cap >= 0) AND (daily_cap <= 20)))
  • CHECK ((jsonb_typeof(kinds) = 'object'::text))
  • CHECK (((quiet_end >= 0) AND (quiet_end <= 23)))
  • CHECK (((quiet_start >= 0) AND (quiet_start <= 23)))
  • CHECK (((length(timezone) >= 1) AND (length(timezone) <= 64)))
  • CHECK ((jsonb_typeof(weights) = 'object'::text))

MemberInsight

Table member_insight · Resource insights

  • GET /api/v1/insights
  • GET /api/v1/insights/{id}
ColumnTypeNullableAllowed valuesReferences
idstring (uuid) · uuid
organization_idstring (uuid) · uuidorganization
workspace_idstring (uuid) · uuidworkspace
user_idstring (uuid) · uuidapp_user
kindstring · textassigned_to_me, dependency_changed, blocker, deadline, customer_complaint, order_late, invoice_overdue, conflicting_facts, asked_of_me, today_open_questions
dedupe_keystring · text
severitystring · textinfo, attention, urgent
scorenumber · float4
titlestring · text
bodystring · text
factsobject · jsonb
sourcesobject · jsonb
unverifiedobject · jsonb
actionsobject · jsonb
localestring · texttr, en
composed_byobject · jsonb
statusstring · textnew, seen, done, dismissed, expired
feedbackstring · textyes
deliveredobject · jsonb
deliver_afterstring (date-time) · timestamptzyes
expires_atstring (date-time) · timestamptzyes
seen_atstring (date-time) · timestamptzyes
created_atstring (date-time) · timestamptz
updated_atstring (date-time) · timestamptz

Primary key: id

Unique: workspace_id, user_id, dedupe_key

Checks:

  • CHECK ((jsonb_typeof(actions) = 'array'::text))
  • CHECK ((length(body) <= 4000))
  • CHECK ((jsonb_typeof(composed_by) = 'object'::text))
  • CHECK (((length(dedupe_key) >= 1) AND (length(dedupe_key) <= 300)))
  • CHECK ((jsonb_typeof(delivered) = 'object'::text))
  • CHECK ((jsonb_typeof(facts) = 'array'::text))
  • CHECK (((feedback IS NULL) OR (feedback = ANY (ARRAY['useful'::text, 'not_useful'::text]))))
  • CHECK ((jsonb_typeof(sources) = 'array'::text))
  • CHECK (((length(btrim(title)) >= 1) AND (length(btrim(title)) <= 200)))
  • CHECK ((jsonb_typeof(unverified) = 'array'::text))
Was this page helpful?