Popups API
Every Popups action (4) and data model (2): endpoints, scopes, input, preconditions, events and examples.
Website popups, with targeting and A/B conversion counts.
Module code popups · 4 actions · 2 data models · 2 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: popups (everything), popups:read (read only) or popups:<capability>.
Resources
| Resource | Table | List and read | POST | PATCH | DELETE |
|---|---|---|---|---|---|
popup_events | popup_event | /api/v1/popup_events | |||
popups | popup | /api/v1/popups |
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 |
|---|---|---|
popups.delete | popups:delete | Delete a popup |
popups.save | popups:manage | Create or edit a popup |
popups.submit | popups:write | Send a popup form |
popups.track | popups:write | Count a popup interaction |
popups.delete
Delete a popup — Deletes the popup and its anonymous counts.
Needs popups:delete · removes or cannot be undone · asks a person to confirm when Era runs it
https://app.getera.io/api/v1/popups/actions/delete- Canonical address:
POST /api/v1/actions/popups.delete
Input
| Field | Type | Required | Notes |
|---|---|---|---|
id | uuid | yes | Popup |
Events it publishes: popups.deleted
What it writes: popup (delete) — Deletes the popup; popup_event (delete) — Deletes its counts
curl -X POST https://app.getera.io/api/v1/popups/actions/delete \
-H "Authorization: Bearer $ERA_API_KEY" \
-H "Content-Type: application/json" \
-H "Idempotency-Key: $(uuidgen)" \
-d '{"id":"ID_ID"}'{
"ok": true,
"result": "…",
"events": [
"popups.deleted"
]
}import { createEra } from "@getera/sdk"
const era = createEra({ apiKey: process.env.ERA_API_KEY })
const res = await era.popups.delete({
id: "ID_ID"
})era popups delete \
--id "ID_ID"{
"name": "era__popups__delete",
"arguments": {
"id": "ID_ID"
}
}Errors: 401 no or expired credential · 403 the credential does not hold popups:delete · 404 the record or module is outside what it may reach · 422 invalid input (problems[]) · 429 slow down
popups.save
Create or edit a popup — Saves a popup shown to visitors on your website, with its targeting and A/B content.
Needs popups:manage · changes data
https://app.getera.io/api/v1/popups/actions/save- Canonical address:
POST /api/v1/actions/popups.save
Input
| Field | Type | Required | Notes |
|---|---|---|---|
id | uuid | Popup | |
name | string | yes | Name · max 200 |
siteId | uuid | yes | Website · id of site |
formId | uuid | Lead form · id of public_form | |
active | boolean | Live | |
config | object / array | yes | Content and targeting · JSON: {a:{title,text,image,ctaLabel,ctaUrl},b:{title,text,image,ctaLabel,ctaUrl},split:0,trigger:"arrival",threshold:5,pages:["/"],visitor:"all",device:"all",frequency:"session"}. Both content variants are required; optional content strings may be empty. split is B traffic 0–100. trigger: arrival/delay/exit/scroll; threshold: seconds (delay) or percent (scroll). visitor: all/new/returning; device: all/mobile/desktop; frequency: session/daily/once. |
startsAt | date-time | Starts | |
endsAt | date-time | Ends |
Preconditions
The action is refused with 409 and one of these codes:
| Code | Refused when |
|---|---|
popup_invalid | The content, site, form and timing must be valid and in this workspace. |
Events it publishes: popups.saved
What it writes: popup (upsert) — Saves the popup as a new revision
curl -X POST https://app.getera.io/api/v1/popups/actions/save \
-H "Authorization: Bearer $ERA_API_KEY" \
-H "Content-Type: application/json" \
-H "Idempotency-Key: $(uuidgen)" \
-d '{"name":"Name","siteId":"SITE_ID","config":{}}'{
"ok": true,
"result": "…",
"events": [
"popups.saved"
]
}import { createEra } from "@getera/sdk"
const era = createEra({ apiKey: process.env.ERA_API_KEY })
const res = await era.popups.save({
name: "Name",
siteId: "SITE_ID",
config: {}
})era popups save --data '{"name":"Name","siteId":"SITE_ID","config":{}}'{
"name": "era__popups__save",
"arguments": {
"name": "Name",
"siteId": "SITE_ID",
"config": {}
}
}Errors: 401 no or expired credential · 403 the credential does not hold popups:manage · 404 the record or module is outside what it may reach · 422 invalid input (problems[]) · 409 popup_invalid · 429 slow down
popups.submit
Send a popup form — Creates a lead through the form engine and counts the successful send for the A/B test.
Needs popups:write · reaches outside (sends, publishes or charges) · Also callable from a published site (visitor)
/api/site/v1/{siteId}, e.g. with @getera/storefront). With an API key or a token it is refused (403 site_only).https://app.getera.io/api/v1/popup_events/actions/submit- Canonical address:
POST /api/v1/actions/popups.submit
Input
| Field | Type | Required | Notes |
|---|---|---|---|
id | uuid | yes | Popup |
revision | number | yes | Revision · min 1 |
impressionId | uuid | yes | Impression |
variant | string (enum) | yes | Variant · Allowed values: A, B |
answers | object / array | Answers | |
meta | object / array | Form details |
Preconditions
The action is refused with 409 and one of these codes:
| Code | Refused when |
|---|---|
popup_invalid | Needs a live popup, its earlier view and an active lead form. |
What it writes: popup_event (insert) — A successful form send
Errors: 401 no or expired credential · 403 the credential does not hold popups:write · 404 the record or module is outside what it may reach · 422 invalid input (problems[]) · 409 popup_invalid · 429 slow down
popups.track
Count a popup interaction — Records an anonymous view or click, once.
Needs popups:write · changes data · Also callable from a published site (visitor)
/api/site/v1/{siteId}, e.g. with @getera/storefront). With an API key or a token it is refused (403 site_only).https://app.getera.io/api/v1/popup_events/actions/track- Canonical address:
POST /api/v1/actions/popups.track
Input
| Field | Type | Required | Notes |
|---|---|---|---|
id | uuid | yes | Popup |
revision | number | yes | Revision · min 1 |
impressionId | uuid | yes | Impression |
variant | string (enum) | yes | Variant · Allowed values: A, B |
kind | string (enum) | yes | Interaction · Allowed values: view, click |
Preconditions
The action is refused with 409 and one of these codes:
| Code | Refused when |
|---|---|
popup_invalid | The popup must be live on this site; a click needs its view first. |
What it writes: popup_event (insert) — One interaction
Errors: 401 no or expired credential · 403 the credential does not hold popups:write · 404 the record or module is outside what it may reach · 422 invalid input (problems[]) · 409 popup_invalid · 429 slow down
Data models
PopupEvent
Table popup_event · Resource popup_events
GET /api/v1/popup_eventsGET /api/v1/popup_events/{id}
| Column | Type | Nullable | Allowed values | References |
|---|---|---|---|---|
id | string (uuid) · uuid | |||
organization_id | string (uuid) · uuid | organization | ||
workspace_id | string (uuid) · uuid | workspace | ||
popup_id | string (uuid) · uuid | popup | ||
revision | integer · int4 | |||
impression_id | string (uuid) · uuid | |||
variant | string · text | A, B | ||
kind | string · text | view, click, submit | ||
created_at | string (date-time) · timestamptz |
Primary key: id
Unique: popup_id, revision, impression_id, kind
Popup
Table popup · Resource popups
GET /api/v1/popupsGET /api/v1/popups/{id}
| Column | Type | Nullable | Allowed values | References |
|---|---|---|---|---|
id | string (uuid) · uuid | |||
organization_id | string (uuid) · uuid | organization | ||
workspace_id | string (uuid) · uuid | workspace | ||
site_id | string (uuid) · uuid | site | ||
form_id | string (uuid) · uuid | yes | public_form | |
name | string · text | |||
is_active | boolean · bool | |||
revision | integer · int4 | |||
config | object · jsonb | |||
starts_at | string (date-time) · timestamptz | yes | ||
ends_at | string (date-time) · timestamptz | yes | ||
created_at | string (date-time) · timestamptz | |||
updated_at | string (date-time) · timestamptz |
Primary key: id
Checks:
CHECK (((ends_at IS NULL) OR (starts_at IS NULL) OR (ends_at > starts_at)))
Events
Workflows and webhooks react to these events.
| Event | What happens | Payload |
|---|---|---|
popups.deleted | A popup was deleted. | id |
popups.saved | A popup was saved. | id |