diff --git a/bbb-common-web/.gitignore b/bbb-common-web/.gitignore
new file mode 100644
index 0000000000000000000000000000000000000000..82f02806ec59d06e2e53a6be5bcbc81c410cb817
--- /dev/null
+++ b/bbb-common-web/.gitignore
@@ -0,0 +1,56 @@
+.DS_Store
+._.DS_Store*
+.metadata
+.project
+.classpath
+.settings
+.history
+.worksheet
+gen
+**/*.swp
+**/*~.nib
+**/build/
+**/*.pbxuser
+**/*.perspective
+**/*.perspectivev3
+*.xcworkspace
+*.xcuserdatad
+**/target
+target
+*.iml
+project/*.ipr
+project/*.iml
+project/*.iws
+project/out
+project/*/target
+project/target
+project/*/bin
+project/*/build
+project/*.iml
+project/*/*.iml
+project/.idea
+project/.idea/*
+.idea
+.idea/*
+.idea/**/*
+.DS_Store
+project/.DS_Store
+project/*/.DS_Store
+tm.out
+tmlog*.log
+*.tm*.epoch
+out/
+provisioning/.vagrant
+provisioning/*/.vagrant
+provisioning/*/*.known
+/sbt/akka-patterns-store/
+/daemon/src/build/
+*.lock
+log/
+tmp/
+build/
+akka-patterns-store/
+lib_managed/
+.cache
+bin/
+
diff --git a/bbb-common-web/README.md b/bbb-common-web/README.md
new file mode 100644
index 0000000000000000000000000000000000000000..3cfa0f7331e42fc6afea656bb4bd0321478bce08
--- /dev/null
+++ b/bbb-common-web/README.md
@@ -0,0 +1 @@
+ see http://code.google.com/p/bigbluebutton/wiki/DevelopingBBB
diff --git a/bbb-common-web/build.sbt b/bbb-common-web/build.sbt
new file mode 100755
index 0000000000000000000000000000000000000000..1e694fb23f03d29da0e8aa109d9147b020346bac
--- /dev/null
+++ b/bbb-common-web/build.sbt
@@ -0,0 +1,90 @@
+name := "bbb-common-web"
+
+organization := "org.bigbluebutton"
+
+version := "0.0.1-SNAPSHOT"
+
+// We want to have our jar files in lib_managed dir.
+// This way we'll have the right path when we import
+// into eclipse.
+retrieveManaged := true
+
+testOptions in Test += Tests.Argument(TestFrameworks.Specs2, "html", "console", "junitxml")
+
+testOptions in Test += Tests.Argument(TestFrameworks.ScalaTest, "-h", "target/scalatest-reports")
+
+libraryDependencies += "commons-lang" % "commons-lang" % "2.5"
+libraryDependencies += "org.freemarker" % "freemarker" % "2.3.23"
+
+libraryDependencies += "org.pegdown" % "pegdown" % "1.4.0" % "test"
+libraryDependencies += "junit" % "junit" % "4.12" % "test"
+libraryDependencies += "com.novocode" % "junit-interface" % "0.11" % "test"
+
+// https://mvnrepository.com/artifact/org.mockito/mockito-core
+libraryDependencies += "org.mockito" % "mockito-core" % "2.7.12" % "test"
+libraryDependencies += "org.scalactic" %% "scalactic" % "3.0.1" % "test"
+libraryDependencies += "org.scalatest" %% "scalatest" % "3.0.1" % "test"
+
+seq(Revolver.settings: _*)
+
+//-----------
+// Packaging
+//
+// Reference:
+// http://xerial.org/blog/2014/03/24/sbt/
+// http://www.scala-sbt.org/sbt-pgp/usage.html
+// http://www.scala-sbt.org/0.13/docs/Using-Sonatype.html
+// http://central.sonatype.org/pages/requirements.html
+// http://central.sonatype.org/pages/releasing-the-deployment.html
+//-----------
+
+// Build pure Java lib (i.e. without scala)
+// Do not append Scala versions to the generated artifacts
+crossPaths := false
+
+// This forbids including Scala related libraries into the dependency
+autoScalaLibrary := false
+
+/***************************
+* When developing, change the version above to x.x.x-SNAPSHOT then use the file resolver to
+* publish to the local maven repo using "sbt publish"
+*/
+// Uncomment this to publish to local maven repo while commenting out the nexus repo
+publishTo := Some(Resolver.file("file",  new File(Path.userHome.absolutePath+"/.m2/repository")))
+
+
+// Comment this out when publishing to local maven repo using SNAPSHOT version.
+// To push to sonatype "sbt publishSigned"
+//publishTo := {
+//   val nexus = "https://oss.sonatype.org/"
+//   if (isSnapshot.value)
+//     Some("snapshots" at nexus + "content/repositories/snapshots")
+//   else
+//     Some("releases"  at nexus + "service/local/staging/deploy/maven2")
+//}
+
+// Enables publishing to maven repo
+publishMavenStyle := true
+
+publishArtifact in Test := false
+
+pomIncludeRepository := { _ => false }
+
+pomExtra := (
+  <scm>
+    <url>git@github.com:bigbluebutton/bigbluebutton.git</url>
+    <connection>scm:git:git@github.com:bigbluebutton/bigbluebutton.git</connection>
+  </scm>
+  <developers>
+    <developer>
+      <id>ritzalam</id>
+      <name>Richard Alam</name>
+      <url>http://www.bigbluebutton.org</url>
+    </developer>
+  </developers>)
+  
+licenses := Seq("LGPL-3.0" -> url("http://opensource.org/licenses/LGPL-3.0"))
+
+homepage := Some(url("http://www.bigbluebutton.org"))
+  
+
diff --git a/bbb-common-web/project/Build.scala b/bbb-common-web/project/Build.scala
new file mode 100755
index 0000000000000000000000000000000000000000..e69de29bb2d1d6434b8b29ae775ad8c2e48c5391
diff --git a/bbb-common-web/project/build.properties b/bbb-common-web/project/build.properties
new file mode 100755
index 0000000000000000000000000000000000000000..a6e117b61042ee81c62ba3a0fc5210d9502944df
--- /dev/null
+++ b/bbb-common-web/project/build.properties
@@ -0,0 +1 @@
+sbt.version=0.13.8
diff --git a/bbb-common-web/project/plugins.sbt b/bbb-common-web/project/plugins.sbt
new file mode 100755
index 0000000000000000000000000000000000000000..d33e342247ce264e1f5fd861cf0b88d3adcfca43
--- /dev/null
+++ b/bbb-common-web/project/plugins.sbt
@@ -0,0 +1,8 @@
+addSbtPlugin("io.spray" % "sbt-revolver" % "0.7.2")
+
+addSbtPlugin("com.typesafe.sbteclipse" % "sbteclipse-plugin" % "2.2.0")
+
+addSbtPlugin("com.jsuereth" % "sbt-pgp" % "1.0.0")
+
+
+
diff --git a/bigbluebutton-web/src/java/org/bigbluebutton/api/domain/Config.java b/bbb-common-web/src/main/java/org/bigbluebutton/api/domain/Config.java
similarity index 100%
rename from bigbluebutton-web/src/java/org/bigbluebutton/api/domain/Config.java
rename to bbb-common-web/src/main/java/org/bigbluebutton/api/domain/Config.java
diff --git a/bigbluebutton-web/src/java/org/bigbluebutton/api/domain/Extension.java b/bbb-common-web/src/main/java/org/bigbluebutton/api/domain/Extension.java
old mode 100644
new mode 100755
similarity index 100%
rename from bigbluebutton-web/src/java/org/bigbluebutton/api/domain/Extension.java
rename to bbb-common-web/src/main/java/org/bigbluebutton/api/domain/Extension.java
diff --git a/bigbluebutton-web/src/java/org/bigbluebutton/api/domain/Meeting.java b/bbb-common-web/src/main/java/org/bigbluebutton/api/domain/Meeting.java
similarity index 94%
rename from bigbluebutton-web/src/java/org/bigbluebutton/api/domain/Meeting.java
rename to bbb-common-web/src/main/java/org/bigbluebutton/api/domain/Meeting.java
index 6af99082cbbf470e4ff13a21f3ace050090c737c..733d18432ecf28d643188335dfae6ded21198eb2 100755
--- a/bigbluebutton-web/src/java/org/bigbluebutton/api/domain/Meeting.java
+++ b/bbb-common-web/src/main/java/org/bigbluebutton/api/domain/Meeting.java
@@ -19,20 +19,14 @@
 
 package org.bigbluebutton.api.domain;
 
