Update a customer
Operation ID: updateCustomer
Group: Accounting › Customers
Open in the interactive reference
PATCH /accounting/customers/{id}
Retry-safe: A write that accepts Idempotency-Key: repeating a request with the same key replays the stored answer instead of executing twice.
Updates a customer with the fields you send. A field you leave out keeps its current value. To clear a field that accepts null, send null.
Use the customer's id, not its customerNumber.
taxRegistrations and addresses each replace the whole list, so include every item you want to keep. To change addresses one at a time, use createAddresses, updateAddresses, and deleteAddresses. External identifiers change through createExternalIdentifiers, updateExternalIdentifiers, and deleteExternalIdentifiers.
To move the customer to another legal entity, send entityId. Documents created afterward use the new legal entity. Existing sales orders, invoices, and payments keep the legal entity they were created under. The customer keeps its payment term unless you also send paymentTermCode, and the request fails with PAYMENT_TERM_NOT_AVAILABLE_FOR_ENTITY when the new legal entity doesn't have that payment term. defaultCurrency doesn't change, so send it too if the new legal entity uses another currency.
If you change name, customerType, or entityId, another customer with the same name, legal entity, and customer type makes the request fail with DUPLICATE_CUSTOMER.
The response is empty. Read the updated record with GET accounting/customers/:id.
Parameters
| Name | In | Type | Required | Description |
|---|---|---|---|---|
Api-Version |
header | string · v1 | yes | The API version this request targets, named by its public identifier. Required on every request; omitting it, or naming a version this company does not have, is answered with 400. This document describes version v1. |
Idempotency-Key |
header | string | no | An opaque caller-chosen string (1-255 characters) that makes this request safe to retry. Repeating the same key with an identical request body replays the original response instead of re-executing - but only once that original request succeeded; a failed attempt re-executes on retry. Repeating the key with a different body is answered with 422. A key still in flight is answered with 409 - as is a key whose original request was interrupted before it finished, for a few minutes afterwards, until that attempt is presumed dead. A completed response stays replayable for 24 hours. The key is scoped to the caller, not to the action: reusing it for a different action is answered with 409 or 422 rather than treated independently. On read actions this header is ignored. On write actions that cannot offer the guarantee it is answered with 400 IDEMPOTENCY_NOT_SUPPORTED rather than silently ignored. |
id |
path | string | yes | The unique identifier of the customer you want to update. |
Request body
Required, application/json: updateCustomerInput.
| Field | Type | Required | Description |
|---|---|---|---|
entityId |
string | no | The id of the legal entity to move the customer to. Documents created afterward use this legal entity, and existing ones keep theirs. |
name |
string | no | The name of the customer, as it appears on invoices. |
customerType |
string | no | The customer type. Accepted values: 'default', 'partner'. Cannot be changed once the customer appears on a sales order. That change fails with CUSTOMER_TYPE_CHANGE_NOT_ALLOWED. 'endCustomer' is not supported and fails with END_CUSTOMER_NOT_SUPPORTED. |
partnerType |
string | null | no | The partner type, for a customer whose customerType is 'partner'. Accepted values: 'reseller', 'thirdPartyPayer'. |
businessType |
string | no | The business type of the customer. Accepted values: 'company', 'individual'. |
invoiceEmail |
string | null | no | The email address invoices are sent to. Example: "ap@example-robotics.com". |
mainEmail |
string | null | no | The email address of the customer's main contact. |
taxExempt |
boolean | no | Whether the customer is exempt from tax. Setting it to false also clears exemptionNumber and taxExemptCode. |
defaultCurrency |
string | no | The default currency for the customer's transactions, as a 3-letter ISO 4217 code. |
segment |
string | null | no | The market segment of the customer. Accepted values: 'SMB', 'MidMarket', 'Enterprise'. Ignored when businessType is 'individual', in this request or already set. Example: "MidMarket". |
exemptionNumber |
string | null | no | The tax-exemption certificate number. Accepted only when taxExempt is true, in this request or already set. Otherwise the request fails with EXEMPTION_NUMBER_REQUIRES_TAX_EXEMPT. |
paymentTermCode |
string | no | The code of a payment term on the customer's legal entity's list. When the request also changes entityId, the code must be on the new legal entity's list. A code that is not on the list fails with UNKNOWN_REFERENCE. See code on GET accounting/payment-terms. |
parentId |
string | no | The id of the parent customer. An unknown id fails with UNKNOWN_REFERENCE. |
partnerId |
string | no | The id of the partner this customer buys through. An unknown id fails with UNKNOWN_REFERENCE. |
salesChannel |
string | null | no | The sales channel for this customer. Accepted values: 'salesAssisted' (sold through a salesperson), 'selfServe'. |
additionalContactEmail |
string | null | no | Another email address for the customer, besides invoiceEmail and mainEmail. |
mainContactName |
string | null | no | The name of the customer's main contact. |
preferredLanguage |
string | null | no | The customer's preferred language. Accepted values: 'english'. |
crmCustomerId |
string | null | no | The customer's identifier in an external CRM system. |
businessIdentificationNumber |
string | null | no | The customer's business registration number. |
invoiceConsolidation |
string | null | no | How the customer's invoices are consolidated. Accepted values: 'customer', 'purchaseOrderNumber', 'salesArrangement'. |
invoiceDeliveryMode |
string | null | no | How invoices are delivered to the customer. Accepted values: 'manual', 'automated'. |
isExemptFromCreditCardFee |
boolean | no | Whether the customer is exempt from credit-card fees. |
billableTravelExpenseInvoiceDetail |
string | no | How billable travel and expense items appear on invoices. Accepted values: 'detailed', 'consolidated'. |
status |
string | no | The status of the customer. Accepted values: 'active', 'inactive'. |
taxExemptCode |
string | null | no | The tax-exemption reason code. Cleared when taxExempt is false. |
taxRegistrations |
array<object> | no | The customer's tax registrations. This array replaces the customer's whole set of registrations. An entry matching an existing registration on country and type updates it. Any other entry is added. A registration not in the array is deleted. Send an empty array to remove them all. |
taxRegistrations[].country |
string | yes | The country the registration applies in, as an ISO 3166-1 code. |
taxRegistrations[].taxNumber |
string | yes | The tax identification number issued by the tax authority. |
taxRegistrations[].type |
string | yes | The kind of tax registration. Accepted values: 'tax', 'salesTax', 'VAT', 'GST', 'EIN', 'TIN'. |
taxRegistrations[].effectiveDate |
date | no | The date the registration takes effect. Use format YYYY-MM-DD. |
taxRegistrations[].isActive |
boolean | no | Whether the registration is active. Only one active registration is allowed per country and tax type. Defaults to true. |
payment |
object | no | The customer's link to a payment provider. externalPaymentMethodId requires externalCustomerId, in this request or already set. |
payment.provider |
string | no | The name of a payment provider connected to your tenant. An unknown name fails with UNKNOWN_PAYMENT_PROVIDER, which lists the connected providers. Required when any other payment field is sent. Example: 'Stripe'. |
payment.externalCustomerId |
string | no | The customer's identifier in the payment provider's system. |
payment.externalPaymentMethodId |
string | no | The customer's default payment method in the payment provider's system. |
addresses |
array<object> | no | The customer's addresses. This array replaces the customer's whole address set, both types, and every address gets a new addressId. Send an empty array to remove every address. |
addresses[].type |
string | yes | The address type. Accepted values: 'billTo', 'soldTo'. |
addresses[].attention |
string | no | The person or department that mail to this address is for. |
addresses[].isDefault |
boolean | no | Whether this entry is the default address of its type. |
addresses[].line1 |
string | yes | The first address line: street number and name, or PO box. |
addresses[].line2 |
string | no | The second address line: apartment, suite, unit, building, or floor. |
addresses[].city |
string | yes | The city or locality. |
addresses[].stateProvince |
string | no | The state, province, or region. |
addresses[].country |
string | yes | The country, as a name or ISO 3166-1 code. |
addresses[].zipCode |
string | yes | The postal or ZIP code. |
createAddresses |
array<object> | no | Addresses to add to the customer, alongside its existing ones. Mark at most one entry per type as the default with isDefault. Cannot be combined with addresses. That combination fails with INVALID_FIELD_VALUE. |
createAddresses[].type |
string | yes | The address type. Accepted values: 'billTo', 'soldTo'. |
createAddresses[].attention |
string | no | The person or department that mail to this address is for. |
createAddresses[].isDefault |
boolean | no | Whether this entry is the default address of its type. |
createAddresses[].line1 |
string | yes | The first address line: street number and name, or PO box. |
createAddresses[].line2 |
string | no | The second address line: apartment, suite, unit, building, or floor. |
createAddresses[].city |
string | yes | The city or locality. |
createAddresses[].stateProvince |
string | no | The state, province, or region. |
createAddresses[].country |
string | yes | The country, as a name or ISO 3166-1 code. |
createAddresses[].zipCode |
string | yes | The postal or ZIP code. |
updateAddresses |
array<object> | no | Changes to existing addresses of the customer, each named by its addressId. A field you omit keeps its current value. Each address keeps its addressId. An addressId the customer does not have fails with ADDRESS_NOT_FOUND. Cannot be combined with addresses. That combination fails with INVALID_FIELD_VALUE. |
updateAddresses[].addressId |
string | yes | The address to update. See addressId on GET accounting/customers/:id. |
updateAddresses[].type |
string | no | The address type. Accepted values: 'billTo', 'soldTo'. A different value moves the address to that type. |
updateAddresses[].attention |
string | no | The person or department that mail to this address is for. |
updateAddresses[].isDefault |
boolean | no | Whether this entry is the default address of its type. |
updateAddresses[].line1 |
string | no | The first address line: street number and name, or PO box. |
updateAddresses[].line2 |
string | no | The second address line: apartment, suite, unit, building, or floor. |
updateAddresses[].city |
string | no | The city or locality. |
updateAddresses[].stateProvince |
string | no | The state, province, or region. |
updateAddresses[].country |
string | no | The country, as a name or ISO 3166-1 code. |
updateAddresses[].zipCode |
string | no | The postal or ZIP code. |
deleteAddresses |
array<string> | no | The addressIds of the addresses to remove from the customer. An addressId the customer does not have fails with ADDRESS_NOT_FOUND. When you remove the default address of a type, another address of that type becomes the default. Cannot be combined with addresses. That combination fails with INVALID_FIELD_VALUE. See addressId on GET accounting/customers/:id. |
createExternalIdentifiers |
array<object> | no | External identifiers to add. A fieldName the customer already has fails with DUPLICATE_EXTERNAL_IDENTIFIER. |
createExternalIdentifiers[].fieldName |
string | yes | The configured field name of the identifier. Example: 'netsuiteCustomerId'. |
createExternalIdentifiers[].value |
string | yes | The identifier in the other system. |
createExternalIdentifiers[].externalUrl |
string | no | A link to the record in the other system. |
updateExternalIdentifiers |
array<object> | no | External identifiers to replace, matched by fieldName. A fieldName the customer does not have fails with EXTERNAL_IDENTIFIER_NOT_FOUND. |
updateExternalIdentifiers[].fieldName |
string | yes | The configured field name of the identifier. Example: 'netsuiteCustomerId'. |
updateExternalIdentifiers[].value |
string | yes | The identifier in the other system. |
updateExternalIdentifiers[].externalUrl |
string | no | A link to the record in the other system. |
deleteExternalIdentifiers |
array<string> | no | The fieldNames of external identifiers to remove. A fieldName the customer does not have fails with EXTERNAL_IDENTIFIER_NOT_FOUND. |
{
"entityId": "3fa85f64-5717-4562-b3fc-2c963f66afa6",
"name": "<name>",
"customerType": "<customerType>",
"partnerType": "<partnerType>",
"businessType": "<businessType>",
"invoiceEmail": "ap@example-robotics.com",
"mainEmail": "<mainEmail>",
"taxExempt": true,
"defaultCurrency": "<defaultCurrency>",
"segment": "MidMarket",
"exemptionNumber": "<exemptionNumber>",
"paymentTermCode": "<paymentTermCode>",
"parentId": "3fa85f64-5717-4562-b3fc-2c963f66afa6",
"partnerId": "3fa85f64-5717-4562-b3fc-2c963f66afa6",
"salesChannel": "<salesChannel>",
"additionalContactEmail": "<additionalContactEmail>",
"mainContactName": "<mainContactName>",
"preferredLanguage": "<preferredLanguage>",
"crmCustomerId": "3fa85f64-5717-4562-b3fc-2c963f66afa6",
"businessIdentificationNumber": "<businessIdentificationNumber>",
"invoiceConsolidation": "<invoiceConsolidation>",
"invoiceDeliveryMode": "<invoiceDeliveryMode>",
"isExemptFromCreditCardFee": true,
"billableTravelExpenseInvoiceDetail": "<billableTravelExpenseInvoiceDetail>",
"status": "<status>",
"taxExemptCode": "<taxExemptCode>",
"taxRegistrations": [
{
"country": "<country>",
"taxNumber": "<taxNumber>",
"type": "<type>",
"effectiveDate": "2026-01-15",
"isActive": true
}
],
"payment": {
"provider": "<provider>",
"externalCustomerId": "3fa85f64-5717-4562-b3fc-2c963f66afa6",
"externalPaymentMethodId": "3fa85f64-5717-4562-b3fc-2c963f66afa6"
},
"addresses": [
{
"type": "<type>",
"attention": "<attention>",
"isDefault": true,
"line1": "<line1>",
"line2": "<line2>",
"city": "<city>",
"stateProvince": "<stateProvince>",
"country": "<country>",
"zipCode": "<zipCode>"
}
],
"createAddresses": [
{
"type": "<type>",
"attention": "<attention>",
"isDefault": true,
"line1": "<line1>",
"line2": "<line2>",
"city": "<city>",
"stateProvince": "<stateProvince>",
"country": "<country>",
"zipCode": "<zipCode>"
}
],
"updateAddresses": [
{
"addressId": "3fa85f64-5717-4562-b3fc-2c963f66afa6",
"type": "<type>",
"attention": "<attention>",
"isDefault": true,
"line1": "<line1>",
"line2": "<line2>",
"city": "<city>",
"stateProvince": "<stateProvince>",
"country": "<country>",
"zipCode": "<zipCode>"
}
],
"deleteAddresses": [
"<deleteAddresses>"
],
"createExternalIdentifiers": [
{
"fieldName": "<fieldName>",
"value": "<value>",
"externalUrl": "<externalUrl>"
}
],
"updateExternalIdentifiers": [
{
"fieldName": "<fieldName>",
"value": "<value>",
"externalUrl": "<externalUrl>"
}
],
"deleteExternalIdentifiers": [
"<deleteExternalIdentifiers>"
]
}
Response
200 Success
{
"data": {},
"diagnostics": [
{
"code": "<code>",
"message": "<message>",
"severity": "error",
"path": [
"<path>"
],
"details": "<details>"
}
]
}
Response headers
Idempotency-Replayed— Present andtrueonly when this response replays a previously stored one for the same Idempotency-Key, rather than reflecting a live execution. Absent on a live response - never sent asfalse.
Errors
| Code | Status |
|---|---|
NOT_FOUND |
400 |
INVALID_ENTITY |
400 |
PAYMENT_TERM_NOT_AVAILABLE_FOR_ENTITY |
400 |
INVALID_FIELD_VALUE |
400 |
MULTIPLE_DEFAULT_ADDRESSES |
400 |
DUPLICATE_CUSTOMER |
400 |
END_CUSTOMER_NOT_SUPPORTED |
400 |
UNKNOWN_EXTERNAL_IDENTIFIER |
400 |
DUPLICATE_EXTERNAL_IDENTIFIER |
400 |
EXTERNAL_IDENTIFIER_NOT_FOUND |
400 |
ADDRESS_NOT_FOUND |
400 |
CUSTOMER_TYPE_CHANGE_NOT_ALLOWED |
400 |
UNKNOWN_REFERENCE |
400 |
UNKNOWN_PAYMENT_PROVIDER |
400 |
PAYMENT_METHOD_REQUIRES_CUSTOMER_ID |
400 |
EXEMPTION_NUMBER_REQUIRES_TAX_EXEMPT |
400 |
IDEMPOTENCY_KEY_CONFLICT |
409 |
IDEMPOTENCY_PAYLOAD_MISMATCH |
422 |
Statuses
400— Invalid request or business failure. Codes: NOT_FOUND, INVALID_ENTITY, PAYMENT_TERM_NOT_AVAILABLE_FOR_ENTITY, INVALID_FIELD_VALUE, MULTIPLE_DEFAULT_ADDRESSES, DUPLICATE_CUSTOMER, END_CUSTOMER_NOT_SUPPORTED, UNKNOWN_EXTERNAL_IDENTIFIER, DUPLICATE_EXTERNAL_IDENTIFIER, EXTERNAL_IDENTIFIER_NOT_FOUND, ADDRESS_NOT_FOUND, CUSTOMER_TYPE_CHANGE_NOT_ALLOWED, UNKNOWN_REFERENCE, UNKNOWN_PAYMENT_PROVIDER, PAYMENT_METHOD_REQUIRES_CUSTOMER_ID, EXEMPTION_NUMBER_REQUIRES_TAX_EXEMPT401— The request carries no valid access token.403— Not authorized404— Not found409— The Idempotency-Key is still being processed by another request.422— The Idempotency-Key was already used with a different request payload.429— Too many requests from this client address. The response has no body and noRetry-Afterheader.500— Internal server error