Why breaking changes ?

At Sage Active, we strive to maintain backward compatibility to ensure a seamless experience for our users.

Most changes to our API are designed to be non-disruptive and are implemented in a way that preserves existing functionality.
However, there are exceptions where, in the best interest of the product and its users, breaking compatibility is necessary.

In such cases, maintaining an element that could negatively impact performance, security, or usability would be detrimental to the overall user experience and the product’s evolution.
Therefore, when a breaking change is unavoidable, it is made with careful consideration of its necessity and potential benefits, aiming to minimize disruption and provide clear migration paths for all affected users.

Here is a list of recent breaking changes that you may need to adapt to:

Resource: Accounting Entries

2026 June

  • Change: The input field isGroupingInvoices of type Boolean! was added to AccountingEntryLineCreateUsingCodesGLDtoInput and AccountingEntryLineCreateUsingIdsGLDtoInput.

  • Reason:
    • This field is required in the schema, but the server automatically assigns a default value of false when the field is not provided.
  • Impact:
    • Despite being marked as non-nullable (Boolean!), this change does not break existing integrations.
    • Existing GraphQL mutations that create accounting entry lines without providing this field will continue to work as before.
  • Solution:
    • No action is required.
Resource: Organization Sales Setup

2026 June

  • Change: The fields allowPostingSalesInvoice and allowPostingPurchaseInvoice were removed from the object type OrganizationSalesSetupGLDto.

  • Reason:
    • These fields always returned the same value; exposing them in the schema was no longer necessary.
  • Impact:
    • There is no compatibility break: queries that still request these fields continue to work.
  • Solution:
    • You may remove allowPostingSalesInvoice and allowPostingPurchaseInvoice from your organizationSalesSetupByOrgId query for clarity and to match the published schema; keeping them is harmless.
Resource: User Profile

2026 June

  • Change: The field Query.userProfile changed type from UserProfileGLDto to UserProfile.

  • Reason:
    • This is an internal schema adjustment; the exposed shape and behaviour of userProfile for integrators are unchanged.
  • Impact:
    • No impact on how partners use the Public API.
  • Solution:
    • No action is required.
Resource: Sales Documents

2026 June

  • Change: The input fields contactEmail, contactName, and contactPhone were removed from:
    • SalesDeliveryNoteCreateGLDtoInput and SalesDeliveryNoteUpdateGLDtoInput
    • SalesInvoiceCreateGLDtoInput and SalesInvoiceUpdateGLDtoInput
    • SalesOrderCreateGLDtoInput and SalesOrderUpdateGLDtoInput
  • Reason:
    • These fields were published by mistake on create and update inputs although they are not supported on those operations.
  • Impact:
    • There is no compatibility break: if these fields are still present in the mutation payload, the request does not fail — the values are simply ignored.
  • Solution:
    • You may remove contactEmail, contactName, and contactPhone from your create and update payloads for clarity and to match the published schema; keeping them is harmless.
Resource: Customers

2026 May

  • Change: The input fields nonIdentifiedCustomer and printNameOnPdf, both of type Boolean!, were added to CustomerCreateGLDtoInput.

  • Reason:
    • These fields are required in the schema, but the server automatically assigns a default value of false when the field is not provided.
  • Impact:
    • Despite being marked as non-nullable (Boolean!), this change does not break existing integrations.
    • Existing GraphQL mutations that create customers without providing these fields will continue to work as before.
  • Solution:
    • No action is required.
Resource: Sales Invoices

2026 May

  • Change: The input field printNameOnPdf of type Boolean! was added to SalesInvoiceCreateGLDtoInput.

  • Reason:
    • This field is required in the schema, but the server automatically assigns a default value of false when the field is not provided.
  • Impact:
    • Despite being marked as non-nullable (Boolean!), this change does not break existing integrations.
    • Existing GraphQL mutations that create sales invoices without providing this field will continue to work as before.
  • Solution:
    • No action is required.
