Kundali Software API Integration Tutorial
COMPATIBILITY MATCHING

How to Integrate Kundali Matching in Your App via API

Complete developer guide to implementing marriage compatibility features with Ashtakoot gun milan, Mangal dosha detection, and AI-powered match recommendations.

December 23, 2025 • 16 min read

Why Kundali Matching is a Must-Have Feature

Kundali matching (gun milan) is the #1 feature request for astrology and matrimonial apps in India and among the Indian diaspora. With 85% of Indian marriages still being arranged or semi-arranged, compatibility matching drives user engagement and premium conversions. Apps with kundali matching see 3.5x higher retention rates.

Market Opportunity

  • $4.5B - Indian matrimonial market size (2025)
  • 92% of matrimonial app users check kundali compatibility
  • 65% willing to pay $5-20 for detailed compatibility reports
  • 4.2x higher conversion on apps with automated matching

Understanding Ashtakoot System

The Ashtakoot (8 kutas) system evaluates compatibility across 8 dimensions based on Moon's nakshatra position in both birth charts. Here's the complete breakdown:

1. Varna Kuta

1 point

Spiritual compatibility and ego levels

Brahmin > Kshatriya > Vaishya > Shudra

2. Vashya Kuta

2 points

Mutual attraction and control

Human, Quadruped, Water, Insect, Wild

3. Tara Kuta

3 points

Birth star compatibility and health

Count from bride's nakshatra to groom's

4. Yoni Kuta

4 points

Sexual compatibility and intimacy

14 animal categories, natural enemies = 0

5. Graha Maitri

5 points

Mental compatibility and friendship

Based on Moon sign lord relationships

6. Gana Kuta

6 points

Temperament and behavior matching

Deva (divine), Manushya (human), Rakshasa (demon)

7. Bhakoot Kuta

7 points

Love and financial prosperity

6-8 or 2-12 moon sign distance = 0 points

8. Nadi Kuta

8 points

Health and progeny compatibility

Most important - same Nadi = 0 points

Score Interpretation

0-17 points:
❌ Not recommended - significant incompatibility
18-24 points:
⚠️ Average - acceptable with remedies
25-32 points:
✓ Good - compatible match
33-36 points:
✓✓ Excellent - highly compatible

API Integration - Basic Implementation

Let's implement kundali matching step by step. We'll use Vedika API which handles all complex calculations and dosha detection.

Step 1: Initialize API Client

import requests
from typing import Dict

class KundaliMatchingAPI:
    def __init__(self, api_key: str):
        self.api_key = api_key
        self.base_url = "https://api.vedika.io"
        self.headers = {
            "Authorization": f"Bearer {api_key}",
            "Content-Type": "application/json"
        }

    def match_kundali(self, groom: Dict, bride: Dict) -> Dict:
        """Perform kundali (Ashtakoot Guna Milan) matching.

        groom and bride are birth details:
        {"datetime": ..., "latitude": ..., "longitude": ..., "timezone": ...}
        """
        response = requests.post(
            f"{self.base_url}/v2/astrology/guna-milan",
            headers=self.headers,
            json={"male": groom, "female": bride}
        )
        response.raise_for_status()
        return response.json()["data"]

    def mangal_dosha(self, birth: Dict) -> Dict:
        """Mangal (Manglik) dosha check for one person"""
        response = requests.post(
            f"{self.base_url}/v2/astrology/mangal-dosha",
            headers=self.headers,
            json=birth
        )
        response.raise_for_status()
        return response.json()["data"]

# Initialize
api = KundaliMatchingAPI("your_api_key_here")

Step 2: Collect Birth Details for Both Partners

# Bride's birth details (geocode the birth place to latitude/longitude in your app)
bride = {
    "datetime": "1995-03-15T08:30:00",
    "latitude": 19.0760,      # Mumbai
    "longitude": 72.8777,
    "timezone": "+05:30"
}

# Groom's birth details
groom = {
    "datetime": "1992-07-22T14:45:00",
    "latitude": 28.6139,      # Delhi
    "longitude": 77.2090,
    "timezone": "+05:30"
}

Step 3: Perform Matching

# Match kundalis
match_result = api.match_kundali(groom=groom, bride=bride)

# Display results
print(f"\n{'='*50}")
print(f"Compatibility Score: {match_result['total_points']}/{match_result['maximum_points']}")
print(f"Compatibility: {match_result['match_result']}")
print(f"{'='*50}\n")

# Individual koota scores
for koota in match_result['guna_kootas']:
    status = "✓" if koota['points'] == koota['maximum_points'] else "○"
    print(f"{status} {koota['name']:15} {koota['points']}/{koota['maximum_points']}")

