0

Whenever I try to update a Xero contact that already exists in the system using a POST request I get the following error

"ValidationErrors":
[{
    "Message": "The contact name Test Contact is already assigned to another contact. 
    The contact name must be unique across all active contacts."

}]

However this is directly from their documentation. They say that you will get an error if you use PUT to push an update, and with POST it is supposed to work successfully. What am I doing wrong?

POST Contacts Use this method to create or update one or more contact records

When you are updating a contact you don’t need to specify every element. If you exclude an element then the existing value will be preserved

PUT Contacts Use this method to create one or more contact records. This method works very similar to POST Contacts but if an existing contact matches your ContactName or ContactNumber then you will receive an error.

My Code making request

    //req options
    let options =
    {
        method: 'POST',
        headers:
        {
            'Content-Type': 'application/json',
            'Authorization': 'Bearer ' + token,
            'xero-tenant-id': tenant_id,
            'Accept': 'application/json'
        },
        data: { "Contacts": contacts }
    }

    //send request
    let res = await axios(url, options)
search-learn
  • 1,037
  • 1
  • 9
  • 23
  • Can't you use ContactID for updating and exclude contactName? Can you paste here the request – rootkonda Aug 03 '20 at 19:47
  • @rootkonda i need to upsert the contact... meaning if it exists it will be updated, if it doesn't it will be created. That's what I expected the POST option to do. I don't have ContactID, that would require querying for it and then updating, which defeats the point of batching requests, since Xero limits amount of API calls. – search-learn Aug 03 '20 at 20:35
  • XERO is encouraging to use contactID instead of contactName. Here is the Note from their website: `Important Update The business rules around contacts in Xero may be changing in the future and 'Contact Name' may no longer be a unique field. We recommend all developers use ContactID to uniquely reference contacts in Xero and do not rely on ContactName as a way to reference contact data uniquely in Xero.` – rootkonda Aug 04 '20 at 04:29
  • I wonder if this is something to do with the API you are using, rather than Xero specifically. I do this same thing from VB using raw HTTP Post or Put, and I did that for exactly the opposite reason - in testing to see that a duplicate contact name would throw an error when using POST, I found that if I tried to create a new contact but the name was already on another, it would update that first contact rather than failing to create my new one. Also there's a thread on the Xero forum along very similar lines. I must test it again, in case they've changed something. – droopsnoot Aug 04 '20 at 08:33
  • @droopsnoot have you tried the following. You have 2 contacts A and B. But for contact B you also have a ContactNumber set to the value "123". Contact Name and Contact Number are both unique fields. If you try updating Contact A but in the payload set ContactNumber to 123, I wonder if you will get same error. Because that's basically what was happening to me. – search-learn Aug 05 '20 at 19:28
  • @search-learn, I'm not sure because all my contacts have a unique contactnumber - that's how I link them to my clients front end software. I _did_ find that if I have a contact with contactnumber A0001 and name "My Test Company", then try to create a new contact (but using HTTP Post, __not__ Put) with contactnumber B0001 and the same name, it would just change the contactnumber on the first one to be B0001. Changing to Put makes it work correctly, i.e. to reject the second contact because the contact name is a duplicate. – droopsnoot Aug 05 '20 at 19:33

1 Answers1

0

Here is a workaround which solves the problem by passing the SDK for any create functions (e.g. contacts, invoices).

If you are using Custom Connections, first step, use the SDK to initialise the client and get a tokenSet as normal, which provides the access_token; xero-tenant-id has to be an empty string for Custom Connections. If you are using the OAuth2 method, substitute accordingly.

Then, use Axios to PUT or POST your data, e.g.

const axios = require("axios")

const tokenSet = {} // use applicable SDK to get access_token

let contacts = [{
  ContactID: contact_dot_uuid,
  Name:name,
  EmailAddress:email
}]

let config = {
  url: "https://api.xero.com/api.xro/2.0/Contacts",
  method: 'PUT',
  headers: {
    'Authorization': 'Bearer ' + tokenSet.access_token,
    'xero-tenant-id': "",
    'Accept': 'application/json',
    'Content-Type': 'application/json',
  },
  params: { "summarizeErrors": true },
  data: { Contacts: contacts }
}

axios(config).then((response) => {
  // response.data out
}).catch((error)=>{
  // error out
})

For what it's worth, the SDK error was caused by a serialization task on the contacts/invoices data which was returning nulls every time.

Tyler2P
  • 2,324
  • 26
  • 22
  • 31