All Resources

2026 April

  • Change:
    Various input fields were removed from *CreateGLDtoInput and *UpdateGLDtoInput types across resources. The list is not reproduced here field by field.

  • Reason:
    This is a global schema cleanup: those inputs exposed fields that were not aligned with what create and update operations actually support or apply, which made the contract misleading.

  • Impact:
    There is no practical compatibility break for integrations: the removed fields remain accepted when sent on create or update requests; they simply have no effect on how the operation is processed.

  • Solution:
    You may drop these fields from your payloads for clarity and to match the published schema; keeping them is harmless from a processing perspective.

Resource: Operational Number Preset Texts

2026 April

  • Change: The field operation on OperationalNumberPresetText changed type from String to OperationType (enumeration).

  • Reason:
    The field was incorrectly published as a string; it must reflect the OperationType enum.

  • Impact:
    • Filters: There is no change to how you write filters on this field: filter inputs already used the enumeration.
    • Responses: Values returned for operation on the object are now serialized in uppercase snake case (e.g. DELIVERY_NOTE) instead of camelCase. Any client logic that compared or parsed the old string shape should be updated accordingly.
  • Solution:
    Rely on the enum values as returned by the API (uppercase snake case), or normalize comparisons to match the new serialization.
Resource: User Profile

2026 March

  • Change: The field userId was removed from the object type UserProfile.

  • Reason: The field had only just been added; it duplicated the existing id field on the same type, so it was removed as redundant.

  • Solution: Use id instead of userId when you need the user identifier from UserProfile.

Resource: Sales Invoices

2026 February

  • Change:
    • The input field sourceId was removed from SalesInvoiceLineCreateGLDtoInput.
    • The input field originId of type UUID was added to SalesInvoiceLineCreateGLDtoInput.
  • Reason:
    • This change is part of the introduction of the Sales Document Transformation Flow.
    • The transformation flow requires both the identifier and the type of the originating document in order to correctly reference source documents and their lines.
    • As part of this model, the originType field was introduced to explicitly represent the business document type (Quote, Order, Delivery Note, etc.).
    • The existing sourceType field is already used for a different purpose: identifying the technical origin of the document creation.
    • Keeping sourceId alongside originType would have been semantically inconsistent and misleading, as sourceId would no longer match the meaning of sourceType.
    • Renaming sourceId to originId ensures a clear and consistent API contract, where originType and originId are used together to represent the business origin of transformed documents.
  • Impact:
    • This change is a breaking change.
    • However, the risk of regression is limited, as sourceId was introduced very recently.
    • Existing integrations that relied on sourceId will need to be updated.
  • Solution:
    • Replace any usage of sourceId with originId.
    • No other functional change is required.
Resource: Products

2026 January

  • Change: The input field useWithholding of type Boolean! was added to ProductCreateGLDtoInput.

  • Reason:
    • This field is required in the schema, but the server automatically assigns a default value of false when the field is not provided.
  • Impact:
    • Despite being marked as non-nullable (Boolean!), this change does not break existing integrations.
    • Existing GraphQL mutations that create products without providing this field will continue to work as before.
  • Solution:
    • No action is required.
All Resources

2025 December

  • Change: The following directive arguments were updated:
    • temporaryPreventAccessValidation was removed from the accessControl directive
    • temporaryPreventFeatureValidation was removed from the feature directive
    • The argument filter was added to both the accessControl and feature directives
  • Reason:
    This change is part of an internal cleanup and normalization of directive arguments in the GraphQL security and feature-flagging layer.
    The legacy temporaryPrevent* arguments were transitional and are no longer required. The new filter argument provides a more consistent and extensible mechanism to control access and feature exposure.

  • Impact:
    • This change is schema-visible and therefore classified as a breaking change from a strict GraphQL introspection perspective.
    • However, it has no functional impact on API consumers:
      • No existing queries or mutations need to be modified
      • No runtime behavior changes for authenticated users
      • No authorization or feature access rules are affected
    • Only tooling that directly inspects directive arguments for these specific names may observe the change.
  • Solution:
    • No action is required for standard API usage.
    • If you rely on schema introspection for custom tooling or validation, simply update your logic to reflect the new filter argument.
