Skip to content

Platform Error Codes

Applies to: All subscriptions

Purpose

Interpret the coded errors Complifly itself returns — authentication, authorisation, document state — and know immediately which are transient, which are terminal, and who resolves each.

Audience

Integration developers, administrators, support teams.

Prerequisites

Reference

Authentication

Code HTTP Meaning Fixed by Retry?
TOKEN_MISSING 401 No credential presented you No — send the header
TOKEN_INVALID 401 Malformed, wrong audience, wrong issuer, or a bad signature you No — fix the credential
TOKEN_EXPIRED 401 Expired, or the clocks disagree you Yes, once, after refreshing
OAUTH_REQUIRED 403 This client has been switched to identity-provider tokens; the static key is refused admin No — complete the migration
ROLE_MISSING 403 The token is valid but lacks the required application role admin No — grant admin consent
CLIENT_NOT_ONBOARDED 403 The token's directory and application together are not a connection Complifly serves, or the connection is not live admin No — finish onboarding
SESSION_REVOKED 401 A signed-in user's session was ended before the token expired. The body carries a reason you, or admin when the reason is an administrator's action No — sign in again
PASSWORD_TOO_SHORT, PASSWORD_TOO_LONG, PASSWORD_BLANK 400 A new password is under 8 characters, over 72 bytes, or only spaces. Returned by change-password, reset-password and an administrator creating a user you Yes, with a password that meets the rule
SESSION_REVOKE_FAILED 500 The person's sessions could not be ended. When it came with an edit or a delete, nothing was changed: the edit is not saved while its sessions cannot be ended admin Yes — repeat the same request; if it keeps failing, treat it as a platform incident

TOKEN_EXPIRED recurring after a refresh points at clock drift, not at the credential. Token validation is time-sensitive; check time synchronisation on both hosts.

SESSION_REVOKED says why

When an administrator removes or changes someone's access, that person is signed out on their next request, and the response says why. A user token is only valid while its session is live, and a role, approval role or GSTIN list is fixed into the token when the person signs in. Ending the session is therefore the only way a change reaches someone who is already signed in.

reason What happened What happens next
ACCOUNT_DEACTIVATED An administrator disabled the account The person cannot sign in again until an administrator re-enables it
ACCOUNT_DELETED An administrator removed the account As above; an administrator must recreate it
ROLE_CHANGED The system role changed The person signs in again and gets the new role
ACCESS_CHANGED The approval role, the GSTIN access or the primary GSTIN changed The person signs in again and gets the new access
ADMIN_ENDED An administrator used End sessions The person can sign in again straight away
logout, logout_all, concurrent_limit, user_terminated The person ended it themselves, or signed in elsewhere Nothing to fix

An edit that changes none of the role, approval role, GSTIN list or primary GSTIN, such as a name change, does not end anyone's session.

SESSION_REVOKE_FAILED on an edit or a delete means nothing was changed. The edit and the ending of the person's sessions are one all-or-nothing step: an access change is not saved while the person could still use the old access. The body says changeSaved: false, the user still has their old role and access, and repeating the same request is a real retry. On the End sessions action by itself there was no change to save; the body has no changeSaved, and the message says only that the sessions could not be ended.

Why it is built this way matters if you script against the API: a 500 that left the change saved would have made a retry of the same edit do nothing, because the stored role already matched the request, and would have left a deleted user's token valid with no way to end it. The failure is recorded in the audit log as SESSIONS_REVOKE_FAILED, with changeRolledBack.

CLIENT_NOT_ONBOARDED is about the pair, not the application

Complifly recognises an integration as this application, in this directory. An application ID on its own identifies nobody: the same application can be installed in many directories and keeps the same ID in each.

So this code has several distinct causes that look identical from the outside, and the message deliberately does not say which — telling an unauthenticated caller which half matched would let anyone enumerate other customers' integrations.

Cause How to tell
Onboarding never finished — Complifly has your directory but not your application ID Ask for the connection's stage. AWAITING_CLIENT means exactly this
The ERP moved to a different app registration Compare the appid in your token against what you sent Complifly
The token came from a different directory than the one recorded Compare the tid in your token against your Directory (tenant) ID
The connection was suspended Ask your Complifly contact

Decode the token and check tid and appid before reporting a fault. Between them they identify the connection, and the answer is almost always visible there.

Authorisation

Code HTTP Meaning Fixed by Retry?
GSTIN_NOT_PERMITTED 403 The document's supplier registration is outside the credential's scope. From the user-administration endpoints (POST /users, PUT /users/{id}): an Org Admin tried to grant a GSTIN not registered under their own company; the body carries gstins, the ones refused admin No
FORBIDDEN 403 The document does not belong to this credential's company admin No
PERMISSION_DENIED 403 Application routes, user token. The caller's role does not hold the permission the route needs. The body carries permission (for example tds.view) and a message naming the role. Nothing was changed and the attempt is audited admin No — give the user a role that holds it
PLATFORM_ROLE_REQUIRES_SUPER_ADMIN 403 User administration (POST /users, PUT /users/{id}). An Org Admin tried to assign super_admin, support_engineer or platform_engineer. These are Complifly's own roles and reach across customers. Nothing was changed; the attempt is audited as ACCESS_DENIED support No. Only a Complifly Super Admin can assign them
PLATFORM_USER_NOT_MANAGEABLE 403 User administration (PUT, DELETE, POST /users/{id}/end-sessions). An Org Admin tried to change, deactivate, delete or sign out a person who holds a platform role in their company. Nothing was changed; audited support No
ROLE_NOT_CLASSIFIED 403 User administration. The role exists but is neither a platform nor a tenant role (for example the legacy admin), so nobody can assign it, and an Org Admin cannot manage its holder unless the edit moves them onto a tenant role admin Yes: edit the person and choose a standard role
UNKNOWN_ROLE 403 User administration. role is not a role that exists, or is not one the caller may assign (names are exact: Super_Admin is unknown). The message lists the roles this caller may assign you Yes, with a listed role
ROLE_ASSIGNMENT_NOT_PERMITTED 403 User administration. The caller's role may not assign or manage system roles at all admin No
SIGNUP_RETIRED 410 POST /api/auth/signup no longer exists. It created users with no role and no company you No. Use POST /api/admin/users
Missing registration header 400 A user-token call omitted the registration header you No

