Xero SDK OrganisationType Exception: Why Your Integration Breaks for US LLC Customers

Xero SDK OrganisationType Exception: Why Your Integration Breaks for US LLC Customers

Your Xero integration passes every test you write. Unit tests. Integration tests. OAuth flow tests. All green.

Then a US customer connects their Xero org.

The whole thing crashes.

We saw this last week. A multi-tenant SaaS platform we built for a US-based client. Customers were silently failing to connect.

If your product depends on accounting data sync, these small API edge cases can quickly become onboarding blockers. Teams building multi-tenant accounting integrations should treat SDK behavior as part of the production risk, not just a developer convenience.

The customers had done nothing wrong. That integration had passed every test. The SDK was the problem.

Here’s what makes this bug nasty: It hides from your test environment. It only triggers for a specific kind of customer.

And it sits in every official Xero SDK right now .NET, Java, Node, Python, PHP, Ruby waiting for your US users to trip it.

This post walks through the exact failure, the cross-SDK status, and the fix that works in production.

What Causes the Xero SDK OrganisationType Exception?

Xero’s web UI lets a customer pick an organization type from a dropdown.

The US version of that dropdown includes LLC (C corporation), LLC (Partnership), LLC (S corporation), LLC (Sole owner), C corporation, S corporation, Sole Proprietor, Nonprofit, Private Foundation, Exempt Organization, and Unspecified.

The Xero API faithfully returns whatever the customer picked.

But the SDK has a hardcoded enum. 13 values. None of them are LLC anything.

When the SDK’s JSON deserializer hits an unknown enum value, it throws. Your GET /Organisation call fails completely.

No graceful fallback. No warning. Just a crash.

The first time you find out is when a US customer with an LLC tries to connect.

Who Is Affected by This Xero SDK Issue?

This issue is most likely to affect SaaS platforms, middleware products, accounting automation tools, and custom business applications that connect to Xero on behalf of multiple customers.

You should pay attention if your application:

  • Supports US-based Xero organisations
  • Calls the /Organisation endpoint after OAuth connection
  • Uses the official SDK model directly in onboarding logic
  • Depends on OrganisationType for routing, validation, currency handling, tax logic, or tenant setup
  • Has customers reporting failed Xero connections without a clear OAuth error

For single-company internal apps, this issue may be easier to detect. For multi-tenant platforms, it can silently affect only a subset of customers, which makes it harder to catch during normal QA.

OrganisationType Values Supported by Xero SDKs

Here’s the complete list. Verified against the source file in each SDK repo as of April 2026:

ACCOUNTINGPRACTICE
COMPANY
CHARITY
CLUBORSOCIETY
INDIVIDUAL
LOOKTHROUGHCOMPANY
NOTFORPROFIT
PARTNERSHIP
SCORPORATION
SELFMANAGEDSUPERANNUATIONFUND
SOLETRADER
SUPERANNUATIONFUND
TRUST

Notice anything?

Read that list again. Carefully.

SOLETRADER. SUPERANNUATIONFUND. SELFMANAGEDSUPERANNUATIONFUND. LOOKTHROUGHCOMPANY.

These are all Australian and New Zealand concepts.

The entire enum reads like it was written for the ANZ market and never updated.

The overlap with US org types is exactly one value: PARTNERSHIP. And even that doesn’t match the Xero UI label casing. Every other US org type your customer might pick is a guaranteed crash.

Xero OrganisationType Exception Log Example

In the .NET SDK (Xero.NetStandard.OAuth2), the failure surfaces as a JsonSerializationException from Newtonsoft.Json.

It happens deep inside the SDK’s internal ApiClient.Deserialize call. The stack trace points at the auto-generated Organisation model.

You’ll see something like this:

Newtonsoft.Json.JsonSerializationException:
Error converting value "LLC_C_CORPORATION" to type
'Xero.NetStandard.OAuth2.Model.Accounting.Organisation+OrganisationTypeEnum'

Other SDKs fail the same way

Different languages, same root cause, different wrapper:

  • Java JsonMappingException from Jackson
  • Python ValueError from the validator
  • PHP InvalidArgumentException
  • Ruby ArgumentError
  • Node / TypeScript runtime cast failure in xero-node

Same crash point. Same broken integration. Different error class.