# Nadi dosha: both partners in the same Nadi score 0 of 8 on the Nadi koota
nadi = match_result['gunaDetails']['nadi']
print(f"\nNadi: {nadi['score']}/{nadi['maxPoints']}")
print(f"Nadi Dosha: {'present' if nadi['score'] == 0 else 'not present'}")

API Response Structure

A trimmed example response from POST /v2/astrology/guna-milan (the full data object also carries per-koota descriptions and tips; the Python class above returns just data):

{
  "success": true,
  "data": {
    "total_points": 29.0,
    "maximum_points": 36,
    "percentage": 81,
    "match_result": "Compatible",
    "recommendation": "Very good match - Strong compatibility",
    "guna_kootas": [
      {
        "name": "Varna",
        "points": 0.0,
        "maximum_points": 1,
        "male_koot": "Vaishya",
        "female_koot": "Kshatriya"
      },
      {
        "name": "Vasya",
        "points": 2.0,
        "maximum_points": 2,
        "male_koot": "Capricorn",
        "female_koot": "Aries"
      },
      {
        "name": "Tara",
        "points": 3.0,
        "maximum_points": 3,
        "male_koot": "Atimitra",
        "female_koot": "Sampat"
      },
      {
        "name": "Yoni",
        "points": 2.0,
        "maximum_points": 4,
        "male_koot": "Mongoose",
        "female_koot": "Elephant"
      },
      {
        "name": "Graha Maitri",
        "points": 1.0,
        "maximum_points": 5,
        "male_koot": "Saturn",
        "female_koot": "Mars"
      },
      {
        "name": "Gana",
        "points": 6.0,
        "maximum_points": 6,
        "male_koot": "Manav",
        "female_koot": "Manav"
      },
      {
        "name": "Bhakoot",
        "points": 7.0,
        "maximum_points": 7,
        "male_koot": "Capricorn",
        "female_koot": "Aries"
      },
      {
        "name": "Nadi",
        "points": 8.0,
        "maximum_points": 8,
        "male_koot": "Antya",
        "female_koot": "Madhya"
      }
    ],
    "gunaDetails": {
      "nadi": {
        "name": "Nadi (Health & Genetic Compatibility)",
        "score": 8.0,
        "maxPoints": 8,
        "interpretation": "Different Nadis - excellent health compatibility and genetic diversity."
      }
    },
    "interpretation": {
      "summary": "A very good match with strong overall compatibility.",
      "strengths": [
        "Good mutual attraction and influence",
        "Favorable birth star harmony"
      ],
      "challenges": [
        "Different spiritual temperaments"
      ]
    },
    "male_info": {
      "moon_nakshatra": "Uttara Ashadha",
      "moon_sign": "Capricorn"
    },
    "female_info": {
      "moon_nakshatra": "Bharani",
      "moon_sign": "Aries"
    }
  },
  "billing": {
    "charged": 0.05,
    "currency": "USD"
  }
}

Advanced: Mangal Dosha Detection

Mangal dosha (Kuja dosha) is critical for marriage matching. Here's how to detect and analyze it:

# One call per partner (reuses the api client from Step 1)
bride_dosha = api.mangal_dosha(bride)
groom_dosha = api.mangal_dosha(groom)

# Dosha matching logic
def is_mangal_dosha_compatible(dosha1, dosha2):
    """Check if Mangal doshas cancel out"""

    # Both have dosha - cancels out
    if dosha1['has_dosha'] and dosha2['has_dosha']:
        return True, "Both partners have Mangal dosha - cancels out"

    # Neither has dosha
    if not dosha1['has_dosha'] and not dosha2['has_dosha']:
        return True, "No Mangal dosha in either chart"

    # One has dosha
    dosha = dosha1 if dosha1['has_dosha'] else dosha2

    # Cancellation rules already applied by the API
    if dosha['is_cancelled']:
        return True, "Dosha cancelled by an exception rule"

    if dosha['severity'] == 'Mild':
        return True, "Mild dosha - acceptable"

    return False, "Unmatched Mangal dosha - requires remedies"

compatible, reason = is_mangal_dosha_compatible(bride_dosha, groom_dosha)
print(f"Mangal Dosha Compatible: {compatible}")
print(f"Reason: {reason}")

Building a Complete Matching Feature

Frontend Implementation (React)

import React, { useState } from 'react';
import axios from 'axios';

