Independence Day offer · ₹52/employee/moClaim offer
INDPayroll
API reference

Payroll configuration

One-time per-organization setup - cycle, components, groups, TDS, PT, payment methods.

Base URLhttps://api.indpayroll.com/v134 endpoints
GET /payroll-settings

Retrieve payroll settings

Query parameters

organization_id
integer
Organization to act on. Required when the API key can reach more than one organization; optional - and defaulted - when it can reach exactly one.

Responses

  • 200 Settings. PayrollSettings
  • 401 The key is missing, unknown, or the HMAC signature did not verify. ErrorResponse
Request
curl -X GET https://api.indpayroll.com/v1/payroll-settings \
  -H "Authorization: Bearer $INDP_API_KEY"
Response · 200
{
  "organization_id": 42,
  "cycle": "monthly",
  "currency": "INR",
  "payslip_template": 2,
  "lwf_registered": true,
  "lwf_state": "Odisha",
  "rounding": "nearest_rupee"
}
PUT /payroll-settings

Replace payroll settings

Cycle, currency, payslip template, LWF registration and the extra fields printed on the payslip footer.

Body application/json · required

organization_id required
integer
cycle required
enum: monthly, weekly, bi-weekly
currency
string
payslip_template
integer
Which of the six payslip templates PDFs render with.
lwf_registered
boolean
lwf_state
string
rounding
enum: none, nearest_rupee, nearest_ten
Applied to net payable only. Statutory components always follow their own rounding rules.
extra_fields
object
Free-form key/value pairs printed on the payslip footer.

Responses

  • 200 Updated. PayrollSettings
  • 400 The request was malformed or failed validation. ErrorResponse
GET /payroll-settings/period

Retrieve the period setting

Query parameters

organization_id
integer
Organization to act on. Required when the API key can reach more than one organization; optional - and defaulted - when it can reach exactly one.

Responses

  • 200 Cut-off and salary from/to days. PayrollPeriodSetting
  • 401 The key is missing, unknown, or the HMAC signature did not verify. ErrorResponse
PUT /payroll-settings/period

Set the cut-off and the salary period

cut_off_day closes attendance; salary_from_day and salary_to_day bound the period being paid. A period of 26 to 25 is common where attendance is collected a month in arrears.

Body application/json · required

organization_id
integer
cut_off_day required
integer
salary_from_day required
integer
salary_to_day required
integer
carry_forward_late_inputs
boolean
Attendance arriving after the cut-off lands in the next period instead of being ignored.

Responses

  • 200 Updated. PayrollPeriodSetting
  • 400 The request was malformed or failed validation. ErrorResponse
Request
curl -X PUT https://api.indpayroll.com/v1/payroll-settings/period \
  -H "Authorization: Bearer $INDP_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{
  "organization_id": 42,
  "cut_off_day": 25,
  "salary_from_day": 26,
  "salary_to_day": 25,
  "carry_forward_late_inputs": true
}'
GET /payroll-settings/salary-days

Retrieve the salary-days basis

Query parameters

organization_id
integer
Organization to act on. Required when the API key can reach more than one organization; optional - and defaulted - when it can reach exactly one.

Responses

  • 200 The pro-rating denominator. SalaryDaysSetting
  • 401 The key is missing, unknown, or the HMAC signature did not verify. ErrorResponse
PUT /payroll-settings/salary-days

Choose calendar days or a fixed 30-day month

This single setting changes every pro-rated amount on every payslip. fixed_days (30) keeps a day's pay constant through the year; calendar_days makes February's days worth more than March's.

Body application/json · required

organization_id
integer
basis required
enum: calendar_days, fixed_days, working_days
fixed_days
integer
Used when basis is fixed_days.
exclude_weekly_offs
boolean
Only meaningful for working_days.

Responses

  • 200 Updated. SalaryDaysSetting
  • 400 The request was malformed or failed validation. ErrorResponse
