---
agentTools:
  projectIndex: https://docs.quidpay.io/llms.txt
---

# Verify Payment

Verify the payment with quidpay.

After integrating Quidpay checkout button and a user has successfully paid, you need to verify that the payment was successful with Quidpay before giving value to your customer on your website.

Although the Quidpay inline already verifies the payment from the client side, we strongly recommend you still do a server-side verification to be double sure no foul play occurred during the payment flow.

Below are the important things to check for when validating the payment:

Verify the transaction reference.

Verify the `data.status` of the transaction to be `successful`.

Verify the `chargecode` returned in the response to be `00`.

Verify the currency to be the expected currency

Most importantly validate the `amount` paid to be equal to or at least greater than the `amount` of the value to be given.

Below are sample code snippets showing how to implement server-side validation in different programming languages

[block:callout]
{
  "type": "success",
  "title": "Completing a successful verification test",
  "body": "Quidpay uses two environments one for `test` and one for `live`. On test environment the keys and script url are different from the keys and script url on live. To get your test keys sign up on `https://ravesandbox.flutterwave.com` and retrieve your test [API Keys](https://docs.quidpay.io/docs/api-keys) ."
}
[/block]

[block:callout]
{
  "type": "danger",
  "body": "This happens when you are using keys from the live environment with verify URL from the test environment. *The snippet below currently uses test verify URL from the test environment. *\n\nTo avoid the invalid secret key error, you can see how to set up a test and live environment [here](https://flutterwavedevelopers.readme.io/docs/setting-up-on-quidpay).\n\n```\nTest verify URL:  https://ravesandboxapi.flutterwave.com/flwv3-pug/getpaidx/api/v2/verify \n```\n\n```\nLive verify URL: https://api.ravepay.co/flwv3-pug/getpaidx/api/v2/verify \n```",
  "title": "Invalid Secret Key"
}
[/block]

