Skip to content

Imports API

Endpoints that import existing questionnaires from Creative Survey (CS). They are called by the Chrome extension.

Imported data is stored as-is in the external data tables (external_*), and each question is also registered into the question library as "external-origin data".

See API Definition for the response format and error handling.

Method

HTTP Methods

Method URI Overview
POST /api/imports/creative-survey/bundle Import a Creative Survey bundle
GET /api/imports/creative-survey/existing-ids List already-imported externalIds
GET /api/imports/creative-survey/section-previews Section candidate preview (all)
GET /api/imports/creative-survey/section-previews/{externalSurveyId} Section candidate preview (single)

Authentication

/api/imports/* accepts API key authentication in addition to the usual user-header authentication.

Method Condition
User headers x-user-email + x-user-name
API key SURVEY_IMPORT_API_KEY is set and the x-api-key header matches it

With API key authentication, the import is recorded as the user given in x-user-email, or as import-bot@local (display name Import Bot) when no user is given.

Import a Creative Survey Bundle

Overview

Receives the questionnaire data (bundle JSON) that the Chrome extension fetched from the CS API and stores it in the external data tables.

If the same questionnaire (the source + externalId pair) already exists, it is cascade-deleted and re-inserted. Repeated imports therefore never produce duplicates.

URI

POST /api/imports/creative-survey/bundle

Request Headers

  • Content-Type: application/json
  • x-api-key: <SURVEY_IMPORT_API_KEY> (for API key authentication)

Request Body

{
  "fetchedAt": "2026-08-18T00:00:00.000Z",
  "origin": "https://4dsd.svy.ooo",
  "summary": {},
  "surveys": [
    {
      "surveyId": 12345,
      "surveyMeta": {},
      "survey": { "name": "ๆ—ขๅญ˜ใฎ่ชฟๆŸป็ฅจ" },
      "questionnaire": { "id": 1, "survey_id": 12345, "generate_order": [[101, 102]] },
      "questions": [
        {
          "id": 101,
          "answer_type": 2,
          "answer_type_name": "้ธๆŠž",
          "rendered_sentence": "ใ‚ใชใŸใฎๆ€งๅˆฅใ‚’ใŠ็ญ”ใˆใใ ใ•ใ„ใ€‚",
          "order_index": 0,
          "any_logic": true,
          "any_visibility": false,
          "answer_items": [{ "id": 1001, "sentence": "็”ทๆ€ง", "order_index": 0 }],
          "sub_items": [],
          "logics": [
            {
              "id": 5001,
              "order_index": 0,
              "logic_items": [
                { "id": 9001, "question_id": 101, "answer_item_id": 1001, "verb": 0, "value": "" }
              ],
              "logic_action": { "id": 7001, "question_id": 105, "is_random": false }
            }
          ]
        }
      ],
      "errors": []
    }
  ]
}

Validation Rules

Field Rule
origin Required. A string of at least one character
surveys Required. An array with at least one entry
surveys[].surveyId Required. Number (the CS questionnaire ID)
surveys[].survey Required. An object or null
surveys[].questionnaire Required. An object or null
surveys[].questions Optional. Array of questions
fetchedAt / summary / errors Optional

Question, choice, and branch objects pass unknown fields through (because the CS API is undocumented, unexpected fields are still stored as raw JSON).

Response (200 OK)

{
  "ok": true,
  "data": {
    "surveysImported": 1,
    "questionsImported": 24,
    "answerItemsImported": 130,
    "subItemsImported": 12,
    "logicsImported": 8,
    "logicItemsImported": 15,
    "libraryItemsImported": 24,
    "surveyIds": ["3fa85f64-5717-4562-b3fc-2c963f66afa6"],
    "skipped": []
  }
}
Field Type Notes
surveysImported number Number of questionnaires imported
questionsImported number Number of questions imported
answerItemsImported number Number of choices imported
subItemsImported number Number of sub items imported
logicsImported number Number of branch logics imported
logicItemsImported number Number of branch conditions imported
libraryItemsImported number Number of entries registered into the question library
surveyIds string[] UUIDs of the stored external_surveys rows
skipped object[] Questionnaires that were not imported (externalId and reason)

Error Handling

Description Status code Status name
Malformed request body (empty surveys, empty origin, โ€ฆ) 400 Bad Request
Missing authentication, or a mismatched API key 401 Unauthorized

Processing Flow

Sequence Diagram

sequenceDiagram
    participant Ext as Chrome extension
    participant API
    participant DB
    participant Library as Question library

    Ext->>API: POST /api/imports/creative-survey/bundle
    API->>API: Validate the request
    API->>API: Resolve the actor (Import Bot under API key auth)
    loop For each questionnaire
        API->>DB: Look up an existing (source, externalId)
        opt Exists
            API->>DB: Delete the existing external_surveys row (children cascade)
        end
        API->>DB: Store into external_surveys
        API->>DB: Store into external_questions
        API->>DB: Store into external_answer_items / external_sub_items
        API->>DB: Store into external_logics / external_logic_items
        API->>Library: Register each question as external-origin data
    end
    API->>API: Aggregate the import counts
    API-->>Ext: 200 OK

List Already-imported externalIds

Overview

Returns the list of CS questionnaire IDs that have already been imported.

The Chrome extension uses this to skip already-fetched questionnaires when resuming an interrupted import.

URI

GET /api/imports/creative-survey/existing-ids

Query Parameters

Parameter Type Required Notes
source string Source identifier. Defaults to creative_survey

Response (200 OK)

{
  "ok": true,
  "data": {
    "source": "creative_survey",
    "ids": [12345, 12346, 12350]
  }
}

Error Handling

Description Status code Status name
Missing authentication 401 Unauthorized

Section Candidate Preview (All)

Overview

Returns section candidates for every imported external questionnaire.

CS has no concept of sections, so the question sequence is split into section candidates at questions whose answer_type_name is "ๆ็คบใ‚นใƒ†ใƒƒใƒ—" (intro step).

URI

GET /api/imports/creative-survey/section-previews

Response (200 OK)

{
  "ok": true,
  "data": [
    {
      "externalSurveyId": "3fa85f64-5717-4562-b3fc-2c963f66afa6",
      "externalSurveyName": "ๆ—ขๅญ˜ใฎ่ชฟๆŸป็ฅจ",
      "externalSurveyExternalId": 12345,
      "sections": [
        {
          "index": 0,
          "title": "ใ‚นใ‚ฏใƒชใƒผใƒ‹ใƒณใ‚ฐ",
          "description": "",
          "libraryItemIds": ["โ€ฆ", "โ€ฆ"],
          "questionCount": 5
        }
      ]
    }
  ]
}
Field Type Notes
sections[].index number Position of the section candidate
sections[].title string Title derived from the text of the intro step that acted as the divider
sections[].libraryItemIds string[] UUIDs of the question library entries in this section
sections[].questionCount number Number of questions

Passing the resulting libraryItemIds to Insert One Section from External Entries inserts them as a single section.

Error Handling

Description Status code Status name
Missing authentication 401 Unauthorized

Section Candidate Preview (Single)

Overview

Returns the section candidates of a single external questionnaire.

URI

GET /api/imports/creative-survey/section-previews/{externalSurveyId}
Parameter Type Required Notes
externalSurveyId string โ—ฏ UUID in external_surveys

Validation Rules

Field Rule
externalSurveyId Required. UUID format

Response (200 OK)

Returns the section candidates of one questionnaire (the structure matches an element of the list version).

Error Handling

Description Status code Status name
externalSurveyId is not a UUID 400 Bad Request
The external questionnaire does not exist 404 Not Found