Never miss a call

Voicemail, missed-call SMS and forwarding with a fallback.

Text back missed calls

Rings your whole team at once; if nobody picks up, callers on a mobile get an instant SMS saying you will call back, and your team gets the caller's number by SMS and email.

How it works

  1. Someone calls your number and all your team phones ring at the same time.
  2. The first person to pick up takes the call.
  3. If nobody answers, a caller on a mobile gets a text saying you will call them back, then hears a short apology.
  4. Your team gets the caller's number by SMS and email, even if the caller hung up while it was ringing.
  5. Optionally, the missed call is also sent to your CRM or app.

Starts on: inbound-call
Actions used: dial@v2, answer@v1, sms@v1, play@v3, hangup@v1, email@v1, fetch@v3
Guide: Send SMS within a Call Flow

# Missed call text-back.
# Every inbound call rings your team at the same time.
# If nobody picks up, callers on a mobile get an SMS saying you will call
# them back, and your team gets the caller's number by SMS and email.
#
# What to edit: the MODIFIABLE VARIABLES below (team numbers, text-back
# message, alert recipients, optional webhook).
# Needs: SMS credit. The optional webhook must accept requests from the
# Callr IP ranges: https://docs.callr.com/docs/ip-subnets
# Build Mode: calls and SMS only go to your Testing Numbers.
# Docs: https://docs.callr.com/docs/send-sms-in-a-call-flow

description: "Text back missed calls"

compat:
  version: "2025-09-01"

defaults:
  # The caller hears ringing until someone answers
  autoAnswer: false
  language: en-US
  voice: en-US-Olivia:MAI-Voice-2

variables:
  $dial: null

  # MODIFIABLE VARIABLES BELOW
  $targets: # team phones, all ringing at the same time
    - number: "+15550100001"
      timeout: 25
    - number: "+15550100002"
      timeout: 25
  $textBack: Hi, you just called us and we could not pick up. We will call you back as soon as possible. # SMS sent to mobile callers
  $teamSms: # numbers alerted by SMS on a missed call
    - "+15550100001"
  $teamEmail: # addresses alerted by email on a missed call
    - [email protected]
  $webhookUrl: null # e.g. https://api.example.com/missed-call to log missed calls in your CRM

branches:
  inbound-call:
    actions:
      # Ring every team phone, the first to answer takes the call
      - action: dial@v2
        params:
          targets: ${{ $targets }}
          parallel: true
        result: $dial

      - if: "!$dial?.ok"
        goto:
          branch: missed

  missed:
    actions:
      - action: answer@v1

      # Text the caller back, only on numbers that can receive SMS (mobiles)
      - if: /MOBILE/.test(call.fromType ?? '') && call.fromNumber
        action: sms@v1
        params:
          to:
            - ${{ call.fromNumber }}
          body: ${{ $textBack }}
          nature: ALERTING
          # Approved sender ID or one of your Callr numbers
          # from: MyCompany

      - action: play@v3
        params:
          tts:
            text: Sorry we missed your call. We will call you back as soon as possible.

      - action: hangup@v1

  # Runs when the call ends, also when the caller hangs up while it rings
  hangup:
    actions:
      - if: "!$dial?.ok"
        then:
          - if: $teamSms?.length
            action: sms@v1
            params:
              to: ${{ $teamSms }}
              body: Missed call from ${{ call.fromNumber ?? '(hidden number)' }} to ${{ call.toNumber }}.
              nature: ALERTING

          - if: $teamEmail?.length
            action: email@v1
            params:
              to: ${{ $teamEmail }}
              subject: Missed call from ${{ call.fromNumber ?? '(hidden number)' }}
              text: |
                Hello,

                You missed a call from ${{ call.fromNumber ?? '(hidden number)' }} to ${{ call.toNumber }}.
                Time (UTC): ${{ new Date(now).toISOString().slice(0, 16).replace('T', ' ') }}
                Line type: ${{ call.fromType ?? 'unknown' }}

                Please call them back.

          - if: $webhookUrl
            action: fetch@v3
            params:
              url: ${{ $webhookUrl }}
              method: POST
              headers:
                Content-Type: application/json
              body: |
                {
                  "event": "missed-call",
                  "from": ${{ JSON.stringify(call.fromNumber ?? null) }},
                  "to": ${{ JSON.stringify(call.toNumber) }},
                  "fromType": ${{ JSON.stringify(call.fromType ?? null) }},
                  "time": ${{ JSON.stringify(new Date(now).toISOString()) }},
                  "dialStatus": ${{ JSON.stringify($dial?.status ?? null) }}
                }

