diff --git a/symposion_project/apps/sponsorship/__init__.py b/symposion_project/apps/sponsorship/__init__.py
new file mode 100644
index 00000000..e69de29b
diff --git a/symposion_project/apps/sponsorship/admin.py b/symposion_project/apps/sponsorship/admin.py
new file mode 100644
index 00000000..6814c4da
--- /dev/null
+++ b/symposion_project/apps/sponsorship/admin.py
@@ -0,0 +1,7 @@
+from django.contrib import admin
+
+from sponsorship.models import SponsorLevel, Sponsor
+
+
+admin.site.register(SponsorLevel)
+admin.site.register(Sponsor, list_display=("name", "level", "added", "active"), list_filter = ("level", ))
diff --git a/symposion_project/apps/sponsorship/models.py b/symposion_project/apps/sponsorship/models.py
new file mode 100644
index 00000000..07d0cb30
--- /dev/null
+++ b/symposion_project/apps/sponsorship/models.py
@@ -0,0 +1,45 @@
+import datetime
+
+from django.db import models
+from django.utils.translation import ugettext_lazy as _
+
+from conference.models import Conference
+
+
+class SponsorLevel(models.Model):
+    
+    conference = models.ForeignKey(Conference, verbose_name=_("conference"))
+    name = models.CharField(_("name"), max_length=100)
+    order = models.IntegerField(_("order"), default=0)
+    description = models.TextField(_("description"), blank=True)
+    
+    class Meta:
+        ordering = ["conference", "order"]
+        verbose_name = _("sponsor level")
+        verbose_name_plural = _("sponsor levels")
+    
+    def __unicode__(self):
+        return u"%s %s" % (self.conference, self.name)
+    
+    def sponsors(self):
+        return self.sponsor_set.filter(active=True).order_by("added")
+
+
+class Sponsor(models.Model):
+    
+    name = models.CharField(_("name"), max_length=100)
+    external_url = models.URLField(_("external URL"))
+    annotation = models.TextField(_("annotation"), blank=True)
+    contact_name = models.CharField(_("contact_name"), max_length=100)
+    contact_email = models.EmailField(_(u"Contact e\u2011mail"))
+    logo = models.ImageField(_("logo"), upload_to="sponsor_logos/")
+    level = models.ForeignKey(SponsorLevel, verbose_name=_("level"))
+    added = models.DateTimeField(_("added"), default=datetime.datetime.now)
+    active = models.BooleanField(_("active"), default=False)
+    
+    def __unicode__(self):
+        return self.name
+    
+    class Meta:
+        verbose_name = _("sponsor")
+        verbose_name_plural = _("sponsors")
diff --git a/symposion_project/apps/sponsorship/templatetags/__init__.py b/symposion_project/apps/sponsorship/templatetags/__init__.py
new file mode 100644
index 00000000..e69de29b
diff --git a/symposion_project/apps/sponsorship/templatetags/sponsorship_tags.py b/symposion_project/apps/sponsorship/templatetags/sponsorship_tags.py
new file mode 100644
index 00000000..00fb8139
--- /dev/null
+++ b/symposion_project/apps/sponsorship/templatetags/sponsorship_tags.py
@@ -0,0 +1,75 @@
+from django import template
+
+from conference.models import current_conference
+from sponsorship.models import Sponsor, SponsorLevel
+
+
+register = template.Library()
+
+
+class SponsorsNode(template.Node):
+    
+    @classmethod
+    def handle_token(cls, parser, token):
+        bits = token.split_contents()
+        if len(bits) == 3 and bits[1] == "as":
+            return cls(bits[2])
+        elif len(bits) == 4 and bits[2] == "as":
+            return cls(bits[3], bits[1])
+        else:
+            raise template.TemplateSyntaxError("%r takes 'as var' or 'level as var'" % bits[0])
+    
+    def __init__(self, context_var, level=None):
+        if level:
+            self.level = template.Variable(level)
+        else:
+            self.level = None
+        self.context_var = context_var
+    
+    def render(self, context):
+        conference = current_conference()
+        if self.level:
+            level = self.level.resolve(context)
+            queryset = Sponsor.objects.filter(level__conference = conference, level__name__iexact = level, active = True).order_by("added")
+        else:
+            queryset = Sponsor.objects.filter(level__conference = conference, active = True).order_by("level__order", "added")
+        context[self.context_var] = queryset
+        return u""
+
+
+class SponsorLevelNode(template.Node):
+    
+    @classmethod
+    def handle_token(cls, parser, token):
+        bits = token.split_contents()
+        if len(bits) == 3 and bits[1] == "as":
+            return cls(bits[2])
+        else:
+            raise template.TemplateSyntaxError("%r takes 'as var'" % bits[0])
+    
+    def __init__(self, context_var):
+        self.context_var = context_var
+    
+    def render(self, context):
+        conference = current_conference()
+        context[self.context_var] = SponsorLevel.objects.filter(conference=conference)
+        return u""
+
+
+@register.tag
+def sponsors(parser, token):
+    """
+    {% sponsors as all_sponsors %}
+    or
+    {% sponsors "gold" as gold_sponsors %}
+    """
+    return SponsorsNode.handle_token(parser, token)
+
+
+@register.tag
+def sponsor_levels(parser, token):
+    """
+    {% sponsor_levels as levels %}
+    """
+    return SponsorLevelNode.handle_token(parser, token)
+    
\ No newline at end of file
diff --git a/symposion_project/docs/index.rst b/symposion_project/docs/index.rst
index d121dded..45faa102 100644
--- a/symposion_project/docs/index.rst
+++ b/symposion_project/docs/index.rst
@@ -16,6 +16,7 @@ Apps:
    :maxdepth: 2
    
    conference
