diff --git a/src/libs/app.js b/src/libs/app.js
index 8be3a95b9a3e78f9ce54093196facfed9f0223c1..1184e1e026ac6d17e79a90e975d273f1a700f918 100644
--- a/src/libs/app.js
+++ b/src/libs/app.js
@@ -44,6 +44,18 @@ app.use((req, res, next) => {
         };
     };
     req.resetSql();
+
+    req.sql.oldClone = req.sql.clone;
+    req.sql.clone = () => {
+        let cloned = req.sql.oldClone();
+        cloned.oldFrom = cloned.from;
+        cloned.from = (name, alias = null) => {
+            cloned.oldFrom(name, alias || null);
+            cloned.tableFrom = name;
+            return cloned;
+        };
+        return cloned;
+    };
     next();
 });
 app.use(passport.initialize());
diff --git a/src/libs/middlewares/reqQueryFields.js b/src/libs/middlewares/reqQueryFields.js
index c821852b423fb9d9d41d60a579e3b064b88ab427..993aae5bd282199b33d5ff8228cd90dcaf8c275c 100644
--- a/src/libs/middlewares/reqQueryFields.js
+++ b/src/libs/middlewares/reqQueryFields.js
@@ -192,126 +192,142 @@ class ReqQueryFields {
         };
     }
 