Forwarding with voicemail

Rings your number with a whisper; if nobody answers, the caller gets a text-back and leaves a message that is transcribed and sent to you by SMS and email.

How it works

  1. Someone calls: they hear a short greeting, then your number rings.
  2. When you pick up, you hear who the call is for, then you are connected to the caller.
  3. If nobody answers, or your own mobile voicemail picks up, a caller on a mobile gets a text saying you will call back.
  4. The caller leaves a message, can listen to it and record it again.
  5. You get the transcribed message by SMS and email, or a missed-call alert if they hung up without a message, even while your number was still ringing.

Starts on: inbound-call
Actions used: ringing@v1, wait@v1, answer@v1, play@v3, dial@v2, amd@v3, hangup@v1, bridge@v3, sms@v1, record@v1, gather@v4, playRecordingFile@v1, javascript@v1, saveRecordingFile@v1, email@v1
Guide: Send SMS within a Call Flow

# Forwards inbound calls to your number with a whisper ("This is a call from...").
# If nobody answers (or the target's own voicemail picks up), the caller gets
# a text-back SMS and can leave a message. The message is transcribed and sent
# to you by SMS and email. Missed calls without a message are notified too.
#
# What to edit: the variables below the MODIFIABLE VARIABLES line, and the
# whisper and greeting texts.
# Needs: a number to forward to, a mobile for the SMS alerts, an email address.
# Build Mode: calls and SMS only reach your Testing Numbers.
# Docs: https://docs.callr.com/docs/send-sms-in-a-call-flow

description: "Forwarding with voicemail"

compat:
  version: "2025-09-01"

defaults:
  language: en-US
  voice: en-US-Ethan:MAI-Voice-2
  # The call keeps ringing until answer@v1 below
  autoAnswer: false

variables:
  $dial: null
  $amd: null
  $dtmf: null
  $voicemail: null # temporary file of the message
  $tries: 0 # menu attempts

  # MODIFIABLE VARIABLES BELOW
  # Number to forward the calls to, international format
  $callTarget: "+15550100001"
  # Ring duration in seconds, keep it short so the target's mobile voicemail does not pick up first
  $callTimeout: 18
  # Mobile that receives the missed-call SMS (null to disable)
  $smsTarget: "+15550100001"
  # Email address that receives the missed-call emails (null to disable)
  $email: [email protected]
  # Detect the target's own voicemail and take the message here instead
  $detectVoicemailOnTarget: true

