> For the complete documentation index, see [llms.txt](https://boundaryai.gitbook.io/boundaryai-docs/llms.txt). Markdown versions of documentation pages are available by appending `.md` to page URLs; this page is available as [Markdown](https://boundaryai.gitbook.io/boundaryai-docs/api-and-webhooks/input-api.md).

# Input API

Bring feedback into BAI Analytics programmatically with an Input API key. Create feedback groups and data sources, publish them, and push feedback text to questions for analysis.

## Push feedback text to a question

> Push feedback text to a specific question — the primary endpoint for importing data. Each string in \`content\` becomes one piece of feedback attached to the question. Pushing to a published data source consumes Analysis Points (APS).

```json
{"openapi":"3.1.0","info":{"title":"BAI Analytics API","version":"1.0.0"},"tags":[{"name":"InputAPI","description":"Bring feedback into BAI Analytics programmatically with an Input API key. Create feedback groups and data sources, publish them, and push feedback text to questions for analysis."}],"servers":[{"url":"https://app.boundary-ai.com","description":"Production"}],"security":[{"apiKeyAuth":[]}],"components":{"securitySchemes":{"apiKeyAuth":{"type":"http","scheme":"bearer","bearerFormat":"BoundaryAI API key","description":"Input API key. Format `inpk_{env}_{key_id}_{secret}` — send as `Authorization: Bearer <key>`. Create keys under Integrations → API; `test` keys are not charged Analysis Points."}},"schemas":{"ContentPushRequest":{"properties":{"survey_series_id":{"description":"Target survey series id","title":"Survey Series Id","type":"string"},"survey_id":{"description":"Target survey id within the series","title":"Survey Id","type":"string"},"question":{"$ref":"#/components/schemas/QuestionContentPush"},"source_reference":{"anyOf":[{"maxLength":255,"type":"string"},{"type":"null"}],"default":null,"description":"Free-form identifier the customer attaches to the push for their own downstream tracking (e.g. an upstream ticket id).","title":"Source Reference"}},"required":["survey_series_id","survey_id","question"],"title":"ContentPushRequest","type":"object"},"QuestionContentPush":{"properties":{"question_id":{"description":"Target question id (integer as string)","title":"Question Id","type":"string"},"content":{"description":"Free-text responses, one per array entry","items":{"type":"string"},"minItems":1,"title":"Content","type":"array"}},"required":["question_id","content"],"title":"QuestionContentPush","type":"object"},"ContentPushResponse":{"description":"Success body of POST /api/input/content/push.","properties":{"status":{"const":"success","description":"Always 'success' on this path","title":"Status","type":"string"},"survey_id":{"description":"Resolved survey id where content landed","title":"Survey Id","type":"integer"},"question_id":{"description":"Resolved question id where content landed","title":"Question Id","type":"integer"},"inserted":{"description":"Number of content rows inserted","minimum":0,"title":"Inserted","type":"integer"},"aps_deducted":{"description":"APS units deducted from the org's quota","minimum":0,"title":"Aps Deducted","type":"integer"},"message":{"anyOf":[{"type":"string"},{"type":"null"}],"default":null,"description":"Human-readable confirmation","title":"Message"}},"required":["status","survey_id","question_id","inserted","aps_deducted"],"title":"ContentPushResponse","type":"object"},"ErrorEnvelope":{"description":"Top-level error response.\n\nSchema name in the OpenAPI document: ``ErrorEnvelope``.","properties":{"error":{"$ref":"#/components/schemas/ErrorObject"},"details":{"anyOf":[{},{"type":"null"}],"default":null,"description":"Optional structured details (e.g. validation field map)","title":"Details"}},"required":["error"],"title":"ErrorEnvelope","type":"object"},"ErrorObject":{"description":"The inner ``error`` field of an error envelope.\n\nSchema name in the OpenAPI document: ``ErrorObject``.","properties":{"code":{"description":"Machine-readable error code drawn from ErrorCode enum","title":"Code","type":"string"},"message":{"description":"Human-readable error message, safe to display","title":"Message","type":"string"}},"required":["code","message"],"title":"ErrorObject","type":"object"}},"responses":{"RateLimited":{"description":"Rate limit exceeded — see Retry-After header.","headers":{"Retry-After":{"$ref":"#/components/headers/RetryAfter"},"X-RateLimit-Limit":{"$ref":"#/components/headers/XRateLimitLimit"},"X-RateLimit-Remaining":{"$ref":"#/components/headers/XRateLimitRemaining"},"X-RateLimit-Reset":{"$ref":"#/components/headers/XRateLimitReset"}},"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}}}},"headers":{"RetryAfter":{"description":"Seconds to wait before retrying. Emitted on 429 and on 503 responses from the global rate limiter. See ``src/utils/middleware/rate_limiting.py``.","schema":{"type":"integer","minimum":1}},"XRateLimitLimit":{"description":"Total requests allowed in the current rate-limit window.","schema":{"type":"integer","minimum":1}},"XRateLimitRemaining":{"description":"Requests remaining in the current rate-limit window.","schema":{"type":"integer","minimum":0}},"XRateLimitReset":{"description":"Unix timestamp when the rate-limit window resets.","schema":{"type":"integer","minimum":0}}}},"paths":{"/api/input/content/push":{"post":{"summary":"Push feedback text to a question","description":"Push feedback text to a specific question — the primary endpoint for importing data. Each string in `content` becomes one piece of feedback attached to the question. Pushing to a published data source consumes Analysis Points (APS).","tags":["InputAPI"],"operationId":"inputapi_post_content_push","parameters":[{"name":"Idempotency-Key","in":"header","required":false,"schema":{"type":"string","maxLength":255},"description":"Opaque client-supplied key for safe retries (24h window)."}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ContentPushRequest"}}}},"responses":{"200":{"description":"Success","content":{"application/json":{"schema":{"type":"object","properties":{"data":{"$ref":"#/components/schemas/ContentPushResponse"}},"required":["data"]}}}},"400":{"description":"Bad Request — validation failed","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}}},"401":{"description":"Unauthorized — missing or invalid credentials","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}}},"402":{"description":"Payment Required — insufficient credits / APS","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}}},"403":{"description":"Forbidden — insufficient permission","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}}},"404":{"description":"Not Found","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}}},"409":{"description":"Conflict (idempotency key reuse or resource conflict)","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}}},"429":{"$ref":"#/components/responses/RateLimited"},"500":{"description":"Internal Server Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}}}}}}}}
```

## Push feedback to multiple questions

> Push feedback text to several questions in a single request. Returns a task id you can poll for completion.

```json
{"openapi":"3.1.0","info":{"title":"BAI Analytics API","version":"1.0.0"},"tags":[{"name":"InputAPI","description":"Bring feedback into BAI Analytics programmatically with an Input API key. Create feedback groups and data sources, publish them, and push feedback text to questions for analysis."}],"servers":[{"url":"https://app.boundary-ai.com","description":"Production"}],"security":[{"apiKeyAuth":[]}],"components":{"securitySchemes":{"apiKeyAuth":{"type":"http","scheme":"bearer","bearerFormat":"BoundaryAI API key","description":"Input API key. Format `inpk_{env}_{key_id}_{secret}` — send as `Authorization: Bearer <key>`. Create keys under Integrations → API; `test` keys are not charged Analysis Points."}},"schemas":{"BulkContentPushRequest":{"properties":{"survey_series_id":{"title":"Survey Series Id","type":"string"},"survey_id":{"title":"Survey Id","type":"string"},"questions":{"description":"Up to 100 question-content pairs in a single batch","items":{"$ref":"#/components/schemas/BulkQuestionContentPush"},"maxItems":100,"minItems":1,"title":"Questions","type":"array"},"source_reference":{"anyOf":[{"maxLength":255,"type":"string"},{"type":"null"}],"default":null,"title":"Source Reference"}},"required":["survey_series_id","survey_id","questions"],"title":"BulkContentPushRequest","type":"object"},"BulkQuestionContentPush":{"properties":{"question_id":{"description":"Target question id","title":"Question Id","type":"string"},"content":{"description":"Free-text responses","items":{"type":"string"},"minItems":1,"title":"Content","type":"array"}},"required":["question_id","content"],"title":"BulkQuestionContentPush","type":"object"},"BulkPushAccepted":{"description":"202 body of POST /api/input/content/push/bulk.","properties":{"status":{"const":"accepted","title":"Status","type":"string"},"task_id":{"title":"Task Id","type":"string"},"survey_series_id":{"title":"Survey Series Id","type":"integer"},"survey_id":{"title":"Survey Id","type":"integer"},"status_url":{"title":"Status Url","type":"string"}},"required":["status","task_id","survey_series_id","survey_id","status_url"],"title":"BulkPushAccepted","type":"object"},"ErrorEnvelope":{"description":"Top-level error response.\n\nSchema name in the OpenAPI document: ``ErrorEnvelope``.","properties":{"error":{"$ref":"#/components/schemas/ErrorObject"},"details":{"anyOf":[{},{"type":"null"}],"default":null,"description":"Optional structured details (e.g. validation field map)","title":"Details"}},"required":["error"],"title":"ErrorEnvelope","type":"object"},"ErrorObject":{"description":"The inner ``error`` field of an error envelope.\n\nSchema name in the OpenAPI document: ``ErrorObject``.","properties":{"code":{"description":"Machine-readable error code drawn from ErrorCode enum","title":"Code","type":"string"},"message":{"description":"Human-readable error message, safe to display","title":"Message","type":"string"}},"required":["code","message"],"title":"ErrorObject","type":"object"}},"responses":{"RateLimited":{"description":"Rate limit exceeded — see Retry-After header.","headers":{"Retry-After":{"$ref":"#/components/headers/RetryAfter"},"X-RateLimit-Limit":{"$ref":"#/components/headers/XRateLimitLimit"},"X-RateLimit-Remaining":{"$ref":"#/components/headers/XRateLimitRemaining"},"X-RateLimit-Reset":{"$ref":"#/components/headers/XRateLimitReset"}},"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}}}},"headers":{"RetryAfter":{"description":"Seconds to wait before retrying. Emitted on 429 and on 503 responses from the global rate limiter. See ``src/utils/middleware/rate_limiting.py``.","schema":{"type":"integer","minimum":1}},"XRateLimitLimit":{"description":"Total requests allowed in the current rate-limit window.","schema":{"type":"integer","minimum":1}},"XRateLimitRemaining":{"description":"Requests remaining in the current rate-limit window.","schema":{"type":"integer","minimum":0}},"XRateLimitReset":{"description":"Unix timestamp when the rate-limit window resets.","schema":{"type":"integer","minimum":0}}}},"paths":{"/api/input/content/push/bulk":{"post":{"summary":"Push feedback to multiple questions","description":"Push feedback text to several questions in a single request. Returns a task id you can poll for completion.","tags":["InputAPI"],"operationId":"inputapi_post_content_push_bulk","parameters":[{"name":"Idempotency-Key","in":"header","required":false,"schema":{"type":"string","maxLength":255},"description":"Opaque retry key (24h window)."}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/BulkContentPushRequest"}}}},"responses":{"202":{"description":"Accepted — task queued for async processing","content":{"application/json":{"schema":{"type":"object","properties":{"data":{"$ref":"#/components/schemas/BulkPushAccepted"}},"required":["data"]}}}},"400":{"description":"Bad Request — validation failed","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}}},"401":{"description":"Unauthorized — missing or invalid credentials","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}}},"403":{"description":"Forbidden — insufficient permission","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}}},"409":{"description":"Conflict (idempotency key reuse or resource conflict)","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}}},"429":{"$ref":"#/components/responses/RateLimited"}}}}}}
```

## Check bulk push status

> Poll the status of a bulk content push submitted to \`/api/input/content/push/bulk\`.

```json
{"openapi":"3.1.0","info":{"title":"BAI Analytics API","version":"1.0.0"},"tags":[{"name":"InputAPI","description":"Bring feedback into BAI Analytics programmatically with an Input API key. Create feedback groups and data sources, publish them, and push feedback text to questions for analysis."}],"servers":[{"url":"https://app.boundary-ai.com","description":"Production"}],"security":[{"apiKeyAuth":[]}],"components":{"securitySchemes":{"apiKeyAuth":{"type":"http","scheme":"bearer","bearerFormat":"BoundaryAI API key","description":"Input API key. Format `inpk_{env}_{key_id}_{secret}` — send as `Authorization: Bearer <key>`. Create keys under Integrations → API; `test` keys are not charged Analysis Points."}},"schemas":{"BulkPushStatus":{"description":"200/202 body of GET /api/input/content/push/bulk/status/{task_id}.","properties":{"task_id":{"title":"Task Id","type":"string"},"status":{"enum":["pending","processing","completed","failed"],"title":"Status","type":"string"},"survey_series_id":{"anyOf":[{"type":"integer"},{"type":"null"}],"default":null,"title":"Survey Series Id"},"survey_id":{"anyOf":[{"type":"integer"},{"type":"null"}],"default":null,"title":"Survey Id"},"progress":{"default":0,"description":"0..1 fraction complete","maximum":1,"minimum":0,"title":"Progress","type":"number"},"progress_message":{"anyOf":[{"type":"string"},{"type":"null"}],"default":null,"title":"Progress Message"},"created_at":{"anyOf":[{"type":"string"},{"type":"null"}],"default":null,"description":"ISO-8601 UTC","title":"Created At"},"completed_at":{"anyOf":[{"type":"string"},{"type":"null"}],"default":null,"description":"ISO-8601 UTC","title":"Completed At"},"result":{"anyOf":[{"additionalProperties":true,"type":"object"},{"type":"null"}],"default":null,"description":"Result payload mirroring ContentPushResponse, present on status=completed","title":"Result"},"error":{"anyOf":[{"additionalProperties":true,"type":"object"},{"type":"null"}],"default":null,"description":"Error payload, present on status=failed","title":"Error"}},"required":["task_id","status"],"title":"BulkPushStatus","type":"object"},"ErrorEnvelope":{"description":"Top-level error response.\n\nSchema name in the OpenAPI document: ``ErrorEnvelope``.","properties":{"error":{"$ref":"#/components/schemas/ErrorObject"},"details":{"anyOf":[{},{"type":"null"}],"default":null,"description":"Optional structured details (e.g. validation field map)","title":"Details"}},"required":["error"],"title":"ErrorEnvelope","type":"object"},"ErrorObject":{"description":"The inner ``error`` field of an error envelope.\n\nSchema name in the OpenAPI document: ``ErrorObject``.","properties":{"code":{"description":"Machine-readable error code drawn from ErrorCode enum","title":"Code","type":"string"},"message":{"description":"Human-readable error message, safe to display","title":"Message","type":"string"}},"required":["code","message"],"title":"ErrorObject","type":"object"}},"responses":{"RateLimited":{"description":"Rate limit exceeded — see Retry-After header.","headers":{"Retry-After":{"$ref":"#/components/headers/RetryAfter"},"X-RateLimit-Limit":{"$ref":"#/components/headers/XRateLimitLimit"},"X-RateLimit-Remaining":{"$ref":"#/components/headers/XRateLimitRemaining"},"X-RateLimit-Reset":{"$ref":"#/components/headers/XRateLimitReset"}},"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}}}},"headers":{"RetryAfter":{"description":"Seconds to wait before retrying. Emitted on 429 and on 503 responses from the global rate limiter. See ``src/utils/middleware/rate_limiting.py``.","schema":{"type":"integer","minimum":1}},"XRateLimitLimit":{"description":"Total requests allowed in the current rate-limit window.","schema":{"type":"integer","minimum":1}},"XRateLimitRemaining":{"description":"Requests remaining in the current rate-limit window.","schema":{"type":"integer","minimum":0}},"XRateLimitReset":{"description":"Unix timestamp when the rate-limit window resets.","schema":{"type":"integer","minimum":0}}}},"paths":{"/api/input/content/push/bulk/status/{task_id}":{"get":{"summary":"Check bulk push status","description":"Poll the status of a bulk content push submitted to `/api/input/content/push/bulk`.","tags":["InputAPI"],"operationId":"inputapi_get_content_push_bulk_status","parameters":[{"name":"task_id","in":"path","required":true,"schema":{"type":"string"}}],"responses":{"200":{"description":"Success","content":{"application/json":{"schema":{"type":"object","properties":{"data":{"$ref":"#/components/schemas/BulkPushStatus"}},"required":["data"]}}}},"202":{"description":"Accepted — task queued for async processing","content":{"application/json":{"schema":{"type":"object","properties":{"data":{"$ref":"#/components/schemas/BulkPushStatus"}},"required":["data"]}}}},"401":{"description":"Unauthorized — missing or invalid credentials","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}}},"404":{"description":"Not Found","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}}},"429":{"$ref":"#/components/responses/RateLimited"}}}}}}
```

## Create a data source

> Create a new data source, with its questions, inside a feedback group.

```json
{"openapi":"3.1.0","info":{"title":"BAI Analytics API","version":"1.0.0"},"tags":[{"name":"InputAPI","description":"Bring feedback into BAI Analytics programmatically with an Input API key. Create feedback groups and data sources, publish them, and push feedback text to questions for analysis."}],"servers":[{"url":"https://app.boundary-ai.com","description":"Production"}],"security":[{"apiKeyAuth":[]}],"components":{"securitySchemes":{"apiKeyAuth":{"type":"http","scheme":"bearer","bearerFormat":"BoundaryAI API key","description":"Input API key. Format `inpk_{env}_{key_id}_{secret}` — send as `Authorization: Bearer <key>`. Create keys under Integrations → API; `test` keys are not charged Analysis Points."}},"parameters":{"IdempotencyKey":{"name":"Idempotency-Key","in":"header","required":false,"description":"Opaque client-supplied key for safe POST retries. Repeated requests with the same key within a 24-hour window replay the original response instead of executing the mutation twice. Reusing the same key with a DIFFERENT request body returns 409 `IDEMPOTENCY_ERROR`. Backed by ``input_api_idempotency_keys`` in Postgres.","schema":{"type":"string","minLength":1,"maxLength":255}}},"schemas":{"CreateSurveyRequest":{"properties":{"survey_series_id":{"title":"Survey Series Id","type":"string"},"survey_title":{"maxLength":100,"minLength":1,"title":"Survey Title","type":"string"},"survey_description":{"default":"","maxLength":1000,"title":"Survey Description","type":"string"},"questions":{"items":{"$ref":"#/components/schemas/CreateSurveyQuestion"},"title":"Questions","type":"array"},"language":{"anyOf":[{"type":"string"},{"type":"null"}],"default":null,"description":"EN | FR | ES (or full names; case-insensitive)","title":"Language"}},"required":["survey_series_id","survey_title"],"title":"CreateSurveyRequest","type":"object"},"CreateSurveyQuestion":{"description":"One question in the create-survey payload. Permissive on\nquestion_type to match the existing case-insensitive parser.","properties":{"question_title":{"maxLength":500,"minLength":1,"title":"Question Title","type":"string"},"question_type":{"description":"One of DEPTH_TEXT, TEXT, MCQ, SCQ, RATING, NPS, METADATA (case-insensitive; also accepts long_answer / short_answer).","title":"Question Type","type":"string"},"question_options":{"items":{"type":"string"},"maxItems":100,"title":"Question Options","type":"array"},"is_mandatory":{"default":false,"title":"Is Mandatory","type":"boolean"},"min_value":{"anyOf":[{"type":"integer"},{"type":"null"}],"default":null,"title":"Min Value"},"max_value":{"anyOf":[{"type":"integer"},{"type":"null"}],"default":null,"title":"Max Value"},"min_label":{"anyOf":[{"type":"string"},{"type":"null"}],"default":null,"title":"Min Label"},"max_label":{"anyOf":[{"type":"string"},{"type":"null"}],"default":null,"title":"Max Label"}},"required":["question_title","question_type"],"title":"CreateSurveyQuestion","type":"object"},"CreateSurveyResponse":{"properties":{"status":{"const":"success","title":"Status","type":"string"},"survey_series_id":{"title":"Survey Series Id","type":"integer"},"survey_id":{"title":"Survey Id","type":"integer"},"questions_created":{"title":"Questions Created","type":"integer"},"questions":{"items":{"$ref":"#/components/schemas/CreatedQuestion"},"title":"Questions","type":"array"},"message":{"title":"Message","type":"string"}},"required":["status","survey_series_id","survey_id","questions_created","questions","message"],"title":"CreateSurveyResponse","type":"object"},"CreatedQuestion":{"properties":{"id":{"title":"Id","type":"integer"},"title":{"title":"Title","type":"string"},"type":{"description":"The normalized question type echoed back","title":"Type","type":"string"}},"required":["id","title","type"],"title":"CreatedQuestion","type":"object"},"ErrorEnvelope":{"description":"Top-level error response.\n\nSchema name in the OpenAPI document: ``ErrorEnvelope``.","properties":{"error":{"$ref":"#/components/schemas/ErrorObject"},"details":{"anyOf":[{},{"type":"null"}],"default":null,"description":"Optional structured details (e.g. validation field map)","title":"Details"}},"required":["error"],"title":"ErrorEnvelope","type":"object"},"ErrorObject":{"description":"The inner ``error`` field of an error envelope.\n\nSchema name in the OpenAPI document: ``ErrorObject``.","properties":{"code":{"description":"Machine-readable error code drawn from ErrorCode enum","title":"Code","type":"string"},"message":{"description":"Human-readable error message, safe to display","title":"Message","type":"string"}},"required":["code","message"],"title":"ErrorObject","type":"object"}},"responses":{"RateLimited":{"description":"Rate limit exceeded — see Retry-After header.","headers":{"Retry-After":{"$ref":"#/components/headers/RetryAfter"},"X-RateLimit-Limit":{"$ref":"#/components/headers/XRateLimitLimit"},"X-RateLimit-Remaining":{"$ref":"#/components/headers/XRateLimitRemaining"},"X-RateLimit-Reset":{"$ref":"#/components/headers/XRateLimitReset"}},"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}}}},"headers":{"RetryAfter":{"description":"Seconds to wait before retrying. Emitted on 429 and on 503 responses from the global rate limiter. See ``src/utils/middleware/rate_limiting.py``.","schema":{"type":"integer","minimum":1}},"XRateLimitLimit":{"description":"Total requests allowed in the current rate-limit window.","schema":{"type":"integer","minimum":1}},"XRateLimitRemaining":{"description":"Requests remaining in the current rate-limit window.","schema":{"type":"integer","minimum":0}},"XRateLimitReset":{"description":"Unix timestamp when the rate-limit window resets.","schema":{"type":"integer","minimum":0}}}},"paths":{"/api/input/survey/create":{"post":{"summary":"Create a data source","description":"Create a new data source, with its questions, inside a feedback group.","tags":["InputAPI"],"operationId":"inputapi_post_survey_create","parameters":[{"$ref":"#/components/parameters/IdempotencyKey"}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/CreateSurveyRequest"}}}},"responses":{"201":{"description":"Created","content":{"application/json":{"schema":{"type":"object","properties":{"data":{"$ref":"#/components/schemas/CreateSurveyResponse"}},"required":["data"]}}}},"400":{"description":"Bad Request — validation failed","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}}},"401":{"description":"Unauthorized — missing or invalid credentials","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}}},"403":{"description":"Forbidden — insufficient permission","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}}},"404":{"description":"Not Found","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}}},"429":{"$ref":"#/components/responses/RateLimited"}}}}}}
```

## Publish a data source

> Publish a data source to enable data collection and analysis.

```json
{"openapi":"3.1.0","info":{"title":"BAI Analytics API","version":"1.0.0"},"tags":[{"name":"InputAPI","description":"Bring feedback into BAI Analytics programmatically with an Input API key. Create feedback groups and data sources, publish them, and push feedback text to questions for analysis."}],"servers":[{"url":"https://app.boundary-ai.com","description":"Production"}],"security":[{"apiKeyAuth":[]}],"components":{"securitySchemes":{"apiKeyAuth":{"type":"http","scheme":"bearer","bearerFormat":"BoundaryAI API key","description":"Input API key. Format `inpk_{env}_{key_id}_{secret}` — send as `Authorization: Bearer <key>`. Create keys under Integrations → API; `test` keys are not charged Analysis Points."}},"parameters":{"IdempotencyKey":{"name":"Idempotency-Key","in":"header","required":false,"description":"Opaque client-supplied key for safe POST retries. Repeated requests with the same key within a 24-hour window replay the original response instead of executing the mutation twice. Reusing the same key with a DIFFERENT request body returns 409 `IDEMPOTENCY_ERROR`. Backed by ``input_api_idempotency_keys`` in Postgres.","schema":{"type":"string","minLength":1,"maxLength":255}}},"schemas":{"PublishSurveyRequest":{"properties":{"survey_id":{"title":"Survey Id","type":"integer"},"survey_series_id":{"title":"Survey Series Id","type":"integer"}},"required":["survey_id","survey_series_id"],"title":"PublishSurveyRequest","type":"object"},"PublishSurveyResponse":{"properties":{"status":{"const":"success","title":"Status","type":"string"},"survey_id":{"title":"Survey Id","type":"integer"},"survey_series_id":{"title":"Survey Series Id","type":"integer"},"mode":{"const":"ACCESSIBLE","title":"Mode","type":"string"},"message":{"title":"Message","type":"string"}},"required":["status","survey_id","survey_series_id","mode","message"],"title":"PublishSurveyResponse","type":"object"},"ErrorEnvelope":{"description":"Top-level error response.\n\nSchema name in the OpenAPI document: ``ErrorEnvelope``.","properties":{"error":{"$ref":"#/components/schemas/ErrorObject"},"details":{"anyOf":[{},{"type":"null"}],"default":null,"description":"Optional structured details (e.g. validation field map)","title":"Details"}},"required":["error"],"title":"ErrorEnvelope","type":"object"},"ErrorObject":{"description":"The inner ``error`` field of an error envelope.\n\nSchema name in the OpenAPI document: ``ErrorObject``.","properties":{"code":{"description":"Machine-readable error code drawn from ErrorCode enum","title":"Code","type":"string"},"message":{"description":"Human-readable error message, safe to display","title":"Message","type":"string"}},"required":["code","message"],"title":"ErrorObject","type":"object"}},"responses":{"RateLimited":{"description":"Rate limit exceeded — see Retry-After header.","headers":{"Retry-After":{"$ref":"#/components/headers/RetryAfter"},"X-RateLimit-Limit":{"$ref":"#/components/headers/XRateLimitLimit"},"X-RateLimit-Remaining":{"$ref":"#/components/headers/XRateLimitRemaining"},"X-RateLimit-Reset":{"$ref":"#/components/headers/XRateLimitReset"}},"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}}}},"headers":{"RetryAfter":{"description":"Seconds to wait before retrying. Emitted on 429 and on 503 responses from the global rate limiter. See ``src/utils/middleware/rate_limiting.py``.","schema":{"type":"integer","minimum":1}},"XRateLimitLimit":{"description":"Total requests allowed in the current rate-limit window.","schema":{"type":"integer","minimum":1}},"XRateLimitRemaining":{"description":"Requests remaining in the current rate-limit window.","schema":{"type":"integer","minimum":0}},"XRateLimitReset":{"description":"Unix timestamp when the rate-limit window resets.","schema":{"type":"integer","minimum":0}}}},"paths":{"/api/input/survey/publish":{"post":{"summary":"Publish a data source","description":"Publish a data source to enable data collection and analysis.","tags":["InputAPI"],"operationId":"inputapi_post_survey_publish","parameters":[{"$ref":"#/components/parameters/IdempotencyKey"}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/PublishSurveyRequest"}}}},"responses":{"200":{"description":"Success","content":{"application/json":{"schema":{"type":"object","properties":{"data":{"$ref":"#/components/schemas/PublishSurveyResponse"}},"required":["data"]}}}},"400":{"description":"Bad Request — validation failed","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}}},"401":{"description":"Unauthorized — missing or invalid credentials","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}}},"403":{"description":"Forbidden — insufficient permission","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}}},"404":{"description":"Not Found","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}}},"429":{"$ref":"#/components/responses/RateLimited"}}}}}}
```

## Create a feedback group

> Create a new feedback group to organise related data sources.

```json
{"openapi":"3.1.0","info":{"title":"BAI Analytics API","version":"1.0.0"},"tags":[{"name":"InputAPI","description":"Bring feedback into BAI Analytics programmatically with an Input API key. Create feedback groups and data sources, publish them, and push feedback text to questions for analysis."}],"servers":[{"url":"https://app.boundary-ai.com","description":"Production"}],"security":[{"apiKeyAuth":[]}],"components":{"securitySchemes":{"apiKeyAuth":{"type":"http","scheme":"bearer","bearerFormat":"BoundaryAI API key","description":"Input API key. Format `inpk_{env}_{key_id}_{secret}` — send as `Authorization: Bearer <key>`. Create keys under Integrations → API; `test` keys are not charged Analysis Points."}},"parameters":{"IdempotencyKey":{"name":"Idempotency-Key","in":"header","required":false,"description":"Opaque client-supplied key for safe POST retries. Repeated requests with the same key within a 24-hour window replay the original response instead of executing the mutation twice. Reusing the same key with a DIFFERENT request body returns 409 `IDEMPOTENCY_ERROR`. Backed by ``input_api_idempotency_keys`` in Postgres.","schema":{"type":"string","minLength":1,"maxLength":255}}},"schemas":{"CreateSurveySeriesRequest":{"properties":{"name":{"description":"Series display name","maxLength":255,"minLength":2,"title":"Name","type":"string"}},"required":["name"],"title":"CreateSurveySeriesRequest","type":"object"},"CreateSurveySeriesResponse":{"description":"200 (already exists) / 201 (created) body.","properties":{"status":{"const":"success","title":"Status","type":"string"},"created":{"description":"False when the series already existed","title":"Created","type":"boolean"},"message":{"anyOf":[{"type":"string"},{"type":"null"}],"default":null,"title":"Message"},"survey_series":{"$ref":"#/components/schemas/CreatedSeriesMinimal"}},"required":["status","created","survey_series"],"title":"CreateSurveySeriesResponse","type":"object"},"CreatedSeriesMinimal":{"properties":{"id":{"title":"Id","type":"integer"},"name":{"title":"Name","type":"string"}},"required":["id","name"],"title":"CreatedSeriesMinimal","type":"object"},"ErrorEnvelope":{"description":"Top-level error response.\n\nSchema name in the OpenAPI document: ``ErrorEnvelope``.","properties":{"error":{"$ref":"#/components/schemas/ErrorObject"},"details":{"anyOf":[{},{"type":"null"}],"default":null,"description":"Optional structured details (e.g. validation field map)","title":"Details"}},"required":["error"],"title":"ErrorEnvelope","type":"object"},"ErrorObject":{"description":"The inner ``error`` field of an error envelope.\n\nSchema name in the OpenAPI document: ``ErrorObject``.","properties":{"code":{"description":"Machine-readable error code drawn from ErrorCode enum","title":"Code","type":"string"},"message":{"description":"Human-readable error message, safe to display","title":"Message","type":"string"}},"required":["code","message"],"title":"ErrorObject","type":"object"}},"responses":{"RateLimited":{"description":"Rate limit exceeded — see Retry-After header.","headers":{"Retry-After":{"$ref":"#/components/headers/RetryAfter"},"X-RateLimit-Limit":{"$ref":"#/components/headers/XRateLimitLimit"},"X-RateLimit-Remaining":{"$ref":"#/components/headers/XRateLimitRemaining"},"X-RateLimit-Reset":{"$ref":"#/components/headers/XRateLimitReset"}},"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}}}},"headers":{"RetryAfter":{"description":"Seconds to wait before retrying. Emitted on 429 and on 503 responses from the global rate limiter. See ``src/utils/middleware/rate_limiting.py``.","schema":{"type":"integer","minimum":1}},"XRateLimitLimit":{"description":"Total requests allowed in the current rate-limit window.","schema":{"type":"integer","minimum":1}},"XRateLimitRemaining":{"description":"Requests remaining in the current rate-limit window.","schema":{"type":"integer","minimum":0}},"XRateLimitReset":{"description":"Unix timestamp when the rate-limit window resets.","schema":{"type":"integer","minimum":0}}}},"paths":{"/api/input/survey_series/create":{"post":{"summary":"Create a feedback group","description":"Create a new feedback group to organise related data sources.","tags":["InputAPI"],"operationId":"inputapi_post_survey_series_create","parameters":[{"$ref":"#/components/parameters/IdempotencyKey"}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/CreateSurveySeriesRequest"}}}},"responses":{"200":{"description":"Success","content":{"application/json":{"schema":{"type":"object","properties":{"data":{"$ref":"#/components/schemas/CreateSurveySeriesResponse"}},"required":["data"]}}}},"201":{"description":"Created","content":{"application/json":{"schema":{"type":"object","properties":{"data":{"$ref":"#/components/schemas/CreateSurveySeriesResponse"}},"required":["data"]}}}},"400":{"description":"Bad Request — validation failed","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}}},"401":{"description":"Unauthorized — missing or invalid credentials","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}}},"403":{"description":"Forbidden — insufficient permission","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}}},"429":{"$ref":"#/components/responses/RateLimited"}}}}}}
```

## List feedback groups and data sources

> Retrieve all feedback groups and data sources your API key can access.

```json
{"openapi":"3.1.0","info":{"title":"BAI Analytics API","version":"1.0.0"},"tags":[{"name":"InputAPI","description":"Bring feedback into BAI Analytics programmatically with an Input API key. Create feedback groups and data sources, publish them, and push feedback text to questions for analysis."}],"servers":[{"url":"https://app.boundary-ai.com","description":"Production"}],"security":[{"apiKeyAuth":[]}],"components":{"securitySchemes":{"apiKeyAuth":{"type":"http","scheme":"bearer","bearerFormat":"BoundaryAI API key","description":"Input API key. Format `inpk_{env}_{key_id}_{secret}` — send as `Authorization: Bearer <key>`. Create keys under Integrations → API; `test` keys are not charged Analysis Points."}},"schemas":{"SurveysListResponse":{"description":"Body of GET /api/input/surveys and /api/input/surveys/list.\n\nThe `org_id` field is present on the API-key endpoint and omitted on\nthe Clerk endpoint — declare it Optional.","properties":{"survey_series":{"items":{"$ref":"#/components/schemas/SeriesListing"},"title":"Survey Series","type":"array"},"org_id":{"anyOf":[{"type":"integer"},{"type":"null"}],"default":null,"title":"Org Id"},"message":{"anyOf":[{"type":"string"},{"type":"null"}],"default":null,"title":"Message"}},"title":"SurveysListResponse","type":"object"},"SeriesListing":{"properties":{"id":{"title":"Id","type":"integer"},"name":{"title":"Name","type":"string"},"surveys":{"items":{"$ref":"#/components/schemas/SurveyListing"},"title":"Surveys","type":"array"}},"required":["id","name"],"title":"SeriesListing","type":"object"},"SurveyListing":{"properties":{"id":{"title":"Id","type":"integer"},"title":{"title":"Title","type":"string"},"description":{"anyOf":[{"type":"string"},{"type":"null"}],"default":null,"title":"Description"},"mode":{"anyOf":[{"type":"string"},{"type":"null"}],"default":null,"title":"Mode"},"questions":{"items":{"$ref":"#/components/schemas/QuestionListing"},"title":"Questions","type":"array"}},"required":["id","title"],"title":"SurveyListing","type":"object"},"QuestionListing":{"properties":{"id":{"title":"Id","type":"integer"},"title":{"title":"Title","type":"string"},"type":{"title":"Type","type":"string"},"options":{"anyOf":[{"items":{"type":"string"},"type":"array"},{"type":"null"}],"default":null,"title":"Options"},"accepts_content":{"anyOf":[{"type":"boolean"},{"type":"null"}],"default":null,"title":"Accepts Content"},"content_format":{"anyOf":[{"type":"string"},{"type":"null"}],"default":null,"description":"One of text | numeric | single_choice | multi_choice","title":"Content Format"},"min":{"anyOf":[{"type":"integer"},{"type":"null"}],"default":null,"title":"Min"},"max":{"anyOf":[{"type":"integer"},{"type":"null"}],"default":null,"title":"Max"}},"required":["id","title","type"],"title":"QuestionListing","type":"object"},"ErrorEnvelope":{"description":"Top-level error response.\n\nSchema name in the OpenAPI document: ``ErrorEnvelope``.","properties":{"error":{"$ref":"#/components/schemas/ErrorObject"},"details":{"anyOf":[{},{"type":"null"}],"default":null,"description":"Optional structured details (e.g. validation field map)","title":"Details"}},"required":["error"],"title":"ErrorEnvelope","type":"object"},"ErrorObject":{"description":"The inner ``error`` field of an error envelope.\n\nSchema name in the OpenAPI document: ``ErrorObject``.","properties":{"code":{"description":"Machine-readable error code drawn from ErrorCode enum","title":"Code","type":"string"},"message":{"description":"Human-readable error message, safe to display","title":"Message","type":"string"}},"required":["code","message"],"title":"ErrorObject","type":"object"}},"responses":{"RateLimited":{"description":"Rate limit exceeded — see Retry-After header.","headers":{"Retry-After":{"$ref":"#/components/headers/RetryAfter"},"X-RateLimit-Limit":{"$ref":"#/components/headers/XRateLimitLimit"},"X-RateLimit-Remaining":{"$ref":"#/components/headers/XRateLimitRemaining"},"X-RateLimit-Reset":{"$ref":"#/components/headers/XRateLimitReset"}},"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}}}},"headers":{"RetryAfter":{"description":"Seconds to wait before retrying. Emitted on 429 and on 503 responses from the global rate limiter. See ``src/utils/middleware/rate_limiting.py``.","schema":{"type":"integer","minimum":1}},"XRateLimitLimit":{"description":"Total requests allowed in the current rate-limit window.","schema":{"type":"integer","minimum":1}},"XRateLimitRemaining":{"description":"Requests remaining in the current rate-limit window.","schema":{"type":"integer","minimum":0}},"XRateLimitReset":{"description":"Unix timestamp when the rate-limit window resets.","schema":{"type":"integer","minimum":0}}}},"paths":{"/api/input/surveys/list":{"get":{"summary":"List feedback groups and data sources","description":"Retrieve all feedback groups and data sources your API key can access.","tags":["InputAPI"],"operationId":"inputapi_get_surveys_list","parameters":[{"name":"survey_series_id","in":"query","required":false,"schema":{"type":"string"}},{"name":"survey_id","in":"query","required":false,"schema":{"type":"string"}}],"responses":{"200":{"description":"Success","content":{"application/json":{"schema":{"type":"object","properties":{"data":{"$ref":"#/components/schemas/SurveysListResponse"}},"required":["data"]}}}},"400":{"description":"Bad Request — validation failed","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}}},"401":{"description":"Unauthorized — missing or invalid credentials","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}}},"403":{"description":"Forbidden — insufficient permission","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}}},"429":{"$ref":"#/components/responses/RateLimited"}}}}}}
```
