List Columns and Saved Layouts API¶
Applies to: All subscriptions (Audit Logs, saved layouts) · e-Invoice · e-Way Bill · Which modules do I have?
Purpose¶
Explain two things a team reading Complifly's list endpoints directly needs to know since October 2026.
The fact that changes what you do: the list endpoints return a fixed base
set of fields. Any other field you want — the IRN, the NIC error message, the
tax split, transport details — you must ask for by name with
?cols=. A field you do not ask for is not in the response, and a field that
is not in the endpoint's published list below cannot be obtained this way at
all, whatever you send.
These are application endpoints, not a versioned integration contract (see Endpoint Index). Pin to the fields listed here and ignore the rest.
Audience¶
Integration developers and administrators who read Complifly's list endpoints from their own reporting or reconciliation tools, and administrators supporting users who ask why a column is or is not available.
Prerequisites¶
- API Authentication — a user token. Each list
endpoint keeps its existing permission (for example
irn.viewfor the IRN workbench,audit.viewfor audit logs).colsnever widens what a role may see. - An active GSTIN in the
X-GSTINheader, as for every GSTIN-scoped call.
Reference¶
Requesting extra columns — ?cols=¶
Add a comma-separated list of column keys:
GET /api/irn/workbench?cols=irn,errorMessage,cgst,sgst
Each extra field comes back on every row under the key you asked for.
| Behaviour | Detail |
|---|---|
| Unknown key | Ignored silently. No error, no field |
| Key not in the endpoint's list | Ignored silently, even if a database column of that name exists |
| Invalid key (spaces, punctuation) | Ignored silently |
| More than 120 keys | Only the first 120 are considered |
Omitted cols |
Base fields only — the same response as before October 2026, except Audit Logs (below) |
Because unknown keys are ignored rather than rejected, check that the field you asked for is present before relying on it. A typo returns a row without the field, not an error.
What each endpoint offers¶
| Endpoint | Extra columns you may request |
|---|---|
GET /api/irn/workbench |
discount, otherCharges, roundOff, totalFc, buyerTradeName, buyerPin, buyerPlace, shipToGstin, shipToName, shipToState, dispatchFromName, dispatchFromPlace, dispatchFromState, precDocNo, precDocDate, poRef, poRefDate, expShipBillNo, expShipBillDate, expPort, expCountry, expCurrency, payMode, payDue, payCreditDays, payPaid, ewbValidTill, transDocNo, transDocDate, errorCode, errorMessage, cancelDate, cancelReason, cancelRemark, gspProvider, docSource, sourceSystem, erpRef, uploadJob, createdBy, updatedBy, updatedAt, revisionNo, revisionSource, fiscalYear |
GET /api/ewb-doc/list |
recipientName, toPlace, toPin, toState, taxable, total, cgst, sgst, igst, cess, vehicleNo, transMode, transporterId, transporterName, distance, transDocNo, transDocDate, partASlip, partBProvided, errorCode, errorMessage, cancelReason, cancelRemark, generationMode, gspProvider, erpRef, sourceSystem, createdAt, createdBy, updatedBy, updatedAt |
GET /api/ewb/list |
recipientGstin, recipientName, totalValue, cgst, sgst, igst, cess, transMode, distance, transDocNo, transDocDate, fromState, generationMode, processingRoute, nicAlert, cancelReason, cancelRemark, errorCode, errorMessage, gspProvider, createdBy, createdAt, updatedBy, updatedAt |
GET /api/cewb/list |
validUpto, cewbDate, transMode, transporterId, generatedBy, errorCode, errorMessage, previousEwb, tripStart, gspProvider |
GET /api/correction/invoices |
fileName, taxable, cgst, sgst, igst, caseRef, supplierGstin, pos, supplyType, uploadedBy |
GET /api/intelligence/list-findings |
transporterId |
GET /api/admin/audit-logs |
sessionId, userAgent, and orgId (Super Admin only — the key is ignored for every other role) |
Long free-text fields (errorMessage, cancelRemark, nicAlert,
userAgent) are cut to a few hundred characters in a list. The full text is
on the document's own detail endpoint.
What you can never request¶
Phone numbers and e-mail addresses (personal data under the DPDP Act), payee bank account details, credential identifiers such as the audit log's token ID, raw NIC and upload payloads, and internal keys. These are left out of the lists above on purpose, and the server enforces it: asking for them by any name returns nothing.
Changes to base fields in October 2026¶
| Endpoint | Change | What to do |
|---|---|---|
GET /api/irn/workbench |
Adds irn (the 64-character IRN) and doc_type (INV, CRN, DBN) |
Nothing — additive |
GET /api/ewb/list |
Adds ewb_date, doc_date, from_pincode, to_pincode, from_place_name, to_place_name, transporter_id, transporter_name |
Read these instead of from_place, to_place and doc_dt. Those three keep their old content for compatibility: from_place / to_place hold the PIN codes and doc_dt holds the e-Way Bill date, not the document date |
GET /api/cewb/list |
status is now GENERATED, REGENERATED or FAILED. It was the constant ACT on every row. Adds to_place (the delivery places of the bills on the sheet) |
If you matched on status = 'ACT', match on GENERATED or REGENERATED instead |
GET /api/ewb-doc/list |
Adds api_name, the NIC operation that produced the bill |
Nothing — additive |
GET /api/irn/workbench, GET /api/ewb-doc/list, GET /api/ewb/list, GET /api/dashboard/irn-detail, GET /api/dashboard/ewb-detail |
Add irn_state and/or ewb_state: the document's status as one of a small fixed set of values (see Canonical status fields) |
Nothing — additive. Every existing status field (irn_status, ewb_status, status) is unchanged, in name, value and meaning |
GET /api/correction/invoices |
Adds BillTo_Gstin, the buyer's GSTIN |
Use it for the buyer. GSTIN is the uploading registration, not the buyer |
GET /api/admin/audit-logs |
OrgId is no longer in the base response. Super Admin can request it with cols=orgId |
If you read OrgId, a non-Super-Admin caller already only ever receives its own organisation's rows, so the value was constant. Drop the dependency, or call as Super Admin with cols=orgId |
Canonical status fields¶
Five list responses carry irn_state and/or ewb_state next to the status fields they always had. The raw status
fields are not touched. The same status can be spelled several ways in stored data (ACT and ACTIVE, CNL
and CANCELLED); the state fields give you one value to match on.
| Field | Values | Where |
|---|---|---|
irn_state |
NOT_GENERATED, GENERATED, CANCELLED, FAILED, EWB_ONLY, IN_DOUBT, UNKNOWN |
/api/irn/workbench, /api/ewb-doc/list, /api/dashboard/irn-detail |
ewb_state |
NOT_GENERATED, ACTIVE, CANCELLED, EXPIRED, DELIVERED, FAILED, UNKNOWN |
/api/irn/workbench, /api/ewb-doc/list, /api/ewb/list, /api/dashboard/ewb-detail |
IN_DOUBTmeans NIC has not confirmed the IRN. It comes from the stored statusINDETERMINATE: the request timed out or came back unclear, so the IRN may already exist. Do not treat it asNOT_GENERATEDorFAILED, and do not resubmit corrected data; resubmitting the document unchanged is the supported way to settle it.- A document stored as
EWB_PENDINGisEWB_ONLYforirn_stateandNOT_GENERATEDforewb_state: it has no IRN and is waiting for its e-way bill. UNKNOWNmeans the stored status is not one the product recognises. Do not treat it as "not generated". On/api/ewb/listand/api/dashboard/ewb-detailevery row is an existing e-way bill, so a row with no status isUNKNOWN, neverNOT_GENERATED.irn_statuson/api/ewb/listis a different thing (GENERATED,NOT_APPLICABLEorMISSING: whether the source invoice has an IRN). That endpoint has noirn_state.- Treat the value set as open: write your code so that a value it does not know is handled, not a failure.
Paged lists — grid=2 (IRN Workbench)¶
The fact that changes what you do: GET /api/irn/workbench returns at most the newest 1,000 documents, in one array, with no
filter parameters, and a registration with more than 1,000 documents cannot reach the oldest ones through it. Add grid=2 and,
only for a registration whose ENTERPRISE_GRID_V2 control is on (off by default, Super Admin only; see
Feature flags), you get one page at a time, filtered, searched and sorted by the server, over
every document. A request without grid is answered exactly as before. With the control off, grid=2 is refused with
403 FEATURE_DISABLED_BY_OPERATOR.
The paged form is one registration only: the header x-gstin must name a GSTIN (all is refused with 400 GSTIN_REQUIRED).
| Parameter | Meaning | Limits |
|---|---|---|
grid=2 |
Selects the paged form | Required; any other value is 400 GRID_VERSION |
page, size |
1-based page and rows per page | size 10 to 200, default 50; page up to 100,000 |
sort |
key:dir, comma-separated, dir is asc (default) or desc |
At most 3 keys, from the sort keys below |
f |
A filter, key:operator:value. Repeat the parameter for more filters (they are ANDed) |
At most 10 filters; at most 25 values each, each at most 40 printable ASCII characters |
q |
Search: the characters you type must appear in that order, anywhere in the document number or the buyer name, ignoring case (so invc123 finds INV-2025-00123) |
At most 40 characters |
fy, month |
The financial-year filter: fy=2026-27, month=all or 1 to 12. A document with no date is not excluded |
month needs fy |
attention or finding |
Only the documents an Attention Center rule (attention=IRN_WINDOW_PASSED) or one finding (finding=42) points at. Only rules your role may see match |
Not both |
facets=only |
Return the distinct values and counts the filter dropdowns offer, and no rows | See "What is slow" |
cols |
Extra columns, as above | Unchanged |
Sort keys: doc_no, doc_date, doc_type, buyer_name, supply_type, irn_status, total_invoice_value, taxable_value,
created_at. Ties always end in the same order the unpaged list uses, so a page does not reshuffle between requests. The e-way bill
status cannot be sorted on (it lives in two other tables).
Filter keys (operator in takes comma-separated values; doc_date takes between a,b, before or after, with dates as YYYY-MM-DD):
| Key | Matches |
|---|---|
irn_state, ewb_state |
The status as the new status vocabulary reads it: GENERATED, FAILED, IN_DOUBT and the other canonical states from Canonical status fields, plus EWB_PENDING, and RAW:<WORD> for a word the product does not recognise. Two spellings of one state (ACT, ACTIVE) match together |
irn_status, ewb_status |
The stored word itself, compared ignoring case but not spaces (Pending, ACT). Use this when you want exactly what the older screens filter on |
supply_type |
B2B, EXPWP, SEZWP and so on |
doc_type |
INV, CRN, DBN; a blank type counts as INV |
doc_date |
The document date |
Response
{ "grid": 2, "page": 1, "size": 50, "total": 838, "pages": 17, "rows": [ { "inv_hdr_id": 7077, "doc_no": "INMF26-0000132", "irn_status": "ACTIVE", "irn_state": "GENERATED", "ewb_state": "NOT_GENERATED" } ] }
Rows have the same fields as the unpaged list (including irn_state and ewb_state). total is every document behind your
filters, not the page. facets=only returns { "grid": 2, "facets": { "irn_status": [ { "value": "ACTIVE", "count": 413 } ], "ewb_status": [...], "supply_type": [...], "doc_type": [...] } }.
Errors. Each is 400 with { "code", "message" } and runs no query; an unknown parameter, key or operator is refused
rather than ignored, because a filter that is silently dropped shows the wrong documents with no error.
See Platform error codes.
What is slow. Everything above answered in under a second (0.2 to 0.9 s) for 90,000 documents on one registration, on the
machine we measured on, with two exceptions. A filter on the e-way bill status (ewb_state, ewb_status) and the ewb_status facet read the e-invoice
and e-way bill tables for every document, and those tables are guarded by row-level security that looks each row up in the document
table. Before Complifly applies the faster lookup to the database that was about 8 seconds at that size; in our test with the faster lookup it was about 1.5 seconds. The time is in proportion to the number of documents on the registration (roughly 10 times less at 9,000). The
screen therefore asks for facets in a request of its own, after the first page is shown.
Saved layouts — /api/layouts¶
Stores each user's column layout per screen, so it follows them across browsers. Used by the Layout Management dialog; documented here so an administrator can see what is stored.
| Method | Path | Body | Returns |
|---|---|---|---|
GET |
/api/layouts |
— | { layouts: { "<layoutKey>": { columnsVisible, order, updatedAt } } } for the caller |
PUT |
/api/layouts/{layoutKey} |
{ "order": ["docNo", "irn", …] } |
{ layout: { columnsVisible, order } } |
DELETE |
/api/layouts/{layoutKey} |
— | 204 |
Any signed-in user may call these; they only ever act on the caller's own layouts. The user and organisation come from the token, never from the request. A layout holds column keys only, never data.
| Response | Condition |
|---|---|
400 — Invalid layout key |
layoutKey is not lower-case letters, digits, _ or -, 3–100 characters |
400 — order must be an array |
order missing or not an array |
400 — order contains an invalid column key |
A key is not a plain identifier |
400 — order has too many columns |
More than 150 keys |
401 |
No valid token |
Validation¶
- Call a list endpoint with
?cols=naming one field from the table and one made-up key. The response contains the real field and not the made-up one. - As a role other than Super Admin, call
/api/admin/audit-logs?cols=orgId. The rows carry noorgId. PUTa layout, thenGET /api/layoutsfrom a different browser signed in as the same user. The layout is returned.
Troubleshooting¶
| Symptom | Cause | Action |
|---|---|---|
| A field you asked for is missing from every row | The key is misspelt, or the endpoint does not offer it | Check the key against the table above; keys are case-sensitive |
Audit log rows lost OrgId after an upgrade |
OrgId moved out of the base response in October 2026 |
Request cols=orgId as Super Admin, or drop the dependency |
from_place shows a six-digit number |
It is the legacy PIN-code alias | Read from_place_name and from_pincode |
403 FEATURE_DISABLED_BY_OPERATOR on grid=2 |
ENTERPRISE_GRID_V2 is off for the registration |
A Complifly Super Admin switches it on for that GSTIN, or call without grid |
| Paging through the unpaged list never shows an older document | The unpaged list stops at the newest 1,000 documents | Use grid=2 once the control is on |
| Filtering by e-way bill status takes several seconds on a very large registration | That filter reads two guarded tables for every document | Filter by IRN status or search first; see "What is slow" above |
| A user's columns differ between two browsers | The layout was changed in one browser while the server could not be reached; that copy stayed local | Open Layout Management in the browser with the wanted layout and select Apply Layout again |