Scheduling Campaigns

Scheduling Campaigns

A SCHEDULING campaign is designed specifically for booking meetings with candidates. Unlike other campaign types, SCHEDULING campaigns focus solely on getting candidates to book a time slot—no screening questions, no rejection flows.

Overview

SCHEDULING campaigns:

  • Send a booking link to candidates
  • Auto-close when a booking is confirmed (or after 1 week if no booking)
  • Support SMS, WhatsApp, and Email channels
  • Require a calendarMeetingTemplateId for booking configuration

Quick Start

curl -X POST "https://api.joinpopp.com/v1/campaigns" \
  -H "x-api-key: YOUR_API_KEY" \
  -H "x-organization-id: YOUR_ORGANIZATION_ID" \
  -H "Content-Type: application/json" \
  -d '{
    "campaignType": "SCHEDULING",
    "channel": "SMS",
    "campaignTitle": "Interview Scheduling",
    "campaignDescription": "Schedule interviews with engineering candidates",
    "calendarMeetingTemplateId": "a1b2c3d4-e5f6-7890-abcd-ef1234567890",
    "customTemplatedMessage": "Hi {{CANDIDATE_FIRST_NAME}}, please book your interview here: {{MEETING_URL}}. Reply STOP to opt out.",
    "agentName": "Alex",
    "agentTone": "FRIENDLY"
  }'

Note: closingMethod is automatically set to CALENDAR_MEETING_INTEGRATION for SCHEDULING campaigns—you don't need to specify it.


Choosing the AI Agent

There is no agentId field on campaign creation. An agent cannot be referenced by ID — the API resolves one from what else you send:

What you sendWhat Popp does
agentName and agentToneReuses your organization's default agent if both match it; otherwise creates a new agent with that name and tone
NeitherFalls back to your organization's default agent — only if one is configured, otherwise a 404 (see below)

Send both. The fallback depends on your organization having a default agent, and not every organization does — so an integration that relies on it works for some organizations and 404s for others.

The two fields travel together — sending one without the other is a 400:

agentTone is required when agentName is provided
agentName is required when agentTone is provided

The 404 Agent not found trap

Omit agentName and agentTone and there are two ways it can fail, depending on how your organization is set up:

Organization stateResponse
Config exists, but no default agent on it404 Agent not found
No organization config at all404 Organization config not found

Either way the 404 reads like a resource you referenced is missing — a bad campaign or meeting-template ID. It is not. It means no agent could be resolved, and the fix is to add agentName and agentTone (as in Quick Start) — not to hunt for an ID you failed to pass.

For API-led integrations, naming the agent explicitly is the reliable option. agentName takes up to 3 words of Unicode letters; agentTone is one of CASUAL, ENCOURAGING, FRIENDLY, MOTIVATIONAL, NEUTRAL, PROFESSIONAL.


Field Restrictions

SCHEDULING campaigns have specific field restrictions to keep the flow focused on booking.

Disallowed Fields

The following fields are NOT allowed for SCHEDULING campaigns:

FieldReason
questionsNo screening questions—scheduling only
rejectionMessageNo rejection flow for scheduling
closingMessageBooking confirmation serves as the closing message
meetingUrlConflicts with calendarMeetingTemplateId booking URL
customMessageNot applicable for scheduling campaigns
closingMethodAutomatically set to CALENDAR_MEETING_INTEGRATION (ignored if provided)

Example Error Response

If you include a disallowed field:

{
  "error": "closingMessage is not allowed for SCHEDULING campaigns - booking confirmation serves as the closing message"
}

Channel-Specific Rules

WhatsApp

WhatsApp SCHEDULING campaigns require an approved template (openingMessageTemplateId). Custom messages are not allowed.

FieldRequiredNotes
openingMessageTemplateIdRequiredMust reference a SCHEDULING template with {{MEETING_URL}} and STOP keyword
customTemplatedMessage❌ Not allowedWhatsApp requires approved templates

Template Requirements:

  • Template must be of type SCHEDULING
  • Template content must include {{MEETING_URL}} placeholder
  • Template content must include STOP opt-out instruction
  • Template must belong to your organization

Example Request (WhatsApp):

