diff --git a/gracedb/api.py b/gracedb/api.py
index 7a998ff9c56d6de53932913b063a40d54cb3d73b..14fadd595ecc83bee0d7af73d9d743f02c51de3b 100644
--- a/gracedb/api.py
+++ b/gracedb/api.py
@@ -20,7 +20,6 @@ from view_logic import create_label, get_performance_info
 from view_logic import _createEventFromForm
 from view_logic import create_eel
 from view_logic import create_emobservation
-from view_utils import fix_old_creation_request
 from view_utils import eventToDict, eventLogToDict, labelToDict
 from view_utils import embbEventLogToDict, voeventToDict
 from view_utils import emObservationToDict, skymapViewerEMObservationToDict
@@ -491,17 +490,10 @@ class EventList(APIView):
 
     #@pipeline_auth_required
     def post(self, request, format=None):
-        # XXX Deal with POSTs coming in from the old client.
-        # Eventually, we will want to get rid of this check and just let it fail.
         rv = {}
         rv['warnings'] = []
-        if 'type' in request.data:
-            request = fix_old_creation_request(request)
-            rv['warnings'] += ['It looks like you are using the old GraceDB client (v<=1.14). ' + \
-                             'Please update! This will eventually stop working.']
 
         # Check user authorization for pipeline. 
-        # XXX This is a temporary hack until they roll out the new client.
         group_name = request.data.get('group', None) 
         if not group_name=='Test':
             try:
@@ -1553,22 +1545,6 @@ class GracedbRoot(APIView):
             "groups"    : [group.name for group in Group.objects.all()],
             "pipelines" : [pipeline.name for pipeline in Pipeline.objects.all()],
             "searches"  : [search.name for search in Search.objects.all()],
-            # XXX Retained for compatibility with old clients (v<=1.14).
-            # Should eventually be removed.
-            "analysis-types" : dict(
-                    (
-                        ("LM",  "LowMass"),
-                        ("HM",  "HighMass"),
-                        ("GRB", "GRB"),
-                        ("RD",  "Ringdown"),
-                        ("OM",  "Omega"),
-                        ("Q",   "Q"),
-                        ("X",   "X"),
-                        ("CWB", "CWB"),
-                        ("MBTA", "MBTAOnline"), 
-                        ("HWINJ", "HardwareInjection"),
-                    ) 
-                ),
             "em-groups"  : [g.name for g in EMGroup.objects.all()],
             "wavebands"      : dict(EMSPECTRUM),
             "eel-statuses"   : dict(EMBBEventLog.EEL_STATUS_CHOICES),
