diff --git a/partner-datacell.js b/partner-datacell.js
new file mode 100644
index 0000000..419b1ce
--- /dev/null
+++ b/partner-datacell.js
@@ -0,0 +1,108 @@
+var url = require('url');
+var math = require('mathjs');
+var xml = require('xml');
+var strftime = require('strftime');
+var xor = require('base64-xor');
+var request = require('request');
+
+var config;
+var callbackReport;
+
+var max_retry = 2;
+var sleep_before_retry = 2000;
+
+function calculateSignature(userid, password, msisdn, timestamp) {
+    var a = msisdn.substr(msisdn.length - 4) + timestamp;
+    var b = userid.substr(0, 4) + password;
+    
+    return xor.encode(a,b);
+}
+
+function createPayload(task) {
+    var timestamp = strftime('%H%M%S');
+    
+    var payload = {
+        datacell: {
+            perintah: 'charge',
+            oprcode: task['remoteProduct'],
+            userid: config.h2h_out.userid,
+            time: timestamp,
+            msisdn: task['destination'],
+            ref_trxid: task['requestId'],
+            sgn: calculateSignature(config.h2h_out.userid, config.h2h_out.password, task['destination'], timestamp);
+        }
+    };
+    
+    console.log(payload);
+    return xml(payload);
+}
+
+function topupRequest(task, retry) {
+    if (config.globals.requests_count == undefined) {
+        config.globals.requests_count = 1;
+    } else {
+        config.globals.requests_count++;
+    }
+    
+    if (config.globals.active_requests_count == undefined) {
+        config.globals.active_requests_count = 1;
+    } else {
+        config.globals.active_requests_count++;
+    }
+    
+    if (config.globals.max_active_requests_count == undefined) {
+        config.globals.max_active_requests_count = config.globals.active_requests_count;
+    } else {
+        config.globals.max_active_requests_count = math.max(config.globals.max_active_requests_count, config.globals.active_requests_count);
+    }
+    
+    
+    if (retry === undefined) {
+        retry = max_retry;
+    }
+    
+    var payload_xml = createPayload(task);
+    
+    request.post(config.h2h_out.partner, {message: payload_xml}, function(error, response, body) {
+        if (error) {
+            var error_mesasge = 'Error requesting to partner: ' + error;
+            console.log(error_message);
+            callbackReport(task['requestId'], '40', error_message);
+            return;
+        }
+        
+        if (response.statusCode != 200) {
+            var error_mesasge = 'HTTP status code =  ' + response.statusCode;
+            console.log(error_message);
+            callbackReport(task['requestId'], '40', error_message);
+            return;
+        }
+        
+        console.log('Direct response from partner:');
+        console.log(body);
+        callbackReport(task['requestId'], '68', 'cek');
+        
+    });;
+}
+
+function createServer() {
+    var httpServer = http.createServer(function(request, response) {
+        console.log('Got request from partner: ' + request.url);
+        response.end('OK');
+    });
+    
+    httpServer.listen(config.h2h_out.listen_port, function() {
+        console.log('HTTP Reverse/Report server listen on port ' + config.h2h_out.listen_port);
+    });
+}
+
+
+function start(_config, _callbackReport) {
+    config = _config;
+    callbackReport = _callbackReport
+
+    createServer();
+}
+
+exports.start = start;
+exports.topupRequest = topupRequest;