Request
curl -X PUT https://api.indpayroll.com/v1/payroll-settings/salary-days \
  -H "Authorization: Bearer $INDP_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{
  "organization_id": 42,
  "basis": "fixed_days",
  "fixed_days": 30
}'
GET /payroll-settings/currency

Retrieve the payroll currency

Query parameters

organization_id
integer
Organization to act on. Required when the API key can reach more than one organization; optional - and defaulted - when it can reach exactly one.

Responses

  • 200 Currency. CurrencySetting
PUT /payroll-settings/currency

Set the payroll currency

Indian statutory calculation - PF, ESI, PT, TDS, LWF - is only defined for INR.

Body application/json · required

organization_id
integer
currency required
string
ISO 4217. Statutory calculation is only defined for INR.
symbol
string

Responses

  • 200 Updated. CurrencySetting
  • 400 The request was malformed or failed validation. ErrorResponse
GET /salary-components

List salary components

Query parameters

organization_id
integer
Organization to act on. Required when the API key can reach more than one organization; optional - and defaulted - when it can reach exactly one.
kind
enum: earning, deduction, employer_contribution, reimbursement

Responses

  • 200 Components. object
  • 401 The key is missing, unknown, or the HMAC signature did not verify. ErrorResponse
Request
curl -X GET https://api.indpayroll.com/v1/salary-components \
  -H "Authorization: Bearer $INDP_API_KEY"
Response · 200
{
  "data": [
    {
      "id": 20,
      "name": "Basic",
      "code": "BASIC",
      "kind": "earning",
      "calculation": "percent_of_ctc",
      "value": 50,
      "taxable": true,
      "pf_applicable": true,
      "esi_applicable": true,
      "pro_rate": true
    },
    {
      "id": 21,
      "name": "House Rent Allowance",
      "code": "HRA",
      "kind": "earning",
      "calculation": "percent_of_basic",
      "value": 40,
      "taxable": true,
      "pf_applicable": false,
      "esi_applicable": true,
      "pro_rate": true
    },
    {
      "id": 24,
      "name": "Special Allowance",
      "code": "SPL",
      "kind": "earning",
      "calculation": "balance",
      "taxable": true,
      "pf_applicable": false,
      "esi_applicable": true,
      "pro_rate": true
    }
  ]
}
POST /salary-components

Create a salary component

The three flags matter more than the amount: taxable decides whether TDS sees it, pf_applicable whether it joins PF wages, esi_applicable whether it joins ESI wages. Getting them wrong is the usual cause of a statutory figure a partner cannot reconcile.

Headers

Idempotency-Key
string
A unique key, at most 255 characters, that makes this request safe to retry. Replaying a key within 24 hours returns the original response and does not act again.

Body application/json · required

organization_id
integer
The entity the component belongs to.
name required
string
What appears on the payslip.
code required
string
Short identifier used in formulas and in the payslip breakdown.
kind required
enum: earning, deduction, employer_contribution, reimbursement
Earning, deduction, employer contribution or reimbursement.
calculation required
enum: fixed, percent_of_basic, percent_of_ctc, percent_of_gross, formula, balance
How the amount is arrived at.
value
number
The fixed amount, or the percentage, depending on calculation.
formula
string
taxable
boolean
pf_applicable
boolean
esi_applicable
boolean
pro_rate
boolean
show_on_payslip
boolean
active
boolean

Responses

  • 201 Created. SalaryComponent
  • 400 The request was malformed or failed validation. ErrorResponse
  • 409 The resource is in a state that forbids the change - a locked or paid run, a duplicate external_id, or a settlement already approved. ErrorResponse
Request
curl -X POST https://api.indpayroll.com/v1/salary-components \
  -H "Authorization: Bearer $INDP_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{
  "organization_id": 42,
  "name": "Conveyance Allowance",
  "code": "CONV",
  "kind": "earning",
  "calculation": "fixed",
  "value": 1600,
  "taxable": true,
  "pf_applicable": false,
  "esi_applicable": true,
  "pro_rate": true
}'
GET /salary-components/{id}

Retrieve a salary component

Path parameters

id required
string
INDPayroll id of the resource.

