hey everyone, been working on integration for KISSmetrics following the KM SaaS adivces (http://support.kissmetrics.com/best-practices/saas-essentials), code is working fine but still needs development (esp for Upgraded/Downgrade events). Please keep in mind that I built this for my needs, so might not fit for everyone. It's based on assumption that you use recurring subscription, with trials. It includes registering signups, with email/username as aliases. Recording Billing/Upgrades/Downgrades/Cancels and changing alias if user updates email. Not a professional dev, so surely some optimisation to be done... Anyhow might be useful for some people so here it is... PHP: /***********************************************IMPORTANT REMEMBER TO DO "require km.php"BEFORE ACTIVATIONhttps://github.com/kissmetrics/KISSmetrics*************************************************/ class Am_Plugin_KISSmetrics extends Am_Plugin{ const PLUGIN_STATUS = self::STATUS_PRODUCTION; const PLUGIN_REVISION = '4.2.11'; protected $id; protected $done = false; public function __construct(Am_Di $di, array $config) { $this->id = $di->config->get('KISSmetrics_id'); parent::__construct($di, $config); } public function isConfigured() { return !empty($this->id); } function onSetupForms(Am_Event_SetupForms $forms) { $form = new Am_Form_Setup('KISSmetrics'); $form->setTitle("KISSmetrics"); $forms->addForm($form); $form->addText('KISSmetrics_id', array('size'=>50)) ->setLabel(array("KISSmetrics API")) ->addRule('required', 'This field is required'); // $form->addText('km_php_dir', array('size'=>50)) // ->setLabel(array("Directory of km.php")) // ->addRule('required', 'This field is required'); //$form->addText('km_log_dir', array('size'=>50)) // ->setLabel(array("Kissmetric logs directory")); //$form->addCheckbox('km_use_cron') // ->setLabel(array("Use cron ?<br>http://support.kissmetrics.com/apis/cron")); //$form->setDefault('km_log_dir', '/tmp'); } function init() { if($this->isConfigured()) { $KM_KEY = $this->getDi()->config->get('KISSmetrics_id'); //km initialize KM::init($KM_KEY, array()); } } // when user created (before payment) we send Signed Up for Free. function onSignupUserAdded(Am_Event $event) { $user = $event->getUser(); KM::identify($user->login); KM::record('Signed Up', array('Plan Name' => 'Free')); KM::alias($user->login, $user->email); } //everytime invoice is created function onInvoiceStarted(Am_Event_InvoiceStarted $event) { $invoice = $event->getInvoice(); $item = $invoice->getItem(0); // only get first item since site doesn't allow basket checkout $user = $event->getUser(); $has_paid = $user->isPaid(); // if invoice status RECURRING_ACTIVE ... may add event for PAID or PENDING if ($invoice->status == Invoice::RECURRING_ACTIVE ) { /* TO DO : should add comparison to see if user has a lower priced sub for now if user has paid before it will show as Downgraded */ if($has_paid == 0 ) { KM::identify($user->login); KM::record('Upgraded', array('Plan Name' => $item->item_title, 'InvoiceId' => $invoice->invoice_id )); } else{ KM::identify($user->login); KM::record('Downgraded', array('Plan Name' => $item->item_title, 'InvoiceId' => $invoice->invoice_id )); } } } //everytime payment is made, we call Billed function onPaymentAfterInsert(Am_Event $event) { $invoice = $event->getInvoice(); $payment = $event->getPayment(); $item = $invoice->getItem(0); $user = $event->getUser(); // check recurence of payments... using second_payment since I work with trials if ($invoice->second_period == '30d' || $invoice->second_period =='1m') $frequency = 'Monthly'; elseif ($invoice->second_period == '90d' || $invoice->second_period =='3m') $frequency = 'Quarterly'; elseif ($invoice->second_period == '7d' || $invoice->second_period =='1w') $frequency = 'Weekly'; KM::identify($user->login); KM::record('Billed', array( 'Billing Amount' => $payment->amount, 'Billing Description' => $frequency, 'Invoice#' => $payment->invoice_id )); } // change alias if user updates email function onUserAfterUpdate(Am_Event_UserAfterUpdate $event) { $user = $event->getUser(); $newEmail = $user->get('email'); $oldEmail = $event->getOldUser()->get('email'); if ($newEmail != $oldEmail) KM::alias($user->login, $newEmail); } // if recurring canceled function onInvoiceStatusChange(Am_Event_InvoiceStatusChange $event) { /* [invoice statuses] Invoice::PENDING = 0; // pending, not processed yet - initial status Invoice::PAID = 1; // paid and not-recurring Invoice::RECURRING_ACTIVE=2; // active recurring - there will be rebills, access open Invoice::RECURRING_CANCELLED=3; // recurring cancelled, access is open until paid Invoice::RECURRING_FAILED=4; // rebilling failed, access is closed Invoice::RECURRING_FINISHED=5; // rebilling finished, no access anymore Invoice::CHARGEBACK=7; // chargeback processed, no access Invoice::NOT_CONFIRMED = 8; */ $invoice = $event->getInvoice(); $username = Am_Di::getInstance()->db->selectCell("SELECT login FROM ?_user WHERE user_id=?d", $invoice->user_id); if ($invoice->status == Invoice::RECURRING_CANCELLED || $invoice->status == Invoice::RECURRING_FAILED || $invoice->status == Invoice::RECURRING_FINISHED) { if($invoice->isPaid()) { KM::identify($username); KM::record('Canceled'); } else { KM::identify($username); KM::record('Trial Ended'); } } }}