All Resources

2025 September

  • Change: The cost directive has undergone structural changes during the migration from HotChocolate v13 to v15:
    • The argument weight was added
    • The arguments complexity, defaultMultiplier, multipliers and MultiplierPath were removed
  • Reason: In HotChocolate v15, the internal cost analysis system was redesigned to simplify and standardize performance cost estimation across resolvers.
    The former approach using complexity, defaultMultiplier, multipliers and MultiplierPath has been deprecated in favor of a single weight argument that is easier to configure and interpret. This is part of a broader refactoring of the execution engine in HotChocolate to make middleware resolution and cost-based batching more predictable and performant.
  • Impact:
    • Any custom usage or tooling that relied on the previous cost directive arguments will break unless updated.
    • If you used @cost(complexity: X) or similar in your schema extensions or stitching logic, you must now use @cost(weight: X) instead.
    • Existing introspection queries or documentation tools expecting the old arguments will no longer find them.
    • This change reflects a breaking change in the GraphQL schema and may cause errors at runtime if clients still attempt to use the old directive structure.
  • Solution:
    • Update all usages of the @cost directive to conform to the new syntax introduced in HotChocolate v15.
    • Review all schema stitching and introspection-dependent tooling to ensure compatibility with the updated directive shape.
Resource: All resources using DateOperationFilterInput

2025 September

  • Change:
    • Type Date was removed
    • All input fields in DateOperationFilterInput changed from Date to DateTime:
      • eq, neq, gt, gte, lt, lte, ngt, ngte, nlt, nlte
      • in and nin changed from [Date] to [DateTime]
  • Reason:
    The Date scalar type was used exclusively in filter operators. In Sage Active, business dates such as invoice dates or accounting entry dates use a date-only format, while system dates like creationDate and modificationDate use full datetime values.

    In HotChocolate 13, the Date type in filters was permissive: it accepted both date-only and datetime values, even though the time part was ignored.
    In HotChocolate 15, this behavior is no longer supported. For consistency and compatibility, the Date type has been removed from filters and replaced by DateTime.

  • Impact:
    Filters that pass datetime or date-only values directly (e.g., in literals or Postman queries) will continue to work as before.
    The only breaking change occurs if your GraphQL query variables were explicitly typed as Date and used to filter business dates. In this case, you must update the variable type from Date to DateTime.

    The impact should be minimal or nonexistent, as production API usage statistics show no cases where variables of type Date were declared for date filters.

  • Recommendation:
    Review your client-side code and update any GraphQL variables typed as Date to use DateTime, especially if used in filters involving business dates.
Resource: Journal Types, Products, Suppliers, Customers

2025 May

  • Change: The following input fields were removed:
    • accountingEntryTemplateId from JournalTypeCreateGLDtoInput
    • purchaseUnitPrice from ProductCreateGLDtoInput
    • blockDeliveryNoteEnabled, blockInvoiceEnabled, and blockOrderEnabled from both SupplierCreateGLDtoInput and SupplierUpdateGLDtoInput
  • Change: Several fields in the CustomerSortInput and SupplierSortInput input types changed type:
    • countryAcronym from StringOperationFilterInput to SortEnumType
    • documentType from DocumentTypeFilterInput to DocumentTypeSortInput
    • documentTypeId from UuidOperationFilterInput to SortEnumType
    • tradeName from StringOperationFilterInput to SortEnumType
  • Reason:
    • The removed fields were part of a feature that was ultimately not implemented and never made officially available. This is a cleanup of unused elements.
    • The type changes reflect a cleanup and standardization effort: sort inputs should use only sort-compatible types (SortEnumType) and not filtering types.
  • Solution:
    • Ensure that no GraphQL queries rely on the removed fields. Since they were never functional, their removal has no impact on integration.