+   sponsorship
 
 
 Indices and tables
diff --git a/symposion_project/docs/sponsorship.rst b/symposion_project/docs/sponsorship.rst
new file mode 100644
index 00000000..5907a1a3
--- /dev/null
+++ b/symposion_project/docs/sponsorship.rst
@@ -0,0 +1,82 @@
+Sponsorship App
+===============
+
+Sponsorship is managed via the ``sponsorship`` app.
+
+Sponsorship levels and sponsors are added via the Django admin.
+
+
+Models
+------
+
+Each sponsor level has a ``name`` (e.g. "Gold", "Silver") and an ``order``
+field which is an integer that is used to sort levels (lowest first). Each
+level also has a ``description`` which is not currently exposed anywhere
+but can be used for private annotation.
+
+Each sponsor has a ``name``, ``external_url`` (i.e. link to the sponsor's
+website), ``contact_name`` and ``contact_email``, ``logo``, and ``level``.
+
+A sponsor may also have a private ``annotation`` that can be used by
+organizers to take notes about the sponsor.
+
+A sponsor will not appear on the site until the ``active`` flag is set true.
+
+
+Template Snippets
+-----------------
+
+The easiest way to include sponsor logos, grouped by level, is to either::
+
+    {% include "sponsorship/_vertical_by_level.html" %}
+
+or::
+    
+    {% include "sponsorship/_horizontal_by_level.html" %}
+
+You can get a wall of sponsors (without level designation) with::
+
+    {% include "sponsorship/_wall.html" %}
+
+
+You can always tweak these templates or use them as the basis for your own.
+This is often all you'll need to do to display sponsors on your site.
+
+If you want to display a specific sponsor logo you can use::
+
+    {% include "sponsorship/_sponsor_link.html" with sponsor=sponsor %}
+
+or::
+    
+    {% include "sponsorship/_sponsor_link.html" with sponsor=sponsor dimensions="100x100" %}
+
+if you want different dimensions than the default 150 x 150.
+
+
+Template Tags
+-------------
+
+If you want to retrieve the sponsors and traverse them yourself, you can use
+the provided template tags::
+
+    {% load sponsorship_tags %}
+    
+    {% sponsors as all_sponsors %}
+
+or::
+
+    {% load sponsorship_tags %}
+    
+    {% sponsors "Gold" as gold_sponsors %}
+
+if you want to just get a specific level.
+
+
+You can get the levels with::
+
+    {% load sponsorship_tags %}
+    
+    {% sponsor_levels as levels %}
+
+and you can always iterate over those levels, calling ``level.sponsors`` to
+get the sponsors at that level.
diff --git a/symposion_project/requirements/project.txt b/symposion_project/requirements/project.txt
index 6d8b1485..0d0fa5f3 100644
--- a/symposion_project/requirements/project.txt
+++ b/symposion_project/requirements/project.txt
@@ -4,4 +4,7 @@
 --requirement=base.txt
 
 # Put project-specific requirements here.
