Deletions & recovery
Deletes are a first-class part of the API: most resource removals are soft deletes with a fixed retention window, an audit trail you can list, and a background purge after that window. This page describes the model end-to-end; individual resource guides link here from their DELETE sections.
Soft delete model
When a supported resource is deleted (via DELETE or an MCP delete_* tool that maps to the same route):
- The row is marked with
deleted_atanddeletion_scheduled_purge_atinstead of being removed immediately from the database. - The default retention period is 7 days from deletion (server-defined constant). After that time, a daily purge job may hard-delete the row and related data where foreign keys allow.
Until purge runs, the entity is recoverable only at the infrastructure / support layer; there is no public “restore” API that clears deleted_at. If you need undo support in product, plan a dedicated restore endpoint and docs update.
DELETE requests and workers
Many writes—including deletes—are queued to workers. The HTTP response is typically asynchronous (for example a request_id / job reference). Poll job status using your existing job or worker patterns.
When the worker completes a soft delete, the job result payload often includes:
recoverable_until— RFC3339 timestamp after which the row is eligible for hard purge (aligned withdeletion_scheduled_purge_at).deletion_status— e.g.pending_purgewhere applicable.
The API records which API key initiated the delete (deleted_by_api_key_id on the job) for audit rows when the caller is authenticated with an API key.
Visibility after delete
List and detail endpoints generally return only active rows: deleted_at IS NULL. So after a successful delete job, the resource disappears from normal API lists for the rest of the retention window—even though it still exists until purge.
Do not rely on GET by id for soft-deleted rows unless the API explicitly documents otherwise.
Audit: recently deleted
Deletion events are stored in resource_deletions. You can list them with read-only endpoints (same API key authentication as the rest of the API).
List for one organization
/organizations/:organization_id/recently-deletedReturns deletions recorded for this API key, optionally filtered, for the given organization_id.
Query parameters
| Parameter | Type | Description |
|---|---|---|
since | string | Optional. RFC3339 datetime; only rows with deleted_at >= since. If omitted, the server applies a default lower bound (for example the last 30 days of audit index). |
entity_type | string | Optional. Filter by entity type label (e.g. contact, transaction, invoice). |
limit | integer | Optional. Max rows (default around 100; server clamps to a safe maximum). |
List across organizations (same key)
/recently-deletedSame query parameters as above, but no organization_id in the path: returns audit rows for this key across organizations (subject to your key’s access patterns).
Response shape
Each item is a structured audit record, including fields such as:
| Field | Type | Description |
|---|---|---|
id | string | Audit row id |
organization_id | string | Organization the entity belonged to |
api_key_id | string | null | Key that performed the delete, when known |
entity_type | string | Normalized type (e.g. contact, bill) |
entity_id | string | Id of the deleted entity |
deleted_at | datetime | When the soft delete was recorded |
purge_after_at | datetime | When the row becomes eligible for hard purge |
metadata | object | Optional extra context |
Purge (server-side)
A daily background process removes rows whose deletion_scheduled_purge_at is in the past, in an order that respects foreign keys (children before parents where needed). There is no client-facing purge endpoint; callers should treat purge_after_at as the end of the recoverability window for operational purposes.
Recovery: what exists today
| Capability | Status |
|---|---|
| Soft delete + hidden from normal lists | Supported |
Audit list (recently-deleted) | Supported |
| Public restore / undelete API | Not supported — data may still exist server-side until purge for support or internal use only |
For compliance and product copy, describe deletes as irreversible from the customer’s perspective after the grace period (or immediately for listing), while pointing integrators at this page for the technical lifecycle.
GraphQL
GraphQL delete mutations are implemented by calling the same REST DELETE routes. The same soft-delete, audit, and purge behavior applies. See the GraphQL mutations overview for entry points.
Related
- API Reference Overview — worker vs real-time routing
- Events — general activity stream (distinct from
resource_deletions) - MCP (Model Context Protocol) — delete tools map to REST deletes
Need help?
Create a free account to access our support portal. Once signed in, use the Support tab in your dashboard to submit a support ticket — our team typically responds within 24 hours.
- ✨ For LLMs/AI assistants: Read our structured API reference