Conversations
Understanding Conversations
A Conversation represents an individual interaction between your AI agent and a candidate. Every conversation belongs to a Campaign and inherits its configuration.
Conversation Lifecycle
A conversation progresses through the following stages:
1. CREATED → 2. QUEUED → 3. ONGOING → 4. Final Status
| Stage | What Happens |
|---|---|
| CREATED | Conversation is created and queued for delivery |
| QUEUED | Waiting to start (e.g., if another active conversation exists with this participant) |
| ONGOING | Message delivered, AI agent is actively conversing with the candidate |
| Final | Conversation ends with one of the completion statuses below |
Note: A conversation can transition to
DELIVERY_FAILEDat any point beforeONGOINGif the message can't be delivered.
Conversation Statuses
| Status | Description |
|---|---|
CREATED | Conversation created, waiting to be sent |
QUEUED | Waiting to start (e.g., another conversation with same participant is active) |
ONGOING | Active conversation in progress |
COMPLETED_SCREENING_PASSED | Candidate completed all screening questions successfully |
COMPLETED_SCREENING_FAILED | Candidate did not meet screening criteria |
CLOSED | Conversation closed (timeout or manual) |
OPTED_OUT | Candidate opted out of communication |
DELIVERY_FAILED | Initial message could not be delivered |
Creating a Conversation
To start a conversation with a candidate, you need:
- A Campaign ID from an active campaign
- The candidate's contact information
Basic Request
curl -X POST "https://api.popp.ai/v1/conversations" \
-H "x-api-key: YOUR_API_KEY" \
-H "x-organization-id: YOUR_ORGANIZATION_ID" \
-H "Content-Type: application/json" \
-d '{
"campaignId": "10fe477c-5a4a-451d-9f18-b8340e2154e8",
"firstName": "John",
"phoneNumber": "+14155551234"
}'Request Fields
| Field | Type | Required | Description |
|---|---|---|---|
campaignId | string | Yes* | The Popp campaign ID |
externalCampaignId | string | Yes* | Your external campaign reference, e.g., your job ID (alternative to campaignId) |
firstName | string | Yes | Candidate's first name |
lastName | string | No | Candidate's last name |
phoneNumber | string | Yes** | Phone number in E.164 format (e.g., +14155551234) |
emailAddress | string | Yes** | Email address (for email-based campaigns) |
externalId | string | No | Your external reference ID for this conversation |
shouldSendDuringBusinessHours | boolean | No | Schedule message for business hours |
openingMessage | string | No | Custom opening message (max 600 chars, SMS requires "STOP", not for WhatsApp) |
additionalContext | string | No | Custom context for the AI agent to use during this conversation (see below) |
skipDuplicationCheck | boolean | No | Close ongoing conversation in same campaign and create new (see below) |
closePreviousConversations | boolean | No | Close ongoing conversations across all campaigns on same channel (SMS, WhatsApp, Email) (see below) |
*Either campaignId or externalCampaignId is required
**Required based on campaign channel (SMS/WhatsApp needs phone, Email needs email)
Using External IDs
You can use your own identifiers to reference campaigns and track conversations:
curl -X POST "https://api.popp.ai/v1/conversations" \
-H "x-api-key: YOUR_API_KEY" \
-H "x-organization-id: YOUR_ORGANIZATION_ID" \
-H "Content-Type: application/json" \
-d '{
"externalCampaignId": "your-ats-job-id-123",
"firstName": "John",
"phoneNumber": "+14155551234",
"externalId": "your-candidate-id-456"
}'The externalId will be included in webhook events, making it easy to correlate Popp conversations with your system.
Listing Conversations
List All Conversations
curl -X GET "https://api.popp.ai/v1/conversations" \
-H "x-api-key: YOUR_API_KEY" \
-H "x-organization-id: YOUR_ORGANIZATION_ID"Filter by Campaign
curl -X GET "https://api.popp.ai/v1/conversations?campaignId=10fe477c-5a4a-451d-9f18-b8340e2154e8" \
-H "x-api-key: YOUR_API_KEY" \
-H "x-organization-id: YOUR_ORGANIZATION_ID"Filter by Status
curl -X GET "https://api.popp.ai/v1/conversations?status=COMPLETED_SCREENING_PASSED" \
-H "x-api-key: YOUR_API_KEY" \
-H "x-organization-id: YOUR_ORGANIZATION_ID"Filter by Phone Number
curl -X GET "https://api.popp.ai/v1/conversations?phoneNumber=%2B14155551234" \
-H "x-api-key: YOUR_API_KEY" \
-H "x-organization-id: YOUR_ORGANIZATION_ID"Conversation Response
{
"id": "conv_abc123",
"organizationId": "org_123456",
"campaignId": "10fe477c-5a4a-451d-9f18-b8340e2154e8",
"participantFirstName": "John",
"participantLastName": "Doe",
"participantPhoneNumber": "+14155551234",
"participantEmailAddress": "[email protected]",
"conversationStatus": "COMPLETED_SCREENING_PASSED",
"needsReview": false,
"isHumanTakeover": false,
"messagesCount": 12,
"repliesCount": 5,
"scorecardTotalValue": 85,
"screeningQuestionsOutcome": [
{
"screeningQuestion": "Do you have 5+ years of experience with React?",
"responseSummary": "Yes, 7 years of experience",
"questionOutcome": "PASSED"
}
],
"createdAt": "2024-01-15T10:00:00.000Z",
"sentAt": "2024-01-15T10:00:05.000Z",
"completedAt": "2024-01-15T10:30:00.000Z",
"timeToFirstResponse": 120,
"timeToComplete": 1800
}Conversation Messages
Retrieve the message history for a conversation:
curl -X GET "https://api.popp.ai/v1/conversations/{conversationId}/messages" \
-H "x-api-key: YOUR_API_KEY" \
-H "x-organization-id: YOUR_ORGANIZATION_ID"Pagination
# Get messages with pagination
curl -X GET "https://api.popp.ai/v1/conversations/{conversationId}/messages?limit=20&sortDirection=ASC" \
-H "x-api-key: YOUR_API_KEY" \
-H "x-organization-id: YOUR_ORGANIZATION_ID"Conversation Documents
Candidates can share documents during conversations (e.g., resumes, certificates). Retrieve them:
curl -X GET "https://api.popp.ai/v1/conversations/{conversationId}/documents" \
-H "x-api-key: YOUR_API_KEY" \
-H "x-organization-id: YOUR_ORGANIZATION_ID"Best Practices
1. Use External IDs
Always provide externalId and externalCampaignId to easily correlate Popp data with your systems:
{
"campaignId": "...",
"firstName": "John",
"phoneNumber": "+14155551234",
"externalId": "candidate-123",
"externalCampaignId": "job-456"
}2. Handle Duplicate Conversations
By default, Popp prevents duplicate conversations with the same participant in the same campaign. There are two parameters that modify this behavior:
skipDuplicationCheck vs closePreviousConversations
skipDuplicationCheck vs closePreviousConversations| Parameter | Scope | Behavior | Use Case |
|---|---|---|---|
skipDuplicationCheck | Same campaign | Closes ongoing conversation in the same campaign, then creates new one | Re-engaging a candidate in the same campaign (e.g., retry after failed delivery) |
closePreviousConversations | All campaigns | Closes ongoing conversations in any campaign on the same channel | Starting fresh outreach, ensuring no queuing across campaigns |
Example: skipDuplicationCheck
skipDuplicationCheckUse when you want to restart a conversation in the same campaign:
{
"campaignId": "campaign-A",
"firstName": "John",
"phoneNumber": "+14155551234",
"skipDuplicationCheck": true
}If John has an ongoing conversation in campaign-A, it will be closed and a new one created. However, if John has an ongoing conversation in campaign-B, this new conversation will be queued behind it.
Example: closePreviousConversations (SMS/WhatsApp)
closePreviousConversations (SMS/WhatsApp)Use when you want to ensure the new conversation starts immediately, regardless of other campaigns:
{
"campaignId": "campaign-A",
"firstName": "John",
"phoneNumber": "+14155551234",
"closePreviousConversations": true
}The new conversation is created immediately. All ongoing SMS/WhatsApp conversations with John (across all campaigns) will be closed asynchronously before the first outgoing message is sent.
Example: closePreviousConversations (Email)
closePreviousConversations (Email){
"campaignId": "campaign-A",
"firstName": "John",
"emailAddress": "[email protected]",
"closePreviousConversations": true
}The new conversation is created immediately. All ongoing Email conversations with [email protected] (across all campaigns) will be closed asynchronously before the first outgoing message is sent.
Note: When
closePreviousConversationsis set totrue, the new conversation is created immediately and returned in the API response. The closing of previous conversations happens asynchronously inmessaging-serviceright before the first outgoing message is sent. This applies to SMS, WhatsApp, and Email channels. All ongoing conversations with the same contact identifier (phone number for SMS/WhatsApp, email address for Email) on the same channel will be closed (status set toCOMPLETED).
3. Schedule for Business Hours
For better response rates, schedule messages during business hours:
{
"campaignId": "...",
"firstName": "John",
"phoneNumber": "+14155551234",
"shouldSendDuringBusinessHours": true
}The timezone is automatically inferred from the phone number.
4. Custom Opening Message
You can override the campaign's default opening message with a custom one:
{
"campaignId": "...",
"firstName": "John",
"phoneNumber": "+14155551234",
"openingMessage": "Hi John! We saw your application for the Software Engineer role. Are you still interested? Reply STOP to opt out."
}Requirements:
- Maximum 600 characters
- SMS campaigns: Must include the word "STOP" (uppercase) for opt-out compliance
- Email campaigns: Supported with no additional restrictions
- WhatsApp campaigns: Not supported (returns 400 error)
Error Responses:
| Scenario | Status | Message |
|---|---|---|
| SMS missing STOP keyword | 400 Bad Request | Opening message must include the 'STOP' keyword for opt-out compliance |
| Message exceeds length limit | 400 Bad Request | Opening message must be 600 characters or less |
5. Additional Context
You can provide conversation-specific context that the AI agent will use when generating replies. This context is combined with any campaign-level and organization-level context already configured.
{
"campaignId": "...",
"firstName": "John",
"phoneNumber": "+14155551234",
"additionalContext": "John previously expressed interest in remote positions. He has 5 years of Python experience and is currently based in London."
}Use Cases:
- Passing candidate-specific information from your ATS or CRM
- Providing details about prior interactions with the candidate
- Including relevant notes that should influence the AI agent's responses
Context Hierarchy: The AI agent uses context from multiple sources, in this order:
- Organization-level (global context for all conversations)
- Campaign-level (specific to this campaign's job/role)
- Conversation-level (the
additionalContextyou provide via API)
All context sources are combined to give the AI agent a complete picture when generating replies.
6. Listen to Webhooks
Instead of polling, use webhooks to get real-time notifications when conversations complete:
CONVERSATION_STARTED- First message deliveredCONVERSATION_COMPLETED- Screening completeCONVERSATION_NEEDS_REVIEW- Requires attention
API Reference
- Create Conversation - Create a new conversation
- Get Conversation - Get conversation details
- List Conversations - Query and filter conversations
- List Conversation Messages - Get message history
- List Conversation Documents - Get shared documents
Next Steps
- Documents - Handle documents shared by candidates
- Scheduling - Create conversations that book meetings
- Webhooks - Get real-time updates on conversation events
- Understanding Campaigns - Learn more about campaign configuration
Updated about 14 hours ago