Developers
J Gene Billing API.
Read your products, customers, invoices, transactions and expenses from your own software, accounting tools or reports.
Overview
The J Gene Billing API is a read-only REST API over HTTPS. Every request returns JSON, every amount is a number in Indian Rupees, and every timestamp is an ISO 8601 string in UTC. Field names use camelCase.
A key only ever sees the data of the J Gene Billing account it was created in. The API cannot create, change or delete anything, so it is safe to connect to reporting and accounting tools.
Base URL
https://sherut.j-gene.com/api/v1
API access is part of the Enterprise plan. If the plan ends, existing keys stop working with a 403 until it is renewed; your data and keys are kept.
Quickstart
- Sign in to J Gene Billing as the account owner and open Settings.
- In API access, give the key a name you will recognise (for example “Accounting sync”) and choose Create key.
- Copy the key straight away. For your security it is shown only once.
- Make your first request:
curl https://sherut.j-gene.com/api/v1/products \
-H "Authorization: Bearer jgb_your_api_key"The same request from code:
// Node.js 18+ (built-in fetch)
const response = await fetch("https://sherut.j-gene.com/api/v1/invoices?status=PAID", {
headers: { Authorization: `Bearer ${process.env.JGENE_API_KEY}` },
});
if (!response.ok) {
const { error } = await response.json();
throw new Error(`${error.code}: ${error.message}`);
}
const { data, pagination } = await response.json();
console.log(`Fetched ${data.length} of ${pagination.total} paid invoices`);import os
import requests
response = requests.get(
"https://sherut.j-gene.com/api/v1/customers",
headers={"Authorization": f"Bearer {os.environ['JGENE_API_KEY']}"},
params={"perPage": 100},
timeout=30,
)
response.raise_for_status()
body = response.json()
print(f"{body['pagination']['total']} customers")Authentication
Send your key in the Authorization header of every request, as a bearer token. Keys start with jgb_.
Authorization: Bearer jgb_your_api_key- Only the account owner can create and revoke keys, and only on the Enterprise plan.
- An account can have up to 10 active keys. Use one per integration so you can revoke them separately.
- We store only a fingerprint of each key, never the key itself, so a lost key cannot be recovered. Revoke it and create a new one.
- Revoking a key in Settings stops it working immediately.
- Settings shows when each key was last used, so you can spot keys that are no longer needed.
Pagination
Every list endpoint is paginated. Pass page (from 1) and perPage (up to 100, default 50). Results come in a data array with a pagination object:
{
"data": [ ... ],
"pagination": { "page": 1, "perPage": 50, "total": 124, "totalPages": 3 }
}Lists are sorted newest first. To read everything, keep requesting pages until you reach totalPages:
// Fetch every invoice, one page at a time.
async function fetchAllInvoices() {
const all = [];
let page = 1;
let totalPages = 1;
do {
const response = await fetch(`https://sherut.j-gene.com/api/v1/invoices?page=${page}&perPage=100`, {
headers: { Authorization: `Bearer ${process.env.JGENE_API_KEY}` },
});
if (!response.ok) throw new Error(`Request failed: ${response.status}`);
const body = await response.json();
all.push(...body.data);
totalPages = body.pagination.totalPages;
page += 1;
} while (page <= totalPages);
return all;
}Errors
Errors use standard HTTP status codes and a consistent body with a machine-readable code and a human-readable message:
{
"error": {
"code": "unauthorized",
"message": "Invalid or revoked API key."
}
}| Status | Code | Meaning |
|---|---|---|
| 401 | unauthorized | The Authorization header is missing or malformed, or the key is wrong or revoked. |
| 403 | plan_required | The account's plan no longer includes API access (Enterprise). |
| 404 | not_found | The resource does not exist in your account. |
| 429 | rate_limited | More than 120 requests in a minute with this key. Wait a minute and retry. |
| 500 | server_error | Something went wrong on our side. Retry later; contact us if it persists. |
Filters with values the API does not recognise (for example status=OPEN or a date it cannot read) are ignored rather than rejected, so check your parameters if a list looks unfiltered.
Rate limits
Each key can make up to 120 requests a minute. Beyond that the API answers 429 rate_limited; wait a minute before retrying. For bulk exports, use perPage=100 to make fewer requests.
Best practices
- Keep keys on your server, in an environment variable or secret manager. Never put them in a website, mobile app or public repository.
- Create one key per integration and name it after what uses it.
- If a key may have been exposed, revoke it in Settings and create a new one.
- To sync regularly, ask only for what changed: for example invoices with
fromset to the time of your last sync. - Retry 429 and 500 responses after a short wait; do not retry 401, 403 or 404.
/productsList products
Every product in your inventory, newest first.
Parameters
| Name | Type | Description |
|---|---|---|
| page | integer | Page to return, starting at 1. Default 1. |
| perPage | integer | Rows per page, up to 100. Default 50. |
Response fields
| Name | Type | Description |
|---|---|---|
| id | string | Product ID. |
| name | string | Product name. |
| sku | string | null | Your SKU or item code. |
| category | string | null | Category. |
| price | number | Selling price, in INR. |
| cost | number | Cost price, in INR. |
| quantity | integer | Units in stock. |
| minStock | integer | Low-stock threshold. |
| cgstPercent | number | CGST rate, in percent. |
| sgstPercent | number | SGST rate, in percent. |
| createdAt | string | Created (ISO 8601, UTC). |
| updatedAt | string | Last changed (ISO 8601, UTC). |
curl "https://sherut.j-gene.com/api/v1/products?perPage=2" \
-H "Authorization: Bearer jgb_your_api_key"{
"data": [
{
"id": "6f1c2a9e-4b7d-4e21-9a3f-2c8d1e5b7a40",
"name": "Cotton shirt",
"sku": "SH-001",
"category": "Apparel",
"price": 700,
"cost": 420,
"quantity": 38,
"minStock": 5,
"cgstPercent": 2.5,
"sgstPercent": 2.5,
"createdAt": "2026-09-02T06:15:00.000Z",
"updatedAt": "2026-10-11T10:42:18.000Z"
}
],
"pagination": { "page": 1, "perPage": 2, "total": 124, "totalPages": 62 }
}/customersList customers
Every customer in your account, newest first.
Parameters
| Name | Type | Description |
|---|---|---|
| page | integer | Page to return, starting at 1. Default 1. |
| perPage | integer | Rows per page, up to 100. Default 50. |
Response fields
| Name | Type | Description |
|---|---|---|
| id | string | Customer ID. |
| name | string | Customer name. |
| string | null | Email address. | |
| phone | string | null | Phone number. |
| address | string | null | Address. |
| businessName | string | null | Business name, for business customers. |
| createdAt | string | Created (ISO 8601, UTC). |
curl "https://sherut.j-gene.com/api/v1/customers" \
-H "Authorization: Bearer jgb_your_api_key"{
"data": [
{
"id": "b2e4c6a8-1d3f-4a5b-8c7d-9e0f1a2b3c4d",
"name": "Priya Raman",
"email": "priya@example.com",
"phone": "+91 98400 12345",
"address": "12 Market Road, Chennai",
"businessName": "Raman Stores",
"createdAt": "2026-08-19T04:30:00.000Z"
}
],
"pagination": { "page": 1, "perPage": 50, "total": 1, "totalPages": 1 }
}/invoicesList invoices
Bills and invoices, newest first, with optional filters. Line items are not included; fetch one invoice for those.
Parameters
| Name | Type | Description |
|---|---|---|
| page | integer | Page to return, starting at 1. Default 1. |
| perPage | integer | Rows per page, up to 100. Default 50. |
| status | string | Only "PENDING" or only "PAID" invoices. |
| channel | string | "billing" for counter bills or "invoice" for tax invoices. |
| customerId | string | Only invoices for this customer. |
| from | date-time | Created at or after this time, e.g. 2026-10-01 or 2026-10-01T00:00:00Z. |
| to | date-time | Created at or before this time. |
Response fields
| Name | Type | Description |
|---|---|---|
| id | string | Invoice ID. |
| channel | string | "billing" for a counter bill, "invoice" for a tax invoice. |
| status | string | "PENDING" or "PAID". |
| customerId | string | The customer the invoice is for. |
| customerName | string | That customer's name. |
| subtotal | number | Total of the line items before taxes and discount, in INR. |
| taxPercent | number | Additional tax rate applied to the subtotal, in percent. |
| discountPercent | number | Discount rate, in percent. |
| cgstTotal | number | Total CGST, in INR. |
| sgstTotal | number | Total SGST, in INR. |
| otherChargesTotal | number | Total of other charges, in INR. |
| total | number | Amount payable, in INR. |
| advanceAmount | number | Amount already received in advance, in INR. |
| branchId | string | null | Branch the invoice belongs to, if branches are used. |
| createdAt | string | When the invoice was created (ISO 8601, UTC). |
| paidAt | string | null | When it was marked paid, or null. |
curl "https://sherut.j-gene.com/api/v1/invoices?status=PAID&from=2026-10-01T00:00:00Z" \
-H "Authorization: Bearer jgb_your_api_key"{
"data": [
{
"id": "0d9b8a7c-6e5f-4d3c-2b1a-0f9e8d7c6b5a",
"channel": "invoice",
"status": "PAID",
"customerId": "b2e4c6a8-1d3f-4a5b-8c7d-9e0f1a2b3c4d",
"customerName": "Priya Raman",
"subtotal": 15600,
"taxPercent": 0,
"discountPercent": 0,
"cgstTotal": 390,
"sgstTotal": 390,
"otherChargesTotal": 0,
"total": 16380,
"advanceAmount": 0,
"branchId": null,
"createdAt": "2026-10-12T09:05:41.000Z",
"paidAt": "2026-10-12T09:20:03.000Z"
}
],
"pagination": { "page": 1, "perPage": 50, "total": 1, "totalPages": 1 }
}/invoices/{id}Get an invoice
One invoice with its line items. Returns 404 if the ID is not an invoice in your account.
Parameters
| Name | Type | Description |
|---|---|---|
| id | string (path) | The invoice ID. |
Response fields
| Name | Type | Description |
|---|---|---|
| id | string | Invoice ID. |
| channel | string | "billing" for a counter bill, "invoice" for a tax invoice. |
| status | string | "PENDING" or "PAID". |
| customerId | string | The customer the invoice is for. |
| customerName | string | That customer's name. |
| subtotal | number | Total of the line items before taxes and discount, in INR. |
| taxPercent | number | Additional tax rate applied to the subtotal, in percent. |
| discountPercent | number | Discount rate, in percent. |
| cgstTotal | number | Total CGST, in INR. |
| sgstTotal | number | Total SGST, in INR. |
| otherChargesTotal | number | Total of other charges, in INR. |
| total | number | Amount payable, in INR. |
| advanceAmount | number | Amount already received in advance, in INR. |
| branchId | string | null | Branch the invoice belongs to, if branches are used. |
| createdAt | string | When the invoice was created (ISO 8601, UTC). |
| paidAt | string | null | When it was marked paid, or null. |
| items | array | Line items: id, productId, name, price, quantity, subtotal, cgstAmount, sgstAmount, otherChargesAmount. |
curl "https://sherut.j-gene.com/api/v1/invoices/0d9b8a7c-6e5f-4d3c-2b1a-0f9e8d7c6b5a" \
-H "Authorization: Bearer jgb_your_api_key"{
"data": {
"id": "0d9b8a7c-6e5f-4d3c-2b1a-0f9e8d7c6b5a",
"channel": "invoice",
"status": "PAID",
"customerName": "Priya Raman",
"subtotal": 15600,
"cgstTotal": 390,
"sgstTotal": 390,
"total": 16380,
"createdAt": "2026-10-12T09:05:41.000Z",
"paidAt": "2026-10-12T09:20:03.000Z",
"items": [
{
"id": "a1b2c3d4-e5f6-4a7b-8c9d-0e1f2a3b4c5d",
"productId": "6f1c2a9e-4b7d-4e21-9a3f-2c8d1e5b7a40",
"name": "Cotton shirt",
"price": 700,
"quantity": 12,
"subtotal": 8400,
"cgstAmount": 210,
"sgstAmount": 210,
"otherChargesAmount": 0
}
]
}
}/transactionsList transactions
Stock transactions (sales, purchases, expenses and refunds), newest first.
Parameters
| Name | Type | Description |
|---|---|---|
| page | integer | Page to return, starting at 1. Default 1. |
| perPage | integer | Rows per page, up to 100. Default 50. |
| type | string | "sale", "purchase", "expense" or "refund". |
| search | string | Case-insensitive match on customer name or notes. |
Response fields
| Name | Type | Description |
|---|---|---|
| id | string | Transaction ID. |
| type | string | "sale", "purchase", "expense" or "refund". |
| productId | string | null | Product involved. |
| quantity | number | Units. |
| unitPrice | number | Price per unit, in INR. |
| totalAmount | number | Total, in INR. |
| customerName | string | null | Customer or supplier name. |
| notes | string | null | Notes. |
| transactionDate | string | Date of the transaction. |
| createdAt | string | Recorded (ISO 8601, UTC). |
curl "https://sherut.j-gene.com/api/v1/transactions?type=sale&perPage=20" \
-H "Authorization: Bearer jgb_your_api_key"{
"data": [
{
"id": "7c6b5a4d-3e2f-4a1b-9c8d-7e6f5a4b3c2d",
"type": "sale",
"productId": "6f1c2a9e-4b7d-4e21-9a3f-2c8d1e5b7a40",
"quantity": 2,
"unitPrice": 700,
"totalAmount": 1400,
"customerName": "Walk-in",
"notes": null,
"transactionDate": "2026-10-13T00:00:00.000Z",
"createdAt": "2026-10-13T07:12:55.000Z"
}
],
"pagination": { "page": 1, "perPage": 20, "total": 1, "totalPages": 1 }
}/expensesList expenses
Expenses from the expense tracker, newest first.
Parameters
| Name | Type | Description |
|---|---|---|
| page | integer | Page to return, starting at 1. Default 1. |
| perPage | integer | Rows per page, up to 100. Default 50. |
| category | string | Only expenses in this category, e.g. Rent. |
| search | string | Case-insensitive match on vendor, notes or category. |
Response fields
| Name | Type | Description |
|---|---|---|
| id | string | Expense ID. |
| category | string | Category. |
| amount | number | Amount, in INR. |
| vendor | string | null | Who was paid. |
| notes | string | null | Notes. |
| paymentMethod | string | null | How it was paid, e.g. Bank Transfer. |
| expenseDate | string | Date of the expense. |
| isRecurring | boolean | Whether it repeats. |
| recurringFrequency | string | null | How often it repeats, if recurring. |
| createdAt | string | Recorded (ISO 8601, UTC). |
curl "https://sherut.j-gene.com/api/v1/expenses?category=Rent" \
-H "Authorization: Bearer jgb_your_api_key"{
"data": [
{
"id": "3f2e1d0c-9b8a-4c7d-6e5f-4a3b2c1d0e9f",
"category": "Rent",
"amount": 15000,
"vendor": "Landlord",
"notes": null,
"paymentMethod": "Bank Transfer",
"expenseDate": "2026-10-01T00:00:00.000Z",
"isRecurring": true,
"recurringFrequency": "Monthly",
"createdAt": "2026-10-01T05:00:00.000Z"
}
],
"pagination": { "page": 1, "perPage": 50, "total": 1, "totalPages": 1 }
}Need something the API doesn't do yet?
The API is read-only today. If your integration needs more, or you are stuck, tell us what you are building. Common questions are answered in the knowledge base.
Contact us