-import java.util.Collection;
-import java.util.Collections;
-import java.util.HashMap;
-import java.util.Map;
+import java.util.*;
 import java.util.concurrent.ConcurrentHashMap;
 import java.util.concurrent.ConcurrentMap;
-
 import org.apache.commons.lang.RandomStringUtils;
-import org.slf4j.Logger;
-import org.slf4j.LoggerFactory;
+
 
 public class Meeting {
-	private static Logger log = LoggerFactory.getLogger(Meeting.class);
-	
+
 	private static final long MILLIS_IN_A_MINUTE = 60000;
 	
 	private String name;
@@ -68,6 +62,7 @@ public class Meeting {
 	private final ConcurrentMap<String, Long> registeredUsers;
 	private final ConcurrentMap<String, Config> configs;
 	private final Boolean isBreakout;
+	private final List<String> breakoutRooms = new ArrayList();
 	
 	private long lastUserLeftOn = 0;
 	
@@ -102,6 +97,14 @@ public class Meeting {
         configs = new ConcurrentHashMap<String, Config>();
     }
 
+	public void addBreakoutRoom(String meetingId) {
+		breakoutRooms.add(meetingId);
+	}
+
+	public List<String> getBreakoutRooms() {
+		return breakoutRooms;
+	}
+
 	public String storeConfig(boolean defaultConfig, String config) {
 		String token = RandomStringUtils.randomAlphanumeric(8);
 		while (configs.containsKey(token)) {
diff --git a/bigbluebutton-web/src/java/org/bigbluebutton/api/domain/Playback.java b/bbb-common-web/src/main/java/org/bigbluebutton/api/domain/Playback.java
similarity index 100%
rename from bigbluebutton-web/src/java/org/bigbluebutton/api/domain/Playback.java
rename to bbb-common-web/src/main/java/org/bigbluebutton/api/domain/Playback.java
diff --git a/bigbluebutton-web/src/java/org/bigbluebutton/api/domain/Poll.java b/bbb-common-web/src/main/java/org/bigbluebutton/api/domain/Poll.java
similarity index 100%
rename from bigbluebutton-web/src/java/org/bigbluebutton/api/domain/Poll.java
rename to bbb-common-web/src/main/java/org/bigbluebutton/api/domain/Poll.java
diff --git a/bigbluebutton-web/src/java/org/bigbluebutton/api/domain/Recording.java b/bbb-common-web/src/main/java/org/bigbluebutton/api/domain/Recording.java
similarity index 100%
rename from bigbluebutton-web/src/java/org/bigbluebutton/api/domain/Recording.java
rename to bbb-common-web/src/main/java/org/bigbluebutton/api/domain/Recording.java
diff --git a/bigbluebutton-web/src/java/org/bigbluebutton/api/domain/Recordings.java b/bbb-common-web/src/main/java/org/bigbluebutton/api/domain/Recordings.java
similarity index 100%
rename from bigbluebutton-web/src/java/org/bigbluebutton/api/domain/Recordings.java
rename to bbb-common-web/src/main/java/org/bigbluebutton/api/domain/Recordings.java
diff --git a/bigbluebutton-web/src/java/org/bigbluebutton/api/domain/User.java b/bbb-common-web/src/main/java/org/bigbluebutton/api/domain/User.java
similarity index 100%
rename from bigbluebutton-web/src/java/org/bigbluebutton/api/domain/User.java
rename to bbb-common-web/src/main/java/org/bigbluebutton/api/domain/User.java
diff --git a/bigbluebutton-web/src/java/org/bigbluebutton/api/domain/UserSession.java b/bbb-common-web/src/main/java/org/bigbluebutton/api/domain/UserSession.java
similarity index 100%
rename from bigbluebutton-web/src/java/org/bigbluebutton/api/domain/UserSession.java
rename to bbb-common-web/src/main/java/org/bigbluebutton/api/domain/UserSession.java
diff --git a/bbb-common-web/src/main/java/org/bigbluebutton/api/util/MeetingResponseDetail.java b/bbb-common-web/src/main/java/org/bigbluebutton/api/util/MeetingResponseDetail.java
new file mode 100755
index 0000000000000000000000000000000000000000..d9ebe5293f0b05c34e4ef72cdd3640ba6d72e8e2
--- /dev/null
+++ b/bbb-common-web/src/main/java/org/bigbluebutton/api/util/MeetingResponseDetail.java
@@ -0,0 +1,23 @@
+package org.bigbluebutton.api.util;
+
+
+import org.bigbluebutton.api.domain.Meeting;
+
+public class MeetingResponseDetail {
+
+  private final String createdOn;
+  private final Meeting meeting;
+
+  public MeetingResponseDetail(String createdOn, Meeting meeting) {
+    this.createdOn = createdOn;
+    this.meeting = meeting;
+  }
+
+  public String getCreatedOn() {
+    return createdOn;
+  }
+
+  public Meeting getMeeting() {
+    return meeting;
+  }
+}
diff --git a/bbb-common-web/src/main/java/org/bigbluebutton/api/util/MeetingsResponse.java b/bbb-common-web/src/main/java/org/bigbluebutton/api/util/MeetingsResponse.java
new file mode 100755
index 0000000000000000000000000000000000000000..0e67f3eadcf5b42bbc5e31500fdcf9739cd6a24f
--- /dev/null
+++ b/bbb-common-web/src/main/java/org/bigbluebutton/api/util/MeetingsResponse.java
@@ -0,0 +1,12 @@
+package org.bigbluebutton.api.util;
+
+import java.util.Collection;
+
+public class MeetingsResponse {
+
+  public final Collection<MeetingResponseDetail> meetings;
+
+  public MeetingsResponse(Collection<MeetingResponseDetail> meetings) {
+    this.meetings = meetings;
+  }
+}
diff --git a/bbb-common-web/src/main/java/org/bigbluebutton/api/util/ResponseBuilder.java b/bbb-common-web/src/main/java/org/bigbluebutton/api/util/ResponseBuilder.java
new file mode 100755
index 0000000000000000000000000000000000000000..86685d86fdbfe7ed6bbb51fdcf0f48f1f4abf36e
--- /dev/null
+++ b/bbb-common-web/src/main/java/org/bigbluebutton/api/util/ResponseBuilder.java
@@ -0,0 +1,97 @@
+package org.bigbluebutton.api.util;
+
+import org.bigbluebutton.api.domain.Meeting;
+import org.apache.commons.lang.StringUtils;
+
+import java.io.File;
+import java.io.IOException;
+import java.io.StringWriter;
+import java.util.*;
+
+import freemarker.template.*;
+
+public class ResponseBuilder {
+  Configuration cfg = new Configuration(Configuration.VERSION_2_3_23);
+
+  public ResponseBuilder(File templatesLoc) {
+
+    try {
+      cfg.setDirectoryForTemplateLoading(templatesLoc);
+    } catch (IOException e) {
+      e.printStackTrace();
+    }
+    cfg.setDefaultEncoding("UTF-8");
+    cfg.setTemplateExceptionHandler(TemplateExceptionHandler.RETHROW_HANDLER);
+    cfg.setLogTemplateExceptions(false);
+  }
+
+  public String formatPrettyDate(Long timestamp) {
+    return new Date(timestamp).toString();
+  }
+
+  public String buildGetMeetingInfoResponse(Meeting meeting, String returnCode) {
+    String createdOn = formatPrettyDate(meeting.getCreateTime());
+
+    Template ftl = null;
+    try {
+      ftl = cfg.getTemplate("get-meeting-info.ftl");
+    } catch (IOException e) {
+      e.printStackTrace();
+    }
+
+    StringWriter xmlText = new StringWriter();
+
+    Map root = new HashMap();
+    root.put("returnCode", returnCode);
+    root.put("createdOn", createdOn);
+    root.put("meeting", meeting);
+
+    try {
+      ftl.process(root, xmlText);
+    } catch (TemplateException e) {
+      e.printStackTrace();
+    } catch (IOException e) {
+      e.printStackTrace();
+    }
+
+    return xmlText.toString();
+  }
+
+  public String buildGetMeetingsResponse(Collection<Meeting> meetings, String returnCode) {
+
+    ArrayList<MeetingResponseDetail> meetingResponseDetails = new ArrayList<MeetingResponseDetail>();
+
+    for (Meeting meeting : meetings) {
+      String createdOn = formatPrettyDate(meeting.getCreateTime());
+      MeetingResponseDetail details = new MeetingResponseDetail(createdOn, meeting);
+      meetingResponseDetails.add(details);
+    }
+
+    Template ftl = null;
+    try {
+      ftl = cfg.getTemplate("get-meetings.ftl");
+    } catch (IOException e) {
+      e.printStackTrace();
+    }
+
+    StringWriter xmlText = new StringWriter();
+
+    Map root = new HashMap();
+    root.put("returnCode", returnCode);
+    root.put("meetingDetailsList", meetingResponseDetails);
+
+    for (MeetingResponseDetail details : (ArrayList<MeetingResponseDetail>)root.get("meetingDetailsList"))  {
+      System.out.println(details.getMeeting().getName());
+    }
+
+    try {
+      ftl.process(root, xmlText);
+    } catch (TemplateException e) {
+      e.printStackTrace();
+    } catch (IOException e) {
+      e.printStackTrace();
+    }
+
+    return xmlText.toString();
+  }
+}
diff --git a/bbb-common-web/src/test/resources/get-meeting-info.ftl b/bbb-common-web/src/test/resources/get-meeting-info.ftl
new file mode 100755
index 0000000000000000000000000000000000000000..c26d16d0e546bb1bdd67d259714fd1a45283cab1
--- /dev/null
+++ b/bbb-common-web/src/test/resources/get-meeting-info.ftl
@@ -0,0 +1,78 @@
+<#-- GET_RECORDINGS FreeMarker XML template -->
+<response>
+  <#-- Where code is a 'SUCCESS' or 'FAILED' String -->
+  <returncode>${returnCode}</returncode>
+  <meetingName>${meeting.getName()}</meetingName>
+  <meetingID>${meeting.getExternalId()}</meetingID>
+  <internalMeetingID>${meeting.getInternalId()}</internalMeetingID>
+  <createTime>${meeting.getCreateTime()?c}</createTime>
+  <createDate>${createdOn}</createDate>
+  <voiceBridge>${meeting.getTelVoice()}</voiceBridge>
+  <dialNumber>${meeting.getDialNumber()}</dialNumber>
+  <attendeePW>${meeting.getViewerPassword()}</attendeePW>
+  <moderatorPW>${meeting.getModeratorPassword()}</moderatorPW>
+  <running>${meeting.isRunning()?c}</running>
+  <duration>${meeting.getDuration()}</duration>
+  <hasUserJoined>${meeting.hasUserJoined()?c}</hasUserJoined>
+  <recording>${meeting.isRecord()?c}</recording>
+  <hasBeenForciblyEnded>${meeting.isForciblyEnded()?c}</hasBeenForciblyEnded>
+  <startTime>${meeting.getStartTime()?c}</startTime>
+  <endTime>${meeting.getEndTime()}</endTime>
+  <participantCount>${meeting.getNumUsers()}</participantCount>
+  <listenerCount>${meeting.getNumListenOnly()}</listenerCount>
+  <voiceParticipantCount>${meeting.getNumVoiceJoined()}</voiceParticipantCount>
+  <videoCount>${meeting.getNumVideos()}</videoCount>
+  <maxUsers>${meeting.getMaxUsers()}</maxUsers>
+  <moderatorCount>${meeting.getNumModerators()}</moderatorCount>
+  <attendees>
+  <#list meeting.getUsers() as att>
+    <attendee>
+        <userID>${att.getInternalUserId()}</userID>
+        <fullName>${att.getFullname()}</fullName>
+        <role>${att.getRole()}</role>
+        <isPresenter>${att.isPresenter()?c}</isPresenter>
+        <isListeningOnly>${att.isListeningOnly()?c}</isListeningOnly>
+        <hasJoinedVoice>${att.isVoiceJoined()?c}</hasJoinedVoice>
+        <hasVideo>${att.hasVideo()?c}</hasVideo>
+        <#if meeting.getUserCustomData(att.getExternalUserId())??>
+            <#assign ucd = meeting.getUserCustomData(att.getExternalUserId())>
+            <customdata>
+                <#list ucd?keys as prop>
+                    <${prop}><![CDATA[${ucd[prop]}]]></${prop}>
+                </#list>
+            </customdata>
+        </#if>
+    </attendee>
+  </#list>
+  </attendees>
+  <#assign m = meeting.getMetadata()>
+  <metadata>
+  <#list m?keys as prop>
+     <${prop}><![CDATA[${m[prop]}]]></${prop}>
+  </#list>
+  </metadata>
+
+  <#if messageKey?has_content>
+  <messageKey>${messageKey}</messageKey>
+  </#if>
+
+  <#if message?has_content>
+  <message>${message}</message>
+  </#if>
+
+  <#if meeting.isBreakout()>
+    <breakout>
+     <parentMeetingID>${meeting.getParentMeetingId()}</parentMeetingID>
+     <sequence>${meeting.getSequence()}</sequence>
+    </breakout>
+  </#if>
+
+  <#list meeting.getBreakoutRooms()>
+     <breakoutRooms>
+     <#items as room>
+        <breakout>${room}</breakout>
+     </#items>
+     </breakoutRooms>
+  </#list>
+
+</response>
\ No newline at end of file
diff --git a/bbb-common-web/src/test/resources/get-meetings.ftl b/bbb-common-web/src/test/resources/get-meetings.ftl
new file mode 100755
index 0000000000000000000000000000000000000000..fdee481dbdfec7dfc888a966497184a005d1e0d5
--- /dev/null
+++ b/bbb-common-web/src/test/resources/get-meetings.ftl
@@ -0,0 +1,78 @@
+<#-- GET_RECORDINGS FreeMarker XML template -->
+<response>
+  <#-- Where code is a 'SUCCESS' or 'FAILED' String -->
+  <returncode>${returnCode}</returncode>
+  <#list meetingDetailsList>
+  <meetings>
+    <#items as meetingDetail>
+      <#assign meeting = meetingDetail.getMeeting()>
+      <meeting>
+        <meetingName>${meeting.getName()}</meetingName>
+        <meetingID>${meeting.getExternalId()}</meetingID>
+        <internalMeetingID>${meeting.getInternalId()}</internalMeetingID>
+        <createTime>${meeting.getCreateTime()?c}</createTime>
+        <createDate>${meetingDetail.getCreatedOn()}</createDate>
+        <voiceBridge>${meeting.getTelVoice()}</voiceBridge>
+        <dialNumber>${meeting.getDialNumber()}</dialNumber>
+        <attendeePW>${meeting.getViewerPassword()}</attendeePW>
+        <moderatorPW>${meeting.getModeratorPassword()}</moderatorPW>
+        <running>${meeting.isRunning()?c}</running>
+        <duration>${meeting.getDuration()}</duration>
+        <hasUserJoined>${meeting.hasUserJoined()?c}</hasUserJoined>
+        <recording>${meeting.isRecord()?c}</recording>
+        <hasBeenForciblyEnded>${meeting.isForciblyEnded()?c}</hasBeenForciblyEnded>
+        <startTime>${meeting.getStartTime()?c}</startTime>
+        <endTime>${meeting.getEndTime()}</endTime>
+        <participantCount>${meeting.getNumUsers()}</participantCount>
+        <listenerCount>${meeting.getNumListenOnly()}</listenerCount>
+        <voiceParticipantCount>${meeting.getNumVoiceJoined()}</voiceParticipantCount>
+        <videoCount>${meeting.getNumVideos()}</videoCount>
+        <maxUsers>${meeting.getMaxUsers()}</maxUsers>
+        <moderatorCount>${meeting.getNumModerators()}</moderatorCount>
+        <attendees>
+        <#list meetingDetail.meeting.getUsers() as att>
+          <attendee>
+              <userID>${att.getInternalUserId()}</userID>
+              <fullName>${att.getFullname()}</fullName>
+              <role>${att.getRole()}</role>
+              <isPresenter>${att.isPresenter()?c}</isPresenter>
+              <isListeningOnly>${att.isListeningOnly()?c}</isListeningOnly>
+              <hasJoinedVoice>${att.isVoiceJoined()?c}</hasJoinedVoice>
+              <hasVideo>${att.hasVideo()?c}</hasVideo>
+              <#if meeting.getUserCustomData(att.getExternalUserId())??>
+                  <#assign ucd = meetingDetail.meeting.getUserCustomData(att.getExternalUserId())>
+                  <customdata>
+                      <#list ucd?keys as prop>
+                          <${prop}><![CDATA[${ucd[prop]}]]></${prop}>
+                      </#list>
+                  </customdata>
+              </#if>
+          </attendee>
+        </#list>
+        </attendees>
+        <#assign m = meetingDetail.meeting.getMetadata()>
+        <metadata>
+        <#list m?keys as prop>
+           <${prop}><![CDATA[${m[prop]}]]></${prop}>
+        </#list>
+        </metadata>
+
+        <#if meetingDetail.meeting.isBreakout()>
+          <breakout>
+           <parentMeetingID>${meetingDetail.meeting.getParentMeetingId()}</parentMeetingID>
+           <sequence>${meetingDetail.meeting.getSequence()}</sequence>
+          </breakout>
+        </#if>
+
+        <#list meetingDetail.meeting.getBreakoutRooms()>
+           <breakoutRooms>
+           <#items as room>
+              <breakout>${room}</breakout>
+           </#items>
+           </breakoutRooms>
+        </#list>
+      </meeting>
+    </#items>
+  </meetings>
+  </#list>
+</response>
\ No newline at end of file
diff --git a/bbb-common-web/src/test/scala/org/bigbluebutton/api/util/ResponseBuilderTest.scala b/bbb-common-web/src/test/scala/org/bigbluebutton/api/util/ResponseBuilderTest.scala
new file mode 100755
index 0000000000000000000000000000000000000000..b8a786f4ae700abae35a97435b7e7c89d72b8aeb
--- /dev/null
+++ b/bbb-common-web/src/test/scala/org/bigbluebutton/api/util/ResponseBuilderTest.scala
@@ -0,0 +1,185 @@
+package org.bigbluebutton.api.util
+
+import java.io.File
+import java.util
+
+import org.bigbluebutton.api.domain.{Meeting, User}
+import org.scalatest._
+
+class ResponseBuilderTest extends UnitSpec {
+
+  it should "find template" in {
+    val current = new java.io.File( "." ).getCanonicalPath()
+    println("Current dir:"+current)
+
+
+
+    val meetingInfo = new util.TreeMap[String, String]()
+    meetingInfo.put("foo", "foo")
+    meetingInfo.put("bar", "baz")
+
+    val meeting: Meeting = new Meeting.Builder("extMid", "intMid", System.currentTimeMillis())
+      .withName("Demo Meeting").withMaxUsers(25)
+      .withModeratorPass("mp").withViewerPass("ap")
+      .withRecording(true).withDuration(600)
+      .withLogoutUrl("/logoutUrl").withTelVoice("85115").withWebVoice("85115")
+      .withDialNumber("6135551234").withDefaultAvatarURL("/avatar")
+      .withAutoStartRecording(false).withAllowStartStopRecording(true)
+      .withWebcamsOnlyForModerator(false).withMetadata(meetingInfo)
+      .withWelcomeMessageTemplate("hello").withWelcomeMessage("hello")
+      .isBreakout(false).build
+
+    meeting.setParentMeetingId("ParentMeetingId")
+    meeting.setSequence(0);
+
+    meeting.addBreakoutRoom("breakout-room-id-1")
+    meeting.addBreakoutRoom("breakout-room-id-2")
+    meeting.addBreakoutRoom("breakout-room-id-3")
+
+    val user: User = new User("uid1", "extuid1", "Richard", "moderator", "/aygwapo")
+    meeting.userJoined(user)
+
+    val user2: User = new User("uid2", "extuid2", "Richard 2", "moderator", "/aygwapo")
+    meeting.userJoined(user2)
+
+    val user3: User = new User("uid3", "extuid3", "Richard 3", "moderator", "/aygwapo")
+    meeting.userJoined(user2)
+
+    val custData = new util.HashMap[String, String]()
+    custData.put("gwapo", "totoo")
+
+    meeting.addUserCustomData("extuid1", custData)
+
+    val templateLoc = new File("src/test/resources")
+    val builder = new ResponseBuilder(templateLoc)
+    def response = builder.buildGetMeetingInfoResponse(meeting, "success")
+    println(response)
+
+    assert(templateLoc.exists())
+  }
+
+  it should "return meetings" in {
+    val meetingInfo1 = new util.TreeMap[String, String]()
+    meetingInfo1.put("foo", "foo")
+    meetingInfo1.put("bar", "baz")
+
+    val meeting1: Meeting = new Meeting.Builder("extMid1", "intMid1", System.currentTimeMillis())
+      .withName("Demo Meeting 1").withMaxUsers(25)
+      .withModeratorPass("mp").withViewerPass("ap")
+      .withRecording(true).withDuration(600)
+      .withLogoutUrl("/logoutUrl").withTelVoice("85115").withWebVoice("85115")
+      .withDialNumber("6135551234").withDefaultAvatarURL("/avatar")
+      .withAutoStartRecording(false).withAllowStartStopRecording(true)
+      .withWebcamsOnlyForModerator(false).withMetadata(meetingInfo1)
+      .withWelcomeMessageTemplate("hello").withWelcomeMessage("hello")
+      .isBreakout(false).build
+
+    meeting1.setParentMeetingId("ParentMeetingId")
+    meeting1.setSequence(0);
+
+    meeting1.addBreakoutRoom("breakout-room-id-1")
+    meeting1.addBreakoutRoom("breakout-room-id-2")
+    meeting1.addBreakoutRoom("breakout-room-id-3")
+
+    val userm11: User = new User("uid1", "extuid1", "Richard", "moderator", "/aygwapo")
+    meeting1.userJoined(userm11)
+
+    val userm12: User = new User("uid2", "extuid2", "Richard 2", "moderator", "/aygwapo")
+    meeting1.userJoined(userm12)
+
+    val userm13: User = new User("uid3", "extuid3", "Richard 3", "moderator", "/aygwapo")
+    meeting1.userJoined(userm13)
+
+    val custDatam1 = new util.HashMap[String, String]()
+    custDatam1.put("gwapo", "totoo")
+
+    meeting1.addUserCustomData("extuid1", custDatam1)
+
+    val meetingInfo2 = new util.TreeMap[String, String]()
+    meetingInfo2.put("foo", "foo")
+    meetingInfo2.put("bar", "baz")
+
+    val meeting2: Meeting = new Meeting.Builder("extMid2", "intMid2", System.currentTimeMillis())
+      .withName("Demo Meeting 2").withMaxUsers(25)
+      .withModeratorPass("mp").withViewerPass("ap")
+      .withRecording(true).withDuration(600)
+      .withLogoutUrl("/logoutUrl").withTelVoice("85115").withWebVoice("85115")
+      .withDialNumber("6135551234").withDefaultAvatarURL("/avatar")
+      .withAutoStartRecording(false).withAllowStartStopRecording(true)
+      .withWebcamsOnlyForModerator(false).withMetadata(meetingInfo2)
+      .withWelcomeMessageTemplate("hello").withWelcomeMessage("hello")
+      .isBreakout(false).build
+
+    meeting2.setParentMeetingId("ParentMeetingId")
+    meeting2.setSequence(0);
+
+    meeting2.addBreakoutRoom("breakout-room-id-1")
+    meeting2.addBreakoutRoom("breakout-room-id-2")
+    meeting2.addBreakoutRoom("breakout-room-id-3")
+
+    val userm21: User = new User("uid1", "extuid1", "Richard", "moderator", "/aygwapo")
+    meeting2.userJoined(userm21)
+
+    val userm22: User = new User("uid2", "extuid2", "Richard 2", "moderator", "/aygwapo")
+    meeting2.userJoined(userm22)
+
+    val userm23: User = new User("uid3", "extuid3", "Richard 3", "moderator", "/aygwapo")
+    meeting2.userJoined(userm23)
+
+    val custDatam2 = new util.HashMap[String, String]()
+    custDatam2.put("gwapo", "totoo")
+
+    meeting2.addUserCustomData("extuid1", custDatam2)
+
+
+    val meetingInfo3 = new util.TreeMap[String, String]()
+    meetingInfo3.put("foo", "foo")
+    meetingInfo3.put("bar", "baz")
+
+    val meeting3: Meeting = new Meeting.Builder("extMid", "intMid", System.currentTimeMillis())
+      .withName("Demo Meeting").withMaxUsers(25)
+      .withModeratorPass("mp").withViewerPass("ap")
+      .withRecording(true).withDuration(600)
+      .withLogoutUrl("/logoutUrl").withTelVoice("85115").withWebVoice("85115")
+      .withDialNumber("6135551234").withDefaultAvatarURL("/avatar")
+      .withAutoStartRecording(false).withAllowStartStopRecording(true)
+      .withWebcamsOnlyForModerator(false).withMetadata(meetingInfo3)
+      .withWelcomeMessageTemplate("hello").withWelcomeMessage("hello")
+      .isBreakout(false).build
+
+    meeting3.setParentMeetingId("ParentMeetingId")
+    meeting3.setSequence(0);
+
+    meeting3.addBreakoutRoom("breakout-room-id-1")
+    meeting3.addBreakoutRoom("breakout-room-id-2")
+    meeting3.addBreakoutRoom("breakout-room-id-3")
+
+    val user: User = new User("uid1", "extuid1", "Richard", "moderator", "/aygwapo")
+    meeting3.userJoined(user)
+
+    val user2: User = new User("uid2", "extuid2", "Richard 2", "moderator", "/aygwapo")
+    meeting3.userJoined(user2)
+
+    val user3: User = new User("uid3", "extuid3", "Richard 3", "moderator", "/aygwapo")
+    meeting3.userJoined(user2)
+
+    val custData = new util.HashMap[String, String]()
+    custData.put("gwapo", "totoo")
+
+    meeting3.addUserCustomData("extuid1", custData)
+
+
+
+    val meetings = new util.ArrayList[Meeting]()
+    meetings.add(meeting1)
+    meetings.add(meeting2)
+    meetings.add(meeting3)
+
+    val templateLoc = new File("src/test/resources")
+    val builder = new ResponseBuilder(templateLoc)
+    def response = builder.buildGetMeetingsResponse(meetings, "success")
+    println(response)
+
+    assert(templateLoc.exists())
+  }
+}
\ No newline at end of file
diff --git a/bbb-common-web/src/test/scala/org/bigbluebutton/api/util/UnitSpec.scala b/bbb-common-web/src/test/scala/org/bigbluebutton/api/util/UnitSpec.scala
new file mode 100755
index 0000000000000000000000000000000000000000..fef2d5a231b50c2ea1597f488d4533cd972b040c
--- /dev/null
+++ b/bbb-common-web/src/test/scala/org/bigbluebutton/api/util/UnitSpec.scala
@@ -0,0 +1,8 @@
+package org.bigbluebutton.api.util
+
+import org.scalatest.FlatSpec
+import org.scalatest.BeforeAndAfterAll
+import org.scalatest.WordSpec
+import org.scalatest.Matchers
+
+abstract class UnitSpec extends FlatSpec with Matchers with BeforeAndAfterAll
diff --git a/bigbluebutton-web/build.gradle b/bigbluebutton-web/build.gradle
index ce6c71534b855548c196e9dcc4fd72fbdbb20c7b..9ada92023833c731967f4c770964117beddd5222 100755
--- a/bigbluebutton-web/build.gradle
+++ b/bigbluebutton-web/build.gradle
@@ -26,6 +26,7 @@ dependencies {
 	compile 'com.zaxxer:nuprocess:1.1.0'
 
 	compile 'org.bigbluebutton:bbb-common-message:0.0.18-SNAPSHOT'
+	compile 'org.bigbluebutton:bbb-common-web:0.0.1-SNAPSHOT'
 
   // Logging
   // Commenting out as it results in build failure (ralam - may 11, 2014)
diff --git a/bigbluebutton-web/grails-app/controllers/org/bigbluebutton/web/controllers/ApiController.groovy b/bigbluebutton-web/grails-app/controllers/org/bigbluebutton/web/controllers/ApiController.groovy
index 5cf6e37d548c17e740eec8c50211fb9d8490af14..50e6a46615deca689f0f51f6b891efb95f76a284 100755
--- a/bigbluebutton-web/grails-app/controllers/org/bigbluebutton/web/controllers/ApiController.groovy
+++ b/bigbluebutton-web/grails-app/controllers/org/bigbluebutton/web/controllers/ApiController.groovy
@@ -19,6 +19,7 @@
 package org.bigbluebutton.web.controllers
 
 import com.google.gson.Gson
+import org.bigbluebutton.api.util.ResponseBuilder
 
 import javax.servlet.ServletRequest;
 
@@ -53,9 +54,10 @@ import org.bigbluebutton.web.services.turn.StunTurnService;
 import org.bigbluebutton.web.services.turn.TurnEntry;
 import org.json.JSONArray;
 import org.json.JSONObject;
-
+import org.bigbluebutton.api.util.ResponseBuilder
 import freemarker.template.Configuration;
 import freemarker.cache.WebappTemplateLoader;
+import java.io.File;
 
 class ApiController {
   private static final Integer SESSION_TIMEOUT = 14400  // 4 hours
@@ -75,6 +77,8 @@ class ApiController {
   PresentationUrlDownloadService presDownloadService
   StunTurnService stunTurnService
 
+
+
   /* general methods */
   def index = {
     log.debug CONTROLLER_NAME + "#index"
@@ -791,7 +795,15 @@ class ApiController {
       return;
     }
 
-    respondWithConferenceDetails(meeting, null, null, null);
+    def templateLoc = getServletContext().getRealPath("/WEB-INF/freemarker")
+    ResponseBuilder responseBuilder = new ResponseBuilder(new File(templateLoc))
+
+    def xmlText = responseBuilder.buildGetMeetingInfoResponse(meeting, "success")
+    withFormat {
+      xml {
+        render(text: xmlText, contentType: "text/xml")
+      }
+    }
   }
 
   /************************************
@@ -850,41 +862,14 @@ class ApiController {
       }
     } else {
       response.addHeader("Cache-Control", "no-cache")
+
+      def templateLoc = getServletContext().getRealPath("/WEB-INF/freemarker")
+      ResponseBuilder responseBuilder = new ResponseBuilder(new File(templateLoc))
+
+      def xmlText = responseBuilder.buildGetMeetingsResponse(mtgs, "success")
       withFormat {
         xml {
-          render(contentType:"text/xml") {
-            response() {
-              returncode(RESP_CODE_SUCCESS)
-              meetings {
-                for (m in mtgs) {
-                  meeting {
-                    meetingID() { mkp.yield(m.getExternalId()) }
-                    internalMeetingID() { mkp.yield(m.getInternalId()) }
-                    if (m.isBreakout()) {
-                        parentMeetingID() { mkp.yield(m.getParentMeetingId()) }
-                        sequence(m.getSequence())
-                    }
-                    isBreakout() { mkp.yield(m.isBreakout()) }
-                    meetingName() { mkp.yield(m.getName()) }
-                    createTime(m.getCreateTime())
-                    createDate(formatPrettyDate(m.getCreateTime()))
-                    voiceBridge() { mkp.yield(m.getTelVoice()) }
-                    dialNumber() { mkp.yield(m.getDialNumber()) }
-                    attendeePW() { mkp.yield(m.getViewerPassword()) }
-                    moderatorPW() { mkp.yield(m.getModeratorPassword()) }
-                    hasBeenForciblyEnded(m.isForciblyEnded() ? "true" : "false")
-                    running(m.isRunning() ? "true" : "false")
-                    participantCount(m.getNumUsers())
-                    listenerCount(m.getNumListenOnly())
-                    voiceParticipantCount(m.getNumVoiceJoined())
-                    videoCount(m.getNumVideos())
-                    duration(m.duration)
-                    hasUserJoined(m.hasUserJoined())
-                  }
-                }
-              }
-            }
-          }
+          render(text: xmlText, contentType: "text/xml")
         }
       }
     }
@@ -1798,6 +1783,9 @@ class ApiController {
       }
       return;
     }
+
+
+
     def cfg = new Configuration()
 
     // Load the XML template
diff --git a/bigbluebutton-web/src/java/org/bigbluebutton/api/MeetingService.java b/bigbluebutton-web/src/java/org/bigbluebutton/api/MeetingService.java
index 2d4f22553d2300c101783a50b97b9c87de263053..996417b5b4ccf811b24c6b60cb09868cc8b720a4 100755
--- a/bigbluebutton-web/src/java/org/bigbluebutton/api/MeetingService.java
+++ b/bigbluebutton-web/src/java/org/bigbluebutton/api/MeetingService.java
@@ -302,6 +302,19 @@ public class MeetingService implements MessageListener {
     }
 
     private void handleCreateMeeting(Meeting m) {
+        Map<String, String> breakoutMetadata = new TreeMap<String, String>();
+
+        if (m.isBreakout()){
+            breakoutMetadata.put("meetingId", m.getExternalId());
+            breakoutMetadata.put("sequence", m.getSequence().toString());
+            breakoutMetadata.put("parentMeetingId", m.getParentMeetingId());
+            Meeting parent = meetings.get(m.getParentMeetingId());
+            parent.addBreakoutRoom(m.getExternalId());
+            if (parent.isRecord()) {
+                messagingService.addBreakoutRoom(parent.getInternalId(), m.getInternalId());
+            }
+        }
+
         if (m.isRecord()) {
             Map<String, String> metadata = new TreeMap<String, String>();
             metadata.putAll(m.getMetadata());
@@ -310,12 +323,6 @@ public class MeetingService implements MessageListener {
             metadata.put("meetingName", m.getName());
             metadata.put("isBreakout", m.isBreakout().toString());
 
-            Map<String, String> breakoutMetadata = new TreeMap<String, String>();
-            breakoutMetadata.put("meetingId", m.getExternalId());
-            if (m.isBreakout()){
-                breakoutMetadata.put("sequence", m.getSequence().toString());
-                breakoutMetadata.put("parentMeetingId", m.getParentMeetingId());
-            }
             messagingService.recordMeetingInfo(m.getInternalId(), metadata, breakoutMetadata);
         }
 
diff --git a/bigbluebutton-web/src/java/org/bigbluebutton/api/messaging/MessagingService.java b/bigbluebutton-web/src/java/org/bigbluebutton/api/messaging/MessagingService.java
index 70974ae0b4fe440e520d89b670d0596487e9f0ee..7e57ba4bbc9e81382b8b0e02c198c41edbebfd49 100755
--- a/bigbluebutton-web/src/java/org/bigbluebutton/api/messaging/MessagingService.java
+++ b/bigbluebutton-web/src/java/org/bigbluebutton/api/messaging/MessagingService.java
@@ -28,6 +28,7 @@ import java.util.Set;
 
 public interface MessagingService {	
 	void recordMeetingInfo(String meetingId, Map<String, String> info, Map<String, String> breakoutInfo);
+	void addBreakoutRoom(String parentId, String breakoutId);
 	void destroyMeeting(String meetingID);
     void createMeeting(String meetingID, String externalMeetingID,
             String parentMeetingID, String meetingName, Boolean recorded,
diff --git a/bigbluebutton-web/src/java/org/bigbluebutton/api/messaging/RedisMessagingService.java b/bigbluebutton-web/src/java/org/bigbluebutton/api/messaging/RedisMessagingService.java
index 768be2a43ff9cb31ab061435b75df458620565ac..9909890f26846ad6b001fe2d7c76e8805ec33990 100755
--- a/bigbluebutton-web/src/java/org/bigbluebutton/api/messaging/RedisMessagingService.java
+++ b/bigbluebutton-web/src/java/org/bigbluebutton/api/messaging/RedisMessagingService.java
@@ -53,6 +53,10 @@ public class RedisMessagingService implements MessagingService {
 		storeService.recordMeetingInfo(meetingId, info, breakoutInfo);
 	}
 
+	public void addBreakoutRoom(String parentId, String breakoutId) {
+		storeService.addBreakoutRoom(parentId, breakoutId);
+	}
+
 	public void destroyMeeting(String meetingID) {
 		DestroyMeetingMessage msg = new DestroyMeetingMessage(meetingID);
 		String json = MessageToJson.destroyMeetingMessageToJson(msg);
diff --git a/bigbluebutton-web/src/java/org/bigbluebutton/api/messaging/RedisStorageService.java b/bigbluebutton-web/src/java/org/bigbluebutton/api/messaging/RedisStorageService.java
index f27a34d9b928dfee9f95f22d1e0935f1de55b33d..f458ed4eaadadd13866436e999e1a7ffac44a1c9 100755
--- a/bigbluebutton-web/src/java/org/bigbluebutton/api/messaging/RedisStorageService.java
+++ b/bigbluebutton-web/src/java/org/bigbluebutton/api/messaging/RedisStorageService.java
@@ -54,6 +54,19 @@ public class RedisStorageService {
             jedis.close();
         }
     }
+
+	public void addBreakoutRoom(String parentId, String breakoutId) {
+		Jedis jedis = redisPool.getResource();
+		try {
+
+			log.debug("Saving breakout room for meeting {}", parentId);
+			jedis.sadd("meeting:breakout:rooms:" + parentId, breakoutId);
+		} catch (Exception e) {
+			log.warn("Cannot record the info meeting:" + parentId, e);
+		} finally {
+			jedis.close();
+		}
+	}
 	
 	public void removeMeeting(String meetingId){
 		Jedis jedis = redisPool.getResource();
diff --git a/bigbluebutton-web/web-app/WEB-INF/freemarker/get-meeting-info.ftl b/bigbluebutton-web/web-app/WEB-INF/freemarker/get-meeting-info.ftl
new file mode 100755
index 0000000000000000000000000000000000000000..c26d16d0e546bb1bdd67d259714fd1a45283cab1
--- /dev/null
+++ b/bigbluebutton-web/web-app/WEB-INF/freemarker/get-meeting-info.ftl
@@ -0,0 +1,78 @@
+<#-- GET_RECORDINGS FreeMarker XML template -->
+<response>
+  <#-- Where code is a 'SUCCESS' or 'FAILED' String -->
+  <returncode>${returnCode}</returncode>
+  <meetingName>${meeting.getName()}</meetingName>
+  <meetingID>${meeting.getExternalId()}</meetingID>
+  <internalMeetingID>${meeting.getInternalId()}</internalMeetingID>
+  <createTime>${meeting.getCreateTime()?c}</createTime>
+  <createDate>${createdOn}</createDate>
+  <voiceBridge>${meeting.getTelVoice()}</voiceBridge>
+  <dialNumber>${meeting.getDialNumber()}</dialNumber>
+  <attendeePW>${meeting.getViewerPassword()}</attendeePW>
+  <moderatorPW>${meeting.getModeratorPassword()}</moderatorPW>
+  <running>${meeting.isRunning()?c}</running>
+  <duration>${meeting.getDuration()}</duration>
+  <hasUserJoined>${meeting.hasUserJoined()?c}</hasUserJoined>
+  <recording>${meeting.isRecord()?c}</recording>
+  <hasBeenForciblyEnded>${meeting.isForciblyEnded()?c}</hasBeenForciblyEnded>
+  <startTime>${meeting.getStartTime()?c}</startTime>
+  <endTime>${meeting.getEndTime()}</endTime>
+  <participantCount>${meeting.getNumUsers()}</participantCount>
+  <listenerCount>${meeting.getNumListenOnly()}</listenerCount>
+  <voiceParticipantCount>${meeting.getNumVoiceJoined()}</voiceParticipantCount>
+  <videoCount>${meeting.getNumVideos()}</videoCount>
+  <maxUsers>${meeting.getMaxUsers()}</maxUsers>
+  <moderatorCount>${meeting.getNumModerators()}</moderatorCount>
+  <attendees>
+  <#list meeting.getUsers() as att>
+    <attendee>
+        <userID>${att.getInternalUserId()}</userID>
+        <fullName>${att.getFullname()}</fullName>
+        <role>${att.getRole()}</role>
+        <isPresenter>${att.isPresenter()?c}</isPresenter>
+        <isListeningOnly>${att.isListeningOnly()?c}</isListeningOnly>
+        <hasJoinedVoice>${att.isVoiceJoined()?c}</hasJoinedVoice>
+        <hasVideo>${att.hasVideo()?c}</hasVideo>
+        <#if meeting.getUserCustomData(att.getExternalUserId())??>
+            <#assign ucd = meeting.getUserCustomData(att.getExternalUserId())>
+            <customdata>
+                <#list ucd?keys as prop>
+                    <${prop}><![CDATA[${ucd[prop]}]]></${prop}>
+                </#list>
+            </customdata>
+        </#if>
+    </attendee>
+  </#list>
+  </attendees>
+  <#assign m = meeting.getMetadata()>
+  <metadata>
+  <#list m?keys as prop>
+     <${prop}><![CDATA[${m[prop]}]]></${prop}>
+  </#list>
+  </metadata>
+
+  <#if messageKey?has_content>
+  <messageKey>${messageKey}</messageKey>
+  </#if>
+
+  <#if message?has_content>
+  <message>${message}</message>
+  </#if>
+
+  <#if meeting.isBreakout()>
+    <breakout>
+     <parentMeetingID>${meeting.getParentMeetingId()}</parentMeetingID>
+     <sequence>${meeting.getSequence()}</sequence>
+    </breakout>
+  </#if>
+
+  <#list meeting.getBreakoutRooms()>
+     <breakoutRooms>
+     <#items as room>
+        <breakout>${room}</breakout>
+     </#items>
+     </breakoutRooms>
+  </#list>
+
+</response>
\ No newline at end of file
diff --git a/bigbluebutton-web/web-app/WEB-INF/freemarker/get-meetings.ftl b/bigbluebutton-web/web-app/WEB-INF/freemarker/get-meetings.ftl
new file mode 100755
index 0000000000000000000000000000000000000000..fdee481dbdfec7dfc888a966497184a005d1e0d5
--- /dev/null
+++ b/bigbluebutton-web/web-app/WEB-INF/freemarker/get-meetings.ftl
@@ -0,0 +1,78 @@
+<#-- GET_RECORDINGS FreeMarker XML template -->
+<response>
+  <#-- Where code is a 'SUCCESS' or 'FAILED' String -->
+  <returncode>${returnCode}</returncode>
+  <#list meetingDetailsList>
+  <meetings>
+    <#items as meetingDetail>
+      <#assign meeting = meetingDetail.getMeeting()>
+      <meeting>
+        <meetingName>${meeting.getName()}</meetingName>
+        <meetingID>${meeting.getExternalId()}</meetingID>
+        <internalMeetingID>${meeting.getInternalId()}</internalMeetingID>
+        <createTime>${meeting.getCreateTime()?c}</createTime>
+        <createDate>${meetingDetail.getCreatedOn()}</createDate>
+        <voiceBridge>${meeting.getTelVoice()}</voiceBridge>
+        <dialNumber>${meeting.getDialNumber()}</dialNumber>
+        <attendeePW>${meeting.getViewerPassword()}</attendeePW>
+        <moderatorPW>${meeting.getModeratorPassword()}</moderatorPW>
+        <running>${meeting.isRunning()?c}</running>
+        <duration>${meeting.getDuration()}</duration>
+        <hasUserJoined>${meeting.hasUserJoined()?c}</hasUserJoined>
+        <recording>${meeting.isRecord()?c}</recording>
+        <hasBeenForciblyEnded>${meeting.isForciblyEnded()?c}</hasBeenForciblyEnded>
+        <startTime>${meeting.getStartTime()?c}</startTime>
+        <endTime>${meeting.getEndTime()}</endTime>
+        <participantCount>${meeting.getNumUsers()}</participantCount>
+        <listenerCount>${meeting.getNumListenOnly()}</listenerCount>
+        <voiceParticipantCount>${meeting.getNumVoiceJoined()}</voiceParticipantCount>
+        <videoCount>${meeting.getNumVideos()}</videoCount>
+        <maxUsers>${meeting.getMaxUsers()}</maxUsers>
+        <moderatorCount>${meeting.getNumModerators()}</moderatorCount>
+        <attendees>
+        <#list meetingDetail.meeting.getUsers() as att>
+          <attendee>
+              <userID>${att.getInternalUserId()}</userID>
+              <fullName>${att.getFullname()}</fullName>
+              <role>${att.getRole()}</role>
+              <isPresenter>${att.isPresenter()?c}</isPresenter>
+              <isListeningOnly>${att.isListeningOnly()?c}</isListeningOnly>
+              <hasJoinedVoice>${att.isVoiceJoined()?c}</hasJoinedVoice>
+              <hasVideo>${att.hasVideo()?c}</hasVideo>
+              <#if meeting.getUserCustomData(att.getExternalUserId())??>
+                  <#assign ucd = meetingDetail.meeting.getUserCustomData(att.getExternalUserId())>
+                  <customdata>
+                      <#list ucd?keys as prop>
+                          <${prop}><![CDATA[${ucd[prop]}]]></${prop}>
+                      </#list>
+                  </customdata>
+              </#if>
+          </attendee>
+        </#list>
+        </attendees>
+        <#assign m = meetingDetail.meeting.getMetadata()>
+        <metadata>
+        <#list m?keys as prop>
+           <${prop}><![CDATA[${m[prop]}]]></${prop}>
+        </#list>
+        </metadata>
+
+        <#if meetingDetail.meeting.isBreakout()>
+          <breakout>
+           <parentMeetingID>${meetingDetail.meeting.getParentMeetingId()}</parentMeetingID>
+           <sequence>${meetingDetail.meeting.getSequence()}</sequence>
+          </breakout>
+        </#if>
+
+        <#list meetingDetail.meeting.getBreakoutRooms()>
+           <breakoutRooms>
+           <#items as room>
+              <breakout>${room}</breakout>
+           </#items>
+           </breakoutRooms>
+        </#list>
+      </meeting>
+    </#items>
+  </meetings>
+  </#list>
+</response>
\ No newline at end of file