{
  "campaignType": "SCHEDULING",
  "channel": "WHATSAPP",
  "campaignTitle": "Technical Interview",
  "campaignDescription": "Schedule technical interviews",
  "closingMethod": "CALENDAR_MEETING_INTEGRATION",
  "calendarMeetingTemplateId": "a1b2c3d4-e5f6-7890-abcd-ef1234567890",
  "openingMessageTemplateId": "f6a7b8c9-0123-4567-89ab-cdef01234567"
}

SMS

SMS SCHEDULING campaigns require either openingMessageTemplateId OR customTemplatedMessage (not both).

FieldRequiredNotes
openingMessageTemplateIdOne of these requiredMust reference a SCHEDULING template with {{MEETING_URL}} and STOP
customTemplatedMessageOne of these requiredMust include {{MEETING_URL}} placeholder and STOP opt-out instruction

Template Requirements (if using templateId):

  • Template must be of type SCHEDULING
  • Template content must include {{MEETING_URL}} placeholder
  • Template content must include STOP opt-out instruction
  • Template must belong to your organization

Custom Template Requirements (if using customTemplatedMessage):

  • Must include {{MEETING_URL}} placeholder
  • Must include STOP opt-out instruction

Available Placeholders (for SMS and Email)

  • {{CANDIDATE_FIRST_NAME}} - Candidate's first name
  • {{MEETING_URL}} - Booking link (required in message body)
  • {{MEETING_TITLE}} - Meeting title from calendar template
  • {{AGENT_NAME}} - AI agent's name
  • {{JOB_TITLE}} - Job title
  • {{EMPLOYER_NAME}} - Employer name
  • {{LOCATION}} - Job location
  • {{ORGANIZATION_NAME}} - Organization name

Example Request (SMS with Template ID):

{
  "campaignType": "SCHEDULING",
  "channel": "SMS",
  "campaignTitle": "Phone Screen Scheduling",
  "campaignDescription": "Schedule phone screens with candidates",
  "closingMethod": "CALENDAR_MEETING_INTEGRATION",
  "calendarMeetingTemplateId": "b2c3d4e5-f6a7-8901-bcde-f23456789012",
  "openingMessageTemplateId": "0a1b2c3d-4e5f-6789-abcd-ef0123456789"
}

Example Request (SMS with Custom Template):

{
  "campaignType": "SCHEDULING",
  "channel": "SMS",
  "campaignTitle": "Phone Screen Scheduling",
  "campaignDescription": "Schedule phone screens with candidates",
  "closingMethod": "CALENDAR_MEETING_INTEGRATION",
  "calendarMeetingTemplateId": "b2c3d4e5-f6a7-8901-bcde-f23456789012",
  "customTemplatedMessage": "Hi {{CANDIDATE_FIRST_NAME}}, we'd love to chat! Book your interview here: {{MEETING_URL}}\n\nReply STOP to opt out."
}

Email

Email SCHEDULING campaigns require customTemplatedMessage. Template IDs are not supported for Email.

FieldRequiredNotes
customTemplatedMessageRequiredMust include {{MEETING_URL}} placeholder and STOP opt-out instruction
customTemplatedSubjectLineRequiredEmail subject line (supports placeholders)
openingMessageTemplateId❌ Not allowedEmail templates not supported via templateId

Custom Template Requirements:

  • customTemplatedMessage must include {{MEETING_URL}} placeholder
  • customTemplatedMessage must include STOP opt-out instruction
  • customTemplatedSubjectLine is required for Email SCHEDULING campaigns

Note: Email supports the same placeholders as SMS (see Available Placeholders above).

Custom Subject Line (Email only):

You can also specify a custom email subject line using customTemplatedSubjectLine. This field supports the same placeholders as the message body (but none are required).

Example Request (Email with Custom Subject):

{
  "campaignType": "SCHEDULING",
  "channel": "EMAIL",
  "campaignTitle": "Executive Interview",
  "campaignDescription": "Schedule executive interviews",
  "closingMethod": "CALENDAR_MEETING_INTEGRATION",
  "calendarMeetingTemplateId": "c3d4e5f6-a7b8-9012-cdef-345678901234",
  "customTemplatedSubjectLine": "Schedule Your {{MEETING_TITLE}} with {{ORGANIZATION_NAME}}",
  "customTemplatedMessage": "Hello {{CANDIDATE_FIRST_NAME}},\n\nWe're excited to move forward with your application! Please select a time that works for you: {{MEETING_URL}}\n\nLooking forward to speaking with you.\n\nBest regards,\n{{AGENT_NAME}}\n\nReply STOP to unsubscribe."
}

