AuthenticationEvery request must carry a bearer token in the Authorization header. Keys are per-organization, scoped, and revokable without touching your code.
API key formatKeys are prefixed gt_sk_ for easy scanning. The secret is shown exactly once at creation time and stored only as a bcrypt hash on our servers.
Per-key scopes (read / write / admin)
Last-used timestamp for audit
Instant revocation — no TTL wait
Rate limitsRate limits apply per API key and globally. Limits are returned in response headers so you can back off gracefully.
X-RateLimit-Limit
X-RateLimit-Remaining
X-RateLimit-Reset (Unix epoch)
Webhook deliveriesRegister an HTTPS endpoint and receive HMAC-signed events for every submission state change. Retried with exponential backoff.
submission.created
submission.approved
task.completed
EndpointsBase URL: https://groundtruth.io/api/v1
POST
/tasksCreate a new task and receive a funding linkGET
/tasksList tasks for your organization (paginated)GET
/tasks/{id}Retrieve a single task with current statusGET
/tasks/{id}/submissionsStream approved submissions with signed media URLsGET
/submissions/{id}Retrieve a submission and a short-lived download URLPOST
/webhook-endpointsRegister an HTTPS URL for event deliveryCreate a taskPOST a task definition. The response includes a Stripe-hosted funding_url. Once funded, the task status transitions to open and contributors can begin submitting.
http
POST /api/v1/tasks
Authorization: Bearer gt_sk_••••••••
Content-Type: application/json
{
"title": "Record a busy street scene",
"instructions": "Walk any public street for 30 s. Steady hand, no filters.",
"modalities": ["video"],
"reward_cents": 250,
"target_submissions": 100
}
// → 201 Created
{
"id": "tsk_01hx4nvzgw5q9k3m",
"status": "funding",
"funding_url": "https://checkout.stripe.com/...",
"reward_cents": 250,
"target_submissions": 100,
"created_at": "2026-06-18T14:32:00Z"
}Fetch approved submissionsEach approved submission includes a short-lived signed URL (1 hour) for the raw media file. Paginate with next_cursor to stream all results.
http
GET /api/v1/tasks/tsk_01hx4nvzgw5q9k3m/submissions
Authorization: Bearer gt_sk_••••••••
// → 200 OK
{
"data": [
{
"id": "sub_01hx7r4s2g0k1a5b",
"status": "approved",
"duration_seconds": 31,
"media_url": "https://r2.groundtruth.io/sub_...?X-Amz-Expires=3600",
"created_at": "2026-06-18T16:05:12Z"
}
],
"pagination": {
"total": 47,
"page": 1,
"per_page": 20,
"next_cursor": "cur_01hx7r4s2..."
}
}ErrorsAll errors follow a consistent structure with machine-readable codes so you can handle them programmatically without parsing messages.
json
{
"error": {
"code": "insufficient_budget",
"message": "Task budget is below the minimum required to open.",
"details": {
"budget_cents": 1000,
"required_cents": 2500
}
}
}400validation_error
401unauthorized
403forbidden
404not_found
409conflict
429rate_limited
500internal_error