Skip to main content

Documentation Index

Fetch the complete documentation index at: https://docs.txncheck.com/llms.txt

Use this file to discover all available pages before exploring further.

Python Integration

This guide shows how to integrate TxnCheck API into your Python application.

Installation

Install the required dependencies:
pip install requests
For async support:
pip install httpx

Basic Client Setup

Create a reusable client class for all API interactions:
import requests
import hashlib
import hmac
import time
from typing import Optional, Dict, Any, List
from dataclasses import dataclass
from enum import Enum

class RequestStatus(Enum):
    QUEUED = "QUEUED"
    PROCESSING = "PROCESSING"
    COMPLETED = "COMPLETED"
    FAILED = "FAILED"
    PARTIAL = "PARTIAL"

@dataclass
class TxnCheckConfig:
    api_key: str
    base_url: str = "https://api.txncheck.in/api/v1"
    secret_key: Optional[str] = None  # For request signing
    timeout: int = 30

class TxnCheckClient:
    """TxnCheck API Client for Python"""
    
    def __init__(self, config: TxnCheckConfig):
        self.config = config
        self.session = requests.Session()
        self.session.headers.update({
            "X-API-Key": config.api_key,
            "Content-Type": "application/json"
        })
    
    def _sign_request(self, method: str, path: str, body: str) -> Dict[str, str]:
        """Generate HMAC-SHA256 signature for request"""
        if not self.config.secret_key:
            return {}
        
        timestamp = str(int(time.time() * 1000))
        message = f"{timestamp}.{method}.{path}.{body}"
        signature = hmac.new(
            self.config.secret_key.encode(),
            message.encode(),
            hashlib.sha256
        ).hexdigest()
        
        return {
            "X-Timestamp": timestamp,
            "X-Signature": signature
        }
    
    def _request(
        self, 
        method: str, 
        endpoint: str, 
        data: Optional[Dict] = None,
        sync_mode: bool = False
    ) -> Dict[str, Any]:
        """Make API request with optional signing"""
        import json
        
        url = f"{self.config.base_url}{endpoint}"
        body = json.dumps(data) if data else ""
        
        # Add async flag
        if data and sync_mode:
            data["async"] = False
        
        # Sign request if secret key is configured
        headers = self._sign_request(method.upper(), endpoint, body)
        
        response = self.session.request(
            method=method,
            url=url,
            json=data,
            headers=headers,
            timeout=self.config.timeout
        )
        
        response.raise_for_status()
        return response.json()
    
    # ==================
    # Verification Methods
    # ==================
    
    def upi_by_mobile(
        self, 
        mobile: str, 
        sync: bool = False
    ) -> Dict[str, Any]:
        """
        Get UPI VPAs linked to a mobile number.
        
        Args:
            mobile: Mobile number in +91XXXXXXXXXX format
            sync: If True, wait for result (up to 30s)
        
        Returns:
            Request ID and status (async) or full result (sync)
        """
        return self._request(
            "POST", 
            "/upi-by-mobile", 
            {"mobile": mobile},
            sync_mode=sync
        )
    
    def kyc_by_mobile(
        self, 
        mobile: str, 
        sync: bool = False
    ) -> Dict[str, Any]:
        """
        Get KYC data by mobile number.
        
        Args:
            mobile: Mobile number in +91XXXXXXXXXX format
            sync: If True, wait for result (up to 30s)
        
        Returns:
            Request ID and status (async) or full result (sync)
        """
        return self._request(
            "POST", 
            "/kyc-by-mobile", 
            {"mobile": mobile},
            sync_mode=sync
        )
    
    def vpa_chargeback_check(
        self, 
        vpas: List[str], 
        sync: bool = False
    ) -> Dict[str, Any]:
        """
        Check VPAs against blocklist.
        
        Args:
            vpas: List of VPA addresses (max 100)
            sync: If True, wait for result (up to 30s)
        
        Returns:
            Request ID and status (async) or full result (sync)
        """
        return self._request(
            "POST", 
            "/vpa-chargeback-check", 
            {"vpas": vpas},
            sync_mode=sync
        )
    
    def full_check(
        self, 
        mobile: str, 
        sync: bool = False
    ) -> Dict[str, Any]:
        """
        Full verification: UPI + KYC + Chargeback check.
        
        Args:
            mobile: Mobile number in +91XXXXXXXXXX format
            sync: If True, wait for result (up to 30s)
        
        Returns:
            Request ID and status (async) or full result (sync)
        """
        return self._request(
            "POST", 
            "/full-check", 
            {"mobile": mobile},
            sync_mode=sync
        )
    
    def bulk_vpa_check(
        self, 
        vpas: List[str], 
        sync: bool = False
    ) -> Dict[str, Any]:
        """
        Bulk check VPAs against blocklist.
        
        Args:
            vpas: List of VPA addresses (1-100)
            sync: If True, wait for result (up to 30s)
        
        Returns:
            Request ID and status (async) or full result (sync)
        """
        return self._request(
            "POST", 
            "/bulk/vpa-chargeback-check", 
            {"vpas": vpas},
            sync_mode=sync
        )
    
    def get_request_status(self, request_id: str) -> Dict[str, Any]:
        """
        Get status and results of a request.
        
        Args:
            request_id: UUID of the request
        
        Returns:
            Request status and result data
        """
        return self._request("GET", f"/requests/{request_id}")
    
    def wait_for_result(
        self, 
        request_id: str, 
        poll_interval: float = 2.0,
        max_wait: float = 60.0
    ) -> Dict[str, Any]:
        """
        Poll for request completion.
        
        Args:
            request_id: UUID of the request
            poll_interval: Seconds between polls
            max_wait: Maximum seconds to wait
        
        Returns:
            Completed request data
        
        Raises:
            TimeoutError: If max_wait exceeded
        """
        terminal_statuses = {
            RequestStatus.COMPLETED.value,
            RequestStatus.FAILED.value,
            RequestStatus.PARTIAL.value
        }
        
        start_time = time.time()
        while time.time() - start_time < max_wait:
            result = self.get_request_status(request_id)
            if result.get("status") in terminal_statuses:
                return result
            time.sleep(poll_interval)
        
        raise TimeoutError(f"Request {request_id} did not complete within {max_wait}s")

