Survey Endpoints Index

Survey Endpoints

GET /api/surveys/aggregate

Get aggregated survey answers for all users for analytics and graphing (requires authentication and admin access)

Headers:

Authorization: Bearer ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqr...

Response (200 OK):

{
    "count": 5,
    "questions": [
        {
            "id": 1,
            "type": "MOPT",
            "name": "What LMW resources are you using? (Select all that apply.)",
            "sortOrder": 1,
            "totalResponses": 150,
            "options": [
                {
                    "id": 1,
                    "label": "Print Resources",
                    "value": "print_resources",
                    "sortOrder": 1,
                    "count": 85
                },
                {
                    "id": 2,
                    "label": "LMW App",
                    "value": "lmw_app",
                    "sortOrder": 2,
                    "count": 120
                },
                {
                    "id": 3,
                    "label": "Olive Tree",
                    "value": "olive_tree",
                    "sortOrder": 3,
                    "count": 45
                },
                {
                    "id": 10,
                    "label": "Other",
                    "value": "other",
                    "sortOrder": 10,
                    "count": 12
                }
            ]
        },
        {
            "id": 2,
            "type": "BOOL",
            "name": "Are you a first time user in the last 12 months?",
            "sortOrder": 2,
            "totalResponses": 150,
            "trueCount": 95,
            "falseCount": 55
        },
        {
            "id": 3,
            "type": "OPTI",
            "name": "How do you intend to use the material?",
            "sortOrder": 3,
            "totalResponses": 148,
            "options": [
                {
                    "id": 11,
                    "label": "Preach (I hold a formal role in the church)",
                    "value": "preach",
                    "sortOrder": 1,
                    "count": 62
                },
                {
                    "id": 12,
                    "label": "Teach (I teach in an informal capacity)",
                    "value": "teach",
                    "sortOrder": 2,
                    "count": 48
                },
                {
                    "id": 13,
                    "label": "Disciple (I am meeting 1 on 1 with others to help them grow)",
                    "value": "disciple",
                    "sortOrder": 3,
                    "count": 23
                },
                {
                    "id": 14,
                    "label": "Personal Use (I am using this resource for my own time of study)",
                    "value": "personal_use",
                    "sortOrder": 4,
                    "count": 15
                }
            ]
        }
    ]
}

Error Responses:

{
    "message": "User not authenticated"
}

{
    "message": "Administrator access required"
}

Notes:

  • Requires authentication token in the Authorization header
  • Requires administrator access (typeCode = "ADMI")
  • Returns aggregated survey data for all users who have answered survey questions
  • Only includes active questions (is_active = true)
  • Only the latest answer per user per question is used for aggregation - if a user has submitted multiple answers to the same question, only their most recent answer is included in the statistics
  • Questions are ordered by their sort_order value (ascending)
  • Each question includes different aggregation data based on its type:
  • For OPTI and MOPT (option-based questions):
    • options - Array of options with selection counts
    • count - Number of users who selected this specific option
    • For MOPT questions, users can select multiple options, so counts may sum to more than totalResponses
    • Options are ordered by their sort_order value (ascending)
  • For BOOL (yes/no questions):
    • trueCount - Number of users who answered "yes" (true, 1, yes)
    • falseCount - Number of users who answered "no" (false, 0, no)
  • For INTE, FLOA, CURR (numeric questions):
    • sum - Sum of all numeric responses
    • average - Average of all numeric responses
    • min - Minimum value provided
    • max - Maximum value provided
    • Invalid numeric values are filtered out before calculation
  • For TEXT, PARA, DATE (text/date questions):
    • Only totalResponses is provided (count of users who answered)
    • Individual text responses are not aggregated (use user-specific endpoint to see individual answers)
  • totalResponses - Total number of users who provided an answer to this question
  • This endpoint is designed for analytics dashboards and graphing visualization
  • All data is self-contained - no additional API calls needed to display graphs
GET /api/surveys/questions

Get all active survey questions with their options (requires authentication)

Headers:

Authorization: Bearer ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqr...

Response (200 OK):

