Bulk Activities - Add contacts - Need Help

SOLVED
Go to solution
SrinivasU3
Regular Participant

Bulk Activities - Add contacts - Need Help

Hello Support,

 

Following is the Java code that I have written for uploading contacts in bulk using the most recent version of Java SDK.

I get the following errors when I try to execute the code:

 

 

import com.constantcontact.ConstantContact;
import com.constantcontact.components.activities.contacts.request.ContactData;
import com.constantcontact.components.activities.contacts.request.CustomField;
import com.constantcontact.components.activities.contacts.request.AddContactsRequest;
import com.constantcontact.components.contacts.ContactList;
import com.constantcontact.exceptions.component.ConstantContactComponentException;
import com.constantcontact.exceptions.service.ConstantContactServiceException;

 

import java.util.ArrayList;
import java.util.List;

 

public class BulkMemberUpload
{
public BulkMemberUpload()
{

}

 

public static void UploadMembers(ArrayList alMemberId, ArrayList alFirstName,
ArrayList alLastName, ArrayList alEmailId,
String strAPIKey, String strAccessToken)
{
// Create Constant Contact object
ConstantContact objConstantContact = new ConstantContact(strAPIKey, strAccessToken);

// Create AddContactsRequest object
AddContactsRequest objAddContactsRequest = new AddContactsRequest();

// Create new list of contact data
List<ContactData> lsContactData = new ArrayList<ContactData>();

// Create list of columns
List<String> lsColumnName = new ArrayList<String>();

// Create object for contact list
List<String> contactlist = new ArrayList<String>();

// ContactList object
ContactList objContactList = new ContactList();

for(int i=0; i < alMemberId.size(); i++)
{
// Create new contact data object
ContactData objContactData = new ContactData();

// Set Email Id
List<String> lsEmailAddresses = new ArrayList<String>();
lsEmailAddresses.add(alEmailId.get(i).toString());
objContactData.setEmailAddresses(lsEmailAddresses);

// Set First Name
objContactData.setFirstName(alFirstName.get(i).toString());

// Set Last Name
objContactData.setLastName(alLastName.get(i).toString());

// Set Member Id
CustomField objCustomField = new CustomField();
List<CustomField> lsCustomField = new ArrayList<CustomField>();
objCustomField.setName("MemberId");
objCustomField.setValue(alMemberId.get(i).toString());
lsCustomField.add(objCustomField);
objContactData.setCustomFields(lsCustomField);

 

// Add contact to contact list
lsContactData.add(objContactData);

} // End of for


// Add column names for list
lsColumnName.add("EMAIL");
lsColumnName.add("FIRST NAME");
lsColumnName.add("LAST NAME");
lsColumnName.add("CUSTOM FIELD 1");

// Set List id
contactlist.add("4");

 

// Set list name for upload
objAddContactsRequest.setLists(contactlist);

// Set column names
objAddContactsRequest.setColumnNames(lsColumnName);

// Import data into AddContactsRequest
objAddContactsRequest.setImportData(lsContactData);


// Upload members
try {
System.out.println(objAddContactsRequest.toJSON());
objConstantContact.addBulkContacts(objAddContactsRequest);
} catch (ConstantContactServiceException e) {
// TODO Auto-generated catch block
//e.printStackTrace();
System.out.println("Caught in Exception while uploading the list " + e.getErrorInfo());
} catch (ConstantContactComponentException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}

}

 

public static void main (String[] args)
{
String strAPIKey = "Your_API_Key";
String strAccessToken = "Your_Access_Token";

ArrayList alMemberId = new ArrayList();
ArrayList alFirstName = new ArrayList();
ArrayList alLastName = new ArrayList();
ArrayList alEmailId = new ArrayList();

alMemberId.add("0001");
alFirstName.add("ABCD");
alLastName.add("EFGH");
alEmailId.add("abcdefgh@gmail.com");

alMemberId.add("0002");
alFirstName.add("PQRS");
alLastName.add("TUVW");
alEmailId.add("pwer238@yahoo.com");

 

alMemberId.add("0003");
alFirstName.add("PERIWE");
alLastName.add("SDFKSD");
alEmailId.add("wierj@hotmail.com");

UploadMembers(alMemberId, alFirstName, alLastName, alEmailId, strAPIKey, strAccessToken);

}

 

}

 

 

