Skip to main content

Researcher API

Automate studies with the Populiva API: create and launch studies, review and bonus submissions, manage groups, message participants, and get signed webhooks when things happen. Create a token from your lab's Developer page.

OpenAPI 3.1 spec (JSON)

Authentication

Send your lab's token as a Bearer token. Tokens have scopes: read (every GET), studies (create and run studies, review submissions, groups, and messages), and money (bonuses and invoices). Each token can make 600 requests a minute. Participants appear only as PARTICIPANT_IDs for your lab, and amounts are US dollars as strings.

curl https://populiva.com/api/v1/studies \
  -H "Authorization: Bearer pv_..."

curl -X POST https://populiva.com/api/v1/submissions/123/approve \
  -H "Authorization: Bearer pv_..."

Endpoints

Endpoints
Method Path What it does
get /api/v1/studies List your lab's studies (newest first
post /api/v1/studies Create a draft study (title, description, language, external_url, estimated_minutes, max_minutes, reward, places, screeners, ...)
get /api/v1/studies/{id} A study
patch /api/v1/studies/{id} Update a draft study
post /api/v1/studies/{id}/launch Launch a draft (reserves its cost from your balance)
post /api/v1/studies/{id}/pause Pause a running study
post /api/v1/studies/{id}/resume Resume a paused study
post /api/v1/studies/{id}/close Close a study (releases unused reserve)
post /api/v1/studies/{id}/add_places Add places to a running study (count)
get /api/v1/studies/{study_id}/submissions A study's submissions (optional status filter)
get /api/v1/studies/{study_id}/provenance_reports A study's provenance reports
post /api/v1/studies/{study_id}/provenance_reports Issue a new provenance report version
get /api/v1/submissions/{id} A submission
post /api/v1/submissions/{id}/approve Approve a submission awaiting review
post /api/v1/submissions/{id}/reject Reject with a reason (no_completion, failed_attention_checks, did_not_follow_instructions, low_effort, duplicate_or_fraud)
post /api/v1/submissions/{id}/bonus Bonus an approved submission (amount, up to 100.00; money scope)
get /api/v1/groups Your lab's participant groups
post /api/v1/groups Create a group (name)
get /api/v1/groups/{id} A group and its PARTICIPANT_IDs
post /api/v1/groups/{id}/members Add participant_ids, or remove them with remove=true
post /api/v1/messages Message one participant (submission_id, body) or a study audience (study_id, audience, group_id, body)
get /api/v1/balance Your lab's available and reserved balance
get /api/v1/invoices Your lab's invoices
post /api/v1/invoices Request an invoice (amount, billing_name, billing_email, billing_address, po_number; money scope)

Webhooks

Lab → Developer → Webhooks. Each delivery is a POST with a JSON body {id, event, created_at, data} and a `Populiva-Signature: t=<unix time>,v1=<hex HMAC-SHA256 of "<t>.<raw body>" with your endpoint secret>` header. Reject deliveries whose signature doesn't match or whose t is more than 5 minutes old. Failed deliveries are retried after 1 minute, 5 minutes, 30 minutes, 2 hours, and 12 hours.

Events: study.launched, study.paused, study.resumed, study.closed, submission.created, submission.reviewed.

# Ruby: verify a delivery
timestamp, signature = request.headers["Populiva-Signature"].scan(/(?:t|v1)=([^,]+)/).flatten
expected = OpenSSL::HMAC.hexdigest("SHA256", ENDPOINT_SECRET, "#{timestamp}.#{request.raw_post}")
valid = ActiveSupport::SecurityUtils.secure_compare(expected, signature) && Time.now.to_i - timestamp.to_i < 300