{
    "count": 5,
    "questions": [
        {  
            "id": 1,
            "type": "MOPT",
            "name": "What LMW resources are you using? (Select all that apply.)",
            "sortOrder": 1,
            "isActive": true,
            "options": [
                {
                    "id": 1,
                    "label": "Print Resources",
                    "value": "print_resources",
                    "sortOrder": 1
                },
                {
                    "id": 2,
                    "label": "LMW App",
                    "value": "lmw_app",
                    "sortOrder": 2
                },
                {
                    "id": 3,
                    "label": "Olive Tree",
                    "value": "olive_tree",
                    "sortOrder": 3
                },
                {
                    "id": 4,
                    "label": "LOGOS",
                    "value": "logos",
                    "sortOrder": 4
                },
                {
                    "id": 5,
                    "label": "Accordance",
                    "value": "accordance",
                    "sortOrder": 5
                },
                {
                    "id": 6,
                    "label": "e-Sword",
                    "value": "esword",
                    "sortOrder": 6
                },
                {
                    "id": 7,
                    "label": "WD Bible",
                    "value": "wd_bible",
                    "sortOrder": 7
                },
                {
                    "id": 8,
                    "label": "YouVersion (Plans)",
                    "value": "youversion_plans",
                    "sortOrder": 8
                },
                {
                    "id": 9,
                    "label": "USB Flash Drive",
                    "value": "usb_flash_drive",
                    "sortOrder": 9
                },
                {
                    "id": 10,
                    "label": "Other",
                    "value": "other",
                    "sortOrder": 10
                }
            ]
        },
        {
            "id": 2,
            "type": "BOOL",
            "name": "Are you a first time user in the last 12 months?",
            "sortOrder": 2,
            "isActive": true,
            "options": []
        },
        {
            "id": 3,
            "type": "OPTI",
            "name": "How do you intend to use the material?",
            "sortOrder": 3,
            "isActive": true,
            "options": [
                {
                    "id": 11,
                    "label": "Preach (I hold a formal role in the church)",
                    "value": "preach",
                    "sortOrder": 1
                },
                {
                    "id": 12,
                    "label": "Teach (I teach in an informal capacity)",
                    "value": "teach",
                    "sortOrder": 2
                },
                {
                    "id": 13,
                    "label": "Disciple (I am meeting 1 on 1 with others to help them grow)",
                    "value": "disciple",
                    "sortOrder": 3
                },
                {
                    "id": 14,
                    "label": "Personal Use (I am using this resource for my own time of study)",
                    "value": "personal_use",
                    "sortOrder": 4
                }
            ]
        },
        {
            "id": 4,
            "type": "OPTI",
            "name": "What barriers are there for you in gaining access to theologically sound resources?",
            "sortOrder": 4,
            "isActive": true,
            "options": [
                {
                    "id": 15,
                    "label": "Accessibility (I do not have access to print or digital resources in my language)",
                    "value": "accessibility",
                    "sortOrder": 1
                },
                {
                    "id": 16,
                    "label": "Usability (I do not know how to access or use materials at my disposal)",
                    "value": "usability",
                    "sortOrder": 2
                },
                {
                    "id": 17,
                    "label": "None",
                    "value": "none",
                    "sortOrder": 3
                }
            ]
        },
        {
            "id": 5,
            "type": "OPTI",
            "name": "What level of training have you received, if any?",
            "sortOrder": 5,
            "isActive": true,
            "options": [
                {
                    "id": 18,
                    "label": "Formal (I have received seminary training from an accredited institution) (5% of pastors globally have received formal training).",
                    "value": "formal",
                    "sortOrder": 1
                },
                {
                    "id": 19,
                    "label": "Non-Formal (I have received skill-based training from a pastoral trainer or bible teacher, whether in person or online)",
                    "value": "non_formal",
                    "sortOrder": 2
                },
                {
                    "id": 20,
                    "label": "In-Formal (I have been discipled by a pastor or leader of an older age that has encouraged me in my personal walk)",
                    "value": "informal",
                    "sortOrder": 3
                },
                {
                    "id": 21,
                    "label": "None",
                    "value": "none_training",
                    "sortOrder": 4
                }
            ]
        }
    ]
}

Error Responses:

{
    "message": "User not authenticated"
}

Notes:

  • Requires authentication token in the Authorization header
  • Accessible to all authenticated users (no admin access required)
  • Returns only active survey questions (is_active = true)
  • Questions are ordered by their sort_order value (ascending)
  • Options within each question are ordered by their sort_order value (ascending)
  • Each question includes its type, sort order, and associated options
  • Question types available in the system:
    • TEXT - Text (short text input)
    • PARA - Paragraph (long text input)
    • INTE - Integer Number (whole number input)
    • FLOA - Real Number (decimal number input)
    • CURR - Currency (monetary value input)
    • DATE - Date (date input)
    • OPTI - Option (single-option selection from provided options)
    • MOPT - Multiple Options (multi-select from provided options)
    • BOOL - Yes/No (boolean toggle, no options needed)
  • Questions with type TEXT, PARA, INTE, FLOA, CURR, DATE, or BOOL will have an empty options array
  • Questions with type OPTI or MOPT will include options array with selectable choices
  • Use this endpoint to display survey forms to users