Resource: User Profile

2025 May

  • Change: The fields activeOrganizationId, activeTenantId, and activeLegislationCode now return empty values (GUID.empty for the first two, and null for the last).
  • Reason: These fields have not been meaningful for over a year, following a change in how organizations are authorized for a user, they can now technically belong to different tenants.
    Although these fields were removed from the documentation, they remained in the API to avoid execution errors when querying userProfile.
  • Solution: Remove these fields from the userProfile query. They are no longer relevant and will be permanently removed in a future version.
Resource: Sales Documents

2025 Apr

  • Change: The sourceType input field for sales document filters (SalesQuoteFilterInput, SalesOrderFilterInput, SalesInvoiceFilterInput, and SalesDeliveryNoteFilterInput) no longer accepts null.
  • Reason: Previously, sourceType was nullable. Now, it always takes a value: SALES when the document is manually entered, and PUBLIC_API when created through the API.
  • Solution: Update filters to explicitly set sourceType, depending on the origin of the document.
Resource: Accounting Entries

2025 Feb

  • Change: The dataloader accountingEntry and the field accountingEntryId were removed from the salesInvoices dataloader, which is accessible from accountingEntries.
  • Reason: While it was technically functional, exposing accountingEntries through this dataloader was redundant, as the query already originated from the accounting entry. Additionally, it introduced a circular reference issue when sales invoices contained advance payment deductions, leading to multiple accounting entries being linked to the same sales invoice.
  • Solution: It remains possible to access the sales invoice header from an accounting entry if it exists.
Resource: Taxes Treatment

2025 Feb

  • Change: The types AccountingAccountGLDto and TaxTreatmentGLDto were removed.
  • Reason: The list of Tax Treatments was already available through the dataloader logic, accessible from AccountingAccount. However, the list of Tax Treatments as a standalone entity remained as a DTO, as an exception to the general rule introduced with dataloaders.
    Additionally, TaxTreatmentGLDto contained published fields that were not being used.
  • Solution: If you were using a field from TaxTreatmentGLDto that has been removed due to being unused, simply remove it from your query. No other modifications are required as the Tax Treatment list remains accessible through AccountingAccount.
Resource: Sales Documents

2025 Jan

  • Change: Fields xxxx changed type from Int to Decimal.
  • Reason: The January version of Sage Active introduces the ability to handle quantities with decimals in sales documents.
    This results in technical breaking changes as quantities now shift from Int to Decimal. However, this does not impact existing developments because Decimal supports Int.
  • Solution: No modifications are required, as compatibility is maintained.
Resource: Purchase Invoices

2024 Dec

  • Change: The input field taxGroupId was removed from the input object type PurchaseInvoiceLineCreateGLDtoInput.
  • Reason: The API schema has been updated to simplify the handling of tax groups, ensuring a more streamlined and consistent data structure for purchase invoice lines.
  • Solution: Remove any references to the taxGroupId field in your Purchase Invoices mutations.
Resource: Purchase Invoices

2024 Nov

  • Change: The input field lines was removed from the input object type PurchaseInvoiceCreateGLDtoInput. The input field vatLines of type [PurchaseInvoiceLineCreateGLDtoInput!]! was added instead.
  • Reason: The structure of the purchase invoice creation process has been improved to better handle VAT lines separately, providing more clarity and precision in the data model.
  • Solution: Update your queries and mutations by replacing references to the lines input field with the new vatLines input field.
Resource: Organizations

2024 Oct

  • Change: The status field of organizations is no longer relevant and should not be used to check the status of organizations.
  • Reason: Access permission management for an organization now depends on business management, which allows, for example, the termination of a business’s use. Additionally, the status field always returns the value READY, making it meaningless for determining an organization’s status.
  • Solution: Either remove the status field if it was referenced in queries on organization, or, if kept, ensure that its returned value is no longer taken into account.
