diff --git a/salesforce_api/salesforce_api.admin.inc b/salesforce_api/salesforce_api.admin.inc
index c1e78eb..5e6d913 100644
--- a/salesforce_api/salesforce_api.admin.inc
+++ b/salesforce_api/salesforce_api.admin.inc
@@ -70,7 +70,30 @@ function salesforce_api_settings_form() {
     ),
     '#default_value' => variable_get('salesforce_api_error_log', SALESFORCE_LOG_ALL),
   );
-
+  $form['objects'] = array(
+    '#type' => 'fieldset',
+    '#title' => t('Object settings'),
+    '#collapsible' => TRUE,
+    '#collapsed' => TRUE,
+    '#weight' => -9,
+  );
+  $form['objects']['clear_cache'] = array(
+    '#type'  => 'item',
+    '#value' => t('Caching data improves performance, however your Drupal site will be unaware of any alterations made to your Salesforce installation unless the cached data is refreshed. Select the lifetime the object data after which the cache will be automatically refreshed.  To refresh all cached object data on your site, click the button below.'),
+  );
+  $period = drupal_map_assoc(array(32400, 43200, 86400, 172800, 259200, 604800, 1209600, 2419200, 4838400, 9676800), 'format_interval');
+  $period[CACHE_PERMANENT] = t('<none>');
+  $form['objects']['salesforce_api_object_expire'] = array(
+    '#type' => 'select',
+    '#title' => t('Cache lifetime'),
+    '#options' => $period,
+    '#default_value' => variable_get('salesforce_api_object_expire', CACHE_PERMANENT),
+  );
+  $form['objects']['clear_cache_clear'] = array(
+    '#type' => 'submit',
+    '#value' => t('Clear cached object data'),
+    '#submit' => array('salesforce_api_cache_build'),
+  );
   // Validate handler makes sure that the salesforce_api_password doesn't get set to null on accident
   $form['#validate'][] = 'salesforce_api_settings_form_validate';
   $form['#submit'][] = 'salesforce_api_settings_form_submit';
@@ -426,6 +449,88 @@ function theme_salesforce_api_fieldmap_edit_form_table($form) {
   return theme('table', $header, $rows, $attributes, $caption);
 }
 
