Skip to main content

API Reference

Complete reference for the Qlarr backend REST API. There is no global route prefix — all endpoints are at the root level (no /api/ prefix) and routes are unversioned.

For authentication details, see Authentication.

Roles​

Role names as used in the codebase: super_admin, survey_admin, surveyor, analyst.

A global JwtAuthGuard protects every route unless it is marked @Public(); a RolesGuard enforces @Roles(...). "Auth: none" below means the route is public. "Auth: authenticated" means any valid token is accepted regardless of role.


Health​

GET /health​

Liveness check — the app is up and serving HTTP.

  • Auth: none

GET /health/db​

Readiness check — proves the app can reach PostgreSQL.

  • Auth: none

Authentication​

POST /user/login​

Authenticate with email and password. Returns an access token + refresh token.

  • Body: { email, password }
  • Auth: none
  • Rate limit: 10 attempts / 5 min per email

POST /user/refresh_token​

Refresh an expired access token. Refresh tokens are not rotated.

  • Body: { accessToken, refreshToken }
  • Auth: none

POST /user/forgot_password​

Send a password reset email (PIN to the registered address).

  • Body: { email }
  • Auth: none
  • Rate limit: 5 attempts / 15 min per email

POST /user/reset_password​

Reset a password using the reset token from the email.

  • Body: { refreshToken, newPassword }
  • Auth: none

POST /logout​

Log out and invalidate the current session.

  • Auth: authenticated

GET /auth/me​

Verify the current JWT and return its decoded principal.

  • Auth: authenticated

Users​

GET /users/me​

Get the current user's profile.

  • Auth: authenticated

GET /user/all​

List all users.

  • Auth: super_admin, survey_admin

GET /user/count_by_role​

Get user counts grouped by role.

  • Auth: super_admin

POST /user/create​

Create a new user.

  • Body: { firstName, lastName, email, roles }
  • Auth: super_admin

GET /user/{userId}​

Get user details by ID.

  • Auth: authenticated

PUT /user/{userId}​

Update a user (name, roles).

  • Body: { firstName?, lastName?, roles? }
  • Auth: super_admin

DELETE /user/{userId}​

Delete a user.

  • Auth: super_admin

PUT /user/profile​

Update own profile.

  • Body: { firstName?, lastName?, email?, password?, newPassword? }
  • Auth: authenticated
  • Rate limit: 5 attempts / 15 min per user (for email/password changes)

POST /user/confirm_new_email​

Confirm an email-address change using a PIN.

  • Body: { pin }
  • Auth: authenticated
  • Rate limit: 5 attempts / 15 min per user

Surveys​

GET /survey/all​

List all surveys with pagination and filtering.

  • Query: page, per_page, sort_by, status
  • Auth: authenticated

GET /survey/offline​

Get surveys available for offline mode.

  • Auth: super_admin, survey_admin, surveyor

POST /survey/create​

Create a new survey.

  • Body: { name, usage? } (usage: web | offline | mixed)
  • Auth: super_admin, survey_admin

POST /survey/import​

Import a survey from an export ZIP.

  • Body: multipart file upload (file)
  • Auth: super_admin, survey_admin

GET /survey/{surveyId}​

Get survey metadata.

  • Auth: authenticated

PUT /survey/{surveyId}​

Update survey metadata (name, dates, quota, privacy, navigation, etc.).

  • Body: survey settings
  • Auth: super_admin, survey_admin

PUT /survey/{surveyId}/close​

Close/deactivate a survey.

  • Auth: super_admin, survey_admin

POST /survey/{surveyId}/clone​

Clone an existing survey.

  • Auth: super_admin, survey_admin

GET /survey/{surveyId}/export​

Export a survey as a ZIP package.

  • Auth: super_admin, survey_admin

DELETE /survey/{surveyId}​

Delete a survey.

  • Auth: super_admin, survey_admin

Survey Design​

GET /survey/{surveyId}/design​

Get the current survey design (editor input + version metadata).

  • Auth: super_admin, survey_admin

POST /survey/{surveyId}/design​

Save/update the survey design.

  • Query: version
  • Body: survey design JSON
  • Auth: super_admin, survey_admin

POST /survey/{surveyId}/change_code​

Rename a question/component code throughout the design.

  • Query: from, to
  • Auth: super_admin, survey_admin

POST /survey/{surveyId}/design/publish​

Publish a survey design version.

  • Query: version, sub_version
  • Auth: super_admin, survey_admin

POST /survey/{surveyId}/offline/design​