Usage Examples

Async Mode (Default)

from txncheck import TxnCheckClient, TxnCheckConfig

# Initialize client
config = TxnCheckConfig(api_key="fb_your_api_key_here")
client = TxnCheckClient(config)

# Submit request
response = client.upi_by_mobile("+919876543210")
print(f"Request ID: {response['requestId']}")
# Output: Request ID: 550e8400-e29b-41d4-a716-446655440000

# Poll for result
result = client.wait_for_result(response['requestId'])
print(f"Status: {result['status']}")
print(f"UPI addresses: {result['result']['upi']}")

Sync Mode

# Get result immediately (waits up to 30 seconds)
result = client.upi_by_mobile("+919876543210", sync=True)
print(f"Status: {result['status']}")
print(f"Name: {result['result']['name']}")
print(f"UPI addresses: {result['result']['upi']}")

Full Check

# Comprehensive verification
result = client.full_check("+919876543210", sync=True)

if result['status'] == 'COMPLETED':
    # UPI data
    upi_data = result['result']['upiByMobile']
    print(f"Name: {upi_data['name']}")
    print(f"VPAs: {upi_data['upi']}")
    
    # KYC data
    kyc_data = result['result']['kycByMobile']
    print(f"PAN: {kyc_data['pan']}")
    print(f"DOB: {kyc_data['dob']}")
    
    # Blocklist status
    blocklist = result['result']['vpaChargebackCheck']
    print(f"Blocklisted VPAs: {len(blocklist['blocklisted'])}")

VPA Blocklist Check

# Check multiple VPAs
vpas = ["user1@upi", "user2@paytm", "suspicious@ybl"]
result = client.vpa_chargeback_check(vpas, sync=True)

for vpa in result['result']['blocklisted']:
    print(f"⚠️ BLOCKED: {vpa['vpa']}")

for vpa in result['result']['clean']:
    print(f"✓ Clean: {vpa['vpa']}")

