Skip to content
Support

Create a new feedback record

POST/v1/feedback-records

Creates a new feedback record data point

Body ParametersExpand Collapse
field_id: string

Identifier for the question/field. NULL bytes not allowed.

minLength1
maxLength255
field_type: "text" or "categorical" or "nps" or 6 more

Field type: text (enrichable), categorical, nps, csat, ces, rating, number, boolean, date

minLength1
maxLength255
Accepts one of the following:
"text"
"categorical"
"nps"
"csat"
"ces"
"rating"
"number"
"boolean"
"date"
source_type: string

Type of feedback source (e.g., survey, review, feedback_form). NULL bytes not allowed.

minLength1
maxLength255
submission_id: string

Identifier for the logical submission this record belongs to (tenant-scoped). Required. Enables grouping multi-field submissions and idempotent ingestion. Unique per (tenant_id, submission_id, field_id). If a record has no logical submission, use e.g. field_id.

minLength1
maxLength255
tenant_id: string

Tenant/organization identifier for multi-tenancy. Required.

minLength1
maxLength255
collected_at: optional string

When the feedback was collected (defaults to now). Must be between 1970-01-01 and 2080-12-31.

formatdate-time
field_group_id: optional string

Stable identifier grouping related fields (for ranking, matrix, grid questions). NULL bytes not allowed.

maxLength255
field_group_label: optional string

Human-readable question text for the group

maxLength2048
field_label: optional string

The actual question text

maxLength2048
language: optional string

ISO language code. NULL bytes not allowed.

maxLength10
metadata: optional map[unknown]

Arbitrary context for this record, stored as JSON and returned with equivalent values (key order and number formatting are normalized): the dimensions you want to slice a dashboard by, such as channel, device, browser, OS, country, referrer, campaign, plan or tags. Values may be strings, numbers, booleans, null, or nested objects and arrays. Use snake_case keys and keep them stable across records, since a key is what a dashboard groups by: customer_tier, not a mix of customerTier and tier. Numbers keep full precision in storage (unlike value_number, which is a float64), so a large integer id round-trips exactly through this API — though a JavaScript client will still lose precision above 2^53 when it parses the response. Nothing here is redacted. Metadata is not sent to the LLM or embedding enrichment providers, unlike value_text — but it is included in the feedback_record.created and feedback_record.updated webhook payloads, so it reaches whatever URL a tenant has configured. Erasure covers metadata, with one precondition worth knowing: DELETE /v1/feedback-records matches on user_id and hard-deletes the whole row, metadata included — so a record written without a user_id cannot be reached that way. Set user_id on anything you may later have to erase. Three kinds of content are rejected with 400, because none of them can be stored: invalid UTF-8; NULL bytes or unpaired UTF-16 surrogates, in keys or values; and numbers outside the storable numeric range.

source_id: optional string

Reference to survey/form/ticket ID

maxLength255
source_name: optional string

Human-readable name

maxLength255
user_id: optional string

User ID (e.g., anonymous ID or email hash)

maxLength255
value_boolean: optional boolean

For yes/no questions

value_date: optional string

For date responses. Must be between 1970-01-01 and 2080-12-31.

formatdate-time
value_id: optional string

Stable id of the selected option in the source system (e.g. a survey choice id or matrix column id), stored alongside value_text so selected-choice answers keep a durable identity across label edits and languages. Opaque to Hub (not validated). Null for free-text/"other" answers, non-choice fields, and sources without option ids. NULL bytes not allowed when present.

maxLength255
value_number: optional number

For ratings, NPS scores, numeric responses. Must be between -1e15 and +1e15.

formatdouble
minimum-1000000000000000
maximum1000000000000000
value_text: optional string

For open-ended text responses. Omit or null if not applicable. NULL bytes not allowed when present.

maxLength30000
ReturnsExpand Collapse
FeedbackRecordData = object { id, collected_at, created_at, 24 more }
id: string

UUIDv7 primary key

formatuuid
collected_at: string

When the feedback was collected

formatdate-time
created_at: string

When this record was created

formatdate-time
field_id: string

Identifier for the question/field

field_type: "text" or "categorical" or "nps" or 6 more

Type of field

Accepts one of the following:
"text"
"categorical"
"nps"
"csat"
"ces"
"rating"
"number"
"boolean"
"date"
source_type: string

Type of feedback source

submission_id: string

Identifier for the logical submission this record belongs to (required).

tenant_id: string

Tenant/organization identifier. NULL bytes not allowed.

updated_at: string

When this record was last updated

formatdate-time
emotions: optional array of "joy" or "anger" or "sadness" or 3 more

Emotions inferred from value_text (emotion enrichment); multi-label from a fixed set. Read-only; absent until the record is enriched, and never an empty array.

Accepts one of the following:
"joy"
"anger"
"sadness"
"fear"
"surprise"
"disgust"
field_group_id: optional string

Stable identifier grouping related fields (for ranking, matrix, grid questions)

field_group_label: optional string

Human-readable question text for the group

field_label: optional string

The actual question text

language: optional string

ISO language code. NULL bytes not allowed.

metadata: optional unknown or array of unknown or string or 2 more

Arbitrary context stored with this record, returned with equivalent values (key order is normalized, and so are number exponents — 1e2 reads back as 100). 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 request schemas accept. The wider union is for reading: the column stores whatever JSON was written, so a record created before that convention can return an array or a scalar, and an object-only response schema would make a generated client reject it.

Accepts one of the following:
UnionMember0 = unknown

