Privacy API
Every Privacy action (7) and data model (1): endpoints, scopes, input, preconditions, events and examples.
Personal-data requests — export or erase a customer’s data, with a record kept.
Module code privacy · 7 actions · 1 data models · 6 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: privacy (everything), privacy:read (read only) or privacy:<capability>.
Resources
| Resource | Table | List and read | POST | PATCH | DELETE |
|---|---|---|---|---|---|
privacy_requests | privacy_request | /api/v1/privacy_requests |
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 |
|---|---|---|
privacy.approve_erasure | privacy:approve | Approve and erase |
privacy.cancel_erasure | privacy:write | Withdraw erasure request |
privacy.export_data | privacy:export | Export personal data |
privacy.purge_exports | privacy:manage | Apply the export retention policy |
privacy.reject_erasure | privacy:approve | Reject erasure request |
privacy.request_erasure | privacy:write | Request deletion of personal data |
privacy.request_my_erasure | privacy:write | Ask to delete my data |
privacy.approve_erasure
Approve and erase — Approves an erasure request. The customer’s name, contact details, identities and saved addresses are scrubbed.
Needs privacy:approve · reaches outside (sends, publishes or charges) · asks a person to confirm when Era runs it
https://app.getera.io/api/v1/privacy_requests/actions/approve_erasure- Canonical address:
POST /api/v1/actions/privacy.approve_erasure
Input
| Field | Type | Required | Notes |
|---|---|---|---|
id | uuid | yes | Request |
note | string | Note · max 500 |
Preconditions
The action is refused with 409 and one of these codes:
| Code | Refused when |
|---|---|
request_not_found | The erasure request must exist in this workspace. |
request_not_pending | Only a pending request can be decided. |
self_approval | The person who asked cannot approve, unless the workspace allows it. |
Events it publishes: privacy.erasure_approved
What it writes: privacy_request (update) — Marks the request approved and carried out
curl -X POST https://app.getera.io/api/v1/privacy_requests/actions/approve_erasure \
-H "Authorization: Bearer $ERA_API_KEY" \
-H "Content-Type: application/json" \
-H "Idempotency-Key: $(uuidgen)" \
-d '{"id":"ID_ID"}'{
"ok": true,
"result": "…",
"events": [
"privacy.erasure_approved"
]
}import { createEra } from "@getera/sdk"
const era = createEra({ apiKey: process.env.ERA_API_KEY })
const res = await era.privacyRequests.approveErasure({
id: "ID_ID"
})era privacy_requests approve_erasure \
--id "ID_ID"{
"name": "era__privacy__approve_erasure",
"arguments": {
"id": "ID_ID"
}
}Errors: 401 no or expired credential · 403 the credential does not hold privacy:approve · 404 the record or module is outside what it may reach · 422 invalid input (problems[]) · 409 request_not_found, request_not_pending, self_approval · 429 slow down
privacy.cancel_erasure
Withdraw erasure request — Withdraws a pending erasure request (the customer changed their mind, or it was opened by mistake).
Needs privacy:write · removes or cannot be undone
https://app.getera.io/api/v1/privacy_requests/actions/cancel_erasure- Canonical address:
POST /api/v1/actions/privacy.cancel_erasure
Input
| Field | Type | Required | Notes |
|---|---|---|---|
id | uuid | yes | Request |
note | string | Note · max 500 |
Preconditions
The action is refused with 409 and one of these codes:
| Code | Refused when |
|---|---|
request_not_found | The erasure request must exist in this workspace. |
request_not_pending | Only a pending request can be withdrawn. |
Events it publishes: privacy.erasure_cancelled
What it writes: privacy_request (update) — Marks the request cancelled
curl -X POST https://app.getera.io/api/v1/privacy_requests/actions/cancel_erasure \
-H "Authorization: Bearer $ERA_API_KEY" \
-H "Content-Type: application/json" \
-H "Idempotency-Key: $(uuidgen)" \
-d '{"id":"ID_ID"}'{
"ok": true,
"result": "…",
"events": [
"privacy.erasure_cancelled"
]
}import { createEra } from "@getera/sdk"
const era = createEra({ apiKey: process.env.ERA_API_KEY })
const res = await era.privacyRequests.cancelErasure({
id: "ID_ID"
})era privacy_requests cancel_erasure \
--id "ID_ID"{
"name": "era__privacy__cancel_erasure",
"arguments": {
"id": "ID_ID"
}
}Errors: 401 no or expired credential · 403 the credential does not hold privacy:write · 404 the record or module is outside what it may reach · 422 invalid input (problems[]) · 409 request_not_found, request_not_pending · 429 slow down
privacy.export_data
Export personal data — Collects every row this workspace holds about a customer into one downloadable file, and records that it did.
Needs privacy:export · reaches outside (sends, publishes or charges)
https://app.getera.io/api/v1/privacy_requests/actions/export_data- Canonical address:
POST /api/v1/actions/privacy.export_data
Input
| Field | Type | Required | Notes |
|---|---|---|---|
customer_id | uuid | yes | Customer |
reason | string | Why (e.g. the request’s reference) · max 500 |
Preconditions
The action is refused with 409 and one of these codes:
| Code | Refused when |
|---|---|
customer_not_found | The customer must exist in this workspace. |
Events it publishes: privacy.exported
What it writes: privacy_request (insert) — A completed export in the register, with the collected rows
curl -X POST https://app.getera.io/api/v1/privacy_requests/actions/export_data \
-H "Authorization: Bearer $ERA_API_KEY" \
-H "Content-Type: application/json" \
-H "Idempotency-Key: $(uuidgen)" \
-d '{"customer_id":"CUSTOMER_ID"}'{
"ok": true,
"result": "…",
"events": [
"privacy.exported"
]
}import { createEra } from "@getera/sdk"
const era = createEra({ apiKey: process.env.ERA_API_KEY })
const res = await era.privacyRequests.exportData({
customer_id: "CUSTOMER_ID"
})era privacy_requests export_data \
--customer-id "CUSTOMER_ID"{
"name": "era__privacy__export_data",
"arguments": {
"customer_id": "CUSTOMER_ID"
}
}Errors: 401 no or expired credential · 403 the credential does not hold privacy:export · 404 the record or module is outside what it may reach · 422 invalid input (problems[]) · 409 customer_not_found · 429 slow down
privacy.purge_exports
Apply the export retention policy — Deletes the collected data of exports past the retention window. The register row and its counts stay.
Needs privacy:manage · removes or cannot be undone
https://app.getera.io/api/v1/privacy_requests/actions/purge_exports- Canonical address:
POST /api/v1/actions/privacy.purge_exports
Input
This action takes no input.
Events it publishes: privacy.exports_purged
What it writes: privacy_request (update) — Clears export_payload on expired exports
curl -X POST https://app.getera.io/api/v1/privacy_requests/actions/purge_exports \
-H "Authorization: Bearer $ERA_API_KEY" \
-H "Content-Type: application/json" \
-H "Idempotency-Key: $(uuidgen)" \
-d '{}'{
"ok": true,
"result": "…",
"events": [
"privacy.exports_purged"
]
}import { createEra } from "@getera/sdk"
const era = createEra({ apiKey: process.env.ERA_API_KEY })
const res = await era.privacyRequests.purgeExports()era privacy_requests purge_exports{
"name": "era__privacy__purge_exports",
"arguments": {}
}Errors: 401 no or expired credential · 403 the credential does not hold privacy:manage · 404 the record or module is outside what it may reach · 422 invalid input (problems[]) · 429 slow down
privacy.reject_erasure
Reject erasure request — Declines an erasure request, with the reason (e.g. an open contract or a legal hold).
Needs privacy:approve · changes data
https://app.getera.io/api/v1/privacy_requests/actions/reject_erasure- Canonical address:
POST /api/v1/actions/privacy.reject_erasure
Input
| Field | Type | Required | Notes |
|---|---|---|---|
id | uuid | yes | Request |
note | string | yes | Reason · max 500 |
Preconditions
The action is refused with 409 and one of these codes:
| Code | Refused when |
|---|---|
request_not_found | The erasure request must exist in this workspace. |
request_not_pending | Only a pending request can be decided. |
Events it publishes: privacy.erasure_rejected
What it writes: privacy_request (update) — Marks the request rejected
curl -X POST https://app.getera.io/api/v1/privacy_requests/actions/reject_erasure \
-H "Authorization: Bearer $ERA_API_KEY" \
-H "Content-Type: application/json" \
-H "Idempotency-Key: $(uuidgen)" \
-d '{"id":"ID_ID","note":"Reason"}'{
"ok": true,
"result": "…",
"events": [
"privacy.erasure_rejected"
]
}import { createEra } from "@getera/sdk"
const era = createEra({ apiKey: process.env.ERA_API_KEY })
const res = await era.privacyRequests.rejectErasure({
id: "ID_ID",
note: "Reason"
})era privacy_requests reject_erasure \
--id "ID_ID" \
--note "Reason"{
"name": "era__privacy__reject_erasure",
"arguments": {
"id": "ID_ID",
"note": "Reason"
}
}Errors: 401 no or expired credential · 403 the credential does not hold privacy:approve · 404 the record or module is outside what it may reach · 422 invalid input (problems[]) · 409 request_not_found, request_not_pending · 429 slow down
privacy.request_erasure
Request deletion of personal data — Opens an erasure request for a customer. Nothing is deleted until it is approved.
Needs privacy:write · changes data
https://app.getera.io/api/v1/privacy_requests/actions/request_erasure- Canonical address:
POST /api/v1/actions/privacy.request_erasure
Input
| Field | Type | Required | Notes |
|---|---|---|---|
customer_id | uuid | yes | Customer |
reason | string | Why (e.g. the request’s reference) · max 500 |
Preconditions
The action is refused with 409 and one of these codes:
| Code | Refused when |
|---|---|
customer_not_found | The customer must exist in this workspace. |
already_anonymized | A customer whose data was already erased cannot be erased again. |
erasure_already_open | One open erasure request per customer. |
Events it publishes: privacy.erasure_requested
What it writes: privacy_request (insert) — A pending erasure in the register
curl -X POST https://app.getera.io/api/v1/privacy_requests/actions/request_erasure \
-H "Authorization: Bearer $ERA_API_KEY" \
-H "Content-Type: application/json" \
-H "Idempotency-Key: $(uuidgen)" \
-d '{"customer_id":"CUSTOMER_ID"}'{
"ok": true,
"result": "…",
"events": [
"privacy.erasure_requested"
]
}import { createEra } from "@getera/sdk"
const era = createEra({ apiKey: process.env.ERA_API_KEY })
const res = await era.privacyRequests.requestErasure({
customer_id: "CUSTOMER_ID"
})era privacy_requests request_erasure \
--customer-id "CUSTOMER_ID"{
"name": "era__privacy__request_erasure",
"arguments": {
"customer_id": "CUSTOMER_ID"
}
}Errors: 401 no or expired credential · 403 the credential does not hold privacy:write · 404 the record or module is outside what it may reach · 422 invalid input (problems[]) · 409 customer_not_found, already_anonymized, erasure_already_open · 429 slow down
privacy.request_my_erasure
Ask to delete my data — A signed-in customer asks the business to erase their personal data. Nothing is deleted until it is approved.
Needs privacy:write · changes data · Also callable from a published site (customer)
/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/privacy_requests/actions/request_my_erasure- Canonical address:
POST /api/v1/actions/privacy.request_my_erasure
Input
| Field | Type | Required | Notes |
|---|---|---|---|
reason | string | Why · max 500 |
Preconditions
The action is refused with 409 and one of these codes:
| Code | Refused when |
|---|---|
erasure_already_open | One open erasure request per customer. |
Events it publishes: privacy.erasure_requested
What it writes: privacy_request (insert) — A pending erasure in the register
Errors: 401 no or expired credential · 403 the credential does not hold privacy:write · 404 the record or module is outside what it may reach · 422 invalid input (problems[]) · 409 erasure_already_open · 429 slow down
Data models
PrivacyRequest
Table privacy_request · Resource privacy_requests
GET /api/v1/privacy_requestsGET /api/v1/privacy_requests/{id}
| Column | Type | Nullable | Allowed values | References |
|---|---|---|---|---|
id | string (uuid) · uuid | |||
organization_id | string (uuid) · uuid | organization | ||
workspace_id | string (uuid) · uuid | workspace | ||
customer_id | string (uuid) · uuid | |||
subject_label | string · text | |||
kind | string · text | export, erase | ||
status | string · text | pending, completed, rejected, cancelled | ||
reason | string · text | yes | ||
requested_by | string (uuid) · uuid | yes | app_user | |
requested_at | string (date-time) · timestamptz | |||
decided_by | string (uuid) · uuid | yes | app_user | |
decided_at | string (date-time) · timestamptz | yes | ||
decision_note | string · text | yes | ||
completed_at | string (date-time) · timestamptz | yes | ||
export_summary | object · jsonb | yes | ||
export_expires_at | string (date-time) · timestamptz | yes | ||
created_at | string (date-time) · timestamptz | |||
updated_at | string (date-time) · timestamptz |
Primary key: id
Events
Workflows and webhooks react to these events.
| Event | What happens | Payload |
|---|---|---|
privacy.erasure_approved | An erasure was approved; the owners of the data scrub it. | id, customerId |
privacy.erasure_cancelled | An erasure request was withdrawn. | id, customerId |
privacy.erasure_rejected | An erasure request was declined. | id, customerId |
privacy.erasure_requested | An erasure request was opened. | id, customerId |
privacy.exported | A customer’s personal data was exported. | id, customerId, tables, rows |
privacy.exports_purged | Expired exports were cleared. | removed |