Import Contacts using the Multipart form Bulk Activity Endpoint

One of the most efficient ways to add or update contacts using the v2 API is by using the Import Contacts multipart endpoint. You will need to create a file in one of the supported types with the contact information you want to import.

Why is using multipart bulk activity your best bet for adding and updating contacts?

  • You can easily package the contact data by exporting it from your database to a file.
  • The POST creates an asynchronous background job
  • No risk of hitting API call limits – you can add/update up to 20,000 contacts with a single API call
  • Only individual contacts with format problems fail, not the entire job
  • monitor status using the location value in the response header

What’s needed

There are 3 major elements you need to make this happen:

  1. The contact data to import.
  2. The list(s) you want to add the contacts to.
  3. The multipart post code that calls the endpoint and passes the file.

Contact data format

File types

The Import Contacts bulk activity endpoint supports the following file types:

  • .txt
  • .csv
  •  .xls
  • .xlsx

File format

The import file consists of columns, one for each contact property included, and rows, one for each contact being imported.

importdata

Contact Properties

You can include the following contact properties in your import file. You must name the column containing the property as shown below:

  • EMAIL (also E-MAIL, EMAIL ADDRESS, E-MAIL ADDRESS)
  • FIRST NAME
  • MIDDLE NAME
  • LAST NAME
  • JOB TITLE
  • COMPANY NAME
  • WORK PHONE
  • HOME PHONE
  •  ADDRESS LINE 1 to 3
  • CITY
  • STATE
  • US STATE/CA PROVINCE
  • COUNTRY
  • ZIP/POSTAL CODE
  • SUB ZIP/POSTAL CODE
  • CUSTOM FIELD 1 to 15

Limitations

There are two limitations you need to be aware of when using the Import Contacts bulk activity endpoint:

  1. File size: the import file must be less than 4 megabytes.
  2. Number of contacts: Each POST can import a maximum 20,000 contacts.

The activity request will fail if the payload is greater than 4 MBs or if there are more 20,000 contacts.

Examples

Here are a few code examples using the Import Contacts multipart endpoint to import contacts from a file to a contact list.

CURL Example

This example CURL script uploads the file contacts.txt to the import contacts multipart endpoint, adding the contacts to listId=5. It assumes that the data file is located in the same directory from which the script is run, otherwise you must use an absolute path to the data file.

curl -i -H "Authorization: Bearer <Oauth2.0_access_token>" -H "Content-Type: 
multipart/form-data" -H "Accept: application/json" -X POST -F 'lists=5' 
-F 'file_name=contacts.txt'  -F 'data=@contacts.txt' 
"https://api.constantcontact.com/v2/activities/addcontacts?api_key=<api_key>"

Java Example

Here’s an example of a multipart encoded post written in Java that imports the file contacts.txt, adding the contact to contact list 1 (listId=1).

final HttpClient httpclient = new DefaultHttpClient();
    final HttpPost httppost = new 
    HttpPost("https://api.constantcontact.com/v2/activities/addcontacts?api_key=<api_key>");

    httppost.addHeader("Authorization", "Bearer <OAuth2.0_access_token>");
    httppost.addHeader("Accept", ”application/json”);
    httppost.addHeader("content-type", "multipart/form-data");

    final File fileToUse = new File("/path_to_file/contacts.txt");
  //e.g. /temp/contact.txt
    final FileBody data = new FileBody(fileToUse);
    final String listIds = "1";
    final StringBody lists = new StringBody(listIds);
    final StringBody fileName = new StringBody(fileToUse.getName());
    final MultipartEntity reqEntity = new MultipartEntity();
    reqEntity.addPart("file_name", fileName);
    reqEntity.addPart("lists", lists);
    reqEntity.addPart("data", data);

    httppost.setEntity(reqEntity);

    final HttpResponse response = httpclient.execute(httppost);
    final HttpEntity resEntity = response.getEntity();

    EntityUtils.consume(resEntity);

   httpclient.getConnectionManager().shutdown();
 }

Java SDK

The Constant Contact Java SDK includes methods for all bulk activities, including the import contacts multipart bulk activity endpoint.  Here’s a snippet of code that uses the ctct.addBulkContactsMultipart Java SDK method to import the contacts in file.xlsx and add them to contact lists 4 and 5.