Get design differences for offline sync (published version + new resources since the client's last-modified time).

  • Body: { version, subVersion, lastModified }
  • Auth: super_admin, survey_admin, surveyor

Survey Execution​

Survey run endpoints are public (no authentication required). The parallel preview endpoints require authentication and are used by admins to test surveys.

POST /survey/{surveyId}/run/start​

Start a survey session.

  • Body: { lang?, navigationMode?, values?, clientUTCTime? }
  • Auth: none

POST /survey/{surveyId}/run/navigate​

Navigate to the next/previous page or submit.

  • Body: { responseId, navigationDirection, values?, events?, clientUTCTime? }
  • Auth: none

GET /survey/{surveyId}/run/runtime.js​

Get the generated JavaScript state machine for client-side execution.

  • Auth: none

POST /survey/{surveyId}/preview/start​

Start a survey in preview mode.

  • Query: mode (optional: online | offline)
  • Body: { lang?, navigationMode?, values?, clientUTCTime? }
  • Auth: authenticated

POST /survey/{surveyId}/preview/navigate​

Navigate in preview mode.

  • Query: mode (optional)
  • Body: { responseId, navigationDirection, values?, events?, clientUTCTime? }
  • Auth: authenticated

GET /survey/{surveyId}/preview/runtime.js​

Get the runtime JavaScript for preview mode.

  • Auth: authenticated

Responses​

GET /response/{responseId}​

Get a single response with resolved, labelled values.

  • Auth: super_admin, survey_admin, analyst

GET /response_with_event/{responseId}​

Get a response together with its timeline events.

  • Auth: super_admin, survey_admin, analyst

GET /survey/{surveyId}/response/summary​

Get a paginated response summary for a survey.

  • Query: page, per_page, status (ALL | COMPLETE | INCOMPLETE | PREVIEW), surveyor, confirm_files_export
  • Auth: super_admin, survey_admin, analyst

GET /survey/{surveyId}/response/analytics​

Get aggregated analytics for survey responses.

  • Query: max_responses (optional)
  • Auth: super_admin, survey_admin, analyst

GET /survey/{surveyId}/response/export/{format}/{from}/{to}​

Export responses in a given format.

  • Path: format (CSV | EXCEL | JSON), from/to (response indices)
  • Query: complete, db_values
  • Auth: super_admin, survey_admin, analyst

GET /survey/{surveyId}/response/files/download/{from}/{to}​

Download response files as a ZIP archive.

  • Query: complete
  • Auth: super_admin, survey_admin, analyst

DELETE /survey/{surveyId}/response/{responseId}​

Delete a response.

  • Auth: super_admin, survey_admin

Response Files​

POST /survey/{surveyId}/response/attach/{responseId}/{questionId}​

Upload a file attachment to a response.

  • Body: multipart file
  • Auth: none

GET /survey/{surveyId}/response/attach/{responseId}/{questionId}​

Download a response file attachment.

  • Auth: none

GET /survey/{surveyId}/response/{responseId}/attach/{filename}​

Download a response file by filename (legacy path).

  • Auth: none

POST /survey/{surveyId}/response/preview/attach/{responseId}/{questionId}​

Upload a preview/test response file.

  • Body: multipart file
  • Auth: authenticated

Offline Sync​

POST /survey/{surveyId}/response/{responseId}/upload​

Upload a complete offline survey response.

  • Body: { versionId, lang, values?, startDate, submitDate, userId, navigationIndex, events? }
  • Auth: super_admin, survey_admin, surveyor

POST /survey/{surveyId}/offline/response/{responseId}/upload/{fileName}​

Upload a file from an offline response.

  • Body: multipart file
  • Auth: super_admin, survey_admin, surveyor

POST /survey/{surveyId}/offline/response/{responseId}/upload/{filename}/exists​

Check whether an offline response file has already been uploaded.

  • Auth: super_admin, survey_admin, surveyor

Survey Resources​

POST /survey/{surveyId}/resource​

Upload a resource file (images, media) for a survey.

  • Body: multipart file
  • Auth: super_admin, survey_admin

GET /survey/{surveyId}/resource/{fileName}​

Download a survey resource file (cached).

  • Auth: none

DELETE /survey/{surveyId}/resource/{fileName}​

Delete a survey resource file.

  • Auth: super_admin, survey_admin

Autocomplete​

GET /survey/{surveyId}/autocomplete/{filename}​

Search autocomplete values (respondent-facing).

  • Query: q (search term), limit (1–100, default 10)
  • Auth: none

GET /autocomplete/{surveyId}/{componentId}​

Get all autocomplete values for a question (design-time).

  • Auth: super_admin, survey_admin

POST /autocomplete/{surveyId}/{componentId}​

Upload autocomplete data for a question.

  • Body: multipart file
  • Auth: super_admin, survey_admin

Notes​

  • Dates are UTC wall-clock strings in yyyy-MM-dd HH:mm:ss format.
  • Survey ID in the path determines the survey context; the backend is single-tenant, so no tenant header is needed.
  • File uploads go through Multer with a per-request size limit.
  • Errors are shaped by a global exception filter; malformed or invalid bodies are rejected by a global validation pipe.