When it comes back from user administration, it is a company-boundary refusal, not a credential problem. An Org Admin may grant only GSTINs registered under their own company, and a refused request saves nothing. The answer is the same whether the GSTIN belongs to another company or does not exist, so it cannot be used to discover other companies' registrations. Only a Super Admin can grant across companies; see GSTIN Access Control.

Otherwise, GSTIN_NOT_PERMITTED is a credential scope problem, not a user permission problem. It is the single most misdiagnosed platform error: teams check the user's role, find it correct, and conclude the system is broken.

Where that scope comes from depends on the credential, which is worth knowing before you go looking for it:

Credential Scope
OAuth connection The GSTIN list attached to that connection, set at onboarding
Static key with a recorded GSTIN That one registration
Static key without one Every GSTIN registered under the key's company

A registration added to the company after an OAuth connection was onboarded is not automatically in that connection's list. This is deliberate — an ERP's authority should not widen because someone registered a new GSTIN elsewhere — but it does mean a new registration needs the connection updated.

Access explanations

Returned by /api/admin/access/*, the read-only API behind the Access tab. See Administration API.

Code HTTP Meaning Fixed by Retry?
INVALID_PERMISSION 400 permission is not a permission this build knows you Yes, with a key from GET /access/permissions
GSTIN_REQUIRED 400 A registration-level permission was asked without a gstin you Yes, name the registration. Organisation-level permissions (tds.*) need none
USER_REQUIRED 400 No userId you Yes
COMPANY_REQUIRED 400 Complifly staff or a Super Admin called /people without companyId you Yes
NO_ORGANISATION 403 A company-scoped caller's token names no organisation admin No, sign in again as a user with a company
NOT_FOUND 404 No such user or registration in the caller's company. The same answer whether it belongs to another company or does not exist you No
PART_REQUIRED 400 GET /access/review with format=csv and no part. A CSV holds one table you Yes, with part=people, registrations, changes, basis or summary
INVALID_FORMAT, INVALID_DATE, INVALID_RANGE, INVALID_ASOF, RANGE_TOO_LARGE 400 /access/review input the server cannot use: a format other than json or csv; from, to or asOf not a date; from after to; asOf in the future; a period longer than 400 days. Nothing is produced you Yes, corrected. Run one review per quarter
EXPLAIN_FAILED, PEOPLE_FAILED, MATRIX_FAILED, REVIEW_FAILED 500 The facts could not be read support Yes, once. Persisting: report it with the request id

Integration policy limits

Returned to an ERP or agent when a limit on Integration Policies is hit. The ERP cannot change a limit; the customer asks Complifly.

Code HTTP Meaning Fixed by Retry?
RATE_LIMIT 429 More requests in a minute than the connection's limit you — slow down; or support to raise it Yes, after the minute
SPIKE_ARREST 429 More requests in one second than allowed, even inside the per-minute limit you — pace the batch Yes, after a second
CONCURRENCY_LIMIT 429 Too many requests in progress at once you — reduce parallelism Yes, when one completes
IP_NOT_ALLOWED 403 The caller's address is not on the allowlist support — the allowlist is set by Complifly No
GSTIN_LIMIT 403 The plan's number of GSTINs is reached and this is a new one support No

There is no quota code. The monthly invoice quota is advisory: an invoice over it is accepted and the overage is recorded, so an ERP never sees QUOTA_EXCEEDED (retired 2026-10-24).

Document state

Code HTTP Meaning Fixed by Retry?
DUPLICATE 409 The document number already exists you Never — permanent
NOT_FOUND 404 No such document you No
IRN_ALREADY_CANCELLED — The reference number is already cancelled you No
STATUS_LOCK — The document is in a state that does not allow this action you No
INDETERMINATE_PAYLOAD_CHANGED — A previous attempt's outcome is unknown, and the document has since changed support No
EWB_IN_DOUBT — An e-way bill request may have reached NIC and the answer did not come back, so it is not known whether the bill exists. It is in the result body as errorCode, with inDoubt: true, and the document is recorded as failed support, or you after checking the e-way bill dashboard Not until the state is confirmed
EWB_GENERATION_IN_PROGRESS 409 An e-way bill is being generated for this document right now. The request was not sent and the document was not changed you Yes — after a few seconds
EWB_ALREADY_EXISTS 409 The document already has a live e-way bill. Returned by the standalone flow, and now also by generation from an IRN you No
LOCAL_VALIDATION — Validation failed before submission you No
NIC_PRINT_WINDOW_CLOSED 422 The official NIC print copy is no longer obtainable statute Never
CONCURRENT_MODIFICATION 409 Someone else changed this record since you last read it (a stale rowVersion, or the equivalent editable-state check) you Yes — reload the current version and re-apply your change
WORKFLOW_VIOLATION 409 The action doesn't fit the record's current state (e.g. it moved to a terminal status such as DELIVERED/CANCELLED between your read and your write) you No — reload to see the current state; the action may no longer be valid at all

NIC_PRINT_WINDOW_CLOSED deserves its own explanation, because the underlying provider message reads like a fault to fix and is not. The government serves the official e-invoice copy for two days after generation. Complifly fetches and caches it at generation time so it survives that window — but where no copy was cached, it becomes permanently unobtainable.

Retrying cannot help, and neither can support. Use Branded Print, which renders from the signed invoice and signed QR captured at generation; that stored evidence is what makes an e-invoice print valid in the first place.

EWB_IN_DOUBT is the e-way bill counterpart of an indeterminate IRN outcome, with one difference that matters to anyone scripting against it. An IRN that may have been registered is retried automatically, because a repeat is answered with the existing IRN. An e-way bill that may have been issued is never retried automatically, because a repeat has no such answer: it could register a second bill, or be refused as a duplicate and make a document that has a live bill look as if it failed. A request that provably never left (no connection at all, or the provider's "busy" or "unavailable") is retried, a few times, with the same content each time. An ERP that integrates with Complifly is not sent an e-way bill failure for a document that is in doubt, because an ERP that believes NIC refused it would regenerate it.

INDETERMINATE_PAYLOAD_CHANGED deserves explanation. It arises when a submission's outcome could not be determined — a timeout, typically — and the document was then edited. The platform refuses to resubmit, because it cannot tell whether the original was registered, and resubmitting a changed payload under the same number risks either a duplicate or a document that does not match what was registered. Do not force it. Establish the true state first.

Approval workflow

Returned by the Invoice Generation approval endpoints when the multi-level Approval Engine (IGM_APPROVAL_ENGINE) is on.

Code HTTP Meaning Fixed by Retry?
ROLE_MISMATCH 403 The caller's approval role is not the one this level requires admin No — the right approver must act, or an administrator must override
SELF_APPROVAL 403 The caller submitted this document and cannot also decide it. Also returned by POST /api/tds/returns/{id}/approve when the caller filed that return you Never — not waivable by anyone; another approver must act
SELF_OVERRIDE 403 The caller submitted this document and tried to force-approve or force-reject it through POST /api/v1/igm/invoices/{docId}/approval/override. Nothing was changed you Never for that caller — another Org Administrator must override
NOT_PENDING 409 There is no open approval on this document, or no level left to act on you No — re-read the workflow state
CONCURRENT_MODIFICATION 409 Another decision on this same level landed a moment before yours — e.g. two approvers racing, or a double-submitted click you Yes — reload; the level was already decided by the other action, so check what it recorded before acting again
APPROVAL_PENDING 409 Posting was attempted while an approval is still open you Yes, once the approval clears
APPROVAL_REJECTED 409 The document was rejected in approval and cannot post you Never for this document — raise a corrected one
REASON_REQUIRED 400 A force-approve, force-reject, or forced engine disable was sent without the mandatory reason you Yes, with a reason
APPROVALS_IN_FLIGHT 409 IGM_APPROVAL_ENGINE cannot be switched off while documents still await approval — whether the change is a GSTIN override, a company default an affected GSTIN inherits, or the removal of either. gstins[] names every affected registration admin Yes, once the queue is clear — or a Complifly Super Admin with force + reason

ROLE_MISMATCH is usually a provisioning gap, not a bug

The message names the role the level requires and the role the caller actually holds. Read both halves — they distinguish the three causes:

Message ends with Cause Fix
…you have no approval role assigned The user has no approval_role_key Assign one on the user record
…your assigned approval role is X The user is a real approver, but at a different level The named level must act first. Approvals are sequential
The call never reached this check (403 from the permission guard instead) The user's system role does not hold invoice.approve Assign the approver or tax_controller system role

There is deliberately no administrative exemption. An org admin or Platform Super Admin whose approval role does not match is refused exactly like anyone else. The supported way out is POST /invoices/{docId}/approval/override, which requires admin.api, demands a written reason, and records the remaining levels as OVERRIDDEN rather than APPROVED — so a bypass is never indistinguishable from a real approval in the audit trail.

APPROVALS_IN_FLIGHT protects approvals already in progress

Switching the multi-level engine off does not merely stop future routing. Without this refusal, a document routed to three approvers and signed by none would stop being pending and post unapproved: the legacy flat gate takes over, its thresholds default to 0 (meaning off), and it rewrites the document from PENDING to NOT_REQUIRED. Nothing is rejected and nothing is logged as a bypass — the only trace is an approval_request still reading PENDING for a document already in the ledger.

The response body lists every blocking document with the role it is waiting on:

{
  "code": "APPROVALS_IN_FLIGHT",
  "message": "22 document(s) on 29AAACW3775F000 are still awaiting approval (waiting on finance_controller, finance_manager). …",
  "open": [
    { "docNo": "INV/00042", "docId": "…", "waitingOn": "finance_controller",
      "level": "1 of 3", "amount": 1180000, "submittedBy": "U0000013" }
  ]
}

Clear them — approve, reject, or per-document override — then retry. If a level names an approval role nobody holds, those documents can never clear and would block the setting for ever; for that case only, repeat the call with force: true and a written reason. Forcing cancels the approvals rather than approving them: every level is stamped OVERRIDDEN with the reason, the request becomes CANCELLED, and the documents return to having no approval decision at all.

SELF_APPROVAL cannot be resolved by changing a role

It is checked on identity, not permission: whoever submitted the document is refused, whatever role they hold. Granting more permissions will not change the outcome. Either another holder of the level decides it, or a different Org Administrator overrides with a reason. SELF_OVERRIDE is the same rule applied to the override route: the person who submitted the document cannot force it either.

Paged list errors

Returned by GET /api/irn/workbench when called with grid=2 (see List Columns and Saved Layouts API). All are 400 with { "code", "message" }; none runs a query. A request without grid never returns them.

Code Meaning Fixed by Retry?
GRID_VERSION grid is not 2 you Yes, with grid=2
GRID_PARAM_UNKNOWN A parameter the paged form does not take (it is refused, not ignored) you Yes, without it
GRID_QUERY_INVALID A malformed page, size or filter (wrong shape, out of range, too many) you Yes, corrected
GRID_SORT_KEY A sort key, direction or count the list does not offer (the e-way bill status is not sortable) you Yes, with a listed key
GRID_FILTER_KEY A filter key the list does not offer you Yes, with a listed key
GRID_FILTER_OP An operator the key does not support you Yes
GRID_FILTER_VALUE A value the filter cannot take: empty, too long, not ASCII, not a known status, not a real YYYY-MM-DD date, or a range that ends before it starts you Yes, corrected
GRID_SEARCH q is longer than 40 characters you Yes, shorter
GRID_FY fy is not like 2026-27, or month is not all or 1 to 12 you Yes, corrected
GRID_ATTENTION attention and finding together, or a value that is not a rule key / number you Yes, one of them
GRID_FACETS facets is not 1 or only you Yes
GSTIN_REQUIRED The paged form needs one GSTIN; x-gstin is missing or all you After selecting one
FEATURE_DISABLED_BY_OPERATOR (403) ENTERPRISE_GRID_V2 is off for this GSTIN admin Yes, once enabled

Platform operations screens

Returned when a customer's administrator asks for a screen or API that shows how the whole platform is running, across every company (Observability, Operations).

Code HTTP Meaning Fixed by Retry?
PLATFORM_STAFF_ONLY 403 The screen shows every company's activity and is for Complifly staff. Nothing is wrong with your account. Your own activity is under Audit Log and Usage you No

Company status

Returned when a company is suspended or archived, and by the endpoint that changes a status. What each status means is in Company Status.

Code HTTP Meaning Fixed by Retry?
TENANT_ARCHIVED 403 The company is archived: sign-in, every request and document intake are refused. On a request to add something (a user, API key, ERP connection or registration) it is 409 admin — a Complifly Super Admin must reactivate the company No
TENANT_SUSPENDED 409 The company is suspended and a new user, API key, ERP connection or registration was requested. Existing work is unaffected admin — a Complifly Super Admin must reactivate the company No
COMMERCIAL_SUSPENSION_NOT_SUPPORTED 422 A status change named a commercial reason (NON_PAYMENT, OVERAGE, PLAN, QUOTA …). The platform does not record one you — use a permitted reason code No
REASON_CODE_INVALID 400 reasonCode is missing or not one of SECURITY, LEGAL, CUSTOMER_REQUEST, OPERATIONAL, OFFBOARDING you Yes, corrected
REASON_REQUIRED 400 reason is missing or outside 5 to 300 characters you Yes, corrected
STATUS_INVALID 400 status is not ACTIVE, SUSPENDED or ARCHIVED you Yes, corrected
STATUS_UNCHANGED 409 The company already has that status you No
STATUS_CHANGED_MEANWHILE 409 Someone changed the status between your read and your write you Yes, after re-reading
COMPANY_NOT_FOUND 404 No such company you No
COMPANY_REQUIRED 400 No company id was given you Yes, corrected

A suspended company is not refused sign-in, requests or document intake. If a client treats TENANT_SUSPENDED as "stop all work", it is wrong: the code appears only on a request to add something.

Usage and integration visibility

Returned by the Usage API and by /api/admin/integration-visibility.

Code HTTP Meaning Fixed by Retry?
USAGE_PERIOD_INVALID 400 A date is malformed, to is not after from, only one bound was given, or the span exceeds 366 days you Yes, corrected
USAGE_METRIC_UNKNOWN 400 A metric id that is not in the catalogue (GET /api/usage/metrics lists them) you Yes, corrected
USAGE_GSTIN_INVALID 400 gstin is not a 15-character GSTIN you Yes, corrected
USAGE_COMPANY_REQUIRED 400 The session carries no company admin Yes, after signing in again
USAGE_GSTIN_NOT_IN_COMPANY 403 The GSTIN belongs to another company you No
USAGE_SCOPE_NOT_PERMITTED 403 A company other than your own, all, or the reconciliation was requested by someone who is not a Complifly Super Admin you No
STATEMENT_NOT_FOUND 404 The statement asked for does not exist: your company holds no registration under that PAN, or a CSV was asked for and there is nothing to export you No
STATEMENT_PAN_REQUIRED 400 A CSV was asked for and your company holds registrations under more than one PAN. The message lists them; add ?pan= with one you Yes, with pan
USAGE_FAILED 500 An unexpected failure; no detail is returned support Once
SUPER_ADMIN_ONLY 403 The integration-visibility endpoints are for a Complifly Super Admin you No
INVENTORY_FAILED 500 The integration inventory could not be read support Once

Commercial

Returned by the Commercial API. Only the codes a customer's own administrator can receive are listed here; the rest belong to Complifly's internal administration of customer records. None of these is raised by a licence or capacity state: a licence in grace or expired, or a limit exceeded, is reported and never refused.

Code HTTP Meaning Fixed by Retry?
COMMERCIAL_SUPER_ADMIN_ONLY 403 The platform commercial endpoints are for a Complifly Super Admin you No
COMMERCIAL_COMPANY_REQUIRED 400 The session carries no company admin Yes, after signing in again
COMMERCIAL_FAILED 500 An unexpected failure; no detail is returned support Once

When adding a user would go past your plan

These are the only refusals a plan limit can cause, and only when Complifly has set your company's Plan & Limits control to Enforce (it is Off unless Complifly sets it). They stop an administrator adding something: nothing is changed, and nothing about issuing an IRN or an e-way bill, or receiving documents from your ERP, is ever affected.

Code HTTP Meaning Fixed by Retry?
ENTITLEMENT_LIMIT_REACHED 409 Adding or reactivating a user, or giving one access to another registration, would take your company past the number of users your plan allows. The message says what the plan allows and how many are in use. Nothing was changed admin — free one up, or ask your Complifly contact to raise the limit Yes, once there is room
ENTITLEMENT_NOT_INCLUDED 409 A Complifly Super Admin tried to switch on an optional module the customer's plan says is not included. details.canForce is true: repeat the change with force and a written reason to override it, and the exception is recorded support Yes, with force and a reason

If your company shares its PAN with another company on Complifly, you are never refused: Complifly is told instead.

Go-live

Returned by the Go-Live Readiness API. None of these is raised by a company's readiness or go-live state: a company that is not ready, or is not approved, is never refused sign-in, requests or documents. REASON_REQUIRED and DATE_INVALID (listed under Commercial) are also returned here for a missing reason or a malformed date.

Code HTTP Meaning Fixed by Retry?
GO_LIVE_SUPER_ADMIN_ONLY 403 The go-live administration endpoints are for a Complifly Super Admin you No
GO_LIVE_COMPANY_REQUIRED 400 The session carries no company admin Yes, after signing in again
GO_LIVE_FAILED 500 An unexpected failure; no detail is returned support Once

Feature configuration

Returned by the Operational Controls endpoints — POST /api/admin/features/toggle, POST /api/admin/gstins/bulk-toggle and the two DELETE …/features/{featureKey} routes — and by any route gated with requireFeature.

Which 403 you get tells you whom to ask. Application routes check the caller's permission first and the module switch second, on every route. PERMISSION_DENIED means the role lacks the right: ask the Org Admin for a role change. FEATURE_DISABLED_BY_OPERATOR means the role was fine and the module is off: ask Complifly, because module switches are part of the subscription. A caller without the right is never told whether the module is on. Both codes are in the response body's code field; the HTTP status is the same, so branch on code, never on 403.

The two 409s are raised for every GSTIN a change reaches, not only the one named. A company default is inherited by every GSTIN with no override of its own, so one company-level write — or the removal of one override — can be refused on behalf of a GSTIN you did not mention. The body's gstins[] says which.

Code HTTP Meaning Fixed by Retry?
VIEW_INVALID 400 A saved view or its name is not acceptable (a sort or filter the screen cannot show, a value the list would refuse, a name outside 1 to 60 characters, a view over 4,000 characters). message names the part. Nothing is stored you Yes, with a corrected view
VIEW_UNKNOWN_SCREEN 400 The screen key cannot hold views (only einvoice_irn-workbench-table today) you Yes, with a supported screen
VIEW_LIMIT 400 The user already has 20 views for the screen you Yes, after deleting one
VIEW_NOT_FOUND 404 No such view for this user. A view belonging to another user is answered identically, on purpose you No
VIEW_NAME_TAKEN 409 The user already has a view with that name for the screen (compared ignoring capitals) you Yes, with another name
PRINT_CONFIG_INVALID 400 POST /api/print-config/save refused a corporate field (Udyam_No, Prepared_By, Checked_By, Authorised_By, Reference_Partner, Reference_Manager) that is not text, is too long, contains a character that cannot be printed, or (Udyam) is not in the registered form. message names each field; fields lists them. Nothing is saved you Yes, with the fields corrected
PRINT_BANK_INVALID 400 POST or PUT /api/print-config/bank-accounts refused an account number, IFSC, SWIFT code, account type or name that does not meet its rule. message names each; fields lists them. Nothing is saved you Yes, with the values corrected
BANK_ACCOUNT_EXISTS 409 An active bank account with the same number already exists for the registration you Yes, after editing the existing account or deactivating it
BANK_ACCOUNT_NOT_FOUND 404 The account id does not exist for the registration in X-GSTIN (another registration's account is indistinguishable from a missing one) you Yes, with the right registration and id
PRINT_DTO_SCHEMA_MISMATCH 500 A print was refused because the template and the document data no longer agree (the template was built for a different version of the print data). Raised only with CORPORATE_PRINT_FRAMEWORK on; without it the same mismatch prints blanks. The message names the template, its version and the document's schema support No - report it with the document; switching the control off prints the document with the original renderer
FEATURE_DISABLED_BY_OPERATOR 403 The route's feature flag is off for this GSTIN, or for the company where the module is company-wide (TDS, the agent). The caller's permission was checked first and passed, so this is never a role problem. A Super Admin is not exempt support Yes, once enabled
ACCESS_WIDENING_REASON_REQUIRED 400 The change would relax segregation of duties (a registration's effective SOD_ENFORCED moving from on to off) and no reason was sent. The body names the registrations in gstins. Nothing was changed. Any caller, a Super Admin included you Yes, with a written reason. The company's other Org Admins are then emailed
SOD_LOCKED 403 A company administrator tried to relax segregation of duties (SOD_ENFORCED moving from on to off for any registration, including by removing an older GSTIN override that kept one enforced) after the company started live work: a live IRN, a generated e-way bill or a decided approval. The body names the registrations in gstins, with lockedSince and evidence (IRN, EWB or APPROVAL). Nothing was changed; the attempt is audited as FEATURE_CHANGE_BLOCKED. Turning it on is never refused support No — the Org Admin cannot. A Complifly Super Admin can, with a reason and approvalRef
SOD_APPROVAL_REF_REQUIRED 400 A Complifly Super Admin relaxed segregation of duties for a locked company without a usable approvalRef (3 to 120 characters after trimming). Nothing was changed. Sent before the reason is judged, so send both you Yes, with the customer's approvalRef and a written reason
EMERGENCY_GRANT_NOT_PERMITTED 403 The caller is not an Org Admin of the company or a Super Admin you No
EMERGENCY_GRANT_STRICT 403 The company is in Strict governance mode and the caller is an Org Admin: only a Super Admin can lend support Yes, from a Complifly Super Admin with the customer's approvalRef
EMERGENCY_SELF_GRANT 403 The caller tried to lend emergency access to themselves, in either mode you Yes, by another administrator
EMERGENCY_ROLE_NOT_LENDABLE 400 roleKey is not one of tax_controller, tax_executive, transport_manager, logistics_operator. The body lists them in lendable you Yes, with a lendable role
EMERGENCY_DURATION_INVALID 400 durationMinutes is under 15 or over the mode's limit (1440 Standard, 240 Strict). The body carries minMinutes and maxMinutes you Yes, with a duration in range
EMERGENCY_REASON_REQUIRED 400 A reason of at least 10 characters is required to lend (5 to revoke) you Yes, with a reason
EMERGENCY_APPROVAL_REF_REQUIRED 400 Strict mode: the customer's approvalRef (3 to 120 characters) is required you Yes, with the reference
EMERGENCY_GRANTEE_NOT_FOUND 404 No such person in this company (another company's person answers the same) you Yes, with a user of the company
EMERGENCY_GRANTEE_INACTIVE 409 The account is deactivated you After reactivating it
EMERGENCY_GRANTEE_NOT_ELIGIBLE 403 Auditor and Complifly accounts cannot be lent emergency access you No
EMERGENCY_GRANT_EXISTS 409 The person already has emergency access that has not ended. The body carries grantId you After revoking it or when it expires
EMERGENCY_GRANT_ENDED 409 The grant being revoked has already ended you No
EMERGENCY_GRANT_NOT_FOUND 404 No such grant in the caller's company you No
SUPPORT_WINDOW_REQUIRED 403 The company is in Strict mode and has no support window open; the caller is a Complifly support or platform engineer. Audited against the customer as SUPPORT_WINDOW_DENIED support Yes, once the company's Org Admin opens a window
SUPPORT_WINDOW_UNAVAILABLE 503 Whether a window is open could not be checked. The request is refused, never allowed support Yes, shortly
SUPPORT_WINDOW_CUSTOMER_ONLY 403 Only the company's own Org Admin can open a window you No
SUPPORT_WINDOW_EXISTS 409 A window is already open. The body carries windowId you After closing it
SUPPORT_WINDOW_DURATION_INVALID 400 hours is under 1 or over 168 you Yes, in range
SUPPORT_WINDOW_REASON_REQUIRED 400 A reason of at least 5 characters is required you Yes, with a reason
SUPPORT_WINDOW_NOT_PERMITTED 403 Only the company's Org Admin or a Super Admin can close a window you No
SUPPORT_WINDOW_NOT_FOUND 404 No such window in the caller's company you No
SUPPORT_WINDOW_ENDED 409 The window being closed has already ended you No
ROLE_REQUEST_PENDING 409 The person has a role request waiting for a second approval, so they cannot be activated or re-roled by PUT /users. The body carries requestId you After the request is decided
ROLE_REQUEST_EXISTS 409 The person already has a pending request you After it is decided
ROLE_REQUEST_SELF_DECISION 403 The caller made the request and cannot decide it you By another administrator
ROLE_REQUEST_NOT_PERMITTED 403 The caller may not decide this request (Super Admin role: another Super Admin only; Org Admin role: another Org Admin of the company or a Super Admin), or may not withdraw it (requester only) you By the right person
ROLE_REQUEST_NOTE_REQUIRED 400 Rejecting needs a note of at least 3 characters you Yes, with a note
ROLE_REQUEST_DECIDED 409 The request is no longer pending you No
ROLE_REQUEST_NOT_FOUND 404 No such request in the caller's company you No
ROLE_REQUEST_TARGET_GONE 409 The person the request is about no longer exists in the company you No
ROLE_REQUEST_REASON_REQUIRED 400 A roleChangeReason, if sent, must be at least 5 characters you Yes
ELEVATED_ACCESS_FAILED 500 An unexpected failure in an elevated-access call support Yes, and report it if it persists
UNKNOWN_FEATURE_KEY 400 featureKey is not a control in this build you Yes, with a key from GET /api/admin/feature-definitions
INVALID_FEATURE_VALUE 400 The control does not accept that value — wrong type, outside its range, or not one of its options. expects in the body says what it accepts. Nothing is stored you Yes, with an accepted value
FEATURE_SCOPE_NOT_ALLOWED 400 A company-wide control (MODULE_TDS_ENABLED, AGENT_ENABLED, SOD_ENFORCED and the other company-scoped controls) was sent as a GSTIN override you Yes — send it as a company default (scope: "company")
FEATURE_WRITE_NOT_PERMITTED 403 The control is a licensing / subscription control (writeRole: PLATFORM) and the caller is not a Complifly Super Admin — or the caller's role can only view controls. Nothing is changed; the attempt is audited support No — ask Complifly
FORCE_NOT_PERMITTED 403 force: true from anyone but a Complifly Super Admin. Overriding a safety check is Complifly's alone support No — resolve what the check reported, or ask Complifly
COMPANY_NOT_PERMITTED 403 The company in the request is not the caller's own, and the caller is not a Super Admin admin No — a Super Admin must make the change
GSTIN_NOT_PERMITTED 403 The GSTIN is not registered under the caller's company. The same answer is given whether it belongs to another company or does not exist admin No
UNKNOWN_COMPANY 404 The company is not in the company catalogue you Yes, with a company from GET /api/admin/companies
GSTIN_NOT_IN_COMPANY 404 The GSTIN in the path does not belong to the company in the path you Yes, with the right company
NO_STORED_VALUE 404 A DELETE found no override or company default to remove you No — there is nothing to remove
CONCURRENT_MODIFICATION 409 The rowVersion sent no longer matches — someone else changed the value first you Yes — reload, then decide again
TOO_MANY_GSTINS 400 More than 500 GSTINs in one bulk call you Yes, in smaller batches
NON_ERP_POSTING_BLOCKED 409 The change would turn EXCEL_UPLOAD_ENABLED or INVOICING_ENABLED on for a GSTIN with an active ERP connection — directly, through a company default it inherits, or by removing the override that kept it off admin Yes, once cleared — or a Complifly Super Admin with force + reason
REASON_REQUIRED 400 force: true was sent on the feature toggle without a reason you Yes, with a reason

NON_ERP_POSTING_BLOCKED protects against the same document being posted twice

A GSTIN fed by a connected ERP that also accepts Excel uploads or Invoice Generation Module entries can receive one commercial transaction through both doors — each raising its own IRN and e-Way Bill. Nothing else in the platform detects or merges the duplicate, so the toggle refuses the change rather than opening a second channel silently.

{
  "code": "NON_ERP_POSTING_BLOCKED",
  "message": "29AAACW3775F000 is fed by D365FO. Turning Excel Upload on opens a second door for the same GSTIN to post documents — …",
  "gstins": ["29AAACW3775F000"],
  "connections": ["D365FO"]
}

Leave the channel off, route the correction through the ERP instead, or — for a genuine multi-source setup such as an ERP migration running two systems in parallel — repeat the call with force: true and a written reason. The reason is written to the audit trail against this change. Forcing does not enable ERP_WRITEBACK_ENABLED and adds no duplicate detection between channels. See Feature Flags.

Compliance profile

Returned by the Compliance Profile endpoints under /api/admin/…/compliance-profile, /api/admin/gstins/{gstin}/registration-class and /api/admin/companies/{companyId}/onboarding-tasks. See the Compliance Profile API. Every refusal changes nothing.

Code HTTP Meaning Fixed by Retry?
PERMISSION_DENIED 403 A write needs compliance_profile.manage (a Complifly Super Admin); a read needs compliance_profile.view. A role without the permission is also refused earlier with a plain 403 carrying only a message support No. A customer cannot obtain write access, so ask your Complifly implementation consultant
COMPANY_NOT_PERMITTED 403 The company in the path is not the caller's own, and the caller is not Complifly staff admin No
UNKNOWN_COMPANY 404 The company is not in the company catalogue you Yes, with a company from GET /api/admin/companies
UNKNOWN_GSTIN 404 The GSTIN does not belong to a company the caller may use. The same answer is given whether it belongs to another company or does not exist you Yes, with the right GSTIN
UNSUPPORTED_ERP 404 {erp} in the path is not TALLY you Yes, with TALLY
INVALID_COMPANY, INVALID_GSTIN, INVALID_PARAMETER, INVALID_STATUS, INVALID_TASK_CODE 400 A path or query value is malformed you Yes, corrected
DELTA_REQUIRED 400 The body has no delta object you Yes
BASE_REVISION_REQUIRED 400 baseRevision is missing. Send the revision you loaded, or null when the company has none. It cannot be left out, because that would skip the check that stops one person overwriting another you Yes
NOTE_REQUIRED 400 A change was sent with no reason you Yes, with a note
NOTE_TOO_LONG 400 The note is over 500 characters you Yes, shortened
PROFILE_DELTA_INVALID 422 The settings do not validate. problems[] lists each, in words: a section a customer may not change, a key the base profile does not define, or a value that is not an accepted option you Yes, after fixing each problem
CONCURRENT_MODIFICATION 409 The profile changed since you loaded it. latestRevision says what it is now you Yes. Reload, then make your change again. It is not merged for you
REVISION_NOT_FOUND 404 The revision does not exist for this company you No
ROLLBACK_TARGET_IS_CURRENT 422 The revision you asked to roll back to is already the active one you No. There is nothing to restore
CLASS_REQUIRED 400 registrationClass is missing from the body. Send a class, or null to clear it you Yes
INVALID_CLASS 400 The class is not TURNOVER_GE_5CR or TURNOVER_LT_5CR you Yes
TASK_NOT_FOUND 404 The task is not this company's you No
TASK_NOT_OPEN 409 The task is already closed, or someone closed it first you No
ASSIGNEE_REQUIRED 400 assignee is missing you Yes
ASSIGNEE_NOT_ELIGIBLE 422 The assignee is not an active user of this company you Yes, with a user from the task list's assignableUsers
COMPLIANCE_PROFILE_ERROR 500 An unexpected failure. The message says nothing was changed support Yes, once; then quote the request identifier

Validation and ingest

Code HTTP Meaning Fixed by
REJECTED with errors 422 Validation failed you
VALIDATION 422 Same, recorded as a rejection reason you
ERROR 500 Server error support

Agent held reasons

A HELD receipt means Complifly sent nothing and assumed nothing; the agent keeps the voucher and sends it again once the cause is fixed. It is not a rejection and is not stored in the intake-refusals list. The heldReason in the receipt is one of:

Code Meaning Who resolves it Retry?
OBLIGATION_RULE_MISSING No obligation rule covers this document type, sale type, turnover band and date Complifly support, after compliance confirms the rule Yes, automatically, once the rule exists
MOVEMENT_PURPOSE_UNMAPPED A challan-type voucher whose voucher type the customer's setup does not map to a purpose Complifly support, from the customer's list of purposes Yes, after the setup is updated
MOVEMENT_PURPOSE_INVALID_FOR_DOCUMENT NIC does not allow this purpose on this document type Complifly support Yes, after the setup is corrected
MOVEMENT_DIRECTION_MISMATCH The voucher type is set as inward but the purpose is outward, or the reverse Complifly support Yes, after the setup is corrected
MOVEMENT_PURPOSE_UNKNOWN The purpose named in the setup is not one Complifly defines Complifly support Yes, after the setup is corrected
EXPORT_PORT_NOT_CONFIGURED An export that needs an e-way bill, and the company has no export port saved. The voucher is not stored Complifly support saves the port once the customer gives its name, address, city, state and PIN Yes: send the voucher again from Tally after the port is saved. It is not retried automatically
PROFILE_DELTA_INVALID The customer's saved setup no longer validates against Complifly's standard settings. The whole batch is held; errors[] names each fault Complifly support Yes, after the setup is corrected

Warnings on an accepted document (the receipt's warnings[]; the document was stored):

Code Meaning Action
MOVEMENT_UNKNOWN_AT_THRESHOLD At or over the e-way bill value limit, with no dispatch details on the voucher. Complifly did not assume the goods are not moving. A B2CS or B2CL sale is stored as EWB_PENDING for the e-Way Bill Doc Workbench; any other sale is stored with no e-way bill flagged Add the shipping details in the e-Way Bill Doc Workbench (B2C), or in Tally for any other sale. If nothing moves, leave it: nothing is sent to NIC until an e-way bill is generated
UNKNOWN_TURNOVER No turnover band is recorded for the GSTIN. The document was not held; it was routed as if above the e-invoicing limit. An AGENT_UNKNOWN_TURNOVER audit entry was written and an onboarding task opened Ask Complifly support to record the band
SHIPPING_DATA_ABSENT The voucher has no dispatch details. Complifly does not read that as "no movement" Add dispatch details in Tally if goods are moving
EXPORT_PORT_NOT_CONFIGURED An export that only needs an IRN, and the company has no export port. The IRN was filed; the e-way bill cannot be made until a port is saved. An onboarding task CONFIGURE_EXPORT_PORT was opened (one per company) Complifly support saves the export port
STOCK_TRANSFER_MODE_UNSET A stock-transfer voucher was held because the customer's setup does not say whether transfers are challans or tax invoices Complifly support records the mode once the customer confirms it (appears in the held receipt's errors[])
SHIP_BLOCK_INCOMPLETE The ship-to or dispatch-from address has some but not all of state, location and pin. The block was omitted, not sent partial; the document was accepted Fill in all three on the voucher, or clear the partial fields
LUT_SOURCE_UNCONFIGURED The setup says to read the LUT from a field but names no field; no LUT was found Complifly support names the field or restores narration reading
RULE_IS_COMPLIANCE_PLACEHOLDER The rule that decided the route has not been confirmed by Complifly's compliance review None for the customer; Complifly confirms the rule

Agent enrolment

These come from POST /api/v1/agent/enrol (the agent redeeming its token) and from the enrolment requests under /api/admin/agent-enrolments. A refusal that says "the token was not used up" can be tried again with the same token.

Code HTTP Meaning Fixed by
ENROLMENT_TOKEN_INVALID 403 The token is not one Complifly issued admin: copy it again, or request a new enrolment
ENROLMENT_TOKEN_USED 403 The token has already been redeemed. A token works once admin: request a new enrolment
ENROLMENT_TOKEN_EXPIRED 403 The token is older than 24 hours admin: request a new enrolment
ENROLMENT_NOT_APPROVED 403 The token is not tied to an approved request (it was rejected, or the token was not issued through a request) admin
AGENT_DISABLED 403 The Complifly Agent control is off for the company. The token was not used up support switches it on
ENROLMENT_CSR_INVALID 400 The certificate request is malformed, its key is weak or of a disallowed type, or the key was used before. problems[] names each. The token was not used up support
ENROLMENT_CA_UNAVAILABLE 503 The certificate service did not answer or is not configured for this environment. retryable: true. The token was not used up try again; support if it persists
ENROLMENT_CA_REFUSED 502 The certificate service declined to issue. The token was not used up support
BAD_REQUEST 400 enrolmentToken, csr or machineFingerprint is missing the installer
ENROLMENT_REQUEST_DECIDED 409 The request was approved or rejected already (status says which). No second token was issued reload
ENROLMENT_REQUEST_EXPIRED 409 Nobody decided the request within 7 days admin: request again
SELF_APPROVAL_NOT_ALLOWED 403 The person deciding is the person who asked a different Complifly person
REJECTION_REASON_REQUIRED, MACHINE_LABEL_REQUIRED, GSTIN_INVALID, DECISION_INVALID, COMPANY_REQUIRED 400 A field is missing or malformed; the message names it you
ENROLMENT_REQUEST_NOT_FOUND 404 No such request you

Write-back feed

Code HTTP Meaning Fixed by
NO_SUBSCRIPTION 404 No active subscription for the credential's registrations admin
NO_EVENT_IDS 422 Acknowledgement body missing identifiers you
TOO_MANY 422 Too many identifiers in one acknowledgement you
FEED_ERROR 500 Feed query failed support
ACK_ERROR 500 Acknowledgement failed support

NO_SUBSCRIPTION is a configuration state, not a transient one. Retrying it forever is a common integration defect; it will never succeed until someone configures a subscription.

Attention Center findings

Returned by /api/attention — see Attention API.

Code HTTP Meaning Fixed by Retry?
GSTIN_REQUIRED 400 No single GSTIN selected you After selecting one
INVALID_RESOLUTION_CODE 400 The decision is not allowed for this kind of finding — most kinds allow none and close only when the document is fixed you No — fix the document instead
INVALID_TRANSITION 400 / 409 The action does not fit the finding's status, or the bulk request is malformed you After re-reading the finding
RULE_NOT_PERMITTED 403 The role lacks the document right for this kind of finding admin No
FINDING_NOT_FOUND 404 No such finding for this GSTIN, or not visible to the caller you No
STALE_FINDING 409 The finding changed since the caller read it you Yes, after re-reading
NO_RULES_ENABLED 409 A check was requested but no rules are enabled support No
EVIDENCE_REQUIRED 422 A decision's required evidence or note is missing or malformed you Yes, with the missing detail
ASSIGNEE_NOT_ELIGIBLE 422 The chosen user cannot own findings on this GSTIN or of this kind you With an eligible user
EVALUATE_RATE_LIMITED 429 A check for this GSTIN ran less than a minute ago you Yes, after a minute
ATTENTION_ERROR 500 Unexpected failure; nothing was changed support Yes, bounded

Notification settings (/api/attention/notification-profiles, Attention API):

Code HTTP Meaning Fixed by Retry?
INVALID_EVENT, INVALID_SEVERITY, INVALID_HOUR, INVALID_WEEKDAY, INVALID_TIMEZONE, INVALID_GSTIN, INVALID_COMPANY 400 A value is not one the API accepts. OVERDUE is not an event you After correcting it
EVENT_HAS_NO_EMAIL 400 A registration or organization setting for the bell-only critical-item event. A person sets that one for themselves you No
USER_PROFILE_HAS_NO_RECIPIENTS 400 Recipients were sent with a personal setting you After removing them
TOO_MANY_RECIPIENTS, INVALID_RECIPIENT_TYPE, INVALID_ROLE, INVALID_EMAIL 400 / 422 A recipient is not valid you After correcting it
SCOPE_NOT_PERMITTED 403 The role may not edit that scope: a registration needs an organization administrator or admin.manage_users, an organization needs an organization administrator admin No
GSTIN_NOT_PERMITTED, COMPANY_NOT_PERMITTED 403 The registration or company is outside the caller's own. The same answer whether it belongs to someone else or does not exist admin No
EMAIL_RECIPIENT_NEEDS_ORG_ADMIN 403 An external address was added by someone who is not an organization administrator admin No
NOT_PENDING, UNKNOWN_COMPANY, UNKNOWN_GSTIN 404 A confirmation was re-sent for an address that is already confirmed or not on the setting; or the company is not in the catalogue; or the registration belongs to no company you / admin No
STALE_PROFILE 409 Someone else saved the same setting first you Yes, after reloading
BLOCKED_BY_ORGANIZATION 409 A registration was set On for an event the organization has switched Off. A lower level cannot turn on what a higher one switched off admin After the organization turns it on
RECIPIENT_NOT_ELIGIBLE 422 A named user is not an active user of the registration or company, or has no email address you With an eligible user

Rate limiting

Condition HTTP Fixed by Retry?
Limit exceeded 429 you Yes, after backing off

The retry summary

Never retry Retry
DUPLICATE 429
REJECTED and VALIDATION 5xx, bounded
GSTIN_NOT_PERMITTED, FORBIDDEN TOKEN_EXPIRED, once, after refresh
OAUTH_REQUIRED Timeouts, after reconciling
NO_SUBSCRIPTION
STATUS_LOCK, IRN_ALREADY_CANCELLED

Validation

Check Pass condition
The code is captured Along with the request identifier
Authentication and authorisation are distinguished 401 and 403 take different paths
Nothing terminal is retried Verified by forcing each response
Scope errors reach an administrator Not treated as a data fault
Support-class errors carry evidence Request identifier and document number included

Troubleshooting

Symptom Cause Action
TOKEN_EXPIRED immediately after refresh Clock drift Fix time synchronisation on both hosts
TOKEN_INVALID with a token that decodes correctly Wrong audience or issuer Compare the claims against the configuration
Valid token, 403 Application role not granted Grant admin consent
GSTIN_NOT_PERMITTED while the user's role is correct It is a credential scope problem Check the credential's registration scope
OAUTH_REQUIRED on a working key The client was switched to token-only Complete the migration
DUPLICATE on a document never sent Numbering restarted, or two systems share a series Fix the series. Numbers are consumed permanently
STATUS_LOCK The document's state does not allow the action Check its status; the action may already have occurred
INDETERMINATE_PAYLOAD_CHANGED Unknown outcome plus a subsequent edit Do not force. Establish the true state, with support if necessary
NO_SUBSCRIPTION retried indefinitely Treated as transient It is configuration. Configure a subscription
Persistent 429 at modest volume Retrying terminal failures, or authenticating per call Fix the retry policy; cache tokens
ERROR repeatedly A genuine server fault Escalate with the request identifier