Python SDK
The label-studio-sdk
Python package works against AfriAnnotate out of the box — the API
shape is the same as upstream Label Studio's. Use it to automate
project creation, task imports, annotation exports, and member
management from Python scripts or CI pipelines.
Install​
pip install label-studio-sdk
Minimum Python 3.9. The SDK depends on httpx and pydantic.
Get a token​
You need a Personal Access Token (PAT) to authenticate. See API → Authentication for the step-by-step. Briefly:
- Sign in to afriannotate.waraka.org.
- Profile → Settings → Personal Access Token → Create new token.
- Copy the token immediately (only shown once).
For production scripts, store the token in a secret manager / env var, not in source.
Hello world​
import os
from label_studio_sdk import LabelStudio
client = LabelStudio(
base_url="https://afriannotate.waraka.org",
api_key=os.environ["AFRIANNOTATE_API_KEY"],
)
# List your projects
for project in client.projects.list():
print(f"{project.id}: {project.title} ({project.task_number} tasks)")
Common operations​
Create a project​
project = client.projects.create(
title="Hausa sentiment v1",
description="Sentiment labels for Hausa product reviews",
label_config="""
<View>
<Choices name="sentiment" toName="text">
<Choice value="positive"/>
<Choice value="negative"/>
<Choice value="neutral"/>
</Choices>
<Text name="text" value="$text"/>
</View>
""",
)
print(f"Created project {project.id}")
Import tasks​
client.projects.import_tasks(
id=project.id,
request=[
{"data": {"text": "Yana da kyau sosai"}},
{"data": {"text": "Ban so wannan ba"}},
{"data": {"text": "Wannan ya yi kyau ainun"}},
],
)
Each task's data keys must match the $varname references in
the project's labeling config. See
Task format.
Export annotations​
# JSON with full task + annotation structure
export = client.projects.exports.create(
project_id=project.id,
request={"format": "JSON"},
)
with open("annotations.json", "wb") as f:
f.write(export.content)
Other supported formats include CSV, CoNLL2003, COCO, YOLO, Pascal VOC, and ASR Manifest for audio. List the formats available for your project with:
formats = client.projects.exports.list_formats(project_id=project.id)
for fmt in formats:
print(fmt.name, fmt.title)
Iterate over tasks​
# Paginated — handles large datasets
for task in client.tasks.list(project=project.id):
print(task.id, task.data, task.annotations)
Submit an annotation​
client.annotations.create(
task=task_id,
result=[
{
"from_name": "sentiment",
"to_name": "text",
"type": "choices",
"value": {"choices": ["positive"]},
}
],
)
The result array follows the same format the labeling UI emits —
see Task format for the per-tag
schema.
Async client​
The SDK ships an async variant with the same surface:
import asyncio
from label_studio_sdk import AsyncLabelStudio
async def main():
client = AsyncLabelStudio(
base_url="https://afriannotate.waraka.org",
api_key="<your-token>",
)
projects = [p async for p in client.projects.list()]
print(f"{len(projects)} projects")
asyncio.run(main())
Useful when running many concurrent operations (bulk import, parallel exports, etc.).
Error handling​
The SDK raises ApiError for non-2xx responses. The error carries
the raw response: status_code and body — for AfriAnnotate
that body is the API's error shape
({id, status_code, version, detail, exc_info}, plus
validation_errors on validation failures):
from label_studio_sdk.core.api_error import ApiError
try:
client.projects.create(title="")
except ApiError as e:
print(f"Status: {e.status_code}")
print(f"Detail: {e.body.get('detail')}")
print(f"Fields: {e.body.get('validation_errors')}")
Only the anonymous auth endpoints (password reset etc. — not used
by the SDK) return retry_after on 429; for other endpoints just
back off and retry on 429/5xx.
Resources​
label-studio-sdkGitHub — source + per-method reference + more examples- API → Authentication — getting a token, rotation, revocation
- Task format — the JSON shape every import + annotation result follows