---
title: "Outbound Heartbeat"
method: POST
path: "/api/outbound/heartbeat"
tags: ["Outbound", "outbound"]
---

# Outbound Heartbeat

`POST /api/outbound/heartbeat`

## Request

- Base URL: `https://api.ruzora.com` (the document declares no server; this is the origin it was published from)
- URL: `https://api.ruzora.com/api/outbound/heartbeat`
- Auth: none declared

Post the daily outbound heartbeat to #sales-signals.

``once_per_day=true`` (sent by both schedulers — the Railway
cron-scheduler primary and the GitHub backup) makes the post idempotent
per UTC day: the first caller atomically claims today's date in
``feature_flags`` and posts; later callers get 200 with
``skipped="already_posted_today"``. A failed Slack post releases the
claim so the other scheduler can retry.

Driven once a day by ``.github/workflows/outbound-heartbeat-cron.yml``.
Leads created / enrolled / replied, positive intents, queue size and the
state of every send gate — with a :rotating_light: line for a
zero-enrolled day or any gate that is off. See
``outbound_heartbeat_service`` for why a heartbeat and not another alert.

AUTHED with X-Cron-Token: the response carries per-source lead counts
and the gate configuration, and an anonymous caller could spam the
sales channel. ``dry_run=true`` returns the rendered message without
posting it. A real run whose Slack post fails returns 502 (body still
carries the rendered text) so the cron job fails loudly.

## Headers

- `x-cron-token` string, nullable

## Request body

- BodyOutboundHeartbeatApiOutboundHeartbeatPost
  - `dry_run` boolean
  - `once_per_day` boolean

## Response `200`

Successful Response

- object

## Other responses

- `422`: Validation Error

---

[API](https://skmtc.dev/ruzora/apis/ruzora-candidate-crm-api.md) · [All operations](https://skmtc.dev/ruzora/apis/ruzora-candidate-crm-api/llms.txt) · [OpenAPI document](https://skmtc.dev/ruzora/apis/ruzora-candidate-crm-api/revisions/f9b8223f3ac4?raw)
