> ## Documentation Index
> Fetch the complete documentation index at: https://docs.pushctl.com/llms.txt
> Use this file to discover all available pages before exploring further.

# Laravel message options

> Build visible and data-only Pushctl messages with delivery and platform options.

## Content and data

```php theme={null}
$message = PushctlMessage::create('Order ready', 'Collect before 18:00')
    ->imageUrl('https://cdn.example.com/orders/ready.png')
    ->actionUrl('myapp://orders/123')
    ->with('order_id', 123)
    ->with('source', 'fulfilment');
```

Use `data([...])` to replace the whole data object. A data-only message can omit both title and body when data is not empty.

## Delivery options

| Builder                 | API option           | Constraint                     |
| ----------------------- | -------------------- | ------------------------------ |
| `ttl($seconds)`         | `ttl`                | 0 through 2,419,200            |
| `priority('high')`      | `priority`           | `normal` or `high`             |
| `collapseId($id)`       | `collapse_id`        | API maximum 64 characters      |
| `sound($name)`          | `sound`              | Provider sound name            |
| `badge($number)`        | `badge`              | Zero or greater                |
| `androidChannelId($id)` | `android_channel_id` | Channel created by the app     |
| `iosCategory($name)`    | `ios_category`       | Category registered by the app |
| `ios($values)`          | iOS overrides        | Provider-specific object       |
| `android($values)`      | Android overrides    | Provider-specific object       |

## Idempotency

```php theme={null}
$message->idempotencyKey("order-ready:{$order->id}:v1");
```

Use a stable key for one logical notification. Retrying with the same key returns the original notification instead of creating another.
