---
title: "Campaign status — Campaigns for Laravel | Roundly"
description: "The CampaignStatus lifecycle from Created to a terminal state, the event each transition fires, and the enum helpers."
url: https://roundly-consulting.com/open-source/docs/campaigns-for-laravel/campaign-status
language: en
---

[All packages](https://roundly-consulting.com/open-source.md)

[Campaigns for Laravel](https://roundly-consulting.com/open-source/docs/campaigns-for-laravel.md)

# Campaign status

Every campaign moves through the CampaignStatus enum. Each transition fires a lifecycle event — but only when the status actually changes, so repeated calls never re-dispatch:

| Status | Reached when | Event |
| --- | --- | --- |
| `Created` | The default status of a new Campaign object. | — |
| `Pending` | prepare() opened the job batch and stored the recipients; nothing is sent yet. | `CampaignPrepared` |
| `Processing` | start() won the move from Pending and queued the recipient jobs; startedAt is set. | `CampaignStarted` |
| `Completed` | Every delivery job ran — some may have failed — or there was nobody to send to. | `CampaignCompleted` |
| `Failed` | Every delivery job ran and not one delivery got through. | `CampaignFailed` |
| `Canceled` | cancel() cancelled the batch. | `CampaignCancelled` |

startedAt is set on the first switch to Processing, endedAt on the first terminal status. Completed, Failed and Canceled are terminal and final — a cancelled campaign stays Canceled when its batch finishes. Every transition is a compare-and-set on the stored status, so two processes racing one campaign never both move it.

## Enum helpers

CampaignStatus is string-backed — each value equals its case name — and adds isTerminal() on top of the enums-for-laravel Helpers trait:

```php
use RoundlyConsulting\Campaigns\Enums\CampaignStatus;

CampaignStatus::Processing->isTerminal();   // false
CampaignStatus::Canceled->isTerminal();     // true — Completed, Failed and Canceled are terminal

CampaignStatus::values();                   // Collection of 'Created', 'Pending', 'Processing', …
CampaignStatus::toOptions();                // Collection: ['Created' => 'Created', …] for selects
CampaignStatus::validationRule();           // 'in:Created,Pending,Processing,Completed,Failed,Canceled'
CampaignStatus::tryFromName('Pending');     // CampaignStatus::Pending
CampaignStatus::hasValue('Failed');         // true
CampaignStatus::Completed->label();         // 'Completed'
```

The trait also brings labels(), options(), readable() and the other case lookups such as tryFromName() and hasValue(). validationRule() drops straight into a form request when you filter campaigns by status.

## Show your open-source love

This package is free and MIT-licensed. If it saves you time, a one-off donation or a Patreon membership keeps it maintained, tested and documented.

[More ways to support, including crypto](https://roundly-consulting.com/support-us.md)

By donating, you agree to our [donation terms](https://roundly-consulting.com/donation-terms.md).

[Support our open source work (opens in a new tab)](https://donate.stripe.com/dRmeVe8FX5PF1Qd9pXcEw00) [Join us on Patreon (opens in a new tab)](https://www.patreon.com/cw/roundly)

## Want this built into your product?

We integrate our packages into custom Laravel and AI builds. Tell us what you're working on and we'll reply within 48 hours.

[Get a quote in 48 hours](https://roundly-consulting.com/contact.md) [Browse all packages](https://roundly-consulting.com/open-source/docs/campaigns-for-laravel.md)
