diff --git a/labs/bbb-callback/app.coffee b/labs/bbb-callback/app.coffee
deleted file mode 100644
index 1b374fea4691e36f0acd55baefcb26edb9676621..0000000000000000000000000000000000000000
--- a/labs/bbb-callback/app.coffee
+++ /dev/null
@@ -1,50 +0,0 @@
-request = require("request")
-redis = require("redis")
-
-# Class that defines the application.
-module.exports = class Application
-
-  constructor: ->
-    @subscriber = redis.createClient()
-    @client = redis.createClient()
-
-  start: ->
-    @_subscribe()
-
-  _subscribe: ->
-
-    @subscriber.on "psubscribe", (channel, count) ->
-      console.log "subscribed to " + channel
-
-    @subscriber.on "pmessage", (pattern, channel, message) =>
-      console.log "got message [", channel, "]", message
-
-      try
-        properties = JSON.parse(message)
-      catch e
-        properties = null
-        # TODO: handle the error properly
-        console.log e
-
-      if properties?
-        @client.lrange "meeting:" + properties.meetingID + ":subscriptions", 0, -1, (error, reply) =>
-          reply.forEach (sid, index) =>
-            console.log "subscriber id = " + sid
-            @client.hgetall "meeting:" + properties.meetingID + ":subscription:" + sid, (err, rep) ->
-              if rep.active is "true"
-                properties.meetingID = rep.externalMeetingID
-                post_options =
-                  uri: rep.callbackURL
-                  method: "POST"
-                  json: properties
-
-                request post_options, (error, response, body) ->
-                  if not error and response.statusCode is 200
-                    console.log "Error calling url: [" + post_options.uri + "]"
-                    console.log "Error: [" + JSON.stringify(error) + "]"
-                    console.log "Response: [" + JSON.stringify(response) + "]"
-                  else
-                    console.log "Passed calling url: [" + post_options.uri + "]"
-                    console.log "Response: [" + JSON.stringify(response) + "]"
-
-    @subscriber.psubscribe "bigbluebutton:*"
diff --git a/labs/bbb-callback/app.js b/labs/bbb-callback/app.js
index dd1971995389ad1ae3efac8db5354ed77cfec0e3..e21c144726a3ec97f2bec194128054190ea7c030 100755
--- a/labs/bbb-callback/app.js
+++ b/labs/bbb-callback/app.js
@@ -2,6 +2,6 @@
 
 require("coffee-script/register");
 
-Application = require('./app.coffee');
+Application = require('./application.coffee');
 application = new Application();
 application.start();
