Purge all feedback records for a tenant
const url = 'http://localhost:8080/v1/tenants/org-123/feedback-records';const options = {method: 'DELETE', headers: {Authorization: 'Bearer <token>'}};
try { const response = await fetch(url, options); const data = await response.json(); console.log(data);} catch (error) { console.error(error);}curl --request DELETE \ --url http://localhost:8080/v1/tenants/org-123/feedback-records \ --header 'Authorization: Bearer <token>'Permanently deletes every feedback record for the specified tenant_id, everything derived from those records — embeddings and the enrichment stored on each record (sentiment, emotions, translations) — and the taxonomy built on them: runs, clusters, nodes, cluster memberships, active-run pointers and node events.
This is intended for emptying a dataset that stays in use, so it removes the tenant’s DATA but
never its CONFIGURATION: webhooks and tenant settings are left untouched. That is the difference
from DELETE /v1/tenants/{tenant_id}/data, which additionally deletes both and is meant for
offboarding a deprovisioned tenant.
The taxonomy is removed rather than preserved because it describes records that no longer exist:
its per-node counts are derived from memberships and would all read zero, while a run’s own stored
counters (record_count, cluster_count, a cluster’s size) are historical and would keep
advertising the old numbers. A new taxonomy can be generated once the dataset has enough feedback
again; manual node renames and removals are per-run and do not survive a regeneration in any case.
The tenant is a required path segment, so it cannot be omitted the way a filter on a collection delete could be — dropping it routes elsewhere rather than widening the operation to every tenant.
Asynchronous: the request schedules the purge and returns 202 immediately, because the deletion is
unbounded and can outlive a request. There is therefore no deleted count in the response. Poll
GET /v1/feedback-records/count?tenant_id=... to observe progress.
The purge removes only the records that existed when it started — it takes a high-water mark up front — so feedback ingested while it runs is never deleted. For a dataset that is no longer receiving feedback the count reaching zero means the purge is complete; for one still ingesting, a nonzero count is those newer records. Note this means the count alone cannot distinguish “finished” from “failed” on an active dataset.
Idempotent and safe to repeat. Requesting a purge while one is already running for the same tenant joins the running purge rather than queueing a second one, and still returns 202. A purge requested after an earlier one finished starts a new run.
Records are deleted in committed batches, so a purge interrupted by a restart or a timeout keeps
the progress it made and resumes on retry; the taxonomy is removed in a final step once the records
are gone. While each step runs, the tenant’s write lock is held exclusively and Hub-owned writes
for that tenant are rejected with HTTP 409 (code tenant_write_conflict); the lock is released
between steps, and writes for other tenants are never affected. This does not apply to the request below — scheduling a purge takes no lock, so
this endpoint does not return 409. A batch that cannot acquire the lock is retried by the job
queue without any caller action, up to a bounded number of attempts.
No webhook events are published for a purge, and no webhooks are deleted. Enrichment jobs already queued for purged records no-op when they run, since the record they reference is gone.
Authorizations
Section titled “Authorizations”Parameters
Section titled “Parameters”Path Parameters
Section titled “Path Parameters”Example
org-123Tenant ID whose feedback records should be purged. Empty strings and NULL bytes are not allowed.
Responses
Section titled “Responses”Purge accepted and scheduled
object
Tenant ID whose feedback records are being purged
Always accepted. The purge runs in the background, so this reports that the work was
scheduled, not that it finished — poll GET /v1/feedback-records/count for the tenant to
observe completion.
Human-readable confirmation
Examples
Purge accepted
{ "tenant_id": "org-123", "status": "accepted", "message": "Feedback records purge accepted for org-123"}Bad Request (e.g. missing or invalid tenant_id)
RFC 9457 problem details (application/problem+json). Branch on the stable code member rather than on title or type.
object
Stable, machine-readable error code; the primary value to branch on. service_unavailable indicates a feature or dependency is temporarily unavailable and the request may be retried later. tenant_write_conflict indicates the write conflicted with an in-progress tenant data purge (or vice versa) and may be retried later unchanged. All other codes are terminal until the request itself is changed.
A human-readable explanation specific to this occurrence of the problem.
Optional structured context for this problem, e.g. resource_type on a 404.
object
A URI reference (typically the request path) identifying the specific occurrence of the problem.
Field-level validation failures (RFC 9457 “invalid_params” extension). Present on validation errors.
A single invalid request parameter (RFC 9457 “invalid_params” extension member).
object
Dotted path to the offending request field, e.g. ‘field_type’ or ‘items[0].field_type’.
Human- and agent-readable explanation of why the value is invalid, naming allowed values or constraints where applicable so the request can be corrected without guessing.
Identifier for this request, also returned in the X-Request-ID response header; include it when reporting a problem.
HTTP status code
A short, human-readable summary of the problem type. This value should not change between occurrences of the error.
A URI reference identifying the problem type.
Example
{ "code": "validation", "detail": "One or more request parameters are invalid", "instance": "/v1/feedback-records", "invalid_params": [ { "name": "field_type", "reason": "must be one of: text, categorical, nps, csat, ces, rating, number, boolean, date" } ], "request_id": "0190a1b2-c3d4-7e5f-8a9b-0c1d2e3f4a5b", "status": 400, "title": "Bad Request", "type": "https://hub.formbricks.com/problems/bad-request"}Unauthorized (missing or invalid API key)
RFC 9457 problem details (application/problem+json). Branch on the stable code member rather than on title or type.
object
Stable, machine-readable error code; the primary value to branch on. service_unavailable indicates a feature or dependency is temporarily unavailable and the request may be retried later. tenant_write_conflict indicates the write conflicted with an in-progress tenant data purge (or vice versa) and may be retried later unchanged. All other codes are terminal until the request itself is changed.
A human-readable explanation specific to this occurrence of the problem.
Optional structured context for this problem, e.g. resource_type on a 404.
object
A URI reference (typically the request path) identifying the specific occurrence of the problem.
Field-level validation failures (RFC 9457 “invalid_params” extension). Present on validation errors.
A single invalid request parameter (RFC 9457 “invalid_params” extension member).
object
Dotted path to the offending request field, e.g. ‘field_type’ or ‘items[0].field_type’.
Human- and agent-readable explanation of why the value is invalid, naming allowed values or constraints where applicable so the request can be corrected without guessing.
Identifier for this request, also returned in the X-Request-ID response header; include it when reporting a problem.
HTTP status code
A short, human-readable summary of the problem type. This value should not change between occurrences of the error.
A URI reference identifying the problem type.
Example
{ "code": "validation", "detail": "One or more request parameters are invalid", "instance": "/v1/feedback-records", "invalid_params": [ { "name": "field_type", "reason": "must be one of: text, categorical, nps, csat, ces, rating, number, boolean, date" } ], "request_id": "0190a1b2-c3d4-7e5f-8a9b-0c1d2e3f4a5b", "status": 400, "title": "Bad Request", "type": "https://hub.formbricks.com/problems/bad-request"}default
Section titled “default”Error
RFC 9457 problem details (application/problem+json). Branch on the stable code member rather than on title or type.
object
Stable, machine-readable error code; the primary value to branch on. service_unavailable indicates a feature or dependency is temporarily unavailable and the request may be retried later. tenant_write_conflict indicates the write conflicted with an in-progress tenant data purge (or vice versa) and may be retried later unchanged. All other codes are terminal until the request itself is changed.
A human-readable explanation specific to this occurrence of the problem.
Optional structured context for this problem, e.g. resource_type on a 404.
object
A URI reference (typically the request path) identifying the specific occurrence of the problem.
Field-level validation failures (RFC 9457 “invalid_params” extension). Present on validation errors.
A single invalid request parameter (RFC 9457 “invalid_params” extension member).
object
Dotted path to the offending request field, e.g. ‘field_type’ or ‘items[0].field_type’.
Human- and agent-readable explanation of why the value is invalid, naming allowed values or constraints where applicable so the request can be corrected without guessing.
Identifier for this request, also returned in the X-Request-ID response header; include it when reporting a problem.
HTTP status code
A short, human-readable summary of the problem type. This value should not change between occurrences of the error.
A URI reference identifying the problem type.
Example
{ "code": "validation", "detail": "One or more request parameters are invalid", "instance": "/v1/feedback-records", "invalid_params": [ { "name": "field_type", "reason": "must be one of: text, categorical, nps, csat, ces, rating, number, boolean, date" } ], "request_id": "0190a1b2-c3d4-7e5f-8a9b-0c1d2e3f4a5b", "status": 400, "title": "Bad Request", "type": "https://hub.formbricks.com/problems/bad-request"}