Python SDK
The Python SDK wraps the Survey Coder Pro REST API with typed kwargs, automatic retries, idempotency keys, and structured errors.
Latest version: surveycoder@1.0.2 (adds refinement workflow methods: bulk_apply_refinement + export_refinement).
Install
Section titled “Install”pip install surveycoderRequires Python 3.9+. Built on httpx.
Quickstart
Section titled “Quickstart”import osfrom surveycoder import SurveyCoderClient
client = SurveyCoderClient(api_key=os.environ["SCP_API_KEY"])
result = client.code( responses=[ {"id": "R001", "text": "Tide because it removes stains better"}, {"id": "R002", "text": "Ariel - bigger pack, lasts longer"}, {"id": "R003", "text": "Persil because my mom always used it"}, ], coding_type="qualitative", language="en", # Strongly recommended — drives codebook quality: question_text="Which brand of laundry detergent do you prefer and why?", project_name="Laundry brand tracker — wave 1", country="US", category="CPG / Home Care",)
print(f"Codebook: {len(result['codebook'])} categories")for row in result["results"]: code_names = ", ".join(c["name"] for c in row["codes"]) print(f"{row['id']} -> {code_names}")Constructor options
Section titled “Constructor options”SurveyCoderClient( api_key: str, # required — starts with scp_live_ or scp_test_ base_url: str = "https://api.surveycoder.io", timeout: int = 300, # seconds — coding can be slow max_retries: int = 3, # on 5xx and 429, exponential backoff)The code() call
Section titled “The code() call”The hero method. Sync if len(responses) < 50, async (returns a {"job_id": ...} dict) otherwise.
client.code( # Required responses: list[dict], # list of {id: str, text: str}
# Optional, with defaults coding_type: str = "qualitative", # 'qualitative' | 'entity' | 'qualitative_topics' language: str = "en",
# Optional context — strongly recommended, all improve quality: question_text: str | None = None, # the actual survey question project_name: str | None = None, # shown in your dashboard country: str | None = None, # ISO code or country name category: str | None = None, # organizational tag coding_guidance: str | None = None, # free-form prompt instructions
# Advanced: bring your own codebook (skips AI generation) codebook: dict | None = None,)Other methods
Section titled “Other methods”| Method | What it does |
|---|---|
client.get_job(job_id) | Get current state of an async job. |
client.wait_for_job(job_id, poll_interval=5.0) | Poll until complete; returns the result or raises. |
client.list_jobs(status=None, limit=20) | List recent jobs. |
client.get_usage() | Current credit balance + rate-limit config. |
client.health() | Unauthenticated health probe. |
client.code_to_dataframe(...) | Convenience: returns a pandas DataFrame with one row per coded response. |
client.export_excel(project_id, question_id, ...) | Excel export (returns bytes). |
client.export_csv(project_id, question_id, ...) | CSV export (returns str). |
client.refinement_suggestions(project_id, question_id, force=False) | List/generate codebook refinement suggestions. See Refinement workflow. |
client.apply_refinement(project_id, question_id, suggestion) | Apply one refinement suggestion (full object). |
client.resolve_refinement(project_id, question_id, suggestion_id, action, ...) | Resolve a suggestion (create_new / assign_existing / merge / dismiss). |
client.undo_refinement(project_id, question_id, suggestion_id) | Reopen a resolved suggestion. |
client.bulk_apply_refinement(project_id, question_id, suggestion_ids?, min_confidence?) | Auto-apply many new_code suggestions in one call. |
client.export_refinement(project_id, question_id, format='xlsx'|'csv') | Download all suggestions as a file (returns bytes). |
Waiting for async jobs
Section titled “Waiting for async jobs”res = client.code(responses=[...], question_text="...") # 50+ responses
if "job_id" in res: final = client.wait_for_job(res["job_id"], poll_interval=5.0) print(final["codebook"])wait_for_job raises SurveyCoderError if the job ends in failed.
Errors
Section titled “Errors”from surveycoder import SurveyCoderClient, SurveyCoderError, RateLimitError
try: client.code(responses=[...], question_text="...")except RateLimitError as e: print(f"Rate limited, retry in {e.retry_after}s")except SurveyCoderError as e: print(e.code) # 'INSUFFICIENT_CREDITS' print(e.message) print(e.request_id) # 'req_01HXJZK4...' print(e.status) # HTTP statusEvery code is documented in the error reference.
Pandas integration
Section titled “Pandas integration”code_to_dataframe is a convenience for analysts who want results in tabular form:
import pandas as pd
df = client.code_to_dataframe( responses=[{"id": f"R{i}", "text": t} for i, t in enumerate(my_verbatims)], question_text="Why do you prefer this brand?", project_name="Brand study",)
# df has columns: respondent_id, response_text, codes (list), sentiments (list), confidencedf.head()Optional dep: pip install surveycoder[pandas] if you don’t have pandas installed.
Related
Section titled “Related”- TypeScript SDK — same API surface
- Webhooks — async job notifications
- API reference