branches:
  # The 'inbound-call' branch defines the actions for incoming calls
  inbound-call:
    actions:
      - action: ringing@v1

      - action: wait@v1
        params:
          seconds: 2

      - action: answer@v1

      # Greeting message
      - action: play@v3
        params:
          tts:
            text: Hello! Please wait while we connect you.

      # Call forwarding to the target number
      - if: $callTarget
        action: dial@v2
        params:
          targets:
            - number: ${{ $callTarget }}
              timeout: ${{ $callTimeout }}
          answerOnBranch: targetAnswered
        result: $dial

      # If the target does not answer in time, go to voicemail
      - if: "!$dial?.ok"
        goto:
          branch: voicemail

  # The custom 'targetAnswered' branch defines actions when the target answers
  # These actions are played only for the recipient
  targetAnswered:
    actions:
      - if: $detectVoicemailOnTarget
        then:
          # Is the target on voicemail?
          # Automatic answering machine detection
          - action: amd@v3
            params:
              timeout: 6
              minWords: 4 # if more than minWords are said => voicemail
              yesHints:
                # these words are often heard in voicemails
                - voicemail
                - message
                - tone
              noHints:
                # these words are often heard in human conversations
                - "yes"
            result: $amd

          # If the target is on voicemail, hang up the outgoing call.
          # The caller will be redirected to our own voicemail.
          - if: $amd?.detected == 'machine'
            action: hangup@v1

      # Whisper to the target about the call.
      # The caller keeps hearing the ringing tone.
      - action: play@v3
        params:
          tts:
            text: This is a call from (your brand).

      # Bridge the caller and the target
      - action: bridge@v3

      - action: hangup@v1

  # The 'voicemail' branch is used when the target number is not reachable
  voicemail:
    actions:
      # Text the caller back if they call from a mobile
      - if: call.fromType == 'MOBILE'
        action: sms@v1
        params:
          to:
            - ${{ call.fromNumber }}
          nature: ALERTING
          body: >
            Hello! You have tried to reach us.
            We will get back to you ASAP.
          # Sent from your account's default sender. To show an approved
          # sender ID or one of your SMS-capable Callr numbers:
          # from: MyCompany

      # We are not available.
      - action: play@v3
        params:
          tts:
            text: Sorry, we are not available at the moment.

      - label: record
        action: play@v3
        params:
          tts:
            text: Leave us a message after the tone and we will call you back.

      # The 'record@v1' action records the caller
      # A temporary file is created, and its name is stored in the variable $voicemail
      - action: record@v1
        params:
          maxLength: 120 # seconds
        result: $voicemail

      # Gather will wait for a DTMF
      - label: menu
        action: gather@v4
        params:
          maxDigits: 1
          timeout: 15
          tts:
            # You can use multi-line YAML strings
            text: |
              To listen to your message, press 1.
              To send your message, press 2.
              To record your message again, press 3.
        result: $dtmf

      - if: $dtmf?.input == '1'
        then:
          - action: playRecordingFile@v1
            params:
              file: ${{ $voicemail }}
          - goto:
              label: menu

      - if: $dtmf?.input == '3'
        then:
          - action: javascript@v1
            params:
              code: $voicemail = null # reset the variable $voicemail
          - goto:
              label: record

      # Press 2, or no valid choice after 3 attempts: send the message
      - if: $dtmf?.input == '2' || $tries >= 2
        then:
          - action: play@v3
            params:
              tts:
                text: We have received your message, thank you!
          - action: hangup@v1

      - action: javascript@v1
        params:
          code: $tries++

      - action: play@v3
        params:
          tts:
            text: Sorry, I did not get that.

      - goto:
          label: menu

  # Runs when the call ends, also when the caller hangs up while your number rings
  hangup:
    actions:
      # Notify only missed calls: nothing to do if the target took the call
      - if: "!$dial?.ok"
        then:
          - if: $voicemail
            then:
              # Save the recording for processing.
              - action: saveRecordingFile@v1
                params:
                  file: ${{ $voicemail }}
                events:
                  # When the file has been processed, you can execute actions on it
                  ready:
                    # Notify the target via SMS of the missed call
                    - if: $smsTarget
                      action: sms@v1
                      params:
                        nature: ALERTING
                        body: |
                          You have a missed call from ${{ call.fromNumber ?? '(hidden number)' }}.
                          « ${{ transcription_leg_a }} »
                        to:
                          - ${{ $smsTarget }}

                    # Also send email notification
                    - if: $email
                      action: email@v1
                      params:
                        subject: Missed call from ${{ call.fromNumber ?? '(hidden number)' }}
                        text: |
                          Hello,

                          You have a missed call from: ${{ call.fromNumber ?? '(hidden number)' }}.
                          Number called: ${{ call.toNumber }} (${{ scenario.name }}).

                          « ${{ transcription_leg_a }} »

                          You can download the message here: ${{ recording.url }}
                        to:
                          - ${{ $email }}

          - if: "!$voicemail"
            then:
              # SMS notification for a missed call without a message
              - if: $smsTarget
                action: sms@v1
                params:
                  nature: ALERTING
                  body: >
                    Missed call from ${{ call.fromNumber ?? '(hidden number)' }}.
                    No voicemail left by the caller.
                  to:
                    - ${{ $smsTarget }}

              # Also send email notification
              - if: $email
                action: email@v1
                params:
                  subject: Missed call from ${{ call.fromNumber ?? '(hidden number)' }}
                  text: |
                    Hello,

                    You have missed a call from: ${{ call.fromNumber ?? '(hidden number)' }}.
                    Number called: ${{ call.toNumber }} (${{ scenario.name }}).

                    The caller did not leave a message.
                  to:
                    - ${{ $email }}

Voicemail with transcription

The number goes straight to voicemail; callers can listen back and re-record, and the transcript is sent to you by email, SMS and to your webhook.

How it works

  1. Someone calls: they hear that you are not available and are asked to leave a message.
  2. After the tone, they record their message.
  3. They can listen to it, record it again, or send it.
  4. Once the message is transcribed, you get it by email and SMS, and your server receives it if you set a webhook.

Starts on: inbound-call
Actions used: wait@v1, play@v3, record@v1, gather@v4, playRecordingFile@v1, javascript@v1, hangup@v1, saveRecordingFile@v1, sms@v1, email@v1, fetch@v3
Guide: Send Emails within a Call Flow