[block:code]
{
  "codes": [
    {
      "code": "curl --request POST \\\n  --url https://ravesandboxapi.flutterwave.com/flwv3-pug/getpaidx/api/xrequery \\\n  --header 'content-type: application/json' \\\n  --data '{\"txref\":\"MC-1520443531487\",\"SECKEY\":\"FLWSECK-e6db11d1f8a6208de8cb2f94e293450e-X\", \"include_payment_entity\": 1}'",
      "language": "curl",
      "name": "curl"
    },
    {
      "code": "const unirest = require(\"unirest\"); //unirest is an http request library so any other preferred library can be used.\n\nvar payload =\n {\n  \"SECKEY\": \"FLWSECK-e6db11d1f8a6208de8cb2f94e293450e-X\",\n  \"txref\": \"MC-1520443531487\"\n};\n\nvar server_url = \"https://ravesandboxapi.flutterwave.com/flwv3-pug/getpaidx/api/v2/verify\"; \n//please make sure to change this to production url when you go live\n\n//make a post request to the server\nunirest.post(server_url)\n      .headers({'Content-Type': 'application/json'})\n      .send(payload)\n      .end(function(response) {\n      \t\t//check status is success.\n          if (response.body.data.status === \"successful\" && response.body.data.chargecode == 00) {\n              //check if the amount is same as amount you wanted to charge just to be very sure\n              if (response.body.data.amount === \"2000\") {\n                  console.log(\"Payment successful\");\n                  //then give value for the payment\n              }\n          }\n      });",
      "language": "javascript",
      "name": "Node"
    },
    {
      "code": "<?php\n\nuse Unirest\\Request\\Body;\n\n$data = array('txref' => 'MC-1520443531487',\n  'SECKEY' => 'FLWSECK-e6db11d1f8a6208de8cb2f94e293450e-X' //secret key from pay button generated on quidpay dashboard\n);\n\n\n\n  // make request to endpoint using unirest.\n  $headers = array('Content-Type' => 'application/json');\n  $body = Unirest\\Request\\Body::json($data);\n  $url = \"https://ravesandboxapi.flutterwave.com/flwv3-pug/getpaidx/api/v2/verify\"; //please make sure to change this to production url when you go live\n\n// Make `POST` request and handle response with unirest\n  $response = Unirest\\Request::post($url, $headers, $body);\n  \n  //check the status is success\n  if ($response->body->data->status === \"success\" && $response->body->data->chargecode === \"00\") {\n      //confirm that the amount is the amount you wanted to charge\n      if ($response->body->data->amount === 100) {\n          echo(\"Give value\");\n      }\n  }\n\n?>",
      "language": "php",
      "name": "PHP"
    },
    {
      "code": "import unirest #unirest is a http library. You can use any http library you prefer\nimport json\n\ndata = {\n\"txref\": \"MC-1520443531487\", #this is the reference from the payment button response after customer paid.\n\"SECKEY\": \"FLWSECK-e6db11d1f8a6208de8cb2f94e293450e-X\" #this is the secret key of the pay button generated\n}\n\n\n#function called after your request gets a response from quidpay's server\ndef callback_function(response):\n    #confirm that the response for the transaction is successful\n    if response.body['data']['status'] == 'success':\n      #confirm that the amount for that transaction is the amount you wanted to charge\n      \tif response.body['data']['chargecode'] == '00'\n        \n      \t  if response.body['data']['amount'] == 2000:\n        \t    print(\"Payment successful then give value\");\n      \n\n#this is the url of the staging server. Please make sure to change to that of production server when you are ready to go live.\nurl = \"https://ravesandboxapi.flutterwave.com/flwv3-pug/getpaidx/api/v2/verify\"\n\n#make the http post request to our server with the parameters\nthread = unirest.post(url, headers={\"Content-Type\":\"application/json\"}, params=data, callback=callback_function)",
      "language": "python",
      "name": "Python"
    },
    {
      "code": "require 'net/http'\nrequire 'uri'\nrequire 'json'\n\n\nuri = URI.parse(\"https://ravesandboxapi.flutterwave.com/flwv3-pug/getpaidx/api/v2/verify\") // Please make sure to change to that of production server when you are ready to go live.\nheader = {'Content-Type': 'application/json'}\npayload = {\n  'SECKEY' => 'FLWSECK-e6db11d1f8a6208de8cb2f94e293450e-X', //merchant secret key\n\t'txref'=> 'MC-1520443531487' //payment reference\n}\n\n\nhttp = Net::HTTP.new(uri.host)\nrequest = Net::HTTP::Post.new(uri.request_uri, header)\nrequest.body = payload.to_json\n\nresponse = http.request(request);\nbody = JSON.parse(response.body);\nif body['data'] && body['data']['status'] == 'successful'&& body['data']['chargecode'] == '00'\n\t#check amount and do other stuff with response\n\t# body['data']['amount'] == amount_to_give_value_for\nend",
      "language": "ruby",
      "name": "Ruby"
    },
    {
      "code": "package main\n\nimport (\n   \"bytes\"\n   \"io/ioutil\"\n   \"encoding/json\"\n   \"net/http\"\n   \"strings\"\n)\n\nfunc main() {\n   url := \"https://ravesandboxapi.flutterwave.com/flwv3-pug/getpaidx/api/v2/verify\" //Please make sure to change to that of production server when you are ready to go live.\n\n   data := make(map[string]string)\n   data[\"txref\"] = \"MC-1520443531487\"\n   // merchant secret key \n   data[\"SECKEY\"] = \"FLWSECK-e6db11d1f8a6208de8cb2f94e293450e-X\"\n\n   //convert data map to json byte[]\n   jsonData, _ := json.Marshal(data)\n\n   // make request to endpoint\n   client := &http.Client{}\n   request, _ := http.NewRequest(\"POST\", url, bytes.NewBuffer(jsonData))\n   request.Header.Set(\"Content-Type\", \"application/json\")\n\n   // Make `POST` request and handle response\n   response, err := client.Do(request)\n\n   if err == nil && response != nil {\n      responseJSON, _ := ioutil.ReadAll(response.Body)\n      var responseData map[string]interface{}\n      err = json.Unmarshal(responseJSON, &responseData)\n      \n      if err == nil {\n         if strings.Compare(responseData[\"data\"][\"status\"].(string), \"successful\") == 0 {\n            amount, _ := responseData[\"data\"].(map[string]interface{})[\"amount\"].(float64)\n            if amount == 2000 {\n               print(\"Give value\")\n            }\n         }\n      }\n   }\n}",
      "language": "go",
      "name": "Go"
    },
    {
      "code": "//Endpoint to verify transaction, Please make sure to change to that of production server when you are ready to go live.\n    private final String VERIFY_ENDPOINT = \"https://ravesandboxapi.flutterwave.com/flwv3-pug/getpaidx/api/v2/verify\"; \n    \n    /**\n     * \n     * Method to \n     * \n     * @param paymententity - <b>paymententity - set as a constant with default value as 1</b>\n     * @param txref - <b>txref - is the unique payment reference generated by the merchant.</b>\n     * @param secret - <b>secret - is the merchant secret key</b>\n     * @return\n     * @throws UnirestException \n     */\n    public JSONObject verify(String flwRef, String secret, double amount, int paymententity) throws UnirestException, Exception {\n        \n        // This packages the payload\n        JSONObject data = new JSONObject();\n        data.put(\"txref\", txref);\n        data.put(\"SECKEY\", secret)\n        \n        // end of payload\n        \n        // This sends the request to server with payload\n        HttpResponse<JsonNode> response = Unirest.post(VERIFY_ENDPOINT)\n                .header(\"Content-Type\", \"application/json\")\n                .body(data)\n                .asJson();\n        \n        // This get the response from payload\n        JsonNode jsonNode = response.getBody();\n        \n        // This get the json object from payload\n        JSONObject responseObject = jsonNode.getObject();\n        \n        // check of no object is returned\n        if(responseObject == null)\n            throw new Exception(\"No response from server\");\n        \n        // This get status from returned payload\n        String status = responseObject.optString(\"status\", null);\n        \n        // this ensures that status is not null\n        if(status == null)\n            throw new Exception(\"Transaction status unknown\");\n        \n        // This confirms the transaction exist on quidpay\n        if(!\"success\".equalsIgnoreCase(status)){\n            \n            String message = responseObject.optString(\"message\", null);\n            \n            throw new Exception(message);\n        }\n        \n        data = responseObject.getJSONObject(\"data\");\n        \n        // This get the amount stored on server\n        double actualAmount = data.getDouble(\"amount\");\n        \n        // This validates that the amount stored on client is same returned\n        if(actualAmount != amount)\n            throw new Exception(\"Amount does not match\");\n        \n        \n        // now you can give value for payment.\n       \n    }",
      "language": "java",
      "name": "Java"
    },
    {
      "code": "var data = new {txref = \"OH-AAED44\", SECKEY = \"FLWSECK-e6db11d1f8a6208de8cb2f94e293450e-X\"};\n            var client = new HttpClient();\n            client.DefaultRequestHeaders.Accept.Add(new MediaTypeWithQualityHeaderValue(\"application/json\"));\n            var responseMessage = client.PostAsJsonAsync(\"https://ravesandboxapi.flutterwave.com/flwv3-pug/getpaidx/api/v2/verify\", data).Result; //please make sure to change this to production url when you go live\n            var responseStr = responseMessage.Content.ReadAsStringAsync().Result;\n            var response = Newtonsoft.Json.JsonConvert.DeserializeObject<ResponseData>(responseStr);\n            if (response.data.status == \"successful\" && response.data.amount == amount && response.data.chargecode == \"00\")\n            {\n              \n              System.Console.WriteLine(\"Payment Successful then give value\");\n               \n            }",
      "language": "csharp",
      "name": "C#"
    }
  ]
}
[/block]

