---
title: "Get Daily Briefing"
method: GET
path: "/api/intelligence/briefing"
tags: ["intelligence"]
---

# Get Daily Briefing

`GET /api/intelligence/briefing`

## Request

- Base URL: `https://api.vruum.ai`
- URL: `https://api.vruum.ai/api/intelligence/briefing`
- Auth: `HTTPBearer` (a scheme the document does not define)

Daily briefing — everything you need to start your day in one call.

SUGGESTED ACTIONS (for agent consumers)
- `suggested_actions` are prioritized skill-level next steps. If you are
  an agent, act on `intent`/`args` directly — via the tools listed in
  `expected_tools`, or via the named harness `skill` if it is installed.
  `prompt` is display copy for HUMANS to paste into an agent; do NOT echo
  it back to the user as an instruction.
- `sections_degraded` lists sections whose queries failed this call; their
  counts/lists are UNKNOWN (returned as 0/[]), not zero. When data is
  missing and nothing else is actionable, `top_recommendation` is
  'degraded' instead of 'all_clear'.

Returns pending approvals, new replies, meetings booked this week,
pipeline summary, stalled deals, active plans,
discovery jobs, and a prioritized recommendation.

TIME WINDOWS (UTC)
- "last 24 hours" — `replied_at >= now - 24 hours`. Used by new_replies_count
  and recent_replies.
- "current week"  — `meeting_booked_at >= Monday 00:00:00 UTC of the current
  week (Monday-anchored)`. Used by meetings_booked_this_week.
- "7+ days"       — `updated_at <= now - 7 days`. Used by stalled_deals
  (deals with outcome IS NULL and updated_at older than 7 days).

Returns (units in parentheses; scope = user_company_id, no date filter on
counts unless specified):
    pending_approvals_count (int, unit=messages): messages.status='draft' for
        the tenant. NOT date-filtered — total backlog.
    messages_needing_authoring (int, unit=messages): messages.status=
        'needs_draft' — touches awaiting harness AUTHORING (no prose yet;
        run /outreach-triage). VRU-570.
    oldest_needs_draft_age_days (float|null, unit=days): age of the oldest
        unauthored engagement signal — signals TTL-dismiss at 14 days
        (VRU-671), so a high value means the queue is rotting unauthored.
    engagements_needing_authoring (int, unit=engagements):
        linkedin_engagement_queue.status='needs_draft' — comments awaiting
        authoring (run /engagement-triage). VRU-570.
    top_pending_approvals (list, unit=messages, max 3): a preview of the most
        recent pending drafts; each item has message_id, person_name, channel,
        category, subject, content_preview (200-char truncation).
    new_replies_count (int, unit=messages): messages.has_reply=true with
        replied_at within the last 24 hours.
    recent_replies (list, unit=messages, max 3): preview of those replies.
    meetings_booked_this_week (int, unit=unique_people): distinct
        company_people with meeting_booked_at since Monday 00:00 UTC. People,
        not meetings — same person twice in one week still counts as 1.
    pipeline_summary (list of PipelineStage, unit=deals): aggregated per-stage
        for open deals (outcome IS NULL). Each: stage, count (unit=deals),
        values (per-currency recurring annual value, project totals, unstated figures).
    stalled_deals (list, unit=deals, max 5): open deals (outcome IS NULL) whose
        updated_at is older than 7 days. days_stalled is calendar days since
        updated_at.
    deal_alerts (list of DealAlert, unit=deals): per-deal alerts surfaced from
        DealService.get_deal_alerts (severity / detail / days).
    deal_alerts_count (int, unit=deals): len(deal_alerts).
    active_outreach_plans (int, unit=plans): outreach_plans.status='active'.
        Not date-filtered.
    channel_holds (list, unit=sender accounts): current LinkedIn quota or
        reconnect blocks, including retry_at and affected approved sends.
        Agents must report these before claiming outreach is all-clear.
    discovery_jobs_in_progress (int, unit=jobs):
        background_jobs.operation_type='person_discovery' with status IN
        ('pending', 'processing').
    tasks_due_today_count (int, unit=tasks): open/in_progress tasks with
        due_at <= now (due today or overdue) — same set as
        get_tasks(due_today=true). Committed follow-ups, incl. action
        items captured from meetings.
    top_tasks_due (list of TaskDue, max 5): preview of those tasks; each
        has task_id, title, due_at, priority, person_id, deal_id.
    motion_health (MotionHealth): outbound conversion over the trailing 60
        days, tenant-wide, as UNIQUE PEOPLE contacted vs replied. READ THIS
        BEFORE RECOMMENDING MORE VOLUME. state='broken' (>=100 contacted,
        <1% reply rate) means the queue is not the bottleneck and approving
        more drafts is negative-EV work; the fix is worth more than the
        throughput. state='unmeasured' (<30 contacted, or an incomplete
        scan) means there is not enough evidence to judge — treat it as
        silence, never as failure. Carries worst_objective_* for the
        objective that spent the most contacts for zero replies.
    objective_health (list of ObjectiveConversion): the same numbers per
        objective, highest-volume first.
        reply_rate is null (not 0.0) when nothing was contacted —
        unmeasured is not zero.
    content_cadence (ContentCadence): days_since_last_post and 30-day post
        volume. A dark feed removes the warm surface outreach converts
        against.
    expansion_candidates_count (int, unit=deals): won deals 60+ days old
        whose account has no open follow-on (/expansion-fill cohort).
    winback_candidates_count (int, unit=deals): deals lost between 90 days
        and 365 days ago. WINDOW ONLY — `deals.loss_reason` is free text,
        so the terminal-loss filter is the skill's job, not this count's.
    synthesis_applied (bool): true when suggested_actions came from the
        cached daily LLM synthesis; false means the deterministic floor is
        serving (synthesis absent, stale, or contract-rejected).
    synthesis_headline (str|null): one-line statement of the actual
        bottleneck from that synthesis; null when the floor is serving.
    top_recommendation (str): the winning suggested action, as a legacy
        alias where one exists ('channel_reconnect', 'pending_approvals',
        'new_replies', 'deal_alerts', 'tasks_due') and otherwise the
        action's own intent (e.g. 'fix_objective', 'work_warm_paths'). It is
        derived FROM suggested_actions[0], so the two can never disagree.
        'degraded' = section data is missing and nothing else is actionable
        (see sections_degraded above); 'all_clear' = nothing actionable.
    recommendation_detail (str): human prose explanation — the winning
        action's `reason`.