Caught in Exception while uploading the list [
CUrlRequestError [errorKey=json.field.invalid, errorMessage=#/import_data/0/custom_fields: Property was found but is not permitted at this location.],
CUrlRequestError [errorKey=json.field.invalid, errorMessage=#/import_data/1/custom_fields: Property was found but is not permitted at this location.],
CUrlRequestError [errorKey=json.field.invalid, errorMessage=#/import_data/2/custom_fields: Property was found but is not permitted at this location.],
CUrlRequestError [errorKey=url, errorMessage=https://api.constantcontact.com/v2/activities/addcontacts]]

 

Can you please look into my code and let me know what is the cause for the errors mentioned above?  Please replace the strings "Your_API_Key" and "Your_Access_Token" in the main() method with the actual values.  I have removed the actual values from my program for security reasons.

 

Thanks,

Srinivas

 

1 ACCEPTED SOLUTION

Hi there,

 

If you're looking to use multiple custom fields,  they both need to be added to the list before being set in the ContactData object.  This should do the trick:

 

// Set Member Id
            CustomField objCustomField = new CustomField();
            List<CustomField> lsCustomField = new ArrayList<CustomField>();
            objCustomField.setName("CUSTOM FIELD 1");
            objCustomField.setValue(alMemberId.get(i).toString());
            lsCustomField.add(objCustomField);
            //objContactData.setCustomFields(lsCustomField);

            CustomField objCustomField2 = new CustomField();
            //List<CustomField> lsCustomField = new ArrayList<CustomField>();
            objCustomField2.setName("CUSTOM FIELD 2");
            objCustomField2.setValue(alMemberId.get(i).toString());
            lsCustomField.add(objCustomField2);
            objContactData.setCustomFields(lsCustomField);

// Add contact to contact list
            lsContactData.add(objContactData);

 

View solution in original post

27 REPLIES 27
DaveBerard
Moderator

Sorry for the problem you are running into.  Our development team is looking into this right now and we hope to have a fix out for this very soon.  The problem is not your code, it's a bug in our JSON Schema validation.  We should have a fix for this by mid week and are working on this as a top priority.  Thanks for reporting!

Dave Berard
Senior Product Manager, Constant Contact

Thanks, I will be looking for the fix coming ahead...

We have tested a fix in our development environment and have it planned to be released Thurs morning.  Will update once we confirm we've released the fix in production.  Sorry again for the frustration here!

Dave Berard
Senior Product Manager, Constant Contact
AdamP91
Occasional Participant

I'm still seeing an error with this when using the phpWrapper library.  Calling the addCreateContactsActivity, with contacts that have a custom field returns an error saying.

 

[{"error_key":"json.regex.mismatch","error_message":"#/import_data/0/custom_fields/0/name: Value does not match the required regex pattern: ^Custom\\s?Field\\s?1[0-5]$|^Custom\\s?Field\\s?[1-9]$."}]

 

Looking at the AddContacs class the expected name value for custom fields is in the format custom_field_[0-15].  The library appears to update this value for the columns array in the requwt to the format "CUSTOM FIELD [0-15]" but does not ever update the name attribute in the contact->custom field array to the expected key value for the server.

 

As a quick work around I modified the toJson function to update the name 

 

public function toJson()
{
    foreach ($this->import_data as $contact) {
        if( !empty( $contact->custom_fields ) ){
            foreach( $contact->custom_fields as &$cf ){
                $cf->name = Config::get('activities_columns.' . $cf->name );
            }
        }
        foreach ($contact as $key => $value) {
            if ($value == null) {
                unset($contact->$key);
            }
        }
    }
    return json_encode($this);
}

 

running this gets past the server side regx check but generates an error saying 

 

[{"error_key":"http.status.internal_server_error","error_message":"We are currently experiencing an issue with our service, please try again in a few minutes or contact Customer Support at webservices@constantcontact.com."}]

 

When I remove all custom field information the bulk add works correctly.

 

Here is the json data that generates the regx exception with no modifications to the toJson function

 

{"import_data":[{"first_name":"John","last_name":"Doe","email_addresses":["john.doe@hsc.edu"],"custom_fields":[{"name":"custom_field_1","value":"325"}]},{"first_name":"Jane","last_name":"Doe","email_addresses":["jane.doe@test.com"],"custom_fields":[{"name":"custom_field_1","value":"1037"}]}],"lists":["1"],"column_names":["EMAIL","FIRST NAME","LAST NAME","CUSTOM FIELD 1"]}

 

 

Here is the modifed json that generates the internal server error

 

{"import_data":[{"first_name":"John","last_name":"Doe","email_addresses":["john.doe@hsc.edu"],"custom_fields":[{"name":"CUSTOM FIELD 1","value":"325"}]},{"first_name":"Jane","last_name":"Doe","email_addresses":["jane.doe@test.com"],"custom_fields":[{"name":"CUSTOM FIELD 1","value":"1037"}]}],"lists":["1"],"column_names":["EMAIL","FIRST NAME","LAST NAME","CUSTOM FIELD 1"]}

Thanks for sending this over.  We did release a fix yesterday afternoon for the custom field errors and confirmed that is all set.  We'll take a look at this new report and let you know when we have more information.

Dave Berard
Senior Product Manager, Constant Contact

Hi Dave,

 

Thanks for the confirmation.  However I am seeing the following error message now when I try to compile the Java code posted earlier (the very first program in this thread).

 

CUrlRequestError [errorKey=json.regex.mismatch, errorMessage=#/import_data/0/custom_fields/0/name: Value does not match the required regex pattern: ^Custom\s?Field\s?1[0-5]$|^Custom\s?Field\s?[1-9]$.]

 

Could you please explain me about this error and how to fix it? The other day you confirmed that my code was correct, please note that I have not modified anything in my code.

 

Regards,

Srinivas

Hi Srinivas,

 

Our developers are working on this, and if all goes well, this custom field issue will be resolved by Friday afternoon.  Thanks for your patience!

 

Best Regards,

Shannon W.

API Support Specialist

SrinivasU3
Regular Participant

Hi Shannon,


Looks like the bulk member upload API is working fine now.  I am able to upload the members into the account using the code that I have mentioned in the beginning of this thread.  However I am still unable to set the label and the value for the custom field.  Not sure if it is something that I need to fix in my code.

 

Also, can you please let me know the limit of member upload count for trial account?  Looks like I am able to upload 500 members in one shot into the account.  However I get the invalid json payload error when I try to load more than 7,000 members.  Also, please note that I am able to upload 7,000+ members manually into the account from the CSV file but not from my code.  My code uploads successfully when the load is fed in batches of 500.

 

Thanks,

Srinivas

 

 

We have some size limitations for the bulk imports from the API (which are identical to the UI limitations, just exposed in different ways).  You can read them all here, but here is an except that should answer your questions:

 

Limitations

The size of the JSON request payload must be less than 4 megabytes. Also, the  number of contacts that you can import in a single POST is limited to 20,000. The activity request will fail if the payload is greater than 4 MBs or if there are more 20,000 contacts. Remember, the more columns or properties that you include with the imported contact, the bigger the JSON payload will be

Dave Berard
Senior Product Manager, Constant Contact

On additional piece that could be helpful.  We have released importing via CSV through the API, though this hasn't been added to the wrapper libraries yet.  This allows you to do the exact same imports that you would through our UI with a CSV file through the API.  You can see the documentation for that here: http://developer.constantcontact.com/docs/bulk_activities_api/bulk-activities-addcontact-multipart.h...

Dave Berard
Senior Product Manager, Constant Contact
TimC245
Regular Participant

Could you provide me with a sample in either C# or VB.net? I'm working at integrating with my windows form application and have no exprience with Java and having a problem. I could send you guys my vb.net code if you would like to see what I'm doing.

 

I'm tryign to do the bulk import file upload as suggested.

 

Thanks a head of time.

We don't currently have any examples of doing a file import with C# currently, we are in the process of adding this to our wrapper library and will hopefully have this in the next few weeks.  Follow our Github repo and you'll see when this is added: https://github.com/constantcontact/.net-sdk

Dave Berard
Senior Product Manager, Constant Contact
TimC245
Regular Participant

It's nice that you guys will be adding it to the Github repository but I was wondering if you could look at my code and see what I'm doing wrong. It's VB.net. I think it's the whole Oauth with passing in the http headers thats the problem. Thanks a head of time.

 

Imports System.IO
Imports System.Text
Imports System.Collections.Specialized

 

Private Sub tyrout()

        Dim filename As String = ""

        Dim boundary As String = Guid.NewGuid().ToString()

        Dim request As HttpWebRequest = TryCast(HttpWebRequest.Create("https://api.constantcontact.com/v2/activities/addcontacts"), HttpWebRequest)

        request.Method = "POST"  

       request.ContentType = String.Format("multipart/form-data")

        request.Accept = "application/json"

        'request.PreAuthenticate = True

        Dim sb As New StringBuilder()

        sb.AppendFormat("--{0}", boundary)

        sb.AppendFormat(vbCr & vbLf)

        filename = "C:\Development\constantcontact\emailkust.csv"

        sb.AppendFormat("Content-Disposition: form-data; name=""media""; filename=""" & filename & """")

        sb.AppendFormat(vbCr & vbLf)

        sb.AppendFormat("Authorization:  Bearer ") 'place the key from oauth here is my guess

        sb.AppendFormat(vbCr & vbLf)    

        sb.AppendFormat("content-Type:  multipart/form-data")

        sb.AppendFormat(vbCr & vbLf)

        sb.AppendFormat("lists:  75") 'list number I guess is where it should go

        sb.AppendFormat(vbCr & vbLf)

        sb.AppendFormat("api_key: ") 'place the api key here I think or should it go on the http path?

        sb.AppendFormat(vbCr & vbLf)

        Using fs As New FileStream(filename, FileMode.Open, FileAccess.Read)  

           Dim contents As Byte() = New Byte(fs.Length - 1) {}

            fs.Read(contents, 0, contents.Length)

            sb.Append(Encoding.[Default].GetString(contents))

        End Using

        sb.AppendFormat(vbCr & vbLf)

        sb.AppendFormat("--{0}--", boundary)

        Dim fulldata As Byte() = Encoding.[Default].GetBytes(sb.ToString())

        request.ContentLength = fulldata.Length

        Using sw As Stream = request.GetRequestStream()

            sw.Write(fulldata, 0, fulldata.Length)

        End Using       

  Dim response As HttpWebResponse = TryCast(request.GetResponse(), HttpWebResponse)        

Using sr As New StreamReader(response.GetResponseStream())

            MessageBox.Show(sr.ReadToEnd())       

  End Using    

End Sub

 

The csv file looks like this

"EMAIL","LAST NAME","FIRST NAME"
"1@one.org","1","1"
"2@two.org","2","2"
"3@three.org","3","3"
"4@four.org","4","4"

The one thing I see immediately is that api_key is a query parameter for the URL, not a header parameter.  Our support team will check out the code though as well to see if we can get you up and running.

Dave Berard
Senior Product Manager, Constant Contact
TimC245
Regular Participant

Thank you guys for the help. I've included the code that you guys have helped me with so it can be of help for those in the future.

 

Note about the api_key. Looking at the java sample that is posted to follow I see/saw no mention of even needing/using the api-key. I was just throwing everything I could think of at this and figured since the Bearer code went in the http header that maybe the api_key should also since it didn't appear to be needed. Although I do have to say I may have had it in the right place but had something else wrong at one point in all the tries I went thru before asking for help.  

 

Either way I would like to thank you for the support.  

 

VB.net VS 2010, framework 3.5

 

Imports System.IO
Imports System.Text
Imports System.Collections.Specialized
Private Sub FileUpload()
        Dim filename As String = ""
        ' Added -- to boundary for simplicity
        Dim boundary As String = "--" & Guid.NewGuid().ToString()
 
        ' The API key needs to be appended to the request URI
        Dim request As HttpWebRequest = TryCast(HttpWebRequest.Create("https://api.constantcontact.com/v2/activities/addcontacts?api_key=APIKEYHERE"), HttpWebRequest)
        request.Method = "POST"
        request.ContentType = String.Format("multipart/form-data")
        request.Accept = "application/json"
        'request.PreAuthenticate = True
        request.Headers.Add("Authorization:  Bearer BEARERTOKEN"' Add your Access Token here
        ' I Also changed from AppendFormat for all lines to simply using AppendLine to shorten the content. 
        ' Feel free to change it back where you want to merge variables.
 
        filename = "C:\Development\constantcontact\emailkust.csv"
 
        ' In order to get the request right, there are three request parts to add:
        ' file_name - The filename
        ' lists - comma separated list of list IDs
        ' data - The actual file data
 
        Dim sb As New StringBuilder()
        sb.AppendLine(boundary)
        sb.AppendLine("content-disposition: form-data; name=""file_name""")
        sb.AppendLine()
        sb.AppendLine("emailkust.csv"'filename
        sb.AppendLine(boundary)
        sb.AppendLine("content-disposition: form-data; name=""lists""")
        sb.AppendLine()
        sb.AppendLine("1"' List Number
        sb.AppendLine(boundary)
 
        sb.AppendLine("content-disposition: file; name=""data"" filename=""emailkust.csv""")
        sb.AppendLine("Content-Type: text/csv")
        sb.AppendLine()
        Using fs As New FileStream(filename, FileMode.Open, FileAccess.Read)
            Dim contents As Byte() = New Byte(fs.Length - 1) {}
            fs.Read(contents, 0, contents.Length)
            sb.Append(Encoding.[Default].GetString(contents))
        End Using
 
        sb.AppendLine(boundary & "--")
        Dim fulldata As Byte() = Encoding.[Default].GetBytes(sb.ToString())
        ' Uncomment the next line to dump the multipart request contents to a file for debugging.
        ' My.Computer.FileSystem.WriteAllText("C:\constantcontact\test.txt", sb.ToString(), True)
        request.ContentLength = fulldata.Length
        Using sw As Stream = request.GetRequestStream()
            sw.Write(fulldata, 0, fulldata.Length)
        End Using
        ' Exception Handling was added so that I could display the error 
        Try
            Dim response As HttpWebResponse = TryCast(request.GetResponse(), HttpWebResponse)
            Using sr As New StreamReader(response.GetResponseStream())
                MessageBox.Show(sr.ReadToEnd())
            End Using
        Catch e As WebException
            Using sr As New StreamReader(e.Response.GetResponseStream())
                MessageBox.Show("Error Message:" & e.Message & vbCr & vbLf & "Error Body: " & sr.ReadToEnd(), "Web Error"MessageBoxButtons.OK, MessageBoxIcon.Error)
            End Using
        End Try
 
    End Sub

 

Thanks so much for posting this, I'm sure it will be useful for others as well!

 

Sincerely,

Elijah G.

API Support Specialist

Elijah G.
API Support Engineer
TimC245
Regular Participant

I have a simular problem. I am sending first name,last name, and email using the builk actitivies add contacts v2/activities/addcontacts and it works fine until I increase the number of contacts that I send. In my testing I can get around 2,000 clients (156281 characters once all the json items are added)  with no problem but as soon as I increase it I get json error messages. 

 

error_key: json.payload.invalid, error_message: Exception with request to: class com.roving.platform.domain.activities.addcontactsactivity 

 

I know that the size that I'm sending (with 20,000 contacts with the josn) is 1,357,263 characters so if I'm rembering correctly the actual size in bytes is then twice that which is 2,714,526 bytes (2.5 mb) which is less than the 4mb in the limitations.

 

I'm using the information from http://developer.constantcontact.com/docs/bulk_activities_api/bulk-activities-add-contacts.html)

 

I'm currently looking at your suggested builk activites multipart- add contacts multipart api but I would rather not do file uploads with the layer of file managment that would then be needed.

 

In way of testing is there any way that I could see exactly what the api is receiving by way of some kind of bounce back or echo in the responce. So I can exactly see what is being received. I have checked my controls that I'm using and they say the have no limits on the size but still just looking for more way to touble shoot this.

 

Thanks ahead of time.

 

Also I just verified that once I get to 200,000 characters the error happens which is a little more than 2,600 contacts.

Hi,

 

I'd like to reproduce this behavior and work with my engineering team to figure out if we need to revise the stated bulk activity size limits, or if there is something we can do to get these bulk payloads accepted.

 

Would you mind sending webservices@constantcontact.com an email with the 2.000 and 2,600 contact payloads (as text attachments, so that we can quickly verify the issue and work toward a resolution?  Thanks in advance!  

 

Best Regards,

Shannon W.

API Support Specialist

TimC245
Regular Participant

Have sent it off to the email to  webservices@constantcontact.com

Looking forward to seeing what is going on.

 

let me know if you need any more specifics off of me.

Thanks for reporting this.  In looking into this, our engineers found that we had an issue on our side with large JSON payloads.  We're working on fixing it now.  Unfortunately, the problem is on any import from JSON over 200,000 Bytes until we resolve the issue.  The temporary workaround is to use a CSV file import using multi-part imports, which is working correctly with the 4MB file cap.  Sorry for the inconvenience and we'll update once we have a fix.

Dave Berard
Senior Product Manager, Constant Contact
Developer Portal

View API documentation, code samples, get your API key.

Visit Page