# The number goes straight to voicemail: it never forwards the call.
# Callers can listen back to their message and record it again. Once the
# message is transcribed, it is sent to you by email and SMS, and to your
# webhook if you set one.
#
# What to edit: the variables below the MODIFIABLE VARIABLES line.
# Needs: an email address, a mobile for the SMS, optionally a webhook URL.
# Build Mode: SMS only reach your Testing Numbers.
# Docs: https://docs.callr.com/docs/send-an-email-within-a-call-flow
# Webhook: allow Callr's IP ranges, see https://docs.callr.com/docs/ip-subnets

description: "Voicemail with transcription"

compat:
  version: "2025-09-01"

defaults:
  # define a default voice for Speech
  voice: en-US-Olivia:MAI-Voice-2
  language: en-US

variables:
  $dtmf: null
  $file: null # temporary file of the message
  $tries: 0 # menu attempts

  # MODIFIABLE VARIABLES BELOW
  # Email addresses that receive the voicemail (empty list to disable)
  $emailTargets:
    - [email protected]
    - [email protected]
  # Mobile that receives the voicemail by SMS (null to disable)
  $smsTarget: "+15550100001"
  # Your server receives the voicemail as JSON (null to disable), e.g. https://api.example.com/voicemail
  $webhookUrl: null
  # Sender name shown in the email
  $companyName: My Company

branches:
  # The 'inbound-call' branch defines the actions for incoming calls
  inbound-call:
    actions:
      - action: wait@v1
        params:
          seconds: 2

      # Let's say we cannot take this call
      - action: play@v3
        params:
          tts:
            text: Sorry, we are not available at the moment.

      # Continue to another branch
      - goto:
          branch: voicemail

  voicemail:
    actions:
      - label: start
        action: play@v3
        params:
          tts:
            text: Please leave a message after the tone.

      # The 'record@v1' action records the caller
      # A temporary file is created and stored in the $file variable
      - action: record@v1
        params:
          maxLength: 120 # seconds
        result: $file

      # Gather will wait for a DTMF
      - label: menu
        action: gather@v4
        params:
          maxDigits: 1
          timeout: 15
          tts:
            # You can leverage YAML multi line strings
            text: |
              To listen to your message, press 1.
              To send this message, press 2.
              To re-record this message, press 3.
        result: $dtmf

      - if: $dtmf?.input == '1'
        then:
          - action: playRecordingFile@v1
            params:
              file: ${{ $file }}
          - goto:
              label: menu

      - if: $dtmf?.input == '3'
        then:
          - action: javascript@v1
            params:
              code: $file = null # reset the $file variable
          - goto:
              label: start

      # Press 2, or no valid choice after 3 attempts: send the message
      - if: $dtmf?.input == '2' || $tries >= 2
        then:
          - action: play@v3
            params:
              tts:
                text: Your message has been delivered. Thank you!

          # Now we can hangup. The processing will continue in special branch "hangup".
          - action: hangup@v1

      - action: javascript@v1
        params:
          code: $tries++

      - action: play@v3
        params:
          tts:
            text: Sorry, I did not get that.
      - goto:
          label: menu

  hangup:
    actions:
      - if: $file
        then:
          # saveRecordingFile will transcribe the recording by default
          - action: saveRecordingFile@v1
            params:
              file: ${{ $file }}
            events:
              # When the file is ready, define some actions
              ready:
                # Send an SMS to the voicemail owner
                - if: $smsTarget
                  action: sms@v1
                  params:
                    nature: ALERTING
                    body: >
                      You have a new voicemail from ${{ call.fromNumber ?? '(hidden number)' }}.
                      Transcription: "${{ transcription_leg_a }}"
                    to:
                      - ${{ $smsTarget }}

                # Send an email
                - if: $emailTargets?.length
                  action: email@v1
                  params:
                    fromName: ${{ $companyName }}
                    subject: You have a new voicemail from ${{ call.fromNumber ?? '(hidden number)' }}
                    text: |
                      Hello there!
                      You have a new voicemail from ${{ call.fromNumber ?? '(hidden number)' }}. Duration: ${{ recording.duration }}s.
                      "${{ transcription_leg_a }}".

                      You can download the file here: ${{ recording.url }}.
                    to: ${{ $emailTargets }}

                # Push the voicemail to your own server
                - if: $webhookUrl
                  action: fetch@v3
                  params:
                    url: ${{ $webhookUrl }}
                    method: POST
                    body: |
                      {
                        "type": "voicemail",
                        "call": ${{ JSON.stringify(call) }},
                        "recording": ${{ JSON.stringify(recording) }},
                        "transcription": ${{ JSON.stringify(transcription_leg_a) }}
                      }
                    headers:
                      Content-Type: application/json
                      # If your server requires a header
                      # Authorization: Bearer your-token

Did this page help you?