# Segments

> Save reusable filters over a sending domain’s contacts and target campaigns at a subset of them.

A **segment** is a saved, reusable filter over the contacts on one of your sending **domains**. Instead of sending a [campaign](https://www.sendping.co/docs/campaigns/managing) to a domain’s entire contact pool, you can target a segment — a subset matched by a filter. A segment belongs to exactly one domain: names are unique within a domain but freely reusable across domains, and every domain also carries an auto-created **General** segment that matches all of its contacts.

Segments are for **your own internal organization** — they are never visible to your contacts. Use them to group contacts however makes sense for your sending (by signup source, plan, engagement, email domain, and so on).

## Filters

A segment filter is a set of predicates, all combined with AND:

**Filter**

| Name | Type | Required | Description |
| --- | --- | --- | --- |
| `status` | 'all' | 'subscribed' | 'unsubscribed' | 'members_only' | No | Match by subscription status. Defaults to `all`. `members_only` (matches nobody by filter — the segment resolves to its explicitly added contacts only). |
| `email_contains` | string | No | Match contacts whose email contains this substring (case-insensitive). |
| `property_filters` | array | No | Optional list of custom-property predicates combined with AND. Each entry requires a `key` (registered contact property), an `operator` (`eq`, `contains`, or `exists`), and (for `eq`/`contains`) a `value`. Register properties first with `POST /contact-properties`. |
| `engagement` | object | null | No | Optional engagement predicate against one campaign: `{ event, campaign_id }`. `event` is one of `clicked`, `not_clicked`, `opened`, `not_opened`. `null` (the default) means no engagement predicate. |

## Create a segment

**Node.js**

```js
import { SendPing } from 'sendping';

const mb = new SendPing('mb_xxxxxxxxx');

const { data, error } = await mb.segments.create({
  "domain": "yourdomain.com",
  "name": "Gmail subscribers",
  "filter": { "status": "subscribed", "email_contains": "@gmail.com" }
});
console.log({ data, error });
```

**Ruby**

```ruby
require "sendping"

SendPing.api_key = "mb_xxxxxxxxx"

SendPing::Segments.create({
  "domain": "yourdomain.com",
  "name": "Gmail subscribers",
  "filter": {
    "status": "subscribed",
    "email_contains": "@gmail.com"
  }
})
```

**PHP**

```php
<?php
require 'vendor/autoload.php';

use SendPing\SendPing;

$sendping = SendPing::client('mb_xxxxxxxxx');

$sendping->segments->create([
  'domain' => "yourdomain.com",
  'name' => "Gmail subscribers",
  'filter' => [
    'status' => "subscribed",
    'email_contains' => "@gmail.com"
  ]
]);
```

**Python**

```python
import sendping

sendping.api_key = "mb_xxxxxxxxx"

sendping.Segments.create({
  "domain": "yourdomain.com",
  "name": "Gmail subscribers",
  "filter": {
    "status": "subscribed",
    "email_contains": "@gmail.com"
  }
})
```

**Go**

```go
import "github.com/shekhu10/sendping-sdks/sendping-go"

client := sendping.NewClient("mb_xxxxxxxxx")

segment, err := client.Segments.Create(&sendping.CreateSegmentRequest{
    Domain: "yourdomain.com",
    Name:   "Gmail subscribers",
    Filter: &sendping.SegmentFilterInput{
        Status:        "subscribed",
        EmailContains: "@gmail.com",
    },
})
```

**Rust**

```rust
use sendping::{CreateSegmentOptions, SegmentFilterOptions, SegmentStatus, SendPing};

let mb = SendPing::new("mb_xxxxxxxxx");

let params = CreateSegmentOptions::new("yourdomain.com", "Gmail subscribers")
    .with_filter(SegmentFilterOptions::new()
        .with_status(SegmentStatus::Subscribed)
        .with_email_contains("@gmail.com"));
let _segment = mb.segments.create(params).await?;
```

**Java**

```java
import co.sendping.SendPing;
import co.sendping.SendPingResponse;
import co.sendping.requests.CreateSegmentRequest;
import co.sendping.requests.SegmentFilter;

SendPing sendping = new SendPing("mb_xxxxxxxxx");

CreateSegmentRequest request = CreateSegmentRequest.builder()
        .domain("yourdomain.com")
        .name("Gmail subscribers")
        .filter(SegmentFilter.builder()
                .status("subscribed")
                .emailContains("@gmail.com")
                .build())
        .build();

SendPingResponse response = sendping.segments().create(request);
```

**.NET**

```csharp
using SendPing;

ISendPing sendping = SendPingClient.Create("mb_xxxxxxxxx");

var resp = await sendping.SegmentCreateAsync(new SegmentCreateOptions
{
    Domain = "yourdomain.com",
    Name = "Gmail subscribers",
    Filter = new SegmentFilterOptions
    {
        Status = "subscribed",
        EmailContains = "@gmail.com",
    },
});
```

**cURL**

```bash
curl -X POST 'https://www.sendping.co/api/segments' \
  -H 'Authorization: Bearer mb_xxxxxxxxx' \
  -H 'Content-Type: application/json' \
  -d '{
  "domain": "yourdomain.com",
  "name": "Gmail subscribers",
  "filter": { "status": "subscribed", "email_contains": "@gmail.com" }
}'
```

**CLI**

```bash
sendping segments create \
  --domain 'yourdomain.com' \
  --name 'Gmail subscribers' \
  --filter '{"status":"subscribed","email_contains":"@gmail.com"}'
```

## Preview who matches

List the contacts a segment currently resolves to — useful to sanity-check a filter before sending.

```ts
const { data } = await mb.segments.contacts('4c1f8b2e-9a2f-4d71-8f0c-2b5d7e6a1c93');
console.log(data.data.length, 'contacts match');
```

## Send a campaign to a segment

Pass `segment_id` when creating a campaign. The campaign then fans out only to the segment’s matching contacts (still excluding anyone unsubscribed, for compliance).

```ts
await mb.campaigns.create({
  domain: 'yourdomain.com',
  segment_id: '4c1f8b2e-9a2f-4d71-8f0c-2b5d7e6a1c93',
  from: 'Acme <news@yourdomain.com>',
  subject: 'A note for our Gmail folks',
  html: '<p>Hi {{FIRST_NAME}}</p>',
});
```

> **Note:** For compliance, a campaign never sends to unsubscribed contacts even if a segment’s `status` would include them — the `status` filter is most useful for previewing/auditing, while `email_contains` is what narrows a send.

> **Note:** Include the `{{{SENDPING_UNSUBSCRIBE_URL}}}` merge tag in a segment campaign and SendPing automatically replaces it with the correct per-contact unsubscribe link — so opt-outs are handled for you. See [Managing unsubscribed contacts](https://www.sendping.co/docs/audiences/unsubscribed).
