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. CREATED2. QUEUED3. ONGOING4. Final Status

StageWhat Happens
CREATEDConversation is created and queued for delivery
QUEUEDWaiting to start (e.g., if another active conversation exists with this participant)
ONGOINGMessage delivered, AI agent is actively conversing with the candidate
FinalConversation ends with one of the completion statuses below

Note: A conversation can transition to DELIVERY_FAILED at any point before ONGOING if the message can't be delivered.

Conversation Statuses

StatusDescription
CREATEDConversation created, waiting to be sent
QUEUEDWaiting to start (e.g., another conversation with same participant is active)
ONGOINGActive conversation in progress
COMPLETED_SCREENING_PASSEDCandidate completed all screening questions successfully
COMPLETED_SCREENING_FAILEDCandidate did not meet screening criteria
CLOSEDConversation closed (timeout or manual)
OPTED_OUTCandidate opted out of communication
DELIVERY_FAILEDInitial message could not be delivered

Creating a Conversation

To start a conversation with a candidate, you need:

  1. A Campaign ID from an active campaign
  2. 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

FieldTypeRequiredDescription
campaignIdstringYes*The Popp campaign ID
externalCampaignIdstringYes*Your external campaign reference, e.g., your job ID (alternative to campaignId)
firstNamestringYesCandidate's first name
lastNamestringNoCandidate's last name
phoneNumberstringYes**Phone number in E.164 format (e.g., +14155551234)
emailAddressstringYes**Email address (for email-based campaigns)
externalIdstringNoYour external reference ID for this conversation
shouldSendDuringBusinessHoursbooleanNoSchedule message for business hours
openingMessagestringNoCustom opening message (max 600 chars, SMS requires "STOP", not for WhatsApp)
additionalContextstringNoCustom context for the AI agent to use during this conversation (see below)
skipDuplicationCheckbooleanNoClose ongoing conversation in same campaign and create new (see below)
closePreviousConversationsbooleanNoClose 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

ParameterScopeBehaviorUse Case
skipDuplicationCheckSame campaignCloses ongoing conversation in the same campaign, then creates new oneRe-engaging a candidate in the same campaign (e.g., retry after failed delivery)
closePreviousConversationsAll campaignsCloses ongoing conversations in any campaign on the same channelStarting fresh outreach, ensuring no queuing across campaigns

Example: skipDuplicationCheck

Use 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)

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)

{
  "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 closePreviousConversations is set to true, the new conversation is created immediately and returned in the API response. The closing of previous conversations happens asynchronously in messaging-service right 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 to COMPLETED).

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:

ScenarioStatusMessage
SMS missing STOP keyword400 Bad RequestOpening message must include the 'STOP' keyword for opt-out compliance
Message exceeds length limit400 Bad RequestOpening 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:

  1. Organization-level (global context for all conversations)
  2. Campaign-level (specific to this campaign's job/role)
  3. Conversation-level (the additionalContext you 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 delivered
  • CONVERSATION_COMPLETED - Screening complete
  • CONVERSATION_NEEDS_REVIEW - Requires attention

API Reference

Next Steps