Responses

  • 200 The component. SalaryComponent
  • 404 No such resource, or it belongs to an organization this key cannot reach. ErrorResponse
PATCH /salary-components/{id}

Update a salary component

Changes apply to runs calculated afterwards. Slips already generated keep the values they were calculated with.

Path parameters

id required
string
INDPayroll id of the resource.

Body application/json · required

organization_id
integer
The entity the component belongs to.
name required
string
What appears on the payslip.
code required
string
Short identifier used in formulas and in the payslip breakdown.
kind required
enum: earning, deduction, employer_contribution, reimbursement
Earning, deduction, employer contribution or reimbursement.
calculation required
enum: fixed, percent_of_basic, percent_of_ctc, percent_of_gross, formula, balance
How the amount is arrived at.
value
number
The fixed amount, or the percentage, depending on calculation.
formula
string
taxable
boolean
pf_applicable
boolean
esi_applicable
boolean
pro_rate
boolean
show_on_payslip
boolean
active
boolean

Responses

  • 200 Updated. SalaryComponent
  • 404 No such resource, or it belongs to an organization this key cannot reach. ErrorResponse
DELETE /salary-components/{id}

Delete a salary component

Refused while a salary group still carries it. Deactivate it with active: false instead.

Path parameters

id required
string
INDPayroll id of the resource.

Responses

  • 204 Deleted. No body.
  • 404 No such resource, or it belongs to an organization this key cannot reach. ErrorResponse
  • 409 The resource is in a state that forbids the change - a locked or paid run, a duplicate external_id, or a settlement already approved. ErrorResponse
GET /salary-groups

List salary groups

Query parameters

organization_id
integer
Organization to act on. Required when the API key can reach more than one organization; optional - and defaulted - when it can reach exactly one.

Responses

  • 200 Groups. object
  • 401 The key is missing, unknown, or the HMAC signature did not verify. ErrorResponse
POST /salary-groups

Create a salary group

A structure template. Attach components here, or afterwards with PUT /salary-groups/{id}/components.

Headers

Idempotency-Key
string
A unique key, at most 255 characters, that makes this request safe to retry. Replaying a key within 24 hours returns the original response and does not act again.

Body application/json · required

organization_id
integer
name required
string
description
string
basis
enum: monthly_ctc, daily_wage, hourly
components
SalaryGroupComponent[]
active
boolean

Responses

  • 201 Created. SalaryGroup
  • 400 The request was malformed or failed validation. ErrorResponse
Request
curl -X POST https://api.indpayroll.com/v1/salary-groups \
  -H "Authorization: Bearer $INDP_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{
  "organization_id": 42,
  "name": "Engineering - L3 and above",
  "basis": "monthly_ctc",
  "components": [
    {
      "component_id": 20,
      "calculation": "percent_of_ctc",
      "value": 50,
      "sequence": 1
    },
    {
      "component_id": 21,
      "calculation": "percent_of_basic",
      "value": 40,
      "sequence": 2
    },
    {
      "component_id": 24,
      "calculation": "balance",
      "sequence": 3
    }
  ]
}'
GET /salary-groups/{id}

Retrieve a salary group

Path parameters

id required
string
INDPayroll id of the resource.

Responses

  • 200 The group, with its components. SalaryGroup
  • 404 No such resource, or it belongs to an organization this key cannot reach. ErrorResponse
PATCH /salary-groups/{id}

Update a salary group

Path parameters

id required
string
INDPayroll id of the resource.

Body application/json · required

organization_id
integer
name required
string
description
string
basis
enum: monthly_ctc, daily_wage, hourly
components
SalaryGroupComponent[]
active
boolean

Responses

  • 200 Updated. SalaryGroup
  • 404 No such resource, or it belongs to an organization this key cannot reach. ErrorResponse
DELETE /salary-groups/{id}

Delete a salary group

Refused while employees are assigned to it.

Path parameters

id required
string
INDPayroll id of the resource.

