# BaseUPI — Complete Technical Reference for LLMs > This document is a self-contained reference for AI/LLM systems. It contains the full specification of BaseUPI — no external links are needed. Everything an LLM needs to understand, integrate, or answer questions about BaseUPI is included below. --- # 1. WHAT IS BASEUPI BaseUPI is a developer-first, commission-free, open-source payment infrastructure that enables businesses in India to accept UPI payments directly to their bank accounts. It uses an Android phone as a real-time payment verification oracle. BaseUPI is NOT a payment gateway, payment aggregator, escrow service, banking institution, or financial intermediary. It does not hold, process, transfer, or have custody of any funds. All payments flow directly from the Customer to the Merchant via the NPCI UPI rail. BaseUPI does not require an RBI Payment Aggregator (PA) license because it does not pool or handle merchant funds. The software merely automates the verification of incoming payments by reading bank SMS notifications. ## Key Capabilities - Zero Commissions: 100% of the funds reach the merchant's bank account. - Direct Settlement: No intermediary holds the money. Instant settlement via UPI. - Developer First: Official SDKs for Node.js (baseupi) and React (baseupi-react). - Real-time Verification: Instant payment confirmation via Bank SMS detection on Android. - Self-Hosted: Merchant deploys their own instance with a Supabase database. BaseUPI developers have zero access to merchant data. - Open Source: Licensed under permissive terms. ## Tech Stack - Frontend: Next.js 16, React 19, Tailwind CSS 4 - Backend: Next.js API Routes, Supabase (PostgreSQL + GoTrue Auth) - Mobile: Android Companion App (reads bank SMS) - SDKs: baseupi (Node.js), baseupi-react (React) --- # 2. HOW IT WORKS (MERCHANT PERSPECTIVE) Unlike traditional payment gateways (Stripe, Razorpay) that collect money, hold it in a nodal account, and settle it days later minus a fee, BaseUPI acts only as a communication layer. ## The Payment Flow (What You See) 1. ORDER CREATION: Your backend creates an order via the API. BaseUPI returns a checkout_url, QR code, and UPI deeplink. 2. CHECKOUT: Your customer sees a QR code or UPI deeplink on your website (via React SDK, Vanilla JS Widget, or Payment Link). 3. PAYMENT: The customer pays using any UPI app. Money goes directly from their bank to yours. BaseUPI never touches the funds. 4. VERIFICATION: BaseUPI's proprietary verification system automatically confirms the payment was received. 5. WEBHOOK: Once verified, BaseUPI fires a signed webhook to your server. You verify the HMAC-SHA256 signature and fulfill the order. ## Order Status Lifecycle CREATED → PAID/COMPLETED (on successful verification) CREATED → FAILED (on timeout or explicit failure) --- # 3. GETTING STARTED — ACCOUNT SETUP ## Step 1: Create Account 1. Sign up on the BaseUPI dashboard. 2. Go to Profile settings. 3. Enter your UPI ID (VPA) — e.g., merchant@okicici. This is where payments are received. Double-check this: BaseUPI does not hold your money. ## Step 2: Connect Android Companion App 1. Download the BaseUPI Companion App APK on an Android device. 2. Grant SMS Permissions when prompted (required to detect bank "Credited" messages). 3. Disable Battery Optimization: - Go to Phone Settings > Apps > BaseUPI - Select Battery or App Battery Usage - Choose "Unrestricted" or "No Restrictions" (NOT "Optimized") 4. Link Device to Dashboard: - In the Dashboard, go to Devices to view the pairing QR Code. - In the Android App, go to Settings > Scan QR Code. - Scan the code to link your phone to your account. - Click "Test Connection" to verify communication. ## Step 3: Get API Keys Go to the Developer / API Keys tab in the Dashboard. You will receive: - Public Key (x-api-key header): Safe to use in server requests, identifies your merchant account. - Secret Key (Authorization: Bearer header): NEVER expose on the frontend. Used for creating orders and verifying webhooks. - Webhook Secret: Used to verify webhook signature authenticity. --- # 4. API REFERENCE ## Base URL All API requests must be made over HTTPS: `https:///api/v1` ## Authentication Headers | Header | Value | Description | |------------------|------------------------------|---------------------------| | x-api-key | zp_live_... | Your Merchant Public Key | | Authorization | Bearer zp_live_secret_... | Your Secret Key | IMPORTANT: NEVER use the Secret Key on the frontend. Always make API calls from your backend server. --- ## 4.1 Orders ### Create an Order Creates a new payment intent. Endpoint: POST /orders Request Body (JSON): { "amount_paise": 49900, "merchant_order_id": "ord_12345", "customer_email": "customer@example.com", "redirect_url": "https://yoursite.com/success", "line_items": [ { "name": "Pro Monthly Plan", "amount_paise": 49900, "quantity": 1 } ], "metadata": { "plan_id": "gold", "userId": "user_99" } } Required fields: amount_paise, merchant_order_id Optional fields: customer_email, redirect_url, line_items, metadata Response (JSON): { "order_id": "ord_K9EFTDQV", "status": "CREATED", "amount_paise": 49900, "checkout_url": "https:///checkout/ord_K9EFTDQV", "upi_deeplink": "upi://pay?pa=merchant@upi&am=499.00&tn=Order ord_K9EFTDQV", "qr_code_url": "https:///api/qr/ord_K9EFTDQV" } ### Get Order Details Retrieves an existing order status without waiting for webhooks. Endpoint: GET /orders/:order_id Response (JSON): { "order_id": "ord_K9EFTDQV", "status": "PAID", "amount_paise": 49900, "merchant_order_id": "ord_12345", "reference_number": "330012345678", "paid_at": "2026-03-18T10:05:00.000Z" } Possible status values: CREATED, PAID, COMPLETED, FAILED, EXPIRED --- ## 4.2 Payment Links ### Create Payment Link Generates a permanent, reusable URL to accept payments. No code required to share. Endpoint: POST /payment-links Request Body (JSON): { "title": "Yoga Class", "description": "Drop-in session", "slug": "yoga-drop-in", "amount_paise": 50000 } Response (JSON): { "link_id": "plink_xyz", "url": "https:///pay/yoga-drop-in" } Payment Link Features: - Custom Slugs: Create specific URLs like /pay/my-product for brand consistency. - Fixed Amounts: Set a specific price that users cannot change. - Reusable: One link can accept unlimited payments. - Active/Inactive: Toggle links on/off from the dashboard. - Auto QR Codes: Every payment link automatically generates a downloadable QR code. Creating Payment Links via Dashboard (No Code): 1. Log into the BaseUPI Dashboard. 2. Navigate to the Payment Links tab. 3. Click Create New Link. 4. Enter the Title, Description, and Price. 5. Customize the URL slug (optional). 6. Save and share the generated URL. --- ## 4.3 Webhooks BaseUPI sends webhooks to notify the merchant's backend when a payment event occurs. ### Configuration Set the Webhook URL and Webhook Secret in the Dashboard Settings. ### Signature Verification BaseUPI signs all webhook payloads using HMAC-SHA256. To verify: 1. Extract the X-BaseUPI-Signature header from the request. 2. Generate an HMAC-SHA256 hash using the Webhook Secret and the raw text request body. 3. Compare the signatures. If they match, the webhook is authentic. ### Webhook Event: payment.completed Sent when a payment is successfully matched to an order. Payload (JSON): { "event": "payment.completed", "order_id": "ord_K9EFTDQV", "merchant_order_id": "ord_12345", "amount_paise": 49900, "status": "COMPLETED", "reference_number": "330012345678", "paid_at": "2026-03-18T10:05:00.000Z", "metadata": { "plan_id": "gold" } } ### Webhook Event: payment.failed Sent when an order expires or is explicitly failed. Payload (JSON): { "event": "payment.failed", "order_id": "ord_K9EFTDQV", "reason": "Payment timeout" } ### Webhook Retry Policy - If the merchant endpoint does not respond with 2xx within 15 seconds, BaseUPI retries. - Up to 10 retry attempts with exponential backoff over 72 hours. --- ## 4.4 Internal Endpoints The Android Companion App communicates with BaseUPI through authenticated internal endpoints. These are not part of the public API and are not intended for direct use by merchants. --- ## 4.5 API Rate Limits - 60 requests/minute for order creation (POST /orders) - 60 requests/minute for SMS ingest (POST /sms/hooks) - 20 requests/minute for webhook endpoints - All API requests must use HTTPS. Plain HTTP is rejected. - Idempotency keys should be used for order creation to prevent duplicates. --- # 5. SDK DOCUMENTATION ## 5.1 Node.js SDK (baseupi) Install: npm install baseupi ### Initialization import BaseUPI from 'baseupi'; const baseupi = new BaseUPI('zp_live_public_YOUR_KEY', { secretKey: 'zp_live_secret_YOUR_KEY' // Or set BASEUPI_SECRET_KEY environment variable }); ### Create an Order const order = await baseupi.orders.create({ merchant_order_id: 'sub_12345', amount_paise: 99900, // ₹999.00 customer_email: 'customer@example.com', redirect_url: 'https://mysaas.com/thank-you', line_items: [ { name: 'Pro Monthly Plan', amount_paise: 99900, quantity: 1 } ], metadata: { userId: 'user_99' } }); console.log(order.checkout_url); // Redirect user to order.checkout_url or use order.order_id with the widget ### Check Order Status const status = await baseupi.orders.get('ord_K9EFTDQV'); console.log(status.status); // "PAID" | "CREATED" | "FAILED" ### Verify Webhook (Express.js Example) app.post('/webhooks/baseupi', express.text({ type: '*/*' }), (req, res) => { try { const event = baseupi.webhooks.constructEvent( req.body, req.headers['x-baseupi-signature'], process.env.BASEUPI_WEBHOOK_SECRET ); if (event.event === 'payment.completed') { const { merchant_order_id, metadata } = event; // Fulfill your order: upgrade plan, grant access, etc. console.log(`Order ${merchant_order_id} fulfilled.`); } res.json({ received: true }); } catch (err) { res.status(400).send(`Webhook Error: ${err.message}`); } }); --- ## 5.2 React SDK (baseupi-react) Install: npm install baseupi-react ### Basic Usage import { BaseUPICheckout } from 'baseupi-react'; import 'baseupi-react/styles.css'; function CheckoutButton({ orderId }) { return ( alert("Payment confirmed!")} onClose={() => console.log("User closed checkout")} > ); } Props: - orderId (string, required): The order ID from baseupi.orders.create() - onSuccess (function): Called when payment is confirmed - onClose (function): Called when user closes the checkout modal - onError (function): Called on error - children (ReactNode): The trigger element (usually a button) --- ## 5.3 Vanilla JavaScript Widget No framework needed. Load the widget script and call BaseUPI.checkout(). Script Tag: ### Modal Mode (Default) document.getElementById('pay-btn').addEventListener('click', function() { BaseUPI.checkout({ orderId: "ord_K9EFTDQV", onSuccess: function(order) { console.log("Payment successful!", order); window.location.href = "/thank-you"; }, onClose: function() { console.log("Widget closed by user"); }, onError: function(error) { console.error("Payment error:", error); } }); }); ### Inline Mode (Embedded) To embed the checkout form directly on the page instead of a popup:
### Widget Security - The widget loads the checkout page securely over HTTPS. - Parent window communicates via secure postMessage protocol. - Only initialize the widget over HTTPS in production. --- # 6. COMPLETE SAAS INTEGRATION WALKTHROUGH For SaaS applications that need end-to-end payment integration: ## Step 1: Backend — Create Order When a user clicks "Buy" or "Subscribe", your server creates an order. NEVER do this from the browser. import BaseUPI from 'baseupi'; const baseupi = new BaseUPI('zp_live_public_...', { secretKey: 'zp_live_secret_...' }); const order = await baseupi.orders.create({ merchant_order_id: "ORD-001", amount_paise: 49900, line_items: [{ name: "Pro Plan", amount_paise: 49900, quantity: 1 }] }); // Pass order.order_id to your frontend ## Step 2: Frontend — Show Widget Once the frontend receives the order_id, render the checkout: router.push('/dashboard')}> ## Step 3: Backend — Handle Webhook The user pays via their UPI app → payment is verified automatically → BaseUPI fires a signed webhook to your server. app.post('/webhooks/baseupi', express.text({ type: '*/*' }), (req, res) => { const event = baseupi.webhooks.constructEvent( req.body, req.headers['x-baseupi-signature'], process.env.BASEUPI_WEBHOOK_SECRET ); if (event.event === 'payment.completed') { // Upgrade user, grant access, send confirmation email, etc. } res.json({ received: true }); }); ## Step 4: Test Use the Simulator in the Dashboard (Test Mode) to simulate the complete flow: Create Order → Widget Rendering → SMS Detection → Webhook Delivery. --- # 7. CORE CONCEPTS & GLOSSARY - VPA (Virtual Payment Address): The merchant's UPI ID (e.g., merchant@okicici). This is the destination for all payments. - Companion App: The Android application that runs on the merchant's phone, listens for bank SMS, and forwards transaction data to BaseUPI. - Amount Paise: All monetary amounts are represented in paise (1/100 of a Rupee). Example: 10000 paise = ₹100.00. - Smart Matching: BaseUPI uses a proprietary system to accurately match incoming payments to the correct pending orders. - Webhook: An HTTP POST request sent by BaseUPI to the merchant's server when a payment event occurs. - HMAC-SHA256: The cryptographic algorithm used to sign webhook payloads for verification. - Idempotency Key: A unique identifier sent with order creation requests to prevent duplicate orders. - UTR (Unique Transaction Reference): A bank-generated reference number for each UPI transaction. - Checkout URL: A hosted page where customers can scan a QR code or tap a UPI deeplink to pay. - UPI Deeplink: A `upi://pay?` URL that directly opens the customer's UPI app with pre-filled payment details. - Order Time Window: The period during which an order remains active waiting for payment (configurable via ORDER_TIME_WINDOW_MINUTES environment variable). --- # 8. DEPLOYMENT BaseUPI is self-hosted. You deploy your own instance with your own database. Required configuration (Supabase credentials and API keys) is set via environment variables during deployment. See the README in the repository for setup instructions. --- # 9. SECURITY MODEL - HMAC-SHA256 Signatures: All webhook payloads are signed. Merchants must verify signatures before processing. - Idempotency Keys: Prevents duplicate order creation from retried API calls. - API Key Authentication: Dual-key system — Public Key identifies the merchant, Secret Key authorizes privileged operations. - SMS Privacy: The Companion App reads ONLY transactional SMS from recognized bank sender IDs. Personal, promotional, or non-banking messages are NEVER read, processed, or transmitted. - Data Sovereignty: All data is stored in the merchant's own Supabase instance. BaseUPI developers have zero access. - HTTPS Only: All API endpoints reject plain HTTP requests. --- # 10. LEGAL FRAMEWORK SUMMARY ## Nature of Service BaseUPI is a software automation toolkit, NOT a payment gateway or aggregator. It does not hold, process, or transfer funds. No RBI PA license is required. ## Merchant Obligations - Must be 18+ and operate a legitimate business. - Must comply with: Payment and Settlement Systems Act (2007), IT Act (2000), DPDP Act (2023), RBI guidelines, NPCI UPI procedural guidelines. - Responsible for all tax filings (GST, Income Tax, TDS). - Responsible for security of their own hosted instance. ## Prohibited Activities Gambling, adult content, MLM/pyramid schemes, narcotics, weapons, counterfeit goods, unauthorized crypto exchanges, money laundering, terrorist financing. Using BaseUPI API as a resold "Payment-Gateway-as-a-Service" without an RBI PA license is prohibited. ## Privacy (DPDP Act 2023 Compliant) - Merchant is the "Data Fiduciary" (controller). - All data stored in merchant's own Supabase instance. - No data transmitted to BaseUPI servers or third-party analytics. - SMS data: Only bank transactional SMS read. Personal messages never accessed. - Customers (Data Principals) can request data erasure under DPDP Act. ## Liability - Platform provided "AS IS" without warranties. - Aggregate liability capped at ₹0 (free, open-source software). - Merchant assumes all risk related to bank account restrictions, SMS delays, etc. - Merchant must indemnify BaseUPI developers against all claims. ## Refund Policy BaseUPI cannot process refunds (no custody of funds). All refunds are the merchant's responsibility. Customer disputes follow NPCI's dispute resolution framework. ## Governing Law Indian law applies. Disputes resolved via arbitration under Arbitration and Conciliation Act, 1996. Courts of New Delhi have exclusive jurisdiction. --- # 11. COMMON USE CASES 1. E-commerce Checkout: Integrate the React SDK or Vanilla Widget into a shopping cart. Create orders on the backend, render checkout on frontend, handle fulfillment via webhooks. 2. SaaS Subscription Payments: Create orders when users click "Upgrade". Use webhooks to activate premium features immediately upon payment confirmation. 3. Freelancer "Pay Me" Links: Create Payment Links via the dashboard. Share the URL on social media, email, or invoices. No code required. 4. Digital Product Sales: Create Payment Links with fixed amounts. Each link can accept unlimited payments. 5. Event Ticketing: Create orders programmatically via the API for each ticket purchase. Use metadata to store seat numbers, event IDs, etc. 6. Donation Pages: Use Payment Links or the checkout widget with customizable amounts. --- # 12. BEST PRACTICES 1. Always create orders server-side. Never expose the Secret Key to the browser. 2. Use the official SDKs for automatic webhook signature verification. 3. Ensure the Companion App has "Unrestricted" battery usage on Android. 4. Implement a manual verification fallback for mission-critical transactions. 5. Use idempotency keys for all order creation requests. 6. Store webhook payloads and verify before fulfilling — never trust the frontend `onSuccess` callback alone. 7. Host your Supabase instance in India for RBI data localization compliance. 8. Regularly check that the Companion App is connected (status visible in Dashboard). 9. Configure webhook retry policy expectations — your endpoint must respond with 2xx within 15 seconds. 10. Keep the Android phone charged, connected to WiFi/data, and the BaseUPI app running. --- # 13. TROUBLESHOOTING ## Payment not detected - Check if the Android Companion App is running and connected (Dashboard > Devices). - Verify SMS permissions are granted. - Check if battery optimization is set to "Unrestricted". - Verify the phone has internet connectivity. - Check if the bank SMS was actually received (some banks delay SMS). ## Webhook not received - Verify the Webhook URL is correctly configured in Dashboard Settings. - Ensure your endpoint is publicly accessible (not localhost). - Check if your server responded with 2xx within 15 seconds. - Check webhook delivery logs in the Dashboard. ## Order stuck in CREATED status - The payment may not have been detected yet. Check Companion App connectivity. - The order may have expired. Orders have a configurable time window. ## Duplicate orders - Use idempotency keys when calling POST /orders. - Check if your frontend is calling the create order endpoint multiple times. --- END OF DOCUMENT This document was auto-generated by BaseUPI. Last updated: March 2026.