function KundaliMatchingForm() {
  // Each holds birth details: { datetime, latitude, longitude, timezone }
  const [bride, setBride] = useState({});
  const [groom, setGroom] = useState({});
  const [result, setResult] = useState(null);
  const [loading, setLoading] = useState(false);

  const handleMatch = async () => {
    setLoading(true);

    try {
      // Your own backend route calls POST https://api.vedika.io/v2/astrology/guna-milan
      // with { male: groom, female: bride } and returns the "data" object,
      // so the API key never reaches the browser.
      const matchResult = await axios.post('/api/kundali/match', { groom, bride });

      setResult(matchResult.data);
    } catch (error) {
      console.error('Matching failed:', error);
    } finally {
      setLoading(false);
    }
  };

  return (
    <div className="max-w-4xl mx-auto p-6">
      <h2 className="text-3xl font-bold mb-8">Kundali Matching</h2>

      <div className="grid md:grid-cols-2 gap-8 mb-8">
        {/* Bride Details */}
        <div className="bg-white rounded-lg shadow p-6">
          <h3 className="text-xl font-bold mb-4 text-pink-600">Bride Details</h3>
          <BirthDetailsForm
            data={bride}
            onChange={setBride}
          />
        </div>

        {/* Groom Details */}
        <div className="bg-white rounded-lg shadow p-6">
          <h3 className="text-xl font-bold mb-4 text-blue-600">Groom Details</h3>
          <BirthDetailsForm
            data={groom}
            onChange={setGroom}
          />
        </div>
      </div>

      <button
        onClick={handleMatch}
        disabled={loading}
        className="w-full bg-purple-600 text-white py-3 rounded-lg font-bold"
      >
        {loading ? 'Matching...' : 'Match Kundalis'}
      </button>

      {result && <MatchingResults result={result} />}
    </div>
  );
}

function MatchingResults({ result }) {
  const getScoreColor = (score) => {
    if (score >= 33) return 'text-green-600';
    if (score >= 25) return 'text-blue-600';
    if (score >= 18) return 'text-orange-600';
    return 'text-red-600';
  };

  return (
    <div className="mt-8 space-y-6">
      {/* Overall Score */}
      <div className="bg-gradient-to-r from-purple-100 to-pink-100 rounded-xl p-8 text-center">
        <div className={`text-6xl font-bold mb-2 ${getScoreColor(result.total_points)}`}>
          {result.total_points}/{result.maximum_points}
        </div>
        <div className="text-xl font-semibold">{result.match_result}</div>
        <div className="text-gray-700 mt-2">{result.recommendation}</div>
      </div>

      {/* Kuta Breakdown */}
      <div className="bg-white rounded-xl shadow p-6">
        <h3 className="text-xl font-bold mb-4">Detailed Analysis</h3>
        <div className="space-y-3">
          {result.guna_kootas.map((koota, idx) => (
            <div key={idx} className="flex items-center justify-between border-b pb-3">
              <div className="flex-1">
                <div className="font-bold">{koota.name}</div>
                <div className="text-sm text-gray-600">{koota.description}</div>
              </div>
              <div className="text-right">
                <div className="text-2xl font-bold">
                  {koota.points}/{koota.maximum_points}
                </div>
              </div>
            </div>
          ))}
        </div>
      </div>

      {/* Doshas: Nadi dosha shows as 0 of 8 on the Nadi koota */}
      {result.gunaDetails.nadi.score === 0 && (
        <div className="bg-red-50 rounded-xl p-6">
          <h3 className="text-xl font-bold mb-4 text-red-900">Doshas Detected</h3>
          <div className="space-y-4">
            <div>
              <div className="font-bold text-red-800">Nadi Dosha</div>
              <div className="text-sm text-red-700">
                {result.gunaDetails.nadi.interpretation}
              </div>
            </div>
          </div>
        </div>
      )}

      {/* Summary */}
      <div className="bg-blue-50 rounded-xl p-6">
        <h3 className="text-xl font-bold mb-4">Analysis</h3>
        <p className="text-gray-700">{result.interpretation.summary}</p>
      </div>
    </div>
  );
}

Batch Matching for Matrimonial Platforms

For matrimonial sites, you need to match one profile against hundreds. Here's an efficient batch implementation:

from concurrent.futures import ThreadPoolExecutor
from typing import Dict, List

def find_compatible_matches(
    base_profile: Dict,
    candidates: List[Dict],
    min_score: int = 18
) -> List[Dict]:
    """Find all compatible matches from a list of candidates.

    base_profile is the groom's birth details; each candidate is
    {"id": ..., "birth": {datetime, latitude, longitude, timezone}} for a bride.
    """

    # One Guna Milan call per candidate, run in parallel
    with ThreadPoolExecutor(max_workers=8) as pool:
        results = list(pool.map(
            lambda c: api.match_kundali(base_profile, c['birth']),
            candidates
        ))

    # Filter and sort results
    compatible = [
        {
            'profileId': candidates[i]['id'],
            'score': result['total_points'],
            'compatibility': result['match_result'],
            'concerns': result['interpretation']['challenges']
        }
        for i, result in enumerate(results)
        if result['total_points'] >= min_score
    ]

    # Sort by score descending
    compatible.sort(key=lambda x: x['score'], reverse=True)

    return compatible