Responses

  • 204 Deleted. No body.
  • 404 No such resource, or it belongs to an organization this key cannot reach. ErrorResponse
  • 409 The resource is in a state that forbids the change - a locked or paid run, a duplicate external_id, or a settlement already approved. ErrorResponse
PUT /salary-groups/{id}/components

Attach components and their values

Replaces the group's component list wholesale. sequence is both the print order on the payslip and the evaluation order, so a balance component must sit last.

Path parameters

id required
string
INDPayroll id of the resource.

Body application/json · required

components required
SalaryGroupComponent[]

Responses

  • 200 Updated. SalaryGroup
  • 400 The request was malformed or failed validation. ErrorResponse
  • 404 No such resource, or it belongs to an organization this key cannot reach. ErrorResponse
Request
curl -X PUT https://api.indpayroll.com/v1/salary-groups/{id}/components \
  -H "Authorization: Bearer $INDP_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{
  "components": [
    {
      "component_id": 20,
      "calculation": "percent_of_ctc",
      "value": 50,
      "sequence": 1
    },
    {
      "component_id": 21,
      "calculation": "percent_of_basic",
      "value": 40,
      "sequence": 2
    },
    {
      "component_id": 22,
      "calculation": "fixed",
      "value": 1600,
      "sequence": 3
    },
    {
      "component_id": 24,
      "calculation": "balance",
      "sequence": 4
    }
  ]
}'
POST /salary-groups/{id}/employees

Assign employees to a salary group

Each employee's CTC is re-spread across the group's components from effective_from. Runs already calculated are untouched.

Path parameters

id required
string
INDPayroll id of the resource.

Headers

Idempotency-Key
string
A unique key, at most 255 characters, that makes this request safe to retry. Replaying a key within 24 hours returns the original response and does not act again.

Body application/json · required

employee_ids required
string[]
effective_from
string (date)
Defaults to the first day of the current period.

Responses

  • 200 Assigned. Ack
  • 400 The request was malformed or failed validation. ErrorResponse
  • 404 No such resource, or it belongs to an organization this key cannot reach. ErrorResponse
Request
curl -X POST https://api.indpayroll.com/v1/salary-groups/{id}/employees \
  -H "Authorization: Bearer $INDP_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{
  "employee_ids": [
    "ext:emp-1001",
    "ext:emp-1002"
  ],
  "effective_from": "2026-10-01"
}'
GET /tds-slabs

List TDS slabs

The slabs the engine applies for a financial year, per regime. INDPayroll ships the statutory schedule and refreshes it as the Budget changes them; these endpoints exist for organizations that need to override or disable a slab.

Query parameters

organization_id
integer
Organization to act on. Required when the API key can reach more than one organization; optional - and defaulted - when it can reach exactly one.
financial_year
string
Indian financial year in YYYY-YY form. Defaults to the year containing the period.
regime
enum: old, new

Responses

  • 200 Slabs. object
  • 401 The key is missing, unknown, or the HMAC signature did not verify. ErrorResponse
POST /tds-slabs

Create a TDS slab

Headers

Idempotency-Key
string
A unique key, at most 255 characters, that makes this request safe to retry. Replaying a key within 24 hours returns the original response and does not act again.

Body application/json · required

organization_id
integer
regime required
enum: old, new
financial_year required
string
from_amount required
number (double)
An amount in the organization's payroll currency, to two decimal places.
to_amount
number (double)
An amount in the organization's payroll currency, to two decimal places.
rate_percent required
number
surcharge_percent
number
cess_percent
number
active
boolean

Responses

  • 201 Created. TdsSlab
  • 400 The request was malformed or failed validation. ErrorResponse
Request
curl -X POST https://api.indpayroll.com/v1/tds-slabs \
  -H "Authorization: Bearer $INDP_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{
  "organization_id": 42,
  "regime": "new",
  "financial_year": "2026-27",
  "from_amount": 1200000,
  "to_amount": 1500000,
  "rate_percent": 20,
  "cess_percent": 4
}'
PATCH /tds-slabs/{id}

Enable or disable a TDS slab

Path parameters

id required
string
INDPayroll id of the resource.