Nudge Settings

You can customize the follow-up nudge timing for any campaign type (not just SCHEDULING) by providing nudgeSettings when creating a campaign.

{
  "campaignType": "SCHEDULING",
  "nudgeSettings": [
    { "delayHours": 12 },
    { "delayHours": 48 }
  ]
}

Each entry in the array represents one follow-up nudge. The delayHours field specifies the wait time since the previous message. The array length determines the total number of nudges.

ConfigurationBehavior
"nudgeSettings": [{"delayHours": 24}, {"delayHours": 48}]2 nudges: first at 24h, second at 48h after the first
"nudgeSettings": []Disables nudging entirely
"nudgeSettings": null (or omitted)Uses default behavior (3 nudges at 24h intervals)
"disableNudging": trueDisables nudging (shortcut for empty array)

Note: You cannot set both disableNudging: true and a non-empty nudgeSettings array. This returns a 400 error.


Default Behaviors

Auto-Close Duration

SCHEDULING campaigns default to 168 hours (1 week) for timeToAutoCloseConversationsInHours if not specified.

Note: If a candidate books a meeting, the conversation closes immediately upon booking confirmation. The 1-week timeout only applies if no booking is made.

Calendar Meeting Template

A calendarMeetingTemplateId is required for SCHEDULING campaigns. You can provide it:

  1. On the campaign - All conversations use this template
  2. On each conversation - Override the campaign-level template per conversation

If neither is provided, the API returns an error:

{
  "message": "calendarMeetingTemplateId is required for SCHEDULING campaigns. Provide it on the campaign or in the conversation payload."
}

Opening Message Override

The openingMessage field is not supported for SCHEDULING campaigns at the conversation level. This is because SCHEDULING campaigns require variable substitution (e.g., {{MEETING_URL}}, {{CANDIDATE_FIRST_NAME}}), which is only processed for campaign-level customTemplatedMessage.

To customize messages for SCHEDULING campaigns, use customTemplatedMessage and customTemplatedSubjectLine when creating the campaign.


Validation Summary

ChannelcustomTemplatedMessageopeningMessageTemplateIdcustomTemplatedSubjectLine
WhatsApp❌ Not allowedRequired (must include {{MEETING_URL}} and STOP)❌ Not applicable
SMSOne of these required (must include {{MEETING_URL}} and STOP)One of these required❌ Not applicable
EmailRequired (must include {{MEETING_URL}} and STOP)❌ Not allowedRequired

The STOP opt-out requirement

Every SCHEDULING customTemplatedMessage must contain a STOP opt-out instruction, on both SMS and Email. This is a hard validation — the literal word STOP has to appear in the message text. Omitting it returns 400:

{
  "message": "customTemplatedMessage must include STOP opt-out instruction for SCHEDULING campaigns"
}

A trailing Reply STOP to opt out. satisfies it. The check matches the whole word STOP case-sensitively, so lowercase "stop" in ordinary prose does not count.

Templates referenced by openingMessageTemplateId must carry {{MEETING_URL}} and a STOP instruction in their own content.


Complete Example

Create a SCHEDULING Campaign (SMS)

curl -X POST "https://api.joinpopp.com/v1/campaigns" \
  -H "x-api-key: YOUR_API_KEY" \
  -H "x-organization-id: YOUR_ORGANIZATION_ID" \
  -H "Content-Type: application/json" \
  -d '{
    "campaignType": "SCHEDULING",
    "channel": "SMS",
    "campaignTitle": "Engineering Interview",
    "campaignDescription": "Schedule interviews for senior engineering roles",
    "closingMethod": "CALENDAR_MEETING_INTEGRATION",
    "calendarMeetingTemplateId": "d4e5f6a7-b8c9-0123-def4-567890123456",
    "agentName": "Sarah",
    "agentTone": "FRIENDLY"
  }'

Create a Conversation

curl -X POST "https://api.joinpopp.com/v1/conversations" \
  -H "x-api-key: YOUR_API_KEY" \
  -H "x-organization-id: YOUR_ORGANIZATION_ID" \
  -H "Content-Type: application/json" \
  -d '{
    "campaignId": "campaign-id-from-above",
    "phoneNumber": "+14155551234",
    "firstName": "John",
    "lastName": "Doe"
  }'

Related Guides


Did this page help you?