Kirora keeps each kind of data for a set period, then deletes it or removes the personal data from it. This page lists what is kept, for how long, and what deleting a contact removes, so you can answer a customer’s question or a data-protection review without reading every guide.
Periods are in days and counted from when the data was created, unless a row says otherwise. Removal runs in the background, so data can remain readable for a short while after its period ends.
Periods set by the plan
Three periods depend on the owner’s plan:
- Event retention: 30 days on Free, up to a year on paid plans, counted from the
event’s
occurredAt. An event’s expiry (expiresAt) is fixed when it is stored, so a plan change moves only the expiry of events stored afterwards. - History period, for the message log: from 90 days to two years.
- Audit period, for the audit log: from 30 days to two years.
For 30 days after a plan changes, nothing is removed under the new plan’s history or audit period, so moving to a plan with a shorter one does not take history away the same day.
What is kept
| Data | Kept | Then |
|---|---|---|
| Contact profile, with its attributes and topic choices | Until the contact is deleted | See Deleting contacts |
| Consent changes | Until the contact is deleted | Deleted with the contact |
| Events | The event retention, until the event’s expiresAt |
Deleted. listEvents and listContactEvents no longer list them |
| Refused events in the event log | 30 days | Deleted |
Events under a name you deleted with deleteEventName |
Until the background removal reaches them | Deleted |
| Message status and timestamps | As long as the workspace | After the history period, the message is anonymised (below) and keeps its status |
| A transactional message’s content | The workspace’s content period, from when it was accepted: 30 days by default, set from 0 to 90 days in the workspace settings | Removed. getMessageContent returns 404 CONTENT_NOT_RETAINED |
A sensitive transactional message’s content |
Until sending finishes | Removed. It returns 404 CONTENT_NOT_RETAINED |
| Attachments of a transactional email | Until sending finishes | Deleted once it is sent; a cleanup job removes those of a message that won’t send |
Per-recipient data on a campaign trigger |
Until sending finishes | Removed |
| A message export file | 7 days, given in the export’s expiresAt |
Deleted. The export reads expired, and its download returns 410 EXPORT_UNAVAILABLE |
| A delivered webhook delivery | 30 days, without its body | Deleted |
| A failed webhook delivery | 90 days, with its body, so you can resend it | Deleted. Before that, once the body is gone, redeliverWebhookDelivery returns 409 |
| A segment’s daily size | 400 days | Deleted |
| The request log in the dashboard | 31 days | Deleted |
Messages after the history period
A message older than the history period is anonymised, not deleted, so campaign and journey totals and the reports stay correct. Anonymising removes:
- the link to the contact:
contactreadsnull; - the address it went to (
recipientEmail) and the bounce detail; - what was sent: the email and push content and any data sent with it;
- the provider’s message ids.
The message keeps its status, its timestamps, channel, messageType and where it came
from (campaign, journey). An anonymised message no longer matches a recipient
filter on listMessages.
Idempotency keys
| Key | Kept |
|---|---|
The shared Idempotency-Key on any POST |
The first response is kept for 24 hours |
| A transactional send’s key | As long as the message it created, so a late retry is still recognised |
| A tracked event’s key | A year from the event’s occurredAt, even when the event itself is kept for less |
| A campaign trigger’s key | As long as what the trigger created |
After a key is gone, the same key starts a new request. A backdated event’s key is therefore kept for less time than one tracked as it happened. See Idempotency.
Deleting contacts
For a right-to-erasure request, deleteContact (DELETE /v1/contacts/{id}, scope
contacts:delete) deletes one contact, named as on any contact route: Kirora’s id, or
your own id or the email address with idType. It answers 204, 404 for a contact that
does not exist, and 409 CONTACT_SEND_IN_PROGRESS while a message to the contact is
being handed to a provider, which takes seconds: retry shortly. A message waiting to be
retried does not hold it up; it is skipped (contact_deleted); a push that already
reached one of the contact’s devices is marked sent, and one a push service refused is
marked failed, as it would have ended anyway.
curl -X DELETE "$KIRORA_API_URL/v1/contacts/customer-4821?idType=externalId" \
-H "Authorization: Bearer $KIRORA_API_KEY"deleteContacts (POST /v1/contacts/delete) deletes up to 100 at once, each named by
contactId, externalId or email, and reports an outcome for each: deleted,
not_found, or send_in_progress (retry that one shortly). An agent key can do
neither.
curl "$KIRORA_API_URL/v1/contacts/delete" \
-H "Authorization: Bearer $KIRORA_API_KEY" \
-H "Content-Type: application/json" \
-H "Idempotency-Key: delete-request-2026-10-23-001" \
-d '{ "contacts": [ { "externalId": "customer-4821" }, { "email": "[email protected]" } ] }'| Deleting a contact | What happens |
|---|---|
| Deletes | The contact, its events, list memberships, consent changes and journey enrollments, the messages its journey enrollments sent, and its pending and failed webhook deliveries, which are then never sent or resent |
| Anonymises | Its campaign and transactional messages, as after the history period: no address, content or provider ids, and nothing that links them to the contact. Its conversions are kept for revenue figures, without the link |
| Keeps | Address suppressions, so a deleted address that is imported again is still not mailed. Campaign, journey and report totals |
A deleted contact cannot be restored. A contact created later with the same email or
externalId is a new contact with no history.
To answer a right-of-access request before deleting, getContactExport
(GET /v1/contacts/{id}/export) returns everything held about one contact. Data past
the periods above is no longer held, so it is not in the export.
Deleting a workspace
A partner deletes a workspace it manages with deleteWorkspace. Sending stops at once,
and after a grace period, 14 days by default, the workspace and everything in it is
deleted for good. Until then, cancelWorkspaceDeletion keeps it.