curl --request PATCH \
--url https://app.formbricks.com/api/v3/feedbackRecords/{id} \
--header 'Content-Type: application/json' \
--header 'x-api-key: <api-key>' \
--data '
{
"value_text": "Queues at the north gate were far too long on match day."
}
'{
"id": "018e1234-5678-7abc-8ef0-123456789abd",
"tenant_id": "ph7zv3w2u1x5k9d8m4q6c0bn",
"collected_at": "2026-08-15T10:30:00Z",
"created_at": "2026-08-15T10:30:02Z",
"updated_at": "2026-08-16T09:02:11Z",
"source_type": "survey",
"source_id": "cm2k7q9x00003v8h1a2b3c4d5",
"source_name": "Post-match survey",
"submission_id": "cm2k7qa1z0007v8h1e6f7g8h9",
"field_id": "q2",
"field_label": "What could we improve?",
"field_type": "text",
"value_text": "Queues at the north gate were far too long on match day.",
"user_id": "fan-8813",
"language": "en"
}Update a feedback record
Changes the answer, language, user_id or metadata of one record. Only the members sent
are changed; provenance (tenant_id, source_*, field_*, submission_id, collected_at)
is immutable. Requires an API key with write permission (or higher) on a workspace the
record’s dataset is assigned to, and the dataset must be assigned to exactly one workspace
— see the delete operation for why.
Two behaviours are silent and worth knowing: metadata is replaced, not merged; and
changing value_text clears the enrichment members (sentiment, sentiment_score,
emotions, value_text_translated, translation_lang_key) and queues re-enrichment and
re-embedding — the response shows them absent until that completes. Changing language clears
and re-queues the translation pair only.
curl --request PATCH \
--url https://app.formbricks.com/api/v3/feedbackRecords/{id} \
--header 'Content-Type: application/json' \
--header 'x-api-key: <api-key>' \
--data '
{
"value_text": "Queues at the north gate were far too long on match day."
}
'{
"id": "018e1234-5678-7abc-8ef0-123456789abd",
"tenant_id": "ph7zv3w2u1x5k9d8m4q6c0bn",
"collected_at": "2026-08-15T10:30:00Z",
"created_at": "2026-08-15T10:30:02Z",
"updated_at": "2026-08-16T09:02:11Z",
"source_type": "survey",
"source_id": "cm2k7q9x00003v8h1a2b3c4d5",
"source_name": "Post-match survey",
"submission_id": "cm2k7qa1z0007v8h1e6f7g8h9",
"field_id": "q2",
"field_label": "What could we improve?",
"field_type": "text",
"value_text": "Queues at the north gate were far too long on match day.",
"user_id": "fan-8813",
"language": "en"
}Authorizations
Management API key; must include workspaceId as an allowed workspace with read, write, or manage permission.
Path Parameters
Feedback record id (UUID). The dataset is resolved from the record itself, so the caller cannot choose which dataset it is authorized against. An id that is not a UUID answers 400, and an id whose dataset the API key cannot reach answers 403 rather than 404, so ids cannot be probed. The gateway caches the record→dataset lookup for 60 seconds, so for up to a minute after a delete the id is still authorized and the store answers 404; after that the same id answers 403.
Body
A partial update. Only the members sent are changed; an empty body is accepted and changes nothing. Provenance (tenant_id, source_*, field_*, submission_id, collected_at) is immutable.
New text answer. Changing it clears the server-generated enrichment members (sentiment, sentiment_score, emotions, value_text_translated, translation_lang_key), queues re-enrichment and re-embedding, and the response reflects the cleared state.
30000New stable option id for a choice answer. Opaque, not validated.
255New numeric answer. Must be between -1e15 and +1e15.
-1000000000000000 <= x <= 1000000000000000New yes / no answer.
New date answer. Must be between 1970-01-01 and 2080-12-31.
New ISO language code. Changing it clears and re-queues the translation pair only.
10New end-user identifier.
255Replaces the stored metadata wholesale — it is not merged, so send every key you want to keep. Same value rules and 400 rejections as on create.
Show child attributes
Show child attributes
Response
Feedback record updated
One piece of feedback in the normalized Feedback Record shape. Field names are snake_case: the payload is the Hub's, passed through the API gateway unchanged. Optional members are absent (not null) when unset.
UUIDv7 primary key.
The feedback dataset this record belongs to (the dataset id, as shown by the MCP list_feedback_datasets tool).
When the feedback was given.
When the record was stored. Diverges from collected_at on a historical re-import.
When the record was last changed.
Type of feedback source, e.g. survey, review, feedback_form.
Identifier of the logical submission this record belongs to (e.g. a response id). Records are unique per (tenant_id, submission_id, field_id).
Identifier of the question / field.
The type of a feedback field, which determines which value_* member carries the answer: text → value_text (the only enrichable type), categorical → value_text + value_id, nps / csat / ces / rating / number → value_number, boolean → value_boolean, date → value_date.
text, categorical, nps, csat, ces, rating, number, boolean, date Reference to the survey / form / ticket the record came from.
Human-readable name of the source.
The question text.
Stable identifier grouping related fields (ranking, matrix and grid questions).
Human-readable question text for the group.
ISO language code the feedback was given in.
End-user identifier (e.g. an anonymous id or an email hash).
Text answer.
Stable id of the selected option in the source system (e.g. a survey choice id), stored alongside value_text so choice answers keep their identity across label edits and languages. Opaque. Absent for free-text and non-choice answers.
Numeric answer (ratings, NPS scores, numbers).
Yes / no answer.
Date answer.
Arbitrary context stored with the record and returned with equivalent values (key order and number formatting are normalized). Omitted when the record has no metadata; a record explicitly stored with a JSON null returns null. An object is the supported shape and the only one the write operations accept; the wider union exists so records written before that convention still deserialize.
Sentiment polarity label inferred from value_text by the sentiment enrichment: five ordinal levels plus a distinct mixed. Server-generated and read-only.
very_negative, negative, neutral, positive, very_positive, mixed Signed sentiment polarity from -1.0 (very negative) to 1.0 (very positive). Read-only; absent until the record is enriched.
-1 <= x <= 1Emotions inferred from value_text; multi-label from a fixed set. Read-only, and never an empty array — the column is either absent or has at least one label. Absent covers two different states: not yet classified, and classified with no emotion detected. Do not read absence as "not enriched yet"; has_emotions=false selects both, and the enrichment-status endpoint is what distinguishes them.
1A single emotion label inferred from value_text by the emotion enrichment (the six Ekman basic emotions). Emotions are multi-label, so a record carries zero or more of these; "mixed" is not a label, it is two or more present at once. Server-generated and read-only.
joy, anger, sadness, fear, surprise, disgust value_text translated into the dataset's configured target language. Read-only; absent until the record is enriched.
BCP-47 locale that value_text_translated was produced in. Read-only; absent until the record is enriched.
35Was this page helpful?