An error occured while initiating transaction Error: Hashes do not match! at Paynow.parse


#1

Hie there, I followed the documentation here https://developers.paynow.co.zw/docs/nodejs_quickstart.html. However I am getting the following error when i try to initiate any payment using my number. What should i do to correct that?

An error occured while initiating transaction Error: Hashes do not match!
    at Paynow.parse (/home/ec2-user/environment/node_modules/paynow/dist/paynow.js:101:23)
    at /home/ec2-user/environment/node_modules/paynow/dist/paynow.js:87:26
    at process._tickCallback (internal/process/next_tick.js:68:7)

#2

hi @k1muza , I don’t have your code so I 'll make a few assumptions about it. Your Paynow merchant account is still in testing mode. For testing, we advise the use of test numbers found here https://developers.paynow.co.zw/docs/initiate_mobile_transaction.html#express-checkout-test-mode
. If your challenge persists may you share your code Minus integration ID and Integration key


#3

Hashes do not match will be a hashing problem - @k1muza are you using Paynow SDK or your own code for generating hash? If your own code, please share how you create your message hash.


#4

Thanks for the replies. Below is my code

app.post("/payment/ecocash", async function(req, res, next) {
  console.log(req.body.invoice);
  const items = req.body.items;

  let payment = paynow.createPayment(req.body.invoice, req.body.email);
  items.forEach(item => {
    payment.add(item.name, item.price);
  })

  const response = await paynow.sendMobile(payment, '0771111111', 'ecocash');
  if (response && response.success) {
    let instructions = response.instructions
    let pollUrl = response.pollUrl; 

    console.log('PollUrl', pollUrl);
    console.log('Instructions', instructions)
    let status = await paynow.pollTransaction(pollUrl);

    console.log('Status', status);
    if (status.paid()) {
      res.json('Yay! Transaction was paid for');
    }
    else {
      res.json("Why you no pay?");
    }
  }
  else {
    console.log('Error', response.error);
    res.json(response.error);
  }
});

#5

@Harvey I am using the test number as shown in the above code, however the error continues to be thrown. And also how do i move my account from testing mode. I also need to test with my own numbers. Real life simulation is important to us.


#6

@k1muza . Kindly console.log(item.price) and advise . I am suspecting that the price is being parsed as a string instead of a double or integer depending on your implementation.


#7

Hi @k1muza,

I’ve done a few tests with the node sdk and the only scenarios where I get Hashes do not match are

  • When paynow.returnUrl or paynow.resultUrl are not set
  • When you use a number that isn’t one of the test numbers while you are in testing mode
  • When the auth email parameter which in your case is req.body.email isn’t one that belongs to the account that is testing while in test mode.
  • Incorrect integration_id and integration_key. Please not the " 1234", "1234 " and " 1234 " where 1234 is your integration key will cause a hash mismatch.

Here is a working example:

const { Paynow } = require('paynow');
const { INTEGRATION_KEY, INTEGRATION_ID } = require('./constants');

const paynow = new Paynow(INTEGRATION_ID, INTEGRATION_KEY);

paynow.resultUrl = "http://example.com/gateways/paynow/update";
paynow.returnUrl = "http://example.com/return?gateway=paynow&merchantReference=1234";

makePayment();

async function makePayment () {
    const ref = new Date().getTime();

    const payment = paynow.createPayment(`Invoice ${ref}`, '[email protected]');

    payment.add("Oranges", 30);
    payment.add("Bread", 15);

    try {
        const response = await paynow.sendMobile(payment, '0771111111', 'ecocash');
        if (response && response.success) {
            console.log(response)
        } else {
            console.log(response);
        }
    } catch (e) {
        console.log(e);
    }
}

#8

Thanks a lot @adrian

I followed all your pointers, after copying your code and further testing, my problem seems to emanate from somewhere else. If I change products from

payment.add("Oranges", 30);
payment.add("Bread", 15);

to

payment.add("10 to 1", 0.5);
payment.add("CG Summer Cut Day 1", 1);

then I am getting the error. Leaving “Oranges” and “Bread” then there isn’t any problem. However, I don’t want to sell Bread and Oranges :slight_smile:

Might this be another testing criteria?

Below is my entire edited code

const express = require('express');
const app = express();
var http = require('http').createServer(app);
var cors = require('cors');
const { Paynow } = require("paynow");

const port = process.env.PORT || 3000;

const paynow = new Paynow(__ID__, __TOKEN___); // Replaced these before i uploaded here
const base_url = "http://3.15.41.118";

paynow.resultUrl = `${base_url}/gateways/paynow/update`;
paynow.returnUrl = `${base_url}/return`;

app.use(cors());
app.options('*', cors());

app.use(express.urlencoded({ extended: true }));
app.use(express.json());

