Skip to content

Get surveys

GET{{API_BASE_URL}}/ticketinghub/odata/v1/Surveys?$select=SubmissionInternalId,AnswerInternalId,SelectionOrdinal,QuestionText,AnswerDisplayValue,TicketInternalId

What visitors told you, joined back to who they are. One row per selected option — read the grain note before you count anything.

Because survey answers join to the ticket, any answer can be segmented by anything the ticket knows: article, event, statistics group, country, or how the ticket was issued.

Grain and key

Grainone row per selected option (selection grain)
Natural keyMandatorInternalId, AnswerInternalId, SelectionOrdinal
Page size500
Columns32
WatermarkLastRefreshedAt — incremental loading possible

The columns most extracts start with

ColumnTypeNotes
SubmissionInternalIdintOne completed survey. Count distinct for responses.
AnswerInternalIdintOne answer to one question. Count distinct for answers.
SelectionOrdinalshortWhich selected option this row represents.
QuestionTextstring?The question as the visitor saw it.
QuestionTypestring?The question's form type. Pass-through — no fixed list.
IsMultiSelectboolWhether several options were possible.
IsRequiredboolWhether the question was mandatory.
Answerstring?The raw lookup key.
AnswerDisplayValuestring?The label the visitor saw. Report on this one.
IsCustomAnswerboolA free-text answer rather than a chosen option.
AnswerSourcestring?Where the answer came from. Pass-through.
SubmittedAtdatetimeoffsetWhen it was answered.
Languagestring?Which language they answered in.
TicketInternalIdintJoin key back to Tickets.
LastRefreshedAtdatetimeWatermark. No offset — do not convert.

Traps specific to this dataset

  • Selection grain is the trap. A multi-select answer is not one row with a comma-separated list; it is one row per selected option. Someone ticking four boxes produces four rows. Counting rows overcounts, sometimes by a lot.

    You wantCount
    Responses (completed surveys)distinct SubmissionInternalId
    Answers (question-level)distinct AnswerInternalId
    Selections (option-level)rows
  • Group on AnswerDisplayValue, not Answer. Answer holds the raw lookup key, which is stable but meaningless on a chart. AnswerDisplayValue is the label the visitor actually read.

  • Free-text answers need separate handling. IsCustomAnswer rows contain whatever the visitor typed — do not group on them as if they were a controlled vocabulary.

  • No visitor context here. Name, contact data and article are deliberately not in this dataset — join Tickets.

Joining

Join to Tickets on MandatorInternalId, TicketInternalId.


Request

No request body.

  • $select(string): the columns to load.
  • $filter(string): an OData predicate. This dataset carries LastRefreshedAt, so it can be loaded incrementally.
  • $orderby(string): sort order.
  • $top(integer): maximum rows, capped at 1000.
  • $count(boolean): include the total count.
  • $skiptoken(string): server-generated paging token.

Response

  • @odata.context (string): the metadata URL describing this payload.
  • value (array): the page of selection rows.
  • @odata.nextLink (string, optional): the next page; absent on the last one.
  • @odata.count (integer, optional): present only when $count=true.

The grain will catch you out

One row is one selected option, not one answer. Somebody ticking four boxes on a multi-select question produces four rows.

You wantCount
Responses (completed surveys)distinct SubmissionInternalId
Answers (question level)distinct AnswerInternalId
Selections (option level)rows

Group and report on AnswerDisplayValue, the label the visitor actually read — Answer holds the raw lookup key, which is stable but meaningless on a chart.

Notes

Page size is 500. @odata.count counts selections, so it is not your response count.

QuestionType, AnswerSource and Characteristic are pass-through columns — their value sets come from your own survey configuration rather than from a fixed list. See Datasets → Column values.

Authentication#auth

This endpoint does not require authentication.

Headers#headers

AuthorizationBearer {{ACCESS_TOKEN}}

Required. A client-credentials token carrying the scope ticketinghub-api and no subject. See Authentication.

Acceptapplication/json

Optional. JSON is returned by default.

Query parameters#query

$selectSubmissionInternalId,AnswerInternalId,SelectionOrdinal,QuestionText,AnswerDisplayValue,TicketInternalIdoptional

Comma-separated list of columns to load. Carry TicketInternalId so the answers can be joined back and segmented; report on AnswerDisplayValue rather than the raw Answer key.

$filterLastRefreshedAt gt 2026-01-01T00:00:00Zoptional

OData predicate. This dataset exposes LastRefreshedAt, so a watermark filter gives you an incremental load.

$orderbySubmittedAtoptional

Sort order. Note that it also changes the order the keyset walk runs in.

$top1000optional

Maximum number of rows. Capped at 1000; a higher value is rejected with 400. A smaller value lowers the page size but cannot raise it above 500.

$counttrueoptional

Include the total row count in @odata.count. Because of the selection grain this counts ticked options, not responses — count distinct SubmissionInternalId for that.

$skiptokenoptional

Server-generated keyset paging token. Note that this dataset has a three-part key, so the walk runs in alphabetical key order.

$skipoptional

Offset paging. Supported but discouraged — use @odata.nextLink instead.

Responses#responses

200OKGet surveys