Resource: SalesInvoice Post Sales Invoice, Sales Open Items settlement

2024 Oct

  • Change: The Id field in response use by PostSalesInvoice service and SalesOpentItemSettlment service is removed and change by accountingEntryId.
  • Reason: accountingEntryIdindicates that it is the ID of the accountingEntry and not Id of SalesInvoice.
  • Solution: Simply replace the Id field by the accountingEntryId field when it was referenced in actions on PostSalesInvoice or SalesOpenItemSettlement.
Resource: Userprofile

2024 Sept

  • Change: The expirationDate field is removed from userprofile.
  • Reason: Access permission management for users now depends on business management, which allows, for example, managing the role of a user.
  • Solution: Simply remove the expirationDate field if it is referenced in queries on userprofile.
Resource: Products

2024 May

  • Change: The comments field length has been reduced from 65536 characters to 250.
  • Reason: This change was implemented to mitigate performance impact risks if large volumes are added.
  • Solution: Ensure during the creation and modification of products that the length of comment values does not exceed 250 characters. Replace overly lengthy content with a hyperlink that leads to a page displaying detailed comments.

img

Resource: Sales Documents

2024 May

  • Change: The mainAddress and deliveryAddress for salesDocuments were previously exposed as arrays. Now, they are presented in a simple format.
  • Reason: These objects contained only one element, and simplifying their structure facilitates filtering, such as retrieving sales quotes from clients in Brussels.
  • Solution: When retrieving data, remove the index [0].
    For example, use salesQuoteNode.mainAddress instead of salesQuoteNode.mainAddress[0].

img

Resource: Sales Documents

2024 May

  • Change: The id field has been removed from mainAddress and deliveryAddress in salesDocuments because it contained a non-significant value.
  • Reason: This change was made to streamline the data structure, as the id was not providing useful information.
  • Solution: Remove the id field from queries involving mainAddress and deliveryAddress.

img

Resources: Customers, Suppliers

2024 May

  • Change: The defaultAccountingAccountId field in Customers and Suppliers is no longer filterable or sortable.
  • Reason: The introduction of dataloaders has currently prevented filtering on this field, which was possible in previous versions. A solution is being studied for a future version.
  • Solution: Remove the filter or sort from the query and perform local filtering on the response data.

img

Resource: All Resources

2024 May

  • Change: In the syntax of queries using fragments, the DTO used to qualify fragment fields is no longer compatible due to the transition to data loaders.
  • Reason: This update is part of a move to simplify query writing and to enhance performance with the use of data loaders.
  • Solution: Replace the DTO name in the fragment syntax with the name of the resource in singular form, starting with a capital letter.
    Example for a query users, fragment UserProps on UserGLDto becomes fragment UserProps on User.
Resource: Other removed fields

2024 May

  • Changes: All of these fields are
    • salesQuotes -> action
    • salesOrders -> action
    • salesDeliveryNotes -> action
    • salesInvoices -> action
    • salesTariffs -> calculationBase
    • suppliers / thirdCollectorName
    • paymentMeans -> inactive
    • paymentMeans -> paymentMethodId
    • paymentMeans -> paymentMethodReferenceName
    • organizations -> isDefaultDeliveryAddress
    • organizations -> isDeliveryAddress
    • organizations -> isMainAddress
    • zipcode -> code
  • Reason: These fields were historically present but became inconsistent with the developments in Sage Active. They have been removed to avoid the implication that they may contain incoherent data.
  • Solution: Remove these fields from queries and modify the code responsible for retrieving data from the affected queries.
Resource: User Profile

2024 April

  • Change: The activeOrganizationId field no longer returns the current user’s active organization in Sage Active, but instead returns the first organization assigned to the user.
  • Reason: The information returned was no longer relevant, leading to its removal from the documentation, though the field still exists to prevent query errors.
  • Solution: Manage the current user’s organization in a local cache to retrieve it upon the user’s next login.

img