Segmentation & Targeting
Miranda’s segmentation engine lets you define filter criteria to build contact lists dynamically. Segments can be saved for reuse in campaigns, exports, and reporting.
How segmentation works
Section titled “How segmentation works”The SegmentationService applies a criteria array to an Eloquent query builder, progressively narrowing the contact set. Criteria are combined with AND logic — a contact must match all specified filters.
class SegmentationService{ public function apply(Builder $query, array $criteria): Builder; public function resolve(string $foundationId, array $criteria): Builder;}resolve() starts with all contacts in a foundation and applies the criteria. apply() can be used on an existing query for composition.
Available criteria
Section titled “Available criteria”| Key | Type | Description |
|---|---|---|
relationship_types | string[] | Filter to contacts with any of these types (donor, applicant, subscriber, general) |
tags | string[] | Filter to contacts tagged with any of these tag names |
giving_min | integer | Minimum lifetime giving (in cents) from donor relationship metadata |
giving_max | integer | Maximum lifetime giving (in cents) from donor relationship metadata |
first_contact_after | date string | Only contacts with first_contact_at on or after this date |
email_opt_in | boolean | Filter by email opt-in preference |
sms_opt_in | boolean | Filter by SMS opt-in preference |
Example criteria object
Section titled “Example criteria object”{ "relationship_types": ["donor"], "tags": ["major-donor", "annual-gala"], "giving_min": 50000, "email_opt_in": true}This resolves to: donors who are tagged “major-donor” OR “annual-gala”, have given at least $500 lifetime, and are opted in to email.
Saved segments
Section titled “Saved segments”The SavedSegment model persists criteria for reuse:
| Field | Type | Description |
|---|---|---|
id | UUID | Primary key |
foundation_id | UUID | Owning foundation |
name | string | Display name (e.g., “Lapsed donors”) |
criteria | JSON | The criteria object applied at query time |
Saved segments are dynamic — they re-evaluate against current contact data every time they are used. There is no cached member list.
Campaign integration
Section titled “Campaign integration”When a campaign is created, its segment_criteria field stores the targeting criteria. At send time, the CampaignService resolves the segment and dispatches batched jobs:
// CampaignService::send()$criteria = $campaign->segment_criteria ?? [];
// Auto-filter for opt-in based on channelif ($campaign->channel === CampaignChannel::Email) { $criteria['email_opt_in'] = true;}
$contactIds = $this->segmentationService ->resolve($campaign->foundation_id, $criteria) ->pluck('id') ->toArray();The campaign service automatically adds opt-in filtering based on the campaign channel — email_opt_in for email campaigns, sms_opt_in for SMS campaigns.
API endpoints
Section titled “API endpoints”| Method | Path | Description |
|---|---|---|
| GET | /api/segments | List saved segments |
| POST | /api/segments | Create a saved segment |
| POST | /api/segments/preview | Preview contact count for given criteria (without saving) |
| DELETE | /api/segments/{segment} | Delete a saved segment |
Preview endpoint
Section titled “Preview endpoint”The preview endpoint lets you test criteria before saving or sending:
POST /api/segments/previewContent-Type: application/json
{ "criteria": { "relationship_types": ["donor"], "giving_min": 10000 }}Returns the count of matching contacts without creating a saved segment.