Why This Affects Multiple Xero SDKs, Not Just .NET

Here’s the uncomfortable part.

Every official Xero SDK is generated from the same Xero-OpenAPI specification.

One spec in, six SDKs out. When the spec lists 13 enum values, every SDK gets 13 enum values. C#, Java, TypeScript, Python, PHP, Ruby all simultaneously.

Fix one, fix none. They all have to be regenerated from an updated spec.

Xero SDK OrganisationType Support Across Languages

Current status across the six official SDKs maintained at github.com/XeroAPI, verified April 2026:

SDKLanguageEnum sizeLLC?Public issueStatus
Xero-NetStandardC# / .NET13No#201Closed (wontfix), Mar 2021
Xero-JavaJava13No#112 (same class of bug, different enum)Closed
xero-nodeTypeScript13NoNone publiclyUnreported
xero-pythonPython13NoNone publiclyUnreported
xero-php-oauth2PHP13NoNone publiclyUnreported
xero-rubyRuby13NoNone publiclyUnreported

The .NET issue tells the whole story

In July 2020, a developer named Richard Cubic opened Xero-NetStandard #201.

His proposal: ship a TolerantEnumConverter. A small Newtonsoft.Json converter that returns null instead of throwing when it hits an unknown enum value.

One change. Forward-compatible. It would have prevented the entire class of bugs.

Xero engineers Jenks Guo and GraceYBR replied with a different plan: improve the internal workflow so SDK enum updates ship ahead of API releases.

The issue was closed in March 2021. The TolerantEnumConverter Never shipped.

GitHub issue discussing enum deserialization failures caused by new API values and outdated SDK code generation.

Screenshot of Xero-NetStandard Issue #201 the rejected TolerantEnumConverter proposal from 2020 that would have prevented this entire class of bug. Closed wontfix, March 2021.

The same pattern recurs in Java

Xero-Java has Issue #112, opened in December 2018.

Same root cause, different enum. The SDK was missing "OFFICE" from PhoneTypeEnum a value Xero’s API was returning for the US Demo Company.

Sidney Allen (Xero) acknowledged it. The fix was a one-off enum patch. Not a structural change.

GitHub issue showing a JSON mapping exception caused by an unsupported enum value in an API SDK integration.

Screenshot of Xero-Java Issue #112 the same class of enum drift bug on PhoneTypeEnum, reported in December 2018. Different enum, identical pattern.

The same pattern has recurred since then BankAccountTypeEnum, SystemAccountEnum, and ReportTaxTypeEnum.

Translation: Xero knows about this entire class of bugs. They’ve chosen not to fix it at the converter level.

They’re betting on “we’ll update the spec faster” and that bet has demonstrably failed multiple times. As long as you rely on a strongly-typed Xero SDK enum, you’re exposed.

How Other Xero Integration Platforms Handle Enum Drift

Maybe you’re thinking: this is an old issue. Surely it’s been fixed.

It hasn’t.

Look at how the big third-party Xero integration platforms handle this risk.

Codat is one of the largest unified accounting API providers in the world. In July 2024, they published a changelog notice telling their customers that Xero had silently changed the Organisation Class enum values.

Three new values appeared in the live API: IGNITE, GROW, COMPREHENSIVE. No warning from Xero. No coordinated SDK release.

Codat had to patch its own data model to handle them.

It’s a different field Class, not Type. But the pattern is identical.

The takeaway: If a tier-one unified accounting API like Codat is publishing changelog notices about Xero’s enum drift, smaller teams using the SDK directly are getting silently broken at the same time. They just don’t know it yet.

Why This Matters for SaaS and Accounting Platforms

This is not just a code-level exception. In a production onboarding flow, this bug can stop a valid Xero customer from connecting their account even when authentication has completed successfully.

For SaaS teams, that can create a few practical problems:

  • Failed onboarding for US LLC customers
  • Higher support tickets with unclear root cause
  • Lost trial-to-paid conversions
  • Manual account setup work for the operations team
  • Poor first impression during integration setup
  • Hidden failures if the exception is swallowed or logged without alerting

The tricky part is that your integration can pass every internal test and still fail when it sees a real organisation type from a real US customer.

How to Fix Xero OrganisationType SDK Crashes

The only fix that actually works is the same one Xero rejected in 2020.