Body application/json · required

active required
boolean

Responses

  • 200 Updated. TdsSlab
  • 404 No such resource, or it belongs to an organization this key cannot reach. ErrorResponse
Request
curl -X PATCH https://api.indpayroll.com/v1/tds-slabs/{id} \
  -H "Authorization: Bearer $INDP_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{
  "active": false
}'
GET /professional-tax/states

List professional tax states and slabs

PT is a state levy, so each state the organization employs in needs its own registration and slab table. The engine ships current schedules for every state that levies PT.

Query parameters

organization_id
integer
Organization to act on. Required when the API key can reach more than one organization; optional - and defaulted - when it can reach exactly one.

Responses

  • 200 States with their slabs. object
  • 401 The key is missing, unknown, or the HMAC signature did not verify. ErrorResponse
Request
curl -X GET https://api.indpayroll.com/v1/professional-tax/states \
  -H "Authorization: Bearer $INDP_API_KEY"
Response · 200
{
  "data": [
    {
      "id": 5,
      "state": "Odisha",
      "registration_number": "PT-OD-0099123",
      "deduction_frequency": "monthly",
      "slabs": [
        {
          "from_amount": 0,
          "to_amount": 160000,
          "amount": 0
        },
        {
          "from_amount": 160001,
          "to_amount": 300000,
          "amount": 125
        },
        {
          "from_amount": 300001,
          "to_amount": null,
          "amount": 200
        }
      ],
      "active": true
    }
  ]
}
POST /professional-tax/states

Add a professional tax state

Headers

Idempotency-Key
string
A unique key, at most 255 characters, that makes this request safe to retry. Replaying a key within 24 hours returns the original response and does not act again.

Body application/json · required

organization_id
integer
state required
string
registration_number
string
deduction_frequency
enum: monthly, half_yearly, yearly
slabs required
PtSlab[]
active
boolean

Responses

  • 201 Created. PtState
  • 400 The request was malformed or failed validation. ErrorResponse
  • 409 The resource is in a state that forbids the change - a locked or paid run, a duplicate external_id, or a settlement already approved. ErrorResponse
GET /employees/{id}/professional-tax

Retrieve an employee's PT mapping

Path parameters

id required
string
Employee id, or your own identifier prefixed with ext: - /employees/ext:emp-1001.

Responses

  • 200 The mapping. EmployeePtMapping
  • 404 No such resource, or it belongs to an organization this key cannot reach. ErrorResponse
PUT /employees/{id}/professional-tax

Map an employee to a PT state

An employee works where they work, not where the entity is registered. Map remote employees to their own state, or the deduction lands in the wrong return.

Path parameters

id required
string
Employee id, or your own identifier prefixed with ext: - /employees/ext:emp-1001.

Body application/json · required

employee_id
string
pt_state required
string
pt_applicable
boolean
override_amount
number (double) or null
Fixes the monthly deduction and bypasses the slab lookup. Rarely needed.

Responses

  • 200 Updated. EmployeePtMapping
  • 400 The request was malformed or failed validation. ErrorResponse
  • 404 No such resource, or it belongs to an organization this key cannot reach. ErrorResponse
Request
curl -X PUT https://api.indpayroll.com/v1/employees/{id}/professional-tax \
  -H "Authorization: Bearer $INDP_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{
  "pt_state": "Karnataka",
  "pt_applicable": true
}'
GET /reimbursement-rates

Retrieve reimbursement rates

Query parameters

organization_id
integer
Organization to act on. Required when the API key can reach more than one organization; optional - and defaulted - when it can reach exactly one.

Responses

  • 200 Travel and distance rates. ReimbursementRates
PUT /reimbursement-rates

Set reimbursement rates

Claims sent with distance_km instead of an amount are valued at these rates.

Body application/json · required

organization_id
integer
per_km_two_wheeler
number (double)
An amount in the organization's payroll currency, to two decimal places.
per_km_four_wheeler
number (double)
An amount in the organization's payroll currency, to two decimal places.
daily_allowance
number (double)
An amount in the organization's payroll currency, to two decimal places.
max_claim_per_month
number (double) or null
effective_from
string (date)

