Happily.ai Get an API key

Pull survey analytics

Export your survey questions and the responses members submit, then load them into your warehouse or BI tool.

List questions

GET /questions

Returns the questions available to your company (your custom questions plus shared "main" questions). Filter by type, skill, or dimension.

Filter Values
type Question type, for example Multiple Choice.
skill Critical Thinking, Empathy, Initiative Making, Leadership, Self Awareness, Optimism.
dimension A question category/dimension name.
curl "https://api.happily.ai/prod/1/questions?skill=Empathy&limit=250" \
  -H "x-api-key: $HAPPILY_API_KEY"
{
  "statusCode": 200,
  "message": "success",
  "questions": [
    {
      "question_id": "q_abc123",
      "question_text": "How supported did you feel this week?",
      "type": "Multiple Choice",
      "options": ["Not at all", "A little", "Mostly", "Completely"],
      "skill": "Empathy",
      "dimension": "Belonging"
    }
  ],
  "pagination": { "currentPage": 1, "totalPages": 1, "totalItems": 1, "pageSize": 250 }
}

List responses

GET /responses

Filter by email, question_id, or both (at least one is required). Bound by date with date_from and date_to (YYYY-MM-DD).

curl "https://api.happily.ai/prod/1/responses?question_id=q_abc123&date_from=2026-01-01&date_to=2026-06-30&limit=250" \
  -H "x-api-key: $HAPPILY_API_KEY"
{
  "statusCode": 200,
  "message": "success",
  "responses": [
    {
      "email": "jordan@acme.com",
      "question_id": "q_abc123",
      "question_text": "How supported did you feel this week?",
      "answer": "Mostly",
      "date": "2026-06-03"
    }
  ],
  "pagination": { "currentPage": 1, "totalPages": 1, "totalItems": 1, "pageSize": 250 }
}

Export everything to a CSV

This script pages through every response for a question and writes a CSV, pacing within the pagination limits.

import os, csv, requests

API = "https://api.happily.ai/prod/1"
HEADERS = {"x-api-key": os.environ["HAPPILY_API_KEY"]}

def responses_for_question(question_id, date_from, date_to):
    page = 1
    while True:
        res = requests.get(f"{API}/responses", headers=HEADERS, params={
            "question_id": question_id,
            "date_from": date_from,
            "date_to": date_to,
            "page": page,
            "limit": 250,
        })
        body = res.json()
        yield from body.get("responses", [])
        if page >= body["pagination"]["totalPages"]:
            break
        page += 1

with open("responses.csv", "w", newline="") as f:
    writer = csv.DictWriter(f, fieldnames=["email", "question_id", "question_text", "answer", "date"])
    writer.writeheader()
    for row in responses_for_question("q_abc123", "2026-01-01", "2026-06-30"):
        writer.writerow(row)
const API = "https://api.happily.ai/prod/1";
const headers = { "x-api-key": process.env.HAPPILY_API_KEY };

async function* responsesForQuestion(questionId, dateFrom, dateTo) {
  let page = 1;
  while (true) {
    const url = new URL(`${API}/responses`);
    url.search = new URLSearchParams({ question_id: questionId, date_from: dateFrom, date_to: dateTo, page, limit: 250 });
    const body = await (await fetch(url, { headers })).json();
    for (const row of body.responses ?? []) yield row;
    if (page >= body.pagination.totalPages) break;
    page++;
  }
}

for await (const row of responsesForQuestion("q_abc123", "2026-01-01", "2026-06-30")) {
  console.log(row.email, row.answer, row.date);
}
Tip

Use limit=250 for exports and schedule a nightly job to incrementally pull the previous day's responses with date_from/date_to.

Member engagement profiles

For richer analytics on a single person, fetch their engagement profile:

GET /api/v1/users/{email}/profile

It returns impact_rating, engagement_health_score (0–100), an engagement_health_status (Novice, Intermediate, Advanced, Elite), and optional personal_context. Set include_personal_context=false to omit the context block, or context_limit (1–50) to cap each list.

Next steps