Don’t trust the SDK’s strongly-typed enum.

Treat the OrganisationType field as a string. Map it to your own internal type later, in your own code, where you control the failure mode.

Quick Fix vs Production-Safe Fix

ApproachWorks Temporarily?Production-Safe?Risk
Downgrade SDK versionMaybeNoSame enum limitation may exist
Add try/catch onlyPartiallyNoError is hidden, not solved
Wait for SDK updateMaybeNoNew values can appear again
Treat OrganisationType as stringYesYesRequires internal mapping
Add Unknown fallbackYesYesSafest long-term approach

Step 1: Fetch /Organisation Without SDK Enum Deserialization

Here’s the .NET pattern we use in production.

We bypass XeroAccountingApi.GetOrganisationsAsync() entirely for this one endpoint. We use RestSharp to fetch the JSON directly:

using RestSharp;
using Newtonsoft.Json;

public class XeroOrganisationDto
{
    public string OrganisationID { get; set; }
    public string Name { get; set; }
    public string LegalName { get; set; }
    public string CountryCode { get; set; }
    public string BaseCurrency { get; set; }

    // Critical: type as string, NOT as the SDK's OrganisationType enum.
    public string OrganisationType { get; set; }
}

public class XeroOrganisationResponse
{
    public List<XeroOrganisationDto> Organisations { get; set; }
}

public async Task<XeroOrganisationDto> GetOrganisationSafelyAsync(
    string accessToken,
    string xeroTenantId)
{
    var client = new RestClient("https://api.xero.com/api.xro/2.0");
    var request = new RestRequest("Organisation", Method.Get);
    request.AddHeader("Authorization", $"Bearer {accessToken}");
    request.AddHeader("Xero-tenant-id", xeroTenantId);
    request.AddHeader("Accept", "application/json");

    var response = await client.ExecuteAsync(request);

    if (!response.IsSuccessful)
    {
        throw new XeroIntegrationException(
            $"Failed to fetch organisation: {response.StatusCode} {response.Content}");
    }

    var parsed = JsonConvert.DeserializeObject<XeroOrganisationResponse>(response.Content);
    return parsed?.Organisations?.FirstOrDefault();
}

Notice the critical line: public string OrganisationType { get; set; }.

Not an enum. A string. That’s the whole fix.

Step 2: Map OrganisationType to an Internal Enum with Unknown Fallback

Now in your own domain code, map the raw string to your internal type. Always include an Unknown fallback:

public enum InternalOrgType
{
    Unknown, LimitedCompany, LlcCCorporation, LlcPartnership, LlcSCorporation,
    LlcSoleOwner, Partnership, SoleTrader, Trust, Charity, Nonprofit,
    PrivateFoundation, SCorporation, CCorporation, SoleProprietor
}

public static InternalOrgType MapXeroOrgType(string raw) => raw switch
{
    "COMPANY"            => InternalOrgType.LimitedCompany,
    "LLC_C_CORPORATION"  => InternalOrgType.LlcCCorporation,
    "LLC_PARTNERSHIP"    => InternalOrgType.LlcPartnership,
    "LLC_S_CORPORATION"  => InternalOrgType.LlcSCorporation,
    "LLC_SOLE_OWNER"     => InternalOrgType.LlcSoleOwner,
    "PARTNERSHIP"        => InternalOrgType.Partnership,
    "SOLETRADER"         => InternalOrgType.SoleTrader,
    "TRUST"              => InternalOrgType.Trust,
    "CHARITY"            => InternalOrgType.Charity,
    _                    => InternalOrgType.Unknown  // critical safety net
};

The key line is the last one. _ => InternalOrgType.Unknown.

That’s your safety net. Any new value Xero adds today, tomorrow, next year falls through to Unknown instead of crashing.

Important note on the wire-format strings: Xero does not publicly document the exact strings their API returns for US LLC variants. You have to discover them empirically.

Connect a test Xero org of each type in a non-production environment and log what comes back. Build your mapping iteratively as you observe new values.

If your team does not want to maintain edge-case handling across multiple accounting APIs in-house, this is the type of Xero integration logic that can be moved into a managed integration layer.

How to Apply the Fix in Java, Node, Python, PHP, and Ruby

