From 350ddc48e2d59effb7ff5580bb4f2c7c27fef129 Mon Sep 17 00:00:00 2001 From: Nathan Jackson Date: Fri, 7 Aug 2026 10:27:23 +0100 Subject: [PATCH 1/5] CONN-801: extend update bills/suppliers docs to Sage Intacct, NetSuite, Zoho Books - update-bill.md: coverage note, per-platform example payloads (including trackingRefs id formats), six-column software requirements table, new "Software-specific behavior" section, and error tabs for the three new platforms with verbatim error messages. - suppliers.md: coverage note and software-specific behavior tables for the three new platforms. - configure-customer.md: Sage Intacct (knfz) and Zoho Books (rwuv) added to the platformKey table. All platform behaviours were verified live against integration during CONN-799 acceptance testing rather than inferred from code. Co-Authored-By: Claude Fable 5 --- docs/payables/configure-customer.md | 2 + docs/payables/sync/suppliers.md | 32 ++++++- docs/payables/sync/update-bill.md | 141 ++++++++++++++++++++++++++-- 3 files changed, 166 insertions(+), 9 deletions(-) diff --git a/docs/payables/configure-customer.md b/docs/payables/configure-customer.md index 14e48e5d3..38ca0914f 100644 --- a/docs/payables/configure-customer.md +++ b/docs/payables/configure-customer.md @@ -131,7 +131,9 @@ This will allow you to synchronize data with that source, fetching or creating s | FreeAgent | `fbrh` | | Oracle NetSuite | `akxx` | | QuickBooks Online | `qhyg` | +| Sage Intacct | `knfz` | | Xero | `gbol` | +| Zoho Books | `rwuv` | As an example, let's create a QuickBooks Online (QBO) connection. In response, the endpoint returns a `dataConnection` object with a `PendingAuth` status and a `linkUrl`. Direct your customer to the `linkUrl` to initiate our [Link auth flow](/auth-flow/overview) and enable them to authorize this connection. diff --git a/docs/payables/sync/suppliers.md b/docs/payables/sync/suppliers.md index d1e89406f..26459a59b 100644 --- a/docs/payables/sync/suppliers.md +++ b/docs/payables/sync/suppliers.md @@ -64,7 +64,7 @@ Include all fields in the request, even if their values haven't changed. If you :::info Software coverage -This action is currently only supported for FreeAgent, QuickBooks Online, and Xero. +This action is currently only supported for FreeAgent, Oracle NetSuite, QuickBooks Online, Sage Intacct, Xero, and Zoho Books. ::: @@ -96,6 +96,36 @@ Each accounting software has some limitations when updating suppliers. We've sum | **Country** | It's not possible to clear the supplier's country. Sending a `null` value or excluding the field from the request sets the value to the company's default country. | | **Default currency** | FreeAgent doesn't support currency at supplier level. Any value sent in the request is ignored, and the response returns the company's base currency. | +#### NetSuite + +| Limitation | Description | +| -------------------- | ----------------------------------------------------------------------------------------------------------------------------------------------------------------- | +| **Status** | Always include `status` in the request. Omitting it reactivates an archived supplier. | +| **Contact name** | `contactName` is not supported on update. Any value sent in the request is ignored and the response returns `null`. | +| **Duplicate names** | Supplier names must be unique. Updating a name to match an existing supplier returns a `400` response. | +| **Supplier name** | Omitting `supplierName` clears it. Include the existing name if you don't want to change it. | +| **Default currency** | The currency must be enabled in the NetSuite organization, or the update returns a `400` response. Sending a `null` value leaves the existing currency unchanged. | +| **Country** | Address `country` must be a 2-character ISO code. | + +#### Sage Intacct + +| Limitation | Description | +| -------------------- | -------------------------------------------------------------------------------------------------------------------- | +| **Supplier name** | It's not possible to clear the supplier name. Sending a `null` value or excluding the field keeps the existing name. | +| **Default currency** | Sending a `null` value keeps the existing currency, but sending `""` clears the supplier's currency on the platform. | +| **Addresses** | Sage Intacct supports a single address per supplier, and the response returns the first address only. | +| **Contact name** | `contactName` is split on the last space into a first and last name, each limited to 40 characters. | + +#### Zoho Books + +| Limitation | Description | +| ---------------------- | ---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | +| **Supplier name** | It's not possible to clear the supplier name. Sending a `null` value or excluding the field keeps the existing name. | +| **Duplicate names** | Supplier names must be unique, unless the Zoho Books organization allows duplicate vendor names. Updating a name to match an existing supplier returns a `400` response. | +| **Default currency** | The currency must exist in the Zoho Books organization's currency list, or the update returns a `400` response. Sending a `null` value keeps the existing currency. Changing a supplier's currency also changes the currency of bills created for that supplier, because Zoho Books derives bill currency from the supplier. | +| **Addresses** | Billing and delivery addresses are replaced together. Sending only a billing address clears the delivery address. | +| **Archived suppliers** | Archived suppliers can still be updated — the field changes are applied and the supplier remains archived. A rejected update never changes the supplier's status. | + :::tip Recap You have learnt how to view, create, and update your customer's suppliers who provide them with goods and services. diff --git a/docs/payables/sync/update-bill.md b/docs/payables/sync/update-bill.md index 351f2a57d..ab121b01d 100644 --- a/docs/payables/sync/update-bill.md +++ b/docs/payables/sync/update-bill.md @@ -16,7 +16,7 @@ We distinguish between invoices where the company _owes_ money and those where t :::info Software coverage -This action is currently only supported for FreeAgent, QuickBooks Online, and Xero. +This action is currently only supported for FreeAgent, Oracle NetSuite, QuickBooks Online, Sage Intacct, Xero, and Zoho Books. ::: @@ -101,6 +101,50 @@ PUT /companies/{companyId}/connections/{dataConnectionId}/payables/bills/{billId + + +```json +{ + "description": "Consulting", + "unitAmount": 500, + "quantity": 2, + "accountRef": { "id": "" }, + "taxRateRef": { "id": "" }, + "trackingRefs": [ + { + "id": "department-", + "dataType": "trackingCategories" + }, + { + "id": "location-", + "dataType": "trackingCategories" + }, + { + "id": "", + "dataType": "customers", + "isBillable": true + } + ] +} +``` + + + + + +```json +{ + "description": "Consulting", + "unitAmount": 500, + "quantity": 2, + "accountRef": { "id": "" }, + "taxRateRef": { "id": "" }, + "taxAmount": 200 +} +``` + + + ```json @@ -116,19 +160,69 @@ PUT /companies/{companyId}/connections/{dataConnectionId}/payables/bills/{billId + + +```json +{ + "description": "Consulting", + "unitAmount": 500, + "quantity": 2, + "accountRef": { "id": "" }, + "taxRateRef": { "id": "" }, + "taxAmount": 200, + "trackingRefs": [ + { "id": "-", "dataType": "trackingCategories" }, + { "id": "", "dataType": "customers", "isBillable": true } + ] +} +``` + + + ### Software requirements We have summarized the key differences between the integrations that support updates to bills below: -| Feature | FreeAgent | QBO | Xero | -| ------------------------ | -------------------- | ------------------- | ------------------- | -| **Reference max length** | 255 characters | 21 characters | 255 characters | -| **`TaxRateRef`** | Must be `null` | Required | Required | -| **Tax handling** | Use `taxAmount` only | Use `taxRateRef.id` | Use `taxRateRef.id` | -| **`AccountRef` format** | Nominal code | Numeric string | GUID | -| **Max line items** | 40 | No limit | No limit | +| Feature | FreeAgent | NetSuite | QBO | Sage Intacct | Xero | Zoho Books | +| ------------------------ | -------------------- | --------------------------------- | ------------------- | --------------------------------- | ------------------- | ------------------------------------ | +| **Reference max length** | 255 characters | 45 characters | 21 characters | 100 characters | 255 characters | 50 characters | +| **`TaxRateRef`** | Must be `null` | Required with `taxAmount` | Required | Required with `taxAmount` | Required | Required with a non-zero `taxAmount` | +| **Tax handling** | Use `taxAmount` only | Use `taxRateRef.id` + `taxAmount` | Use `taxRateRef.id` | Use `taxRateRef.id` + `taxAmount` | Use `taxRateRef.id` | Use `taxRateRef.id` + `taxAmount` | +| **`AccountRef` format** | Nominal code | Internal ID | Numeric string | Account record number | GUID | Numeric ID | +| **Max line items** | 40 | No limit | No limit | No limit | No limit | No limit | + +### Software-specific behavior + +Each accounting software has some limitations when updating bills. We've summarized them below. + +#### NetSuite + +| Limitation | Description | +| ------------- | ----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | +| **Currency** | It's not possible to change a bill's currency after creation. Sending a different `currency` returns a `400` response. | +| **Reference** | It's not possible to clear the reference. Omit the field to keep the existing value; sending `""` returns a `400` response. | +| **Tax lines** | NetSuite may add automatically generated tax lines to a bill, so retrieving the bill later can return more line items than were sent in the update. | +| **Tracking** | Per-line department, location, and customer references must be valid for the bill's subsidiary. A reference from another subsidiary returns a `400` response, even if it is active. | + +#### Sage Intacct + +| Limitation | Description | +| ----------------- | ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | +| **Reference** | Omitting `reference` clears the bill number on the platform. Companies that require bill numbers reject the update, so include the existing reference if you don't want to change it. | +| **Currency rate** | Omitting `currencyRate` applies Sage Intacct's daily exchange rate. Sending an explicit value fixes the rate for the bill. | +| **Paid bills** | Bills that have been paid or partially paid can no longer be updated and return a `400` response. | +| **Description** | Line item descriptions are limited to 1000 characters, rather than the usual 4000. | + +#### Zoho Books + +| Limitation | Description | +| ----------------- | ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | +| **Currency** | A bill's currency always follows its supplier. A `currency` value that differs from the supplier's currency is ignored, and the response returns the supplier's currency. To change a bill's currency, move it to a supplier with the desired currency. | +| **Currency rate** | Zoho Books forces the exchange rate to `1` on bills in the organization's base currency. When you move a bill to a foreign-currency supplier, the rate is **not** recalculated automatically — send `currencyRate` explicitly. | +| **Reference** | The reference must be unique per supplier; a duplicate returns a `400` response. Omitting `reference` keeps the existing value. | +| **Not found** | A `404` response is not limited to an unknown bill ID — Zoho Books also returns `404` when the request body contains an invalid supplier, account, or tax rate ID. | ### Validation errors @@ -165,6 +259,26 @@ You may encounter a validation error when sending a request to update a bill. In + + +| Issue | Error message | +| ------------------------------- | ----------------------------------------- | +| Invalid supplier ID | `Supplier Ref` was not found in NetSuite. | +| Invalid account ID | `Account Ref` was not found in NetSuite. | +| Invalid tax rate ID | `Tax Rate Ref` was not found in NetSuite. | +| Changed or unsupported currency | `Currency` is not supported for supplier. | + + + + + +| Issue | Error message | +| ------------------------- | ----------------------------------------------------------------------- | +| Bill fully or partly paid | This bill has been paid or partially paid and can no longer be updated. | +| Invalid supplier ID | The Supplier with Id `` was not found. | + + + | Issue | Error message | @@ -184,6 +298,17 @@ You may encounter a validation error when sending a request to update a bill. In + + +| Issue | Error message | +| -------------------------- | ------------------------------------------------- | +| Duplicate reference | Reference has already been used for this supplier | +| Invalid supplier ID | `SupplierRef Id` was not found in ZohoBooks. | +| Negative bill total | The total amount due cannot be negative. | +| Due date before issue date | `dueDate` must be after `issueDate`. | + + + --- From 3651d31480115acef173bb768e9544883ec1a002 Mon Sep 17 00:00:00 2001 From: Nathan Jackson Date: Fri, 7 Aug 2026 11:17:39 +0100 Subject: [PATCH 2/5] CONN-801: move bill software-specific behaviour to the internal cheat sheet The limitations section belongs in the Bill Pay Kit acceptance-testing cheat sheets rather than the public docs; the requirements table and error tabs carry the client-facing essentials. Co-Authored-By: Claude Fable 5 --- docs/payables/sync/update-bill.md | 31 ------------------------------- 1 file changed, 31 deletions(-) diff --git a/docs/payables/sync/update-bill.md b/docs/payables/sync/update-bill.md index ab121b01d..446e94854 100644 --- a/docs/payables/sync/update-bill.md +++ b/docs/payables/sync/update-bill.md @@ -193,37 +193,6 @@ We have summarized the key differences between the integrations that support upd | **`AccountRef` format** | Nominal code | Internal ID | Numeric string | Account record number | GUID | Numeric ID | | **Max line items** | 40 | No limit | No limit | No limit | No limit | No limit | -### Software-specific behavior - -Each accounting software has some limitations when updating bills. We've summarized them below. - -#### NetSuite - -| Limitation | Description | -| ------------- | ----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | -| **Currency** | It's not possible to change a bill's currency after creation. Sending a different `currency` returns a `400` response. | -| **Reference** | It's not possible to clear the reference. Omit the field to keep the existing value; sending `""` returns a `400` response. | -| **Tax lines** | NetSuite may add automatically generated tax lines to a bill, so retrieving the bill later can return more line items than were sent in the update. | -| **Tracking** | Per-line department, location, and customer references must be valid for the bill's subsidiary. A reference from another subsidiary returns a `400` response, even if it is active. | - -#### Sage Intacct - -| Limitation | Description | -| ----------------- | ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | -| **Reference** | Omitting `reference` clears the bill number on the platform. Companies that require bill numbers reject the update, so include the existing reference if you don't want to change it. | -| **Currency rate** | Omitting `currencyRate` applies Sage Intacct's daily exchange rate. Sending an explicit value fixes the rate for the bill. | -| **Paid bills** | Bills that have been paid or partially paid can no longer be updated and return a `400` response. | -| **Description** | Line item descriptions are limited to 1000 characters, rather than the usual 4000. | - -#### Zoho Books - -| Limitation | Description | -| ----------------- | ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | -| **Currency** | A bill's currency always follows its supplier. A `currency` value that differs from the supplier's currency is ignored, and the response returns the supplier's currency. To change a bill's currency, move it to a supplier with the desired currency. | -| **Currency rate** | Zoho Books forces the exchange rate to `1` on bills in the organization's base currency. When you move a bill to a foreign-currency supplier, the rate is **not** recalculated automatically — send `currencyRate` explicitly. | -| **Reference** | The reference must be unique per supplier; a duplicate returns a `400` response. Omitting `reference` keeps the existing value. | -| **Not found** | A `404` response is not limited to an unknown bill ID — Zoho Books also returns `404` when the request body contains an invalid supplier, account, or tax rate ID. | - ### Validation errors You may encounter a validation error when sending a request to update a bill. In the sections below, we`ve included general and software-specific errors to help resolve these. From c5aa1a50b2d07720f0ff76ce3b89c9ad6cdd00f8 Mon Sep 17 00:00:00 2001 From: Nathan Jackson Date: Fri, 7 Aug 2026 12:11:37 +0100 Subject: [PATCH 3/5] CONN-801: repair the malformed Xero limitations table Pre-existing on main: the separator row declared a third column and the archived-suppliers row carried a stray trailing cell. Co-Authored-By: Claude Fable 5 --- docs/payables/sync/suppliers.md | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/docs/payables/sync/suppliers.md b/docs/payables/sync/suppliers.md index 26459a59b..d32016e15 100644 --- a/docs/payables/sync/suppliers.md +++ b/docs/payables/sync/suppliers.md @@ -75,10 +75,10 @@ Each accounting software has some limitations when updating suppliers. We've sum #### Xero | Limitation | Description | -| ---------------------- | -------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | --- | +| ---------------------- | -------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | | **Supplier name** | It's not possible to clear the supplier name. Sending a `null` or `""` value for `supplierName`, or `null` value for both `supplierName` and `contactName` keeps the existing supplier name. | | **Duplicate names** | Supplier names must be unique. Updating a name to match an existing supplier returns a `400` response. | -| **Archived suppliers** | It's not possible to update archived suppliers via the Xero API. To unarchive, do it manually in Xero. | | +| **Archived suppliers** | It's not possible to update archived suppliers via the Xero API. To unarchive, do it manually in Xero. | #### QuickBooks Online From 5e3616dab4a9afe1836de65d3cccede98c962a8a Mon Sep 17 00:00:00 2001 From: Nathan Jackson Date: Fri, 7 Aug 2026 12:31:17 +0100 Subject: [PATCH 4/5] CONN-801: present supplier software-specific behaviour as platform tabs Converts the six per-platform headings into the same Tabs/TabItem layout the update-bill page uses for its software-specific errors, sharing groupId="software" so the platform selection carries across pages. Co-Authored-By: Claude Fable 5 --- docs/payables/sync/suppliers.md | 54 +++++++++++++++++++++------------ 1 file changed, 35 insertions(+), 19 deletions(-) diff --git a/docs/payables/sync/suppliers.md b/docs/payables/sync/suppliers.md index d32016e15..b47af6c9c 100644 --- a/docs/payables/sync/suppliers.md +++ b/docs/payables/sync/suppliers.md @@ -72,23 +72,9 @@ This action is currently only supported for FreeAgent, Oracle NetSuite, QuickBoo Each accounting software has some limitations when updating suppliers. We've summarized them below. -#### Xero + -| Limitation | Description | -| ---------------------- | -------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | -| **Supplier name** | It's not possible to clear the supplier name. Sending a `null` or `""` value for `supplierName`, or `null` value for both `supplierName` and `contactName` keeps the existing supplier name. | -| **Duplicate names** | Supplier names must be unique. Updating a name to match an existing supplier returns a `400` response. | -| **Archived suppliers** | It's not possible to update archived suppliers via the Xero API. To unarchive, do it manually in Xero. | - -#### QuickBooks Online - -| Limitation | Description | -| ---------------------- | ----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | -| **Supplier name** | If `supplierName` is `null` in the request, QBO uses the value in `contactName` instead. If both fields are `null`, QBO returns a `400` response. | -| **Default currency** | It's not possible to update the supplier's currency. Sending a `defaultCurrency` in the request that differs from the current value results in a `400` response. Send a `null` value to leave it unchanged. | -| **Archived suppliers** | All changes to archived suppliers are ignored. Include `"status": "Active"` in the update request to reactivate an archived supplier and apply the changes. | - -#### FreeAgent + | Limitation | Description | | -------------------- | ---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | @@ -96,7 +82,9 @@ Each accounting software has some limitations when updating suppliers. We've sum | **Country** | It's not possible to clear the supplier's country. Sending a `null` value or excluding the field from the request sets the value to the company's default country. | | **Default currency** | FreeAgent doesn't support currency at supplier level. Any value sent in the request is ignored, and the response returns the company's base currency. | -#### NetSuite + + + | Limitation | Description | | -------------------- | ----------------------------------------------------------------------------------------------------------------------------------------------------------------- | @@ -107,7 +95,19 @@ Each accounting software has some limitations when updating suppliers. We've sum | **Default currency** | The currency must be enabled in the NetSuite organization, or the update returns a `400` response. Sending a `null` value leaves the existing currency unchanged. | | **Country** | Address `country` must be a 2-character ISO code. | -#### Sage Intacct + + + + +| Limitation | Description | +| ---------------------- | ----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | +| **Supplier name** | If `supplierName` is `null` in the request, QBO uses the value in `contactName` instead. If both fields are `null`, QBO returns a `400` response. | +| **Default currency** | It's not possible to update the supplier's currency. Sending a `defaultCurrency` in the request that differs from the current value results in a `400` response. Send a `null` value to leave it unchanged. | +| **Archived suppliers** | All changes to archived suppliers are ignored. Include `"status": "Active"` in the update request to reactivate an archived supplier and apply the changes. | + + + + | Limitation | Description | | -------------------- | -------------------------------------------------------------------------------------------------------------------- | @@ -116,7 +116,19 @@ Each accounting software has some limitations when updating suppliers. We've sum | **Addresses** | Sage Intacct supports a single address per supplier, and the response returns the first address only. | | **Contact name** | `contactName` is split on the last space into a first and last name, each limited to 40 characters. | -#### Zoho Books + + + + +| Limitation | Description | +| ---------------------- | -------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | +| **Supplier name** | It's not possible to clear the supplier name. Sending a `null` or `""` value for `supplierName`, or `null` value for both `supplierName` and `contactName` keeps the existing supplier name. | +| **Duplicate names** | Supplier names must be unique. Updating a name to match an existing supplier returns a `400` response. | +| **Archived suppliers** | It's not possible to update archived suppliers via the Xero API. To unarchive, do it manually in Xero. | + + + + | Limitation | Description | | ---------------------- | ---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | @@ -126,6 +138,10 @@ Each accounting software has some limitations when updating suppliers. We've sum | **Addresses** | Billing and delivery addresses are replaced together. Sending only a billing address clears the delivery address. | | **Archived suppliers** | Archived suppliers can still be updated — the field changes are applied and the supplier remains archived. A rejected update never changes the supplier's status. | + + + + :::tip Recap You have learnt how to view, create, and update your customer's suppliers who provide them with goods and services. From 69c2fd95b8b17518f52dcd177378db85fe334384 Mon Sep 17 00:00:00 2001 From: Nathan Jackson Date: Fri, 7 Aug 2026 14:14:32 +0100 Subject: [PATCH 5/5] CONN-801: state that Codat rejects a nameless FreeAgent supplier update Review feedback (Huw): the 400 comes from Codat-side validation (FreeAgentUpdateSupplierValidator - "Supplier Name or Contact Name must be provided"), not from FreeAgent; the request never reaches the platform. Reworded from the consumer perspective. Co-Authored-By: Claude Fable 5 --- docs/payables/sync/suppliers.md | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/docs/payables/sync/suppliers.md b/docs/payables/sync/suppliers.md index b47af6c9c..3106076a9 100644 --- a/docs/payables/sync/suppliers.md +++ b/docs/payables/sync/suppliers.md @@ -76,11 +76,11 @@ Each accounting software has some limitations when updating suppliers. We've sum -| Limitation | Description | -| -------------------- | ---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | -| **Supplier name** | If `supplierName` is `null` in the request, FreeAgent uses the value in `contactName` instead (the value must contain a space). If both fields are `null`, FreeAgent returns a `400` response. | -| **Country** | It's not possible to clear the supplier's country. Sending a `null` value or excluding the field from the request sets the value to the company's default country. | -| **Default currency** | FreeAgent doesn't support currency at supplier level. Any value sent in the request is ignored, and the response returns the company's base currency. | +| Limitation | Description | +| -------------------- | ---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | +| **Supplier name** | If `supplierName` is `null` in the request, FreeAgent uses the value in `contactName` instead (the value must contain a space). Codat rejects a request where both fields are `null` with a `400` response, because FreeAgent requires a name. | +| **Country** | It's not possible to clear the supplier's country. Sending a `null` value or excluding the field from the request sets the value to the company's default country. | +| **Default currency** | FreeAgent doesn't support currency at supplier level. Any value sent in the request is ignored, and the response returns the company's base currency. |