diff --git modules/uc_recurring.uc_paypal.inc modules/uc_recurring.uc_paypal.inc
index 05776ea..4d7bf92 100644
--- modules/uc_recurring.uc_paypal.inc
+++ modules/uc_recurring.uc_paypal.inc
@@ -6,6 +6,8 @@
  * Uc recurring implementation for the Paypal module.
  */
 
+define('UC_PAYPAL_RECURRING_API', '50.0');
+
 /**
  * Implementation of hook_recurring_info().
  */
@@ -14,18 +16,26 @@ function uc_recurring_uc_paypal_recurring_info() {
     'name' => t('Paypal website payments standard'),
     'payment method' => 'paypal_wps',
     'fee handler' => 'paypal_wps',
-    'module' => 'UC recurring',
-    'renew' => 'uc_recurring_paypal_wps_renew',
-    'process' => 'uc_recurring_paypal_wps_process',
+    'module' => 'uc_recurring',
+    'renew callback' => 'uc_recurring_paypal_wps_renew',
+    'process callback' => 'uc_recurring_paypal_wps_process',
   );
 
   $items['paypal_wpp'] = array(
     'name' => t('PayPal website payments pro'),
-    'payment method' => 'paypal_wpp',
+    'payment method' => 'credit',
     'fee handler' => 'paypal_wpp',
-    'module' => 'UC recurring',
-    'renew' => 'uc_recurring_paypal_wpp_renew',
-    'process' => 'uc_recurring_paypal_wpp_process',
+    'module' => 'uc_recurring',
+    'renew callback' => 'uc_recurring_paypal_wpp_renew',
+    'process callback' => 'uc_recurring_paypal_wpp_process',
+    'cancel callback' => 'uc_recurring_paypal_wpp_cancel',
+    'menu' => array(
+      'cancel' => array(
+        'title' => 'Cancel',
+        'page arguments' => array('uc_recurring_paypal_update_form'),
+        'file' => 'modules/uc_recurring.uc_paypal.inc',
+      ),
+    ),
   );
   return $items;
 }
@@ -45,17 +55,229 @@ function uc_recurring_paypal_wps_renew($order, $fee) {
 }
 
 /**
+ * Helper function; Get a recurring payments profile from PayPal.
+ *
+ * @param $rfid
+ *   The recurring fee ID.
+ * @return
+ *   FALSE on failure, otherwise, the NVP response from PayPal.
+ */
+function uc_recurring_paypal_get_profile($rfid) {
+  $fee = uc_recurring_fee_user_load($rfid);
+
+  // Build an NVP request.
+  $nvp_request = array(
+    'METHOD' => 'GetRecurringPaymentsProfileDetails',
+    'PROFILEID' => $fee->data['paypal'],
+  );
+
+  // Post the request, and parse the response.
+  $nvp_response = uc_paypal_api_request($nvp_request, variable_get('uc_paypal_wpp_server', 'https://api-3t.sandbox.paypal.com/nvp'), UC_PAYPAL_RECURRING_API);
+  if ($nvp_response['ACK'] != 'Success' && $nvp_response['ACK'] != 'SuccessWithWarning') {
+    return FALSE;
+  }
+
+  return $nvp_response;
+}
+
+/**
  * PayPal website payments pro process.
  */