The pattern translates cleanly. Same move every time: skip the SDK’s typed model, fetch raw JSON, parse into a DTO where the org type is a string.

  • Java OkHttp + Jackson. Parse into a POJO with organisationType as String.
  • Node / TypeScript axios or fetch. Type the response interface with organisationType: string. Skip the xero-node Accounting client.
  • Python requests + standard json module. Or pydantic with OrganisationType: Optional[str].
  • PHP Guzzle + json_decode($body, true). Array access only.
  • Ruby Faraday or HTTParty + standard JSON module.

In every language, the rule is the same: do your enum mapping after the HTTP boundary. Never let a third-party API enum cross into a deserializer that throws on unknown values.

The Bigger Lesson: Treat Third-Party API Enums as Unstable

This bug isn’t really about Xero.

It’s a specific instance of a much bigger anti-pattern.

Any time an SDK author defines an enum that corresponds to a value returned by a third-party API, that enum is going to drift. Your deserializer is going to crash.

It’s not a question of whether. It’s a question of when.

Think of an SDK enum like a dictionary printed in 2023

The language keeps evolving. New words enter common use every year.

If your code throws an exception every time it encounters a word that wasn’t in the printed edition, your application becomes brittle by design.

The moment anything in the upstream world changes, you ship a production incident you didn’t write.

The principle: At the HTTP boundary, treat third-party enums as strings. Map them to your own internal types, in your own code, where you fully control the failure mode.

The cost is a few extra lines. The benefit is that your integration cannot be broken by an upstream change you didn’t see coming.

Apply this to every API integration you build. Not just Xero.

When Should You Audit Your Xero Integration Code?

If any of the following describe your app, yes. Audit today.

1. You support US customers on a multi-tenant Xero integration

Most US businesses select an LLC variant. Most of your US connections will crash on the first /Organisation call.

2. You call /Organisation in your OAuth callback

This is the most common place the crash hits. It runs the moment the customer finishes connecting. The customer sees “connection failed” and bounces.

3. You use /Organisation to detect currency or country

Multi-currency logic, tax handling, regional defaults all depend on a successful /Organisation call. One LLC customer and the whole flow is dead.

4. You wrapped the SDK in a try/catch and assumed the exception was transient

It isn’t. The failure is permanent for that customer’s tenant. They can’t change it unless they update their Xero settings. They won’t.

Audit checklist: Search your codebase for GetOrganisationsAsync, getOrganisations, or any direct /Organisation SDK call.

Check your error logs for JsonSerializationException, JsonMappingException, ValueError, or ArgumentError on the Organisation endpoint. You may already be silently failing for some of your customers.

Xero OrganisationType Audit Checklist

Check your codebase for:

  • Direct SDK calls to /Organisation
  • Strong enum usage for OrganisationType
  • OAuth callback logic that depends on organisation details
  • Tenant setup logic that expects only known organisation types
  • Missing fallback for unknown API values
  • Error logs containing JsonSerializationException, ValueError, JsonMappingException, or enum parsing errors
  • Customer support tickets mentioning failed Xero connection after successful login

FAQs About Xero SDK OrganisationType Errors

