Skip to content

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).

Terminal window
pip install surveycoder

Requires Python 3.9+. Built on httpx.

import os
from 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}")
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 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,
)
MethodWhat 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).
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.

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 status

Every code is documented in the error reference.

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), confidence
df.head()

Optional dep: pip install surveycoder[pandas] if you don’t have pandas installed.