Precondition Failed (412) error when using Phone pe Web API for getting transaction list

I am using the POST method on a Phone Pe Web API endpoint to get a list of transactions. I include cookies for authorization, but I’m encountering a 412 Precondition Failed error after a few hours. Specifically, the cookies _X52F70K3N and _CKB2N1BHVZ refresh every time, and I’m able to get the transaction list for about 2-4 hours. After that, the cookies expire, and I have to manually refresh them.

Here is the code I am using to make the request, along with the response I’m getting:

Code I am using:

   
const axios = require('axios');
const mysql = require('mysql2');
require('dotenv').config(); // Load environment variables from .env file

   
const dbConfig = {
    host: process.env.DB_HOST,
    user: process.env.DB_USER,
    password: process.env.DB_PASSWORD,
    database: process.env.DB_NAME
};

// PhonePe API URL and headers
const PHONEPE_API_URL = 'https://web-api.phonepe.com/apis/mi-web/v3/transactions/list';
const headers = {
    'Host': 'web-api.phonepe.com',
    'Content-Type': 'application/json',
    'Accept': 'application/json, text/plain, */*',
    'X-Csrf-Token': 'X7M1l************YQhI', // Use the actual CSRF token here
    'X-App-Id': 'oculus',
    'X-Source-Type': 'WEB',
    'User-Agent': 'Mozilla/5.0',
    'Namespace': 'insights',
    'X-Source-Platform': 'WEB',
    'Sec-Fetch-Site': 'same-site',
    'Sec-Fetch-Mode': 'cors',
    'Sec-Fetch-Dest': 'empty',
    'Referer': 'https://business.phonepe.com/',
    'Accept-Encoding': 'gzip, deflate, br',
    'Priority': 'u=4, i',
    'Cookie': '_ppabwduref=PA***********00; MERCHANT_USER_A_TOKEN=eyJ0*************9.ey*****************************************bSgo***M-y90******wg; MERCHANT_USER_R_TOKEN=f8*******-1****-4****-a***3-6*****3; _ppabwdcid=ZX***********FRR*********************WV************************zhFVU********==; _ppabwdsid=*****-***-****-***-****; _CKB2N1BHVZ=1s**************************xKStt/S*****kQ; _X52F70K3N=X7M*******QhI' // Replace with actual cookies // Replace with actual cookies
};

// Calculate timestamps for "from" and "to"
const now = Date.now();
const fromTimestamp = now - 24 * 60 * 60 * 1000; // 24 hours before now
const toTimestamp = now;

// API request payload
const requestData = {
    offset: 0,
    size: 10,
    filters: {},
    transactionType: "FORWARD",
    from: fromTimestamp,
    to: toTimestamp,
    selectedDateType: "today"
};

// Function to fetch transaction data from PhonePe API
async function fetchTransactionData() {
    try {
        const response = await axios.post(PHONEPE_API_URL, requestData, { headers });
        if (response.data.success) {
            console.log("Transaction Data Retrieved Successfully");
            return response.data.data.results || []; // Extract results from the response
        } else {
            console.error("Failed to fetch transaction data.");
            return [];
        }
    } catch (error) {
        console.error("Error during API request:", error);
        return [];
    }
}

// Function to check if a transaction ID exists in the database
async function transactionExists(transactionId, connection) {
    const query = 'SELECT COUNT(*) AS count FROM transactions WHERE transaction_id = ?';
    try {
        const [rows] = await connection.promise().query(query, [transactionId]);
        return rows[0].count > 0;
    } catch (error) {
        console.error('Error checking transaction existence:', error);
        return false;
    }
}

// Function to insert transaction data into the database
async function insertTransaction(transaction, connection) {
    const transactionData = {
        transaction_id: transaction.transactionId,
        transaction_type: transaction.transactionType,
        payment_state: transaction.paymentState,
        amount: transaction.amount / 100, // Convert paise to rupees
        merchant_transaction_id: transaction.merchantTransactionId,
        instrument_type: transaction.instrumentDetails[0]?.instrumentType || null,
        vpa: transaction.instrumentDetails[0]?.vpa || null,
        transaction_note: transaction.transactionNote,
        transaction_date: new Date(transaction.transactionDate).toISOString(),
        customer_name: transaction.customerDetails?.userName || null,
        payment_app: transaction.paymentApp?.paymentApp || null,
        settlement_status: transaction.settlement?.status || null,
        settlement_text: transaction.settlement?.settlementText || null,
        utr: transaction.utr || null
    };

    const query = `
        INSERT INTO transactions (transaction_id, transaction_type, payment_state, amount, 
            merchant_transaction_id, instrument_type, vpa, transaction_note, transaction_date, 
            customer_name, payment_app, settlement_status, settlement_text, utr)
        VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?);
    `;

    try {
        await connection.promise().query(query, [
            transactionData.transaction_id,
            transactionData.transaction_type,
            transactionData.payment_state,
            transactionData.amount,
            transactionData.merchant_transaction_id,
            transactionData.instrument_type,
            transactionData.vpa,
            transactionData.transaction_note,
            transactionData.transaction_date,
            transactionData.customer_name,
            transactionData.payment_app,
            transactionData.settlement_status,
            transactionData.settlement_text,
            transactionData.utr
        ]);
        console.log(`Transaction ID ${transactionData.transaction_id} inserted successfully.`);
    } catch (error) {
        console.error(`Error inserting transaction ID ${transactionData.transaction_id}:`, error);
    }
}