Arbitrary context stored with this record, returned with equivalent values (key order is normalized, and so are number exponents — 1e2 reads back as 100). 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 request schemas accept. The wider union is for reading: the column stores whatever JSON was written, so a record created before that convention can return an array or a scalar, and an object-only response schema would make a generated client reject it.

UnionMember1 = array of unknown

Arbitrary context stored with this record, returned with equivalent values (key order is normalized, and so are number exponents — 1e2 reads back as 100). 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 request schemas accept. The wider union is for reading: the column stores whatever JSON was written, so a record created before that convention can return an array or a scalar, and an object-only response schema would make a generated client reject it.

UnionMember2 = string

Arbitrary context stored with this record, returned with equivalent values (key order is normalized, and so are number exponents — 1e2 reads back as 100). 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 request schemas accept. The wider union is for reading: the column stores whatever JSON was written, so a record created before that convention can return an array or a scalar, and an object-only response schema would make a generated client reject it.

UnionMember3 = number

Arbitrary context stored with this record, returned with equivalent values (key order is normalized, and so are number exponents — 1e2 reads back as 100). 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 request schemas accept. The wider union is for reading: the column stores whatever JSON was written, so a record created before that convention can return an array or a scalar, and an object-only response schema would make a generated client reject it.

UnionMember4 = boolean

Arbitrary context stored with this record, returned with equivalent values (key order is normalized, and so are number exponents — 1e2 reads back as 100). 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 request schemas accept. The wider union is for reading: the column stores whatever JSON was written, so a record created before that convention can return an array or a scalar, and an object-only response schema would make a generated client reject it.

sentiment: optional "very_negative" or "negative" or "neutral" or 3 more

Sentiment polarity inferred from value_text (sentiment enrichment). Read-only; absent until the record is enriched.

Accepts one of the following:
"very_negative"
"negative"
"neutral"
"positive"
"very_positive"
"mixed"
sentiment_score: optional number

Signed sentiment polarity from -1.0 (very negative) to 1.0 (very positive) (sentiment enrichment). Read-only; absent until the record is enriched.

formatdouble
minimum-1
maximum1
source_id: optional string

Reference to survey/form/ticket ID

source_name: optional string

Human-readable name

translation_lang_key: optional string

BCP-47 target locale that value_text_translated was produced in (language enrichment). Read-only; absent until the record is enriched.

maxLength35
user_id: optional string

User ID (e.g., anonymous ID or email hash)

value_boolean: optional boolean

Boolean response

value_date: optional string

Date response

formatdate-time
value_id: optional string

Stable id of the selected option in the source system (e.g. a survey choice id), stored alongside value_text for durable option identity. Opaque to Hub. Absent for free-text/non-choice answers. NULL bytes not allowed.

value_number: optional number

Numeric response

formatdouble
value_text: optional string

Text response. NULL bytes not allowed.

value_text_translated: optional string

value_text translated into the tenant's configured target language (language enrichment). Read-only; absent until the record is enriched.

Create a new feedback record

curl http://localhost:8080/v1/feedback-records \
    -H 'Content-Type: application/json' \
    -H "Authorization: Bearer $HUB_API_KEY" \
    -d '{
          "field_id": "q1",
          "field_type": "rating",
          "source_type": "survey",
          "submission_id": "550e8400-e29b-41d4-a716-446655440000",
          "tenant_id": "org-123"
        }'
{
  "id": "018e1234-5678-9abc-def0-123456789abc",
  "collected_at": "2024-01-15T10:30:00Z",
  "created_at": "2024-01-15T10:30:00Z",
  "updated_at": "2024-01-15T10:30:00Z",
  "source_type": "survey",
  "field_id": "q1",
  "field_type": "rating",
  "field_label": "How satisfied are you?",
  "value_number": 9,
  "source_id": "survey-123",
  "source_name": "Q1 NPS Survey",
  "user_id": "user-abc-123",
  "tenant_id": "org-123",
  "submission_id": "550e8400-e29b-41d4-a716-446655440000",
  "language": "en"
}
{
  "type": "https://hub.formbricks.com/problems/validation",
  "title": "Validation Error",
  "status": 400,
  "code": "validation",
  "detail": "One or more request parameters are invalid",
  "instance": "/v1/feedback-records",
  "request_id": "0190a1b2-c3d4-7e5f-8a9b-0c1d2e3f4a5b",
  "invalid_params": [
    {
      "name": "field_type",
      "reason": "has invalid value \"textt\"; must be one of: text, categorical, nps, csat, ces, rating, number, boolean, date"
    }
  ]
}
Returns Examples
{
  "id": "018e1234-5678-9abc-def0-123456789abc",
  "collected_at": "2024-01-15T10:30:00Z",
  "created_at": "2024-01-15T10:30:00Z",
  "updated_at": "2024-01-15T10:30:00Z",
  "source_type": "survey",
  "field_id": "q1",
  "field_type": "rating",
  "field_label": "How satisfied are you?",
  "value_number": 9,
  "source_id": "survey-123",
  "source_name": "Q1 NPS Survey",
  "user_id": "user-abc-123",
  "tenant_id": "org-123",
  "submission_id": "550e8400-e29b-41d4-a716-446655440000",
  "language": "en"
}
{
  "type": "https://hub.formbricks.com/problems/validation",
  "title": "Validation Error",
  "status": 400,
  "code": "validation",
  "detail": "One or more request parameters are invalid",
  "instance": "/v1/feedback-records",
  "request_id": "0190a1b2-c3d4-7e5f-8a9b-0c1d2e3f4a5b",
  "invalid_params": [
    {
      "name": "field_type",
      "reason": "has invalid value \"textt\"; must be one of: text, categorical, nps, csat, ces, rating, number, boolean, date"
    }
  ]
}