Static Documentation

Provider API

Version latest · Updated 2026-08-17
Interactive docs View on GitHub

Provider API#

Every provider module must define a class named Provider.

The class must inherit from:

app.notifiers.voice.base.BaseVoiceProvider

Minimal provider#

from app.notifiers.voice.base import (
    BaseVoiceProvider,
    VoiceCallRequest,
    VoiceCallResult,
    VoiceProviderCapabilities,
)


class Provider(BaseVoiceProvider):
    """Minimal custom voice provider."""

    name = "example"

    capabilities = VoiceProviderCapabilities(
        tts=True,
        status_callback=False,
        dtmf_callback=False,
        status_polling=False,
    )

    def place_call(self, request: VoiceCallRequest) -> VoiceCallResult:
        """Place a voice call."""

        print(f"Calling {request.phone}: {request.text}")

        return VoiceCallResult(
            call_id="example-call-id",
            status="queued",
            raw={"provider": self.name},
        )

Provider methods#

A provider may implement:

place_call()
parse_callback()
get_call_status()
validate_config()

Only place_call() is required.

Callback and polling methods are optional and depend on what your provider supports.

BaseVoiceProvider#

class BaseVoiceProvider:
    name = "base"

    capabilities = VoiceProviderCapabilities()

    def __init__(self, config: dict[str, Any] | None = None) -> None:
        self.config = config or {}

    @classmethod
    def validate_config(cls, config: dict[str, Any]) -> None:
        """Validate provider-specific configuration."""

    def place_call(self, request: VoiceCallRequest) -> VoiceCallResult:
        """Place a voice call."""

        raise NotImplementedError

    def parse_callback(
        self,
        payload: dict[str, Any],
        headers: dict[str, str] | None = None,
        raw_body: bytes | None = None,
        query_args: dict[str, Any] | None = None,
    ) -> list[VoiceCallCallbackEvent]:
        """Parse provider webhook callback."""

        return []

    def get_call_status(self, call_id: str) -> VoiceCallResult:
        """Return current call status."""

        raise NotImplementedError

Capabilities#

Each provider should declare its capabilities.

from app.notifiers.voice.base import VoiceProviderCapabilities


class Provider(BaseVoiceProvider):
    name = "mango"

    capabilities = VoiceProviderCapabilities(
        tts=True,
        status_callback=True,
        dtmf_callback=True,
        status_polling=False,
    )

tts#

Provider can receive text and play it during a call.

status_callback#

Provider can send webhook callbacks with call status changes.

Recommended statuses:

queued
ringing
answered
completed
failed
busy
no_answer
cancelled
unknown

dtmf_callback#

Provider can send webhook callbacks when the user presses phone keypad buttons.

Example:

1 -> acknowledge
2 -> resolve

status_polling#

Provider can return call status through an API request.

This is useful when the provider does not support callbacks.

VoiceCallRequest#

place_call() receives one VoiceCallRequest.

def place_call(self, request: VoiceCallRequest) -> VoiceCallResult:
    ...

Fields#

FieldDescription
request.phoneTarget phone number
request.textText that should be spoken during the call
request.alert_idIncidentRelay alert ID
request.event_typeNotification event type: notification, reminder, escalation, test
request.callback_urlCallback URL for status and DTMF events
request.callback_secretServer-only callback credential; send it in Authorization: Bearer ... (or X-IncidentRelay-Callback-Secret), never in the URL
request.severityAlert severity
request.titleAlert title
request.messageAlert message
request.assigneeHuman-readable assignee name
request.teamTeam slug
request.action_hintsRecommended keypad actions
request.metadataAdditional IncidentRelay metadata

Example action_hints:

{
    "1": "acknowledge",
    "2": "resolve",
}

Example metadata:

{
    "channel_id": 1,
    "channel_name": "infra-voice-critical",
    "channel_type": "voice_call",
}

VoiceCallResult#

place_call() and get_call_status() must return VoiceCallResult.

return VoiceCallResult(
    call_id="abc-123",
    status="queued",
    raw=response_data,
)

call_id#

External call ID returned by the provider.

IncidentRelay stores it as external_message_id.

This ID is later used to match provider callbacks with the original alert notification.

status#

Normalized provider status.

Recommended values:

queued
ringing
answered
completed
failed
busy
no_answer
cancelled
logged
unknown

raw#

Original provider response or useful debug information.

Do not put secrets into raw.

VoiceCallCallbackEvent#

parse_callback() must return a list of VoiceCallCallbackEvent objects.

return [
    VoiceCallCallbackEvent(
        call_id="abc-123",
        event_type="dtmf",
        status="answered",
        digit="1",
        raw=payload,
    )
]

Fields#

FieldDescription
call_idExternal provider call ID
event_typeNormalized event type: status, dtmf, error
statusCall status
digitDTMF digit pressed by the call recipient
actionOptional normalized IncidentRelay action
alert_idOptional alert ID
messageOptional human-readable callback message
rawOriginal provider callback payload

Supported actions:

acknowledge
resolve