Responses

  • 200 Updated. ReimbursementRates
  • 400 The request was malformed or failed validation. ErrorResponse
Request
curl -X PUT https://api.indpayroll.com/v1/reimbursement-rates \
  -H "Authorization: Bearer $INDP_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{
  "organization_id": 42,
  "per_km_two_wheeler": 4.5,
  "per_km_four_wheeler": 12,
  "daily_allowance": 500,
  "effective_from": "2026-04-01"
}'
GET /payment-methods

List payment methods

Query parameters

organization_id
integer
Organization to act on. Required when the API key can reach more than one organization; optional - and defaulted - when it can reach exactly one.

Responses

  • 200 Payment methods. object
  • 401 The key is missing, unknown, or the HMAC signature did not verify. ErrorResponse
POST /payment-methods

Create a payment method

bank_file_format decides the layout GET /payroll-runs/{id}/bank-file renders, so set it to the bank you actually upload to.

Headers

Idempotency-Key
string
A unique key, at most 255 characters, that makes this request safe to retry. Replaying a key within 24 hours returns the original response and does not act again.

Body application/json · required

organization_id
integer
name required
string
type required
enum: bank_transfer, cash, cheque, upi
bank_name
string
account_number
string
ifsc
string
bank_file_format
enum: generic_csv, hdfc, icici, axis, sbi, kotak, yes_bank
is_default
boolean
active
boolean

Responses

  • 201 Created. PaymentMethod
  • 400 The request was malformed or failed validation. ErrorResponse
Request
curl -X POST https://api.indpayroll.com/v1/payment-methods \
  -H "Authorization: Bearer $INDP_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{
  "organization_id": 42,
  "name": "HDFC current account",
  "type": "bank_transfer",
  "bank_name": "HDFC Bank",
  "account_number": "50200012345678",
  "ifsc": "HDFC0000123",
  "bank_file_format": "hdfc",
  "is_default": true
}'
GET /payroll-cycles

List payroll cycles

Query parameters

organization_id
integer
Organization to act on. Required when the API key can reach more than one organization; optional - and defaulted - when it can reach exactly one.

Responses

  • 200 Cycles. object
  • 401 The key is missing, unknown, or the HMAC signature did not verify. ErrorResponse
POST /payroll-cycles

Create a payroll cycle

An organization can run several cycles at once - monthly for staff, weekly for contract labour. Each run names one.

Headers

Idempotency-Key
string
A unique key, at most 255 characters, that makes this request safe to retry. Replaying a key within 24 hours returns the original response and does not act again.

Body application/json · required

organization_id
integer
name required
string
frequency required
enum: monthly, weekly, bi-weekly
week_start_day
string
pay_day
integer
is_default
boolean

Responses

  • 201 Created. PayrollCycle
  • 400 The request was malformed or failed validation. ErrorResponse
Request
curl -X POST https://api.indpayroll.com/v1/payroll-cycles \
  -H "Authorization: Bearer $INDP_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{
  "organization_id": 42,
  "name": "Weekly - site labour",
  "frequency": "weekly",
  "week_start_day": "monday"
}'
PUT /employees/{id}/cycle

Assign an employee to a cycle

Path parameters

id required
string
Employee id, or your own identifier prefixed with ext: - /employees/ext:emp-1001.

Body application/json · required

cycle_id required
integer
effective_from
string (date)

Responses

  • 200 Assigned. Ack
  • 400 The request was malformed or failed validation. ErrorResponse
  • 404 No such resource, or it belongs to an organization this key cannot reach. ErrorResponse
  • 409 The resource is in a state that forbids the change - a locked or paid run, a duplicate external_id, or a settlement already approved. ErrorResponse
Request
curl -X PUT https://api.indpayroll.com/v1/employees/{id}/cycle \
  -H "Authorization: Bearer $INDP_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{
  "cycle_id": 2,
  "effective_from": "2026-10-01"
}'