You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

如何在React Native应用中无服务器通过API生成Paytm支付链接并在WebView打开

Got it, let's figure out how to implement Paytm payments in your React Native app without running your own dedicated server. Here's a practical, step-by-step approach that leverages Paytm's official APIs and serverless functions (so you don't have to manage a full server):

Core Overview

Paytm requires a signed transaction request to initiate payments, and your merchant secret key can never be exposed in frontend code. Instead of building a full server, we'll use serverless functions to handle the secure parts (signature generation, API calls to Paytm) while keeping the React Native app focused on user interaction and payment flow.

The flow will be:

  1. User fills in order details (amount, contact info)
  2. App calls your serverless function to get a Paytm transaction token
  3. App generates the payment URL using the token and opens it in a WebView
  4. User completes payment in the WebView
  5. App and serverless function handle payment success/failure feedback

Step 1: Get Paytm Merchant Credentials

First, set up your Paytm account:

  • Sign up for a Paytm Merchant account (use the Sandbox environment for testing first)
  • Retrieve your Sandbox Merchant ID and Merchant Key from the Paytm Dashboard
  • Note: For production, you'll switch to live credentials later

Step 2: Build a Serverless Function for Transaction Initialization

We'll use a Node.js serverless function (e.g., Vercel/Netlify Functions) to handle the secure Paytm API call. This function will generate the required signature and fetch a transaction token.

Here's a sample function (save as api/init-paytm.js for Vercel):

const crypto = require('crypto');
const axios = require('axios');

