diff --git a/config.sample.json b/config.sample.json
new file mode 100644
index 0000000..3848abb
--- /dev/null
+++ b/config.sample.json
@@ -0,0 +1,28 @@
+{
+    "handler_name": "KOMODO",
+    "products": [
+    ],
+    "core_url": "http://127.0.0.1:32972/apikey/PLEASE_CHANGE_ME",
+    "pull_interval_ms": 1000,
+    "partner": {
+        "url": "http://PLEASE_CHANGE_ME:25614/",
+        "terminal_name": "PLEASE_CHANGE_ME",
+        "password": "PLEASE_CHANGE_ME"
+    },
+    "remote_products": {
+        "XL5": "XJ5",
+        "XL10": "XJ10",
+        "XL15": "XJ15",
+        "XL25": "XJ25",
+        "XL30": "XJ30",
+        "XL50": "XJ50",
+        "XL100": "XJ100",
+        "XL200": "XJ200"
+    },
+    "reverse_report_url": "http://PLEASE_CHANGE_ME:24867/",
+    "reverse_report_port": 24867,
+    "control_panel": {
+        "listen_port": 24868
+    },
+    "do_not_verbose_log_report": false
+}
diff --git a/index.js b/index.js
new file mode 100644
index 0000000..01d94b7
--- /dev/null
+++ b/index.js
@@ -0,0 +1,13 @@
+"use strict";
+process.chdir(__dirname);
+
+/*
+const config = require('komodo-sdk/config');
+const logger = require('komodo-sdk/logger');
+const matrix = require('komodo-sdk/matrix');
+*/
+
+const pullgw = require('komodo-sdk/gateway/pull');
+const partner = require('./lib/partner');
+
+pullgw.setPartner(partner);
diff --git a/lib/komodo-client.js b/lib/komodo-client.js
new file mode 100644
index 0000000..0e4d873
--- /dev/null
+++ b/lib/komodo-client.js
@@ -0,0 +1,15 @@
+"use strict";
+
+function parseResponse(body) {
+    let result;
+    try {
+        result = JSON.parse(body);
+    }
+    catch(e) {
+        result = null;
+    }
+
+    return result;
+}
+
+exports.parseResponse = parseResponse;
diff --git a/lib/komodo-rc.js b/lib/komodo-rc.js
new file mode 100644
index 0000000..68e4a22
--- /dev/null
+++ b/lib/komodo-rc.js
@@ -0,0 +1,14 @@
+"use strict";
+
+module.exports = {
+    '00': '00',
+    '13': '90',
+    '14': '14',
+    '68': '68',
+    '88': '88',
+    '89': '89',
+    '90': '90',
+    '91': '90',
+    '93': '94',
+    '96': '68'
+}
diff --git a/lib/partner.js b/lib/partner.js
new file mode 100644
index 0000000..a4ecbcf
--- /dev/null
+++ b/lib/partner.js
@@ -0,0 +1,171 @@
+"use strict";
+
+const HTTP = require('http');
+const URL = require('url');
+const request = require('request');
+const uuidv4 = require('uuid/v4');
+
+const config = require('komodo-sdk/config');
+const logger = require('komodo-sdk/logger');
+const matrix = require('komodo-sdk/matrix');
+const pull = require('komodo-sdk/gateway/pull');
+
+const komodoClient = require('./komodo-client');
+const partnerRc = require('./komodo-rc');
+
+if (!matrix.pending_tasks) {
+    matrix.pending_tasks = {};
+}
+
+function deleteFromPendingTasks(trx_id) {
+    if (matrix.pending_tasks && matrix.pending_tasks[trx_id]) {
+        delete matrix.pending_tasks[trx_id];
+    }
+}
+
+function report(data) {
+    pull.report(data);
+
+    if (data.rc !== '68' && data.rc !== '96') {
+        deleteFromPendingTasks(data.trx_id);
+    }
+}
+
+function _hit(task, is_advice) {
+
+    if (matrix.pending_tasks && !matrix.pending_tasks[task.trx_id]) {
+        matrix.pending_tasks[task.trx_id] = task;
+    }
+
+    const request_options = {
+        url: config.partner.url,
+        qs: {
+            request_id: task.trx_id,
+            terminal_name: config.partner.terminal_name || config.partner.username,
+            password: config.partner.password,
+            reverse_url: config.reverse_report_url,
+            product_name: task.remote_product,
+            destination: task.destination
+        }
+    }
+
+    if (!request_options.qs.request_id || !request_options.qs.terminal_name || !request_options.qs.password || !request_options.qs.reverse_url || !request_options.qs.product_name || !request_options.qs.destination) {
+        logger.verbose('Missing parameter on request', request_options.qs);
+        return;
+    }
+
+    logger.info('Requesting to partner', {is_advice: is_advice, trx_id: task.trx_id, destination: task.destination, product: task.product, remote_product: task.remote_product});
+    request(request_options, function(err, res, body) {
+        if (err) {
+            logger.warn('Error requesting to partner', {err: err, trx_id: task.trx_id, destination: task.destination, is_advice: is_advice});
+            report({
+                trx_id: task.trx_id,
+                rc: (!is_advice && (err.syscall === 'connect')) ? '91' : '68',
+                message: 'INTERNAL: REQUEST ERROR: ' + err.toString(),
+                misc: {
+                    task: task
+                }
+            });
+            return;
+        }
+
+        if (res.statusCode != 200) {
+            logger.warn('Partner returning non 200 HTTP status code', {trx_id: task.trx_id, destination: task.destination, is_advice: is_advice, http_status_code: res.statusCode, response_body: body});
+            report({
+                trx_id: task.trx_id,
+                rc: '68',
+                message: ('INTERNAL: Got non 200 HTTP status code: ' + res.statusCode + '\n\n' + body).trim(),
+                raw: body,
+                misc: {
+                    task: task
+                }
+            });
+            return;
+        }
+
+        logger.verbose('Got response from partner', {trx_id: task.trx_id, destination: task.destination, is_advice: is_advice, response_body: body});
+
+        const result = komodoClient.parseResponse(body);
+        if (!result) {
+            logger.warn('Partner returning invalid JSON', {trx_id: task.trx_id, destination: task.destination, is_advice: is_advice, response_body: body});
+            report({
+                trx_id: task.trx_id,
+                rc: is_advice ? '68' : '90',
+                message: 'INTERNAL: Partner return invalid JSON:\n' + body,
+                raw: body,
+                misc: {
+                    task: task
+                }
+            });
+            return;
+        }
+
+        report({
+            trx_id: task.trx_id,
+            rc: partnerRc[result.rc] || '40',
+            message: result.message,
+            sn: result.sn,
+            amount: Number(result.amount) || null,
+            raw: body,
+            misc: {
+                task: task
+            }
+        });
+    })
+}
+
+function buy(task) {
+    _hit(task, false);
+}
+
+function advice(task) {
+    _hit(task, true);
+}
+
+function reverseReportHandler(req, res) {
+    const report_id = uuidv4();
+
+    logger.verbose('Incoming reverse report', {report_id: report_id, url: req.url});
+    const qs = URL.parse(req.url, true).query;
+
+    if (!qs.request_id || !qs.rc) {
+        logger.verbose('No request_id and rc on reverse report message', {report_id: report_id, url: req.url, qs: qs});
+        return;
+    }
+
+    const task = {
+        trx_id: qs.request_id,
+        destination: qs.destination,
+        remote_product: qs.product_name
+    }
+
+    report({
+        trx_id: qs.request_id,
+        rc: partnerRc[qs.rc] || '40',
+        message: qs.message,
+        sn: qs.sn,
+        amount: qs.amount || null,
+        raw: req.url,
+        misc: {
+            task: task
+        }
+    });
+}
+
+function createReverseReportHttpServer() {
+    const http_server = HTTP.createServer(reverseReportHandler);
+    http_server.listen(config.reverse_report_port, function(err) {
+        if (err) {
+            logger.warn('Error creating reverse report HTTP server: ' + err.toString());
+            process.exit(1);
+            return;
+        }
+
+        logger.info('Reverse report HTTP server listening on port ' + config.reverse_report_port);
+    })
+}
+
+createReverseReportHttpServer();
+
+exports.buy = buy;
+exports.advice = advice;
diff --git a/package.json b/package.json
index c7faa58..6ba9d4f 100644
--- a/package.json
+++ b/package.json
@@ -20,6 +20,7 @@
   "dependencies": {
     "json-stringify-pretty-compact": "^1.1.0",
     "komodo-sdk": "git+http://gitlab.kodesumber.com/komodo/komodo-sdk.git",
-    "request": "^2.85.0"
+    "request": "^2.85.0",
+    "uuid": "^3.2.1"
   }
 }