---
title: "Retry permanently-failed enrichments for a tenant"
method: POST
path: "/v1/tenants/{tenant_id}/enrichments/retry"
tags: ["Enrichment Status"]
---

# Retry permanently-failed enrichments for a tenant

`POST /v1/tenants/{tenant_id}/enrichments/retry`

## Request

- Base URL: `http://localhost:8080`
- URL: `http://localhost:8080/v1/tenants/{tenant_id}/enrichments/retry`
- Auth: HTTP bearer

Clears the terminal failure markers for a tenant so the reconciler will attempt those
records again.

The automatic sweep deliberately never revives a terminal record: a terminal failure is a
property of the record's own text — a content-policy block, a refusal, an input past the
model's limit — so re-running it costs a provider call and fails identically. This endpoint
is the override for when that premise has changed: the text was edited, or the provider
changed its policy.

Because of that, it is **rate limited per (tenant, enrichment)**. Clearing is a request to
spend a provider call on every record already known to fail, so an unbounded clear would be
a cost-amplification loop. A refused call returns `cooling_down` with the remaining wait
rather than silently doing nothing.

Every requested enrichment gets its own outcome — a tenant can have one cleared, one cooling
down and one switched off in the same call. Responds 202: clearing is synchronous, but the
retrying is not.

## Path parameters

- `tenant_id` string, required

## Request body

- EnrichmentRetryInputBody
  - `enrichments` string[]: Which enrichments to clear. Omit or leave empty for all of them, which is the usual call. An unknown name is rejected rather than ignored, so a typo cannot come back as a successful no-op. A list longer than the three names is rejected too.

## Response `202`

Accepted; see each enrichment's outcome.

- EnrichmentRetryOutputBody
  - `tenant_id` string, required
  - `results` EnrichmentRetryResult[], required
    - `enrichment` 'translation' | 'sentiment' | 'emotions', required
    - `outcome` 'cleared' | 'cooling_down' | 'disabled', required: `cleared` — the markers were removed and the records will be picked up by the next reconcile sweep. `cooling_down` — this enrichment was cleared too recently; see `retry_after_seconds`. `disabled` — the enrichment is not running for this tenant, so clearing would queue work the worker skips; see `disabled_reason`.
    - `cleared` integer, required: How many records had a terminal marker removed. Zero with outcome `cleared` is a real answer: nothing was permanently failed.
    - `retry_after_seconds` integer: Present only for `cooling_down`. How long until this enrichment may be cleared again.
    - `disabled_reason` 'not_configured' | 'switched_off' | 'no_target_language': Present only for `disabled`. Same values the enrichment-status endpoint uses, so a consumer needs one vocabulary rather than two.

## Other responses

- `400`: Bad Request. Returned for an unknown enrichment name, a body that is not a JSON object, an unknown or repeated member, malformed JSON, or a missing tenant id.
- `401`: Unauthorized (missing or invalid API key)
- `409`: Conflict. Returned when the reconciler is disabled on this deployment (clearing failures would have no effect until it is re-enabled), or when a tenant data purge currently holds the tenant's write lock.
- `413`: Request body exceeds the maximum allowed size.
- `default`: Error

## Changes

- **2026-09-04** `e258f5b032aa`: 1 info
  - endpoint added

[Operation history](https://skmtc.dev/formbricks/apis/formbricks-hub-api/changes/v1/tenants/:tenant_id/enrichments/retry/post.md)

---

[API](https://skmtc.dev/formbricks/apis/formbricks-hub-api.md) - [All operations](https://skmtc.dev/formbricks/apis/formbricks-hub-api/llms.txt) - [OpenAPI document](https://skmtc.dev/formbricks/apis/formbricks-hub-api/revisions/d28d293b345d?raw)
