Only offers with
status: "active" are considered by Decision Flows. Draft and paused offers are excluded from all candidate selection.How Offers Work at Runtime
When a Decision Flow executes via the Recommend API, every offer passes through these stages:| Stage | Regular Offers | Mandatory Offers |
|---|---|---|
| Inventory | Loaded by scope (all, category, or manual) | Same — split into separate list |
| Schedule | Excluded if outside date/time window | Same — expired promotions are not forced |
| Qualification | Evaluated against propensity, segments, recency | Bypassed |
| Scoring | PRIE formula with model + weights | Fixed score of 1.0 |
| Contact Policy | Filtered by all active policies | Bypassed (except mandatory-specific policies) |
| Daily Cap | N/A | Capped at 5/customer/day (configurable) |
| Ranking | Sorted by score descending | Prepended above regular results |
Common Use Cases
| Use Case | Example | Key Config |
|---|---|---|
| Product recommendation | ”Upgrade to Premium Card” | priority: 70, businessValue: 85, qualification rules for credit score |
| Time-sensitive promotion | ”Flash Sale: 24 Hours Only” | schedule.startDate / endDate, high priority |
| Regulatory notice | ”CFPB Rate Disclosure” | mandatory: true with reason, approver, and expiry |
| Retention offer | ”Stay with us — get 20% off for 6 months” | High businessValue, churn model for propensity scoring |
| Exploratory content | ”Did you know about our new savings account?” | Low priority: 25, broad eligibility |
Priority and Business Value
Two fields control how aggressively an offer competes during scoring. They look similar but serve different purposes in the PRIE formula:| Field | PRIE Factor | Range | Purpose | Who Sets It |
|---|---|---|---|---|
priority | Emphasis (E) | 0—100 | Subjective campaign lever — how much to boost or suppress this offer | Marketer |
businessValue | Impact (I) | 0—100 | Objective business worth — revenue, margin, strategic importance | Business analyst |
Priority Bands
| Level | Value | When to Use |
|---|---|---|
| Critical | 90 | Regulatory, compliance |
| High | 70 | Strategic campaigns, time-sensitive |
| Medium | 50 | Standard recommendations (default) |
| Low | 25 | Exploratory, filler content |
Business Value Example (Starbucks)
| Offer | businessValue | Normalized (I) | Rationale |
|---|---|---|---|
| BOGO Frappuccino | 80 | 0.80 | High margin on Frappuccinos, drives store visits |
| 25% Off Merchandise | 50 | 0.50 | Lower margin but drives basket size |
| Informational: New Store | 20 | 0.20 | No direct revenue, brand awareness only |
Status Lifecycle
Offers progress through a defined lifecycle:| Status | Description |
|---|---|
draft | Being configured. Not available for decisioning. |
active | Live and eligible for recommendation. |
paused | Temporarily removed from decisioning. Can be reactivated. |
archived | Permanently retired. Preserved for reporting history. |
Qualification Config
Control which customers are eligible to receive this offer via theeligibility object:
| Field | Type | Description | Example |
|---|---|---|---|
propensityThreshold | number (0—1) | Minimum model score required | 0.65 — only show to customers with 65%+ propensity |
recency | number (days) | Minimum days since customer last received this offer | 30 — no repeat within a month |
requiredSegments | string[] | Customer must belong to all listed segments | ["high_value", "credit_eligible"] |
modelReference | string | Scoring model to use for propensity evaluation | "model_propensity_cc_v3" |
Budget Config
Set spend and impression limits via thebudget object:
| Field | Type | Description | Example |
|---|---|---|---|
maxImpressions | number | Total lifetime impression cap | 50000 |
maxDailyBudget | number | Maximum spend per day | 2500.00 |
costPerAction | number | Cost per impression or conversion | 1.50 |
INCR (with Prisma fallback) to prevent race conditions under concurrent load. When an offer’s budget is exhausted, it is automatically excluded from decisioning.
The
budget_exhausted Contact Policy rule type can also enforce budget limits at the policy level.Schedule Config
Restrict when an offer is eligible via theschedule object:
| Field | Type | Description | Example |
|---|---|---|---|
startDate | ISO 8601 | Earliest date the offer can be recommended | "2026-03-15T00:00:00Z" |
endDate | ISO 8601 | Latest date the offer can be recommended | "2026-06-15T23:59:59Z" |
daysOfWeek | number[] | Allowed days (0=Sunday through 6=Saturday) | [1,2,3,4,5] — weekdays only |
timeWindow | object | { start: "HH:mm", end: "HH:mm" } within allowed days | { "start": "08:00", "end": "20:00" } |
Mandatory Governance
Marking an offer asmandatory: true activates a special runtime path for compliance-critical communications. Mandatory offers bypass qualification rules and receive a fixed score of 1.0, guaranteeing they rank above all regular candidates.
Required Fields
Whenmandatory is true, the API enforces three governance fields:
| Field | Purpose | Example |
|---|---|---|
mandatoryReason | Why this offer must be shown (audit trail) | "CFPB regulation 2026-04 requires rate disclosure" |
mandatoryApprovedBy | Who approved the override | "jane.smith@acme.com" |
mandatoryExpiresAt | ISO 8601 expiry after which the offer reverts to normal | "2026-04-15T23:59:59Z" |
400 Bad Request. Only users with the admin role can create or update mandatory offers.
Example: Regulatory Disclosure
Emergency Exclusions
TheemergencyExcluded flag lets you instantly remove an offer from all recommendations without changing its status or modifying a Decision Flow. Designed for pricing errors, compliance issues, or product recalls.
| Aspect | Behavior |
|---|---|
| Scope | Excluded from all flows, all channels, all segments |
| Speed | Takes effect on the next Recommend API call — no cache flush needed |
| Status | Remains active (toggling back is a single API call) |
| Audit | Every toggle is recorded with timestamp, user, and previous value |
Creating an Offer
Fill in basic info
Enter the offer name, description, and select a Category and sub-category.
Set priority and business value
Choose the priority level (Emphasis) and business value (Impact). Both default to 50.
Configure budget and schedule (optional)
Set impression caps, daily budget limits, start/end dates, and time windows.
Fill custom fields
Populate any custom fields defined by the parent category, including computed field formulas.
Field Reference
Every field accepted byPOST /api/v1/offers (create) and PUT /api/v1/offers (update):
| Field | Required | Type | Default | Description |
|---|---|---|---|---|
name | Yes | string | — | Display name. Must be unique within the tenant. |
status | No | enum | "draft" | draft, active, paused, archived |
categoryId | No | string | null | Parent Category ID |
subCategoryId | No | string | null | Sub-category ID within the category |
productType | No | string | "" | Product nature: bogo, discount, auto_insurance, credit_card, etc. Used for PRIE strategy overrides and offer_attribute qualification rules. |
priority | No | integer (0—100) | 50 | PRIE Emphasis (E) factor. Higher = more aggressive ranking. |
businessValue | No | integer (0—100) | 50 | PRIE Impact (I) factor. Overall business importance. |
margin | No | float | 0 | Profit margin per conversion. Sub-weight of Impact (I) in PRIE scoring. |
revenueValue | No | float | 0 | Expected revenue per conversion. Sub-weight of Impact (I) in PRIE scoring. |
mandatory | No | boolean | false | Bypass qualification and rank above all regular offers |
mandatoryReason | Conditional | string | null | Required when mandatory=true |
mandatoryApprovedBy | Conditional | string | null | Required when mandatory=true |
mandatoryExpiresAt | Conditional | string | null | Required when mandatory=true. ISO 8601. |
description | No | string | "" | Internal documentation |
shortDesc | No | string | "" | Brief description surfaced in responses |
eligibility | No | object | {} | Qualification config (see above) |
budget | No | object | {} | Budget config (see above) |
schedule | No | object | {} | Schedule config (see above) |
tags | No | string[] | [] | Freeform tags for filtering |
metadata | No | object | {} | Arbitrary key-value pairs for integrations |
emergencyExcluded | No | boolean | false | Instant exclusion from all recommendations |
API Quick Reference
Create
201 Created with the full offer object including generated id.
List
status, categoryId, tags.
Update
id in the request body along with the fields to update. Only provided fields are changed.
Delete
409 Conflict if the offer has creatives or interaction history. Add ?force=true to confirm permanent deletion.
Next Steps
Channels
Define how your offers are delivered to customers.
Creatives
Create the content variants for each offer and channel.
Decision Flows
Build the pipeline that scores, filters, and ranks your offers.
Glossary
Look up key terms used across the platform.