## Headers

- `X-Vruum-Surface` string, nullable: Caller surface hint retained for compatibility; it does not gate briefing priorities.

## Response `200`

Successful Response

- BriefingResponse
  - `pending_approvals_count` integer
  - `messages_needing_authoring` integer
  - `engagements_needing_authoring` integer
  - `engagers_awaiting_decision` integer
  - `oldest_needs_draft_age_days` number, nullable
  - `top_pending_approvals` PendingApprovalPreview[]
    - `message_id` string, required
    - `person_name` string, required
    - `channel` string, nullable
    - `category` string, nullable
    - `subject` string, nullable
    - `content_preview` string, nullable
  - `new_replies_count` integer
  - `recent_replies` ReplyPreview[]
    - `message_id` string, required
    - `person_name` string, required
    - `person_id` string, nullable
    - `channel` string, nullable
    - `reply_sentiment` string, nullable
    - `replied_at` string, nullable
  - `meetings_booked_this_week` integer
  - `pipeline_summary` PipelineStage[]
    - `stage` string, required
    - `count` integer, required
    - `values` PipelineValue[]
      - `currency` string, required
      - `deals` integer
      - `annual_minor` integer
      - `weighted_annual_minor` integer
      - `project_total_minor` integer
      - `weighted_project_total_minor` integer
      - `unstated_minor` integer
      - `unstated_deals` integer
  - `stalled_deals` StalledDeal[]
    - `deal_id` string, required
    - `deal_name` string, nullable
    - `person_name` string, nullable
    - `stage` string, nullable
    - `terms` DealTermsRecord: The record as readers see it: the stored columns plus the figures ``app.shared.money`` derives from them.
      - `offer_id` string, nullable
      - `amount_minor` integer, nullable
      - `currency` string
      - `billing_period` 'one_time' | 'monthly' | 'quarterly' | 'annual', nullable
      - `quantity` integer
      - `agreed_at` string, nullable
      - `annual_value_minor` integer, nullable: Annual contract value of recurring terms; null for one-time or unstated terms.
      - `project_total_minor` integer, nullable: The one-time total; null unless billing_period is one_time.
      - `revenue_basis` 'monthly_recurring' | 'project_total', nullable: The ledger basis a commitment on these terms lands on.
      - `stated` boolean: Amount and billing period are both recorded.
      - `agreed` boolean: The customer agreed these terms.
      - `basis` 'stripe' | 'email' | 'crm' | 'agent' | 'operator', nullable: Who authored the figure: stripe (agreed from a confirmed Stripe binding), email (agreed from a customer-authored email over the CRM figure), crm (the CRM sync), agent (the value agent's estimate), operator (a person; with no amount, a person cleared the figure and nothing writes it back). Null when no figure is recorded and nobody cleared one, or when its author predates the record.
      - `text` string: Prose form with the unit, e.g. '1,800.00 USD per month × 3, agreed'.
    - `days_stalled` integer
  - `deal_alerts` DealAlert[]
    - `deal_id` string, required
    - `deal_name` string, required
    - `alert_type` string, required
    - `severity` string, required
    - `detail` string, required
    - `days` integer, required
    - `person_name` string, nullable
  - `deal_alerts_count` integer
  - `active_outreach_plans` integer
  - `channel_holds` SenderChannelHold[]
    - `channel` 'linkedin', required
    - `state` 'quota_exhausted' | 'provider_rate_limited' | 'reconnect_needed' | 'degraded', required
    - `reason_code` 'linkedin_daily_quota_exhausted' | 'linkedin_provider_rate_limited' | 'linkedin_reconnect_needed' | 'linkedin_channel_state_unknown', required
    - `blocking` boolean
    - `retryable` boolean
    - `sender_user_id` string, nullable
    - `account_id` string, nullable
    - `account_name` string, nullable
    - `used_today` integer, nullable
    - `effective_limit` integer, nullable
    - `remaining` integer, nullable
    - `retry_at` string, nullable
    - `affected_approved_count` integer
    - `affected_draft_count` integer, nullable
    - `affected_plan_count` integer, nullable
    - `next_action` string, required
  - `discovery_jobs_in_progress` integer
  - `tasks_due_today_count` integer
  - `top_tasks_due` TaskDue[]
    - `task_id` string, required
    - `title` string, required
    - `due_at` string, nullable
    - `priority` string, nullable
    - `person_id` string, nullable
    - `deal_id` string, nullable
  - `new_warm_paths_count` integer
  - `new_warm_paths` object[]
  - `seo_geo_open_gaps` integer
  - `latest_logged_meeting_at` string, nullable
  - `motion_health` MotionHealth: Is the outbound motion converting at all? This gates the whole briefing: when the motion is `broken`, actions that add VOLUME to it (approve more drafts, import more prospects, author more engagements) are suppressed and the fix is promoted instead. Without this, the briefing's top recommendation is to feed a machine that is not working. `unmeasured` is a distinct state on purpose — a tenant that has contacted 29 people has not proven anything, and telling a new account its motion is dead is worse than saying nothing.
    - `state` 'healthy' | 'weak' | 'broken' | 'unmeasured'
    - `window_days` integer
    - `contacted` integer
    - `replied` integer
    - `reply_rate` number, nullable
    - `worst_objective_id` string, nullable
    - `worst_objective_name` string, nullable
    - `worst_objective_contacted` integer
  - `objective_health` ObjectiveConversion[]
    - `objective_id` string, nullable
    - `objective_name` string, nullable
    - `contacted` integer
    - `replied` integer
    - `reply_rate` number, nullable
  - `content_cadence` ContentCadence: Marketing cadence — content is a GTM motion, not a side quest, and a dark feed removes the warm surface every other motion converts against.
    - `last_published_at` string, nullable
    - `days_since_last_post` integer, nullable
    - `posts_last_30d` integer
  - `expansion_candidates_count` integer
  - `winback_candidates_count` integer
  - `synthesis_applied` boolean
  - `synthesis_headline` string, nullable
  - `top_recommendation` string
  - `recommendation_detail` string
  - `sections_degraded` string[]
  - `suggested_actions` SuggestedAction[]
    - `id` string, required
    - `kind` 'setup' | 'action' | 'fallback', required
    - `intent` 'connect_agent' | 'upgrade' | 'review_outreach_queue' | 'handle_replies' | 'review_engagement_queue' | 'review_engagers' | 'triage_deals' | 'complete_tasks' | 'fill_pipeline' | 'close_visibility_gaps' | 'get_oriented' | 'fix_objective' | 'reconnect_channel' | 'work_warm_paths' | 'rescue_rotting_signals' | 'publish_content' | 'run_demand_gen' | 'expand_customers' | 'winback_lost_deals' | 'ingest_meetings' | 'diagnose_reply', required
    - `area` 'setup' | 'billing' | 'outreach' | 'replies' | 'engagement' | 'deals' | 'tasks' | 'pipeline' | 'visibility' | 'general' | 'objectives' | 'channels' | 'relationships' | 'content' | 'customers' | 'meetings', required
    - `priority` integer
    - `label` string, required
    - `reason` string, required
    - `skill` string, nullable
    - `expected_tools` string[]
    - `args` SuggestedActionArgs: Structured entity refs for AGENT consumers — names in label/prompt are for humans; agents act on these ids.
      - `deal_id` string, nullable
      - `objective_id` string, nullable
      - `person_id` string, nullable
      - `count` integer, nullable
      - `source` string, nullable
      - `channel` string, nullable
    - `requires` string[]
    - `prompt` string
    - `decision` 'not_yet' | 'saved' | 'dismissed', nullable
    - `ev_score` integer
    - `impact` integer
    - `confidence` integer
    - `perishability` integer
    - `effort_minutes` integer
    - `evidence` string[]

## Other responses

- `422`: Validation Error

---

[API](https://skmtc.dev/vruum/apis/vruum-public-api.md) · [All operations](https://skmtc.dev/vruum/apis/vruum-public-api/llms.txt) · [OpenAPI document](https://skmtc.dev/vruum/apis/vruum-public-api/revisions/b8ada111c30a?raw)