Error Handling

import requests

class TxnCheckError(Exception):
    """Base exception for TxnCheck errors"""
    def __init__(self, status_code: int, message: str, error: str):
        self.status_code = status_code
        self.message = message
        self.error = error
        super().__init__(f"{status_code} {error}: {message}")

def handle_api_error(response: requests.Response):
    """Convert HTTP errors to TxnCheckError"""
    try:
        data = response.json()
        raise TxnCheckError(
            status_code=response.status_code,
            message=data.get('message', 'Unknown error'),
            error=data.get('error', 'Error')
        )
    except ValueError:
        raise TxnCheckError(
            status_code=response.status_code,
            message=response.text,
            error='Unknown Error'
        )

# Usage with retry logic
from tenacity import retry, stop_after_attempt, wait_exponential, retry_if_exception_type

@retry(
    stop=stop_after_attempt(3),
    wait=wait_exponential(multiplier=1, min=2, max=10),
    retry=retry_if_exception_type(requests.exceptions.RequestException)
)
def verify_with_retry(client: TxnCheckClient, mobile: str):
    try:
        return client.upi_by_mobile(mobile, sync=True)
    except requests.exceptions.HTTPError as e:
        if e.response.status_code == 429:  # Rate limited
            raise  # Will retry
        if e.response.status_code >= 500:  # Server error
            raise  # Will retry
        handle_api_error(e.response)  # Client error - don't retry

Webhook Signature Verification

import hmac
import hashlib

def verify_webhook_signature(
    payload: bytes,
    signature: str,
    timestamp: str,
    secret_key: str,
    max_age_seconds: int = 300
) -> bool:
    """
    Verify webhook signature from TxnCheck.
    
    Args:
        payload: Raw request body bytes
        signature: X-Webhook-Signature header value
        timestamp: X-Webhook-Timestamp header value
        secret_key: Your webhook secret key
        max_age_seconds: Maximum age of webhook to accept
    
    Returns:
        True if signature is valid
    """
    import time
    
    # Check timestamp freshness
    webhook_time = int(timestamp)
    current_time = int(time.time() * 1000)
    age_ms = current_time - webhook_time
    
    if age_ms > max_age_seconds * 1000:
        return False  # Webhook too old
    
    # Compute expected signature
    message = f"{timestamp}.{payload.decode('utf-8')}"
    expected = hmac.new(
        secret_key.encode(),
        message.encode(),
        hashlib.sha256
    ).hexdigest()
    
    # Constant-time comparison
    return hmac.compare_digest(signature, expected)

# Flask example
from flask import Flask, request, jsonify

app = Flask(__name__)
WEBHOOK_SECRET = "your_webhook_secret"

@app.route('/webhook/fraud-buster', methods=['POST'])
def handle_webhook():
    signature = request.headers.get('X-Webhook-Signature')
    timestamp = request.headers.get('X-Webhook-Timestamp')
    
    if not verify_webhook_signature(
        request.data, signature, timestamp, WEBHOOK_SECRET
    ):
        return jsonify({"error": "Invalid signature"}), 401
    
    data = request.json
    event = data['event']
    
    if event == 'request.completed':
        handle_completed(data['data'])
    elif event == 'request.failed':
        handle_failed(data['data'])
    
    return jsonify({"status": "ok"}), 200

Async Client (httpx)

For high-performance async applications:
import httpx
import asyncio
from typing import Optional, Dict, Any, List

class AsyncTxnCheckClient:
    """Async TxnCheck API Client using httpx"""
    
    def __init__(self, config: TxnCheckConfig):
        self.config = config
        self.client = httpx.AsyncClient(
            base_url=config.base_url,
            headers={
                "X-API-Key": config.api_key,
                "Content-Type": "application/json"
            },
            timeout=config.timeout
        )
    
    async def __aenter__(self):
        return self
    
    async def __aexit__(self, *args):
        await self.client.aclose()
    
    async def upi_by_mobile(
        self, 
        mobile: str, 
        sync: bool = False
    ) -> Dict[str, Any]:
        data = {"mobile": mobile}
        if sync:
            data["async"] = False
        
        response = await self.client.post("/upi-by-mobile", json=data)
        response.raise_for_status()
        return response.json()
    
    async def verify_multiple(
        self, 
        mobiles: List[str]
    ) -> List[Dict[str, Any]]:
        """Verify multiple mobile numbers concurrently"""
        tasks = [self.upi_by_mobile(m, sync=True) for m in mobiles]
        return await asyncio.gather(*tasks, return_exceptions=True)

