# HumanSurvey > Feedback collection infrastructure for AI agents. An agent working on a long-horizon task creates a survey from JSON schema, shares the URL with a group of people, and retrieves structured results when ready. ## What HumanSurvey is NOT HumanSurvey does not provide: survey dashboards, visual form builders, email campaigns, analytics/reporting UI, template libraries, or human-in-the-loop decision gates for single users. If a feature mainly serves human survey operators, it is out of scope. ## Typical agent scenarios - **Post-event feedback** — event management agent creates an attendee satisfaction survey after the event ends, collects responses over 48 hours, summarizes results for the organizer - **Product launch survey** — product agent sends a feedback survey to users after a feature ships, aggregates NPS and open-ended responses - **Team pulse** — HR or team agent runs a periodic health check survey across a team, tracks trends over time - **Post-resolution CSAT** — customer success agent triggers a satisfaction survey when a support ticket closes ## Core Flow ``` Agent is doing a long-horizon job → decides it needs structured feedback from a group → POST /api/keys # one-time setup, save the key → POST /api/surveys # create survey from JSON schema → share /s/{id} with the target group (email, Slack, in-product, etc.) → GET /api/surveys/{id}/responses # check results over hours or days → PATCH /api/surveys/{id} # close when done → act on the structured results ``` The survey ID is extracted from the `survey_url` field in the create response (e.g. `/s/abc123` → ID is `abc123`). ## Authentication Creator endpoints require: `Authorization: Bearer hs_sk_...` Public endpoints: - `GET /api/surveys/{id}` - `POST /api/surveys/{id}/responses` - `/s/{id}` ## Markdown Syntax ### Choice ```markdown **Q1. Which area needs the most attention?** - ☐ Onboarding - ☐ Performance - ☐ Reporting ``` ### Multi-choice ```markdown **Q2. Which constraints apply?** (select all that apply) - ☐ Budget - ☐ Time - ☐ Access ``` ### Text ```markdown **Q3. What should we never change without review?** > _______________________________________________ ``` ### Scale ```markdown **Q4. How likely are you to recommend us?** [scale 0-10] **Q5. Rate onboarding difficulty** [scale 1-5 min-label="Very hard" max-label="Very easy"] ``` ### Matrix ```markdown | # | Item | Rating | |---|------|--------| | 1 | Onboarding | ☐Good ☐OK ☐Bad | | 2 | Support | ☐Good ☐OK ☐Bad | ``` ### Conditional Logic ```markdown **Q1. Have you used the product before?** - ☐ Yes - ☐ No **Q2. How satisfied are you?** > show if: Q1 = "Yes" [scale 1-5] ``` Supported operators: - `show if: Q1 = "Yes"` - `show if: Q1 != "No"` - `show if: Q2 contains "Other"` - `show if: Q3 answered` ## JSON Schema Input ```json { "schema": { "title": "Product Feedback", "sections": [ { "title": "Core", "questions": [ { "type": "single_choice", "label": "What is your primary use case?", "required": true, "options": [ { "label": "Work" }, { "label": "Personal" } ] }, { "type": "scale", "label": "How satisfied are you overall?", "required": true, "min": 1, "max": 5, "showIf": { "questionId": "q_0", "operator": "eq", "value": "Work" } } ] } ] } } ``` ## API Reference ### `POST /api/keys` - No auth required - Request: `{ "name": "my-agent" }` (name is optional) - Response 201: `{ "id": "abc123", "key": "hs_sk_...", "name": "my-agent", "created_at": "..." }` - **Save the key value — it is shown only once** ### `GET /api/keys` - Auth required - Returns metadata (id, name, created_at) for the current key — key value is not returned ### `DELETE /api/keys/{id}` - Auth required - Revokes the current key. Surveys remain but key can no longer call creator endpoints. ### `POST /api/surveys` - Auth required - Request body: `{ "schema": { ... }, "max_responses": 50, "expires_at": "2026-04-14T00:00:00Z", "webhook_url": "https://..." }` - `schema` is required. `max_responses`, `expires_at`, and `webhook_url` are optional. - `webhook_url`: if set, receives a POST request once when the survey closes. Payload: `{ "survey_id", "status": "closed", "closed_reason": "manual" | "max_responses", "response_count", "closed_at" }`. Fires for manual close (PATCH status=closed) and max_responses limit reached. Does NOT fire when expires_at elapses. - Response 201: `{ "survey_url": "/s/abc123", "question_count": 3 }` - Error 400: `{ "error": "schema is required" }` or `{ "error": "Invalid schema", "errors": ["..."] }` ### `GET /api/surveys` - Auth required - Returns array of surveys owned by the current key, newest first - Each item: `{ "id", "title", "status", "response_count", "max_responses", "expires_at", "created_at" }` ### `GET /api/surveys/{id}` - **Public** — no auth required - Returns survey metadata, full schema, response count, status, lifecycle fields - status is `"open"` or `"closed"` ### `PATCH /api/surveys/{id}` - Auth required, must own the survey - Update any subset of: `{ "status": "closed", "max_responses": 100, "expires_at": "..." }` - Response 200: `{ "id", "status", "max_responses", "expires_at" }` ### `POST /api/surveys/{id}/responses` - **Public** — no auth required - Request: `{ "answers": { "q_0": "opt_1", "q_1": ["opt_0", "opt_2"], "q_2": 4, "q_3": "free text" } }` - Answer value types by question type: - `single_choice` → option ID string (e.g. `"opt_0"`) - `multi_choice` → array of option ID strings (e.g. `["opt_0", "opt_2"]`) - `scale` → number within the defined range (e.g. `4`) - `text` → string - Response 201: `{ "id": "responseId" }` - Error 410: `{ "error": "This survey is closed" }` / `"...expired"` / `"...full"` ### `GET /api/surveys/{id}/responses` - Auth required, must own the survey - Returns: - `count`: total response count - `questions`: pre-aggregated results per question (see below) - `raw`: array of individual responses #### Aggregated question shapes **single_choice / multi_choice:** ```json { "id": "q_0", "type": "single_choice", "label": "...", "options": [...], "tally": { "opt_0": 3, "opt_1": 1 } } ``` **scale:** ```json { "id": "q_1", "type": "scale", "label": "...", "min": 1, "max": 5, "stats": { "count": 4, "mean": 3.5, "median": 4, "distribution": { "1": 0, "2": 1, "3": 1, "4": 1, "5": 1 } } } ``` **text:** ```json { "id": "q_2", "type": "text", "label": "...", "responses": [{ "value": "...", "created_at": "..." }] } ``` **matrix:** ```json { "id": "q_3", "type": "matrix", "label": "...", "rows": [...], "columns": [...], "tally": { "row_0": { "opt_0": 2, "opt_1": 1 } } } ``` ## MCP Tools ### `create_survey` - Input: `{ markdown }` or `{ schema }` - Output: survey URL, survey ID, question count ### `get_results` - Input: `{ survey_id }` - Output: human-readable summary with choice tallies, scale mean/median, recent text responses ### `list_surveys` - Output: table of survey IDs, titles, status, responses, created date ### `close_survey` - Input: `{ survey_id }` - Output: confirmation with total response count ## Discoverability - Site docs: https://www.humansurvey.co/docs - OpenAPI: https://www.humansurvey.co/api/openapi.json - llms.txt: https://www.humansurvey.co/llms.txt