Export and purge
GET /api/v1/export uses the secret key and returns only that key's environment. The body is pretty-printed JSON with Content-Disposition: attachment; filename="comments-export.json". The widget cannot export. Publishable keys cannot export.
{
"data": {
"threads": [],
"comments": [],
"reads": [],
"events": []
}
}Each thread includes tenantKey, resourceType, and resourceId so you can map rows back to a record. Comments include tombstones with body: null and mentions: []. Deleted text is absent. Events stay id-only: name, schema version, actor, time, scope, thread, optional comment id, optional mentioned user id. This file is not an automatic import.
Field mapping
threads[].resourceType+threads[].resourceId+threads[].tenantKeymatch the host record you scoped the widget to. Example: tenantacme, typetask, idtask_1842.comments[].threadIdjoinsthreads[].id.comments[].authorIdis the host user id, such asuser_ada.reads[].userId+reads[].readSeqrestore that viewer's marker onreads[].threadId.events[].idis the id to dedupe if you already consumed webhooks. Do not expect a body.
Cancel and plan changes
- Cancel Hosted: writes freeze immediately. Rows stay. Dashboard or secret-key export works for 30 days, then the cron deletes both environments.
- Hosted to active BYO: Hosted writes freeze, rows stay, and the 30-day clock does not start. Nothing is copied into your database.
- Hosted again before purge: retained rows are available and the clock clears.
Resource purge is separate. POST /api/v1/resources/purge with the secret key freezes one tuple, then deletes its threads, comments, mentions, and read markers. A replay after success returns applied: false and the original { deletedThreads, deletedComments }. Guide: export and migration.
Related: Deletion · Privacy by mode · Webhooks