What causes the Xero SDK OrganisationType exception?
The exception usually happens when Xero returns an OrganisationType value that is not available in the SDK’s fixed enum list. The OAuth connection may complete successfully, but the integration can fail when it calls the /Organisation endpoint and the SDK tries to deserialize an unsupported organisation type.
Why does the Xero integration fail for US LLC customers?
US organisations can use LLC-related business types that may not be represented in the SDK enum. When a customer with one of these organisation types connects their Xero account, the API can return a value the SDK does not recognize. Instead of treating it as an unknown value, the SDK may throw a deserialization or enum parsing exception.
Does the OrganisationType exception break the Xero OAuth flow?
No, not directly. The OAuth flow can still complete and return a valid access token. The failure usually happens after OAuth, when your app calls the /Organisation endpoint to fetch tenant or company details. That is why the issue can look confusing: the customer signs in successfully, but the connection still fails during setup.
Which Xero SDKs can be affected by this issue?
Any Xero SDK that maps OrganisationType to a fixed enum can be affected if the API returns a value that is not included in the SDK-generated enum. This can impact SDKs across languages such as .NET, Java, Node.js, Python, PHP, and Ruby, depending on how each SDK handles unknown enum values.
Can I fix the Xero OrganisationType error by using an older SDK version?
Usually, no. Pinning or downgrading the SDK is not a reliable fix because older SDK versions may still have the same fixed enum limitation. It can also create security, compatibility, and maintenance issues. A safer approach is to avoid depending on the SDK enum for this field and handle OrganisationType as a string at the API boundary.
Will Xero fix the OrganisationType enum issue in a future SDK release?
Possibly, but production integrations should not depend on that. Even if an SDK update adds missing enum values, new organisation types can appear later before the SDK is regenerated. Your integration should be designed to handle unknown API values without crashing.
What is the safest way to handle Xero OrganisationType in production?
The safest approach is to fetch the raw /Organisation API response, treat OrganisationType as a string, and map known values to your own internal enum. Always include an Unknown fallback so that new or unsupported organisation types do not break the customer connection flow.
Can a try/catch block solve the Xero OrganisationType exception?
A try/catch block may stop the entire application from crashing, but it does not properly solve the issue. If the integration still cannot process the organisation data, the customer connection may remain incomplete. The better fix is to prevent the deserialization failure by treating the organisation type as a string and mapping it safely after the API response is received.
How can I check if my Xero integration is affected?
Check whether your app calls the /Organisation endpoint after OAuth and whether it depends on the SDK’s OrganisationType enum. Also review logs for errors such as JsonSerializationException, JsonMappingException, ValueError, InvalidArgumentException, or enum parsing failures during Xero onboarding.
How can I find the actual OrganisationType values returned by Xero?
Test with Xero organisations that use the relevant business types and log the raw /Organisation API response before SDK enum conversion. Run this in a controlled test or staging environment. Use the observed values to update your internal mapping, but keep an Unknown fallback for future values you have not seen yet.
Should developers report this issue upstream?
Yes, reporting SDK enum issues upstream is helpful. However, it should not be your only fix. Third-party APIs can change faster than SDKs are updated, so your production integration should still handle unknown enum values defensively.
Is this issue specific only to Xero integrations?
No. Xero is the example in this blog, but the broader issue can happen with any third-party API where the SDK uses fixed enums for values controlled by the external platform. Accounting, CRM, ERP, payment, and eCommerce APIs can all introduce new values before SDKs are updated.

Final Recommendation for Xero Integration Teams

Six official Xero SDKs. One shared OpenAPI spec. Thirteen enum values. Zero LLC variants.

A rejected TolerantEnumConverter Proposal from 2020 that would have prevented this entire class of bugs.

And a production failure mode that silently breaks every multi-tenant Xero integration the moment a US LLC customer tries to connect.

What to do right now

  1. Bypass the SDK for /Organisation
  2. Treat OrganisationType as a string, not an enum
  3. Map to your own internal enum with an Unknown fallback
  4. Apply the same defensive pattern to every other Xero enum you depend on (PhoneType, BankAccountType, SystemAccount, ReportTaxType, OrganisationClass)
  5. Do the same thing for every third-party API integration you build. Not just Xero.

Not sure if your integration is exposed? We’ll tell you in 30 minutes. Book a free Xero integration audit and we’ll review your /Organisation call sites and show you exactly where the crashes will happen.

Book a Free Xero Integration Audit

Sources

Article by

Chintan Prajapati

Chintan Prajapati is the Founder and CEO of Satva Solutions and a seasoned computer engineer with over two decades of experience in the software industry. His expertise spans Accounting & ERP Integrations, Robotic Process Automation, and the development of technology solutions built around leading ERP and accounting platforms with a particular focus on responsible AI and machine learning in fintech.Chintan holds a BE in Computer Engineering and carries an impressive roster of certifications, including Microsoft Certified Professional, Microsoft Certified Technology Specialist, Certified Azure Solution Developer, Certified Intuit Developer, Certified QuickBooks ProAdvisor, and Xero Developer.Over the course of his career, he has made a measurable impact on the accounting industry consulting on and delivering integration and automation solutions that have collectively saved thousands of man-hours. His writing aims to offer readers practical, insight-driven advice on harnessing technology to unlock greater business efficiency.When he steps away from the desk, Chintan can be found trekking through mountain trails or watching birds in the wild. Grounded in the philosophy of delivering the highest value to clients, he continues to champion innovation and excellence in digital transformation from his home base in Ahmedabad, India.