diff --git a/gracedb/cli_views.py b/gracedb/cli_views.py
deleted file mode 100644
index 29870efd45a160987c21a9a16712aca4ad20cb2a..0000000000000000000000000000000000000000
--- a/gracedb/cli_views.py
+++ /dev/null
@@ -1,254 +0,0 @@
-
-from django.http import HttpResponse, HttpResponseBadRequest, HttpResponseForbidden
-#from django.contrib.sites.models import Site
-from django.utils.html import strip_tags
-
-from models import Event, EventLog
-from forms import SimpleSearchForm
-
-from utils.vfile import VersionedFile
-
-from view_logic import create_label, _createLog
-from view_utils import assembleLigoLw
-from permission_utils import filter_events_for_user, user_has_perm, internal_user_required
-
-import os
-from django.conf import settings
-
-# XXX This should be configurable / moddable or something
-MAX_QUERY_RESULTS = 1000
-
-import json
-
-@internal_user_required
-def cli_search(request):
-    assert request.user
-    form = SimpleSearchForm(request.POST)
-    if form.is_valid():
-        objects = form.cleaned_data['query']
-        objects = filter_events_for_user(objects, request.user, 'view') 
-
-        if 'ligolw' in request.POST or 'ligolw' in request.GET:
-            from glue.ligolw import utils
-            if objects.count() > 1000:
-                return HttpResponseBadRequest("Too many events.")
-            xmldoc = assembleLigoLw(objects)
-            response = HttpResponse(content_type='application/xml')
-            response['Content-Disposition'] = 'attachment; filename=gracedb-query.xml'
-            utils.write_fileobj(xmldoc, response)
-            response['Warning'] = '299 - "The /cli URLs are deprecated and will be removed on March 8, 2016." "2016-01-12:10:30:00.000"'
-            return response
-
-        accessFun = {
-            "labels" : lambda e: \
-                ",".join([labelling.label.name for labelling in e.labelling_set.all()]),
-            "pipeline" : lambda e: e.pipeline.name,
-            #"search"  : lambda e: e.search.name or "",
-            "search"  : lambda e: e.search.name if e.search else "",
-            "gpstime" : lambda e: str(e.gpstime) or "",
-            "created" : lambda e: e.created.isoformat(),
-            "dataurl" : lambda e: e.weburl(),
-            "graceid" : lambda e: e.graceid(),
-            "group" : lambda e: e.group.name,
-        }
-        defaultAccess = lambda e, a: str(getattr(e,a,None) or "")
-
-        defaultColumns = "graceid,labels,group,pipeline,search,far,gpstime,created,dataurl"
-        columns = request.POST.get('columns')
-        if not columns:
-            columns = defaultColumns
-        columns = columns.split(',')
-
-        header = "#" + "\t".join(columns)
-        outTable = [header]
-        for e in objects:
-            row = [ accessFun.get(column, lambda e: defaultAccess(e,column))(e) for column in columns ]
-            outTable.append("\t".join(row))
-        d = {'output': "\n".join(outTable)}
-    else:
-        d = {'error': ""}
-        for key in form.errors:
-            d['error'] += "%s: %s\n" % (key, strip_tags(form.errors[key]))
-    response = HttpResponse(content_type='application/javascript')
-    msg = json.dumps(d)
-    response['Content-length'] = len(msg)
-    response.write(msg)
-    response['Warning'] = '299 - "The /cli URLs are deprecated and will be removed on March 8, 2016." "2016-01-12:10:30:00.000"'
-    return response
-
-@internal_user_required
-def cli_label(request):
-    graceid = request.POST.get('graceid')
-    labelName = request.POST.get('label')
-
-    doxmpp = request.POST.get('alert') == "True"
-    event = graceid and Event.getByGraceid(graceid)
-
-    if not user_has_perm(request.user, 'change', event):
-        return HttpResponseForbidden()
-
-    d = create_label(event, request, labelName, doXMPP=doxmpp)
-
-    msg = str(d)
-    response = HttpResponse(content_type='application/json')
-    response.write(msg)
-    response['Content-length'] = len(msg)
-
-    response['Warning'] = '299 - "The /cli URLs are deprecated and will be removed on March 8, 2016." "2016-01-12:10:30:00.000"'
-    return response
-
-@internal_user_required
-def cli_tag(request):
-    raise Exception("tag is not implemented.  Maybe you're thinking of 'label'?")
-    graceid = request.POST.get('graceid')
-    tagname = request.POST.get('tag')
-
-    event = graceid and Event.getByGraceid(graceid)
-
-    if not user_has_perm(request.user, 'change', event):
-        return HttpResponseForbidden()
-
-    event.add_tag(tagname)
-    msg = str({})
-    response = HttpResponse(content_type='application/json')
-    response.write(msg)
-    response['Content-length'] = len(msg)
-
-    response['Warning'] = '299 - "The /cli URLs are deprecated and will be removed on March 8, 2016." "2016-01-12:10:30:00.000"'
-    return response
-
-@internal_user_required
-def ping(request):
-    #ack = "(%s) " % Site.objects.get_current()
-    ack = "(%s/%s) " % (request.META['SERVER_NAME'], settings.CONFIG_NAME)
-    ack += request.POST.get('ack', None) or request.GET.get('ack','ACK')
-
-    from templatetags.timeutil import utc
-    if 'cli_version' in request.POST:
-        response = HttpResponse(content_type='application/json')
-        d = {'output': ack}
-        if 'extended' in request.POST:
-            latest = Event.objects.order_by("-id")[0]
-            if user_has_perm(request.user, 'view', latest):
-                d['latest'] = {}
-                d['latest']['id'] = latest.graceid()
-                d['latest']['created'] = str(utc(latest.created))
-        d =  json.dumps(d)
-        response.write(d)
-        response['Content-length'] = len(d)
-    else:
-        # Old client
-        response = HttpResponse(content_type='text/plain')
-        response.write(ack)
-        response['Content-length'] = len(ack)
-    response['Warning'] = '299 - "The /cli URLs are deprecated and will be removed on March 8, 2016." "2016-01-12:10:30:00.000"'
-    return response
-
-@internal_user_required
-def upload(request):
-    graceid = request.POST.get('graceid', None)
-    comment = request.POST.get('comment', None)
-    uploadedfile = request.FILES['upload']
-
-    try:
-        event = graceid and Event.getByGraceid(graceid)
-    except Event.DoesNotExist:
-        event = None
-
-    if not event:
-        return HttpResponseBadRequest("Event does not exist.")
-    if not user_has_perm(request.user, 'change', event):
-        return HttpResponseForbidden()
-
-    if 'cli_version' in request.POST:
-        response = _createLog(request, graceid, comment, uploadedfile)
-        response['Warning'] = '299 - "The /cli URLs are deprecated and will be removed on March 8, 2016." "2016-01-12:10:30:00.000"'
-        return response
-    # else: old, old client
-    response = HttpResponse(content_type='text/plain')
-    # uploadedFile.{name/chunks()}
-    try:
-        event = graceid and Event.getByGraceid(graceid)
-    except Event.DoesNotExist:
-        event = None
-    if not (comment and uploadedfile and graceid):
-        msg = "ERROR: missing arg(s)"
-    elif not event:
-        msg = "ERROR: Event '%s' does not exist" % graceid
-    else:
-        #event issuer comment
-        # XXX Note:  filename or comment oughta have a version
-        log = EventLog(event=event,
-                       issuer=request.user,
-                       filename=uploadedfile.name,
-                       comment=comment)
-        try:
-            log.save()
-            msg = "OK"
-        except:
-            msg = "ERROR: problem creating log entry"
-        try:
-            # XXX
-            # Badnesses:
-            #   Same hardcoded path in multiple places.
-            fname = os.path.join(event.datadir(), uploadedfile.name)
-            f = VersionedFile(fname, 'w')
-            for chunk in uploadedfile.chunks():
-                f.write(chunk)
-            f.close()
-            log.file_version = f.version
-            log.save()
-        except Exception, e:
-            msg = "ERROR: could not save file " + fname + " " + str(e)
-            log.delete()
-    response = HttpResponse(content_type='text/plain')
-    response.write(msg)
-    response['Content-length'] = len(msg)
-    response['Warning'] = '299 - "The /cli URLs are deprecated and will be removed on March 8, 2016." "2016-01-12:10:30:00.000"'
-    return response
-
-@internal_user_required
-def log(request):
-    message = request.POST.get('message')
-    graceid = request.POST.get('graceid')
-
-    try:
-        event = graceid and Event.getByGraceid(graceid)
-    except Event.DoesNotExist:
-        event = None
-
-    if not event:
-        return HttpResponseBadRequest("Event does not exist.")
-    if not user_has_perm(request.user, 'change', event):
-        return HttpResponseForbidden()
-
-    if 'cli_version' in request.POST:
-        response = _createLog(request, graceid, message)
-        response['Warning'] = '299 - "The /cli URLs are deprecated and will be removed on March 8, 2016." "2016-01-12:10:30:00.000"'
-        return response
-
-    # old, old client only
-    response = HttpResponse(content_type='text/plain')
-    try:
-        event = graceid and Event.getByGraceid(graceid)
-    except Event.DoesNotExist:
-        event = None
-
-    if not (message and graceid):
-        msg = "ERROR: missing arg(s)"
-    elif not event:
-        msg = "ERROR: Event '%s' does not exist" % graceid
-    else:
-        #event issuer comment
-        log = EventLog(event=event, issuer=request.user, comment=message)
-        try:
-            log.save()
-            msg = "OK"
-        except:
-            msg = "ERROR: problem creating log entry"
-
-    response = HttpResponse(content_type='text/plain')
-    response.write(msg)
-    response['Content-length'] = len(msg)
-    response['Warning'] = '299 - "The /cli URLs are deprecated and will be removed on March 8, 2016." "2016-01-12:10:30:00.000"'
-    return response
diff --git a/gracedb/view_utils.py b/gracedb/view_utils.py
index c19b6bc2bf01754161ea1ad8a031011c447d691f..41ebbd3869fc056ace27565d30af36913b3c06b1 100644
--- a/gracedb/view_utils.py
+++ b/gracedb/view_utils.py
@@ -755,76 +755,6 @@ def get_file(event, filename="event.log"):
         contents = None
     return contents
 
