Run billing now#
/v1/invoicesTurns your agent group's outstanding POSTED charges into ISSUED invoices, without waiting for the scheduled run. Each one is numbered from its registration's filed series, rendered to a PDF and given a Razorpay order, exactly as the scheduled run does it.
This is the same engine the scheduled run uses. There is no second selection, grouping or tax path: an invoice produced here is identical to the one the schedule would have produced from the same charges. With an empty body it bills the billing period that has most recently CLOSED for your group, derived from your billing cycle and anchor day — precisely what the schedule bills.
Re-running is safe and is not a way to bill twice. The run compares the invoice lines that already exist against the properties on each booking and bills only the difference, and the database refuses a second line for the same charge and property outright. Two runs over the same period produce one set of invoices.
Read blockedStates and unreconciledEntries, not just invoiceIds. A run that invoices four states and holds a fifth back — because we have no GST registration for it — is reported here as a success with that state listed. Nothing will invoice those charges until the registration exists.
The result is ISSUED invoices. Each carries a number from its registration's filed series, an issue date, a due date from your credit terms, a PDF and a Razorpay order, and appears immediately on GET /v1/invoices. An invoice the run could not issue is left a DRAFT — its id is still returned, and the next run that touches it tries again.
Bounded deliberately. A run takes an exclusive lock on your group's billing, so this endpoint is throttled well below the general rate limit; a rejected run is a 429 with Retry-After. It is not a polling endpoint — the schedule bills every closed period without being asked.
Request
curl -X POST 'https://partner-api.elivaas.com/v1/invoices' \
-u "$ELIVAAS_API_KEY:" \
-H 'Content-Type: application/json' \
-d '{"from":"2026-07-01","to":"2026-07-31","bookingIds":["BK-2026-000123","BK-2026-000124"]}'const res = await fetch('https://partner-api.elivaas.com/v1/invoices', {
method: 'POST',
headers: {
Authorization: 'Basic ' + Buffer.from(process.env.ELIVAAS_API_KEY + ':').toString('base64'),
'Content-Type': 'application/json',
},
body: JSON.stringify({"from":"2026-07-01","to":"2026-07-31","bookingIds":["BK-2026-000123","BK-2026-000124"]}),
});
if (!res.ok) throw new Error(`${res.status} ${await res.text()}`);
const data = await res.json();import os, requests
res = requests.post(
"https://partner-api.elivaas.com/v1/invoices",
auth=(os.environ["ELIVAAS_API_KEY"], ""),
json={"from":"2026-07-01","to":"2026-07-31","bookingIds":["BK-2026-000123","BK-2026-000124"]},
timeout=30,
)
res.raise_for_status()
data = res.json(){
"periodFrom": "2026-07-01",
"periodTo": "2026-07-31",
"cutoff": "2026-08-01T00:00:00Z",
"invoiceIds": [
"3fa85f64-5717-4562-b3fc-2c963f66afa6"
],
"linesWritten": 12,
"blockedStates": [
{
"state": "Himachal Pradesh",
"lineCount": 3,
"taxableValue": 45000
}
],
"skippedEntries": [
{
"ledgerEntryId": "3fa85f64-5717-4562-b3fc-2c963f66afa6",
"bookingId": "string",
"reason": "string"
}
],
"unreconciledEntries": [
{
"ledgerEntryId": "3fa85f64-5717-4562-b3fc-2c963f66afa6",
"bookingId": "string",
"chargedAmount": 23600,
"billedAmount": 22400
}
]
}Request body#
fromstring<date>Inclusive start of the billing window recorded on the invoice. Must be supplied together with
to, and not together withbookingIds.tostring<date>Inclusive end of the billing window. Charges are selected up to the END of this day.
This bounds what is recorded on the invoice, not only what is selected. The run also picks up any still-unbilled charge OLDER than
from— that is deliberate, and is what stops a charge left unbilled by an earlier run (for example a property in a state whose GST registration had not been configured yet) from being stranded forever behind a lower bound nothing revisits.bookingIdsstring[]Bill only these bookings. At most 100 per request. Ids that are not yours, do not exist, or have no POSTED charge are silently not billed — the selection is scoped to your agent group in SQL, so there is nothing to reject. Cannot be combined with
from/to.
Responses#
| Status | Meaning |
|---|---|
200 | What the run billed, and what it refused to bill. |
400 | Validation failure. The message names the offending parameter. Limits are rejected, never silently clamped: an over-length id list, a page size above 100 or a date window longer than 365 days all land here rather than coming back quietly truncated. |
401 | Missing, malformed, revoked or unknown API key, or an agent group whose distribution access is disabled. Pass the key as the HTTP Basic username with an empty password. |
429 | Rate limit exhausted for this credential. Wait Retry-After seconds before retrying; the budget is per credential, not per IP. |
See Errors for the error body shape and which statuses are worth retrying.