Calling createContact() with logged in user returns 403 error

I created a custom sign-up form for my site that allows for me to capture additional information from my members. Upon successful registration, the additional details are saved to both the Contact record in the CRM as well as a Data Collection. This works perfectly.

I have also created a Members Page that retrieves the members additional info from the collection and displays it for the member to update/change. When the member submits the form, I update the collection, and then, using the onAfterSave event, I call the createContact() method of the WixCRM API to update the members contact record. Which, according to the documentation, if the email address or phone number already exists, the contact record should be updated instead of a new one being created.

However, when I submit the form, the createContact() method returns “Uncaught (in promise) permission_denied, details: {“Error”:“A member with these communication details (Email / Phone) already exists”} (403)”

This error is a bit confusing since the expected result of an existing member should be an updated contact record, not an error. Here is the code I am using…

$w("#dataset1").onAfterSave((itemBefore, itemAfter) => {
        changeLabel();

        let contactInfo = {
        "firstName": itemAfter.firstName,
         "lastName": itemAfter.lastName,
         "loginEmail": loginEmail,
         "emails": [itemAfter.email],
         "phones": [itemAfter.phone],
         "birthday": itemAfter.birthday,
         "gender": itemAfter.gender,
         "shirtSize": itemAfter.shirtSize,
         "passport": itemAfter.passport,
         "emergencyFirstName": itemAfter.emergencyFirst,
         "emergencyLastName": itemAfter.emergencyLast,
         "emergencyPhone": itemAfter.emergencyPhone,
         "emergencyEmail": itemAfter.emergencyEmail,
         "foodIssues": itemAfter.foodIssues,
         "medicalIssues": itemAfter.medicalIssues,
         "medications": itemAfter.medications
        };

        wixCrm.createContact(contactInfo);
    });

Any help on this would be appreciated!

Bump on this… Anyone? Bueller… Bueller…

Hi

@jamescook: Did you manage to find a solution to this problem?

I have the same issue too. Could anyone help understand why this is happening? Following is the code I am using.

import wixUsers from ‘wix-users’;
import wixLocation from ‘wix-location’;
import wixCRM from ‘wix-crm’;