-function uc_recurring_paypal_wpp_process($order, $fee) {
+function uc_recurring_paypal_wpp_process($order, &$fee) {
+  // Setup variables for the payment schedule.
+  list($length, $unit) = explode(' ', $fee->regular_interval);
+  list($trial_length, $trial_unit) = explode(' ', $fee->initial_charge);
+
+  // Make sure we have valid values.
+  if (
+    $length <= 0 ||
+    $unit == 'days' && $length > 365 ||
+    $unit == 'months' && $length > 12 ||
+    $unit == 'semimonths' && $length > 24 ||
+    $unit == 'weeks' && $length > 52 ||
+    $unit == 'years' && $length > 1
+  ) {
+    // Get a default SKU if none was supplied.
+    if (empty($fee->model)) {
+      $fee->model = db_result(db_query("SELECT model FROM {uc_products} WHERE nid = %d", $fee->nid));
+    }
+    watchdog('uc_recurring', 'Product @sku has invalid interval settings for PayPal - @length @unit', array('@sku' => $fee->model, '@length' => $length, '@unit' => $unit), WATCHDOG_ERROR);
+    return FALSE;
+  }
+ 
+  // 'weeks' => 'Week', etc. PayPal API allows billing period to be one of Day, Week, SemiMonth, or Year
+  if ($unit == 'semimonth') {
+    $unit='SemiMonth';
+  }
+  else {
+    $unit = ucfirst(substr($unit, 0, -1));
+  if ($trial_unit == 'semimonth') {
+    $trial_unit='SemiMonth';
+  }
+  else {
+    $trial_unit = ucfirst(substr($trial_unit, 0, -1));
+  }
+
+  $cc_type = '';
+  if (isset($order->payment_details['cc_type'])) {
+    switch (strtolower($order->payment_details['cc_type'])) {
+      case 'amex':
+      case 'american express':
+        $cc_type = 'Amex';
+        break;
+      case 'visa':
+        $cc_type = 'Visa';
+        break;
+      case 'mastercard':
+      case 'master card':
+        $cc_type = 'MasterCard';
+        break;
+      case 'discover':
+        $cc_type = 'Discover';
+        break;
+    }
+  }
+  if (empty($cc_type)) {
+    $cc_type = _uc_paypal_card_type($order->payment_details['cc_number']);
+    if ($cc_type === FALSE) {
+      drupal_set_message(t('The credit card type did not pass validation.'), 'error');
+      watchdog('uc_recurring', 'Could not figure out credit card type @type', array('@type' => $order->payment_details['cc_type']), WATCHDOG_ERROR);
+      return FALSE;
+    }
+  }
+  // Build an NVP request.
+  $nvp_request = array(
+    'METHOD' => 'CreateRecurringPaymentsProfile',
+    'DESC' => 'Order '. $order->order_id .' at '. check_plain(variable_get('uc_store_name', 'Ubercart')),
+    'PROFILESTARTDATE' => date(DATE_ATOM, strtotime('+ '. $fee->initial_charge)),
+
+    'CREDITCARDTYPE' => $cc_type,
+    'ACCT' => $order->payment_details['cc_number'],
+    'EXPDATE' => date('mY', mktime(0, 0, 0, $order->payment_details['cc_exp_month'], 1, $order->payment_details['cc_exp_year'])),
+    'FIRSTNAME' => check_plain($order->billing_first_name),
+    'LASTNAME' => check_plain($order->billing_last_name),
+
+    'BILLINGPERIOD' => $unit,
+    'BILLINGFREQUENCY' => $length,
+    'TOTALBILLINGCYCLES' => $fee->number_intervals,
+    'AMT' => round($fee->fee_amount, 2),
+
+    'NOTIFYURL' => url('uc_paypal/ipn/'. $order->order_id, array('absolute' => TRUE)),
+  );
+
+  // Only add trial if we have to wait to start payments. We make sure the trail
+  // length is bigger then 1, otherwise the first month will be charged 0$.
+  if (count($trial_length) > 1) {
+    $nvp_request['TRIALBILLINGPERIOD'] = $trial_unit;
+    $nvp_request['TRIALBILLINGFREQUENCY'] = $trial_length;
+    $nvp_request['TRIALTOTALBILLINGCYCLES'] = 1;
+    $nvp_request['TRIALAMT'] = 0;
+  }
+
+  if (variable_get('uc_credit_cvv_enabled', TRUE)) {
+    $nvp_request['CVV2'] = $order->payment_details['cc_cvv'];
+  }
+
+  // Post the request, and parse the response.
+  $nvp_response = uc_paypal_api_request($nvp_request, variable_get('uc_paypal_wpp_server', 'https://api-3t.sandbox.paypal.com/nvp'), UC_PAYPAL_RECURRING_API);
+  if ($nvp_response['ACK'] != 'Success' && $nvp_response['ACK'] != 'SuccessWithWarning') {
+    watchdog('uc_recurring', 'PayPal recurring fee for @model failed. @error - @text', array('@model' => $fee->fee_title, '@error' => $nvp_response['L_ERRORCODE0'], '@text' => $nvp_response['L_LONGMESSAGE']), WATCHDOG_ERROR);
+    return FALSE;
+  }
+
+  $fee->data['paypal'] = $nvp_response['PROFILEID'];
   return TRUE;
 }
 
 /**
  * PayPal website payments pro renew.
+ *
+ * Renew is triggered by Paypal, the only thing we do here, is capture the
+ * payment and update the fee object upon success or failure.
+ *
+ * @TODO: This can't be done now, as uc_paypal doesn't pass the payment 
+ * notification.
+ *
+ * @see uc_paypal_ipn().
  */
 function uc_recurring_paypal_wpp_renew($order, $fee) {
+
   return TRUE;
 }
 
+/**
+ * PayPal website payments pro renew.
+ */
+function uc_recurring_paypal_wpp_cancel($order, &$fee) {
+  global $user;
+  // Build an NVP request.
+  $nvp_request = array(
+    'METHOD' => 'ManageRecurringPaymentsProfileStatus',
+    'PROFILEID' => $fee->data['paypal'],
+    'ACTION' => 'Cancel',
+  );
+
+  // Post the request, and parse the response.
+  $nvp_response = uc_paypal_api_request($nvp_request, variable_get('uc_paypal_wpp_server', 'https://api-3t.sandbox.paypal.com/nvp'), UC_PAYPAL_RECURRING_API);
+  if ($nvp_response['ACK'] != 'Success' && $nvp_response['ACK'] != 'SuccessWithWarning') {
+    watchdog('uc_recurring', 'Failed to cancel recurring profile @id', array('@id' => $fee->data['paypal']), WATCHDOG_ERROR);
+    return FALSE;
+  }
+
+  uc_order_comment_save($order->order_id, $user->uid, t('PayPal recurring fee @id canceled.', array('@id' => $fee->data['paypal'])), 'admin');
+
+  return TRUE;
+}
+
+/**
+ * Updates a PayPal subscription; for simplicity's sake, Credit Card
+ * information except for expiration date cannot be updated at this time.
+ *
+ * @param $order
+ *   The order object.
+ * @param $fee
+ *   The recurring fee object.
+ * @param $updates
+ *   An array of data to update using key/ value pairs from the NVP API for
+ *   PayPal.
+ * @return
+ *   TRUE or FALSE indicating the success of the update.
+ */
+function uc_paypal_recurring_update($order, $fee, $updates = array()) {
+  global $user;
+  // Build an NVP request.
+  $nvp_request = array(
+    'METHOD' => 'UpdateRecurringPaymentsProfile',
+    'PROFILEID' => $fee->data['payapl'],
+  ) + $updates;
+
+  // Post the request, and parse the response.
+  $nvp_response = uc_paypal_api_request($nvp_request, variable_get('uc_paypal_wpp_server', 'https://api-3t.sandbox.paypal.com/nvp'), UC_PAYPAL_RECURRING_API);
+  if ($nvp_response['ACK'] != 'Success' && $nvp_response['ACK'] != 'SuccessWithWarning') {
+    watchdog('uc_recurring', 'Failed to update recurring profile @id', array('@id' => $fee->data['payapl']), WATCHDOG_ERROR);
+    return FALSE;
+  }
+
+  uc_order_comment_save($order->order_id, $user->uid, t('PayPal recurring fee @id updated.', array('@id' => $fee->data['payapl'])), 'admin');
+  return TRUE;
+}
+
+/**
+ * TODO: Form function to allow updating a Paypal profile.
+ *
+ * @param $rfid
+ *   The recurring fee ID passed the menu item.
+ */
+function uc_recurring_paypal_update_form($form_state, $rfid) {
+
+}
+
+/**
+ * Submit handler for the update Paypal profile form.
+ */
+function uc_recurring_paypal_update_form_submit($form, $form_state) {
+  // Here we will call uc_paypal_recurring_update()
+}
+
+
 
diff --git uc_recurring.module uc_recurring.module
index 38b3d85..579a9c7 100644
--- uc_recurring.module
+++ uc_recurring.module
@@ -226,6 +226,16 @@ function uc_recurring_recurring_info() {
 }
 
 /**
+ * Implementation of hook_form_alter().
+ */
+function uc_recurring_form_alter(&$form, $form_state) {
+  // Allow implementing modules to alter the form.
+  foreach (uc_recurring_get_recurring_info() as $handler => $value) {
+    uc_recurring_invoke($handler, 'hook_form_alter', array(&$form, $form_state));
+  }
+}
+
+/**
  * Submit handler for the processing recurring fee.
  */
 function uc_recurring_order_view_update_form_submit($form, &$form_state) {
@@ -314,7 +324,7 @@ function uc_recurring_order($op, &$arg1, $arg2) {
         uc_recurring_fee_cancel($fee->rfid, $fee);
         uc_recurring_fee_user_delete($rfid);
       }
-      break; 
+      break;
   }
 }
 
@@ -466,7 +476,7 @@ function uc_recurring_renew($fee) {
   $product->title = !empty($fee->fee_title) ? $fee->fee_title : t('Renewal of product @model', array('@model' => $product->model));
   $product->qty = 1;
   $product->price = $fee->fee_amount;
- 
+
   // initialize these items to remove warnings
   $product->cost = 0;
   $product->manufacturer = '';
@@ -804,7 +814,7 @@ function uc_recurring_get_all_fees() {
   $result = db_query("SELECT * FROM {uc_recurring_users}");
   while ($fee = db_fetch_object($result)) {
     $fees[$fee->rfid] = $fee;
-    $fee->data = unserialize($fee->data);    
+    $fee->data = unserialize($fee->data);
   }
   return $fees;
 }
@@ -1250,7 +1260,7 @@ function uc_recurring_set_intervals(&$fee) {
   $fee->next_charge = strtotime('+'. $fee->regular_interval);
   if ($fee->remaining_intervals > 0) {
     $fee->remaining_intervals--;
-  }  
+  }
   $fee->charged_intervals++;
   $fee->attempts = 0;
 }
