Skip to content


When you install Lime CRM, a central service is the Lime CRM Webserver (sometimes referred to as the appserver). The Lime CRM Webserver handles among other things:

  • Security, such as certificates and authentication via logon via a web form or via an API key.
  • Serving the Lime CRM REST API
  • Serving the static assets and the API used by the web client

The Lime CRM REST API can be used for a multitude of integrations, but sometimes you'll want an API that is better suited for your particular integration. Uses cases for this might include:

  • Having one endpoint that updates or creates more that one object and where you want to have those operations in one transaction
  • Creating an API that better matches the business events for an organization than an API where you set individual properties on objects.
  • Better control over how data is serialized back to the client.

With custom endpoints you can extend the API exposed by the Lime CRM Webserver with URLs that are better suited for your particular problem domain.

The Application

Lime CRM is at its core a multi-tenant server, meaning that several applications can be served by the same application server. That means that an endpoint cannot make assumptions or hard code information about, for instance, what database to connect to.

To relieve you from having to keep track of information about the current database, its current structure etc., you can use the application member of LimeResource <lime-webserver:lime_webserver.webserver.LimeResource>

class Todos(LimeResource):

    def get(self):
        todos = self.application.limetypes.todo.get_all()

Adding a custom endpoint

To add a custom endpoint to your package, change directory to your package directory and run the command for generating the boiler plate for a custom endpoint:

cd cool-stuff
lime-project generate endpoint

This generates the following in cool-stuff/cool_stuff/endpoints/

import lime_webserver.webserver as webserver
import logging
import webargs.fields as fields
from webargs.flaskparser import use_args
from ..endpoints import api

logger = logging.getLogger(__name__)

class LimeobjectCounter(webserver.LimeResource):
    """Summarize your resource's functionality here"""

    # This describes the schema for the payload when posting a new deal
    # See for more info.
    args = {
        "limetype": fields.String(required=True),

    def get(self, args):
        """Get the current number of objects of the given type in the system.

        limetype = self.application.limetypes.get_limetype(args['limetype'])
        limeobjects = limetype.get_all()

        return {
            'message': (
                'Hello, {}! There are {} objects of type {} available'

api.add_resource(LimeobjectCounter, '/count/')

The generated module defines a resource, LimeobjectCounter, that is accessible at the URL https://hostname/myapplication/cool-stuff/count/. The URL we want to listen to is defined by the last line api.add_resource(LimeobjectCounter, '/count/').

This particular resource only listens to HTTP GET requests as it implements a method called get. If we want to add support for other HTTP methods, we need to add their corresponding methods, such as post, put etc.

The get method requires the caller to supply a limetype argument in the form of query strings. The args dict at the beginning specifies that we require the argument limetype, and that it should be a string. Together with the @use_args decorator on the get method, we ensure that the caller get a proper error message back if arguments are missing or malformed.

Once we're satisfied that our get method has a proper limetype argument we proceed to get all objects of that type from the database via the resource's application property.


We won't actually retrieve all objects from the database. The returned list is a lazy collection that starts retrieving objects as we iterate over it.

Finally, we return a dictionary with a greeting to the logged on coworker containing information about how many objects of the specified type is available in the database. The return value will automatically be formatted as a JSON response to the caller.