// Main function to fetch and update transaction data
async function main() {
    const transactions = await fetchTransactionData();
    if (!transactions.length) {
        console.log("No transactions found.");
        return;
    }

    const connection = mysql.createConnection(dbConfig);

    try {
        for (const transaction of transactions) {
            const exists = await transactionExists(transaction.transactionId, connection);
            if (exists) {
                console.log(`Transaction ID ${transaction.transactionId} already exists. Skipping.`);
            } else {
                await insertTransaction(transaction, connection);
            }
        }
    } catch (error) {
        console.error("Error processing transactions:", error);
    } finally {
        connection.end();
    }
}

main();

Response of 412 is

config: {
  transitional: [Object],
  adapter: [Array],
  transformRequest: [Array],
  transformResponse: [Array],
  timeout: 0,
  xsrfCookieName: 'XSRF-TOKEN',
  xsrfHeaderName: 'X-XSRF-TOKEN',
  maxContentLength: -1,
  maxBodyLength: -1,
  env: [Object],
  validateStatus: [Function: validateStatus],
  headers: [Object [AxiosHeaders]],
  method: 'post',
  url: 'https://web-api.phonepe.com/apis/mi-web/v3/transactions/list',
  data: '{"offset":0,"size":10,"filters":{},"transactionType":"FORWARD","from":1734776412434,"to":1734862812434,"selectedDateType":"today"}'
},
request: <ref *1> ClientRequest {
  _events: [Object: null prototype],
  _eventsCount: 7,
  _maxListeners: undefined,
  outputData: [],
  outputSize: 0,
  writable: true,
  destroyed: false,
  _last: true,
  chunkedEncoding: false,
  shouldKeepAlive: false,
  maxRequestsOnConnectionReached: false,
  _defaultKeepAlive: true,
  useChunkedEncodingByDefault: true,
  sendDate: false,
  _removedConnection: false,
  _removedContLen: false,
  _removedTE: false,
  strictContentLength: false,
  _contentLength: '130',
  _hasBody: true,
  _trailer: '',
  finished: true,
  _headerSent: true,
  _closed: false,
  socket: [TLSSocket],
  _header: 'POST /apis/mi-web/v3/transactions/list HTTP/1.1rn' +
    'Accept: application/json, text/plain, */*rn' +
    'Content-Type: application/jsonrn' +
    'Host: web-api.phonepe.comrn' +
    'X-Csrf-Token: X7M1l************YQhIrn' +
    'X-App-Id: oculusrn' +
    'X-Source-Type: WEBrn' +
    'User-Agent: Mozilla/5.0rn' +
    'Namespace: insightsrn' +
    'X-Source-Platform: WEBrn' +
    'Sec-Fetch-Site: same-sitern' +
    'Sec-Fetch-Mode: corsrn' +
    'Sec-Fetch-Dest: emptyrn' +
    'Referer: https://business.phonepe.com/rn' +
    'Accept-Encoding: gzip, deflate, brrn' +
    'Priority: u=4, irn' +
    'Cookie: __ppabwduref=PA***********00; MERCHANT_USER_A_TOKEN=eyJ0*************9.ey*****************************************bSgo***M-y90******wg; MERCHANT_USER_R_TOKEN=f8*******-1****-4****-a***3-6*****3; _ppabwdcid=ZX***********FRR*********************WV************************zhFVU********==; _ppabwdsid=*****-***-****-***-****; _CKB2N1BHVZ=1s**************************xKStt/S*****kQ; _X52F70K3N=X7M*******QhI
    'Content-Length: 130rn' +
    'Connection: closern' +
    'rn',
  _keepAliveTimeout: 0,
  _onPendingData: [Function: nop],
  agent: [Agent],
  socketPath: undefined,
  method: 'POST',
  maxHeaderSize: undefined,
  insecureHTTPParser: undefined,
  joinDuplicateHeaders: undefined,
  path: '/apis/mi-web/v3/transactions/list',
  _ended: true,
  res: [IncomingMessage],
  aborted: false,
  timeoutCb: null,
  upgradeOrConnect: false,
  parser: null,
  maxHeadersCount: null,
  reusedSocket: false,
  host: 'web-api.phonepe.com',
  protocol: 'https:',
  _redirectable: [Writable],
  [Symbol(kCapture)]: false,
  [Symbol(kBytesWritten)]: 0,
  [Symbol(kNeedDrain)]: false,
  [Symbol(corked)]: 0,
  [Symbol(kOutHeaders)]: [Object: null prototype],
  [Symbol(errored)]: null,
  [Symbol(kHighWaterMark)]: 16384,
  [Symbol(kRejectNonStandardBodyWrites)]: false,
  [Symbol(kUniqueHeaders)]: null
},
data: ''

},
status: 412
}