export default async function handler(req, res) {
  if (req.method !== 'POST') {
    return res.status(405).json({ error: 'Method not allowed' });
  }

  const { orderId, amount, customerId, customerEmail, customerPhone } = req.body;

  // Paytm Sandbox API URL (replace with production URL later)
  const paytmApiUrl = 'https://securegw-stage.paytm.in/theia/api/v1/initiateTransaction';
  const merchantId = process.env.PAYTM_MERCHANT_ID;
  const merchantKey = process.env.PAYTM_MERCHANT_KEY;

  // Build Paytm request payload
  const payload = {
    body: {
      requestType: 'Payment',
      mid: merchantId,
      websiteName: 'WEBSTAGING', // Use your production website name later
      orderId: orderId,
      callbackUrl: `${process.env.NEXT_PUBLIC_APP_URL}/api/paytm-callback`,
      txnAmount: { value: amount, currency: 'INR' },
      userInfo: { custId: customerId, email: customerEmail, mobile: customerPhone }
    }
  };

  // Generate Paytm signature
  const payloadString = JSON.stringify(payload.body);
  const signature = crypto.createHmac('sha256', merchantKey)
    .update(payloadString)
    .digest('base64');

  // Send request to Paytm
  try {
    const paytmResponse = await axios.post(paytmApiUrl, {
      ...payload,
      head: { signature: signature }
    }, { headers: { 'Content-Type': 'application/json' } });

    if (paytmResponse.data.body.resultInfo.resultCode === '0000') {
      res.status(200).json({
        txnToken: paytmResponse.data.body.txnToken,
        mid: merchantId,
        orderId: orderId
      });
    } else {
      res.status(400).json({ error: paytmResponse.data.body.resultInfo.resultMsg });
    }
  } catch (error) {
    res.status(500).json({ error: 'Failed to start payment process' });
  }
}
  • Deploy this function to a serverless platform (Vercel/Netlify)
  • Set environment variables for PAYTM_MERCHANT_ID, PAYTM_MERCHANT_KEY, and NEXT_PUBLIC_APP_URL (your deployed app's URL)

Step 3: React Native App Implementation

First, install required dependencies:

npm install react-native-webview axios

Then build the payment screen component:

import React, { useState } from 'react';
import { View, Button, TextInput, Alert, StyleSheet } from 'react-native';
import { WebView } from 'react-native-webview';
import axios from 'axios';

const PaytmPaymentScreen = () => {
  const [amount, setAmount] = useState('15000');
  const [customerId, setCustomerId] = useState('CUST_001');
  const [customerEmail, setCustomerEmail] = useState('test@example.com');
  const [customerPhone, setCustomerPhone] = useState('9876543210');
  const [paymentUrl, setPaymentUrl] = useState(null);
  const [showWebView, setShowWebView] = useState(false);

  // Generate unique order ID for each payment
  const generateOrderId = () => `ORDER_${Date.now()}`;

  const initiatePayment = async () => {
    try {
      const orderId = generateOrderId();
      // Call your serverless function to get transaction token
      const serverResponse = await axios.post('https://your-vercel-app.vercel.app/api/init-paytm', {
        orderId,
        amount,
        customerId,
        customerEmail,
        customerPhone
      });

      const { txnToken, mid } = serverResponse.data;
      // Build Paytm payment URL
      const paytmPaymentUrl = `https://securegw-stage.paytm.in/theia/api/v1/showPaymentPage?mid=${mid}&orderId=${orderId}&txnToken=${txnToken}`;
      
      setPaymentUrl(paytmPaymentUrl);
      setShowWebView(true);
    } catch (error) {
      Alert.alert('Error', error.response?.data?.error || 'Failed to initiate payment');
    }
  };

  // Handle payment result from WebView navigation
  const handleWebViewNavigation = (navState) => {
    if (navState.url.includes('/api/paytm-callback')) {
      const urlParams = new URLSearchParams(navState.url.split('?')[1]);
      const paymentStatus = urlParams.get('STATUS');
      const transactionId = urlParams.get('TXNID');

      if (paymentStatus === 'TXN_SUCCESS') {
        Alert.alert('Payment Success!', `Transaction ID: ${transactionId}`);
        setShowWebView(false);
        // Add logic to update your app's order status here
      } else {
        Alert.alert('Payment Failed', 'Please try again later.');
        setShowWebView(false);
      }
    }
  };

  return (
    <View style={styles.container}>
      {!showWebView ? (
        <>
          <TextInput
            style={styles.input}
            placeholder="Amount (INR)"
            value={amount}
            onChangeText={setAmount}
            keyboardType="numeric"
          />
          <TextInput
            style={styles.input}
            placeholder="Customer ID"
            value={customerId}
            onChangeText={setCustomerId}
          />
          <TextInput
            style={styles.input}
            placeholder="Email"
            value={customerEmail}
            onChangeText={setCustomerEmail}
            keyboardType="email-address"
          />
          <TextInput
            style={styles.input}
            placeholder="Phone Number"
            value={customerPhone}
            onChangeText={setCustomerPhone}
            keyboardType="phone-pad"
          />
          <Button title="Pay Now" onPress={initiatePayment} />
        </>
      ) : (
        <WebView
          source={{ uri: paymentUrl }}
          onNavigationStateChange={handleWebViewNavigation}
          style={styles.webView}
        />
      )}
    </View>
  );
};

const styles = StyleSheet.create({
  container: { flex: 1, padding: 20, justifyContent: 'center' },
  input: { borderBottomWidth: 1, marginBottom: 20, padding: 10, fontSize: 16 },
  webView: { flex: 1 }
});

export default PaytmPaymentScreen;

Step 4: Add a Serverless Callback Function

To verify payment status securely (critical for order management), add another serverless function (api/paytm-callback.js):

const crypto = require('crypto');

export default async function handler(req, res) {
  if (req.method !== 'POST') {
    return res.status(405).json({ error: 'Method not allowed' });
  }

  const merchantKey = process.env.PAYTM_MERCHANT_KEY;
  const paytmParams = req.body;
  const receivedChecksum = paytmParams.CHECKSUMHASH;
  delete paytmParams.CHECKSUMHASH;

  // Verify Paytm's signature to ensure authenticity
  const calculatedChecksum = crypto.createHmac('sha256', merchantKey)
    .update(JSON.stringify(paytmParams))
    .digest('base64');

  if (calculatedChecksum === receivedChecksum) {
    console.log('Payment Status:', paytmParams.STATUS);
    // Add logic to update your database/order system here
    res.status(200).json({ status: 'SUCCESS', message: 'Payment verified' });
  } else {
    res.status(400).json({ status: 'FAILURE', message: 'Invalid payment signature' });
  }
}

Key Notes

  • Sandbox Testing: Use Paytm's sandbox test credentials (e.g., test phone number 7777777777, test OTP 489876) to test payments before going live.
  • Production Switch: Replace sandbox API URLs (securegw-stage.paytm.in) with production URLs (securegw.paytm.in) and update the websiteName to your official domain.
  • Security: Never hardcode your merchant key in frontend code—always use environment variables in serverless functions.
  • Order Uniqueness: Ensure each order has a unique ID to avoid duplicate payments.

内容的提问来源于stack exchange,提问作者Yohan K

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.05.07 19:33:10