API: Changes and deprecations
Sist oppdatert: 23.10.2026The Luca API has a single GraphQL schema with no version numbers. The v1 in /api/v1/graphql belongs to the
endpoint, not to the schema, so there is no older version to stay on. When we change the schema, we change it for
everyone. This page explains how we do that, so you know what to expect, and lists every change we have made.
How we change the API
Changes we make at any time
We add to the schema all the time: new types, new fields, new optional arguments and input fields, and new enum values. None of these affect a query that already works, so we make them without notice.
Your integration should be written to cope with them:
- Ignore fields in a response you did not ask for or do not know.
- Handle an enum value you do not recognise, for example by treating it as “other” instead of failing.
Changes we announce first
Everything else breaks somebody: removing or renaming a field, argument, input field or enum value, making an argument required, or changing a field’s type. We never make such a change in a single step.
- We add the replacement first.
- We mark the old field as deprecated. It gets GraphQL’s
@deprecateddirective, with a reason naming what to use instead, and is listed below under Deprecated fields together with the date. - The deprecated field keeps working, unchanged, for at least six months from that date.
- After six months we may remove it at any time. When we do, the list below shows the date we removed it, and the changelog says so too.
We may remove a deprecated field sooner than six months if we can see that no integration is using it.
Security fixes
If a field or argument has to change to fix a security problem, we change it straight away, without a deprecation period, and document the change here afterwards.
How to keep up
- Check this page. Most GraphQL clients, such as Insomnia, Altair and GraphiQL, also strike through deprecated
fields when you write a query, and an introspection query returns them with
isDeprecated: trueand thedeprecationReason. - Move off a deprecated field when you next work on your integration, not when it disappears.
- Contact support@lucalabs.com if a deprecation leaves you without something you need. We would rather hear about it before the field is gone.
Deprecated fields
Everything we have deprecated, newest first. A field without a date under “Removed on” still works. A removed field stays in this table for three months after we removed it, and in the changelog for good.
| Deprecated | Use instead | Deprecated on | Removed on |
|---|---|---|---|
tag, tags, tagCreate, tagUpdate, tagDestroy |
Nothing, tags are no longer supported | 23.10.2026 | – |
BookkeepingPostingLine.tags, SaleProduct.tags, SaleProductInput.tagIds, bookkeepingGeneralLedger(tagIds:) |
Nothing, tags are no longer supported | 23.10.2026 | – |
EntryCreateInput.salaryEmployeeId, EntryUpdateInput.salaryEmployeeId |
workedById (already ignored) |
22.10.2026 | – |
timesheetEntries(salaryEmployee:) |
workedBy |
22.10.2026 | – |
TimesheetEntry.finalized, EntryCreateInput.finalized, EntryUpdateInput.finalized |
submitted |
21.10.2026 | – |
PaymentInput.payments |
paymentOn, amountCents, bankAccountId and sign on PaymentInput itself (already rejected with an error) |
13.04.2026 | – |
SaleCustomer.addressCity, SaleCustomerInput.addressCity |
addressPlace |
13.11.2025 | 23.10.2026 |
PurchaseSupplier.addressCity, PurchaseSupplierInput.addressCity |
addressPlace |
13.11.2025 | 23.10.2026 |
SaleCustomer.addressStreetOne, SaleCustomer.addressStreetTwo |
addressStreet |
20.11.2024 | 23.10.2026 |
PurchaseSupplier.addressStreetOne, PurchaseSupplier.addressStreetTwo |
addressStreet |
20.11.2024 | 23.10.2026 |
SaleCustomerInput.addressStreetOne, SaleCustomerInput.addressStreetTwo |
addressStreet |
20.11.2024 | 23.10.2026 |
PurchaseSupplierInput.addressStreetOne, PurchaseSupplierInput.addressStreetTwo |
addressStreet |
20.11.2024 | 23.10.2026 |
PurchaseReviewStatusTypes.NOT_REVIEWED |
NOT_CONSIDERED |
16.06.2023 | 23.10.2026 |
BankAccount.openDate |
openedOn |
31.08.2021 | 23.10.2026 |
Changelog
Every change to the API an integration could notice, newest first. Changes marked Breaking stop an existing query from working.
23 October 2026
- Deprecated tags, which are no longer supported: the
tagandtagsqueries, thetagCreate,tagUpdateandtagDestroymutations,BookkeepingPostingLine.tags,SaleProduct.tags,SaleProductInput.tagIdsandbookkeepingGeneralLedger(tagIds:). timesheetEntryUpdatekeeps thebillableDurationyou send, where it used to reset it toduration, and leaves it unchanged when you leave it out.- Breaking: Removed members that had been deprecated for more than six months:
BankAccount.openDate(useopenedOn), theNOT_REVIEWEDvalue ofPurchaseReviewStatusTypes(useNOT_CONSIDERED), and onSaleCustomer,PurchaseSupplier,SaleCustomerInputandPurchaseSupplierInput,addressStreetOneandaddressStreetTwo(useaddressStreet) andaddressCity(useaddressPlace). Updating a customer or supplier withoutaddressStreetnow leaves the street address as it was. - Breaking:
SubscriptionAddon.EXPENSE_REPORTSis renamedTRAVEL_AND_EXPENSES, soCompany.subscription.addonsreturns the new name.
22 October 2026
- Timesheet entries record who did the work and whether the hours are paid out:
TimesheetEntry.workedByandTimesheetEntry.payable, the inputsworkedByIdandpayableonEntryCreateInputandEntryUpdateInput, and the filtertimesheetEntries(workedBy:).salaryEmployeeIdon both inputs andtimesheetEntries(salaryEmployee:)are deprecated.salaryEmployeeIdis already ignored, because the employee now follows fromworkedById. - Added the permission levels
READ_OWNandFULL_OWNtoCompanyPermissionLevel, andSALARY_READ_OWNandTIMESHEET_FULL_OWNtoCompanyPermission. A user with one of them sees only their own payslips or timesheet entries.
21 October 2026
- Added
submittedtoTimesheetEntry,EntryCreateInputandEntryUpdateInput, and deprecatedfinalizedon all three. The steps now have to come in order: an entry has to be submitted before it can be approved, an approved entry cannot be unsubmitted, and only an approved entry can be invoiced.
9 October 2026
- Added
status: ActiveStatustosaleCustomers,purchaseSuppliersandsaleProducts. List queries no longer apply the web app's default filters, sosaleCustomerswithoutstatusreturns inactive customers too. - Added the
permissionsquery, which lists what the current user may do in the company asCompanyPermissionGrantvalues (aCompanyPermissionCategoryand aCompanyPermissionLevel). - Security fix:
paymentCreaterefuses a payment source that belongs to another company, and only a user allowed to edit the supplier or customer can overwrite its bank account number.
7 October 2026
- Added
Company.subscription, which returns the company's plan, add-ons, modules and subscription status. - Added filters to
timesheetEntries:registeredBy,project,activityType,salaryEmployee,approved,billable,invoicedandpaidOut. AddedTimesheetEntry.editableandTimesheetEntry.destroyable. - Added
projects(active:),timesheetActivityTypes(project:)andTimesheetActivityType.saleProduct.
6 October 2026
- Added
PurchaseInvoice.fileName,fileUrlandcontentType, for the document behind a booked purchase.
2 October 2026
- Breaking:
PurchaseInvoiceLineItem.debitAccountcan now benull, on a draft line that has no account yet. AddedamountCents,currencyandkidtoPurchaseInvoice,kidtoPurchaseInvoiceInput,descriptiontoPurchaseInvoiceLineItemand its input,bankAccountNumbertoPurchaseSupplierInput,messagetoPaymentandPaymentInput,PaymentInput.bankTransactionId, andbankTransactions(matched:).
30 September 2026
purchaseInvoiceCreatecan book a document from the inbox withinboxItemId. AddedBookkeepingAccount.vatCodesanddefaultVatCode, theVatCodetype, andPurchaseSupplier.defaultAccountanddefaultVatCode.
29 September 2026
- Added
predictiontoPurchaseInvoiceandInboxItem: what we read from the document, each value with a confidence, and astatuswhile the reading is still running.
26 September 2026
- Added the
meandinboxItemqueries,InboxItem.fileUrlandcontentType, and the mutationsinboxItemCreate(upload a document as base64) andinboxItemDestroy.
22 September 2026
- Added
SaleInvoice.urlandPurchaseInvoice.url, links to the invoice in the web app.purchaseInvoiceCreateaccepts the voucher as base64 throughfileBase64andfileName, as an alternative to a multipart upload.
21 September 2026
- Added the document inbox: the
inboxItemsquery, theInboxItemtype and theinboxItemRegistermutation.
19 September 2026
company(id:)may be called without anid, and returns the current company. AddedbankTransactions(beginningOn:, endingOn:),saleInvoices(dueDateBeginningOn:, dueDateEndingOn:, settled:)andSaleInvoice.dueDate.
18 September 2026
- Every error carries a machine-readable
extensions.code, one of nine. Branch on the code, not on the message. A field the user may not read now answersFORBIDDENfor that field instead of failing the whole request, and error messages are always in English.
17 September 2026
- Breaking: New OAuth server: OAuth 2.1 with the authorization code flow and PKCE, described in API: Authenticate with OAuth2. OAuth applications and tokens from the old server stopped working, and a client secret alone is no longer accepted. One consent can cover several companies, so every query and mutation takes an optional
companyId, which an OAuth token has to give (or sendX-Luca-Company). Mutations need theaccounting.writescope. Personal API keys work as before.
13 September 2026
- Breaking: Fixed fields that failed whenever they were selected:
BookkeepingPostingLine.tagsis now a list,[Tag!], andSalaryPayslipLineItem.employeeresolves.purchaseSuppliersnow returnsPurchaseSupplierConnectioninstead ofSaleCustomerConnection.PurchaseInvoice.reviewStatusreturnsNOT_CONSIDEREDwhere it returnedNOT_REVIEWED, andPayment.sourceIdis the hashed id the rest of the API uses.
11 September 2026
- Breaking: Removed Vipps as a way to send an invoice: the
VIPPSvalue ofSaleSendMethodandsaleInvoiceSend(phoneNumber:). - The depth limit now applies to every query, and a query that runs too long is stopped and answered with
TIMEOUT. Security fix: looking a record up by id refuses one that belongs to a company the caller has no access to.
9 September 2026
- Added
bookkeepingAccounttoBankAccount,SaleCustomerandPurchaseSupplier, the ledger account each one posts to.
3 September 2026
- Added
bankReconciliationMatchCreateandbankReconciliationMatchDestroy. List queries paginate properly withfirstandafter; before, they stopped at 25 rows and could reporthasNextPagewrongly.
2 September 2026
- Added bank reconciliation matching:
BankReconciliation.matches,postingsandtransactions,BankTransaction.match,BookkeepingPosting.description, and theReconciliationMatchandReconciliationPostingtypes.
22 June 2026
- Breaking: Mutations depend on the company's plan. Sales mutations need the Accounting or Invoicing plan, every other mutation needs Accounting, and a company without it gets an error (
PLAN_REQUIREDsince 18 September 2026).
13 April 2026
- Breaking:
paymentCreatetakes the payment directly onPaymentInput:paymentOn,amountCents,bankAccountIdandsignare required, and thepaymentslist is deprecated and rejected with an error. AddedapproveLaterandrecipientBankAccountNumber.
31 March 2026
- Added
vpstoBankAccountTypes, for VPS accounts.
30 March 2026
- Breaking: Removed
BankAccount.integrationRequested.
26 March 2026
- Added the
purchaseInvoiceDestroymutation.
15 December 2025
- Breaking: Removed
BookkeepingPosting.postingType. - Breaking:
productIdonActivityTypeCreateInputandActivityTypeUpdateInputis renamedsaleProductId.
4 December 2025
- Added
ALTINN_SYSTEM_USER_NONE,ALTINN_SYSTEM_USER_READandALTINN_SYSTEM_USER_FULLtoCompanyPermission.
13 November 2025
- Added
addressPlacetoSaleCustomer,PurchaseSupplierand their inputs, and deprecatedaddressCity.
24 October 2025
- Breaking:
addressCityonSalaryEmployee,EmployeeCreateInputandEmployeeUpdateInputis replaced byaddressPlace. AddedcountryNumberto all three.
7 October 2025
- Breaking: The values of
BankAccountTypesare now lower case:standard,tax_deduction,internationalandcredit_card.