[block:api-header]
{
  "title": "How to pass your reference from the client to verify a transaction"
}
[/block]

This example shows you how to get the `txRef`  from the callback response on the **client page** and send it to a **server page** to verify and *log* the transaction before giving value.

[block:code]
{
  "codes": [
    {
      "code": "<input type=\"submit\" style=\"cursor:pointer;\" value=\"Pay Now\" id=\"submit\" />\n\n\n<script src=\"https://ajax.googleapis.com/ajax/libs/jquery/3.1.1/jquery.min.js\"></script>\n<script type=\"text/javascript\" src=\"https://ravesandboxapi.flutterwave.com/flwv3-pug/getpaidx/api/flwpbf-inline.js\"></script>\n<script type=\"text/javascript\">\n  document.addEventListener(\"DOMContentLoaded\", function(event) {\n    document.getElementById('submit').addEventListener('click', function () {\n\n    var flw_ref = \"\", chargeResponse = \"\", trxref = \"FDKHGK\"+ Math.random(), API_publicKey = \"FLWPUBK-4e89f89528693434b14647e83598d546-X\";\n\n    getpaidSetup(\n      {\n        PBFPubKey: API_publicKey,\n      \tcustomer_email: \"user@example.com\",\n      \tamount: 2000,\n      \tcustomer_phone: \"234099940409\",\n      \tcurrency: \"NGN\",\n      \tpayment_method: \"both\",\n      \ttxref: \"quidpay-123456\",\n      \tmeta: [{metaname:\"flightID\", metavalue: \"AP1234\"}],\n        onclose:function(response) {\n        },\n        callback:function(response) {\n          txref = response.tx.txRef, chargeResponse = response.tx.chargeResponseCode;\n          if (chargeResponse == \"00\" || chargeResponse == \"0\") {\n            window.location = \"https://your_URL/paymentverification.php?txref=\"+txref; //Add your success page here\n          } else {\n            window.location = \"https://your_URL/paymentverification.php?txref=\"+txref;  //Add your failure page here\n          }\n        }\n      }\n    );\n    });\n  });\n</script>",
      "language": "php",
      "name": "Verify PHP Sample On Client"
    },
    {
      "code": "<?php\n    if (isset($_GET['txref'])) {\n        $ref = $_GET['txref'];\n        $amount = \"\"; //Correct Amount from Server\n        $currency = \"\"; //Correct Currency from Server\n\n        $query = array(\n            \"SECKEY\" => \"Your Secret Key\",\n            \"txref\" => $ref\n        );\n\n        $data_string = json_encode($query);\n                \n        $ch = curl_init('https://api.ravepay.co/flwv3-pug/getpaidx/api/v2/verify ');                                                                      \n        curl_setopt($ch, CURLOPT_CUSTOMREQUEST, \"POST\");\n        curl_setopt($ch, CURLOPT_POSTFIELDS, $data_string);                                              \n        curl_setopt($ch, CURLOPT_RETURNTRANSFER, true);\n        curl_setopt($ch, CURLOPT_SSL_VERIFYPEER, false);\n        curl_setopt($ch, CURLOPT_HTTPHEADER, array('Content-Type: application/json'));\n\n        $response = curl_exec($ch);\n\n        $header_size = curl_getinfo($ch, CURLINFO_HEADER_SIZE);\n        $header = substr($response, 0, $header_size);\n        $body = substr($response, $header_size);\n\n        curl_close($ch);\n\n        $resp = json_decode($response, true);\n\n      \t$paymentStatus = $resp['data']['status'];\n        $chargeResponsecode = $resp['data']['chargecode'];\n        $chargeAmount = $resp['data']['amount'];\n        $chargeCurrency = $resp['data']['currency']\n\n        if (($chargeResponsecode == \"00\" || $chargeResponsecode == \"0\") && ($chargeAmount == $amount)  && ($chargeCurrency == $currency)) {\n          //Give Value and return to Success page\n        } else {\n            //Dont Give Value and return to Failure page\n        }\n    }\n\n?>",
      "language": "php",
      "name": "Verify PHP Sample on Server"
    }
  ]
}
[/block]