GET /api/surveys/users/:userId/answers

Get all survey answers for a specific user (requires authentication and admin access)

Headers:

Authorization: Bearer ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqr...

URL Parameters:

  • userId (required) - The ID of the user whose survey answers to retrieve

Response (200 OK):

{
    "userId": 123,
    "count": 5,
    "answers": [
        {
            "id": 1,
            "userId": 123,
            "surveyQuestionId": 1,
            "questionName": "What LMW resources are you using? (Select all that apply.)",
            "questionType": "MOPT",
            "value": "lmw_app,print_resources",
            "answeredAt": "2026-02-15T10:30:00.000Z",
            "options": [
                {
                    "id": 1,
                    "label": "Print Resources",
                    "value": "print_resources",
                    "sortOrder": 1
                },
                {
                    "id": 2,
                    "label": "LMW App",
                    "value": "lmw_app",
                    "sortOrder": 2
                },
                {
                    "id": 3,
                    "label": "Olive Tree",
                    "value": "olive_tree",
                    "sortOrder": 3
                },
                {
                    "id": 10,
                    "label": "Other",
                    "value": "other",
                    "sortOrder": 10
                }
            ]
        },
        {
            "id": 2,
            "userId": 123,
            "surveyQuestionId": 2,
            "questionName": "Are you a first time user in the last 12 months?",
            "questionType": "BOOL",
            "value": "true",
            "answeredAt": "2026-02-15T10:30:05.000Z"
        },
        {
            "id": 3,
            "userId": 123,
            "surveyQuestionId": 3,
            "questionName": "How do you intend to use the material?",
            "questionType": "OPTI",
            "value": "preach",
            "answeredAt": "2026-02-15T10:30:10.000Z",
            "options": [
                {
                    "id": 11,
                    "label": "Preach (I hold a formal role in the church)",
                    "value": "preach",
                    "sortOrder": 1
                },
                {
                    "id": 12,
                    "label": "Teach (I teach in an informal capacity)",
                    "value": "teach",
                    "sortOrder": 2
                },
                {
                    "id": 13,
                    "label": "Disciple (I am meeting 1 on 1 with others to help them grow)",
                    "value": "disciple",
                    "sortOrder": 3
                },
                {
                    "id": 14,
                    "label": "Personal Use (I am using this resource for my own time of study)",
                    "value": "personal_use",
                    "sortOrder": 4
                }
            ]
        },
        {
            "id": 4,
            "userId": 123,
            "surveyQuestionId": 4,
            "questionName": "What barriers are there for you in gaining access to theologically sound resources?",
            "questionType": "OPTI",
            "value": "accessibility",
            "answeredAt": "2026-02-15T10:30:15.000Z",
            "options": [
                {
                    "id": 15,
                    "label": "Accessibility (I do not have access to print or digital resources in my language)",
                    "value": "accessibility",
                    "sortOrder": 1
                },
                {
                    "id": 16,
                    "label": "Usability (I do not know how to access or use materials at my disposal)",
                    "value": "usability",
                    "sortOrder": 2
                },
                {
                    "id": 17,
                    "label": "None",
                    "value": "none",
                    "sortOrder": 3
                }
            ]
        },
        {
            "id": 5,
            "userId": 123,
            "surveyQuestionId": 5,
            "questionName": "What level of training have you received, if any?",
            "questionType": "OPTI",
            "value": "non_formal",
            "answeredAt": "2026-02-15T10:30:20.000Z",
            "options": [
                {
                    "id": 18,
                    "label": "Formal (I have received seminary training from an accredited institution) (5% of pastors globally have received formal training).",
                    "value": "formal",
                    "sortOrder": 1
                },
                {
                    "id": 19,
                    "label": "Non-Formal (I have received skill-based training from a pastoral trainer or bible teacher, whether in person or online)",
                    "value": "non_formal",
                    "sortOrder": 2
                },
                {
                    "id": 20,
                    "label": "In-Formal (I have been discipled by a pastor or leader of an older age that has encouraged me in my personal walk)",
                    "value": "informal",
                    "sortOrder": 3
                },
                {
                    "id": 21,
                    "label": "None",
                    "value": "none_training",
                    "sortOrder": 4
                }
            ]
        }
    ]
}

