Custom Backends

You can create a custom backend if the supplied backends don’t suffice. Since backends handle both inbound and outbound communication, the following section is divided into Incoming Messages and Outgoing Messages, respectively.

The built-in Vumi and Kannel backends use the methods described below, so you can review the source code to see actual implementation examples.

For a more general backend overview, please see RapidSMS Backends.

Incoming Messages

HTTP Backend

RapidSMS provides a base suite of HTTP views and forms to help simplify backend creation in rapidsms.backends.http. These are useful for standardizing incoming message handling. They can be extended for use in your own backends. The HTTP Backend powers both the Vumi and Kannel backends.

You can, of course, simply write your own Django views to handle incoming messages if the supplied classes do not provide enough flexibility.

Incoming message life cycle

Typically, when RapidSMS receives a message over HTTP, it’s processed in the following way:

  1. Data from a text message is received by Django over an HTTP request.
  2. The HTTP request is routed through a Backend URL.
  3. This backend view takes the HTTP request and passes it into a backend form.
  4. This backend form cleans the message data and checks its validity.
  5. If the message is valid, message data is sent to the router for processing via rapidsms.router.receive().
  6. An HTTP response is sent to the HTTP request sender with an HTTP status code to indicate that the message was received and passed to the router for processing successfully or that there was an error.

The HTTP response from a backend view does not necessarily indicate that the resulting messages were sent by the router, only that the incoming message was added to the queue for processing.


class rapidsms.backends.http.views.GenericHttpBackendView(**kwargs)

Simple view that allows customization of accepted paramters.

http_method_names = ['get', 'post']

Accepts GET and POST by default.

params = {}

Dictionary that defines mappings to identity and text.

The simplest type of custom backend is an HTTP backend that needs to accept parameters other than identity and text. To create such a custom backend, one can subclass the GenericHttpBackendView as follows:

from rapidsms.backends.http.views import GenericHttpBackendView

class MyBackendView(GenericHttpBackendView):
    params = {
        'identity_name': 'phone',
        'text_name': 'message',

The params dictionary contains key value pairs that map internal names to the keys used in requests to the backend. In the above example, an HTTP request would provide phone and message parameters.

An URL pattern for this backend might look like:

from project_name.app_name.views import MyBackendView

urlpatterns = patterns('',

A request to this backend might look like the following:

>>> import urllib
>>> import urllib2
>>> data = urllib.urlencode({'phone': '1112223333', 'message': 'ping'})
>>> request = urllib2.urlopen('http://localhost:8000/backends/mybackend/', data)
>>> request.code

Custom Validation

Another custom backend might necessitate handling more parameters in the request, or validating the incoming data differently. A convenient way to do this validation with Django is with forms:

from .forms import ExtraParamsHttpBackendForm
from rapidsms.backends.http.views import GenericHttpBackendView

class ExtraParamsHttpBackendView(GenericHttpBackendView):
    form_class = ExtraParamsHttpBackendForm

This example application would have the following forms definition:

from django import forms
from rapidsms.backends.http.forms import BaseHttpForm

class ExtraParamsHttpBackendForm(BaseHttpForm):
    extra = forms.TextField()

    def get_incoming_data(self):
        fields = self.cleaned_data.copy()
        return {'identity': self.cleaned_data['identity_name'],
                'text': self.cleaned_data['text_name'],
                'extra': self.cleaned_data['extra']}

This uses RapidSMS’s BaseHttpForm:

class rapidsms.backends.http.forms.BaseHttpForm(*args, **kwargs)

Helper form for validating incoming messages.

Parameters:backend_name – (Optional) name of the backend

Return a dictionary containing the connection and text for this message, based on the field names passed to __init__().

Must be implemented by subclasses.


Simple wrapper to ease connection lookup on child forms.

Data coming into this backend would require an extra parameter, which would be passed onto the message queue.

Alternatively, here’s an example of a backend form with custom validation:

from django import forms
from rapidsms.backends.http.forms import BaseHttpForm

MY_NUMBER = '1231231234'

class OnlyTextMeHttpBackendForm(BaseHttpForm):

    def clean_text_name():
        text_name = self.cleaned_data.get('text_name')
        if text_name != MY_NUMBER:
            raise forms.ValidationError(
                'SMS received from number other than {0}'.format(MY_NUMBER)
        return text_name

Outgoing Messages


Similar to HTTP Backend for incoming messages, BackendBase provides the foundation for outbound functionality. All backends will typically extend this base class. This class will be passed the configuration dictionary defined in Backend Settings.

class rapidsms.backends.base.BackendBase(router, name, **kwargs)

Base class for outbound backend functionality.


Configuration parameters from INSTALLED_BACKENDS will be passed here after the router is instantiated. You can override this method to parse your configuration.

classmethod find(module_name)

Helper function to import backend classes.

Parameters:module_name – Dotted Python path to backend class name
Returns:Imported class object

The model attribute is the RapidSMS model instance with this backend name. A new backend will automatically be created if one doesn’t exist upon accessing this attribute.

send(id_, text, identities, context=None)

Backend sending logic. The router will call this method for each outbound message. This method must be overridden by sub-classes. Backends typically initiate HTTP requests from within this method.

If multiple identities are provided, the message is intended for all recipients.

Any exceptions raised here will be captured and logged by the router. If messages to some identities failed while others succeeded, you can provide that information back to the router by adding a list of the identities which failed in a failed_identities parameter on the exception. If you do provide that parameter, then the router should assume that all identities not listed in failed_identities were successfully sent.

def send(self, id_, text, identities, context):
    failures = []
    for identity in identities:
        result = send_my_message(identity, text, context)
        if result == 'failed':
    if failures:
        msg = '%d messages failed.' % len(failures)
        raise MessageSendingError(msg, failed_identities=failures)
  • id_ – Message ID
  • text – Message text
  • identities – List of identities
  • context – Optional dictionary with extra context provided by router to backend