System.out.println("Multipart test...");

      File f = new File("file.xlsx");

      ArrayList listIds = new ArrayList();
      listIds.add("4"); listIds.add("5");

      try { ContactsResponse response1 =
      ctct.addBulkContactsMultipart("file.xlsx", f, listIds);
      System.out.println(response1.toJSON()); } catch
      (ConstantContactServiceException e) { List errors =
      e.getErrorInfo(); for (CUrlRequestError error : errors) {
      System.out.println(error.getErrorMessage()); } }

Ruby Example

This example coded in Ruby is available along with all supporting files in the Constant Contact GitHub Ruby repository.

#
# myapp.rb
# ConstantContact
# 
#Copyright (c) 2014 Constant Contact. All rights reserved.
require 'rubygems'
require 'sinatra'
require 'active_support'
require 'yaml'
require 'constantcontact'
# This is a Sinatra application (http://www.sinatrarb.com/).
# Update config.yml with your data before running the application.
# Run this application like this : ruby myapp.rb
# Name this action according to your 
# Constant Contact API Redirect URL, see config.yml
get '/cc_callback' do
    cnf = YAML::load(File.open('config/config.yml'))

    @oauth = ConstantContact::Auth::OAuth2.new(
      :api_key => cnf['api_key'],
      :api_secret => cnf['api_secret'],
      :redirect_url => cnf['redirect_url']
    )

    @error = params[:error]
    @user = params[:username]
    @code = params[:code]

    if @code
      begin
        @lists = []

        response = @oauth.get_access_token(@code)
        @token = response['access_token']

        cc = ConstantContact::Api.new(cnf['api_key'])
        lists = cc.get_lists(@token)
        if lists
          lists.each do |list|
            # Select the first list, by default
            selected = list == lists.first
            @lists << {
              'id' => list.id,
              'name' => list.name,
              'selected' => selected
            }
          end
        end

      rescue => e
        message = parse_exception(e)
        @error = "An error occured when saving the contacts : " + message
      end
      erb :contacts_multipart
    else
      erb :callback
    end
end

# Name this action according to your
# Constant Contact API Redirect URL, see config.yml
post '/cc_callback' do
    cnf = YAML::load(File.open('config/config.yml'))

    @error = params[:error]
    @user = params[:username]
    @code = params[:code]
    @token = params[:token]

    if @code
      cc = ConstantContact::Api.new(cnf['api_key'])

      @activity = params[:activity]
      lists = params[:lists] || {}
      lists['checkboxes'] = [] if lists['checkboxes'].blank?

      @lists = []
      if lists['ids']
        lists['ids'].each do |key, list_id|
          list_name = lists['names'][key]
          selected = !(lists['checkboxes'].blank? || lists['checkboxes'][key].blank?)
          @lists << {
            'id' => list_id,
            'name' => list_name,
            'selected' => selected
          }
        end
      end

      begin
        if @activity
          # Validate
          raise 'Please select a file' if @activity['file'].blank?
          file_name = @activity['file'][:filename]
          contents = @activity['file'][:tempfile].read

          add_to_lists = []
          lists['ids'].each do |key, list_id|
            add_to_lists << list_id if lists['checkboxes'][key]
          end
          add_to_lists = add_to_lists.join(',')

          if /remove_contacts/.match(file_name)
            cc.add_remove_contacts_from_lists_activity_from_file(@token, file_name, contents, add_to_lists)
          elsif /add_contacts/.match(file_name)
            cc.add_create_contacts_activity_from_file(@token, file_name, contents, add_to_lists)
          end

          redirect '/cc_callback'
        end
      rescue => e
        message = parse_exception(e)
        @error = "An error occured when saving the contacts : " + message
        #puts e.backtrace
      end
      erb :contacts_multipart
    else
      erb :callback
    end
end

def parse_exception(e)
  if e.respond_to?(:response)
    hash_error = JSON.parse(e.response)
    message = hash_error.first['error_message']
  else
    message = e.message
  end
  message.to_s
end

Leave a Comment