# 5. Verify payment information

Based on the payment information from the client, the server verifies the <mark style="color:red;">**payment amount for fraud**</mark> and saves the payment information in the database if needed. The following are the steps for verifying the payment information.

* Server receives the i'mport payment ID (**imp\_uid**) and order ID (**merchant\_uid**)
* Call the [**Get payment API**](https://api.iamport.kr/#!/payments/getPaymentByImpUid) to get the payment details.
* Based on the response, compare the actual payment amount with the payment request amount (from merchant's database).

### <mark style="color:green;">**STEP 01**</mark> Server receives payment result

{% tabs %}
{% tab title="Node.js" %}
Example of receiving a POST request to the merchant endpoint URL that receives the payment information

{% code title="server-side" %}

```javascript
app.use(bodyParser.json());
  // "{Merchant endpoint that receives server's payment info}" POST request receiver
  app.post("/payments/complete", async (req, res) => {
    try {
      // Get imp_uid, merchant_uid from req.body
      const { imp_uid, merchant_uid } = req.body; 
    } catch (e) {
      res.status(400).send(e);
    }
  });
```

{% endcode %}
{% endtab %}
{% endtabs %}

### <mark style="color:green;">**STEP 02**</mark> Get payment details

{% tabs %}
{% tab title="Node.js" %}
Example of calling the [**Get payment**](https://api.iamport.kr/#!/payments/getPaymentByImpUid) **API** with the i'mport **payment ID (imp\_uid)** to retrieve the payment info.

{% code title="server-side" %}

```javascript
app.use(bodyParser.json());
    ...
    app.post("/payments/complete", async (req, res) => {
      try {
        // Get imp_uid, merchant_uid from req.body
        const { imp_uid, merchant_uid } = req.body; 
        ...
        // Get access token
        const getToken = await axios({
          url: "https://api.iamport.kr/users/getToken",
          method: "post", // POST method
          headers: { "Content-Type": "application/json" }, 
          data: {
            imp_key: "imp_apikey", // REST API key
            imp_secret: "ekKoeW8RyKuT0zgaZsUtXXTLQ4AhPFW3ZGseDA6bkA5lamv9OqDMnxyeB9wqOsuO9W3Mx9YSJ4dTqJ3f" // REST API Secret
          }
        });
        const { access_token } = getToken.data.response; // access token
        ...
        // Get payment info from i'mport server using imp_uid
        const getPaymentData = await axios({
          // Pass imp_uid
          url: \`https://api.iamport.kr/payments/\${imp_uid}\`, 
          // GET method
          method: "get", 
          // Add access toke to Authorization header
          headers: { "Authorization": access_token } 
        });
        const paymentData = getPaymentData.data.response; // Payment info
        ...
      } catch (e) {
        res.status(400).send(e);
      }
    });
```

{% endcode %}
{% endtab %}
{% endtabs %}

### <mark style="color:green;">**STEP 03**</mark> Verify payment information

> **Why fraud detection is necessary**
>
> Since the payment request is made on the client side, **a payment request can be forged or falsified by manipulating the client script**. Therefore, you must compare the original requested amount with the actual processed amount after the payment process is complete.
>
> For example, when paying for a product that costs 100,000 won, an attacker can manipulate the client script to change the `amount` property to a value lower than the actual amount.
>
> Since you cannot prevent script manipulation on the client, **you must check for fraud on the server after the payment is processed**.

{% tabs %}
{% tab title="Node.js" %}
Example of comparing the actual payment amount with the payment request amount, performing fraud check on the payment amount, and saving the data in the DB.

{% code title="server-side" %}

```javascript
app.use(bodyParser.json());
  ...
  app.post("/payments/complete", async (req, res) => {
    try {
      // Get imp_uid, merchant_uid from req.body
      const { imp_uid, merchant_uid } = req.body; 
      // Get access token
      /* ...Omitted... */
      // Get payment info from iamport server using imp_uid
      /* ...Omitted... */
      const paymentData = getPaymentData.data.response; // Payment info
      ...
      // Get the requested payment amount from the DB
      const order = await Orders.findById(paymentData.merchant_uid);
      const amountToBePaid = order.amount; // Requested payment amount
      ...
      // Verify payment
      const { amount, status } = paymentData;
      // If amount matches. Processed amount === Requested amount
      if (amount === amountToBePaid) { 
        await Orders.findByIdAndUpdate(merchant_uid, { $set: paymentData }); // Save payment info to DB
        ...
        switch (status) {
          case "ready": // Issue virtual account
            // Save virtual account info in DB
            const { vbank_num, vbank_date, vbank_name } = paymentData;
            await Users.findByIdAndUpdate("/* customer id */", { $set: { vbank_num, vbank_date, vbank_name }});
            // Send virtual account issuance text message
            SMS.send({ text: \`Virtual account issued successfully. Account info \${vbank_num} \${vbank_date} \${vbank_name}\`});
            res.send({ status: "vbankIssued", message: "Virtual account issued successfully" });
            break;
          case "paid": // Payment complete
            res.send({ status: "success", message: "General payment successful" });
            break;
        }
      } else { // Amount mismatch. Forged/falsified payment.
        throw { status: "forgery", message: "Forged/falsified payment attempted" };
      }
    } catch (e) {
      res.status(400).send(e);
    }
  });
```

{% endcode %}
{% endtab %}
{% endtabs %}

The original requested amount is queried from the database with the **`merchant_uid`**, and the actual processed amount is retrieved from the i'mport server with the **`imp_uid`**. The **two values ​​are compared** to verify that they match. **If the verification is successful, the payment information is saved in the database** and a response is returned based on the payment status (**`status`**). Otherwise, an error message is returned.<br>

{% hint style="danger" %}
The payment result must be processed on the database based on the data received through a [**webhook**](/docs-en/result/webhook.md) for stable processing without any missing result data.
{% endhint %}


---

# Agent Instructions: Querying This Documentation

If you need additional information that is not directly available in this page, you can query the documentation dynamically by asking a question.

Perform an HTTP GET request on the current page URL with the `ask` query parameter:

```
GET https://portone.gitbook.io/docs-en/auth/guide/5..md?ask=<question>
```

The question should be specific, self-contained, and written in natural language.
The response will contain a direct answer to the question and relevant excerpts and sources from the documentation.

Use this mechanism when the answer is not explicitly present in the current page, you need clarification or additional context, or you want to retrieve related documentation sections.
