diff --git a/gracedb/alert.py b/gracedb/alert.py
index 846a248aab89745e6f6d2c1ea2054085718b6da2..101f0f0a98594a55969db1976e1ffa9c158cc84e 100644
--- a/gracedb/alert.py
+++ b/gracedb/alert.py
@@ -4,6 +4,7 @@ from subprocess import Popen, PIPE, STDOUT
 
 from django.core.mail import EmailMessage
 from django.conf import settings
+from django.contrib.auth.models import Group
 
 import json
 
@@ -31,6 +32,79 @@ def get_twilio_from():
         return from_.phone_number
     raise RuntimeError('Could not determine "from" Twilio phone number')
 
+def make_twilio_calls(event, twilio_recips, alert_type, **kwargs):
+    """
+    USAGE:
+    ------
+        New event created:
+            make_twilio_calls(event, twilio_recips, "create")
+        New label applied to event (Label is a GraceDB model):
+            make_twilio_calls(event, twilio_recips, "label", label=Label)
+
+    Note: twilio_recips is a list of users - we need phone numbers
+          and group memberships for permission checks.
+    """
+    
+    if (alert_type == "create"):
+        # twiml_base_url is the URL of a TwiML Bin
+        # (https://support.twilio.com/hc/en-us/articles/230878368)
+        # with the following content:
+        #
+        #     <?xml version="1.0" encoding="UTF-8"?>
+        #     <Response>
+        #     <Say>
+        #     A {{pipeline}} event with Grace DB ID {{graceid}} was created.
+        #     </Say>
+        #     <Sms>
+        #     A {{pipeline}} event with GraceDB ID {{graceid}} was created.
+        #     https://gracedb-test.ligo.org/events/view/{{graceid}}
+        #     </Sms>
+        #     </Response>
+        twiml_base_url = 'https://handler.twilio.com/twiml/' + settings.TWILIO_CREATE_KEY
+        twiml_url = '{0}?pipeline={1}&graceid={2}'.format(
+            twiml_base_url, event.pipeline.name, event.graceid())
+    elif (alert_type == "label"):
+        # twiml_base_url is the URL of a TwiML Bin
+        # (https://support.twilio.com/hc/en-us/articles/230878368)
+        # with the following content:
+        #
+        #     <?xml version="1.0" encoding="UTF-8"?>
+        #     <Response>
+        #     <Say>
+        #     A {{pipeline}} event with Grace DB ID {{graceid}} was labelled with {{label_lower}}.
+        #     </Say>
+        #     <Sms>
+        #     A {{pipeline}} event with GraceDB ID {{graceid}} was labelled with {{label}}
+        #     https://gracedb-test.ligo.org/events/view/{{graceid}}
+        #     </Sms>
+        #     </Response>
+        twiml_base_url = 'https://handler.twilio.com/twiml/' + settings.TWILIO_LABEL_KEY
+        label = kwargs['label']
+        twiml_url = '{0}?pipeline={1}&graceid={2}&label={3}&label_lower={4}'.format(
+            twiml_base_url, event.pipeline.name, event.graceid(), label.name, label.name.lower())
+    else:
+        log.exception('Failed to process alert_type in make_twilio_calls')
+
+    # Get "from" phone number.
+    from_ = get_twilio_from()
+    
+    # Get LVC user group for checks made below.
+    lvc_group = Group.objects.get(name=settings.LVC_GROUP)
+    
+    # Loop over recipients and make calls.
+    for recip in twilio_recips:
+        try:
+            # Only make calls to LVC members. Non-LVC members shouldn't
+            # even be able to sign up with a phone number, but this is another
+            # safety measure.
+            if lvc_group in recip.user.groups.all():
+                log.info('calling %s', recip.user.username)
+                twilio_client.calls.create(recip.phone, from_, twiml_url, method='GET')
+            else:
+                log.info('user %s is not an LVC member, call not made' % recip.user.username)
+        except:
+            log.exception('Failed to create call')
+
 def issueAlert(event, location, event_url, serialized_object=None):
     issueXMPPAlert(event, location, serialized_object=serialized_object)
     issueEmailAlert(event, event_url)
