Delete your organization
How to permanently delete a Caura organization, what gets destroyed, and when (and how) you can still recover.
You can start deletion from the dashboard. Customer deletion has no automatic grace window, and data that has been purged cannot be restored. Deletion spans several services and can fail after some steps have completed; confirming the dialog is not proof that cleanup and billing cancellation finished.
Who can delete
An organization member must have permission to delete the organization. An admin label alone does not grant that permission. If nobody on the team has it, contact support.
How to delete
- Sign in to caura.ai or your enterprise dashboard.
- Open the organization settings and scroll to Danger Zone.
- Click Delete Organization.
- Type the organization's slug into the confirmation field. Leading/trailing whitespace and letter case are ignored; the backend checks the value again.
- Confirm only after reading the warning and verifying the data copies you need below.
The dashboard redirects after a successful organization deletion. A failed or interrupted request may already have disabled the organization and removed some data. Follow the recovery guidance below rather than assuming the request was rolled back.
What gets destroyed
Deletion removes organization and tenant data through several service calls, rather than one transaction across all systems. The requested scope includes:
- Memories, entities, relations, agents, documents and analysis reports in the organization's tenants
- API keys and install credentials
- Members, pending invites and organization settings
- Tenants and the organization row
- Organization audit history, except retained deletion-audit records
The request also attempts to cancel any linked Paddle subscription. If cancellation cannot be confirmed, it stops and retains the disabled organization for operator recovery. Losing dashboard access or receiving an error does not confirm that billing stopped.
A deletion audit record is retained with the action, requester identifier, timestamp and deletion counts. It does not contain memory content.
Why no grace window?
Customer deletion starts immediately after confirmation. It is not an undoable background request. Operator soft-deletion can have a configured grace period, but customer deletion and operator force-now deletion do not create that recovery window.
I changed my mind
Before confirming, close the dialog to cancel. After confirming, some data may already have been purged even if an error appeared. Support cannot restore purged data; contact support to check an incomplete request and any remaining cleanup.
A deletion request failed or the organization is unavailable
Send support the organization slug and the time of your request. For a self-hosted installation, contact its deployment administrator.
- Billing cancellation was not confirmed: billing may still be active. Ask support to verify the subscription and complete cancellation.
- Data cleanup failed or the response was lost: some data may already be gone. Ask support to reconcile cleanup and billing; an error is not a restore point.
- The organization is already disabled: customer self-delete cannot resume an already-disabled organization. An authorized operator must use the recovery/retry process.
Do not assume that repeatedly submitting the customer form, restoring access or creating a new organization completes the original request. Ask for confirmation of remaining cleanup and billing status.
Data export before deleting
Do not confirm deletion until you have verified the copies you need. There is no dashboard "download everything" button or complete organization-backup endpoint. A memory listing is not an organization backup: it can be paginated and visibility-filtered, and it does not contain documents, graph data, keystones, settings, or audit history.
Copy every page of readable memories
Pause writers, scheduled jobs, and agents first. These reads are not a point-in-time snapshot; concurrent edits or deletions can change the result while you page through it.
The following example uses Python 3 and the standard library. Set CAURA_BASE_URL to your gateway origin (for example, https://caura.ai), CAURA_TENANT_ID to one tenant, and CAURA_API_KEY to a credential allowed to read it. Supply the key through your environment; do not put it in the URL or the saved file. Save this as export-memories.py and run python3 export-memories.py.
The API defaults to 50 rows. This example requests 500 and follows every next_cursor, using the required created_at descending order. It saves newline-delimited JSON in a new directory, leaves a .partial directory on failure, and renames it to .finished only after pagination ends.
import json
import os
from pathlib import Path
import tempfile
from urllib.parse import urlencode
from urllib.request import Request, urlopen
base = os.environ["CAURA_BASE_URL"].rstrip("/")
tenant = os.environ["CAURA_TENANT_ID"]
key = os.environ["CAURA_API_KEY"]
agent = os.environ.get("CAURA_EXPORT_AGENT_ID")
directory = Path(tempfile.mkdtemp(prefix="caura-memories-", suffix=".partial", dir="."))
cursor = None
seen_cursors = set()
count = 0
with (directory / "memories.ndjson").open("x", encoding="utf-8") as output:
while True:
params = {"tenant_id": tenant, "limit": 500, "sort": "created_at", "order": "desc"}
if agent:
params["agent_id"] = agent
if cursor:
params["cursor"] = cursor
request = Request(base + "/api/v1/memories?" + urlencode(params),
headers={"X-API-Key": key, "Accept": "application/json"})
with urlopen(request, timeout=60) as response:
page = json.load(response)
if not isinstance(page, dict) or not isinstance(page.get("items"), list):
raise ValueError("Unexpected memory page; export is incomplete")
if "next_cursor" not in page or not all(isinstance(item, dict) for item in page["items"]):
raise ValueError("Invalid page; export is incomplete")
next_cursor = page["next_cursor"]
if next_cursor is not None:
if not isinstance(next_cursor, str) or not next_cursor or next_cursor in seen_cursors:
raise ValueError("Invalid or repeated cursor; export is incomplete")
seen_cursors.add(next_cursor)
for item in page["items"]:
output.write(json.dumps(item, ensure_ascii=False) + "\n")
count += 1
if next_cursor is None:
break
cursor = next_cursor
finished = directory.with_suffix(".finished")
directory.rename(finished)
print(f"Saved {count} readable memories to {finished / 'memories.ndjson'}")Repeat for every tenant you need. Deleting the organization also removes every member's personal tenant, and Settings › Tenants lists only the shared tenants and your own personal one, never another member's: ask each member to export their own (their tenant_id is the Tenant ID on their Connect › Keys, or GET /api/v1/whoami with their key). A .finished directory means the readable pages were exhausted, not that the whole organization was backed up. Check the saved records, including known old memories beyond the first page, before proceeding.
Include agent-private memories
Visibility depends on the credential and deployed API version. An unqualified listing can omit scope_agent records; a larger page size does not fix that. An agent-bound credential cannot become another agent by changing the query string.
For each author whose private records you need, run the same paginated export with CAURA_EXPORT_AGENT_ID set to that author's identifier and an authorized tenant credential with no bound agent identity, or use the author's own agent credential. agent_id also filters by author, so keep the unfiltered export for other readable memories. Runs can overlap; deduplicate records by id when combining them. Include inactive or removed authors if their records remain; the current agent list alone is not proof that every author was covered. Do not assume a high trust level makes another agent's private memories visible.
Verify that known private records for each author are present. The example exports the default non-deleted listing. If you also need soft-deleted memories, check your deployment's include_deleted=true support and credential requirements, and export and verify those separately. Already purged records cannot be exported.
Copy other data and verify the result
Memories are only one part of the deleted data. Use the REST API reference for the other records you need:
- Documents: enumerate collections, then page through
GET /api/v1/documentsfor each collection and tenant usinglimitandoffsetuntil an empty page. Save each document'sdataand metadata; a memory generated from a document is not the document itself. - Entities and relations: retrieve the entity pages and graph data you need, including their relations. Check endpoint limits and any truncation indicators; an entity list alone does not contain the complete graph.
- Keystones: retrieve tenant, fleet, and agent rule views through the keystone API. Check
X-Truncated; a merged rule view is not necessarily a complete inventory of stored rules. - Settings and audit history: save those separately through the applicable organization and audit APIs. Memory files contain neither.
Confirm every tenant, author, collection, and other object type in your own inventory is covered, that the files can be read, and that representative old and private records are present. Keep the files securely. These API copies are not a restorable database snapshot and there is no one-call organization restore. If you cannot establish that your copies cover what you need, keep the organization and contact support before deleting it.
GDPR / right to erasure
A failed request is not confirmation that all data has been erased. Contact support for completion checks and any formal deletion confirmation. The retained deletion-audit record includes the requester's user identifier, action, timestamp and counts; it is not a memory-content backup.
On-prem and self-hosted
Your deployment administrator owns recovery on a self-hosted installation. Confirm the deletion scope, any linked billing and remaining operational cleanup with them before proceeding.