# Find top matches
user_birth = groom
all_candidates = get_all_eligible_profiles()  # Your DB query: [{"id": ..., "birth": {...}}, ...]

matches = find_compatible_matches(
    user_birth,
    all_candidates,
    min_score=24  # Only "Good" or better
)

# Display top 10 matches
for match in matches[:10]:
    print(f"{match['score']}/36 - {match['compatibility']}")

Caching Strategy for Performance

import hashlib
import json
import redis
from datetime import timedelta
from typing import Dict, Optional

redis_client = redis.Redis(host='localhost', port=6379, decode_responses=True)

def match_cache_key(groom: Dict, bride: Dict) -> str:
    """Deterministic key: the same two sets of birth details always map to the same key"""
    raw = json.dumps([groom, bride], sort_keys=True)
    return f"match:{hashlib.sha256(raw.encode()).hexdigest()}"

def get_cached_match(groom: Dict, bride: Dict) -> Optional[Dict]:
    """Check cache for existing match result"""
    cached = redis_client.get(match_cache_key(groom, bride))
    if cached:
        return json.loads(cached)
    return None

def cache_match_result(groom: Dict, bride: Dict, result: Dict):
    """Cache match result for 30 days"""
    redis_client.setex(
        match_cache_key(groom, bride),
        timedelta(days=30),
        json.dumps(result)
    )

def match_with_cache(groom: Dict, bride: Dict) -> Dict:
    """Match with caching"""
    # Check cache first
    cached = get_cached_match(groom, bride)
    if cached:
        return cached

    # Calculate new match
    result = api.match_kundali(groom, bride)

    # Cache result
    cache_match_result(groom, bride, result)

    return result

Monetization Strategies

Freemium Model

  • ✓ Basic score (free)
  • ✓ 3 matches per month (free)
  • 💎 Detailed kuta breakdown ($4.99)
  • 💎 Unlimited matches ($9.99/mo)
  • 💎 AI compatibility report ($14.99)

Enterprise Model

  • 💼 API access ($299/mo)
  • 💼 White-label solution ($999/mo)
  • 💼 Custom matching rules ($1999/mo)
  • 💼 Astrologer consultation platform ($2999/mo)

Best Practices

Always Handle Exceptions

Invalid birth times, place names, or API errors. Provide fallback UI and clear error messages.

Cache Aggressively

Kundali matches don't change. Cache results for 30+ days to reduce API costs and improve speed.

Explain the Scores

Users don't understand "18/36". Show what each kuta means and why it matters.

Handle Dosha Sensitively

Mangal dosha carries stigma. Present it factually with remedies and cancellation factors.

Add Kundali Matching to Your App

Vedika API handles all kundali matching complexity - Ashtakoot scoring, dosha detection, remedies, and AI insights. About 50 ms median server time, calculation endpoints (Oct 2026). AI answers take longer.

Frequently Asked Questions

What is Kundali matching in Vedic astrology?

Kundali matching (Gun Milan) is the Vedic process of assessing marriage compatibility between two people using their birth charts. It evaluates 8 factors (Ashtakoot) including Varna, Vashya, Tara, Yoni, Graha Maitri, Gana, Bhakoot, and Nadi. A score of 18+ out of 36 points indicates good compatibility.

How is the Ashtakoot compatibility score calculated?

Ashtakoot system assigns points based on Moon's nakshatra in both charts. Maximum points: Nadi (8), Bhakoot (7), Gana (6), Graha Maitri (5), Yoni (4), Tara (3), Vashya (2), Varna (1). Total of 36 points. Scores: 18-24 = Average, 25-32 = Good, 33-36 = Excellent compatibility.

What is Mangal Dosha and how serious is it?

Mangal Dosha (Kuja Dosha) occurs when Mars is in 1st, 4th, 7th, 8th, or 12th house. It's believed to cause marital discord. Severity varies - Mars in 1st or 8th is most severe. Dosha cancels if both partners have it, or after age 28. Many modern astrologers consider it less critical than overall compatibility.

Which API is best for kundali matching integration?

Vedika API offers comprehensive kundali matching with Ashtakoot scoring, Mangal Dosha detection, detailed kuta analysis, and AI-generated compatibility reports. It handles North/South Indian systems, multiple ayanamsas, and provides match recommendations. About 50 ms median server time, calculation endpoints (Oct 2026). AI answers take longer.

Can I customize kundali matching rules in the API?

Yes, Vedika API allows customization of matching criteria including minimum score thresholds, weightage adjustments for each kuta, Mangal Dosha cancellation rules, and regional variations (North vs South Indian). You can also exclude certain doshas or add custom compatibility factors.