@@ -87,7 +161,7 @@ def issueAlertForLabel(event, label, doxmpp, serialized_event=None, event_url=No
             if recip.email:
                 profileRecips.append(recip.email)
             if recip.phone:
-                phoneRecips.append(recip.phone)
+                phoneRecips.append(recip)
 
     if event.search:
         subject = "[gracedb] %s / %s / %s / %s" % (label.name, event.pipeline.name, event.search.name, event.graceid())
@@ -115,35 +189,8 @@ def issueAlertForLabel(event, label, doxmpp, serialized_event=None, event_url=No
         email = EmailMessage(subject, message, fromaddress, toaddresses, bccaddresses)
         email.send()
 
-    # twiml_base_url is the URL of a TwiML Bin
-    # (https://support.twilio.com/hc/en-us/articles/230878368)
-    # with the following content:
-    #
-    #     <?xml version="1.0" encoding="UTF-8"?>
-    #     <Response>
-    #     <Say>
-    #     A {{pipeline}} event with Grace DB ID {{graceid}} was labelled with {{label_lower}}.
-    #     </Say>
-    #     <Sms>
-    #     A {{pipeline}} event with GraceDB ID {{graceid}} was labelled with {{label}}
-    #     https://gracedb-test.ligo.org/events/view/{{graceid}}
-    #     </Sms>
-    #     </Response>
-    twiml_base_url = 'https://handler.twilio.com/twiml/EH7a2cef360c90eec301c3bf325ce1790a'
-
-    twiml_url = '{0}?pipeline={1}&graceid={2}&label={3}&label_lower={4}'.format(
-        twiml_base_url, event.pipeline.name, event.graceid(), label.name, label.name.lower())
-    log.info('phoneRecips: %s' % phoneRecips)
-    from_ = get_twilio_from()
-    log.info('from_: %s' % from_)
-    for recip in phoneRecips:
-        log.info('in for loop')
-        try:
-            log.info('issueAlertForLabel: calling %s', recip)
-            twilio_client.calls.create(recip, from_, twiml_url, method='GET')
-        except:
-            log.exception('Failed to create call')
-
+    # Make phone calls.
+    make_twilio_calls(event, phoneRecips, "label", label=label)
 
 def issueEmailAlert(event, event_url):
 
@@ -177,13 +224,13 @@ def issueEmailAlert(event, event_url):
                    if recip.email:
                        bccaddresses.append(recip.email)
                    if recip.phone:
-                       twilio_recips.append(recip.phone)
+                       twilio_recips.append(recip)
                else:
                    if event.far and event.far < trigger.farThresh:
                        if recip.email:
                            bccaddresses.append(recip.email)
                        if recip.phone:
-                           twilio_recips.append(recip.phone)
+                           twilio_recips.append(recip)
     subject = "[gracedb] %s event. ID: %s" % (event.pipeline.name, event.graceid())
     message = """
 New Event
@@ -207,33 +254,8 @@ Event Summary:
     email = EmailMessage(subject, message, fromaddress, toaddresses, bccaddresses)
     email.send()
 
-    #send_mail(subject, message, fromaddress, toaddresses)
-
-    # twiml_base_url is the URL of a TwiML Bin
-    # (https://support.twilio.com/hc/en-us/articles/230878368)
-    # with the following content:
-    #
-    #     <?xml version="1.0" encoding="UTF-8"?>
-    #     <Response>
-    #     <Say>
-    #     A {{pipeline}} event with Grace DB ID {{graceid}} was created.
-    #     </Say>
-    #     <Sms>
-    #     A {{pipeline}} event with GraceDB ID {{graceid}} was created.
-    #     https://gracedb-test.ligo.org/events/view/{{graceid}}
-    #     </Sms>
-    #     </Response>
-    twiml_base_url = 'https://handler.twilio.com/twiml/EHe8ac043be47528c50558954791fb11fe'
-
-    twiml_url = '{0}?pipeline={1}&graceid={2}'.format(
-        twiml_base_url, event.pipeline.name, event.graceid())
-    from_ = get_twilio_from()
-    for recip in twilio_recips:
-        try:
-            log.info('issueEmailAlert: calling %s', recip)
-            twilio_client.calls.create(recip, from_, twiml_url, method='GET')
-        except:
-            log.exception('Failed to create call')
+    # Make phone calls.
+    make_twilio_calls(event, twilio_recips, "create")
 
 def issueXMPPAlert(event, location, alert_type="new", description="", serialized_object=None):
     
diff --git a/userprofile/forms.py b/userprofile/forms.py
index a6f8a3209a4bc8852b2e268f2efddaff9af33d37..9d092e5f8dbdf8b324fc6b62f86dd016940976a5 100644
--- a/userprofile/forms.py
+++ b/userprofile/forms.py
@@ -46,5 +46,7 @@ class TriggerForm(forms.ModelForm):
 class ContactForm(forms.ModelForm):
     class Meta:
         model = Contact
-        exclude = ['user']
-
+        fields = ['desc','email','phone']
+        help_texts = {
+            'phone': 'Prototype service: may not be available in the future.'
+        }
diff --git a/userprofile/migrations/0004_add_contact_phone_number.py b/userprofile/migrations/0004_add_contact_phone_number.py
new file mode 100644
index 0000000000000000000000000000000000000000..d262aa1aecfc40cbd90d6788ccfaead3a14d5b2c
--- /dev/null
+++ b/userprofile/migrations/0004_add_contact_phone_number.py
@@ -0,0 +1,25 @@
+# -*- coding: utf-8 -*-
+from __future__ import unicode_literals
+
+from django.db import migrations, models
+import userprofile.models
+
+
+class Migration(migrations.Migration):
+
+    dependencies = [
+        ('userprofile', '0003_trigger_label_query'),
+    ]
+
+    operations = [
+        migrations.AddField(
+            model_name='contact',
+            name='phone',
+            field=userprofile.models.PhoneNumberField(blank=True, max_length=255, validators=[userprofile.models.validate_phone, userprofile.models.validate_phone, userprofile.models.validate_phone]),
+        ),
+        migrations.AlterField(
+            model_name='contact',
+            name='email',
+            field=models.EmailField(max_length=254, blank=True),
+        ),
+    ]