Email distribution
Send tracked survey invitations to your own contact list. Each recipient gets a unique tokenized link, and you can monitor delivery, clicks, and completions per person.
Creating an email list
An email list ties a set of recipients to a survey. Create one by providing emails inline or by referencing a saved custom panel.
From inline emails
curl -X POST https://surveys.flashpoint.ai/api/v1/surveys/{survey_id}/email-lists \
-H "X-Service-Token: $TOKEN" \
-H "X-Team-ID: $TEAM_ID" \
-H "X-User-ID: $USER_ID" \
-H "Content-Type: application/json" \
-d '{
"name": "Q4 Customer Feedback",
"emails": [
{"email": "anna@example.com", "name": "Anna Chen"},
{"email": "bob@example.com", "name": "Bob Patel"},
{"email": "carol@example.com", "segment": "enterprise"}
]
}'
Response:
{
"id": "el_a1b2c3d4-...",
"survey_id": "srv_...",
"name": "Q4 Customer Feedback",
"total_count": 3,
"sent_count": 0,
"validation_status": "pending",
"sending_status": "draft",
"source_panel_id": null,
"email_template": null,
"created_at": "2026-05-26T14:00:00Z"
}
Each recipient object requires an email field. Additional metadata fields (name, segment, or any custom key) are stored and can be used for personalization or downstream analysis.
Duplicate emails within a list are silently skipped.
From a custom panel
curl -X POST https://surveys.flashpoint.ai/api/v1/surveys/{survey_id}/email-lists \
-H "X-Service-Token: $TOKEN" \
-H "X-Team-ID: $TEAM_ID" \
-H "X-User-ID: $USER_ID" \
-H "Content-Type: application/json" \
-d '{
"panel_id": "pnl_f5e6d7c8-..."
}'
The list inherits all contacts from the panel. Changes to the panel after creation do not affect the list.
Via the agent
"Create an email list for my NPS survey with anna@example.com and bob@example.com"
The agent calls create_email_list with the emails you provide. It will never invent or guess email addresses.
Custom panels
A custom panel is a reusable contact list that lives at the team level and can be used across multiple surveys.
Create a panel
curl -X POST https://surveys.flashpoint.ai/api/v1/panels/custom \
-H "X-Service-Token: $TOKEN" \
-H "X-Team-ID: $TEAM_ID" \
-H "X-User-ID: $USER_ID" \
-H "Content-Type: application/json" \
-d '{
"name": "Beta Testers",
"description": "Early access program members",
"emails": [
{"email": "tester1@example.com", "name": "Alice"},
{"email": "tester2@example.com", "name": "Bob"}
],
"tags": ["beta", "product"]
}'
Response:
{
"id": "pnl_f5e6d7c8-...",
"name": "Beta Testers",
"description": "Early access program members",
"total_count": 2,
"tags": ["beta", "product"],
"created_at": "2026-05-26T14:00:00Z"
}
List panels
curl https://surveys.flashpoint.ai/api/v1/panels/custom?limit=50&offset=0 \
-H "X-Service-Token: $TOKEN" \
-H "X-Team-ID: $TEAM_ID" \
-H "X-User-ID: $USER_ID"
Via the agent
"Create a custom panel called 'Q4 Enterprise Clients' with these emails: ..."
The agent calls create_custom_panel and returns the panel ID for future use.
Email template
Every send uses a template with three fields:
| Field | Description | Default |
|---|---|---|
subject | Email subject line (max 65 chars recommended) | You're invited: {{SURVEY_NAME}} |
body | Plain-text body; must contain {{SURVEY_LINK}} | Generic invitation text |
cta_text | Call-to-action button label (2-4 words) | Take the Survey |
Supported placeholders
| Placeholder | Substituted with |
|---|---|
{{SURVEY_LINK}} | Personalized survey URL with recipient token (required) |
{{SURVEY_NAME}} | Survey title |
{{RECIPIENT_EMAIL}} | Recipient's email address |
{{SENDER_NAME}} | From name (default: "Flashpoint Surveys") |
AI-drafted templates
The agent can draft or rewrite invitation copy using the compose_email_template tool. It reads the survey's name, audience, objective, and estimated length to generate contextual copy.
"Draft a casual, friendly invitation email for this survey"
"Make the email shorter and mention the $10 incentive"
The tool returns a {subject, body, cta_text} object that you can pass directly to the send call. It does not save or send anything on its own.
Attaching a template at list creation
You can save a template on the email list at creation time:
curl -X POST https://surveys.flashpoint.ai/api/v1/surveys/{survey_id}/email-lists \
-H "X-Service-Token: $TOKEN" \
-H "X-Team-ID: $TEAM_ID" \
-H "X-User-ID: $USER_ID" \
-H "Content-Type: application/json" \
-d '{
"name": "Launch Invite",
"emails": [{"email": "user@example.com"}],
"email_template": {
"subject": "Quick 3-minute survey about your experience",
"body": "Hi there,\n\nWe value your feedback. This takes about 3 minutes.\n\n{{SURVEY_LINK}}\n\nThanks!",
"cta_text": "Share your feedback"
}
}'
The saved template is used as the default for sends and resends unless overridden.
Sending
Trigger delivery of an email list. The survey must be active (published) before sending. This action is irreversible.
curl -X POST https://surveys.flashpoint.ai/api/v1/surveys/{survey_id}/email-lists/{list_id}/send \
-H "X-Service-Token: $TOKEN" \
-H "X-Team-ID: $TEAM_ID" \
-H "X-User-ID: $USER_ID" \
-H "Content-Type: application/json" \
-d '{
"base_survey_url": "https://flashpointopinions.com/{survey_id}"
}'
Response:
{
"id": "el_a1b2c3d4-...",
"survey_id": "srv_...",
"name": "Q4 Customer Feedback",
"total_count": 3,
"sent_count": 3,
"validation_status": "validated",
"sending_status": "sent",
"source_panel_id": null,
"email_template": null,
"created_at": "2026-05-26T14:00:00Z"
}
What happens during a send
- ZeroBounce validation — every recipient email is validated. Invalid, disposable, and risky addresses are skipped.
- Rate-limited delivery — emails are sent through SendGrid at 10/second to avoid spam-filter triggers.
- Token generation — each recipient gets a unique token appended to the survey URL so the response ties back to them.
- Bounce handling — hard bounces are flagged; soft bounces are retried.
Overriding the template for one send
Pass email_template in the send body to override the saved template for this send only:
curl -X POST https://surveys.flashpoint.ai/api/v1/surveys/{survey_id}/email-lists/{list_id}/send \
-H "X-Service-Token: $TOKEN" \
-H "X-Team-ID: $TEAM_ID" \
-H "X-User-ID: $USER_ID" \
-H "Content-Type: application/json" \
-d '{
"base_survey_url": "https://flashpointopinions.com/{survey_id}",
"email_template": {
"subject": "Last chance: share your feedback",
"body": "Hi,\n\nThis is your final reminder.\n\n{{SURVEY_LINK}}\n\nThank you!",
"cta_text": "Take the survey now"
}
}'
Via the agent
"Send the email list to my survey recipients"
The agent calls send_email_list. Because sending is destructive (emails go out immediately), the agent presents an approval card before executing.
Tracking
Per-recipient status
curl "https://surveys.flashpoint.ai/api/v1/surveys/{survey_id}/email-lists/{list_id}/recipients?page=1&per_page=50" \
-H "X-Service-Token: $TOKEN" \
-H "X-Team-ID: $TEAM_ID" \
-H "X-User-ID: $USER_ID"
Response:
{
"recipients": [
{
"id": "rec_...",
"email": "anna@example.com",
"status": "completed",
"validation_status": "valid",
"sent_at": "2026-05-26T14:05:00Z",
"last_sent_at": "2026-05-26T14:05:00Z",
"send_count": 1,
"started_at": "2026-05-26T15:10:00Z",
"completed_at": "2026-05-26T15:14:00Z"
}
],
"total": 3,
"page": 1,
"per_page": 50
}
Filter by status with the status query parameter:
# Only recipients who haven't completed
curl "...?status=sent"
Recipient lifecycle
pending --> sent --> clicked --> completed
\-> bounced
| Status | Meaning |
|---|---|
pending | Added to list, not yet sent |
sent | Email delivered |
clicked | Recipient opened the survey link |
completed | Survey response submitted |
bounced | Delivery failed (hard or soft bounce) |
Summary statistics
curl "https://surveys.flashpoint.ai/api/v1/surveys/{survey_id}/email-lists/{list_id}/stats" \
-H "X-Service-Token: $TOKEN" \
-H "X-Team-ID: $TEAM_ID" \
-H "X-User-ID: $USER_ID"
Response:
{
"total": 100,
"pending": 5,
"sent": 30,
"started": 15,
"completed": 45,
"bounced": 5
}
Resending
Send reminders to recipients who have not completed the survey.
curl -X POST https://surveys.flashpoint.ai/api/v1/surveys/{survey_id}/email-lists/{list_id}/resend \
-H "X-Service-Token: $TOKEN" \
-H "X-Team-ID: $TEAM_ID" \
-H "X-User-ID: $USER_ID" \
-H "Content-Type: application/json" \
-d '{
"base_survey_url": "https://flashpointopinions.com/{survey_id}",
"filter": "non_complete"
}'
Filter options
| Filter | Recipients included |
|---|---|
non_complete | Everyone who has not completed (pending + sent + started + bounced). Default. |
pending | Only recipients whose email was never sent |
sent | Only recipients who received the email but have not started |
specific | Only the recipient_ids you specify |
Specific-recipient resend
curl -X POST https://surveys.flashpoint.ai/api/v1/surveys/{survey_id}/email-lists/{list_id}/resend \
-H "X-Service-Token: $TOKEN" \
-H "X-Team-ID: $TEAM_ID" \
-H "X-User-ID: $USER_ID" \
-H "Content-Type: application/json" \
-d '{
"base_survey_url": "https://flashpointopinions.com/{survey_id}",
"filter": "specific",
"recipient_ids": ["rec_abc123", "rec_def456"]
}'
Resends reuse existing tokens (same survey link per recipient) and skip ZeroBounce re-validation.
Via the agent
"Resend the invitation to everyone who hasn't completed yet"
Adding recipients
Append new contacts to an existing email list after the initial send.
curl -X POST https://surveys.flashpoint.ai/api/v1/surveys/{survey_id}/email-lists/{list_id}/recipients \
-H "X-Service-Token: $TOKEN" \
-H "X-Team-ID: $TEAM_ID" \
-H "X-User-ID: $USER_ID" \
-H "Content-Type: application/json" \
-d '{
"emails": [
{"email": "newuser@example.com", "name": "New User"}
]
}'
Response:
{
"list_id": "el_a1b2c3d4-...",
"added": 1,
"skipped_duplicates": 0,
"total_count": 4
}
New recipients are automatically validated and sent using the same pipeline as the initial send. Emails that already exist on the list are silently skipped (case-insensitive match).
Platform email
The send_platform_email tool sends platform-generated files (survey exports, reports, CSV data) to stakeholders. This is not a survey invitation — it is for sharing deliverables.
Requirements
- At least one attachment is required (an
s3_keyfrom a priorexport_csv,export_docx, orexport_pdfcall). - Maximum 10 recipients (to + cc combined).
- Maximum 5 attachments, 25 MB total.
- Recipients are validated via ZeroBounce before sending.
Via the agent
"Email the CSV export of this survey to stakeholder@company.com"
The agent first runs the export, captures the S3 key, then calls send_platform_email with the attachment. An approval card is presented before sending.
Next steps
- See the overview of all channels: Distribute.
- Analyze incoming responses: Analyze.
- Check response quality: Data quality.