/api/keys
All index, meta, and response field keys with metadata. Includes offeringKey and offeringLabel under meta. See Common commands above.
Lead Quote Questionnaire
REST API Reference
HTTP JSON API for listing, retrieving, saving, and deleting questionnaires.
All API routes require either a signed-in browser session (cookie) or an API key configured on the Admin page.
X-API-Key header or as Authorization: Bearer <key>.Set these once in your terminal to simplify the examples below:
export API_BASE="https://questionnaire.jkseva.com" export API_KEY="your-api-key-from-admin-page"
Every curl example below assumes API_BASE and API_KEY are set. Examples use jq to format JSON output.
These three requests cover the most frequent integration workflow: discover available fields, list saved questionnaires, then read responses for one record.
Returns index keys (representative, customerName, questionnaireName), meta keys (offeringKey, offeringLabel), and every response key for a template. Pass templateId to target a specific template; otherwise the default migrated template is used.
curl -s "$API_BASE/api/keys?templateId=TEMPLATE_ID" \ -H "X-API-Key: $API_KEY" | jq '.keyNames'
[ "representative", "customerName", "questionnaireName", "offeringKey", "offeringLabel", "CI-01", "CI-02", "CI-03", "...", "CI-25" ]
The full /api/keys response also includes a meta array describing offering fields and templateOffering with the template’s default offering when templateId is provided.
Returns a summary row for each saved questionnaire, including offeringKey and offeringLabel. Use the id from this response in the next step.
curl -s "$API_BASE/api/questionnaires" \ -H "X-API-Key: $API_KEY" | jq .
{
"questionnaires": [
{
"id": "da4c0344-a3ac-4228-bd4b-7fa397e62fb5",
"representative": "tkastle",
"customerName": "JK Seva",
"questionnaireName": "Test 1",
"offeringKey": "general_discovery",
"offeringLabel": "General Discovery",
"status": "complete",
"createdBy": "tkastle",
"createdAtPST": "2026-08-11 02:12:11 PDT",
"updatedAtPST": "2026-08-11 08:56:41 PDT",
"updatedAt": "2026-08-11T15:56:41.966Z"
}
]
}
Replace QUESTIONNAIRE_ID with the id from step 2. Offering values are in questionnaire.meta.
export QUESTIONNAIRE_ID="da4c0344-a3ac-4228-bd4b-7fa397e62fb5"
curl -s "$API_BASE/api/questionnaires/$QUESTIONNAIRE_ID" \
-H "X-API-Key: $API_KEY" | jq '.questionnaire.meta | {offeringKey, offeringLabel, status}'
curl -s "$API_BASE/api/questionnaires/$QUESTIONNAIRE_ID" \ -H "X-API-Key: $API_KEY" | jq '.questionnaire.responses'
{
"CI-01": "JK Seva inc.",
"CI-02": "Technical",
"CI-03": "10000",
"CI-04": "Contract / License termination",
"CI-05": "Today",
"CI-06": [
"Workforce Central",
"TeleStaff"
],
"CI-07": "",
"CI-08": "HR, Payroll",
"CI-09": "Jan 2023 - present",
"CI-10": "All Employees",
"...": "..."
}
Checkbox answers (e.g. CI-06) are returned as JSON arrays. Text and select answers are strings. Unanswered questions may be omitted or returned as an empty string.
Templates define questionnaire structure. Instances reference a template via meta.templateId. Each template has an offeringKey and offeringLabel used as the default for new questionnaires and customer communications.
Common values: general_discovery (default), infor_solutions, ukg_solutions, data_migration, managed_services, hosting_services, custom_solutions, on_demand_support, other (requires customOffering text).
curl -s "$API_BASE/api/templates" \
-H "X-API-Key: $API_KEY" | jq '.templates[] | {id, name, status, offeringKey, offeringLabel, questionCount}'
curl -s "$API_BASE/api/templates/active" \ -H "X-API-Key: $API_KEY" | jq .
curl -s "$API_BASE/api/templates/TEMPLATE_ID" \ -H "X-API-Key: $API_KEY" | jq .
# Create blank template
curl -s -X POST "$API_BASE/api/templates" \
-H "Content-Type: application/json" \
-H "X-API-Key: $API_KEY" \
-d '{"name":"Custom Discovery","offeringKey":"general_discovery"}' | jq .
# Clone existing template
curl -s -X POST "$API_BASE/api/templates/TEMPLATE_ID/clone" \
-H "X-API-Key: $API_KEY" | jq .
# Download CSV import template
curl -s "$API_BASE/api/templates/csv-template" \
-H "X-API-Key: $API_KEY" -o questionnaire-template.csv
# Import template from CSV (optional offeringKey; defaults to general_discovery)
curl -s -X POST "$API_BASE/api/templates/import-csv" \
-H "X-API-Key: $API_KEY" \
-F "file=@questionnaire-template.csv" \
-F "name=My Imported Template" \
-F "offeringKey=managed_services" | jq .
# Import with JSON body (csv text + offering)
curl -s -X POST "$API_BASE/api/templates/import-csv" \
-H "X-API-Key: $API_KEY" \
-H "Content-Type: application/json" \
-d '{"name":"Imported Template","offeringKey":"general_discovery","csv":"section,sectionId,key,label,type\n..."}' | jq .
# Archive / unarchive
curl -s -X PUT "$API_BASE/api/templates/TEMPLATE_ID/archive" \
-H "X-API-Key: $API_KEY" | jq .
curl -s -X PUT "$API_BASE/api/templates/TEMPLATE_ID/unarchive" \
-H "X-API-Key: $API_KEY" | jq .
Locked templates (already used) return HTTP 403 on update with message: “This template has already been used and cannot be modified. Please clone it instead.”
CSV files contain question rows only. Offering is template metadata — set offeringKey (and customOffering when other) on import, or edit the template after import.
Includes labels, types, and section names for each key — useful when building integrations or reports.
curl -s "$API_BASE/api/keys" \ -H "X-API-Key: $API_KEY" | jq .
curl -s "$API_BASE/api/questionnaires" \ -H "X-API-Key: $API_KEY" | jq '.questionnaires[].id'
curl -s "$API_BASE/api/questionnaires/$QUESTIONNAIRE_ID" \ -H "X-API-Key: $API_KEY" | jq '.questionnaire.index'
{
"representative": "tkastle",
"customerName": "JK Seva",
"questionnaireName": "Test 1"
}
curl -s "$API_BASE/api/questionnaires/$QUESTIONNAIRE_ID" \
-H "X-API-Key: $API_KEY" | jq '.questionnaire.meta | {offeringKey, offeringLabel, customOffering, templateId, status}'
Returns id, index, meta, and responses.
curl -s "$API_BASE/api/questionnaires/$QUESTIONNAIRE_ID" \ -H "X-API-Key: $API_KEY" | jq '.questionnaire'
curl -s "$API_BASE/api/questionnaires/$QUESTIONNAIRE_ID" \ -H "X-API-Key: $API_KEY" | jq '.questionnaire.responses["CI-03"]'
When using an API key, include index.representative and templateId in the request body.
curl -s -X POST "$API_BASE/api/questionnaires" \
-H "Content-Type: application/json" \
-H "X-API-Key: $API_KEY" \
-d '{
"templateId": "TEMPLATE_ID",
"index": {
"representative": "jsmith",
"customerName": "Acme Corp",
"questionnaireName": "Initial Discovery"
},
"meta": {
"offeringKey": "managed_services"
},
"responses": {
"CI-01": "Acme Corporation",
"CI-03": "1,500 active employees"
},
"status": "draft",
"currentStep": 2
}' | jq .
Include the questionnaire id to update in place.
curl -s -X POST "$API_BASE/api/questionnaires" \
-H "Content-Type: application/json" \
-H "X-API-Key: $API_KEY" \
-d '{
"id": "'"$QUESTIONNAIRE_ID"'",
"index": {
"representative": "tkastle",
"customerName": "JK Seva",
"questionnaireName": "Test 1"
},
"responses": {
"CI-03": "12000"
},
"status": "draft",
"currentStep": 4
}' | jq .
curl -s -X POST "$API_BASE/api/questionnaires" \
-H "Content-Type: application/json" \
-H "X-API-Key: $API_KEY" \
-d '{
"id": "'"$QUESTIONNAIRE_ID"'",
"index": {
"representative": "tkastle",
"customerName": "JK Seva",
"questionnaireName": "Test 1"
},
"responses": {},
"status": "complete"
}' | jq '.questionnaire.meta.status'
curl -s -X DELETE "$API_BASE/api/questionnaires/$QUESTIONNAIRE_ID" \ -H "X-API-Key: $API_KEY" | jq .
Base URL: https://questionnaire.jkseva.com/api
/api/keys
All index, meta, and response field keys with metadata. Includes offeringKey and offeringLabel under meta. See Common commands above.
/api/questionnaires
List all saved questionnaires (summary: id, representative, customer, name, offering, status, timestamps).
/api/questionnaires/:id
Retrieve one questionnaire with full index, meta (including offering fields), and responses.
/api/questionnaires
Create or update a questionnaire. Omit id to create; include id to update.
{
"id": "optional-uuid-for-update",
"index": {
"representative": "jsmith",
"customerName": "Acme Corp",
"questionnaireName": "Initial Discovery"
},
"responses": {
"CI-01": "Answer text…",
"CI-06": ["Option A", "Option B"]
},
"meta": {
"offeringKey": "general_discovery",
"customOffering": null
},
"status": "draft",
"currentStep": 3
}
When using a browser session, index.representative is set automatically from the signed-in user.
/api/questionnaires/:id
Delete a questionnaire. API key access can delete any record.
Authenticated routes for creating and managing customer review links. Requires session cookie or API key.
/api/questionnaires/:id/send-info
Returns questionnaire summary, resolved offeringLabel, subject options (with {{offering}} tokens), default email template, and send/open stats for the send form.
/api/questionnaires/:id/send
Create a customer access link and send email. Body: customerFirstName, customerLastName, customerEmail, subject, emailBody. Subject options and the default body support {{offering}}, resolved from the questionnaire (or its template). On success, the response includes emailSent and representativeNotified. When the customer email is sent, the questionnaire representative also receives a confirmation email (subject prefix [JKS Questionnaire]) with questionnaire details, next steps, the customer link, and a link to review responses.
curl -s -X POST "$API_BASE/api/questionnaires/$QUESTIONNAIRE_ID/send" \
-H "X-API-Key: $API_KEY" \
-H "Content-Type: application/json" \
-d '{
"customerFirstName": "Jane",
"customerLastName": "Doe",
"customerEmail": "jane@example.com",
"subject": "JK Seva – Please Review & Complete Your {{offering}} Questionnaire",
"emailBody": "Dear {{customerName}} Team,\n\nThank you for meeting with us. {{representative}} captured your {{offering}} requirements under \"{{questionnaireName}}\".\n\n{{formLink}}"
}' | jq .
/api/questionnaires/share
Email a completed questionnaire as an attachment. Body: questionnaireId, to, subject, message, format (html, txt, md, or json). Only questionnaires with status complete may be shared. The attachment is generated server-side. Returns { ok: true } on success. Failures return a generic error message.
curl -s -X POST "$API_BASE/api/questionnaires/share" \
-H "X-API-Key: $API_KEY" \
-H "Content-Type: application/json" \
-d '{
"questionnaireId": "'"$QUESTIONNAIRE_ID"'",
"to": "recipient@example.com",
"subject": "Completed questionnaire for review",
"message": "Please find the completed questionnaire attached.",
"format": "html"
}' | jq .
/api/customer-links/:token/{complete|revoke|reactivate}
Update link status. Sender or admin only.
/api/customer-links/:token
Permanently delete a customer access link. Sender or admin only.
No authentication required. Token in URL grants access while the link is active.
/api/customer/q/:token
Load questionnaire for customer review. Increments open count. Returns inactive: true when completed or revoked.
/api/customer/q/:token
Save customer responses. Body: { "responses": { "CI-01": "…" } }
/api/admin/customer-links
List all customer access links with tracking metadata.
/api/admin/smtp
Read SMTP settings (password masked).
/api/admin/smtp
Save SMTP host, port, credentials, from address, and TLS preference.
/api/admin/smtp/test
Test SMTP connection and authentication. Returns a detailed debug log (password never included).
Errors return JSON with an error message and an HTTP status code.
curl -s "$API_BASE/api/questionnaires/not-a-real-id" \ -H "X-API-Key: $API_KEY" | jq .
{ "error": "Questionnaire not found" }