-    build() {
+    buildQuery(req, sql) {
         // "Constrói" o SQL
-        return (req, res, next) => {
-            let hasJoined = {};
-            let thisTable = req.sql.tableFrom;
-            // Foreach no campos
-            Object.keys(this.fields).forEach((key) => {
-                // Campo
-                let field = this.fields[key];
-                log.debug(field);
-                // `param` aqui é o atributo no objeto `req` (dims, filter, search, ...)
-                let param = req[field.name];
-                // Fazemos um foreach nos parametros dentro do atributo
-                Object.keys(param).forEach((k) => {
-                    let values = _.merge(this.fieldValues, field.values);
-                    if(typeof values[k] !== 'undefined') {
-                        // Clonamos para não alterar o original
-                        let value = _.clone(values[k]);
-                        if(value.parseOnly) return;
-                        // Checa se não fizemos o join para este valor e se é necessário fazer
-                        if(!hasJoined[value.table] && typeof value.join !== 'undefined') {
-                            let foreignTable = '';
-                            if(value.join.foreignTable) foreignTable = value.join.foreignTable+'.';
-                            if(value.join.foreignTable === '@') foreignTable = thisTable+'.';
-                            // Fazemos o join
-                            let onClause = '';
-                            if(Array.isArray(value.join.primary)) {
-                                // Se é um array, montamos a cláusula ON com mais de uma coluna
-                                value.join.primary.forEach((column, index, arr) => {
-                                    onClause += foreignTable+value.join.foreign[index]+'='+value.table+'.'+column;
-                                    if(index < arr.length-1) {
-                                        onClause+=' AND ';
-                                    }
-                                });
-                            } else {
-                                onClause = foreignTable+value.join.foreign+'='+value.table+'.'+value.join.primary;
-                            }
-                            req.sql.join(value.table, null, onClause);
-                            // Marcamos o join como feito para não ter problemas
-                            hasJoined[value.table] = true;
+        let hasJoined = {};
+        let thisTable = sql.tableFrom;
+        // Foreach no campos
+        Object.keys(this.fields).forEach((key) => {
+            // Campo
+            let field = this.fields[key];
+            log.debug(field);
+            // `param` aqui é o atributo no objeto `req` (dims, filter, search, ...)
+            let param = req[field.name];
+            // Fazemos um foreach nos parametros dentro do atributo
+            Object.keys(param).forEach((k) => {
+                let values = _.merge(this.fieldValues, field.values);
+                if(typeof values[k] !== 'undefined') {
+                    // Clonamos para não alterar o original
+                    let value = _.clone(values[k]);
+                    if(value.parseOnly) return;
+                    // Checa se não fizemos o join para este valor e se é necessário fazer
+                    if(!hasJoined[value.table] && typeof value.join !== 'undefined') {
+                        let foreignTable = '';
+                        if(value.join.foreignTable) foreignTable = value.join.foreignTable+'.';
+                        if(value.join.foreignTable === '@') foreignTable = thisTable+'.';
+                        // Fazemos o join
+                        let onClause = '';
+                        if(Array.isArray(value.join.primary)) {
+                            // Se é um array, montamos a cláusula ON com mais de uma coluna
+                            value.join.primary.forEach((column, index, arr) => {
+                                onClause += foreignTable+value.join.foreign[index]+'='+value.table+'.'+column;
+                                if(index < arr.length-1) {
+                                    onClause+=' AND ';
+                                }
+                            });
+                        } else {
+                            onClause = foreignTable+value.join.foreign+'='+value.table+'.'+value.join.primary;
                         }
-                        // Se o valor é um campo a ser incluído no SELECT
-                        if(typeof field.field !== 'undefined' && field.field) {
-                            log.debug('SELECT');
-                            let table = value.table;
-                            if(table === '@') table = thisTable;
-                            if (Array.isArray(value.resultField)) {
-                                value.tableField.forEach((f, i) => {
-                                    req.sql.field(table+'.'+f, value.resultField[i] || f)
-                                        .group(table+'.'+f)
-                                        .order(table+'.'+f);
-                                })
-                            }else{
-                                req.sql.field(table+'.'+value.tableField, value.resultField || value.tableField)
-                                    .order(table+'.'+value.tableField)
-                                    .group(table+'.'+value.tableField);
-                            }
+                        sql.join(value.table, null, onClause);
+                        // Marcamos o join como feito para não ter problemas
+                        hasJoined[value.table] = true;
+                    }
+                    // Se o valor é um campo a ser incluído no SELECT
+                    if(typeof field.field !== 'undefined' && field.field) {
+                        log.debug('SELECT');
+                        let table = value.table;
+                        if(table === '@') table = thisTable;
+                        if (Array.isArray(value.resultField)) {
+                            value.tableField.forEach((f, i) => {
+                                sql.field(table+'.'+f, value.resultField[i] || f)
+                                    .group(table+'.'+f)
+                                    .order(table+'.'+f);
+                            })
+                        }else{
+                            sql.field(table+'.'+value.tableField, value.resultField || value.tableField)
+                                .order(table+'.'+value.tableField)
+                                .group(table+'.'+value.tableField);
                         }
-                        // Se o valor é um campo para ser usado no WHERE
-                        if(typeof field.where !== 'undefined' && field.where) {
-                            log.debug('WHERE');
-                            // Valor do where
-
-                            let whereValue = param[k];
-                            log.debug('whereValue');
-                            log.debug(whereValue);
-                            log.debug(`Where value é array? ${Array.isArray(whereValue)}`);
+                    }
+                    // Se o valor é um campo para ser usado no WHERE
+                    if(typeof field.where !== 'undefined' && field.where) {
+                        log.debug('WHERE');
+                        // Valor do where
 
-                            let tbl = value.where.table || value.table;
-                            if (tbl === '@') tbl = thisTable;
-                            // multiple where
-                            if (Array.isArray(value.where.field)) {
-                                let lower = (value.where.type === 'string') ? ' LOWER(?) ' : ' ? ';
-                                let whereField = '';
-                                let whereValues = [];
-                                value.where.field.forEach((f, i, arr) => {
-                                    whereField += (value.where.type === 'string') ? 'LOWER(' + tbl + '.' + value.where.field[i] + ')' : tbl + '.' + value.where.field[i];
-                                    whereField += ' ' + value.where.relation + ' ?';
-                                    if (i < arr.length - 1) {
-                                        whereField += ' ' + value.where.condition + ' ';
-                                    }
+                        let whereValue = param[k];
+                        log.debug('whereValue');
+                        log.debug(whereValue);
+                        log.debug(`Where value é array? ${Array.isArray(whereValue)}`);
 
-                                    if (Array.isArray(whereValue)) {
-                                        let whereString = '(';
-                                        for(let i = 0; i < whereValue.length; ++i) {
-                                            whereString += whereField;
-                                            whereValues.push(parseWhereValue(value.where.type, whereValue[i]));
-                                            if(i < whereValue.length-1) {
-                                                whereString += ' OR ';
-                                            }
-                                        }
-                                        whereString += ')';
-                                    } else {
-                                        whereValues.push(parseWhereValue(value.where.type, whereValue));
-                                    }
-                                });
+                        let tbl = value.where.table || value.table;
+                        if (tbl === '@') tbl = thisTable;
+                        // multiple where
+                        if (Array.isArray(value.where.field)) {
+                            let lower = (value.where.type === 'string') ? ' LOWER(?) ' : ' ? ';
+                            let whereField = '';
+                            let whereValues = [];
+                            value.where.field.forEach((f, i, arr) => {
+                                whereField += (value.where.type === 'string') ? 'LOWER(' + tbl + '.' + value.where.field[i] + ')' : tbl + '.' + value.where.field[i];
+                                whereField += ' ' + value.where.relation + ' ?';
+                                if (i < arr.length - 1) {
+                                    whereField += ' ' + value.where.condition + ' ';
+                                }
 
-                                req.sql.where(whereField, ...whereValues);
-                            } else {
-                                let whereField = (value.where.type === 'string') ? 'LOWER(' + tbl + '.' + value.where.field + ')' : tbl + '.' + value.where.field;
-                                let lower = (value.where.type === 'string') ? ' LOWER(?) ' : ' ? ';
-                                if(Array.isArray(whereValue)) {
+                                if (Array.isArray(whereValue)) {
                                     let whereString = '(';
-                                    let arrayWhereValues = [];
                                     for(let i = 0; i < whereValue.length; ++i) {
-                                        whereString += whereField + ' ' + value.where.relation + lower;
-                                        arrayWhereValues.push(parseWhereValue(value.where.type, whereValue[i]));
+                                        whereString += whereField;
+                                        whereValues.push(parseWhereValue(value.where.type, whereValue[i]));
                                         if(i < whereValue.length-1) {
                                             whereString += ' OR ';
                                         }
                                     }
                                     whereString += ')';
-                                    req.sql.where(whereString, ...arrayWhereValues);
                                 } else {
-                                    req.sql.where(whereField + ' ' + value.where.relation + lower, parseWhereValue(value.where.type, whereValue));
+                                    whereValues.push(parseWhereValue(value.where.type, whereValue));
                                 }
+                            });
+
+                            sql.where(whereField, ...whereValues);
+                        } else {
+                            let whereField = (value.where.type === 'string') ? 'LOWER(' + tbl + '.' + value.where.field + ')' : tbl + '.' + value.where.field;
+                            let lower = (value.where.type === 'string') ? ' LOWER(?) ' : ' ? ';
+                            if(Array.isArray(whereValue)) {
+                                let whereString = '(';
+                                let arrayWhereValues = [];
+                                for(let i = 0; i < whereValue.length; ++i) {
+                                    whereString += whereField + ' ' + value.where.relation + lower;
+                                    arrayWhereValues.push(parseWhereValue(value.where.type, whereValue[i]));
+                                    if(i < whereValue.length-1) {
+                                        whereString += ' OR ';
+                                    }
+                                }
+                                whereString += ')';
+                                sql.where(whereString, ...arrayWhereValues);
+                            } else {
+                                sql.where(whereField + ' ' + value.where.relation + lower, parseWhereValue(value.where.type, whereValue));
                             }
                         }
                     }
-                });
+                }
+            });
+        });
+        return sql;
+    }
+
+    build() {
+        return (req, res, next) => {
+            req.sql = this.buildQuery(req, req.sql);
+            next();
+        };
+    }
+
+    multibuild() {
+        return (req, res, next) => {
+            req.querySet.forEach((query) => {
+                console.log("query");
+                console.log(query.tableFrom);
+                query = this.buildQuery(req, query);
             });
             next();
         };
diff --git a/src/libs/routes/api.js b/src/libs/routes/api.js
index 590ff356b310c4e1258db1c85d9fe41ec49c2cee..e205726df4fdc6fe117337cebd5eaf4b66f0091f 100644
--- a/src/libs/routes/api.js
+++ b/src/libs/routes/api.js
@@ -50,6 +50,8 @@ const infrastructure = require(`${libs}/routes/infrastructure`);
 
 const distributionFactor = require(`${libs}/routes/distributionFactor`);
 
+const siope = require(`${libs}/routes/siope`);
+
 api.get('/', (req, res) => {
     res.json({ msg: 'SimCAQ API is running' });
 });
@@ -77,5 +79,6 @@ api.use('/reset', resetToken);
 api.use('/education_years', educationYears);
 api.use('/infrastructure', infrastructure);
 api.use('/distribution_factor', distributionFactor);
+api.use('/siope', siope);
 
 module.exports = api;
diff --git a/src/libs/routes/siope.js b/src/libs/routes/siope.js
new file mode 100644
index 0000000000000000000000000000000000000000..622da904d074ff80b1d328bcada59ad23eb317ec
--- /dev/null
+++ b/src/libs/routes/siope.js
@@ -0,0 +1,166 @@
+const express = require('express');
+
+const siopeApp = express.Router();
+
+const libs = `${process.cwd()}/libs`;
+
+const log = require(`${libs}/log`)(module);
+
+const squel = require('squel');
+
+const query = require(`${libs}/middlewares/query`);
+
+const multiQuery = require(`${libs}/middlewares/multiQuery`);
+
+const response = require(`${libs}/middlewares/response`);
+
+const ReqQueryFields = require(`${libs}/middlewares/reqQueryFields`);
+
+const id2str = require(`${libs}/middlewares/id2str`);
+
+const config = require(`${libs}/config`);
+
+const cache = require('apicache').options({ debug: config.debug, statusCodes: {include: [200]} }).middleware;
+
+let rqf = new ReqQueryFields();
+
+siopeApp.use(cache('15 day'));
+
+siopeApp.get('/years', (req, res, next) => {
+    req.sql.from('siope_mun')
+    .field('DISTINCT siope_mun.ano_censo', 'year');
+    next();
+}, query, (req, res, next) => {
+    req.oldResult = req.result;
+
+    req.sql = squel.select();
+
+    req.sql.from('siope_uf')
+    .field('DISTINCT siope_uf.ano_censo', 'year');
+    next();
+}, query, (req, res, next) => {
+    let result = Object.assign(req.oldResult, req.result);
+    req.result = result;
+    next();
+}, response('years'));
+
+rqf.addField({
+    name: 'filter',
+    field: true,
+    where: true
+}).addField({
+    name: 'dims',
+    field: true,
+    where: false
+}).addValue({
+    name: 'city',
+    table: 'municipio',
+    tableField: 'nome',
+    resultField: 'city_name',
+    where: {
+        relation: '=',
+        type: 'integer',
+        field: 'municipio_id',
+        table: 'siope_mun'
+    },
+    join: {
+        primary: 'id',
+        foreign: 'municipio_id',
+        foreignTable: 'siope_mun'
+    }
+}).addValue({
+    name: 'state',
+    table: 'estado',
+    tableField: ['id','nome','sigla'],
+    resultField: ['state_id','state_name','state_abbreviation'],
+    where: {
+        relation: '=',
+        type: 'integer',
+        field: 'estado_id',
+        table: '@'
+    },
+    join: {
+        primary: 'id',
+        foreign: 'estado_id',
+        foreignTable: '@'
+    }
+}).addValue({
+    name: 'min_year',
+    table: '@',
+    tableField: 'ano_censo',
+    resultField: 'year',
+    where: {
+        relation: '>=',
+        type: 'integer',
+        table: '@',
+        field: 'ano_censo'
+    }
+}).addValue({
+    name: 'max_year',
+    table: '@',
+    tableField: 'ano_censo',
+    resultField: 'year',
+    where: {
+        relation: '<=',
+        type: 'integer',
+        table: '@',
+        field: 'ano_censo'
+    }
+});
+
+
+
+siopeApp.get('/', rqf.parse(), (req, res, next) => {
+    req.querySet = [];
+    req.queryIndex = {};
+
+    let siopeUf = req.sql.clone();
+    siopeUf.from('siope_uf')
+    .field('siope_uf.ano_censo', 'year')
+    .field('siope_uf.estado_id', 'state_id')
+    .field('siope_uf.fundeb', 'fundeb')
+    .field('siope_uf.total_impostos', 'impostos')
+    .field('siope_uf.total_mde', 'MDE')
+    .group('siope_uf.ano_censo')
+    .group('siope_uf.estado_id')
+    .group('siope_uf.fundeb')
+    .group('siope_uf.total_impostos')
+    .group('siope_uf.total_mde')
+    .order('siope_uf.ano_censo');
+    req.queryIndex.siopeUf = req.querySet.push(siopeUf) - 1;
+
+    let siopeMun = req.sql.clone();
+    siopeMun.from('siope_mun')
+    .field('siope_mun.ano_censo', 'year')
+    .field('siope_mun.estado_id', 'state_id')
+    .field('siope_mun.municipio_id', 'city_id')
+    .field('siope_mun.fundeb', 'fundeb')
+    .field('siope_mun.total_impostos', 'impostos')
+    .field('siope_mun.total_mde', 'MDE')
+    .group('siope_mun.ano_censo')
+    .group('siope_mun.estado_id')
+    .group('siope_mun.municipio_id')
+    .group('siope_mun.fundeb')
+    .group('siope_mun.total_impostos')
+    .group('siope_mun.total_mde')
+    .order('siope_mun.ano_censo');
+    req.queryIndex.siopeMun = req.querySet.push(siopeMun) - 1;
+
+    next();
+}, rqf.multibuild(), multiQuery, (req, res, next) => {
+
+    let result = []
+
+    req.result[req.queryIndex.siopeUf].forEach((item) => {
+        result.push(item)
+    });
+    req.result[req.queryIndex.siopeMun].forEach((item) => {
+        result.push(item)
+    });
+
+    req.result = result;
+    next();
+
+}, response('siope'));
+
+module.exports = siopeApp;