diff --git a/docs/configuration/sinks/index.rst b/docs/configuration/sinks/index.rst
index 3d9be6734..4bdabf6e6 100644
--- a/docs/configuration/sinks/index.rst
+++ b/docs/configuration/sinks/index.rst
@@ -129,6 +129,11 @@ Click a sink for setup instructions.
:link: pushover
:link-type: doc
+ .. grid-item-card:: :octicon:`cpu;1em;` Plivo
+ :class-card: sd-bg-light sd-bg-text-light
+ :link: plivo
+ :link-type: doc
+
.. grid-item-card:: :octicon:`cpu;1em;` ServiceNow
:class-card: sd-bg-light sd-bg-text-light
:link: ServiceNow
diff --git a/docs/configuration/sinks/plivo.rst b/docs/configuration/sinks/plivo.rst
new file mode 100644
index 000000000..768596f90
--- /dev/null
+++ b/docs/configuration/sinks/plivo.rst
@@ -0,0 +1,51 @@
+Plivo
+#################
+
+.. admonition:: This page documents a legacy sink in Robusta classic
+ :class: warning
+
+ For new setups, we recommend `HolmesGPT `_ instead.
+
+ HolmesGPT triages your alerts instead of just forwarding them. Sinks are deterministic: they send every notification, unchanged, to a fixed destination, leaving you to read and prioritize each one yourself.
+
+ HolmesGPT instead uses AI to investigate each alert, surface the likely root cause, and escalate only what needs attention — so you get fewer, more actionable notifications. Set this up with `Alerts Triage `_ for alerts, or :ref:`Triggered Workflows ` for custom events.
+
+
+Robusta can send SMS notifications about issues and events in your Kubernetes cluster to a phone number using Plivo.
+
+Getting your Auth ID and Auth Token
+------------------------------------------------
+Log in to the Plivo console at `cx.plivo.com `_. Your Auth ID and Auth Token are shown on the dashboard.
+
+Getting a sender number
+------------------------------------------------
+You need an SMS enabled Plivo phone number to send from. Buy or view your numbers in the Plivo console under Phone Numbers.
+
+Configuring the Plivo sink
+------------------------------------------------
+Now we're ready to configure the Plivo sink.
+
+.. admonition:: Add this to your generated_values.yaml
+
+ .. code-block:: yaml
+
+ sinksConfig:
+ - plivo_sink:
+ name: plivo_sink
+ auth_id:
+ auth_token:
+ from_number: # E.164 format, e.g. +14155551234
+ to_number: # E.164 format; for several recipients join them with '<'
+
+.. note::
+
+ Numbers use E.164 format. To send to more than one recipient, join the numbers with ``<`` (for example ``+14155551234<+14155555678``).
+
+Save the file and run
+
+.. code-block:: bash
+ :name: cb-add-plivo-sink
+
+ helm upgrade robusta robusta/robusta --values=generated_values.yaml
+
+You should now get playbook results as SMS messages from Plivo.
diff --git a/src/robusta/core/model/runner_config.py b/src/robusta/core/model/runner_config.py
index 5edb08b8e..db5ca0b83 100644
--- a/src/robusta/core/model/runner_config.py
+++ b/src/robusta/core/model/runner_config.py
@@ -25,6 +25,7 @@
from robusta.core.sinks.webex.webex_sink_params import WebexSinkConfigWrapper
from robusta.core.sinks.webhook.webhook_sink_params import WebhookSinkConfigWrapper
from robusta.core.sinks.yamessenger.yamessenger_sink_params import YaMessengerSinkConfigWrapper
+from robusta.core.sinks.plivo.plivo_sink_params import PlivoSinkConfigWrapper
from robusta.core.sinks.pushover.pushover_sink_params import PushoverSinkConfigWrapper
from robusta.core.sinks.zulip.zulip_sink_params import ZulipSinkConfigWrapper
from robusta.model.alert_relabel_config import AlertRelabel
@@ -74,6 +75,7 @@ class RunnerConfig(BaseModel):
FileSinkConfigWrapper,
MailSinkConfigWrapper,
PushoverSinkConfigWrapper,
+ PlivoSinkConfigWrapper,
GoogleChatSinkConfigWrapper,
ServiceNowSinkConfigWrapper,
ZulipSinkConfigWrapper,
diff --git a/src/robusta/core/sinks/plivo/__init__.py b/src/robusta/core/sinks/plivo/__init__.py
new file mode 100644
index 000000000..efbe7af25
--- /dev/null
+++ b/src/robusta/core/sinks/plivo/__init__.py
@@ -0,0 +1,2 @@
+from robusta.core.sinks.plivo.plivo_sink import PlivoSink
+from robusta.core.sinks.plivo.plivo_sink_params import PlivoSinkConfigWrapper, PlivoSinkParams
diff --git a/src/robusta/core/sinks/plivo/plivo_client.py b/src/robusta/core/sinks/plivo/plivo_client.py
new file mode 100644
index 000000000..d77960f58
--- /dev/null
+++ b/src/robusta/core/sinks/plivo/plivo_client.py
@@ -0,0 +1,26 @@
+import logging
+
+import requests
+
+PLIVO_API_BASE = "https://api.plivo.com/v1/Account"
+
+
+class PlivoClient:
+ def __init__(self, auth_id: str, auth_token: str):
+ self.auth_id = str(auth_id)
+ self.auth_token = str(auth_token)
+
+ def send_message(self, src: str, dst: str, text: str):
+ url = f"{PLIVO_API_BASE}/{self.auth_id}/Message/"
+ payload = {"src": src, "dst": dst, "text": text, "type": "sms"}
+
+ try:
+ response = requests.post(
+ url, json=payload, auth=(self.auth_id, self.auth_token), timeout=(5, 15)
+ )
+ if not response.ok:
+ logging.error(
+ f"Failed to send Plivo SMS to {dst}: {response.status_code} {response.reason} {response.text}"
+ )
+ except Exception as e:
+ logging.error(f"Error sending Plivo SMS to {dst}: {e}", exc_info=True)
diff --git a/src/robusta/core/sinks/plivo/plivo_sink.py b/src/robusta/core/sinks/plivo/plivo_sink.py
new file mode 100644
index 000000000..e73306d49
--- /dev/null
+++ b/src/robusta/core/sinks/plivo/plivo_sink.py
@@ -0,0 +1,38 @@
+from typing import List
+
+from robusta.core.reporting.base import Finding
+from robusta.core.sinks.plivo.plivo_client import PlivoClient
+from robusta.core.sinks.plivo.plivo_sink_params import PlivoSinkConfigWrapper
+from robusta.core.sinks.sink_base import SinkBase
+
+MAX_SMS_LENGTH = 1600
+
+
+class PlivoSink(SinkBase):
+ def __init__(self, sink_config: PlivoSinkConfigWrapper, registry):
+ super().__init__(sink_config.plivo_sink, registry)
+
+ self.client = PlivoClient(
+ sink_config.plivo_sink.auth_id,
+ sink_config.plivo_sink.auth_token.get_secret_value(),
+ )
+ self.from_number = sink_config.plivo_sink.from_number
+ self.to_number = sink_config.plivo_sink.to_number
+
+ def write_finding(self, finding: Finding, platform_enabled: bool):
+ message = self.__build_message(finding, platform_enabled)
+ self.client.send_message(src=self.from_number, dst=self.to_number, text=message)
+
+ def __build_message(self, finding: Finding, platform_enabled: bool) -> str:
+ lines: List[str] = [f"{finding.severity.name} - {finding.title}"]
+
+ if platform_enabled:
+ lines.append(f"Investigate: {finding.get_investigate_uri(self.account_id, self.cluster_name)}")
+
+ lines.append(f"Source: {self.cluster_name}")
+
+ if finding.description:
+ lines.append(finding.description)
+
+ message = "\n".join(line for line in lines if line)
+ return message[:MAX_SMS_LENGTH]
diff --git a/src/robusta/core/sinks/plivo/plivo_sink_params.py b/src/robusta/core/sinks/plivo/plivo_sink_params.py
new file mode 100644
index 000000000..1f39e54c5
--- /dev/null
+++ b/src/robusta/core/sinks/plivo/plivo_sink_params.py
@@ -0,0 +1,22 @@
+from pydantic import SecretStr
+
+from robusta.core.sinks.sink_base_params import SinkBaseParams
+from robusta.core.sinks.sink_config import SinkConfigBase
+
+
+class PlivoSinkParams(SinkBaseParams):
+ auth_id: str
+ auth_token: SecretStr
+ from_number: str
+ to_number: str
+
+ @classmethod
+ def _get_sink_type(cls):
+ return "plivo"
+
+
+class PlivoSinkConfigWrapper(SinkConfigBase):
+ plivo_sink: PlivoSinkParams
+
+ def get_params(self) -> SinkBaseParams:
+ return self.plivo_sink
diff --git a/src/robusta/core/sinks/sink_factory.py b/src/robusta/core/sinks/sink_factory.py
index 96ec8f3d3..76375b0ef 100644
--- a/src/robusta/core/sinks/sink_factory.py
+++ b/src/robusta/core/sinks/sink_factory.py
@@ -29,6 +29,7 @@
from robusta.core.sinks.webex import WebexSink, WebexSinkConfigWrapper
from robusta.core.sinks.webhook import WebhookSink, WebhookSinkConfigWrapper
from robusta.core.sinks.yamessenger import YaMessengerSink, YaMessengerSinkConfigWrapper
+from robusta.core.sinks.plivo import PlivoSink, PlivoSinkConfigWrapper
from robusta.core.sinks.pushover import PushoverSink, PushoverSinkConfigWrapper
from robusta.core.sinks.zulip import ZulipSink, ZulipSinkConfigWrapper
from robusta.core.sinks.incidentio.incidentio_sink import IncidentioSink
@@ -56,6 +57,7 @@ class SinkFactory:
FileSinkConfigWrapper: FileSink,
MailSinkConfigWrapper: MailSink,
PushoverSinkConfigWrapper: PushoverSink,
+ PlivoSinkConfigWrapper: PlivoSink,
GoogleChatSinkConfigWrapper: GoogleChatSink,
ServiceNowSinkConfigWrapper: ServiceNowSink,
ZulipSinkConfigWrapper: ZulipSink,