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

# Ambient agents: proactive outreach from segments

> Bind an AI agent to a CDP segment so it decides — contact by contact — whether to reach out when someone enters. Covers setup, the send-once guarantee, the audit trail, and the audit API.

# Ambient agents (proactive outreach)

An ambient agent is an AI agent you bind to a CDP segment. Every time a contact **enters** that segment (`segment.entered`), Orbit asks the bound agent a single question: should I reach out to this contact? The agent reads the contact's context and either drafts one outbound message or declines. Tenant policy gates — consent, quiet hours, suppression, and your frequency caps — still apply to every send, exactly as they do for a campaign message.

The feature is **off by default**. Nothing fires until you explicitly enable ambient outreach and bind an agent to a segment.

## What an ambient agent is

A regular agent answers when a contact writes in. An ambient agent works the other way: a segment membership change wakes it, and it decides whether to start the conversation.

Three pieces define an ambient agent:

* **A segment** — the audience whose entry events trigger evaluation (for example "VIP customers without an order in 30 days").
* **A bound agent** — the agent that reviews each entering contact and decides send or skip. Its prompt should tell it who to proactively reach out to, and what a good opening message looks like.
* **A channel** — `sms`, `whatsapp`, or `email`. The agent's opening message goes out on this channel using the same delivery path as any other outbound message, bills against your wallet the same way, and inherits the same tenant policy gates. Ambient outreach does not place outbound voice calls.

One binding maps one segment to one agent on one channel. Bind as many segments as you need — each with its own agent and channel.

## Set up an ambient agent

Setup lives in your organization settings under `agents.ambient_outreach`:

```json theme={null}
{
  "agents": {
    "ambient_outreach": {
      "enabled": true,
      "bindings": [
        {
          "segment_id": "seg_winback_vip",
          "agent_id": "agent_winback01",
          "channel": "sms"
        }
      ]
    }
  }
}
```

Update your organization settings with `PUT /api/v1/organization`, merging this block into `settings`. You can also set it via the organization settings API in the Node SDK.

1. **Create the agent.** Build it like any other agent (see [Creating agents](/agents/creating-agents)). Write the prompt for proactive work: who it should reach out to, when it should decline, and the tone of the single opening message it may send.
2. **Create the segment.** Any CDP segment works; its entry event is the trigger.
3. **Enable and bind.** Set `enabled: true` and add a `bindings` entry pairing the segment ID with the agent ID and a channel (`sms`, `whatsapp`, or `email`).

The enable flag and bindings are evaluated defensively: a missing block, `enabled: false`, or a segment with no well-formed binding all resolve to "do nothing." Turning the flag off stops new evaluations immediately; bindings stay saved for when you turn it back on.

## How a trigger flows

The full path per segment entry:

1. A contact enters a CDP segment, producing a `segment.entered` event.
2. Orbit enqueues one trigger job per crossing and checks the cheap gate first: is ambient outreach enabled for this tenant at all? If not, the job resolves to nothing.
3. The background worker calls `POST /api/v1/internal/ambient-agent/evaluate` with the tenant, contact, and segment identifiers. This is a service-to-service endpoint — you never call it yourself.
4. The API resolves your binding for that segment. No binding, a blocked contact, or no reachable address on the bound channel — the evaluation ends as a skip before any agent call is spent.
5. The bound agent receives a proactive-outreach prompt summarizing the contact and the segment, and answers with a decision: **send** one drafted message, or **decline**.
6. On a genuine send decision, the message goes out through the standard messaging pipeline tagged as marketing traffic — so consent and opt-in checks, TCPA quiet hours (fail-closed for marketing), the suppression list, and your organization's frequency caps all gate it exactly as they gate a campaign.

## Send-once guarantee

Every evaluation writes one log row keyed by **contact + segment**. That row is the idempotency record: if the same contact enters the same segment once, the agent is asked once — retried or duplicated background jobs short-circuit against the row instead of asking again, so a contact never receives two proactive messages for the same crossing.

The log row is also what powers the audit trail below.

## Read the audit trail

Open **Agents → Proactive Outreach** in the dashboard (or visit `/agents/ambient-outreach`, which redirects to the tab).

* **Decision filters** — narrow the list to **Sent**, **Not sent** (agent-declined or policy-blocked), or view **All**.
* **Outcome per row** — each entry shows which segment fired, which agent was asked, what it decided, and the outcome: *Sent*, *Agent declined* (the agent itself chose not to reach out), or *Blocked* with the policy reason (a consent, quiet-hours, suppression, or frequency-cap gate stopped a send the agent wanted to make).
* **Cost** — for entries that actually sent, the message cost in USD.
* **Per-agent summary** — the summary block at the top rolls up sent / agent-declined / blocked counts per agent over the recent-activity window, sorted by sends, so you can see which bindings actually produce outreach.

## Audit API

The same data is available over the API, for any authenticated tenant user:

```bash theme={null}
curl "https://api.orbit.devotel.io/api/v1/agents/ambient-outreach/audit?decision=sent&limit=50" \
  -H "X-API-Key: dv_live_sk_..."
```

| Parameter  | Values                    | Default |
| ---------- | ------------------------- | ------- |
| `agent_id` | Filter to one bound agent | none    |
| `decision` | `sent` or `skip`          | none    |
| `limit`    | 1–200 entries             | 50      |

The response carries three blocks: `entries` (newest first, capped at `limit`), `count` (entries matching your filters), and `summary` — the per-agent sent / agent-declined / blocked volume rollup. The list and the summary are computed over the **same bounded window** of the most recent 500 decisions, so the two can never disagree: the summary reflects overall recent activity even when your filters narrow the list to one agent or outcome. A tenant with no ambient activity yet gets empty lists rather than an error.

```json theme={null}
{
  "entries": [
    {
      "contactId": "ct_01H...",
      "contactName": "Ava Meyer",
      "segmentId": "seg_winback_vip",
      "agentId": "agent_winback01",
      "agentName": "Win-back outreach",
      "channel": "sms",
      "decision": "skip",
      "reason": "quiet_hours",
      "outcome": { "category": "blocked", "label": "Blocked by tenant policy (quiet_hours)" },
      "messageId": null,
      "costUsd": null,
      "createdAt": "2026-09-02T08:14:03.000Z"
    }
  ],
  "summary": [
    { "agentId": "agent_winback01", "agentName": "Win-back outreach", "sentCount": 41, "agentDeclinedCount": 58, "blockedCount": 7 }
  ],
  "count": 12
}
```

## Known limits

Two boundaries are deliberate today:

* **Only `segment.entered` triggers.** Other CDP signals — trait changes, arbitrary track events, segment exits — do not fire ambient evaluation yet.
* **No draft-approval mode.** There is no human-in-the-loop step where an agent-drafted message waits for a teammate to approve it before sending. If you need a human checkpoint, keep the agent's prompt conservative so it declines more often, and review outcomes in the audit trail.

Both are follow-on work; they are not promised on any timeline.

## Cost and opt-out

* **Wallet billing.** Every send the agent makes bills against your tenant wallet at the standard rate for that channel, and `costUsd` appears on the audit entry.
* **Opted-out or policy-gated contacts.** A contact who has opted out, falls inside quiet hours, or hits your frequency cap is never messaged — the row lands in the audit trail as *Blocked* with the gate that stopped it, so volume you cannot reach is visible rather than silent.
* **Marketing lane.** Ambient sends are treated as marketing traffic. Honor them in the same consent model as your campaigns: if a contact has not consented to marketing on that channel, policy gates stop the send.