-# See http://pip-installer.org/requirement-format.html for more information.
\ No newline at end of file
+# See http://pip-installer.org/requirement-format.html for more information.
+
+PIL==1.1.7
+easy-thumbnails==1.0-alpha-21
diff --git a/symposion_project/settings.py b/symposion_project/settings.py
index 669d8009..ca21bcf4 100644
--- a/symposion_project/settings.py
+++ b/symposion_project/settings.py
@@ -157,6 +157,7 @@ INSTALLED_APPS = [
     "timezones",
     "emailconfirmation",
     "metron",
+    "easy_thumbnails",
     
     # Pinax
     "pinax.apps.account",
@@ -164,6 +165,7 @@ INSTALLED_APPS = [
     
     # project
     "about",
+    "sponsorship",
     "conference",
 ]
 
diff --git a/symposion_project/templates/sponsorship/_horizontal_by_level.html b/symposion_project/templates/sponsorship/_horizontal_by_level.html
new file mode 100644
index 00000000..98025053
--- /dev/null
+++ b/symposion_project/templates/sponsorship/_horizontal_by_level.html
@@ -0,0 +1,11 @@
+{% load sponsorship_tags %}
+{% sponsor_levels as levels %}
+<div class="sponsor-list">
+{% for level in levels %}
+    <h3>{{ level.name }}</h3>
+    
+    {% for sponsor in level.sponsors %}
+        {% include "sponsorship/_sponsor_link.html" with sponsor=sponsor %}
+    {% endfor %}
+{% endfor %}
+</div>
diff --git a/symposion_project/templates/sponsorship/_sponsor_link.html b/symposion_project/templates/sponsorship/_sponsor_link.html
new file mode 100644
index 00000000..39d9aade
--- /dev/null
+++ b/symposion_project/templates/sponsorship/_sponsor_link.html
@@ -0,0 +1,10 @@
+{% load thumbnail %}
+{% spaceless %}
+<a href="{{ sponsor.external_url }}">
+    {% if dimensions %}
+        <img src="{% thumbnail sponsor.logo dimensions %}" alt="{{ sponsor.name }}" />
+    {% else %}
+        <img src="{% thumbnail sponsor.logo '150x150' %}" alt="{{ sponsor.name }}" />
+    {% endif %}
+</a>
+{% endspaceless %}
diff --git a/symposion_project/templates/sponsorship/_vertical_by_level.html b/symposion_project/templates/sponsorship/_vertical_by_level.html
new file mode 100644
index 00000000..b2ed5ec4
--- /dev/null
+++ b/symposion_project/templates/sponsorship/_vertical_by_level.html
@@ -0,0 +1,13 @@
+{% load sponsorship_tags %}
+{% sponsor_levels as levels %}
+<div class="sponsor-list">
+{% for level in levels %}
+    <h3>{{ level.name }}</h3>
+    
+    {% for sponsor in level.sponsors %}
+        <div>
+            {% include "sponsorship/_sponsor_link.html" with sponsor=sponsor %}
+        </div>
+    {% endfor %}
+{% endfor %}
+</div>
diff --git a/symposion_project/templates/sponsorship/_wall.html b/symposion_project/templates/sponsorship/_wall.html
new file mode 100644
index 00000000..7f1b9896
--- /dev/null
+++ b/symposion_project/templates/sponsorship/_wall.html
@@ -0,0 +1,7 @@
+{% load sponsorship_tags %}
+{% sponsors as sponsors %}
+<div class="sponsor-wall">
+{% for sponsor in sponsors %}
+    {% include "sponsorship/_sponsor_link.html" with sponsor=sponsor %}
+{% endfor %}
+</div>