klaviyo icon
SlackIncomingWebhook icon
GetSendJob icon
ForEach icon
Get icon
If icon
Log icon
Set icon
Schedule icon

Klaviyo Send Job Monitoring with Slack Alerts

Scheduled Kestra flow that polls Klaviyo send jobs during business hours and pages Slack once when a campaign send transitions into a bad state.

Categories
Business

Monitor Klaviyo campaign send jobs and page Slack the moment a send goes wrong. This Kestra blueprint gives marketing operations teams real observability over Klaviyo email and SMS send jobs: it polls the Klaviyo Campaign Send Job API on a business-hours schedule, evaluates every job in flight, and alerts a Slack channel exactly once when a job transitions into a failed, cancelled, or error state. It solves a real problem Klaviyo's own UI cannot: a stuck or failed send job stays silent unless someone happens to be watching the dashboard, and naive polling either re-pages the same failure every cycle or never surfaces it at all.

How it works

  1. The business_hours io.kestra.plugin.core.trigger.Schedule trigger fires every 30 minutes from 08:00 to 18:00 UTC, Monday to Friday, with an explicit timezone.
  2. get_send_jobs (io.kestra.plugin.klaviyo.jobs.GetSendJob) fetches the current state of every send job ID in the job_ids input using fetchType: FETCH, so each job is evaluated rather than just the first. It carries a constant retry (4 attempts, 30s apart) and a 5-minute timeout.
  3. evaluate_jobs (io.kestra.plugin.core.flow.ForEach, concurrencyLimit: 1) iterates the fetched jobs. For each one, get_last_status (io.kestra.plugin.core.kv.Get) reads the last-seen status from the KV store.
  4. route_status (io.kestra.plugin.core.flow.If) alerts only when the current status is in alerting_statuses AND differs from the last-seen value. On a match, alert_unhealthy_send posts a rich Slack Block Kit message; otherwise log_status records the status for the audit trail.
  5. record_status (io.kestra.plugin.core.kv.Set) writes the current status back with a 30-day TTL, after the alert branch, so a failed Slack post never silently suppresses a future page.

What you get

  • A Slack page for each send job the instant it newly enters an alerting status, with no duplicate noise on later polls.
  • A per-job KV entry (klaviyo_send_job_<id>) holding the last-seen status, used to deduplicate alerts across runs.
  • A flow-level errors block that alerts Slack if the monitor itself fails (for example, a bad API key).
  • Self-healing on transient Klaviyo 429s and 5xx errors via the built-in retry.

Who it's for

  • Marketing operations and lifecycle teams running high-stakes Klaviyo campaigns.
  • Email and CRM engineers who need send-job failures escalated to Slack, not buried in a dashboard.
  • On-call teams that want one clean page per incident instead of alert fatigue.

Why orchestrate this with Kestra

Klaviyo has no native scheduler that watches its own send jobs and routes failures to your incident channel. Kestra fills that gap: a declarative YAML flow with an event-driven Schedule trigger, automatic retries on flaky API calls, KV-backed state so alerts dedupe on transition, full execution lineage and logs for every poll, and a flow-level error handler. You get production-grade monitoring of an external SaaS without standing up a cron box or writing glue scripts.

Prerequisites

  • A Klaviyo account with a Private API Key that has read access to campaign send jobs.
  • A Slack incoming webhook pointing at your marketing operations channel.

Secrets

  • KLAVIYO_API_KEY: Klaviyo Private API Key, used by get_send_jobs to authenticate against the Campaign Send Job API.
  • SLACK_WEBHOOK_URL: Slack incoming webhook URL used for both the unhealthy-send alert and the flow-failure alert.

Quick start

  1. Add the KLAVIYO_API_KEY and SLACK_WEBHOOK_URL secrets to your Kestra namespace.
  2. Set the job_ids input to the send job IDs you want to watch and confirm alerting_statuses match your account's status enum (verify against the Klaviyo Campaign Send Job API).
  3. Enable the flow. The business-hours schedule keeps jobs under watch and Slack stays quiet until a job transitions into a bad state.

How to extend

  • Feed job_ids from a discovery task that lists recently created send jobs, so the watch list stays current instead of being hand-maintained.
  • Adjust the cron to widen the window or poll around the clock during a launch.
  • Add statuses to alerting_statuses, or branch into PagerDuty, email, or a ticketing system alongside Slack.
  • Push each poll's status into a warehouse or BigQuery for long-term send-health reporting.

Links

See How

New to Kestra?

Use blueprints to kickstart your first workflows.