# Usage
async def main():
    config = TxnCheckConfig(api_key="fb_your_api_key_here")
    
    async with AsyncTxnCheckClient(config) as client:
        # Single request
        result = await client.upi_by_mobile("+919876543210", sync=True)
        print(result)
        
        # Concurrent requests
        mobiles = ["+919876543210", "+919876543211", "+919876543212"]
        results = await client.verify_multiple(mobiles)
        for r in results:
            if isinstance(r, Exception):
                print(f"Error: {r}")
            else:
                print(f"Verified: {r['result']['name']}")

asyncio.run(main())

Complete Integration Example

"""
Complete example: E-commerce checkout verification
"""
from txncheck import TxnCheckClient, TxnCheckConfig
import logging

logging.basicConfig(level=logging.INFO)
logger = logging.getLogger(__name__)

def verify_customer_for_checkout(
    client: TxnCheckClient,
    mobile: str,
    payment_vpa: str
) -> dict:
    """
    Verify customer before processing payment.
    
    Returns:
        dict with verification results and risk score
    """
    result = {
        "verified": False,
        "risk_score": 0,
        "details": {}
    }
    
    try:
        # Step 1: Full verification
        logger.info(f"Starting verification for {mobile}")
        verification = client.full_check(mobile, sync=True)
        
        if verification['status'] != 'COMPLETED':
            logger.warning(f"Verification incomplete: {verification['status']}")
            result["risk_score"] = 100
            return result
        
        # Step 2: Extract data
        upi_data = verification['result'].get('upiByMobile', {})
        kyc_data = verification['result'].get('kycByMobile', {})
        blocklist = verification['result'].get('vpaChargebackCheck', {})
        
        # Step 3: Check if payment VPA belongs to user
        user_vpas = upi_data.get('upi', [])
        vpa_belongs_to_user = payment_vpa.lower() in [v.lower() for v in user_vpas]
        
        if not vpa_belongs_to_user:
            logger.warning(f"Payment VPA {payment_vpa} not linked to {mobile}")
            result["risk_score"] += 50
        
        # Step 4: Check blocklist
        blocklisted_vpas = [v['vpa'] for v in blocklist.get('blocklisted', [])]
        if payment_vpa.lower() in [v.lower() for v in blocklisted_vpas]:
            logger.error(f"Payment VPA {payment_vpa} is BLOCKLISTED!")
            result["risk_score"] = 100
            result["details"]["blocklisted"] = True
            return result
        
        # Step 5: Build result
        result["verified"] = result["risk_score"] < 50
        result["details"] = {
            "name": kyc_data.get('fullName', upi_data.get('name')),
            "pan_verified": bool(kyc_data.get('pan')),
            "vpa_linked": vpa_belongs_to_user,
            "vpa_count": len(user_vpas),
            "blocklisted": False
        }
        
        logger.info(f"Verification complete. Risk score: {result['risk_score']}")
        return result
        
    except Exception as e:
        logger.error(f"Verification failed: {e}")
        result["risk_score"] = 100
        result["error"] = str(e)
        return result

# Usage
if __name__ == "__main__":
    config = TxnCheckConfig(api_key="fb_your_api_key_here")
    client = TxnCheckClient(config)
    
    verification = verify_customer_for_checkout(
        client,
        mobile="+919876543210",
        payment_vpa="user@upi"
    )
    
    if verification["verified"]:
        print("✓ Customer verified, proceed with payment")
    else:
        print(f"⚠️ Verification failed. Risk score: {verification['risk_score']}")

Next Steps

Webhooks Guide

Set up webhooks for async notifications

Error Handling

Handle API errors properly

Security Best Practices

Secure your integration

Use Cases

See real-world examples