+ /**
+ * Ask salesforce for a list of objects and display a checklist for the user.
+ * Based on user selection, set up or tear down cached/synched Salesforce data.
+ * @TODO make this more user friendly. At the moment it's possible for an admin user to blow away
+ * their entire local SalesForce cache with a few clicks. This is not necessarily desirable.
+ *
+ * @param string $form_state
+ * @return void
+ * @author aaron
+ */
+function salesforce_api_admin_object(&$form_state) {
+  $objects = salesforce_api_describeGlobal();
+  $cache = cache_get('salesforce_api_sf_objects');
+  $defaults = is_array($cache->data) ? array_keys($cache->data) : array();
+
+  if (empty($objects->types)) {
+    drupal_set_message(t('There was an error retrieving the list of SalesForce objects. Please verify that your SalesForce instance is properly configured.'), 'error');
+    return;
+  }
+
+  $options = array_combine($objects->types, $objects->types);
+  $fields = array('objects' => array(
+      '#type' => 'checkboxes',
+      '#title' => 'SalesForce Objects',
+      '#description' => 'Check the SalesForce objects you would like to synchronize locally.',
+      '#options' => $options,
+      '#default_value' => $defaults,
+    ),
+    '#theme' => 'salesforce_api_object_options',
+    'submit' => array(
+      '#type' => 'submit',
+      '#value' => 'Save'
+      ),
+    );
+  return $fields;
+}
+
+/**
+ * FAPI submit handler
+ */
+function salesforce_api_admin_object_submit($form, &$form_state) {
+  $values = $form_state['values']['objects'];
+  foreach ($values as $i => $t) {
+  if (empty($t)) continue;
+    $real_types[] = $t;
+  }
+  $sf_objects = variable_set('salesforce_api_enabled_objects', $real_types);
+  $objects = salesforce_api_cache_build();
+  return;
+}
+
+function salesforce_api_admin_object_settings($form_state, $type) {
+  return array('settings' => array(
+    '#type' => 'markup',
+    '#value' => 'Placeholder for per-object configuration settings.'
+    )
+  );
+}
+
+/**
+ * Theming function for salesforce_api_admin_setup
+ * For locally-cached SF Objects, add a "configure" or "re-map" link next to the checkbox
+ */
+function theme_salesforce_api_object_options($element = NULL) {
+  if (empty($element['objects']['#options'])) return drupal_render($element);
+  $objects = $element['objects'];
+  $options = $objects['#options'];
+  foreach ($options as $i) {
+    if (empty($objects[$i]['#value'])) continue;
+    $link = l('configure', SALESFORCE_PATH_OBJECT .'/'. $i);
+    if ($_SESSION['objects_error'][$i]) {
+      $element['objects'][$i]['#prefix'] = '<div class="error">';
+      $element['objects'][$i]['#suffix'] = '</div>';
+      unset($_SESSION['objects_error'][$i]);
+      $link = l('re-map fields', SALESFORCE_PATH_OBJECT .'/'. $i);
+    }
+    $element['objects'][$i]['#title'] .= ' | '. $link;
+  }
+  unset($_SESSION['objects_error']);
+  return drupal_render($element);
+}
+
 /**
  * Demonstrates some of the API functionality through the Salesforce class and
  * fieldmap functionality.
diff --git a/salesforce_api/salesforce_api.install b/salesforce_api/salesforce_api.install
index 7238c6d..3c448e1 100644
--- a/salesforce_api/salesforce_api.install
+++ b/salesforce_api/salesforce_api.install
@@ -20,6 +20,7 @@ function salesforce_api_install() {
 function salesforce_api_uninstall() {
   drupal_uninstall_schema('salesforce_api');
   db_query("DELETE FROM {variable} WHERE {name} LIKE 'salesforce%'");
+  db_query("DELETE FROM {cache} WHERE {cid} = 'salesforce_api_sf_objects'");
 }
 
 /**
@@ -27,6 +28,7 @@ function salesforce_api_uninstall() {
  */
 function salesforce_api_enable() {
   drupal_set_message(t('Salesforce API: Before making any Salesforce connections, please <a href="!url">enter your Salesforce API credentials</a>', array('!url' => url(SALESFORCE_PATH_ADMIN))), 'warning');
+drupal_set_message(t('Salesforce API: The default Salesforce object have been enabled, to export/import any other objects see the <a href="!url">Object setup</a> page.', array('!url' => url(SALESFORCE_PATH_OBJECT))), 'warning');
 }
 
 /**
diff --git a/salesforce_api/salesforce_api.module b/salesforce_api/salesforce_api.module
index f65a1a6..4040cbd 100644
--- a/salesforce_api/salesforce_api.module
+++ b/salesforce_api/salesforce_api.module
@@ -17,10 +17,12 @@ define('SALESFORCE_DIR_TOOLKIT', SALESFORCE_DIR .'/toolkit');
 define('SALESFORCE_DIR_SOAPCLIENT', SALESFORCE_DIR_TOOLKIT .'/soapclient');
 define('SALESFORCE_DIR_WSDL', SALESFORCE_DIR .'/wsdl');
 
+
 // Define Drupal paths for various parts of the Salesforce UI.
 define('SALESFORCE_PATH_ADMIN', 'admin/settings/salesforce');
-define('SALESFORCE_PATH_FIELDMAPS', 'admin/settings/salesforce/fieldmap');
-define('SALESFORCE_PATH_DEMO', 'admin/settings/salesforce/demo');
+define('SALESFORCE_PATH_FIELDMAPS', SALESFORCE_PATH_ADMIN .'/fieldmap');
+define('SALESFORCE_PATH_DEMO', SALESFORCE_PATH_ADMIN .'/demo');
+define('SALESFORCE_PATH_OBJECT', SALESFORCE_PATH_ADMIN .'/object');
 
 // Define field importing requirements.
 // TODO: I believe we need to use bitwise operators instead.
@@ -111,7 +113,23 @@ function salesforce_api_menu() {
     'type' => MENU_CALLBACK,
     'file' => 'salesforce_api.admin.inc',
   );
-
+  $items[SALESFORCE_PATH_OBJECT] = array(
+    'title' => 'Object setup',
+    'description' => 'Define which SalesForce objects you would like to be available in your Drupal site.',
+    'page callback' => 'drupal_get_form',
+    'page arguments' => array('salesforce_api_admin_object'),
+    'access arguments' => array('administer salesforce'),
+    'type' => MENU_LOCAL_TASK,
+    'file' => 'salesforce_api.admin.inc',
+  );
+  $items[SALESFORCE_PATH_OBJECT .'/%'] = array(
+    'title' => 'Object setup',
+    'page callback' => 'drupal_get_form',
+    'page arguments' => array('salesforce_api_admin_object_settings', count(explode('/', SALESFORCE_PATH_OBJECT))),
+    'access arguments' => array('administer salesforce'),
+    'type' => MENU_CALLBACK,
+    'file' => 'salesforce_api.admin.inc',
+  );
   return $items;
 }
 
@@ -164,7 +182,7 @@ function salesforce_api_connect($username = FALSE, $password = FALSE, $token = F
   }
 
   // Include the file that defines the class.
-  require_once(drupal_get_path('module', 'salesforce_api') . '/salesforce.class.inc');
+  require_once(drupal_get_path('module', 'salesforce_api') .'/salesforce.class.inc');
 
   // Create a new Salesforce object with the API credentials.
   $sf = new DrupalSalesforce($username, $password, $token);
@@ -201,7 +219,7 @@ function salesforce_api_connect($username = FALSE, $password = FALSE, $token = F
 function salesforce_api_reset_expired_password($sf) {
   // Append one letter and one digit to the password to make sure we meet
   // salesforce's password validation requirements.
-  $new_password = user_password() . 'z9';
+  $new_password = user_password() .'z9';
   // setPassword() may throw InvalidIdFault or UnexpectedErrorFault exceptions.
   $sf->client->setPassword($sf->login->userId, $new_password);
   variable_set('salesforce_api_password', $new_password);
@@ -239,38 +257,30 @@ function salesforce_api_fieldmap_objects($type) {
   if ($type == 'salesforce') {
     $cache = cache_get('salesforce_api_sf_objects');
     if ($cache->data == '') {
-      $sf_objects = variable_get('salesforce_api_enabled_objects', array('Campaign', 'Contact', 'Lead'));
-      $sf = salesforce_api_connect();
-      if (!$sf) {
-        drupal_set_message(t('Unable to connect to Salesforce using <a href="!url">current credentials</a>.', array('!url' => url(SALESFORCE_PATH_ADMIN))));
-        return array();
-      }
-
-      $result = $sf->client->describeSObjects($sf_objects);
-      foreach ($result as $key => $object) {
-        $objects[$sf_objects[$key]] = array(
-          'label' => t($sf_objects[$key]),
-          'fields' => array(),
-        );
-        foreach ($object->fields as $field) {
-          $objects[$sf_objects[$key]]['fields'][$field->name] = array(
-            'label' => t($field->label),
-          );
-          if ($field->createable != 1) {
-            $objects[$sf_objects[$key]]['fields'][$field->name]['type'] = SALESFORCE_FIELD_SOURCE_ONLY;
-          }
-          elseif ($field->nillable != 1 && $field->defaultedOnCreate != 1) {
-            $objects[$sf_objects[$key]]['fields'][$field->name]['type'] = SALESFORCE_FIELD_REQUIRED;
-          }
-        }
-      }
-      cache_set('salesforce_api_sf_objects', $objects);
+      $objects = salesforce_api_cache_build();
     }
     else {
       $objects = $cache->data;
     }
   }
+  return $objects;
+}
 
+/**
+ * Recreate the salesforce object cache
+ */
+function salesforce_api_cache_build() {
+  $sf_objects = variable_get('salesforce_api_enabled_objects', array('Campaign', 'Contact', 'Lead'));
+  $sf = salesforce_api_connect();
+  $result = $sf->client->describeSObjects($sf_objects);
+  foreach ($result as $key => $object) {
+    $objects[$sf_objects[$key]] = salesforce_api_object_to_fieldmap_fields($object);
+  }
+  // find the expiry time
+  $lifetime = variable_get('salesforce_api_object_expire', CACHE_PERMANENT);
+  $expire = ($lifetime == CACHE_PERMANENT) ? CACHE_PERMANENT : time() + $lifetime;
+  cache_set('salesforce_api_sf_objects', $objects, $table = 'cache', $expire, $headers = NULL);
+  drupal_set_message(t('Salesforce object cache has been refreshed.'));
   return $objects;
 }
 
