Skip to content

Outreach

The outreach system manages the flow of messages sent to prospective testers. An AI draft is generated for each candidate, reviewed or edited by the team, then approved for sending. The proposals section covers invitations generated from the matching algorithm.

Endpoints

GET /api/outreach/queue JWT

List all pending outreach messages awaiting review

Returns all outreach messages in pending status, ordered by creation time (oldest first).

Query parameters

ParameterTypeDescription
jobIdstringFilter queue by study
pageintegerPage number (default: 1)
limitintegerResults per page (default: 20)

Response

{
"success": true,
"data": [
{
"outreachId": "out_001",
"jobId": "job_abc123",
"testerId": "user_xyz789",
"testerEmail": "tester@example.com",
"channel": "email",
"subject": "You're a great fit for a new usability study",
"body": "Hi Alex, we have a new study on checkout flows that matches your profile...",
"status": "pending",
"generatedAt": "2026-03-16T08:00:00Z"
}
],
"error": null,
"metadata": {
"page": 1,
"limit": 20,
"total": 7
}
}
POST /api/outreach/:id/approve JWT

Approve a pending outreach message for sending

Path parameters

ParameterDescription
idOutreach message ID

Approving queues the message for delivery via the configured channel (email or Telegram).

Request body

None required.

Response

{
"success": true,
"data": {
"outreachId": "out_001",
"status": "approved",
"scheduledSendAt": "2026-03-16T09:00:00Z",
"approvedAt": "2026-03-16T08:30:00Z"
},
"error": null,
"metadata": null
}
POST /api/outreach/:id/edit JWT

Edit and save changes to a pending outreach message

Path parameters

ParameterDescription
idOutreach message ID

Updates the message content before sending. The message remains in pending status and must be explicitly approved after editing.

Request body

{
"subject": "New study opportunity - 15 min checkout test",
"body": "Hi Alex, we're running a quick usability test on our checkout redesign. It takes about 15 minutes and pays $15. Your profile is a great match. Interested?"
}
FieldTypeRequiredDescription
subjectstringNoUpdated subject line (email only)
bodystringYesUpdated message body

Response

{
"success": true,
"data": {
"outreachId": "out_001",
"status": "pending",
"updatedAt": "2026-03-16T08:25:00Z"
},
"error": null,
"metadata": null
}
POST /api/outreach/:id/reject JWT

Reject an outreach message to prevent it from being sent

Path parameters

ParameterDescription
idOutreach message ID

Rejected messages are not sent. Use this when a candidate is no longer eligible or the message content is inappropriate.

Request body

{
"reason": "Tester is currently suspended."
}

reason is optional but recommended for audit purposes.

Response

{
"success": true,
"data": {
"outreachId": "out_001",
"status": "rejected",
"rejectedAt": "2026-03-16T08:20:00Z"
},
"error": null,
"metadata": null
}
GET /api/outreach/proposals JWT

List candidate proposals generated by the matching algorithm

Proposals are testers that the matching algorithm has identified as strong candidates for a study, before outreach messages are drafted. Review proposals to confirm or skip candidates before the outreach queue is populated.

Query parameters

ParameterTypeDescription
jobIdstringRequired. Filter proposals by study.
statusstringFilter by pending, accepted, skipped
pageintegerPage number (default: 1)
limitintegerResults per page (default: 20)

Response

{
"success": true,
"data": [
{
"proposalId": "prop_001",
"jobId": "job_abc123",
"testerId": "user_xyz789",
"matchScore": 0.94,
"matchReasons": [
"Country matches targeting (IT)",
"Age within range (28)",
"Device: desktop",
"12 prior completed sessions"
],
"status": "pending",
"generatedAt": "2026-03-16T07:00:00Z"
}
],
"error": null,
"metadata": {
"page": 1,
"limit": 20,
"total": 15
}
}
POST /api/outreach/proposals/:id/approve JWT

Accept a candidate proposal and queue an outreach message

Path parameters

ParameterDescription
idProposal ID

Approving a proposal generates an AI-drafted outreach message and adds it to the pending queue.

Request body

None required.

Response

{
"success": true,
"data": {
"proposalId": "prop_001",
"status": "accepted",
"outreachId": "out_002",
"acceptedAt": "2026-03-16T08:00:00Z"
},
"error": null,
"metadata": null
}
POST /api/outreach/proposals/:id/reject JWT

Skip a candidate proposal without creating an outreach message

Path parameters

ParameterDescription
idProposal ID

Request body

{
"reason": "Tester has already participated in a similar study."
}

Response

{
"success": true,
"data": {
"proposalId": "prop_001",
"status": "skipped",
"skippedAt": "2026-03-16T08:00:00Z"
},
"error": null,
"metadata": null
}