app.post("/payment/ecocash", async function(req, res, next) {
    const invoice = new Date().getTime();
    const items = req.body.items;

    let payment = paynow.createPayment(`Invoice ${invoice}`, '[email protected]');

    payment.add("10 to 1", 0.5);
    payment.add("CG Summer Cut Day 1", 1);

    // payment.add("Oranges", 0.5);
    // payment.add("Bread", 1);

    const response = await paynow.sendMobile(payment, '0771111111', 'ecocash');
    if (response && response.success) {
        let instructions = response.instructions
        let pollUrl = response.pollUrl;

        console.log('PollUrl', pollUrl);
        console.log('Instructions', instructions)
        let status = await paynow.pollTransaction(pollUrl);

        console.log('Status', status);
        if (status.paid()) {
            res.json('Yay! Transaction was paid for');
        }
        else {
            res.json("Why you no pay?");
        }
    }
    else {
        console.log('Error', response.error);
        res.json(response.error);
    }
});

app.get('/return', (req, res) => {
    console.log('Return', req.query);
    res.json(req.query);
})

app.get('/gateways/paynow/update', (req, res) => {
    console.log('Results', req.query);
    res.json(req.query);
})

http.listen(port, function() {
    console.log(`listening on ${port}`);
});

#9

The error has been addressed. Paynow-NodeJS-SDK was updated to version: 1.0.9 . It has not yet updated on npm but is available on Github https://github.com/paynow/Paynow-NodeJS-SDK


#10

The update referenced to by @Harvey in now available via npm. Updating to the latest version (1.0.9) will clear this issue.


#11

Thank you very much. This issue seems to have been solved, though partially. I can transact even with my phone number. However, I am facing a another issue. I can’t seem to get the return or the result url to work. I was hoping to avoid using the pollUrl to poll your servers every now and again to get transaction statuses. I was happy to find out your API has result and return urls for transaction updates, however i dont seem to be able to get them to work. None of my provided urls i.e. returnUrl or resultUrl are visited/updated when a user successfully finishes a transaction.

Again my entire code is as below

const express = require('express');
const app = express();
var http = require('http').createServer(app);
var cors = require('cors');
const { Paynow } = require("paynow");

const port = process.env.PORT || 8080;

const paynow = new Paynow(__ID__, __TOKEN___); // Replaced these before i uploaded here
const base_url = "http://18.217.49.123:8080";

paynow.resultUrl = `${base_url}/result`;
paynow.returnUrl = `${base_url}/return`;

app.use(cors());
app.options('*', cors());

app.use(express.urlencoded({ extended: true }));
app.use(express.json());

app.all('/return', (req, res, next) => {
    console.log('Return', req.query);
    res.json(req.query);
})

app.all('/result', (req, res, next) => {
    console.log('Results', req.query);
    res.json(req.query);
})

app.post("/payment/ecocash", async function(req, res, next) {
    const invoice = new Date().getTime();
    const items = req.body.items;

    let payment = paynow.createPayment(`Invoice ${invoice}`, '[email protected]');

    payment.add("10 to 1", 0.5);
    payment.add("CG Summer Cut Day 1", 1);

    const response = await paynow.sendMobile(payment, '0774684534', 'ecocash');
    if (response && response.success) {
        let instructions = response.instructions
        let pollUrl = response.pollUrl;

        console.log('PollUrl', pollUrl);
        console.log('Instructions', instructions)
        let status = await paynow.pollTransaction(pollUrl);

        console.log('Status', status);
        if (status.paid()) {
            res.json('Yay! Transaction was paid for');
        }
        else {
            res.json("Why you no pay?");
        }
    }
    else {
        console.log('Error', response.error);
        res.json(response.error);
    }
});

http.listen(port, function() {
    console.log(`listening on ${port}`);
});

#12

Hi @k1muza , I tried to ping the url in your base_url variable. There was no response from the url. If your that server is live and online , you may need to look at the reasons why its not accessible from the internet.
“const base_url = “http://18.217.49.123:8080”;”


#13

Oh ok sorry, It’s a development server. Amazon Cloud 9. It’s only ON when I am online and 30min after I log off. Hence you need to ping during the time i’m ON. We would need to coordinate our approach hereon. What time do you want to PING again so i can be available during that time.


#14

Thats fine , before we attempt that, can you confirm if Amazon assigns you the same IP address every time you turn on your server. Next time you are testing can manually send a post to your url and confirm it can receive data


#15

No i am assigned a different one. When you are ready just say so i can kickstart the server and send u the latest IP.


#16

@k1muza and you always update the url as you go? Lets say 1230pm you turn it on.


#17

18.218.24.125:8080 I am live.


#18

Nothing from my end


#19

That’s weird. Can you please try again.
Is it relevant though. You can just try accessing the return url using the browser
http://18.218.24.125:8080/return
or
http://18.218.24.125:8080/result


#20

@Harvey According to my quick search on Google, it turns out you cannot ping ports, you need to use telnet or nmap.