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[].tenantKey match the host record you scoped the widget to. Example: tenant acme, type task, id task_1842.
  • comments[].threadId joins threads[].id. comments[].authorId is the host user id, such as user_ada.
  • reads[].userId + reads[].readSeq restore that viewer's marker on reads[].threadId.
  • events[].id is 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