Skip to content
T
Tools.Town
Free Online Tools for Everyone

Integrating the Tools.Town EMI API in a React App — A Complete Walkthrough

Developer Corner Tools.Town Team 10 April 2026 8 min read

A step-by-step guide to adding loan EMI calculation to your React application using the Tools.Town REST API. Covers setup, authentication, and rendering results.

:::note This API is currently in development. The endpoint documented below is not yet live. Join the waitlist on the API docs page to get notified when it ships. The code examples below are accurate and will work as-is once the endpoint goes live. :::

If you’re building a fintech app, loan comparison tool, or any product that needs EMI calculations, you don’t need to implement the math yourself. The Tools.Town EMI API handles it — free up to 1,000 requests/month, no auth required.

This walkthrough covers everything from the first fetch call to rendering a clean result in React.

The endpoint

GET https://api.tools.town/v1/calculators/emi

Parameters:

NameTypeDescription
principalnumberLoan amount in rupees
ratenumberAnnual interest rate (%)
tenurenumberLoan duration in months

Example response:

{
  "success": true,
  "data": {
    "emi": 10379.73,
    "totalInterest": 122783.8,
    "totalPayment": 622783.8,
    "principalPercent": 80.28,
    "interestPercent": 19.72
  }
}

Step 1: Create the custom hook

Keep the API logic separate from your UI with a custom hook:

// hooks/useEmiCalculator.js
import { useState, useCallback } from "react";

export function useEmiCalculator() {
  const [result, setResult] = useState(null);
  const [loading, setLoading] = useState(false);
  const [error, setError] = useState(null);

  const calculate = useCallback(async ({ principal, rate, tenure }) => {
    setLoading(true);
    setError(null);

    try {
      const params = new URLSearchParams({ principal, rate, tenure });
      const res = await fetch(
        `https://api.tools.town/v1/calculators/emi?${params}`
      );

      if (!res.ok) throw new Error(`API error: ${res.status}`);

      const json = await res.json();
      setResult(json.data);
    } catch (err) {
      setError(err.message);
    } finally {
      setLoading(false);
    }
  }, []);

  return { result, loading, error, calculate };
}

Step 2: Build the form component

// components/EmiForm.jsx
import { useState } from "react";
import { useEmiCalculator } from "../hooks/useEmiCalculator";

export function EmiForm() {
  const [principal, setPrincipal] = useState(500000);
  const [rate, setRate]           = useState(8.5);
  const [tenure, setTenure]       = useState(60);

  const { result, loading, error, calculate } = useEmiCalculator();

  const handleSubmit = (e) => {
    e.preventDefault();
    calculate({ principal, rate, tenure });
  };

  return (
    <form onSubmit={handleSubmit}>
      <label>
        Loan Amount (₹)
        <input
          type="number"
          value={principal}
          onChange={(e) => setPrincipal(e.target.value)}
        />
      </label>

      <label>
        Annual Rate (%)
        <input
          type="number"
          step="0.1"
          value={rate}
          onChange={(e) => setRate(e.target.value)}
        />
      </label>

      <label>
        Tenure (months)
        <input
          type="number"
          value={tenure}
          onChange={(e) => setTenure(e.target.value)}
        />
      </label>

      <button type="submit" disabled={loading}>
        {loading ? "Calculating…" : "Calculate EMI"}
      </button>

      {error && <p className="error">{error}</p>}

      {result && (
        <div className="result">
          <p>Monthly EMI: <strong>₹{result.emi.toLocaleString("en-IN")}</strong></p>
          <p>Total Interest: ₹{result.totalInterest.toLocaleString("en-IN")}</p>
          <p>Total Payment: ₹{result.totalPayment.toLocaleString("en-IN")}</p>
        </div>
      )}
    </form>
  );
}

Step 3: Add debouncing for live updates

If you want the result to update as the user types (without a submit button), add a debounce to avoid hammering the API:

import { useEffect, useRef } from "react";

function useDebouncedEffect(fn, deps, delay = 400) {
  const timer = useRef(null);
  useEffect(() => {
    clearTimeout(timer.current);
    timer.current = setTimeout(fn, delay);
    return () => clearTimeout(timer.current);
  }, deps);
}

// In your component:
useDebouncedEffect(
  () => calculate({ principal, rate, tenure }),
  [principal, rate, tenure]
);

Rate limiting

The free tier allows 1,000 requests/month without an API key. For higher volume, grab a key at dashboard.tools.town/api-keys and add it to the request:

const res = await fetch(url, {
  headers: { Authorization: `Bearer ${process.env.TOOLS_TOWN_API_KEY}` }
});

Keep the key server-side (env variable) — never ship it in client-side bundle code.

Full API reference

See the EMI Calculator API docs for the complete parameter reference, response schema, and error codes.

Frequently Asked Questions

Do I need an API key for the EMI endpoint?
No. The EMI Calculator API allows up to 1,000 free requests/month without authentication.
Can I use this in a Next.js app?
Yes — the fetch call works in any JavaScript environment. For Next.js, put the fetch in a Server Component or API route to avoid exposing your key on the client.

Explore more on Tools.Town Blog

Finance guides, tool launches, and engineering stories — updated weekly.

All Posts