Developers

    J Gene Billing API.

    Read your products, customers, invoices, transactions and expenses from your own software, accounting tools or reports.

    Read-only API key authentication Enterprise plan 120 requests / minute

    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

    1. Sign in to J Gene Billing as the account owner and open Settings.
    2. In API access, give the key a name you will recognise (for example “Accounting sync”) and choose Create key.
    3. Copy the key straight away. For your security it is shown only once.
    4. Make your first request:
    cURL
    curl https://sherut.j-gene.com/api/v1/products \
      -H "Authorization: Bearer jgb_your_api_key"

    The same request from code:

    Node.js
    // 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`);
    Python
    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_.

    Header
    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:

    Response shape
    {
      "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:

    Node.js
    // 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 body
    {
      "error": {
        "code": "unauthorized",
        "message": "Invalid or revoked API key."
      }
    }
    StatusCodeMeaning
    401unauthorizedThe Authorization header is missing or malformed, or the key is wrong or revoked.
    403plan_requiredThe account's plan no longer includes API access (Enterprise).
    404not_foundThe resource does not exist in your account.
    429rate_limitedMore than 120 requests in a minute with this key. Wait a minute and retry.
    500server_errorSomething 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 from set to the time of your last sync.
    • Retry 429 and 500 responses after a short wait; do not retry 401, 403 or 404.
    GET/products

    List products

    Every product in your inventory, newest first.

    Parameters

    List products parameters
    NameTypeDescription
    pageintegerPage to return, starting at 1. Default 1.
    perPageintegerRows per page, up to 100. Default 50.

    Response fields

    List products response fields
    NameTypeDescription
    idstringProduct ID.
    namestringProduct name.
    skustring | nullYour SKU or item code.
    categorystring | nullCategory.
    pricenumberSelling price, in INR.
    costnumberCost price, in INR.
    quantityintegerUnits in stock.
    minStockintegerLow-stock threshold.
    cgstPercentnumberCGST rate, in percent.
    sgstPercentnumberSGST rate, in percent.
    createdAtstringCreated (ISO 8601, UTC).
    updatedAtstringLast changed (ISO 8601, UTC).
    Request
    curl "https://sherut.j-gene.com/api/v1/products?perPage=2" \
      -H "Authorization: Bearer jgb_your_api_key"
    Response 200
    {
      "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 }
    }
    GET/customers

    List customers

    Every customer in your account, newest first.

    Parameters

    List customers parameters
    NameTypeDescription
    pageintegerPage to return, starting at 1. Default 1.
    perPageintegerRows per page, up to 100. Default 50.

    Response fields

    List customers response fields
    NameTypeDescription
    idstringCustomer ID.
    namestringCustomer name.
    emailstring | nullEmail address.
    phonestring | nullPhone number.
    addressstring | nullAddress.
    businessNamestring | nullBusiness name, for business customers.
    createdAtstringCreated (ISO 8601, UTC).
    Request
    curl "https://sherut.j-gene.com/api/v1/customers" \
      -H "Authorization: Bearer jgb_your_api_key"
    Response 200
    {
      "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 }
    }
    GET/invoices

    List invoices

    Bills and invoices, newest first, with optional filters. Line items are not included; fetch one invoice for those.

    Parameters

    List invoices parameters
    NameTypeDescription
    pageintegerPage to return, starting at 1. Default 1.
    perPageintegerRows per page, up to 100. Default 50.
    statusstringOnly "PENDING" or only "PAID" invoices.
    channelstring"billing" for counter bills or "invoice" for tax invoices.
    customerIdstringOnly invoices for this customer.
    fromdate-timeCreated at or after this time, e.g. 2026-10-01 or 2026-10-01T00:00:00Z.
    todate-timeCreated at or before this time.

    Response fields

    List invoices response fields
    NameTypeDescription
    idstringInvoice ID.
    channelstring"billing" for a counter bill, "invoice" for a tax invoice.
    statusstring"PENDING" or "PAID".
    customerIdstringThe customer the invoice is for.
    customerNamestringThat customer's name.
    subtotalnumberTotal of the line items before taxes and discount, in INR.
    taxPercentnumberAdditional tax rate applied to the subtotal, in percent.
    discountPercentnumberDiscount rate, in percent.
    cgstTotalnumberTotal CGST, in INR.
    sgstTotalnumberTotal SGST, in INR.
    otherChargesTotalnumberTotal of other charges, in INR.
    totalnumberAmount payable, in INR.
    advanceAmountnumberAmount already received in advance, in INR.
    branchIdstring | nullBranch the invoice belongs to, if branches are used.
    createdAtstringWhen the invoice was created (ISO 8601, UTC).
    paidAtstring | nullWhen it was marked paid, or null.
    Request
    curl "https://sherut.j-gene.com/api/v1/invoices?status=PAID&from=2026-10-01T00:00:00Z" \
      -H "Authorization: Bearer jgb_your_api_key"
    Response 200
    {
      "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 }
    }
    GET/invoices/{id}

    Get an invoice

    One invoice with its line items. Returns 404 if the ID is not an invoice in your account.

    Parameters

    Get an invoice parameters
    NameTypeDescription
    idstring (path)The invoice ID.

    Response fields

    Get an invoice response fields
    NameTypeDescription
    idstringInvoice ID.
    channelstring"billing" for a counter bill, "invoice" for a tax invoice.
    statusstring"PENDING" or "PAID".
    customerIdstringThe customer the invoice is for.
    customerNamestringThat customer's name.
    subtotalnumberTotal of the line items before taxes and discount, in INR.
    taxPercentnumberAdditional tax rate applied to the subtotal, in percent.
    discountPercentnumberDiscount rate, in percent.
    cgstTotalnumberTotal CGST, in INR.
    sgstTotalnumberTotal SGST, in INR.
    otherChargesTotalnumberTotal of other charges, in INR.
    totalnumberAmount payable, in INR.
    advanceAmountnumberAmount already received in advance, in INR.
    branchIdstring | nullBranch the invoice belongs to, if branches are used.
    createdAtstringWhen the invoice was created (ISO 8601, UTC).
    paidAtstring | nullWhen it was marked paid, or null.
    itemsarrayLine items: id, productId, name, price, quantity, subtotal, cgstAmount, sgstAmount, otherChargesAmount.
    Request
    curl "https://sherut.j-gene.com/api/v1/invoices/0d9b8a7c-6e5f-4d3c-2b1a-0f9e8d7c6b5a" \
      -H "Authorization: Bearer jgb_your_api_key"
    Response 200
    {
      "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
          }
        ]
      }
    }
    GET/transactions

    List transactions

    Stock transactions (sales, purchases, expenses and refunds), newest first.

    Parameters

    List transactions parameters
    NameTypeDescription
    pageintegerPage to return, starting at 1. Default 1.
    perPageintegerRows per page, up to 100. Default 50.
    typestring"sale", "purchase", "expense" or "refund".
    searchstringCase-insensitive match on customer name or notes.

    Response fields

    List transactions response fields
    NameTypeDescription
    idstringTransaction ID.
    typestring"sale", "purchase", "expense" or "refund".
    productIdstring | nullProduct involved.
    quantitynumberUnits.
    unitPricenumberPrice per unit, in INR.
    totalAmountnumberTotal, in INR.
    customerNamestring | nullCustomer or supplier name.
    notesstring | nullNotes.
    transactionDatestringDate of the transaction.
    createdAtstringRecorded (ISO 8601, UTC).
    Request
    curl "https://sherut.j-gene.com/api/v1/transactions?type=sale&perPage=20" \
      -H "Authorization: Bearer jgb_your_api_key"
    Response 200
    {
      "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 }
    }
    GET/expenses

    List expenses

    Expenses from the expense tracker, newest first.

    Parameters

    List expenses parameters
    NameTypeDescription
    pageintegerPage to return, starting at 1. Default 1.
    perPageintegerRows per page, up to 100. Default 50.
    categorystringOnly expenses in this category, e.g. Rent.
    searchstringCase-insensitive match on vendor, notes or category.

    Response fields

    List expenses response fields
    NameTypeDescription
    idstringExpense ID.
    categorystringCategory.
    amountnumberAmount, in INR.
    vendorstring | nullWho was paid.
    notesstring | nullNotes.
    paymentMethodstring | nullHow it was paid, e.g. Bank Transfer.
    expenseDatestringDate of the expense.
    isRecurringbooleanWhether it repeats.
    recurringFrequencystring | nullHow often it repeats, if recurring.
    createdAtstringRecorded (ISO 8601, UTC).
    Request
    curl "https://sherut.j-gene.com/api/v1/expenses?category=Rent" \
      -H "Authorization: Bearer jgb_your_api_key"
    Response 200
    {
      "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