@@ -643,3 +653,56 @@ function salesforce_api_theme($existing, $type, $theme, $path) {
     ),
   );
 }
+
+/**
+ * Wrapper for SOAP SforceBaseClient::describeGlobal
+ * @return an SFQueryResult object (look at ->types for an array of SF object types)
+ */
+function salesforce_api_describeGlobal() {
+  static $objects;
+  if (!empty($objects)) {
+    return $objects;
+  }
+  $sf = salesforce_api_connect();
+  if ($sf === FALSE) {
+    $link = l('Please verify that you have completed your SalesForce credentials', SALESFORCE_PATH_ADMIN);
+    drupal_set_message(t('Unable to connect to SalesForce. !link', array('!link' => $link)), 'error');
+    return;
+  }
+  $objects = $sf->client->describeGlobal();
+  return $objects;
+}
+
+/**
+ * Convert Salesforce object fields to fieldmap array for saving
+ */
+function salesforce_api_object_to_fieldmap_fields($object)  {
+  $fieldmap_object = array(
+    'label' => t($object->label),
+    'fields' => array()
+  );
+
+  foreach ($object->fields as $field) {
+    $fieldmap_object['fields'][$field->name]['label'] = t($field->label);
+    if ($field->createable != 1) {
+      $fieldmap_object['fields'][$field->name]['type'] = SALESFORCE_FIELD_SOURCE_ONLY;
+    }
+    elseif (!$field->nillable && !$field->defaultedOnCreate) {
+      $fieldmap_object['fields'][$field->name]['type'] = SALESFORCE_FIELD_REQUIRED;
+    }
+    else {
+      $fieldmap_object['fields'][$field->name]['type'] = SALESFORCE_FIELD_OPTIONAL;
+    }
+  }
+  return $fieldmap_object;
+}
+
+/**
+ * Implementation of hook_cron().
+ */
+function salesforce_api_cron() {
+  $cache = cache_get('salesforce_api_sf_objects');
+  // if the cache has already been delete or is expired then rebuild
+  if (!$cache || time() > $cache->expire) salesforce_api_cache_build();
+  return;
+}
\ No newline at end of file