-#
-# A utility to 'fix' an event creation request coming from the old client.
-# The old client will provide 'analysisType' instead of 'pipeline' and 
-# 'search'. We will need to make an educated guess about the latter values
-# and stuff them into the POST dictionary *before* we try to bind the data
-# to the event creation form. This is modeled after migration 23, which 
-# attempts to set 'pipeline' and 'search' on old events from the 
-# analysisType era.
-#
-
-GSTLAL_SPIIR_SUBMITTERS = ['gstlal-spiir', 'qi.chu@LIGO.ORG', 'shinkee.chung@LIGO.ORG',]
-
-ANALYSIS_TYPE_TO_PIPELINE = {
-    'RD' : 'Ringdown',
-    'OM' : 'Omega',
-    'Q'  : 'Q',
-    'X'  : 'X',
-    'MBTA' : 'MBTAOnline',
-    'HWINJ' : 'HardwareInjection',
-}
-
-from VOEventLib.Vutil import parseString
-
-def fix_old_creation_request(request):
-    if not 'type' in request.POST:
-        # Fix apparently invoked by mistake.
-        return request
-    else:
-        atype = request.POST['type']
-        username = request.user.username
-
-        if atype=="LM":
-            search = 'LowMass'
-            if username in GSTLAL_SPIIR_SUBMITTERS:
-                pipeline = 'gstlal-spiir'
-            else:
-                pipeline = 'gstlal'
-        elif atype=="HM":
-            search = 'HighMass'
-            if username in GSTLAL_SPIIR_SUBMITTERS:
-                pipeline = 'gstlal-spiir'
-            else:
-                pipeline = 'gstlal'
-        # If the event is a GRB, decide whether it came from Fermi or 
-        # Swift. Assign all GRBs to the search 'GRB'.
-        elif atype=="GRB":
-            # Gonna have to crack the file open. Hopefully this won't actually consume it?
-            f = request.FILES['eventFile']
-            v = parseString(f.read())
-            how_description = v.get_How().get_Description()[0]
-            if how_description.startswith('Fermi'):
-                pipeline = 'Fermi'
-            else:
-                pipeline = 'Swift'
-            search = 'GRB'
-        # For all other analysis types, we just map the analysis type
-        # to the pipeline, and leave the search blank.
-        elif atype=="CWB":
-            pipeline = 'CWB'
-            search = 'AllSky'
-        elif atype in ANALYSIS_TYPE_TO_PIPELINE.keys():
-            pipeline = ANALYSIS_TYPE_TO_PIPELINE[atype]
-            search = None
-        else:
-            raise Exception("What kind of event is this anyway? atype=%s" % atype)
-        request.POST['pipeline'] = pipeline
-        request.POST['search'] = search
-        return request
-
-
 #--------------------------------------------------------------
 # This utility should raise an exception if the FAR range query 
 # upper limit is below the VOEvent FAR floor. This should be 