diff --git a/labs/bbb-callback/application.coffee b/labs/bbb-callback/application.coffee
new file mode 100644
index 0000000000000000000000000000000000000000..59cd8293555f3159203c6039645d54c78fc71027
--- /dev/null
+++ b/labs/bbb-callback/application.coffee
@@ -0,0 +1,43 @@
+request = require("request")
+redis = require("redis")
+
+Callbacks = require("./callbacks")
+
+# Class that defines the application.
+module.exports = class Application
+
+  constructor: ->
+    @subscriber = redis.createClient()
+    @callbacks = new Callbacks()
+
+  start: ->
+    @_subscribe()
+
+  _subscribe: ->
+
+    @subscriber.on "psubscribe", (channel, count) ->
+      console.log "Application: subscribed to " + channel
+
+    @subscriber.on "pmessage", (pattern, channel, message) =>
+      console.log "---------------------------------------------------------"
+      console.log "Application: got message [", channel, "]", message
+      try
+        message = JSON.parse(message)
+
+        # TODO: filter the messages we want to process
+        @_processMessage(message) if message?
+
+      catch e
+        # TODO: handle the error properly
+        console.log e
+
+    @subscriber.psubscribe "bigbluebutton:*"
+
+  _processMessage: (message) ->
+    @callbacks.getCallbackUrls (error, callbackUrls) =>
+      console.log "Application: got callback urls:", callbackUrls
+      callbackUrls.forEach (callbackUrl) ->
+        if callbackUrl.isActive()
+          # TODO: the external meeting ID is not on redis yet
+          # message.meetingID = rep.externalMeetingID
+          callbackUrl.enqueue(message)
diff --git a/labs/bbb-callback/callback_url.coffee b/labs/bbb-callback/callback_url.coffee
new file mode 100644
index 0000000000000000000000000000000000000000..378c34d3055f5d823dd1f2409c9a8b461ae78053
--- /dev/null
+++ b/labs/bbb-callback/callback_url.coffee
@@ -0,0 +1,32 @@
+request = require("request")
+
+# The representation of a callback URL and its properties, taken from redis.
+module.exports = class CallbackURL
+
+  # constructor: ->
+
+  mapFromRedis: (redisData) ->
+    @url = redisData?.callbackURL
+    @externalMeetingID = redisData?.externalMeetingID
+    @active = redisData?.active
+
+  isActive: ->
+    @active
+
+  # TODO: use a queue and enqueue the message instead of sending it
+  # use another class to manage the queue and make the callback calls
+  enqueue: (message) ->
+    console.log "CallbackURL: enqueueing message", message
+    requestOptions =
+      uri: @url
+      method: "POST"
+      json: message
+
+    request requestOptions, (error, response, body) ->
+      if not error and response.statusCode is 200
+        console.log "Error calling url: [" + requestOptions.uri + "]"
+        console.log "Error: [" + JSON.stringify(error) + "]"
+        console.log "Response: [" + JSON.stringify(response) + "]"
+      else
+        console.log "Passed calling url: [" + requestOptions.uri + "]"
+        console.log "Response: [" + JSON.stringify(response) + "]"
diff --git a/labs/bbb-callback/callbacks.coffee b/labs/bbb-callback/callbacks.coffee
new file mode 100644
index 0000000000000000000000000000000000000000..fab3df003c4a4d1d00b9dee3c786979ba60f1c86
--- /dev/null
+++ b/labs/bbb-callback/callbacks.coffee
@@ -0,0 +1,72 @@
+_ = require("lodash")
+async = require("async")
+redis = require("redis")
+
+CallbackURL = require("./callback_url")
+
+# Helper class to fetch the list of callbacks from redis.
+module.exports = class Callbacks
+
+  constructor: ->
+    @subscriber = redis.createClient()
+    @client = redis.createClient()
+    @meetings = []
+    @_subscribe()
+
+  getCallbackUrls: (callback) ->
+    tasks = []
+    @meetings.forEach (meetingId) =>
+      console.log "Callbacks: checking callbacks for the meeting", meetingId
+      tasks.push (done) =>
+
+        @client.lrange "meeting:#{meetingId}:subscriptions", 0, -1, (error, subscriptions) =>
+          # TODO: treat error
+          @_getCallbackUrlsForSubscriptions meetingId, subscriptions, done
+
+    async.series tasks, (errors, result) ->
+      result = _.flatten result
+      console.log "Callbacks#getCallbackUrls: returning", result
+      callback?(errors, result)
+
+  _getCallbackUrlsForSubscriptions: (meetingId, subscriptions, callback) ->
+    tasks = []
+    subscriptions.forEach (sid, index) =>
+
+      tasks.push (done) =>
+        @client.hgetall "meeting:#{meetingId}:subscription:#{sid}", (error, redisData) ->
+          # TODO: treat error
+          console.log "Callbacks: creating callbackUrl for", redisData
+          cb = new CallbackURL()
+          cb.mapFromRedis redisData
+          done null, cb
+
+    async.series tasks, (errors, result) ->
+      console.log "Callbacks#_getCallbackUrlsForSubscriptions: returning", result
+      callback?(errors, result)
+
+
+  # TODO: for now we have to check for all meetings created and store their internal
+  # meeting ID so we can read from redis the callbacks registered for these meetings
+  _subscribe: ->
+    @subscriber.on "subscribe", (channel, count) ->
+      console.log "Callbacks: subscribed to " + channel
+    @subscriber.on "message", (channel, message) =>
+      console.log "Callbacks: got message [", channel, "]", message
+      try
+        message = JSON.parse(message)
+
+        if message.header?.name is "meeting_created_message"
+          @_addMeeting(message.payload?.meeting_id)
+
+        # TODO: remove meetings from the list
+
+      catch e
+        # TODO: handle the error properly
+        console.log e
+
+    @subscriber.subscribe "bigbluebutton:from-bbb-apps:meeting"
+
+  _addMeeting: (meetingId) ->
+    unless _.contains(@meetings, meetingId)
+      console.log "Callbacks: adding meeting to the list", meetingId
+      @meetings.push meetingId
diff --git a/labs/bbb-callback/package.json b/labs/bbb-callback/package.json
index e3b2ea47878edfff417c7b148ae59386ff415263..2077aa1052d20be3533fdfae936f6112fc99c928 100755
--- a/labs/bbb-callback/package.json
+++ b/labs/bbb-callback/package.json
@@ -10,7 +10,9 @@
   "dependencies" : {
     "redis": "0.12.1",
     "request": "2.47.0",
-    "coffee-script": "1.8.0"
+    "coffee-script": "1.8.0",
+    "lodash": "2.4.1",
+    "async": "0.9.0"
   },
   "engines": {
     "node": "0.10.26"