OCT 2023 UPDATE: For information on accessing Tendenci data via API please see our GitHub discussion at

Currently, our API Documentation is still being developed.

If you're a developer looking to integrate with Tendenci - we'd love to talk with you! 

Email us at and check out our open source Github Page to view and download Tendenci's source code. 

Looking to Integrate Your App's APIs with Tendenci?

Come take a look at Tendenci's integration with Campaign Monitor's email newsletter software using Campaign Monitor's APIs to use as an example. You can find the full code for our Campaign Monitor integration module at: shows you how the models for the integration are defined to sync data between a Tendenci website and a Campaign Monitor account. Each of the models defined is responsible for a different set of functions to manage data sharing between Tendenci and Campaign Monitor. 

Here's explanations for some of the models with code snippets.

ListMap model syncs data for specific campaign monitor subscriber lists using # list id from campaign monitor:


class ListMap(models.Model):
    group = models.ForeignKey(Group)
    # list id for campaign monitor
    list_id = models.CharField(max_length=100)
    create_dt = models.DateTimeField(auto_now_add=True)
    update_dt = models.DateTimeField(auto_now=True)
    last_sync_dt = models.DateTimeField(null=True)
    def __unicode__(self):
        return ''

GroupQueue model so that new Tendenci User Groups create new Subscriber lists on Campaign Monitor and can stay sync'd:


class GroupQueue(models.Model):
    group = models.ForeignKey(Group)

SubscriberQueue model for managing individual users on Tendenci with their corresponding subscriptions in Campaign Monitor:


class SubscriberQueue(models.Model):
    group = models.ForeignKey(Group)
    user = models.ForeignKey(User, null=True, on_delete=models.SET_NULL)
    subscriber = models.ForeignKey(FormEntry, null=True)

Template model represents a newsletter template in Campaign Monitor. This includes information specific to a newsletter template like the location of the html and .zip files for each template and the preview and screenshot views:


class Template(models.Model):
This represents a Template in Campaign Monitor.
    class Meta:

= (("view_template","Can view template"),)

    template_id = models.CharField(max_length=100, unique=True, null=True)
    name = models.CharField(max_length=100)
    create_dt = models.DateTimeField(auto_now_add=True)
    update_dt = models.DateTimeField(auto_now=True)
    #get only
    cm_preview_url = models.URLField(null=True)
    cm_screenshot_url = models.URLField(null=True)
    #post only
    html_file = models.FileField(upload_to=file_directory, null=True)
    zip_file = models.FileField(upload_to=file_directory, null=True)
    def content_type(self):
        return 'template'
    def get_absolute_url(self):
        return ("campaign_monitor.template_view", [self.template_id])
    def get_html_url(self):
        return ("campaign_monitor.template_html", [self.template_id])
    def get_html_original_url(self):
        return ("campaign_monitor.template_html_original", [self.template_id])
    def get_render_url(self):
        return ("campaign_monitor.template_render", [self.template_id])
    def get_text_url(self):
        return ("campaign_monitor.template_text", [self.template_id])
    def get_zip_url(self):
        if self.zip_file:
            return self.zip_file.url
        return ''
    def get_media_url(self):
        if self.zip_file:
            return "%scampaign_monitor/%s" % (settings.MEDIA_URL, self.template_id)
        return ''
    def __unicode__(self):
    def save(self, *args, **kwargs):
        super(Template, self).save(*args, **kwargs)
        if self.html_file:
            set_s3_file_permission(self.html_file.file, public=True)
        if self.zip_file:
            set_s3_file_permission(self.zip_file.file, public=True)


Campaign model represents a campaign in Campaign Monitor. Campaigns are the individual newsletters that are created using templates, and you'll see fields defined that represent the unique elements a campaign has for identifying it, such as the date the campaign was sent and the subject of the email campaign. This information is used to sync details of a campaign monitor newsletter so you can view, manage, and create email campaigns from within your Tendenci Super User admin console: 


class Campaign(models.Model):




This represents a Campaign. It is considered as a "Draft" if it is


not yet sent.
    class Meta:
        permissions = (("view_campaign","Can view campaign"),)
        ('C', 'Scheduled'),
        ('D', 'Draft'),
    campaign_id = models.CharField(max_length=100, unique=True)
    create_dt = models.DateTimeField(auto_now_add=True)
    update_dt = models.DateTimeField(auto_now=True)
    status = models.CharField(max_length=1, choices=STATUS_CHOICES, default='D')
    #fields for sync
    name = models.CharField(max_length=100)
    subject = models.CharField(max_length=100)
    lists = models.ManyToManyField(ListMap)
    #fields for sent campaigns
    sent_date = models.DateTimeField(null=True, blank=True)
    web_version_url = models.URLField(null=True, blank=True)
    total_recipients = models.IntegerField(default=0)
    #fields for scheduled campaigns
    scheduled_date = models.DateTimeField(null=True, blank=True)
    scheduled_time_zone = models.CharField(max_length=100, null=True, blank=True)
    preview_url = models.URLField(null=True, blank=True)
    #fields for post only
    from_name = models.CharField(max_length=100, null=True, blank=True)
    from_email = models.EmailField(null=True, blank=True)
    reply_to = models.EmailField(null=True, blank=True)
    template = models.ForeignKey(Template, null=True, blank=True)
    def get_absolute_url(self):
        return ("campaign_monitor.campaign_view", [self.campaign_id])
    def __unicode__(self):



Contact us to upgrade to Tendenci

The open source solution chosen by associations around the world.

Want to talk? (281) 497-6567

Sign up for Tendenci - The Open Source AMS

No per user pricing. Unlimited admins.

Demo Now

Have Questions?

Contact us!

Site Search

I agree

Our site saves small pieces of text information (cookies) on your device in order to deliver better experience and for statistical purposes. You can disable the usage of cookies by changing the settings of your browser. By browsing our website without changing the browser settings you grant us permission to store that information on your device. See our Privacy Policy