$w.onReady( function () {
let user = wixUsers.currentUser;
console.log(user);
$w(‘#shippingnext’).onClick( function (){
user.getEmail().then( (email) => {
let emailId = email;
let addressline1 = $w(‘#addressline1’).value;
let addressline2 = $w(‘#addressline2’).value;
let streetname = $w(‘#streetname’).value;
let city = $w(‘#city’).value;
let pincode =$w(‘#pincode’).value;

let contactInfo = {
“emails” : [“test0@gmail.com”],
“addressline1” : addressline1,
“addressline2” : addressline2,
“streetname” : streetname,
“city” : city,
“pincode” : pincode
};
console.log(contactInfo);
wixCRM.createContact(contactInfo)
.then( (contactId) => {
console.log (contactId);
});

}); 

    }); 

});

Hi James,

Any joy on this one? This is my problem at the moment too. But I think I have thought of a possible workaround for now:

Since you are creating contacts in a data collection, do a query to retrieve the information - and if found, do not proceed on creating the new contact and proceed with your logic, - otherwise create the new contact… This should temporarily prevent any showstoppers and we can maintain synchronization between two data sources (table and wixCRM) using the contact information while waiting for a fix. When wix releases their fix we should be able to do a mass update to synchronize both data sources.

Moreover, I think the main issue is maintaining an overall synchronization of all fields both the dataset and wixCRM contacts. For now we can have our data collection as the “source of truth”.

Any thoughts?

This is a great work around, but the key point for me is that I am using the labels of the CRM to track what content my contacts have subscribed to. I am trying to move away from MailChimp as my mail marketing platform and keep everything in WIX to reduce all the 3rd Party API calls I am making. At present, many of my member pages are connecting to AirTable, SendGrid, and MailChimp to both generate content on the page, and send out notifications/marketing.

For now, I am going to keep my MailChimp integrations, get rid of SendGrid, and use WIX’s triggered emails instead. Hoping that I can implement the WIX CRM down the road. Unless, a solution is provided within the next week.

Not yet…

Hi Guys:

I think you will find that the issue is with the crm contact ‘_id’.

I have had several go arounds with the CRM team on this issue.

The CRM forces you to have one and only one CRM record per loginEmail (which is the correct behaviour IMHO). However the wixUsers API is a different matter :-). The CRM logic in general is a little confusing in this regard but basically emails used to identify contacts should be considered unique keys and this should help with managing duplication of CRM records. I am sure several of you will have thoughts :slight_smile:

CRM uses the data collection _id to verify if a CRM record is new or pre-existing. So if you use createCRM to update a record you had better know its ‘_id’ and use it. The problem is that the wix-crm api doesn’t have a query method so if you don’t keep track of the data you are writing to the crm api (specifically the id returned in the createContact Promise) then you have a high probability of creating a duplicate record and getting the 403.

I definitely get the need to protect against duplication, but the documentation says that the createContact method will either create a new contact or update one if it already exists (see image below). I tried adding the “_id” you suggested to the contactInfo object with the contacts ID (I do keep track of it for this reason), but it still throws the 403 error.

Setting the “_id” with the contact ID makes sense, but it is not specified in the createContact documentation.

I am thinking the functionality of this method has changed and they have not updated the documentation for it.

@jcook Unfortunately, me too I tried to add the “_id” parameter and still triggers the 403 error. @stcroppe I need help badly on this one as well please.

Here is my code:

// For full API documentation, including code examples, visit http://wix.to/94BuAAs
import wixData from ‘wix-data’;
import wixWindow from ‘wix-window’;
import wixCRM from ‘wix-crm’;
import {fetch} from ‘wix-fetch’;
import wixUsers from ‘wix-users’;

$w.onReady(function () {
let user = wixUsers.currentUser;
//TODO: write your page related code here…
let itemData = wixWindow.lightbox.getContext();

$w("#submitForm").onClick( (event) => { 
	// check if there is passed data, if there's none, close this lightbox 
	let bValid = true, 
		guestName = $w("#name").value, 
		guestCompany = $w("#companyName").value, 
		guestEmail = $w("#email").value, 
		guestPhone = $w("#phone").value; 
	// hide initially 
	$w("#errorMessage").hide();	 
	// empty required fields? 
	if (guestCompany === '' || guestEmail === '') { 
		bValid = false; 
	} 
	// Any errors? 
	if (!bValid) { 
		// show error messages.. 
		$w("#errorMessage").show(); 
		return false; 
	} 
	// Any item Data? 
	if (itemData.data) { 
		if (itemData.data.itemId) { 
			wixData.get("JobList", itemData.data.itemId) 
			.then( (results) => { 
				// initialize 
				let jobPost = results; //see item below 
				console.log(guestEmail); 
				// check if contact exists 
				wixData.query("ContactList") 
				.eq("email", guestEmail) 
				.find() 
				.then( (contactList) => { 
					let contacts = contactList.items; 

					if (contacts.length > 0) { 
						let contact = contacts[0]; 
						
						wixCRM.createContact({ 
							"_id": contact.contact_id, 
							"name": guestName, 
							"emails": [guestEmail],								 
							"company": guestCompany, 
							"phones": [guestPhone], 
							"interest_area": jobPost.title, 
						}).then((contactId) => { 
							// create contactList 
							let newRow = { 
								title: guestEmail, 
								contact_id: contactId, 
								name: guestName, 
								phone: guestPhone, 
								company: guestCompany, 
								email: guestEmail 
							}; 
							// create a new SentQuoteList row. 
							wixData.save("ContactList", newRow) 
								.then( (results) => { 
									// newsletter_signup below is the title of the trigerred email 
									wixCRM.emailContact("quote_email", contactId, { 
											"variables": { 
											"title": jobPost.title, 
										} 
									}).then(() => { 
										// do something after the email was sent 
										let newSentRow = { 
											title: jobPost.title, 
											item_id: jobPost._id, 
											contact_id: contactId 
										}; 
										// create a new SentQuoteList row. 
										wixData.save("SentQuoteList", newSentRow) 
											.then( (results) => { 
												// do redirect, or close the lightbox or show a message 
												console.log('sent details saved, email sent. (new contact)'); 
											} ) 
											.catch( (err) => { 
												let errorMsg = err; 
											} );	 
									}).catch((err) => { 
										// handle the error if the email wasn't sent 
									});	 
								} ) 
								.catch( (err) => { 
									let errorMsg = err; 
								} );	 
						}).catch( (error) => { 
							let errorMsg = error.message; 
							let code = error.code; 
							console.log("error:"); 
							console.log(code); 
						}); 
					} 
				} ) 
				.catch( (error) => { 
					let errorMsg = error.message; 
					let code = error.code; 
					console.log("error:"); 
					console.log(code); 
				} ); 
			} ) 
			.catch( (err) => { 
				let errorMsg = err; 
			} ); 
		} 
	} 
}); 

});

Hi Paolo:

I think there may be a couple of things going on here BUT I also think that the CRM API may not be functioning correctly in update mode.

I have mocked up a page here (https://stcroppe.wixsite.com/steveonsoftware/example-code/wix-create-contact-update ) and tested the CRM API and I am able to perform an update request with a success result (i.e. I receive the contactId in the promise resolve) however the CRM Contact record is not updated despite a success result. I can send with or without the “_id” and get the same result. So sorry about the incorrect guidance here.

One thing to think about is what is the CRM and who owns the data in it. When you are logged in and accessing the crm api are you logged in as an admin or a member. If you are logged in as a member and not an admin then you probably should receive a 403 if you are trying to change a crm record. If you are an admin then you should know what you are doing right? The crm api docs do state that if an email or phone number already exists in the crm then you will likely have a duplicate error returned but its not clear under what conditions since emails and phones are both array fields. I have suggested to the Wix team that they use the loginEmail property for the email key to the record. Alternate email addresses may show up as duplicates if several folks use a community email address for contact (e.g. info@xyz.com) BUT the main/preferred/login email address should always by unique.

The other thing is that I presume that the custom fields “interest_area” and “company” are defined in the CRM as custom fields. If they aren’t then this could cause a problem also.

One thing to consider here is adding some console.log statements before the wix-data and wixCRM api calls and dump what you are sending as arguments. If you are sending null in any of the fields that may also cause an issue.

For example instead of doing this:

wixCRM.createContact({
    "_id": contact.contact_id,
    "name": guestName,
    "emails": [guestEmail],								
    "company": guestCompany,
    "phones": [guestPhone],
    "interest_area": jobPost.title,
})

Do this:

let contactRecord = {
     "_id": contact.contact_id,
     "name": guestName, 
     "emails": [guestEmail], 
     "company": guestCompany, 
     "phones": [guestPhone], 
     "interest_area": jobPost.title
      };
console.log("createContact("+JSON.stringify(contactRecord)+")");
wixCRM.createContact(contactRecord)...

Additionally if you check the error in your catch statements to see if it is an Error object and dump the stack trace. This will tell you which wix module flagged the error and may be useful to share here and with Wix.

.catch((error) => {
    if (error instanceof Error) {
       // We may have stack trace info with our error
       console.log(error.message);
       if (error.stack) {
           console.log("STACK TRACE\n"+error.stack);
       }
     } else {
         console.log(error);
     }
 });

Lastly, my suggestion at the moment would be to use CRM for dashboard related work and add visitors once there and then maintain all other web page/app specific data in a data collection not CRM.

Hi @stcroppe ,

Thank you for your informative response. My goal actually here is to provide a search functionality for the guests (the data is from our collection), and I have a CTA (call to action) in my repeaters I pass the ID of the clicked CTA into a lightbox, the lightbox has a form for the guest to fill up in (along with contact details, email/phone), now what happens when the form is submitted is that a triggered email listens to that - but I understand that triggered emails should be sent with a contact ID, what I am doing now is that I am creating a new contact with the fields from the form and pickup the id and send an email. But it results to a 403 error when the contact already exists (with the same email/phone from the submitted one).

However I tried to do a workaround, I stored all my current contacts into a collection (I also have an ID field, for the contact ID)

And when the form is submitted I query for my collection with those contact details, once retrieved, I use the contact ID in my collection and pass it to emailContact() function, but I am also receiving an error 403. Just trying to understand the purpose of emailContact? is it expecting somekind of promise or an ACTUAL contact object to proceed?

Thanks,
Paolo

This is the error:

error:
console.js:35 permission_denied, details: {“Error”:“A member with these communication details (Email / Phone) already exists”} (403)

Also, this doesn’t make any sense, it says in your documentation that if there is a matching existing contact it is updated with the information specified in the contactInfo parameter:

Hello James,
Do you still have this issue? Can you please share your sites URL?

Thanks,
Motiejus

Hi,

I technically am, but due to the lack of a solution, I have gone to plan B and am staying with MailChimp. I have scrapped the use of the CreateContact method since it was not working as expected.

My site is currently in the final stages of development, but can be viewed here:

https://12twomissions.wixsite.com/12two/

@jcook Great to hear you found a solution, however if you will use and will still have issue with crm, please let us know so we can fix it, as I was unable to replicate it.
Thanks!

Hi Navya, do you still have this issue on your site? Can you please share URL of the site, so we can have a look and fix it?
Thanks!

@paoloabarcelona might still need your help

Hi @motiejus-juodelis ,

I still need your help please. I’d like to test by myself if possible since the site I’m working on is already on production. But as I mentioned in my previous replies, the caught error in the try-catch block was this:

error:
console.js:35 permission_denied, details: {“Error”:“A member with these communication details (Email / Phone) already exists”} (403)

Hi Paolo,
Can you please share your sites URL, if possible? I am not able to replicate the issue, so need to understand in which cases this happens.

Thanks!

Paolo:
I have updated this page and added the code that is used behind the scenes to the page.

If you add a valid email and complete the first and last name fields and submit it should create a crm record and load an email button.
when ou click on the email button you will receive a triggered email.