Error Responses:

{
    "message": "User not authenticated"
}

{
    "message": "Administrator access required"
}

{
    "message": "Invalid user ID"
}

Notes:

  • Requires authentication token in the Authorization header
  • Requires administrator access (typeCode = "ADMI")
  • Returns all survey answers for the specified user
  • Only includes answers to active questions (is_active = true)
  • Only the latest answer per question is returned - if a user has submitted multiple answers to the same question, only their most recent answer is included in the response
  • Answers are ordered by question sort_order (ascending)
  • Each answer includes the question name and type for context
  • Options are included with each answer (if the question has options) so the frontend can display them without additional API calls:
    • Questions with type OPTI or MOPT will include an options array
    • Questions with type TEXT, PARA, INTE, FLOA, CURR, DATE, or BOOL will not have an options field
    • Options are ordered by their sort_order value (ascending)
  • Answer value format depends on question type:
    • TEXT, PARA - User's text response as a string
    • INTE, FLOA, CURR - Numeric value as a string
    • DATE - Date value as a string (ISO format)
    • BOOL - "true" or "false" as a string
    • OPTI - The selected option's value (e.g., "preach", "formal")
    • MOPT - Comma-separated list of selected option values (e.g., "lmw_app,print_resources")
  • Returns an empty array if the user has no survey answers
POST /api/surveys/answers

Submit survey answers for the authenticated user (requires authentication)

Headers:

Authorization: Bearer ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqr...

Request Body:

{
    "answers": [
        {
            "questionId": 1,
            "value": "lmw_app,print_resources"
        },
        {
            "questionId": 2,
            "value": "true"
        },
        {
            "questionId": 3,
            "value": "preach"
        }
    ]
}

Response (201 Created):

{
    "message": "Survey answers submitted successfully",
    "count": 3,
    "answers": [
        {
            "id": 1,
            "userId": 123,
            "surveyQuestionId": 1,
            "questionName": "",
            "questionType": "",
            "value": "lmw_app,print_resources",
            "answeredAt": "2026-02-20T10:30:00.000Z"
        },
        {
            "id": 2,
            "userId": 123,
            "surveyQuestionId": 2,
            "questionName": "",
            "questionType": "",
            "value": "true",
            "answeredAt": "2026-02-20T10:30:00.000Z"
        },
        {
            "id": 3,
            "userId": 123,
            "surveyQuestionId": 3,
            "questionName": "",
            "questionType": "",
            "value": "preach",
            "answeredAt": "2026-02-20T10:30:00.000Z"
        }
    ]
}

Error Responses:

{
    "message": "User not authenticated"
}

{
    "message": "Invalid request body. Expected 'answers' array"
}

{
    "message": "No answers provided"
}

{
    "message": "Invalid questionId at index 0. Expected a number"
}

{
    "message": "Missing value at index 0"
}

{
    "message": "Invalid or inactive question ID: 999"
}

{
    "message": "Empty value provided for question ID: 1"
}

Notes:

  • Requires authentication token in the Authorization header
  • Accessible to all authenticated users (no admin access required)
  • The userId is automatically extracted from the authenticated user's session
  • Request body must include an answers array with at least one answer
  • Each answer object requires:
    • questionId (number) - The ID of the survey question being answered
    • value (string) - The answer value
  • Answer value format depends on question type:
    • TEXT, PARA - User's text response as a string
    • INTE, FLOA, CURR - Numeric value as a string (e.g., "42", "3.14", "99.99")
    • DATE - Date value as a string in ISO format (e.g., "2026-02-20")
    • BOOL - "true" or "false" as a string
    • OPTI - The selected option's value (e.g., "preach", "formal")
    • MOPT - Comma-separated list of selected option values (e.g., "lmw_app,print_resources")
  • All question IDs must be valid and refer to active questions
  • Empty or null values are not allowed
  • The answeredAt timestamp is automatically set to the current time
  • Answers are inserted as new records (this endpoint does not update existing answers)
  • All answers are submitted in a single database transaction for consistency
  • If any validation fails, none of the answers will be saved
  • Use the GET /api/surveys/questions endpoint to retrieve available questions and their types before submitting answers