[block:api-header]
{
  "title": "Verify payment response"
}
[/block]

[block:code]
{
  "codes": [
    {
      "code": "{\n    \"status\": \"success\",\n    \"message\": \"Tx Fetched\",\n    \"data\": {\n        \"txid\": 123976,\n        \"txref\": \"MC-1522866789642\",\n        \"flwref\": \"FLW-MOCK-20bdec1097b925b9aa8224e06adb73d7\",\n        \"devicefingerprint\": \"69e6b7f0b72037aa8428b70fbe03986c\",\n        \"cycle\": \"one-time\",\n        \"amount\": 10,\n        \"currency\": \"NGN\",\n        \"chargedamount\": 10,\n        \"appfee\": 0,\n        \"merchantfee\": 0,\n        \"merchantbearsfee\": 1,\n        \"chargecode\": \"00\",\n        \"chargemessage\": \"Approved. Successful\",\n        \"authmodel\": \"VBVSECURECODE\",\n        \"ip\": \"::ffff:127.0.0.1\",\n        \"narration\": \"FLW-PBF CARD Transaction \",\n        \"status\": \"successful\",\n        \"vbvcode\": \"00\",\n        \"vbvmessage\": \"Approved. Successful\",\n        \"authurl\": \"http://flw-pms-dev.eu-west-1.elasticbeanstalk.com/mockvbvpage?ref=FLW-MOCK-20bdec1097b925b9aa8224e06adb73d7&code=00&message=Approved. Successful&receiptno=RN1522866810978\",\n        \"acctcode\": null,\n        \"acctmessage\": null,\n        \"paymenttype\": \"card\",\n        \"paymentid\": \"1450\",\n        \"fraudstatus\": \"ok\",\n        \"chargetype\": \"normal\",\n        \"createdday\": 3,\n        \"createddayname\": \"WEDNESDAY\",\n        \"createdweek\": 14,\n        \"createdmonth\": 3,\n        \"createdmonthname\": \"APRIL\",\n        \"createdquarter\": 2,\n        \"createdyear\": 2018,\n        \"createdyearisleap\": false,\n        \"createddayispublicholiday\": 0,\n        \"createdhour\": 18,\n        \"createdminute\": 33,\n        \"createdpmam\": \"pm\",\n        \"created\": \"2018-04-04T18:33:30.000Z\",\n        \"customerid\": 22015,\n        \"custphone\": \"0902620185\",\n        \"custnetworkprovider\": \"AIRTEL\",\n        \"custname\": \"temi desola\",\n        \"custemail\": \"user@gmail.com\",\n        \"custemailprovider\": \"GMAIL\",\n        \"custcreated\": \"2018-04-02T14:49:59.000Z\",\n        \"accountid\": 134,\n        \"acctbusinessname\": \"Synergy Group\",\n        \"acctcontactperson\": \"Desola Ade\",\n        \"acctcountry\": \"NG\",\n        \"acctbearsfeeattransactiontime\": 1,\n        \"acctparent\": 1,\n        \"acctvpcmerchant\": \"N/A\",\n        \"acctalias\": \"temi\",\n        \"acctisliveapproved\": 0,\n        \"orderref\": \"URF_1522866810933_7293235\",\n        \"paymentplan\": 16,\n        \"paymentpage\": null,\n        \"raveref\": \"RV3152286680999275AD9704CC\",\n        \"amountsettledforthistransaction\": 10,\n        \"card\": {\n            \"expirymonth\": \"12\",\n            \"expiryyear\": \"20\",\n            \"cardBIN\": \"475176\",\n            \"last4digits\": \"9647\",\n            \"brand\": \"VISA ACCESS BANK PLC CREDITPREMIER\",\n            \"card_tokens\": [\n                {\n                    \"embedtoken\": \"flw-t1nf-16dead8e2217a10dccc8278b18dd5b71-m03k\",\n                    \"shortcode\": \"61c4a\",\n                    \"expiry\": \"9999999999999\"\n                }\n            ],\n            \"life_time_token\": \"flw-t1nf-16dead8e2217a10dccc8278b18dd5b71-m03k\"\n        },\n        \"meta\": [\n            {\n                \"id\": 25700,\n                \"metaname\": \"flightID\",\n                \"metavalue\": \"123949494DC\",\n                \"createdAt\": \"2018-04-04T18:33:32.000Z\",\n                \"updatedAt\": \"2018-04-04T18:33:32.000Z\",\n                \"deletedAt\": null,\n                \"getpaidTransactionId\": 123976\n            }\n        ]\n    }\n}",
      "language": "json",
      "name": "200 Successful Card"
    },
    {
      "code": "{\n    \"status\": \"success\",\n    \"message\": \"Tx Fetched\",\n    \"data\": {\n        \"txid\": 124161,\n        \"txref\": \"MC-1522914089167\",\n        \"flwref\": \"ACHG-1522914115739\",\n        \"devicefingerprint\": \"69e6b7f0b72037aa8428b70fbe03986c\",\n        \"cycle\": \"one-time\",\n        \"amount\": 10,\n        \"currency\": \"NGN\",\n        \"chargedamount\": 10,\n        \"appfee\": 0,\n        \"merchantfee\": 0,\n        \"merchantbearsfee\": 1,\n        \"chargecode\": \"00\",\n        \"chargemessage\": \"Pending OTP validation\",\n        \"authmodel\": \"AUTH\",\n        \"ip\": \"::ffff:127.0.0.1\",\n        \"narration\": \"Synergy Group\",\n        \"status\": \"successful\",\n        \"vbvcode\": \"N/A\",\n        \"vbvmessage\": \"N/A\",\n        \"authurl\": \"NO-URL\",\n        \"acctcode\": \"00\",\n        \"acctmessage\": \"Approved Or Completed Successfully\",\n        \"paymenttype\": \"account\",\n        \"paymentid\": \"2\",\n        \"fraudstatus\": \"ok\",\n        \"chargetype\": \"normal\",\n        \"createdday\": 4,\n        \"createddayname\": \"THURSDAY\",\n        \"createdweek\": 14,\n        \"createdmonth\": 3,\n        \"createdmonthname\": \"APRIL\",\n        \"createdquarter\": 2,\n        \"createdyear\": 2018,\n        \"createdyearisleap\": false,\n        \"createddayispublicholiday\": 0,\n        \"createdhour\": 7,\n        \"createdminute\": 41,\n        \"createdpmam\": \"am\",\n        \"created\": \"2018-04-05T07:41:53.000Z\",\n        \"customerid\": 22536,\n        \"custphone\": \"09026420185\",\n        \"custnetworkprovider\": \"AIRTEL\",\n        \"custname\": \"temi desola\",\n        \"custemail\": \"user@example.com\",\n        \"custemailprovider\": \"COMPANY EMAIL\",\n        \"custcreated\": \"2018-04-05T07:38:39.000Z\",\n        \"accountid\": 134,\n        \"acctbusinessname\": \"Synergy Group\",\n        \"acctcontactperson\": \"Desola Ade\",\n        \"acctcountry\": \"NG\",\n        \"acctbearsfeeattransactiontime\": 1,\n        \"acctparent\": 1,\n        \"acctvpcmerchant\": \"N/A\",\n        \"acctalias\": \"temi\",\n        \"acctisliveapproved\": 0,\n        \"orderref\": \"URF_1522914113761_6077035\",\n        \"paymentplan\": null,\n        \"paymentpage\": null,\n        \"raveref\": \"RV31522914113478DA28603ABF\",\n        \"amountsettledforthistransaction\": 10,\n        \"account\": {\n            \"id\": 2,\n            \"account_number\": \"0690000031\",\n            \"account_bank\": \"044\",\n            \"first_name\": \"NO-NAME\",\n            \"last_name\": \"NO-LNAME\",\n            \"account_is_blacklisted\": 0,\n            \"createdAt\": \"2016-12-31T04:09:24.000Z\",\n            \"updatedAt\": \"2018-04-05T07:42:28.000Z\",\n            \"deletedAt\": null,\n            \"account_token\": {\n                \"token\": \"flw-t0e1bb79f967612fc1-k3n-mock\"\n            }\n        },\n        \"meta\": []\n    }\n}",
      "language": "json",
      "name": "200 Successful Account"
    },
    {
      "code": "{\n  \"status\": \"error\",\n  \"message\": \"No transaction found\",\n  \"data\": {\n    \"code\": \"NO TX\",\n    \"message\": \"No transaction found\"\n  }\n}",
      "language": "json",
      "name": "400 No Transaction Found"
    }
  ]
}
[/block]