diff --git a/gracedb/views.py b/gracedb/views.py
index 1c409d9b5a34a56c8ea1a50a9fdf603b17da9374..6bc2ed41e9b8f99347573fc688ef717bc2166c8a 100644
--- a/gracedb/views.py
+++ b/gracedb/views.py
@@ -139,27 +139,6 @@ def create(request):
     d = _create(request)
     if isinstance(d, HttpResponse):
         return d
-    elif 'cli' in request.POST:
-        if 'cli_version' in request.POST:
-            # XXX Risky.  msg should be json, not str.
-            # str(x) is *often* the same as json(x), but not always.
-            # It's not, because we don't reliably have json on the client side.
-            response = HttpResponse(content_type='application/json')
-            if 'graceid' in d:
-                d['output'] = "%s" % d['graceid']
-                d['graceid'] = "%s" % d['graceid']
-            msg = str(d)
-        else: # Old client
-            response = HttpResponse(content_type='text/plain')
-            if 'error' in d:
-                msg = "ERROR: " + d['error']
-            elif 'warning' in d:
-                msg = "ERROR: " + d['warning']
-            else:
-                msg = d['graceid']
-        response.write(msg)
-        response['Content-length'] = len(msg)
-        return response
     else:
         return render_to_response('gracedb/create.html',
                     d,
@@ -187,36 +166,12 @@ def _create(request):
         form = CreateEventForm(request.POST, request.FILES)
         if form.is_valid():
             event, warnings = _createEventFromForm(request, form)
-            if 'cli' not in request.POST:
-                if not event:
-                    # problem creating event...  XXX need an error page for this.
-                    raise Exception("\n".join(warnings))
-                return HttpResponseRedirect(reverse(view, args=[event.graceid()]))
-            if event:
-                rv['graceid'] = str(event.graceid())
-                if warnings:
-                    rv['warning'] = "\n".join(warnings)
-            else:
-                rv['error'] = "\n".join(warnings)
+            if not event:
+                # problem creating event...  XXX need an error page for this.
+                raise Exception("\n".join(warnings))
+            return HttpResponseRedirect(reverse(view, args=[event.graceid()]))
         else:
-            if 'cli' not in request.POST:
-                rv['form'] = form
-            else:
-                # Error occurred in command line client.
-                # Most likely group name is wrong.
-                # XXX the form should have info about what is wrong.
-                #groupname = request.POST.get('group', None)
-                #group = Group.objects.filter(name=groupname)
-                #if not group:
-                #    validGroups = [group.name for group in Group.objects.all()]
-                #    msg = "Group must be one of: %s" % ", ".join(validGroups)
-                #else:
-                #    msg = "Malformed request"
-                #rv['error'] = msg
-                rv['error'] = ""
-                for key in form.errors:
-                    # as_text() not str() otherwise we get HTML.
-                    rv['error'] += "%s: %s\n" % (key, form.errors[key].as_text())
+            rv['form'] = form
     return rv
 
 @event_and_auth_required
diff --git a/urls.py b/urls.py
index 49189e6c63dc0af280a5e1fe47ba2731cb8f5c3f..8e778ad623bf2a2bf51848911f6b0a26f85babc3 100644
--- a/urls.py
+++ b/urls.py
@@ -26,13 +26,6 @@ urlpatterns = patterns('',
     (r'^apiweb/', include('gracedb.urls_rest', app_name="api", namespace="shib")),
     (r'^apibasic/', include('gracedb.urls_rest', app_name="api", namespace="basic")),
     (r'^options/', include('userprofile.urls')),
-    (r'^cli/create', 'gracedb.views.create'),
-    (r'^cli/ping', 'gracedb.cli_views.ping'),
-    (r'^cli/log', 'gracedb.cli_views.log'),
-    (r'^cli/upload', 'gracedb.cli_views.upload'),
-    (r'^cli/tag', 'gracedb.cli_views.cli_tag'),
-    (r'^cli/label', 'gracedb.cli_views.cli_label'),
-    (r'^cli/search', 'gracedb.cli_views.cli_search'),
     (r'^feeds/(?P<url>.*)/$', EventFeed()),
     url (r'^feeds/$', feedview, name="feeds"),