Surge

Fixing a Rejected or Changes-Needed Campaign

Campaign reviews are done by human reviewers, not automated systems. When they need something from you, the campaign status changes to changes_needed or rejected. Here's how to read the feedback and get your campaign approved.

Campaign status lifecycle

stateDiagram-v2
  [*] --> created
  created --> pending
  pending --> in_review
  in_review --> active
  in_review --> changes_needed
  in_review --> rejected
  changes_needed --> pending : resubmit

The diagram shows the typical review lifecycle. deactivated and canceled are administrative states reachable from active (and earlier states for canceled); see the list below.

  • created: you submitted the campaign, Surge has received it
  • pending: queued for submission to the carrier network
  • in_review: actively being reviewed by TCR and carrier reviewers
  • active: approved; you can attach phone numbers and send production traffic
  • changes_needed: reviewer flagged issues; you need to update and resubmit
  • rejected: campaign was rejected; see notes on appealing below
  • deactivated: previously active campaign suspended by carrier
  • canceled: you or Surge canceled the campaign
Note

API status values. The campaign status field in API responses uses a condensed set of public values: created, in_review, active, rejected, canceled, deactivated. Both the pending and in_review internal states surface as "in_review" in the API. Both the changes_needed and rejected internal states surface as "rejected". Keep this in mind when polling for status or using the update table below.

Understanding "changes needed" feedback

Tip

When a campaign moves to changes_needed, Surge sends you an email with reviewer notes. Read it carefully — reviewers include specific details about what needs to change.

Common patterns and what they mean:

Reviewer saysWhat to fix
"The website doesn't give much info"Add clear business description and contact information to your homepage
"The opt-in page doesn't show required disclosures"Add message frequency notice, "Msg&data rates apply", and "Reply STOP to opt out" next to the opt-in checkbox
"The sample message contains placeholder text"Replace {brand name}, {Agent Name}, etc. with actual values
"The privacy policy is behind a login"Move the privacy policy to a publicly accessible URL
"Your business email doesn't match the domain"Use an email at your business domain, not a personal or generic address

Updating a campaign

To address feedback, update the relevant campaign fields and resubmit. Campaigns can only be updated in certain statuses:

Status (API value)Can update?
createdYes
in_reviewUsually no: returns campaign_locked (409) once a reviewer picks it up. A brief window exists while the campaign is still queued (internally pending) before review begins.
rejectedYes, both "changes needed" and hard-rejected campaigns can be updated.
canceledYes
activeNo: returns campaign_locked (409)
deactivatedNo: returns campaign_locked (409)

If you try to update while in_review, wait for the review to complete. The reviewer will either approve it, request changes (moving it to changes_needed), or reject it. Only then can you update.

Important

The campaign update endpoint requires the full field set, not a partial body. Send consent_flow, description, message_samples (≥2 items), privacy_policy_url, terms_and_conditions_url, use_cases, and volume together. Missing any field returns a validation_error.

from surge import Surge

surge = Surge()  # reads SURGE_API_KEY from environment

campaign = surge.campaigns.update(
    "{campaign_id}",
    consent_flow=(
        "Users enter their phone number during checkout. An unchecked checkbox "
        'labeled "I agree to receive text messages from Acme Corp" is present. '
        'Required disclosures are shown: "Message frequency varies. Msg&data '
        'rates apply. Reply STOP to opt out. View our Privacy Policy at '
        'acme.com/privacy."'
    ),
    message_samples=[
        "Acme Corp: Your order #12345 has shipped! Track it: https://acme.com/track",
        "Acme Corp: Your cart is waiting. Complete your order: https://acme.com/cart. Reply STOP to opt out.",
    ],
    description="Marketing messages to opted-in customers",
    privacy_policy_url="https://acme.com/privacy",
    terms_and_conditions_url="https://acme.com/terms",
    use_cases=["marketing"],
    volume="low",
)

print(campaign.status)  # "in_review"

After updating a changes_needed, rejected, or canceled campaign, the campaign moves back to pending and then in_review.

Checking campaign status

Poll the campaign endpoint to track the current status:

from surge import Surge

surge = Surge()
campaign = surge.campaigns.retrieve("{campaign_id}")
print(campaign.status)
{
  "id": "cpn_01jrzhe8d9enptypyx360pcmxl",
  "status": "in_review",
  "use_cases": ["marketing"],
  "volume": "low"
}

Or subscribe to the campaign.approved webhook event to get notified the moment a campaign goes active. This avoids polling. See Webhook Events.

Rejected campaigns

Important

A rejected status is more serious than changes_needed. Unlike changes_needed, a rejection doesn't automatically move the campaign back into the queue when you update it — you may need to create a new campaign entirely. Rejections related to spam or misuse may also affect your account's ability to register future campaigns.

If your campaign is rejected:

Read the rejection notice carefully

Reviewers include the specific reason. Don't guess.

Address every listed issue before doing anything else

Partial fixes typically lead to another rejection.

Contact Surge support

Confirm whether to resubmit the existing campaign or start a new one — the right move depends on the reason.

Make sure your opt-in flow, sample messages, and business identity are solid before resubmitting. If you're unsure what went wrong, Avoiding Rejection covers the seven most common patterns.