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_at and deletion_scheduled_purge_at instead 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 with deletion_scheduled_purge_at).
  • deletion_status — e.g. pending_purge where 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

GET/organizations/:organization_id/recently-deleted
Auth required

Returns deletions recorded for this API key, optionally filtered, for the given organization_id.

Query parameters

ParameterTypeDescription
sincestringOptional. 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_typestringOptional. Filter by entity type label (e.g. contact, transaction, invoice).
limitintegerOptional. Max rows (default around 100; server clamps to a safe maximum).

List across organizations (same key)

GET/recently-deleted
Auth required

Same 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:

FieldTypeDescription
idstringAudit row id
organization_idstringOrganization the entity belonged to
api_key_idstring | nullKey that performed the delete, when known
entity_typestringNormalized type (e.g. contact, bill)
entity_idstringId of the deleted entity
deleted_atdatetimeWhen the soft delete was recorded
purge_after_atdatetimeWhen the row becomes eligible for hard purge
metadataobjectOptional 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

CapabilityStatus
Soft delete + hidden from normal listsSupported
Audit list (recently-deleted)Supported
Public restore / undelete APINot 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.


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.