killbill-aplcache

Changes

Details

diff --git a/api/src/main/java/com/ning/billing/subscription/api/migration/SubscriptionBaseMigrationApi.java b/api/src/main/java/com/ning/billing/subscription/api/migration/SubscriptionBaseMigrationApi.java
new file mode 100644
index 0000000..68cc33f
--- /dev/null
+++ b/api/src/main/java/com/ning/billing/subscription/api/migration/SubscriptionBaseMigrationApi.java
@@ -0,0 +1,133 @@
+/*
+ * Copyright 2010-2013 Ning, Inc.
+ *
+ * Ning licenses this file to you under the Apache License, version 2.0
+ * (the "License"); you may not use this file except in compliance with the
+ * License.  You may obtain a copy of the License at:
+ *
+ *    http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
+ * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.  See the
+ * License for the specific language governing permissions and limitations
+ * under the License.
+ */
+
+package com.ning.billing.subscription.api.migration;
+
+import java.util.UUID;
+
+import org.joda.time.DateTime;
+
+import com.ning.billing.catalog.api.PlanPhaseSpecifier;
+import com.ning.billing.catalog.api.ProductCategory;
+import com.ning.billing.util.callcontext.CallContext;
+
+/**
+ * The interface {@code SubscriptionBaseMigrationApi} is used to migrate subscription data from third party system
+ * in an atomic way.
+ */
+public interface SubscriptionBaseMigrationApi {
+
+
+    /**
+     * The interface {@code AccountMigration} captures all the {@code SubscriptionBaseBundle} associated with
+     * that account.
+     */
+    public interface AccountMigration {
+
+        /**
+         *
+         * @return the unique id for the account
+         */
+        public UUID getAccountKey();
+
+        /**
+         *
+         * @return an array of {@code BundleMigration}
+         */
+        public BundleMigration[] getBundles();
+    }
+
+    /**
+     * The interface {@code BundleMigration} captures all the {@code SubscriptionBase} asociated with a given
+     * {@code SubscriptionBaseBundle}
+     */
+    public interface BundleMigration {
+
+        /**
+         *
+         * @return the bundle external key
+         */
+        public String getBundleKey();
+
+        /**
+         *
+         * @return an array of {@code SubscriptionBase}
+         */
+        public SubscriptionMigration[] getSubscriptions();
+    }
+
+    /**
+     * The interface {@code SubscriptionMigration} captures the detail for each {@code SubscriptionBase} to be
+     * migrated.
+     */
+    public interface SubscriptionMigration {
+
+        /**
+         *
+         * @return the {@code ProductCategory}
+         */
+        public ProductCategory getCategory();
+
+        /**
+         *
+         * @return the chargeTroughDate for that {@code SubscriptionBase}
+         */
+        public DateTime getChargedThroughDate();
+
+        /**
+         *
+         * @return the various phase information for that {@code SubscriptionBase}
+         */
+        public SubscriptionMigrationCase[] getSubscriptionCases();
+    }
+
+    /**
+     * The interface {@code SubscriptionMigrationCase} captures the details of
+     * phase for a {@code SubscriptionBase}.
+     *
+     */
+    public interface SubscriptionMigrationCase {
+        /**
+         *
+         * @return the {@code PlanPhaseSpecifier}
+         */
+        public PlanPhaseSpecifier getPlanPhaseSpecifier();
+
+        /**
+         *
+         * @return the date at which this phase starts.
+         */
+        public DateTime getEffectiveDate();
+
+        /**
+         *
+         * @return the date at which this phase is stopped.
+         */
+        public DateTime getCancelledDate();
+    }
+
+
+    /**
+     * Migrate all the existing entitlements associated with that account.
+     * The semantics is 'all or nothing' (atomic operation)
+     *
+     * @param toBeMigrated all the bundles and associated SubscriptionBase that should be migrated for the account
+     * @throws SubscriptionBaseMigrationApiException
+     *          an subscription api exception
+     */
+    public void migrate(AccountMigration toBeMigrated, CallContext context)
+            throws SubscriptionBaseMigrationApiException;
+}
diff --git a/api/src/main/java/com/ning/billing/subscription/api/migration/SubscriptionBaseMigrationApiException.java b/api/src/main/java/com/ning/billing/subscription/api/migration/SubscriptionBaseMigrationApiException.java
new file mode 100644
index 0000000..df9814b
--- /dev/null
+++ b/api/src/main/java/com/ning/billing/subscription/api/migration/SubscriptionBaseMigrationApiException.java
@@ -0,0 +1,38 @@
+/*
+ * Copyright 2010-2013 Ning, Inc.
+ *
+ * Ning licenses this file to you under the Apache License, version 2.0
+ * (the "License"); you may not use this file except in compliance with the
+ * License.  You may obtain a copy of the License at:
+ *
+ *    http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
+ * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.  See the
+ * License for the specific language governing permissions and limitations
+ * under the License.
+ */
+
+package com.ning.billing.subscription.api.migration;
+
+public class SubscriptionBaseMigrationApiException extends Exception {
+
+    private static final long serialVersionUID = 7623133L;
+
+    public SubscriptionBaseMigrationApiException() {
+        super();
+    }
+
+    public SubscriptionBaseMigrationApiException(final String message, final Throwable cause) {
+        super(message, cause);
+    }
+
+    public SubscriptionBaseMigrationApiException(final String message) {
+        super(message);
+    }
+
+    public SubscriptionBaseMigrationApiException(final Throwable cause) {
+        super(cause);
+    }
+}
diff --git a/api/src/main/java/com/ning/billing/subscription/api/timeline/SubscriptionBaseRepairException.java b/api/src/main/java/com/ning/billing/subscription/api/timeline/SubscriptionBaseRepairException.java
new file mode 100644
index 0000000..30aa3e7
--- /dev/null
+++ b/api/src/main/java/com/ning/billing/subscription/api/timeline/SubscriptionBaseRepairException.java
@@ -0,0 +1,43 @@
+/*
+ * Copyright 2010-2013 Ning, Inc.
+ *
+ * Ning licenses this file to you under the Apache License, version 2.0
+ * (the "License"); you may not use this file except in compliance with the
+ * License.  You may obtain a copy of the License at:
+ *
+ *    http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
+ * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.  See the
+ * License for the specific language governing permissions and limitations
+ * under the License.
+ */
+
+package com.ning.billing.subscription.api.timeline;
+
+import com.ning.billing.BillingExceptionBase;
+import com.ning.billing.ErrorCode;
+import com.ning.billing.catalog.api.CatalogApiException;
+import com.ning.billing.subscription.api.user.SubscriptionBaseApiException;
+
+public class SubscriptionBaseRepairException extends BillingExceptionBase {
+
+    private static final long serialVersionUID = 19067233L;
+
+    public SubscriptionBaseRepairException(final SubscriptionBaseApiException e) {
+        super(e, e.getCode(), e.getMessage());
+    }
+
+    public SubscriptionBaseRepairException(final CatalogApiException e) {
+        super(e, e.getCode(), e.getMessage());
+    }
+
+    public SubscriptionBaseRepairException(final Throwable e, final ErrorCode code, final Object... args) {
+        super(e, code, args);
+    }
+
+    public SubscriptionBaseRepairException(final ErrorCode code, final Object... args) {
+        super(code, args);
+    }
+}
diff --git a/api/src/main/java/com/ning/billing/subscription/api/timeline/SubscriptionBaseTimelineApi.java b/api/src/main/java/com/ning/billing/subscription/api/timeline/SubscriptionBaseTimelineApi.java
new file mode 100644
index 0000000..b628417
--- /dev/null
+++ b/api/src/main/java/com/ning/billing/subscription/api/timeline/SubscriptionBaseTimelineApi.java
@@ -0,0 +1,38 @@
+/*
+ * Copyright 2010-2013 Ning, Inc.
+ *
+ * Ning licenses this file to you under the Apache License, version 2.0
+ * (the "License"); you may not use this file except in compliance with the
+ * License.  You may obtain a copy of the License at:
+ *
+ *    http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
+ * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.  See the
+ * License for the specific language governing permissions and limitations
+ * under the License.
+ */
+
+package com.ning.billing.subscription.api.timeline;
+
+import java.util.UUID;
+
+import com.ning.billing.subscription.api.user.SubscriptionBaseBundle;
+import com.ning.billing.util.callcontext.CallContext;
+import com.ning.billing.util.callcontext.TenantContext;
+
+public interface SubscriptionBaseTimelineApi {
+
+    public BundleBaseTimeline getBundleTimeline(SubscriptionBaseBundle bundle, TenantContext context)
+            throws SubscriptionBaseRepairException;
+
+    public BundleBaseTimeline getBundleTimeline(UUID accountId, String bundleName, TenantContext context)
+            throws SubscriptionBaseRepairException;
+
+    public BundleBaseTimeline getBundleTimeline(UUID bundleId, TenantContext context)
+            throws SubscriptionBaseRepairException;
+
+    public BundleBaseTimeline repairBundle(BundleBaseTimeline input, boolean dryRun, CallContext context)
+            throws SubscriptionBaseRepairException;
+}
diff --git a/api/src/main/java/com/ning/billing/subscription/api/timeline/SubscriptionTimelineApi.java b/api/src/main/java/com/ning/billing/subscription/api/timeline/SubscriptionTimelineApi.java
index 4a4ce75..6108421 100644
--- a/api/src/main/java/com/ning/billing/subscription/api/timeline/SubscriptionTimelineApi.java
+++ b/api/src/main/java/com/ning/billing/subscription/api/timeline/SubscriptionTimelineApi.java
@@ -24,15 +24,15 @@ import com.ning.billing.util.callcontext.TenantContext;
 
 public interface SubscriptionTimelineApi {
 
-    public BundleTimeline getBundleTimeline(SubscriptionBaseBundle bundle, TenantContext context)
+    public BundleBaseTimeline getBundleTimeline(SubscriptionBaseBundle bundle, TenantContext context)
             throws SubscriptionRepairException;
 
-    public BundleTimeline getBundleTimeline(UUID accountId, String bundleName, TenantContext context)
+    public BundleBaseTimeline getBundleTimeline(UUID accountId, String bundleName, TenantContext context)
             throws SubscriptionRepairException;
 
-    public BundleTimeline getBundleTimeline(UUID bundleId, TenantContext context)
+    public BundleBaseTimeline getBundleTimeline(UUID bundleId, TenantContext context)
             throws SubscriptionRepairException;
 
-    public BundleTimeline repairBundle(BundleTimeline input, boolean dryRun, CallContext context)
+    public BundleBaseTimeline repairBundle(BundleBaseTimeline input, boolean dryRun, CallContext context)
             throws SubscriptionRepairException;
 }
diff --git a/api/src/main/java/com/ning/billing/subscription/api/transfer/SubscriptionBaseTransferApi.java b/api/src/main/java/com/ning/billing/subscription/api/transfer/SubscriptionBaseTransferApi.java
new file mode 100644
index 0000000..dc439f7
--- /dev/null
+++ b/api/src/main/java/com/ning/billing/subscription/api/transfer/SubscriptionBaseTransferApi.java
@@ -0,0 +1,46 @@
+/*
+ * Copyright 2010-2013 Ning, Inc.
+ *
+ * Ning licenses this file to you under the Apache License, version 2.0
+ * (the "License"); you may not use this file except in compliance with the
+ * License.  You may obtain a copy of the License at:
+ *
+ *    http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
+ * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.  See the
+ * License for the specific language governing permissions and limitations
+ * under the License.
+ */
+
+package com.ning.billing.subscription.api.transfer;
+
+import java.util.UUID;
+
+import org.joda.time.DateTime;
+
+import com.ning.billing.subscription.api.user.SubscriptionBaseBundle;
+import com.ning.billing.util.callcontext.CallContext;
+
+/**
+ * The interface {@code SubscriptionBaseTransferApi} is used to transfer a bundle from one account to another account.
+ */
+public interface SubscriptionBaseTransferApi {
+
+    /**
+     * @param sourceAccountId   the unique id for the account on which the bundle will be transferred from
+     * @param destAccountId     the unique id for the account on which the bundle will be transferred to
+     * @param bundleKey         the externalKey for the bundle
+     * @param requestedDate     the date at which this transfer should occur
+     * @param transferAddOn     whether or not we should also transfer ADD_ON subscriptions existing on that {@code SubscriptionBaseBundle}
+     * @param cancelImmediately whether cancellation on the sourceAccount occurs immediately
+     * @param context           the user context
+     * @return the newly created {@code SubscriptionBaseBundle}
+     * @throws SubscriptionBaseTransferApiException
+     *          if the system could not transfer the {@code SubscriptionBaseBundle}
+     */
+    public SubscriptionBaseBundle transferBundle(final UUID sourceAccountId, final UUID destAccountId, final String bundleKey, final DateTime requestedDate,
+                                             final boolean transferAddOn, final boolean cancelImmediately, final CallContext context)
+            throws SubscriptionBaseTransferApiException;
+}
diff --git a/api/src/main/java/com/ning/billing/subscription/api/transfer/SubscriptionBaseTransferApiException.java b/api/src/main/java/com/ning/billing/subscription/api/transfer/SubscriptionBaseTransferApiException.java
new file mode 100644
index 0000000..86e2e78
--- /dev/null
+++ b/api/src/main/java/com/ning/billing/subscription/api/transfer/SubscriptionBaseTransferApiException.java
@@ -0,0 +1,47 @@
+/*
+ * Copyright 2010-2013 Ning, Inc.
+ *
+ * Ning licenses this file to you under the Apache License, version 2.0
+ * (the "License"); you may not use this file except in compliance with the
+ * License.  You may obtain a copy of the License at:
+ *
+ *    http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
+ * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.  See the
+ * License for the specific language governing permissions and limitations
+ * under the License.
+ */
+
+package com.ning.billing.subscription.api.transfer;
+
+import com.ning.billing.BillingExceptionBase;
+import com.ning.billing.ErrorCode;
+import com.ning.billing.catalog.api.CatalogApiException;
+import com.ning.billing.subscription.api.timeline.SubscriptionBaseRepairException;
+
+public class SubscriptionBaseTransferApiException extends BillingExceptionBase {
+
+    private static final long serialVersionUID = 17086131L;
+
+    public SubscriptionBaseTransferApiException(final CatalogApiException e) {
+        super(e, e.getCode(), e.getMessage());
+    }
+
+    public SubscriptionBaseTransferApiException(final SubscriptionBaseRepairException e) {
+        super(e, e.getCode(), e.getMessage());
+    }
+
+    public SubscriptionBaseTransferApiException(final Throwable e, final ErrorCode code, final Object... args) {
+        super(e, code, args);
+    }
+
+    public SubscriptionBaseTransferApiException(final Throwable e, final int code, final String message) {
+        super(e, code, message);
+    }
+
+    public SubscriptionBaseTransferApiException(final ErrorCode code, final Object... args) {
+        super(code, args);
+    }
+}
diff --git a/beatrix/src/test/java/com/ning/billing/beatrix/integration/BeatrixIntegrationModule.java b/beatrix/src/test/java/com/ning/billing/beatrix/integration/BeatrixIntegrationModule.java
index 9fe2a7d..8ccbd3d 100644
--- a/beatrix/src/test/java/com/ning/billing/beatrix/integration/BeatrixIntegrationModule.java
+++ b/beatrix/src/test/java/com/ning/billing/beatrix/integration/BeatrixIntegrationModule.java
@@ -39,7 +39,7 @@ import com.ning.billing.beatrix.util.PaymentChecker;
 import com.ning.billing.beatrix.util.RefundChecker;
 import com.ning.billing.catalog.api.CatalogService;
 import com.ning.billing.catalog.glue.CatalogModule;
-import com.ning.billing.subscription.api.SubscriptionService;
+import com.ning.billing.subscription.api.SubscriptionBaseService;
 import com.ning.billing.invoice.api.InvoiceService;
 import com.ning.billing.invoice.generator.DefaultInvoiceGeneratorWithSwitchRepairLogic;
 import com.ning.billing.invoice.generator.InvoiceGenerator;
@@ -182,7 +182,7 @@ public class BeatrixIntegrationModule extends AbstractModule {
                     .add(injector.getInstance(AccountService.class))
                     .add(injector.getInstance(BusService.class))
                     .add(injector.getInstance(CatalogService.class))
-                    .add(injector.getInstance(SubscriptionService.class))
+                    .add(injector.getInstance(SubscriptionBaseService.class))
                     .add(injector.getInstance(InvoiceService.class))
                     .add(injector.getInstance(PaymentService.class))
                     .add(injector.getInstance(OverdueService.class))
diff --git a/beatrix/src/test/java/com/ning/billing/beatrix/integration/TestIntegrationBase.java b/beatrix/src/test/java/com/ning/billing/beatrix/integration/TestIntegrationBase.java
index af82735..e742541 100644
--- a/beatrix/src/test/java/com/ning/billing/beatrix/integration/TestIntegrationBase.java
+++ b/beatrix/src/test/java/com/ning/billing/beatrix/integration/TestIntegrationBase.java
@@ -82,7 +82,7 @@ import com.ning.billing.payment.api.PaymentMethodPlugin;
 import com.ning.billing.payment.api.TestPaymentMethodPluginBase;
 import com.ning.billing.payment.provider.MockPaymentProviderPlugin;
 import com.ning.billing.subscription.api.SubscriptionBase;
-import com.ning.billing.subscription.api.SubscriptionService;
+import com.ning.billing.subscription.api.SubscriptionBaseService;
 import com.ning.billing.subscription.api.timeline.SubscriptionTimelineApi;
 import com.ning.billing.subscription.api.transfer.SubscriptionTransferApi;
 import com.ning.billing.subscription.api.user.SubscriptionData;
@@ -129,7 +129,7 @@ public class TestIntegrationBase extends BeatrixTestSuiteWithEmbeddedDB implemen
     protected BusService busService;
 
     @Inject
-    protected SubscriptionService subscriptionService;
+    protected SubscriptionBaseService subscriptionBaseService;
 
     @Inject
     protected InvoiceService invoiceService;
diff --git a/beatrix/src/test/java/com/ning/billing/beatrix/integration/TestRepairIntegration.java b/beatrix/src/test/java/com/ning/billing/beatrix/integration/TestRepairIntegration.java
index 55f2c3a..000aa39 100644
--- a/beatrix/src/test/java/com/ning/billing/beatrix/integration/TestRepairIntegration.java
+++ b/beatrix/src/test/java/com/ning/billing/beatrix/integration/TestRepairIntegration.java
@@ -36,13 +36,13 @@ import com.ning.billing.catalog.api.PriceListSet;
 import com.ning.billing.catalog.api.ProductCategory;
 import com.ning.billing.entitlement.api.DefaultEntitlement;
 import com.ning.billing.subscription.api.SubscriptionBaseTransitionType;
+import com.ning.billing.subscription.api.timeline.BundleBaseTimeline;
+import com.ning.billing.subscription.api.timeline.SubscriptionBaseTimeline;
 import com.ning.billing.subscription.api.user.SubscriptionData;
 import com.ning.billing.subscription.api.user.SubscriptionEvents;
-import com.ning.billing.subscription.api.timeline.BundleTimeline;
-import com.ning.billing.subscription.api.timeline.SubscriptionTimeline;
-import com.ning.billing.subscription.api.timeline.SubscriptionTimeline.DeletedEvent;
-import com.ning.billing.subscription.api.timeline.SubscriptionTimeline.ExistingEvent;
-import com.ning.billing.subscription.api.timeline.SubscriptionTimeline.NewEvent;
+import com.ning.billing.subscription.api.timeline.SubscriptionBaseTimeline.DeletedEvent;
+import com.ning.billing.subscription.api.timeline.SubscriptionBaseTimeline.ExistingEvent;
+import com.ning.billing.subscription.api.timeline.SubscriptionBaseTimeline.NewEvent;
 import com.ning.billing.subscription.api.user.SubscriptionState;
 
 import static org.testng.Assert.assertEquals;
@@ -101,22 +101,22 @@ public class TestRepairIntegration extends TestIntegrationBase {
         }
         final boolean ifRepair = false;
         if (ifRepair) {
-            BundleTimeline bundleRepair = repairApi.getBundleTimeline(bpEntitlement.getSubscriptionBase().getBundleId(), callContext);
+            BundleBaseTimeline bundleRepair = repairApi.getBundleTimeline(bpEntitlement.getSubscriptionBase().getBundleId(), callContext);
             sortEventsOnBundle(bundleRepair);
 
             // Quick check
-            SubscriptionTimeline bpRepair = getSubscriptionRepair(bpEntitlement.getId(), bundleRepair);
+            SubscriptionBaseTimeline bpRepair = getSubscriptionRepair(bpEntitlement.getId(), bundleRepair);
             assertEquals(bpRepair.getExistingEvents().size(), 2);
 
-            final SubscriptionTimeline aoRepair = getSubscriptionRepair(aoEntitlement1.getId(), bundleRepair);
+            final SubscriptionBaseTimeline aoRepair = getSubscriptionRepair(aoEntitlement1.getId(), bundleRepair);
             assertEquals(aoRepair.getExistingEvents().size(), 2);
 
-            final SubscriptionTimeline aoRepair2 = getSubscriptionRepair(aoEntitlement2.getId(), bundleRepair);
+            final SubscriptionBaseTimeline aoRepair2 = getSubscriptionRepair(aoEntitlement2.getId(), bundleRepair);
             assertEquals(aoRepair2.getExistingEvents().size(), 2);
 
             final DateTime bpChangeDate = clock.getUTCNow().minusDays(1);
 
-            final List<DeletedEvent> des = new LinkedList<SubscriptionTimeline.DeletedEvent>();
+            final List<DeletedEvent> des = new LinkedList<SubscriptionBaseTimeline.DeletedEvent>();
             des.add(createDeletedEvent(bpRepair.getExistingEvents().get(1).getEventId()));
 
             final PlanPhaseSpecifier spec = new PlanPhaseSpecifier("Assault-Rifle", ProductCategory.BASE, BillingPeriod.MONTHLY, PriceListSet.DEFAULT_PRICELIST_NAME, PhaseType.TRIAL);
@@ -154,8 +154,8 @@ public class TestRepairIntegration extends TestIntegrationBase {
         }
     }
 
-    protected SubscriptionTimeline createSubscriptionReapir(final UUID id, final List<DeletedEvent> deletedEvents, final List<NewEvent> newEvents) {
-        return new SubscriptionTimeline() {
+    protected SubscriptionBaseTimeline createSubscriptionReapir(final UUID id, final List<DeletedEvent> deletedEvents, final List<NewEvent> newEvents) {
+        return new SubscriptionBaseTimeline() {
             @Override
             public UUID getId() {
                 return id;
@@ -194,15 +194,15 @@ public class TestRepairIntegration extends TestIntegrationBase {
     }
 
 
-    protected BundleTimeline createBundleRepair(final UUID bundleId, final String viewId, final List<SubscriptionTimeline> subscriptionRepair) {
-        return new BundleTimeline() {
+    protected BundleBaseTimeline createBundleRepair(final UUID bundleId, final String viewId, final List<SubscriptionBaseTimeline> subscriptionRepair) {
+        return new BundleBaseTimeline() {
             @Override
             public String getViewId() {
                 return viewId;
             }
 
             @Override
-            public List<SubscriptionTimeline> getSubscriptions() {
+            public List<SubscriptionBaseTimeline> getSubscriptions() {
                 return subscriptionRepair;
             }
 
@@ -267,8 +267,8 @@ public class TestRepairIntegration extends TestIntegrationBase {
         return ev;
     }
 
-    protected SubscriptionTimeline getSubscriptionRepair(final UUID id, final BundleTimeline bundleRepair) {
-        for (final SubscriptionTimeline cur : bundleRepair.getSubscriptions()) {
+    protected SubscriptionBaseTimeline getSubscriptionRepair(final UUID id, final BundleBaseTimeline bundleRepair) {
+        for (final SubscriptionBaseTimeline cur : bundleRepair.getSubscriptions()) {
             if (cur.getId().equals(id)) {
                 return cur;
             }
@@ -322,11 +322,11 @@ public class TestRepairIntegration extends TestIntegrationBase {
         };
     }
 
-    protected void sortEventsOnBundle(final BundleTimeline bundle) {
+    protected void sortEventsOnBundle(final BundleBaseTimeline bundle) {
         if (bundle.getSubscriptions() == null) {
             return;
         }
-        for (final SubscriptionTimeline cur : bundle.getSubscriptions()) {
+        for (final SubscriptionBaseTimeline cur : bundle.getSubscriptions()) {
             if (cur.getExistingEvents() != null) {
                 sortExistingEvent(cur.getExistingEvents());
             }
diff --git a/jaxrs/src/main/java/com/ning/billing/jaxrs/json/AccountTimelineJson.java b/jaxrs/src/main/java/com/ning/billing/jaxrs/json/AccountTimelineJson.java
index 05c36a9..9f5269f 100644
--- a/jaxrs/src/main/java/com/ning/billing/jaxrs/json/AccountTimelineJson.java
+++ b/jaxrs/src/main/java/com/ning/billing/jaxrs/json/AccountTimelineJson.java
@@ -33,7 +33,7 @@ import com.ning.billing.invoice.api.InvoiceItemType;
 import com.ning.billing.invoice.api.InvoicePayment;
 import com.ning.billing.payment.api.Payment;
 import com.ning.billing.payment.api.Refund;
-import com.ning.billing.subscription.api.timeline.BundleTimeline;
+import com.ning.billing.subscription.api.timeline.BundleBaseTimeline;
 import com.ning.billing.util.audit.AuditLog;
 import com.ning.billing.util.audit.AuditLogsForBundles;
 import com.ning.billing.util.audit.AuditLogsForInvoicePayments;
@@ -64,7 +64,7 @@ public class AccountTimelineJson {
         this.payments = payments;
     }
 
-    private String getBundleExternalKey(final UUID invoiceId, final List<Invoice> invoices, final List<BundleTimeline> bundles) {
+    private String getBundleExternalKey(final UUID invoiceId, final List<Invoice> invoices, final List<BundleBaseTimeline> bundles) {
         for (final Invoice cur : invoices) {
             if (cur.getId().equals(invoiceId)) {
                 return getBundleExternalKey(cur, bundles);
@@ -73,7 +73,7 @@ public class AccountTimelineJson {
         return null;
     }
 
-    private String getBundleExternalKey(final Invoice invoice, final List<BundleTimeline> bundles) {
+    private String getBundleExternalKey(final Invoice invoice, final List<BundleBaseTimeline> bundles) {
         final Set<UUID> b = new HashSet<UUID>();
         for (final InvoiceItem cur : invoice.getInvoiceItems()) {
             b.add(cur.getBundleId());
@@ -81,7 +81,7 @@ public class AccountTimelineJson {
         boolean first = true;
         final StringBuilder tmp = new StringBuilder();
         for (final UUID cur : b) {
-            for (final BundleTimeline bt : bundles) {
+            for (final BundleBaseTimeline bt : bundles) {
                 if (bt.getId().equals(cur)) {
                     if (!first) {
                         tmp.append(",");
@@ -96,7 +96,7 @@ public class AccountTimelineJson {
     }
 
     public AccountTimelineJson(final Account account, final List<Invoice> invoices, final List<Payment> payments,
-                               final List<BundleTimeline> bundlesTimeline, final Multimap<UUID, Refund> refundsByPayment,
+                               final List<BundleBaseTimeline> bundlesTimeline, final Multimap<UUID, Refund> refundsByPayment,
                                final Multimap<UUID, InvoicePayment> chargebacksByPayment, @Nullable final AuditLogsForInvoices invoicesAuditLogs,
                                @Nullable final AuditLogsForPayments paymentsAuditLogs, @Nullable final AuditLogsForRefunds refundsAuditLogs,
                                @Nullable final AuditLogsForInvoicePayments chargebacksAuditLogs, @Nullable final AuditLogsForBundles bundlesAuditLogs) {
@@ -111,7 +111,7 @@ public class AccountTimelineJson {
              bundlesAuditLogs == null ? ImmutableMap.<UUID, List<AuditLog>>of() : bundlesAuditLogs.getSubscriptionEventsAuditLogs());
     }
 
-    public AccountTimelineJson(final Account account, final List<Invoice> invoices, final List<Payment> payments, final List<BundleTimeline> bundles,
+    public AccountTimelineJson(final Account account, final List<Invoice> invoices, final List<Payment> payments, final List<BundleBaseTimeline> bundles,
                                final Multimap<UUID, Refund> refundsByPayment, final Multimap<UUID, InvoicePayment> chargebacksByPayment,
                                final Map<UUID, List<AuditLog>> invoiceAuditLogs, final Map<UUID, List<AuditLog>> invoiceItemsAuditLogs,
                                final Map<UUID, List<AuditLog>> paymentsAuditLogs, final Map<UUID, List<AuditLog>> refundsAuditLogs,
@@ -119,7 +119,7 @@ public class AccountTimelineJson {
                                final Map<UUID, List<AuditLog>> subscriptionsAuditLogs, final Map<UUID, List<AuditLog>> subscriptionEventsAuditLogs) {
         this.account = new AccountJsonSimple(account.getId().toString(), account.getExternalKey());
         this.bundles = new LinkedList<BundleJsonWithSubscriptions>();
-        for (final BundleTimeline bundle : bundles) {
+        for (final BundleBaseTimeline bundle : bundles) {
             final List<AuditLog> bundleAuditLogs = bundlesAuditLogs.get(bundle.getId());
             final BundleJsonWithSubscriptions jsonWithSubscriptions = new BundleJsonWithSubscriptions(bundle, bundleAuditLogs,
                                                                                                       subscriptionsAuditLogs, subscriptionEventsAuditLogs);
diff --git a/jaxrs/src/main/java/com/ning/billing/jaxrs/json/BundleJsonWithSubscriptions.java b/jaxrs/src/main/java/com/ning/billing/jaxrs/json/BundleJsonWithSubscriptions.java
index ac4e383..6bf5e1e 100644
--- a/jaxrs/src/main/java/com/ning/billing/jaxrs/json/BundleJsonWithSubscriptions.java
+++ b/jaxrs/src/main/java/com/ning/billing/jaxrs/json/BundleJsonWithSubscriptions.java
@@ -23,8 +23,8 @@ import java.util.UUID;
 
 import javax.annotation.Nullable;
 
-import com.ning.billing.subscription.api.timeline.BundleTimeline;
-import com.ning.billing.subscription.api.timeline.SubscriptionTimeline;
+import com.ning.billing.subscription.api.timeline.BundleBaseTimeline;
+import com.ning.billing.subscription.api.timeline.SubscriptionBaseTimeline;
 import com.ning.billing.util.audit.AuditLog;
 
 import com.fasterxml.jackson.annotation.JsonCreator;
@@ -48,11 +48,11 @@ public class BundleJsonWithSubscriptions extends BundleJsonSimple {
         return subscriptions;
     }
 
-    public BundleJsonWithSubscriptions(final BundleTimeline bundle, final List<AuditLog> auditLogs,
+    public BundleJsonWithSubscriptions(final BundleBaseTimeline bundle, final List<AuditLog> auditLogs,
                                        final Map<UUID, List<AuditLog>> subscriptionsAuditLogs, final Map<UUID, List<AuditLog>> subscriptionEventsAuditLogs) {
         super(bundle.getId(), bundle.getExternalKey(), auditLogs);
         this.subscriptions = new LinkedList<EntitlementJsonWithEvents>();
-        for (final SubscriptionTimeline subscriptionTimeline : bundle.getSubscriptions()) {
+        for (final SubscriptionBaseTimeline subscriptionTimeline : bundle.getSubscriptions()) {
             // STEPH_ENT
             /*
             this.subscriptions.add(new EntitlementJsonWithEvents(bundle.getId(), subscriptionTimeline,
diff --git a/jaxrs/src/main/java/com/ning/billing/jaxrs/json/EntitlementJsonWithEvents.java b/jaxrs/src/main/java/com/ning/billing/jaxrs/json/EntitlementJsonWithEvents.java
index 59251b9..0b5ea1d 100644
--- a/jaxrs/src/main/java/com/ning/billing/jaxrs/json/EntitlementJsonWithEvents.java
+++ b/jaxrs/src/main/java/com/ning/billing/jaxrs/json/EntitlementJsonWithEvents.java
@@ -283,7 +283,7 @@ public class EntitlementJsonWithEvents extends EntitlementJsonSimple {
         this(data.getId().toString(), events, newEvents, deletedEvents, toAuditLogJson(auditLogs));
     }
 
-    public EntitlementJsonWithEvents(final UUID accountId, final UUID bundleId, final UUID entitlementId, final SubscriptionTimeline input,
+    public EntitlementJsonWithEvents(final UUID accountId, final UUID bundleId, final UUID entitlementId, final SubscriptionBaseTimeline input,
                                       final List<AuditLog> bundleAuditLogs, final Map<UUID, List<AuditLog>> subscriptionEventsAuditLogs) {
         super(input. input.getId().toString(), toAuditLogJson(bundleAuditLogs));
 
diff --git a/jaxrs/src/main/java/com/ning/billing/jaxrs/mappers/SubscriptionRepairExceptionMapper.java b/jaxrs/src/main/java/com/ning/billing/jaxrs/mappers/SubscriptionRepairExceptionMapper.java
index f4f39a7..0947a82 100644
--- a/jaxrs/src/main/java/com/ning/billing/jaxrs/mappers/SubscriptionRepairExceptionMapper.java
+++ b/jaxrs/src/main/java/com/ning/billing/jaxrs/mappers/SubscriptionRepairExceptionMapper.java
@@ -24,11 +24,11 @@ import javax.ws.rs.ext.ExceptionMapper;
 import javax.ws.rs.ext.Provider;
 
 import com.ning.billing.ErrorCode;
-import com.ning.billing.subscription.api.timeline.SubscriptionRepairException;
+import com.ning.billing.subscription.api.timeline.SubscriptionBaseRepairException;
 
 @Singleton
 @Provider
-public class SubscriptionRepairExceptionMapper extends ExceptionMapperBase implements ExceptionMapper<SubscriptionRepairException> {
+public class SubscriptionRepairExceptionMapper extends ExceptionMapperBase implements ExceptionMapper<SubscriptionBaseRepairException> {
 
     private final UriInfo uriInfo;
 
@@ -37,7 +37,7 @@ public class SubscriptionRepairExceptionMapper extends ExceptionMapperBase imple
     }
 
     @Override
-    public Response toResponse(final SubscriptionRepairException exception) {
+    public Response toResponse(final SubscriptionBaseRepairException exception) {
         if (exception.getCode() == ErrorCode.SUB_REPAIR_AO_CREATE_BEFORE_BP_START.getCode()) {
             return buildBadRequestResponse(exception, uriInfo);
         } else if (exception.getCode() == ErrorCode.SUB_REPAIR_BP_RECREATE_MISSING_AO.getCode()) {
diff --git a/jaxrs/src/main/java/com/ning/billing/jaxrs/resources/AccountResource.java b/jaxrs/src/main/java/com/ning/billing/jaxrs/resources/AccountResource.java
index 7a6ebd2..358a754 100644
--- a/jaxrs/src/main/java/com/ning/billing/jaxrs/resources/AccountResource.java
+++ b/jaxrs/src/main/java/com/ning/billing/jaxrs/resources/AccountResource.java
@@ -72,9 +72,8 @@ import com.ning.billing.payment.api.PaymentApi;
 import com.ning.billing.payment.api.PaymentApiException;
 import com.ning.billing.payment.api.PaymentMethod;
 import com.ning.billing.payment.api.Refund;
-import com.ning.billing.subscription.api.timeline.SubscriptionRepairException;
-import com.ning.billing.subscription.api.timeline.SubscriptionTimelineApi;
-import com.ning.billing.subscription.api.user.SubscriptionBaseBundle;
+import com.ning.billing.subscription.api.timeline.SubscriptionBaseRepairException;
+import com.ning.billing.subscription.api.timeline.SubscriptionBaseTimelineApi;
 import com.ning.billing.util.api.AuditUserApi;
 import com.ning.billing.util.api.CustomFieldApiException;
 import com.ning.billing.util.api.CustomFieldUserApi;
@@ -106,7 +105,7 @@ public class AccountResource extends JaxRsResourceBase {
 
     private final EntitlementApi entitlementApi;
     private final SubscriptionApi subscriptionApi;
-    private final SubscriptionTimelineApi timelineApi;
+    private final SubscriptionBaseTimelineApi timelineApi;
     private final InvoiceUserApi invoiceApi;
     private final InvoicePaymentApi invoicePaymentApi;
     private final PaymentApi paymentApi;
@@ -118,7 +117,7 @@ public class AccountResource extends JaxRsResourceBase {
                            final InvoiceUserApi invoiceApi,
                            final InvoicePaymentApi invoicePaymentApi,
                            final PaymentApi paymentApi,
-                           final SubscriptionTimelineApi timelineApi,
+                           final SubscriptionBaseTimelineApi timelineApi,
                            final TagUserApi tagUserApi,
                            final AuditUserApi auditUserApi,
                            final CustomFieldUserApi customFieldUserApi,
@@ -251,7 +250,7 @@ public class AccountResource extends JaxRsResourceBase {
     @Produces(APPLICATION_JSON)
     public Response getAccountTimeline(@PathParam("accountId") final String accountIdString,
                                        @QueryParam(QUERY_AUDIT) @DefaultValue("NONE") final AuditMode auditMode,
-                                       @javax.ws.rs.core.Context final HttpServletRequest request) throws AccountApiException, PaymentApiException, SubscriptionRepairException {
+                                       @javax.ws.rs.core.Context final HttpServletRequest request) throws AccountApiException, PaymentApiException, SubscriptionBaseRepairException {
         final TenantContext tenantContext = context.createContext(request);
 
         final UUID accountId = UUID.fromString(accountIdString);
@@ -284,7 +283,7 @@ public class AccountResource extends JaxRsResourceBase {
         /*
         // Get the bundles
         final List<SubscriptionBaseBundle> bundles = entitlementApi.getBundlesForAccount(account.getId(), tenantContext);
-        final List<BundleTimeline> bundlesTimeline = new LinkedList<BundleTimeline>();
+        final List<BundleBaseTimeline> bundlesTimeline = new LinkedList<BundleBaseTimeline>();
         for (final SubscriptionBaseBundle bundle : bundles) {
             bundlesTimeline.add(timelineApi.getBundleTimeline(bundle.getId(), tenantContext));
         }
diff --git a/jaxrs/src/main/java/com/ning/billing/jaxrs/resources/BundleResource.java b/jaxrs/src/main/java/com/ning/billing/jaxrs/resources/BundleResource.java
index aee7e9f..5623e2e 100644
--- a/jaxrs/src/main/java/com/ning/billing/jaxrs/resources/BundleResource.java
+++ b/jaxrs/src/main/java/com/ning/billing/jaxrs/resources/BundleResource.java
@@ -54,7 +54,6 @@ import com.ning.billing.jaxrs.json.CustomFieldJson;
 import com.ning.billing.jaxrs.json.SubscriptionJsonNoEvents;
 import com.ning.billing.jaxrs.util.Context;
 import com.ning.billing.jaxrs.util.JaxrsUriBuilder;
-import com.ning.billing.subscription.api.transfer.SubscriptionTransferApi;
 import com.ning.billing.util.api.AuditUserApi;
 import com.ning.billing.util.api.CustomFieldApiException;
 import com.ning.billing.util.api.CustomFieldUserApi;
diff --git a/jaxrs/src/test/java/com/ning/billing/jaxrs/json/TestBundleJsonWithSubscriptions.java b/jaxrs/src/test/java/com/ning/billing/jaxrs/json/TestBundleJsonWithSubscriptions.java
index bfed6dd..d747917 100644
--- a/jaxrs/src/test/java/com/ning/billing/jaxrs/json/TestBundleJsonWithSubscriptions.java
+++ b/jaxrs/src/test/java/com/ning/billing/jaxrs/json/TestBundleJsonWithSubscriptions.java
@@ -30,8 +30,8 @@ import com.ning.billing.catalog.api.PhaseType;
 import com.ning.billing.catalog.api.PlanPhaseSpecifier;
 import com.ning.billing.catalog.api.ProductCategory;
 import com.ning.billing.subscription.api.SubscriptionBaseTransitionType;
-import com.ning.billing.subscription.api.timeline.BundleTimeline;
-import com.ning.billing.subscription.api.timeline.SubscriptionTimeline;
+import com.ning.billing.subscription.api.timeline.BundleBaseTimeline;
+import com.ning.billing.subscription.api.timeline.SubscriptionBaseTimeline;
 import com.ning.billing.jaxrs.JaxrsTestSuiteNoDB;
 import com.ning.billing.util.audit.AuditLog;
 import com.ning.billing.clock.DefaultClock;
@@ -45,7 +45,7 @@ public class TestBundleJsonWithSubscriptions extends JaxrsTestSuiteNoDB {
 
     @Test(groups = "fast")
     public void testJson() throws Exception {
-        final SubscriptionTimeline.ExistingEvent event = Mockito.mock(SubscriptionTimeline.ExistingEvent.class);
+        final SubscriptionBaseTimeline.ExistingEvent event = Mockito.mock(SubscriptionBaseTimeline.ExistingEvent.class);
         final DateTime effectiveDate = DefaultClock.toUTCDateTime(new DateTime(DateTimeZone.UTC));
         final UUID eventId = UUID.randomUUID();
         final PlanPhaseSpecifier planPhaseSpecifier = new PlanPhaseSpecifier(UUID.randomUUID().toString(), ProductCategory.BASE,
@@ -56,9 +56,9 @@ public class TestBundleJsonWithSubscriptions extends JaxrsTestSuiteNoDB {
         Mockito.when(event.getSubscriptionTransitionType()).thenReturn(SubscriptionBaseTransitionType.CREATE);
         Mockito.when(event.getPlanPhaseSpecifier()).thenReturn(planPhaseSpecifier);
 
-        final SubscriptionTimeline subscriptionTimeline = Mockito.mock(SubscriptionTimeline.class);
+        final SubscriptionBaseTimeline subscriptionTimeline = Mockito.mock(SubscriptionBaseTimeline.class);
         Mockito.when(subscriptionTimeline.getId()).thenReturn(UUID.randomUUID());
-        Mockito.when(subscriptionTimeline.getExistingEvents()).thenReturn(ImmutableList.<SubscriptionTimeline.ExistingEvent>of(event));
+        Mockito.when(subscriptionTimeline.getExistingEvents()).thenReturn(ImmutableList.<SubscriptionBaseTimeline.ExistingEvent>of(event));
 
         final UUID bundleId = UUID.randomUUID();
         final String externalKey = UUID.randomUUID().toString();
@@ -77,7 +77,7 @@ public class TestBundleJsonWithSubscriptions extends JaxrsTestSuiteNoDB {
 
     @Test(groups = "fast")
     public void testFromBundleTimeline() throws Exception {
-        final SubscriptionTimeline.ExistingEvent event = Mockito.mock(SubscriptionTimeline.ExistingEvent.class);
+        final SubscriptionBaseTimeline.ExistingEvent event = Mockito.mock(SubscriptionBaseTimeline.ExistingEvent.class);
         final DateTime effectiveDate = DefaultClock.toUTCDateTime(new DateTime(DateTimeZone.UTC));
         final UUID eventId = UUID.randomUUID();
         final PlanPhaseSpecifier planPhaseSpecifier = new PlanPhaseSpecifier(UUID.randomUUID().toString(), ProductCategory.BASE,
@@ -88,18 +88,18 @@ public class TestBundleJsonWithSubscriptions extends JaxrsTestSuiteNoDB {
         Mockito.when(event.getSubscriptionTransitionType()).thenReturn(SubscriptionBaseTransitionType.CREATE);
         Mockito.when(event.getPlanPhaseSpecifier()).thenReturn(planPhaseSpecifier);
 
-        final SubscriptionTimeline subscriptionTimeline = Mockito.mock(SubscriptionTimeline.class);
+        final SubscriptionBaseTimeline subscriptionTimeline = Mockito.mock(SubscriptionBaseTimeline.class);
         Mockito.when(subscriptionTimeline.getId()).thenReturn(UUID.randomUUID());
-        Mockito.when(subscriptionTimeline.getExistingEvents()).thenReturn(ImmutableList.<SubscriptionTimeline.ExistingEvent>of(event));
+        Mockito.when(subscriptionTimeline.getExistingEvents()).thenReturn(ImmutableList.<SubscriptionBaseTimeline.ExistingEvent>of(event));
 
-        final BundleTimeline bundleTimeline = Mockito.mock(BundleTimeline.class);
+        final BundleBaseTimeline bundleBaseTimeline = Mockito.mock(BundleBaseTimeline.class);
         final UUID bundleId = UUID.randomUUID();
         final String externalKey = UUID.randomUUID().toString();
-        Mockito.when(bundleTimeline.getId()).thenReturn(bundleId);
-        Mockito.when(bundleTimeline.getExternalKey()).thenReturn(externalKey);
-        Mockito.when(bundleTimeline.getSubscriptions()).thenReturn(ImmutableList.<SubscriptionTimeline>of(subscriptionTimeline));
+        Mockito.when(bundleBaseTimeline.getId()).thenReturn(bundleId);
+        Mockito.when(bundleBaseTimeline.getExternalKey()).thenReturn(externalKey);
+        Mockito.when(bundleBaseTimeline.getSubscriptions()).thenReturn(ImmutableList.<SubscriptionBaseTimeline>of(subscriptionTimeline));
 
-        final BundleJsonWithSubscriptions bundleJsonWithSubscriptions = new BundleJsonWithSubscriptions(bundleTimeline, null,
+        final BundleJsonWithSubscriptions bundleJsonWithSubscriptions = new BundleJsonWithSubscriptions(bundleBaseTimeline, null,
                                                                                                         ImmutableMap.<UUID, List<AuditLog>>of(),
                                                                                                         ImmutableMap.<UUID, List<AuditLog>>of());
         Assert.assertEquals(bundleJsonWithSubscriptions.getBundleId(), bundleId.toString());
@@ -117,7 +117,7 @@ public class TestBundleJsonWithSubscriptions extends JaxrsTestSuiteNoDB {
 
     @Test(groups = "fast")
     public void testFromSubscriptionBundle() throws Exception {
-        final BundleTimeline bundle = Mockito.mock(BundleTimeline.class);
+        final BundleBaseTimeline bundle = Mockito.mock(BundleBaseTimeline.class);
         final UUID bundleId = UUID.randomUUID();
         final String externalKey = UUID.randomUUID().toString();
         Mockito.when(bundle.getId()).thenReturn(bundleId);
diff --git a/jaxrs/src/test/java/com/ning/billing/jaxrs/json/TestBundleTimelineJson.java b/jaxrs/src/test/java/com/ning/billing/jaxrs/json/TestBundleTimelineJson.java
index e2e5bb5..45837c1 100644
--- a/jaxrs/src/test/java/com/ning/billing/jaxrs/json/TestBundleTimelineJson.java
+++ b/jaxrs/src/test/java/com/ning/billing/jaxrs/json/TestBundleTimelineJson.java
@@ -31,7 +31,7 @@ import com.ning.billing.catalog.api.PhaseType;
 import com.ning.billing.catalog.api.PlanPhaseSpecifier;
 import com.ning.billing.catalog.api.ProductCategory;
 import com.ning.billing.subscription.api.SubscriptionBaseTransitionType;
-import com.ning.billing.subscription.api.timeline.SubscriptionTimeline;
+import com.ning.billing.subscription.api.timeline.SubscriptionBaseTimeline;
 import com.ning.billing.jaxrs.JaxrsTestSuiteNoDB;
 
 import com.google.common.collect.ImmutableList;
@@ -60,7 +60,7 @@ public class TestBundleTimelineJson extends JaxrsTestSuiteNoDB {
     }
 
     private BundleJsonWithSubscriptions createBundleWithSubscriptions() {
-        final SubscriptionTimeline.ExistingEvent event = Mockito.mock(SubscriptionTimeline.ExistingEvent.class);
+        final SubscriptionBaseTimeline.ExistingEvent event = Mockito.mock(SubscriptionBaseTimeline.ExistingEvent.class);
         final DateTime effectiveDate = clock.getUTCNow();
         final UUID eventId = UUID.randomUUID();
         final PlanPhaseSpecifier planPhaseSpecifier = new PlanPhaseSpecifier(UUID.randomUUID().toString(), ProductCategory.BASE,
@@ -71,9 +71,9 @@ public class TestBundleTimelineJson extends JaxrsTestSuiteNoDB {
         Mockito.when(event.getSubscriptionTransitionType()).thenReturn(SubscriptionBaseTransitionType.CREATE);
         Mockito.when(event.getPlanPhaseSpecifier()).thenReturn(planPhaseSpecifier);
 
-        final SubscriptionTimeline subscriptionTimeline = Mockito.mock(SubscriptionTimeline.class);
+        final SubscriptionBaseTimeline subscriptionTimeline = Mockito.mock(SubscriptionBaseTimeline.class);
         Mockito.when(subscriptionTimeline.getId()).thenReturn(UUID.randomUUID());
-        Mockito.when(subscriptionTimeline.getExistingEvents()).thenReturn(ImmutableList.<SubscriptionTimeline.ExistingEvent>of(event));
+        Mockito.when(subscriptionTimeline.getExistingEvents()).thenReturn(ImmutableList.<SubscriptionBaseTimeline.ExistingEvent>of(event));
 
         final UUID bundleId = UUID.randomUUID();
         final String externalKey = UUID.randomUUID().toString();
diff --git a/jaxrs/src/test/java/com/ning/billing/jaxrs/json/TestSubscriptionJsonWithEvents.java b/jaxrs/src/test/java/com/ning/billing/jaxrs/json/TestSubscriptionJsonWithEvents.java
index 880cdf1..fc2d3af 100644
--- a/jaxrs/src/test/java/com/ning/billing/jaxrs/json/TestSubscriptionJsonWithEvents.java
+++ b/jaxrs/src/test/java/com/ning/billing/jaxrs/json/TestSubscriptionJsonWithEvents.java
@@ -30,7 +30,7 @@ import com.ning.billing.catalog.api.PhaseType;
 import com.ning.billing.catalog.api.PlanPhaseSpecifier;
 import com.ning.billing.catalog.api.ProductCategory;
 import com.ning.billing.subscription.api.SubscriptionBaseTransitionType;
-import com.ning.billing.subscription.api.timeline.SubscriptionTimeline;
+import com.ning.billing.subscription.api.timeline.SubscriptionBaseTimeline;
 import com.ning.billing.subscription.api.SubscriptionBase;
 import com.ning.billing.jaxrs.JaxrsTestSuiteNoDB;
 import com.ning.billing.clock.DefaultClock;
@@ -105,7 +105,7 @@ public class TestSubscriptionJsonWithEvents extends JaxrsTestSuiteNoDB {
 
     @Test(groups = "fast")
     public void testFromSubscriptionTimeline() throws Exception {
-        final SubscriptionTimeline.ExistingEvent event = Mockito.mock(SubscriptionTimeline.ExistingEvent.class);
+        final SubscriptionBaseTimeline.ExistingEvent event = Mockito.mock(SubscriptionBaseTimeline.ExistingEvent.class);
         final DateTime effectiveDate = DefaultClock.toUTCDateTime(new DateTime(DateTimeZone.UTC));
         final UUID eventId = UUID.randomUUID();
         final PlanPhaseSpecifier planPhaseSpecifier = new PlanPhaseSpecifier(UUID.randomUUID().toString(), ProductCategory.BASE,
@@ -116,9 +116,9 @@ public class TestSubscriptionJsonWithEvents extends JaxrsTestSuiteNoDB {
         Mockito.when(event.getSubscriptionTransitionType()).thenReturn(SubscriptionBaseTransitionType.CREATE);
         Mockito.when(event.getPlanPhaseSpecifier()).thenReturn(planPhaseSpecifier);
 
-        final SubscriptionTimeline subscriptionTimeline = Mockito.mock(SubscriptionTimeline.class);
+        final SubscriptionBaseTimeline subscriptionTimeline = Mockito.mock(SubscriptionBaseTimeline.class);
         Mockito.when(subscriptionTimeline.getId()).thenReturn(UUID.randomUUID());
-        Mockito.when(subscriptionTimeline.getExistingEvents()).thenReturn(ImmutableList.<SubscriptionTimeline.ExistingEvent>of(event));
+        Mockito.when(subscriptionTimeline.getExistingEvents()).thenReturn(ImmutableList.<SubscriptionBaseTimeline.ExistingEvent>of(event));
 
         final UUID bundleId = UUID.randomUUID();
 
diff --git a/subscription/src/main/java/com/ning/billing/subscription/alignment/MigrationPlanAligner.java b/subscription/src/main/java/com/ning/billing/subscription/alignment/MigrationPlanAligner.java
index bd8ddd9..196d7a9 100644
--- a/subscription/src/main/java/com/ning/billing/subscription/alignment/MigrationPlanAligner.java
+++ b/subscription/src/main/java/com/ning/billing/subscription/alignment/MigrationPlanAligner.java
@@ -25,8 +25,8 @@ import com.ning.billing.catalog.api.PhaseType;
 import com.ning.billing.catalog.api.Plan;
 import com.ning.billing.catalog.api.PlanPhase;
 import com.ning.billing.catalog.api.PlanPhaseSpecifier;
-import com.ning.billing.subscription.api.migration.SubscriptionMigrationApi.SubscriptionMigrationCase;
-import com.ning.billing.subscription.api.migration.SubscriptionMigrationApiException;
+import com.ning.billing.subscription.api.migration.SubscriptionBaseMigrationApi.SubscriptionMigrationCase;
+import com.ning.billing.subscription.api.migration.SubscriptionBaseMigrationApiException;
 import com.ning.billing.subscription.events.SubscriptionEvent.EventType;
 import com.ning.billing.subscription.events.user.ApiEventType;
 
@@ -43,7 +43,7 @@ public class MigrationPlanAligner extends BaseAligner {
 
 
     public TimedMigration[] getEventsMigration(final SubscriptionMigrationCase[] input, final DateTime now)
-            throws SubscriptionMigrationApiException {
+            throws SubscriptionBaseMigrationApiException {
 
         try {
             TimedMigration[] events;
@@ -82,7 +82,7 @@ public class MigrationPlanAligner extends BaseAligner {
                     }
                 }
                 if (curPhaseDuration == null) {
-                    throw new SubscriptionMigrationApiException(String.format("Failed to compute current phase duration for plan %s and phase %s",
+                    throw new SubscriptionBaseMigrationApiException(String.format("Failed to compute current phase duration for plan %s and phase %s",
                                                                              plan0.getName(), curPhaseType));
                 }
 
@@ -104,12 +104,12 @@ public class MigrationPlanAligner extends BaseAligner {
                                                               input[1].getEffectiveDate());
 
             } else {
-                throw new SubscriptionMigrationApiException("Unknown migration type");
+                throw new SubscriptionBaseMigrationApiException("Unknown migration type");
             }
 
             return events;
         } catch (CatalogApiException e) {
-            throw new SubscriptionMigrationApiException(e);
+            throw new SubscriptionBaseMigrationApiException(e);
         }
     }
 
@@ -120,7 +120,7 @@ public class MigrationPlanAligner extends BaseAligner {
     }
 
     private TimedMigration[] getEventsOnFuturePhaseChangeMigration(final Plan plan, final PlanPhase initialPhase, final String priceList, final DateTime effectiveDate, final DateTime effectiveDateForNextPhase)
-            throws SubscriptionMigrationApiException {
+            throws SubscriptionBaseMigrationApiException {
 
         final TimedMigration[] result = new TimedMigration[2];
 
@@ -137,7 +137,7 @@ public class MigrationPlanAligner extends BaseAligner {
             }
         }
         if (nextPhase == null) {
-            throw new SubscriptionMigrationApiException(String.format("Cannot find next phase for Plan %s and current Phase %s",
+            throw new SubscriptionBaseMigrationApiException(String.format("Cannot find next phase for Plan %s and current Phase %s",
                                                                      plan.getName(), initialPhase.getName()));
         }
         result[1] = new TimedMigration(effectiveDateForNextPhase, EventType.PHASE, null, plan, nextPhase, priceList);
@@ -160,13 +160,13 @@ public class MigrationPlanAligner extends BaseAligner {
 
 
     // STEPH should be in catalog
-    private PlanPhase getPlanPhase(final Plan plan, final PhaseType phaseType) throws SubscriptionMigrationApiException {
+    private PlanPhase getPlanPhase(final Plan plan, final PhaseType phaseType) throws SubscriptionBaseMigrationApiException {
         for (final PlanPhase cur : plan.getAllPhases()) {
             if (cur.getPhaseType() == phaseType) {
                 return cur;
             }
         }
-        throw new SubscriptionMigrationApiException(String.format("Cannot find PlanPhase from Plan %s and type %s", plan.getName(), phaseType));
+        throw new SubscriptionBaseMigrationApiException(String.format("Cannot find PlanPhase from Plan %s and type %s", plan.getName(), phaseType));
     }
 
     private boolean isRegularMigratedSubscription(final SubscriptionMigrationCase[] input) {
diff --git a/subscription/src/main/java/com/ning/billing/subscription/alignment/PlanAligner.java b/subscription/src/main/java/com/ning/billing/subscription/alignment/PlanAligner.java
index f5cc57d..23faac4 100644
--- a/subscription/src/main/java/com/ning/billing/subscription/alignment/PlanAligner.java
+++ b/subscription/src/main/java/com/ning/billing/subscription/alignment/PlanAligner.java
@@ -40,8 +40,8 @@ import com.ning.billing.catalog.api.PlanSpecifier;
 import com.ning.billing.catalog.api.ProductCategory;
 import com.ning.billing.subscription.api.user.SubscriptionBaseApiException;
 import com.ning.billing.subscription.api.user.SubscriptionBaseTransitionData;
-import com.ning.billing.subscription.api.user.SubscriptionData;
-import com.ning.billing.subscription.exceptions.SubscriptionError;
+import com.ning.billing.subscription.api.user.DefaultSubscriptionBase;
+import com.ning.billing.subscription.exceptions.SubscriptionBaseError;
 
 /**
  * PlanAligner offers specific APIs to return the correct {@code TimedPhase} when creating, changing Plan or to compute
@@ -74,7 +74,7 @@ public class PlanAligner extends BaseAligner {
      * @throws CatalogApiException         for catalog errors
      * @throws com.ning.billing.subscription.api.user.SubscriptionBaseApiException for subscription errors
      */
-    public TimedPhase[] getCurrentAndNextTimedPhaseOnCreate(final SubscriptionData subscription,
+    public TimedPhase[] getCurrentAndNextTimedPhaseOnCreate(final DefaultSubscriptionBase subscription,
                                                             final Plan plan,
                                                             final PhaseType initialPhase,
                                                             final String priceList,
@@ -105,7 +105,7 @@ public class PlanAligner extends BaseAligner {
      * @throws CatalogApiException         for catalog errors
      * @throws com.ning.billing.subscription.api.user.SubscriptionBaseApiException for subscription errors
      */
-    public TimedPhase getCurrentTimedPhaseOnChange(final SubscriptionData subscription,
+    public TimedPhase getCurrentTimedPhaseOnChange(final DefaultSubscriptionBase subscription,
                                                    final Plan plan,
                                                    final String priceList,
                                                    final DateTime requestedDate,
@@ -126,7 +126,7 @@ public class PlanAligner extends BaseAligner {
      * @throws CatalogApiException         for catalog errors
      * @throws com.ning.billing.subscription.api.user.SubscriptionBaseApiException for subscription errors
      */
-    public TimedPhase getNextTimedPhaseOnChange(final SubscriptionData subscription,
+    public TimedPhase getNextTimedPhaseOnChange(final DefaultSubscriptionBase subscription,
                                                 final Plan plan,
                                                 final String priceList,
                                                 final DateTime requestedDate,
@@ -142,11 +142,11 @@ public class PlanAligner extends BaseAligner {
      * @param effectiveDate the date at which we look to compute that event. effective needs to be after last Plan change or initial Plan
      * @return the next phase
      */
-    public TimedPhase getNextTimedPhase(final SubscriptionData subscription, final DateTime requestedDate, final DateTime effectiveDate) {
+    public TimedPhase getNextTimedPhase(final DefaultSubscriptionBase subscription, final DateTime requestedDate, final DateTime effectiveDate) {
         try {
             final SubscriptionBaseTransitionData lastPlanTransition = subscription.getInitialTransitionForCurrentPlan();
             if (effectiveDate.isBefore(lastPlanTransition.getEffectiveTransitionTime())) {
-                throw new SubscriptionError(String.format("Cannot specify an effectiveDate prior to last Plan Change, subscription = %s, effectiveDate = %s",
+                throw new SubscriptionBaseError(String.format("Cannot specify an effectiveDate prior to last Plan Change, subscription = %s, effectiveDate = %s",
                                                          subscription.getId(), effectiveDate));
             }
 
@@ -176,11 +176,11 @@ public class PlanAligner extends BaseAligner {
                                                  effectiveDate,
                                                  WhichPhase.NEXT);
                 default:
-                    throw new SubscriptionError(String.format("Unexpected initial transition %s for current plan %s on subscription %s",
+                    throw new SubscriptionBaseError(String.format("Unexpected initial transition %s for current plan %s on subscription %s",
                                                              lastPlanTransition.getTransitionType(), subscription.getCurrentPlan(), subscription.getId()));
             }
         } catch (Exception /* SubscriptionBaseApiException, CatalogApiException */ e) {
-            throw new SubscriptionError(String.format("Could not compute next phase change for subscription %s", subscription.getId()), e);
+            throw new SubscriptionBaseError(String.format("Could not compute next phase change for subscription %s", subscription.getId()), e);
         }
     }
 
@@ -208,13 +208,13 @@ public class PlanAligner extends BaseAligner {
                 planStartDate = bundleStartDate;
                 break;
             default:
-                throw new SubscriptionError(String.format("Unknown PlanAlignmentCreate %s", alignment));
+                throw new SubscriptionBaseError(String.format("Unknown PlanAlignmentCreate %s", alignment));
         }
 
         return getPhaseAlignments(plan, initialPhase, planStartDate);
     }
 
-    private TimedPhase getTimedPhaseOnChange(final SubscriptionData subscription,
+    private TimedPhase getTimedPhaseOnChange(final DefaultSubscriptionBase subscription,
                                              final Plan nextPlan,
                                              final String nextPriceList,
                                              final DateTime requestedDate,
@@ -268,9 +268,9 @@ public class PlanAligner extends BaseAligner {
                 planStartDate = effectiveDate;
                 break;
             case CHANGE_OF_PRICELIST:
-                throw new SubscriptionError(String.format("Not implemented yet %s", alignment));
+                throw new SubscriptionBaseError(String.format("Not implemented yet %s", alignment));
             default:
-                throw new SubscriptionError(String.format("Unknown PlanAlignmentChange %s", alignment));
+                throw new SubscriptionBaseError(String.format("Unknown PlanAlignmentChange %s", alignment));
         }
 
         final List<TimedPhase> timedPhases = getPhaseAlignments(nextPlan, null, planStartDate);
@@ -301,7 +301,7 @@ public class PlanAligner extends BaseAligner {
                 final Duration curPhaseDuration = cur.getDuration();
                 nextPhaseStart = addDuration(curPhaseStart, curPhaseDuration);
                 if (nextPhaseStart == null) {
-                    throw new SubscriptionError(String.format("Unexpected non ending UNLIMITED phase for plan %s",
+                    throw new SubscriptionBaseError(String.format("Unexpected non ending UNLIMITED phase for plan %s",
                                                              plan.getName()));
                 }
                 curPhaseStart = nextPhaseStart;
@@ -333,7 +333,7 @@ public class PlanAligner extends BaseAligner {
             case NEXT:
                 return next;
             default:
-                throw new SubscriptionError(String.format("Unexpected %s TimedPhase", which));
+                throw new SubscriptionBaseError(String.format("Unexpected %s TimedPhase", which));
         }
     }
 
diff --git a/subscription/src/main/java/com/ning/billing/subscription/api/migration/AccountMigrationData.java b/subscription/src/main/java/com/ning/billing/subscription/api/migration/AccountMigrationData.java
index bfb1178..5bc1fed 100644
--- a/subscription/src/main/java/com/ning/billing/subscription/api/migration/AccountMigrationData.java
+++ b/subscription/src/main/java/com/ning/billing/subscription/api/migration/AccountMigrationData.java
@@ -21,8 +21,8 @@ import java.util.List;
 import org.joda.time.DateTime;
 
 import com.ning.billing.subscription.api.user.SubscriptionBuilder;
-import com.ning.billing.subscription.api.user.SubscriptionBundleData;
-import com.ning.billing.subscription.api.user.SubscriptionData;
+import com.ning.billing.subscription.api.user.DefaultSubscriptionBaseBundle;
+import com.ning.billing.subscription.api.user.DefaultSubscriptionBase;
 import com.ning.billing.subscription.events.SubscriptionEvent;
 
 
@@ -41,17 +41,17 @@ public class AccountMigrationData {
 
     public static class BundleMigrationData {
 
-        private final SubscriptionBundleData data;
+        private final DefaultSubscriptionBaseBundle data;
         private final List<SubscriptionMigrationData> subscriptions;
 
-        public BundleMigrationData(final SubscriptionBundleData data,
+        public BundleMigrationData(final DefaultSubscriptionBaseBundle data,
                                    final List<SubscriptionMigrationData> subscriptions) {
             super();
             this.data = data;
             this.subscriptions = subscriptions;
         }
 
-        public SubscriptionBundleData getData() {
+        public DefaultSubscriptionBaseBundle getData() {
             return data;
         }
 
@@ -62,10 +62,10 @@ public class AccountMigrationData {
 
     public static class SubscriptionMigrationData {
 
-        private final SubscriptionData data;
+        private final DefaultSubscriptionBase data;
         private final List<SubscriptionEvent> initialEvents;
 
-        public SubscriptionMigrationData(final SubscriptionData data,
+        public SubscriptionMigrationData(final DefaultSubscriptionBase data,
                                          final List<SubscriptionEvent> initialEvents,
                                          final DateTime ctd) {
             super();
@@ -74,11 +74,11 @@ public class AccountMigrationData {
             if (ctd != null) {
                 builder.setChargedThroughDate(ctd);
             }
-            this.data = new SubscriptionData(builder);
+            this.data = new DefaultSubscriptionBase(builder);
             this.initialEvents = initialEvents;
         }
 
-        public SubscriptionData getData() {
+        public DefaultSubscriptionBase getData() {
             return data;
         }
 
diff --git a/subscription/src/main/java/com/ning/billing/subscription/api/migration/DefaultSubscriptionBaseMigrationApi.java b/subscription/src/main/java/com/ning/billing/subscription/api/migration/DefaultSubscriptionBaseMigrationApi.java
new file mode 100644
index 0000000..728659c
--- /dev/null
+++ b/subscription/src/main/java/com/ning/billing/subscription/api/migration/DefaultSubscriptionBaseMigrationApi.java
@@ -0,0 +1,276 @@
+/*
+ * Copyright 2010-2013 Ning, Inc.
+ *
+ * Ning licenses this file to you under the Apache License, version 2.0
+ * (the "License"); you may not use this file except in compliance with the
+ * License.  You may obtain a copy of the License at:
+ *
+ *    http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
+ * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.  See the
+ * License for the specific language governing permissions and limitations
+ * under the License.
+ */
+
+package com.ning.billing.subscription.api.migration;
+
+import java.util.ArrayList;
+import java.util.Collections;
+import java.util.Comparator;
+import java.util.LinkedList;
+import java.util.List;
+import java.util.UUID;
+
+import org.joda.time.DateTime;
+
+import com.ning.billing.catalog.api.CatalogService;
+import com.ning.billing.catalog.api.ProductCategory;
+import com.ning.billing.clock.Clock;
+import com.ning.billing.subscription.alignment.MigrationPlanAligner;
+import com.ning.billing.subscription.alignment.TimedMigration;
+import com.ning.billing.subscription.api.SubscriptionApiBase;
+import com.ning.billing.subscription.api.SubscriptionBaseApiService;
+import com.ning.billing.subscription.api.migration.AccountMigrationData.BundleMigrationData;
+import com.ning.billing.subscription.api.migration.AccountMigrationData.SubscriptionMigrationData;
+import com.ning.billing.subscription.api.user.DefaultSubscriptionBase;
+import com.ning.billing.subscription.api.user.DefaultSubscriptionBaseBundle;
+import com.ning.billing.subscription.api.user.SubscriptionBuilder;
+import com.ning.billing.subscription.engine.dao.SubscriptionDao;
+import com.ning.billing.subscription.events.SubscriptionEvent;
+import com.ning.billing.subscription.events.SubscriptionEvent.EventType;
+import com.ning.billing.subscription.events.phase.PhaseEvent;
+import com.ning.billing.subscription.events.phase.PhaseEventData;
+import com.ning.billing.subscription.events.user.ApiEvent;
+import com.ning.billing.subscription.events.user.ApiEventBuilder;
+import com.ning.billing.subscription.events.user.ApiEventCancel;
+import com.ning.billing.subscription.events.user.ApiEventChange;
+import com.ning.billing.subscription.events.user.ApiEventMigrateBilling;
+import com.ning.billing.subscription.events.user.ApiEventMigrateSubscription;
+import com.ning.billing.subscription.events.user.ApiEventType;
+import com.ning.billing.subscription.exceptions.SubscriptionBaseError;
+import com.ning.billing.util.callcontext.CallContext;
+import com.ning.billing.util.callcontext.InternalCallContextFactory;
+
+import com.google.common.collect.Lists;
+import com.google.inject.Inject;
+
+public class DefaultSubscriptionBaseMigrationApi extends SubscriptionApiBase implements SubscriptionBaseMigrationApi {
+
+    private final MigrationPlanAligner migrationAligner;
+    private final InternalCallContextFactory internalCallContextFactory;
+
+    @Inject
+    public DefaultSubscriptionBaseMigrationApi(final MigrationPlanAligner migrationAligner,
+                                               final SubscriptionBaseApiService apiService,
+                                               final CatalogService catalogService,
+                                               final SubscriptionDao dao,
+                                               final Clock clock,
+                                               final InternalCallContextFactory internalCallContextFactory) {
+        super(dao, apiService, clock, catalogService);
+        this.migrationAligner = migrationAligner;
+        this.internalCallContextFactory = internalCallContextFactory;
+    }
+
+    @Override
+    public void migrate(final AccountMigration toBeMigrated, final CallContext context)
+            throws SubscriptionBaseMigrationApiException {
+        final AccountMigrationData accountMigrationData = createAccountMigrationData(toBeMigrated, context);
+        dao.migrate(toBeMigrated.getAccountKey(), accountMigrationData, internalCallContextFactory.createInternalCallContext(toBeMigrated.getAccountKey(), context));
+    }
+
+    private AccountMigrationData createAccountMigrationData(final AccountMigration toBeMigrated, final CallContext context)
+            throws SubscriptionBaseMigrationApiException {
+        final UUID accountId = toBeMigrated.getAccountKey();
+        final DateTime now = clock.getUTCNow();
+
+        final List<BundleMigrationData> accountBundleData = new LinkedList<BundleMigrationData>();
+
+        for (final BundleMigration curBundle : toBeMigrated.getBundles()) {
+
+            final DefaultSubscriptionBaseBundle bundleData = new DefaultSubscriptionBaseBundle(curBundle.getBundleKey(), accountId, clock.getUTCNow());
+            final List<SubscriptionMigrationData> bundleSubscriptionData = new LinkedList<AccountMigrationData.SubscriptionMigrationData>();
+
+            final List<SubscriptionMigration> sortedSubscriptions = Lists.newArrayList(curBundle.getSubscriptions());
+            // Make sure we have first BASE or STANDALONE, then ADDON and for each category order by CED
+            Collections.sort(sortedSubscriptions, new Comparator<SubscriptionMigration>() {
+                @Override
+                public int compare(final SubscriptionMigration o1,
+                                   final SubscriptionMigration o2) {
+                    if (o1.getCategory().equals(o2.getCategory())) {
+                        return o1.getSubscriptionCases()[0].getEffectiveDate().compareTo(o2.getSubscriptionCases()[0].getEffectiveDate());
+                    } else {
+                        if (!o1.getCategory().name().equalsIgnoreCase("ADD_ON")) {
+                            return -1;
+                        } else if (o1.getCategory().name().equalsIgnoreCase("ADD_ON")) {
+                            return 1;
+                        } else {
+                            return 0;
+                        }
+                    }
+                }
+            });
+
+            DateTime bundleStartDate = null;
+            for (final SubscriptionMigration curSub : sortedSubscriptions) {
+                SubscriptionMigrationData data = null;
+                if (bundleStartDate == null) {
+                    data = createInitialSubscription(bundleData.getId(), curSub.getCategory(), curSub.getSubscriptionCases(), now, curSub.getChargedThroughDate(), context);
+                    bundleStartDate = data.getInitialEvents().get(0).getEffectiveDate();
+                } else {
+                    data = createSubscriptionMigrationDataWithBundleDate(bundleData.getId(), curSub.getCategory(), curSub.getSubscriptionCases(), now,
+                                                                         bundleStartDate, curSub.getChargedThroughDate(), context);
+                }
+                if (data != null) {
+                    bundleSubscriptionData.add(data);
+                }
+            }
+            final BundleMigrationData bundleMigrationData = new BundleMigrationData(bundleData, bundleSubscriptionData);
+            accountBundleData.add(bundleMigrationData);
+        }
+
+        return new AccountMigrationData(accountBundleData);
+    }
+
+    private SubscriptionMigrationData createInitialSubscription(final UUID bundleId, final ProductCategory productCategory,
+                                                                final SubscriptionMigrationCase[] input, final DateTime now, final DateTime ctd, final CallContext context)
+            throws SubscriptionBaseMigrationApiException {
+        final TimedMigration[] events = migrationAligner.getEventsMigration(input, now);
+        final DateTime migrationStartDate = events[0].getEventTime();
+        final List<SubscriptionEvent> emptyEvents = Collections.emptyList();
+        final DefaultSubscriptionBase defaultSubscriptionBase = createSubscriptionForApiUse(new SubscriptionBuilder()
+                                                                                      .setId(UUID.randomUUID())
+                                                                                      .setBundleId(bundleId)
+                                                                                      .setCategory(productCategory)
+                                                                                      .setBundleStartDate(migrationStartDate)
+                                                                                      .setAlignStartDate(migrationStartDate),
+                                                                              emptyEvents);
+        return new SubscriptionMigrationData(defaultSubscriptionBase, toEvents(defaultSubscriptionBase, now, ctd, events, context), ctd);
+    }
+
+    private SubscriptionMigrationData createSubscriptionMigrationDataWithBundleDate(final UUID bundleId, final ProductCategory productCategory,
+                                                                                    final SubscriptionMigrationCase[] input, final DateTime now, final DateTime bundleStartDate, final DateTime ctd, final CallContext context)
+            throws SubscriptionBaseMigrationApiException {
+        final TimedMigration[] events = migrationAligner.getEventsMigration(input, now);
+        final DateTime migrationStartDate = events[0].getEventTime();
+        final List<SubscriptionEvent> emptyEvents = Collections.emptyList();
+        final DefaultSubscriptionBase defaultSubscriptionBase = createSubscriptionForApiUse(new SubscriptionBuilder()
+                                                                                      .setId(UUID.randomUUID())
+                                                                                      .setBundleId(bundleId)
+                                                                                      .setCategory(productCategory)
+                                                                                      .setBundleStartDate(bundleStartDate)
+                                                                                      .setAlignStartDate(migrationStartDate),
+                                                                              emptyEvents);
+        return new SubscriptionMigrationData(defaultSubscriptionBase, toEvents(defaultSubscriptionBase, now, ctd, events, context), ctd);
+    }
+
+    private List<SubscriptionEvent> toEvents(final DefaultSubscriptionBase defaultSubscriptionBase, final DateTime now, final DateTime ctd, final TimedMigration[] migrationEvents, final CallContext context) {
+
+
+        if (ctd == null) {
+            throw new SubscriptionBaseError(String.format("Could not create migration billing event ctd = %s", ctd));
+        }
+
+        final List<SubscriptionEvent> events = new ArrayList<SubscriptionEvent>(migrationEvents.length);
+
+        ApiEventMigrateBilling apiEventMigrateBilling = null;
+
+        // The first event date after the MIGRATE_ENTITLEMENT event
+        DateTime nextEventDate = null;
+
+        boolean isCancelledSubscriptionPriorOrAtCTD = false;
+
+        for (final TimedMigration cur : migrationEvents) {
+
+
+            final ApiEventBuilder builder = new ApiEventBuilder()
+                    .setSubscriptionId(defaultSubscriptionBase.getId())
+                    .setEventPlan((cur.getPlan() != null) ? cur.getPlan().getName() : null)
+                    .setEventPlanPhase((cur.getPhase() != null) ? cur.getPhase().getName() : null)
+                    .setEventPriceList(cur.getPriceList())
+                    .setActiveVersion(defaultSubscriptionBase.getActiveVersion())
+                    .setEffectiveDate(cur.getEventTime())
+                    .setProcessedDate(now)
+                    .setRequestedDate(now)
+                    .setFromDisk(true);
+
+
+            if (cur.getEventType() == EventType.PHASE) {
+                nextEventDate = nextEventDate != null && nextEventDate.compareTo(cur.getEventTime()) < 0 ? nextEventDate : cur.getEventTime();
+                final PhaseEvent nextPhaseEvent = PhaseEventData.createNextPhaseEvent(cur.getPhase().getName(), defaultSubscriptionBase, now, cur.getEventTime());
+                events.add(nextPhaseEvent);
+
+
+            } else if (cur.getEventType() == EventType.API_USER) {
+
+                switch (cur.getApiEventType()) {
+                    case MIGRATE_ENTITLEMENT:
+                        ApiEventMigrateSubscription creationEvent = new ApiEventMigrateSubscription(builder);
+                        events.add(creationEvent);
+                        break;
+
+                    case CHANGE:
+                        nextEventDate = nextEventDate != null && nextEventDate.compareTo(cur.getEventTime()) < 0 ? nextEventDate : cur.getEventTime();
+                        events.add(new ApiEventChange(builder));
+                        break;
+                    case CANCEL:
+                        isCancelledSubscriptionPriorOrAtCTD = !cur.getEventTime().isAfter(ctd);
+                        nextEventDate = nextEventDate != null && nextEventDate.compareTo(cur.getEventTime()) < 0 ? nextEventDate : cur.getEventTime();
+                        events.add(new ApiEventCancel(builder));
+                        break;
+                    default:
+                        throw new SubscriptionBaseError(String.format("Unexpected type of api migration event %s", cur.getApiEventType()));
+                }
+            } else {
+                throw new SubscriptionBaseError(String.format("Unexpected type of migration event %s", cur.getEventType()));
+            }
+
+            // create the MIGRATE_BILLING based on the current state of the last event.
+            if (!cur.getEventTime().isAfter(ctd)) {
+                builder.setEffectiveDate(ctd);
+                builder.setUuid(UUID.randomUUID());
+                apiEventMigrateBilling = new ApiEventMigrateBilling(builder);
+            }
+        }
+        // Always ADD MIGRATE BILLING which is constructed from latest state seen in the stream prior to CTD
+        if (apiEventMigrateBilling != null && !isCancelledSubscriptionPriorOrAtCTD) {
+            events.add(apiEventMigrateBilling);
+        }
+
+        Collections.sort(events, new Comparator<SubscriptionEvent>() {
+            int compForApiType(final SubscriptionEvent o1, final SubscriptionEvent o2, final ApiEventType type) {
+                ApiEventType apiO1 = null;
+                if (o1.getType() == EventType.API_USER) {
+                    apiO1 = ((ApiEvent) o1).getEventType();
+                }
+                ApiEventType apiO2 = null;
+                if (o2.getType() == EventType.API_USER) {
+                    apiO2 = ((ApiEvent) o2).getEventType();
+                }
+                if (apiO1 != null && apiO1.equals(type)) {
+                    return -1;
+                } else if (apiO2 != null && apiO2.equals(type)) {
+                    return 1;
+                } else {
+                    return 0;
+                }
+            }
+
+            @Override
+            public int compare(final SubscriptionEvent o1, final SubscriptionEvent o2) {
+
+                int comp = o1.getEffectiveDate().compareTo(o2.getEffectiveDate());
+                if (comp == 0) {
+                    comp = compForApiType(o1, o2, ApiEventType.MIGRATE_ENTITLEMENT);
+                }
+                if (comp == 0) {
+                    comp = compForApiType(o1, o2, ApiEventType.MIGRATE_BILLING);
+                }
+                return comp;
+            }
+        });
+
+        return events;
+    }
+}
diff --git a/subscription/src/main/java/com/ning/billing/subscription/api/SubscriptionApiBase.java b/subscription/src/main/java/com/ning/billing/subscription/api/SubscriptionApiBase.java
index 59a7209..2457501 100644
--- a/subscription/src/main/java/com/ning/billing/subscription/api/SubscriptionApiBase.java
+++ b/subscription/src/main/java/com/ning/billing/subscription/api/SubscriptionApiBase.java
@@ -20,11 +20,10 @@ import java.util.ArrayList;
 import java.util.List;
 
 import com.ning.billing.catalog.api.CatalogService;
+import com.ning.billing.subscription.api.user.DefaultSubscriptionBase;
 import com.ning.billing.subscription.api.user.SubscriptionBuilder;
-import com.ning.billing.subscription.api.user.SubscriptionData;
 import com.ning.billing.subscription.engine.dao.SubscriptionDao;
 import com.ning.billing.subscription.events.SubscriptionEvent;
-import com.ning.billing.subscription.api.SubscriptionBase;
 import com.ning.billing.clock.Clock;
 
 import com.google.common.base.Function;
@@ -34,11 +33,11 @@ public class SubscriptionApiBase {
 
     protected final SubscriptionDao dao;
 
-    protected final SubscriptionApiService apiService;
+    protected final SubscriptionBaseApiService apiService;
     protected final Clock clock;
     protected final CatalogService catalogService;
 
-    public SubscriptionApiBase(final SubscriptionDao dao, final SubscriptionApiService apiService, final Clock clock, final CatalogService catalogService) {
+    public SubscriptionApiBase(final SubscriptionDao dao, final SubscriptionBaseApiService apiService, final Clock clock, final CatalogService catalogService) {
         this.dao = dao;
         this.apiService = apiService;
         this.clock = clock;
@@ -49,17 +48,17 @@ public class SubscriptionApiBase {
         return new ArrayList<SubscriptionBase>(Collections2.transform(internalSubscriptions, new Function<SubscriptionBase, SubscriptionBase>() {
             @Override
             public SubscriptionBase apply(final SubscriptionBase subscription) {
-                return createSubscriptionForApiUse((SubscriptionData) subscription);
+                return createSubscriptionForApiUse((DefaultSubscriptionBase) subscription);
             }
         }));
     }
 
-    protected SubscriptionData createSubscriptionForApiUse(final SubscriptionBase internalSubscription) {
-        return new SubscriptionData((SubscriptionData) internalSubscription, apiService, clock);
+    protected DefaultSubscriptionBase createSubscriptionForApiUse(final SubscriptionBase internalSubscription) {
+        return new DefaultSubscriptionBase((DefaultSubscriptionBase) internalSubscription, apiService, clock);
     }
 
-    protected SubscriptionData createSubscriptionForApiUse(SubscriptionBuilder builder, List<SubscriptionEvent> events) {
-        final SubscriptionData subscription = new SubscriptionData(builder, apiService, clock);
+    protected DefaultSubscriptionBase createSubscriptionForApiUse(SubscriptionBuilder builder, List<SubscriptionEvent> events) {
+        final DefaultSubscriptionBase subscription = new DefaultSubscriptionBase(builder, apiService, clock);
         if (events.size() > 0) {
             subscription.rebuildTransitions(events, catalogService.getFullCatalog());
         }
diff --git a/subscription/src/main/java/com/ning/billing/subscription/api/SubscriptionBaseApiService.java b/subscription/src/main/java/com/ning/billing/subscription/api/SubscriptionBaseApiService.java
new file mode 100644
index 0000000..2164fae
--- /dev/null
+++ b/subscription/src/main/java/com/ning/billing/subscription/api/SubscriptionBaseApiService.java
@@ -0,0 +1,60 @@
+/*
+ * Copyright 2010-2013 Ning, Inc.
+ *
+ * Ning licenses this file to you under the Apache License, version 2.0
+ * (the "License"); you may not use this file except in compliance with the
+ * License.  You may obtain a copy of the License at:
+ *
+ *    http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
+ * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.  See the
+ * License for the specific language governing permissions and limitations
+ * under the License.
+ */
+
+package com.ning.billing.subscription.api;
+
+import org.joda.time.DateTime;
+
+import com.ning.billing.catalog.api.BillingActionPolicy;
+import com.ning.billing.catalog.api.BillingPeriod;
+import com.ning.billing.catalog.api.PhaseType;
+import com.ning.billing.catalog.api.Plan;
+import com.ning.billing.catalog.api.PlanPhaseSpecifier;
+import com.ning.billing.subscription.api.user.DefaultSubscriptionBase;
+import com.ning.billing.subscription.api.user.SubscriptionBaseApiException;
+import com.ning.billing.subscription.api.user.SubscriptionBuilder;
+import com.ning.billing.util.callcontext.CallContext;
+import com.ning.billing.util.callcontext.InternalCallContext;
+
+public interface SubscriptionBaseApiService {
+
+    public DefaultSubscriptionBase createPlan(SubscriptionBuilder builder, Plan plan, PhaseType initialPhase,
+                                       String realPriceList, DateTime requestedDate, DateTime effectiveDate, DateTime processedDate,
+                                       CallContext context)
+            throws SubscriptionBaseApiException;
+
+    public boolean recreatePlan(DefaultSubscriptionBase subscription, PlanPhaseSpecifier spec, DateTime requestedDate, CallContext context)
+            throws SubscriptionBaseApiException;
+
+    public boolean cancel(DefaultSubscriptionBase subscription, DateTime requestedDate, CallContext context)
+        throws SubscriptionBaseApiException;
+
+    public boolean cancelWithPolicy(DefaultSubscriptionBase subscription, DateTime requestedDate, BillingActionPolicy policy, CallContext context)
+        throws SubscriptionBaseApiException;
+
+    public boolean uncancel(DefaultSubscriptionBase subscription, CallContext context)
+            throws SubscriptionBaseApiException;
+
+    public boolean changePlan(DefaultSubscriptionBase subscription, String productName, BillingPeriod term,
+                              String priceList, DateTime requestedDate, CallContext context)
+            throws SubscriptionBaseApiException;
+
+    public boolean changePlanWithPolicy(DefaultSubscriptionBase subscription, String productName, BillingPeriod term,
+                                        String priceList, DateTime requestedDate, BillingActionPolicy policy, CallContext context)
+            throws SubscriptionBaseApiException;
+
+    public int cancelAddOnsIfRequired(final DefaultSubscriptionBase baseSubscription, final DateTime effectiveDate, final InternalCallContext context);
+}
diff --git a/subscription/src/main/java/com/ning/billing/subscription/api/svcs/DefaultSubscriptionInternalApi.java b/subscription/src/main/java/com/ning/billing/subscription/api/svcs/DefaultSubscriptionInternalApi.java
index 885050d..888f084 100644
--- a/subscription/src/main/java/com/ning/billing/subscription/api/svcs/DefaultSubscriptionInternalApi.java
+++ b/subscription/src/main/java/com/ning/billing/subscription/api/svcs/DefaultSubscriptionInternalApi.java
@@ -39,22 +39,22 @@ import com.ning.billing.clock.Clock;
 import com.ning.billing.clock.DefaultClock;
 import com.ning.billing.subscription.api.SubscriptionApiBase;
 import com.ning.billing.subscription.api.user.DefaultEffectiveSubscriptionEvent;
-import com.ning.billing.subscription.api.user.DefaultSubscriptionApiService;
+import com.ning.billing.subscription.api.user.DefaultSubscriptionBase;
+import com.ning.billing.subscription.api.user.DefaultSubscriptionBaseApiService;
+import com.ning.billing.subscription.api.user.DefaultSubscriptionBaseBundle;
 import com.ning.billing.subscription.api.user.DefaultSubscriptionStatusDryRun;
 import com.ning.billing.subscription.api.SubscriptionBase;
 import com.ning.billing.subscription.api.user.SubscriptionBaseApiException;
 import com.ning.billing.subscription.api.user.SubscriptionBaseTransition;
 import com.ning.billing.subscription.api.user.SubscriptionBuilder;
 import com.ning.billing.subscription.api.user.SubscriptionBaseBundle;
-import com.ning.billing.subscription.api.user.SubscriptionBundleData;
-import com.ning.billing.subscription.api.user.SubscriptionData;
 import com.ning.billing.subscription.api.user.SubscriptionState;
 import com.ning.billing.subscription.api.user.SubscriptionStatusDryRun;
 import com.ning.billing.subscription.api.user.SubscriptionStatusDryRun.DryRunChangeReason;
 import com.ning.billing.subscription.api.user.SubscriptionBaseTransitionData;
 import com.ning.billing.subscription.engine.addon.AddonUtils;
 import com.ning.billing.subscription.engine.dao.SubscriptionDao;
-import com.ning.billing.subscription.exceptions.SubscriptionError;
+import com.ning.billing.subscription.exceptions.SubscriptionBaseError;
 import com.ning.billing.util.callcontext.InternalCallContext;
 import com.ning.billing.util.callcontext.InternalTenantContext;
 import com.ning.billing.util.events.EffectiveSubscriptionInternalEvent;
@@ -73,7 +73,7 @@ public class DefaultSubscriptionInternalApi extends SubscriptionApiBase implemen
 
     @Inject
     public DefaultSubscriptionInternalApi(final SubscriptionDao dao,
-                                          final DefaultSubscriptionApiService apiService,
+                                          final DefaultSubscriptionBaseApiService apiService,
                                           final Clock clock,
                                           final CatalogService catalogService,
                                           final AddonUtils addonUtils) {
@@ -97,7 +97,7 @@ public class DefaultSubscriptionInternalApi extends SubscriptionApiBase implemen
 
             final PlanPhase phase = plan.getAllPhases()[0];
             if (phase == null) {
-                throw new SubscriptionError(String.format("No initial PlanPhase for Product %s, term %s and set %s does not exist in the catalog",
+                throw new SubscriptionBaseError(String.format("No initial PlanPhase for Product %s, term %s and set %s does not exist in the catalog",
                                                           spec.getProductName(), spec.getBillingPeriod().toString(), realPriceList));
             }
 
@@ -107,7 +107,7 @@ public class DefaultSubscriptionInternalApi extends SubscriptionApiBase implemen
             }
 
             DateTime bundleStartDate = null;
-            final SubscriptionData baseSubscription = (SubscriptionData) dao.getBaseSubscription(bundleId, context);
+            final DefaultSubscriptionBase baseSubscription = (DefaultSubscriptionBase) dao.getBaseSubscription(bundleId, context);
             switch (plan.getProduct().getCategory()) {
                 case BASE:
                     if (baseSubscription != null) {
@@ -140,7 +140,7 @@ public class DefaultSubscriptionInternalApi extends SubscriptionApiBase implemen
                     bundleStartDate = requestedDate;
                     break;
                 default:
-                    throw new SubscriptionError(String.format("Can't create subscription of type %s",
+                    throw new SubscriptionBaseError(String.format("Can't create subscription of type %s",
                                                               plan.getProduct().getCategory().toString()));
             }
 
@@ -158,7 +158,7 @@ public class DefaultSubscriptionInternalApi extends SubscriptionApiBase implemen
 
     @Override
     public SubscriptionBaseBundle createBundleForAccount(final UUID accountId, final String bundleName, final InternalCallContext context) throws SubscriptionBaseApiException {
-        final SubscriptionBundleData bundle = new SubscriptionBundleData(bundleName, accountId, clock.getUTCNow());
+        final DefaultSubscriptionBaseBundle bundle = new DefaultSubscriptionBaseBundle(bundleName, accountId, clock.getUTCNow());
         return dao.createSubscriptionBundle(bundle, context);
     }
 
@@ -221,23 +221,23 @@ public class DefaultSubscriptionInternalApi extends SubscriptionApiBase implemen
     @Override
     public void setChargedThroughDate(UUID subscriptionId,
                                       DateTime chargedThruDate, InternalCallContext context) {
-        final SubscriptionData subscription = (SubscriptionData) dao.getSubscriptionFromId(subscriptionId, context);
+        final DefaultSubscriptionBase subscription = (DefaultSubscriptionBase) dao.getSubscriptionFromId(subscriptionId, context);
         final SubscriptionBuilder builder = new SubscriptionBuilder(subscription)
                 .setChargedThroughDate(chargedThruDate)
                 .setPaidThroughDate(subscription.getPaidThroughDate());
 
-        dao.updateChargedThroughDate(new SubscriptionData(builder), context);
+        dao.updateChargedThroughDate(new DefaultSubscriptionBase(builder), context);
     }
 
     @Override
     public List<EffectiveSubscriptionInternalEvent> getAllTransitions(final SubscriptionBase subscription, final InternalTenantContext context) {
-        final List<SubscriptionBaseTransition> transitions = ((SubscriptionData) subscription).getAllTransitions();
+        final List<SubscriptionBaseTransition> transitions = ((DefaultSubscriptionBase) subscription).getAllTransitions();
         return convertEffectiveSubscriptionInternalEventFromSubscriptionTransitions(subscription, context, transitions);
     }
 
     @Override
     public List<EffectiveSubscriptionInternalEvent> getBillingTransitions(final SubscriptionBase subscription, final InternalTenantContext context) {
-        final List<SubscriptionBaseTransition> transitions = ((SubscriptionData) subscription).getBillingTransitions();
+        final List<SubscriptionBaseTransition> transitions = ((DefaultSubscriptionBase) subscription).getBillingTransitions();
         return convertEffectiveSubscriptionInternalEventFromSubscriptionTransitions(subscription, context, transitions);
     }
 
@@ -306,7 +306,7 @@ public class DefaultSubscriptionInternalApi extends SubscriptionApiBase implemen
             @Override
             @Nullable
             public EffectiveSubscriptionInternalEvent apply(@Nullable SubscriptionBaseTransition input) {
-                return new DefaultEffectiveSubscriptionEvent((SubscriptionBaseTransitionData) input, ((SubscriptionData) subscription).getAlignStartDate(), null, context.getAccountRecordId(), context.getTenantRecordId());
+                return new DefaultEffectiveSubscriptionEvent((SubscriptionBaseTransitionData) input, ((DefaultSubscriptionBase) subscription).getAlignStartDate(), null, context.getAccountRecordId(), context.getTenantRecordId());
             }
         }));
     }
diff --git a/subscription/src/main/java/com/ning/billing/subscription/api/timeline/DefaultDeletedEvent.java b/subscription/src/main/java/com/ning/billing/subscription/api/timeline/DefaultDeletedEvent.java
index e3f3675..033f280 100644
--- a/subscription/src/main/java/com/ning/billing/subscription/api/timeline/DefaultDeletedEvent.java
+++ b/subscription/src/main/java/com/ning/billing/subscription/api/timeline/DefaultDeletedEvent.java
@@ -19,7 +19,7 @@ import java.util.UUID;
 
 import org.joda.time.DateTime;
 
-import com.ning.billing.subscription.api.timeline.SubscriptionTimeline.DeletedEvent;
+import com.ning.billing.subscription.api.timeline.SubscriptionBaseTimeline.DeletedEvent;
 
 public class DefaultDeletedEvent implements DeletedEvent {
 
diff --git a/subscription/src/main/java/com/ning/billing/subscription/api/timeline/DefaultNewEvent.java b/subscription/src/main/java/com/ning/billing/subscription/api/timeline/DefaultNewEvent.java
index 5c6da3c..95e0a7a 100644
--- a/subscription/src/main/java/com/ning/billing/subscription/api/timeline/DefaultNewEvent.java
+++ b/subscription/src/main/java/com/ning/billing/subscription/api/timeline/DefaultNewEvent.java
@@ -21,7 +21,7 @@ import org.joda.time.DateTime;
 
 import com.ning.billing.catalog.api.PlanPhaseSpecifier;
 import com.ning.billing.subscription.api.SubscriptionBaseTransitionType;
-import com.ning.billing.subscription.api.timeline.SubscriptionTimeline.NewEvent;
+import com.ning.billing.subscription.api.timeline.SubscriptionBaseTimeline.NewEvent;
 
 public class DefaultNewEvent implements NewEvent {
 
diff --git a/subscription/src/main/java/com/ning/billing/subscription/api/timeline/DefaultSubscriptionBaseTimeline.java b/subscription/src/main/java/com/ning/billing/subscription/api/timeline/DefaultSubscriptionBaseTimeline.java
new file mode 100644
index 0000000..2988a79
--- /dev/null
+++ b/subscription/src/main/java/com/ning/billing/subscription/api/timeline/DefaultSubscriptionBaseTimeline.java
@@ -0,0 +1,320 @@
+/*
+ * Copyright 2010-2013 Ning, Inc.
+ *
+ * Ning licenses this file to you under the Apache License, version 2.0
+ * (the "License"); you may not use this file except in compliance with the
+ * License.  You may obtain a copy of the License at:
+ *
+ *    http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
+ * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.  See the
+ * License for the specific language governing permissions and limitations
+ * under the License.
+ */
+
+package com.ning.billing.subscription.api.timeline;
+
+import java.util.ArrayList;
+import java.util.Collections;
+import java.util.Comparator;
+import java.util.LinkedList;
+import java.util.List;
+import java.util.UUID;
+
+import org.joda.time.DateTime;
+
+import com.ning.billing.catalog.api.BillingPeriod;
+import com.ning.billing.catalog.api.Catalog;
+import com.ning.billing.catalog.api.CatalogApiException;
+import com.ning.billing.catalog.api.PhaseType;
+import com.ning.billing.catalog.api.Plan;
+import com.ning.billing.catalog.api.PlanPhaseSpecifier;
+import com.ning.billing.catalog.api.ProductCategory;
+import com.ning.billing.subscription.api.SubscriptionBaseTransitionType;
+import com.ning.billing.subscription.api.user.SubscriptionBaseTransitionData;
+import com.ning.billing.subscription.events.SubscriptionEvent;
+import com.ning.billing.subscription.events.phase.PhaseEvent;
+import com.ning.billing.subscription.events.user.ApiEvent;
+import com.ning.billing.subscription.events.user.ApiEventType;
+
+
+public class DefaultSubscriptionBaseTimeline implements SubscriptionBaseTimeline {
+
+    private final UUID id;
+    private final List<ExistingEvent> existingEvents;
+    private final List<NewEvent> newEvents;
+    private final List<DeletedEvent> deletedEvents;
+    private final long activeVersion;
+
+    public DefaultSubscriptionBaseTimeline(final UUID id, final long activeVersion) {
+        this.id = id;
+        this.activeVersion = activeVersion;
+        this.existingEvents = Collections.<SubscriptionBaseTimeline.ExistingEvent>emptyList();
+        this.deletedEvents = Collections.<SubscriptionBaseTimeline.DeletedEvent>emptyList();
+        this.newEvents = Collections.<SubscriptionBaseTimeline.NewEvent>emptyList();
+    }
+
+    public DefaultSubscriptionBaseTimeline(final SubscriptionBaseTimeline input) {
+        this.id = input.getId();
+        this.activeVersion = input.getActiveVersion();
+        this.existingEvents = (input.getExistingEvents() != null) ? new ArrayList<SubscriptionBaseTimeline.ExistingEvent>(input.getExistingEvents()) :
+                              Collections.<SubscriptionBaseTimeline.ExistingEvent>emptyList();
+        sortExistingEvent(this.existingEvents);
+        this.deletedEvents = (input.getDeletedEvents() != null) ? new ArrayList<SubscriptionBaseTimeline.DeletedEvent>(input.getDeletedEvents()) :
+                             Collections.<SubscriptionBaseTimeline.DeletedEvent>emptyList();
+        this.newEvents = (input.getNewEvents() != null) ? new ArrayList<SubscriptionBaseTimeline.NewEvent>(input.getNewEvents()) :
+                         Collections.<SubscriptionBaseTimeline.NewEvent>emptyList();
+        sortNewEvent(this.newEvents);
+    }
+
+    // CTOR for returning events only
+    public DefaultSubscriptionBaseTimeline(final SubscriptionDataRepair input, final Catalog catalog) throws CatalogApiException {
+        this.id = input.getId();
+        this.existingEvents = toExistingEvents(catalog, input.getActiveVersion(), input.getCategory(), input.getEvents());
+        this.deletedEvents = null;
+        this.newEvents = null;
+        this.activeVersion = input.getActiveVersion();
+    }
+
+    private List<ExistingEvent> toExistingEvents(final Catalog catalog, final long activeVersion, final ProductCategory category, final List<SubscriptionEvent> events)
+            throws CatalogApiException {
+
+        final List<ExistingEvent> result = new LinkedList<SubscriptionBaseTimeline.ExistingEvent>();
+
+        String prevProductName = null;
+        BillingPeriod prevBillingPeriod = null;
+        String prevPriceListName = null;
+        PhaseType prevPhaseType = null;
+
+        DateTime startDate = null;
+
+        for (final SubscriptionEvent cur : events) {
+
+            // First active event is used to figure out which catalog version to use.
+            //startDate = (startDate == null && cur.getActiveVersion() == activeVersion) ?  cur.getEffectiveDate() : startDate;
+
+            // STEPH that needs to be reviewed if we support multi version events
+            if (cur.getActiveVersion() != activeVersion || !cur.isActive()) {
+                continue;
+            }
+            startDate = (startDate == null) ? cur.getEffectiveDate() : startDate;
+
+
+            String productName = null;
+            BillingPeriod billingPeriod = null;
+            String priceListName = null;
+            PhaseType phaseType = null;
+            String planPhaseName = null;
+
+            ApiEventType apiType = null;
+            switch (cur.getType()) {
+                case PHASE:
+                    final PhaseEvent phaseEV = (PhaseEvent) cur;
+                    planPhaseName = phaseEV.getPhase();
+                    phaseType = catalog.findPhase(phaseEV.getPhase(), cur.getEffectiveDate(), startDate).getPhaseType();
+                    productName = prevProductName;
+                    billingPeriod = catalog.findPhase(phaseEV.getPhase(), cur.getEffectiveDate(), startDate).getBillingPeriod();
+                    priceListName = prevPriceListName;
+                    break;
+
+                case API_USER:
+                    final ApiEvent userEV = (ApiEvent) cur;
+                    apiType = userEV.getEventType();
+                    planPhaseName = userEV.getEventPlanPhase();
+                    final Plan plan = (userEV.getEventPlan() != null) ? catalog.findPlan(userEV.getEventPlan(), cur.getRequestedDate(), startDate) : null;
+                    phaseType = (userEV.getEventPlanPhase() != null) ? catalog.findPhase(userEV.getEventPlanPhase(), cur.getEffectiveDate(), startDate).getPhaseType() : prevPhaseType;
+                    productName = (plan != null) ? plan.getProduct().getName() : prevProductName;
+                    billingPeriod = (userEV.getEventPlanPhase() != null) ? catalog.findPhase(userEV.getEventPlanPhase(), cur.getEffectiveDate(), startDate).getBillingPeriod() : prevBillingPeriod;
+                    priceListName = (userEV.getPriceList() != null) ? userEV.getPriceList() : prevPriceListName;
+                    break;
+            }
+
+            final SubscriptionBaseTransitionType transitionType = SubscriptionBaseTransitionData.toSubscriptionTransitionType(cur.getType(), apiType);
+
+            final String planPhaseNameWithClosure = planPhaseName;
+            final PlanPhaseSpecifier spec = new PlanPhaseSpecifier(productName, category, billingPeriod, priceListName, phaseType);
+            result.add(new ExistingEvent() {
+                @Override
+                public SubscriptionBaseTransitionType getSubscriptionTransitionType() {
+                    return transitionType;
+                }
+
+                @Override
+                public DateTime getRequestedDate() {
+                    return cur.getRequestedDate();
+                }
+
+                @Override
+                public PlanPhaseSpecifier getPlanPhaseSpecifier() {
+                    return spec;
+                }
+
+                @Override
+                public UUID getEventId() {
+                    return cur.getId();
+                }
+
+                @Override
+                public DateTime getEffectiveDate() {
+                    return cur.getEffectiveDate();
+                }
+
+                @Override
+                public String getPlanPhaseName() {
+                    return planPhaseNameWithClosure;
+                }
+            });
+
+            prevProductName = productName;
+            prevBillingPeriod = billingPeriod;
+            prevPriceListName = priceListName;
+            prevPhaseType = phaseType;
+
+        }
+        sortExistingEvent(result);
+        return result;
+    }
+
+
+    /*
+
+    private List<ExistingEvent> toExistingEvents(final Catalog catalog, final long processingVersion, final ProductCategory category, final List<SubscriptionEvent> events, List<ExistingEvent> result)
+        throws CatalogApiException {
+
+
+        String prevProductName = null;
+        BillingPeriod prevBillingPeriod = null;
+        String prevPriceListName = null;
+        PhaseType prevPhaseType = null;
+
+        DateTime startDate = null;
+
+        for (final SubscriptionEvent cur : events) {
+
+            if (processingVersion != cur.getActiveVersion()) {
+                continue;
+            }
+
+            // First active event is used to figure out which catalog version to use.
+            startDate = (startDate == null && cur.getActiveVersion() == processingVersion) ?  cur.getEffectiveDate() : startDate;
+
+            String productName = null;
+            BillingPeriod billingPeriod = null;
+            String priceListName = null;
+            PhaseType phaseType = null;
+
+            ApiEventType apiType = null;
+            switch (cur.getType()) {
+            case PHASE:
+                PhaseEvent phaseEV = (PhaseEvent) cur;
+                phaseType = catalog.findPhase(phaseEV.getPhase(), cur.getEffectiveDate(), startDate).getPhaseType();
+                productName = prevProductName;
+                billingPeriod = prevBillingPeriod;
+                priceListName = prevPriceListName;
+                break;
+
+            case API_USER:
+                ApiEvent userEV = (ApiEvent) cur;
+                apiType = userEV.getEventType();
+                Plan plan =  (userEV.getEventPlan() != null) ? catalog.findPlan(userEV.getEventPlan(), cur.getRequestedDate(), startDate) : null;
+                phaseType = (userEV.getEventPlanPhase() != null) ? catalog.findPhase(userEV.getEventPlanPhase(), cur.getEffectiveDate(), startDate).getPhaseType() : prevPhaseType;
+                productName = (plan != null) ? plan.getProduct().getName() : prevProductName;
+                billingPeriod = (plan != null) ? plan.getBillingPeriod() : prevBillingPeriod;
+                priceListName = (userEV.getPriceList() != null) ? userEV.getPriceList() : prevPriceListName;
+                break;
+            }
+
+            final SubscriptionBaseTransitionType transitionType = SubscriptionBaseTransitionData.toSubscriptionTransitionType(cur.getType(), apiType);
+
+            final PlanPhaseSpecifier spec = new PlanPhaseSpecifier(productName, category, billingPeriod, priceListName, phaseType);
+            result.add(new ExistingEvent() {
+                @Override
+                public SubscriptionBaseTransitionType getSubscriptionTransitionType() {
+                    return transitionType;
+                }
+                @Override
+                public DateTime getRequestedDate() {
+                    return cur.getRequestedDate();
+                }
+                @Override
+                public PlanPhaseSpecifier getPlanPhaseSpecifier() {
+                    return spec;
+                }
+                @Override
+                public UUID getEventId() {
+                    return cur.getId();
+                }
+                @Override
+                public DateTime getEffectiveDate() {
+                    return cur.getEffectiveDate();
+                }
+            });
+            prevProductName = productName;
+            prevBillingPeriod = billingPeriod;
+            prevPriceListName = priceListName;
+            prevPhaseType = phaseType;
+        }
+    }
+    */
+
+
+    @Override
+    public UUID getId() {
+        return id;
+    }
+
+    @Override
+    public DateTime getCreatedDate() {
+        throw new UnsupportedOperationException();
+    }
+
+    @Override
+    public DateTime getUpdatedDate() {
+        throw new UnsupportedOperationException();
+    }
+
+    @Override
+    public List<DeletedEvent> getDeletedEvents() {
+        return deletedEvents;
+    }
+
+    @Override
+    public List<NewEvent> getNewEvents() {
+        return newEvents;
+    }
+
+    @Override
+    public List<ExistingEvent> getExistingEvents() {
+        return existingEvents;
+    }
+
+    @Override
+    public long getActiveVersion() {
+        return activeVersion;
+    }
+
+
+    private void sortExistingEvent(final List<ExistingEvent> events) {
+        if (events != null) {
+            Collections.sort(events, new Comparator<ExistingEvent>() {
+                @Override
+                public int compare(final ExistingEvent arg0, final ExistingEvent arg1) {
+                    return arg0.getEffectiveDate().compareTo(arg1.getEffectiveDate());
+                }
+            });
+        }
+    }
+
+    private void sortNewEvent(final List<NewEvent> events) {
+        if (events != null) {
+            Collections.sort(events, new Comparator<NewEvent>() {
+                @Override
+                public int compare(final NewEvent arg0, final NewEvent arg1) {
+                    return arg0.getRequestedDate().compareTo(arg1.getRequestedDate());
+                }
+            });
+        }
+    }
+}
diff --git a/subscription/src/main/java/com/ning/billing/subscription/api/timeline/DefaultSubscriptionBaseTimelineApi.java b/subscription/src/main/java/com/ning/billing/subscription/api/timeline/DefaultSubscriptionBaseTimelineApi.java
new file mode 100644
index 0000000..68f9936
--- /dev/null
+++ b/subscription/src/main/java/com/ning/billing/subscription/api/timeline/DefaultSubscriptionBaseTimelineApi.java
@@ -0,0 +1,507 @@
+/*
+ * Copyright 2010-2013 Ning, Inc.
+ *
+ * Ning licenses this file to you under the Apache License, version 2.0
+ * (the "License"); you may not use this file except in compliance with the
+ * License.  You may obtain a copy of the License at:
+ *
+ *    http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
+ * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.  See the
+ * License for the specific language governing permissions and limitations
+ * under the License.
+ */
+
+package com.ning.billing.subscription.api.timeline;
+
+import java.util.ArrayList;
+import java.util.Collection;
+import java.util.Collections;
+import java.util.Comparator;
+import java.util.LinkedList;
+import java.util.List;
+import java.util.Set;
+import java.util.TreeSet;
+import java.util.UUID;
+
+import javax.annotation.Nullable;
+
+import org.joda.time.DateTime;
+
+import com.ning.billing.ErrorCode;
+import com.ning.billing.catalog.api.CatalogApiException;
+import com.ning.billing.catalog.api.CatalogService;
+import com.ning.billing.catalog.api.ProductCategory;
+import com.ning.billing.subscription.api.SubscriptionApiBase;
+import com.ning.billing.subscription.api.SubscriptionBaseApiService;
+import com.ning.billing.subscription.api.SubscriptionBaseTransitionType;
+import com.ning.billing.subscription.api.user.DefaultSubscriptionBaseBundle;
+import com.ning.billing.subscription.api.user.SubscriptionBaseBundle;
+import com.ning.billing.subscription.api.user.SubscriptionBaseTransition;
+import com.ning.billing.subscription.api.user.SubscriptionBuilder;
+import com.ning.billing.subscription.api.user.DefaultSubscriptionBase;
+import com.ning.billing.subscription.api.user.SubscriptionBaseTransitionData;
+import com.ning.billing.subscription.engine.addon.AddonUtils;
+import com.ning.billing.subscription.engine.dao.SubscriptionDao;
+import com.ning.billing.subscription.events.SubscriptionEvent;
+import com.ning.billing.subscription.glue.DefaultSubscriptionModule;
+import com.ning.billing.subscription.api.timeline.SubscriptionBaseTimeline.NewEvent;
+import com.ning.billing.subscription.api.SubscriptionBase;
+import com.ning.billing.util.callcontext.CallContext;
+import com.ning.billing.util.callcontext.InternalCallContextFactory;
+import com.ning.billing.util.callcontext.InternalTenantContext;
+import com.ning.billing.util.callcontext.TenantContext;
+import com.ning.billing.clock.Clock;
+
+import com.google.common.base.Function;
+import com.google.common.collect.Collections2;
+import com.google.inject.Inject;
+import com.google.inject.name.Named;
+
+public class DefaultSubscriptionBaseTimelineApi extends SubscriptionApiBase implements SubscriptionBaseTimelineApi {
+
+    private final RepairSubscriptionLifecycleDao repairDao;
+    private final CatalogService catalogService;
+    private final InternalCallContextFactory internalCallContextFactory;
+    private final AddonUtils addonUtils;
+
+    private final SubscriptionBaseApiService repairApiService;
+
+    private enum RepairType {
+        BASE_REPAIR,
+        ADD_ON_REPAIR,
+        STANDALONE_REPAIR
+    }
+
+    @Inject
+    public DefaultSubscriptionBaseTimelineApi(final CatalogService catalogService,
+                                              final SubscriptionBaseApiService apiService,
+                                              @Named(DefaultSubscriptionModule.REPAIR_NAMED) final RepairSubscriptionLifecycleDao repairDao, final SubscriptionDao dao,
+                                              @Named(DefaultSubscriptionModule.REPAIR_NAMED) final SubscriptionBaseApiService repairApiService,
+                                              final InternalCallContextFactory internalCallContextFactory, final Clock clock, final AddonUtils addonUtils) {
+        super(dao, apiService, clock, catalogService);
+        this.catalogService = catalogService;
+        this.repairDao = repairDao;
+        this.internalCallContextFactory = internalCallContextFactory;
+        this.repairApiService = repairApiService;
+        this.addonUtils = addonUtils;
+    }
+
+    @Override
+    public BundleBaseTimeline getBundleTimeline(final SubscriptionBaseBundle bundle, final TenantContext context)
+            throws SubscriptionBaseRepairException {
+        return getBundleTimelineInternal(bundle, bundle.getExternalKey(), context);
+    }
+
+    @Override
+    public BundleBaseTimeline getBundleTimeline(final UUID accountId, final String bundleName, final TenantContext context)
+            throws SubscriptionBaseRepairException {
+        final SubscriptionBaseBundle bundle = dao.getSubscriptionBundleFromAccountAndKey(accountId, bundleName, internalCallContextFactory.createInternalTenantContext(context));
+        return getBundleTimelineInternal(bundle, bundleName + " [accountId= " + accountId.toString() + "]", context);
+    }
+
+    @Override
+    public BundleBaseTimeline getBundleTimeline(final UUID bundleId, final TenantContext context) throws SubscriptionBaseRepairException {
+
+        final SubscriptionBaseBundle bundle = dao.getSubscriptionBundleFromId(bundleId, internalCallContextFactory.createInternalTenantContext(context));
+        return getBundleTimelineInternal(bundle, bundleId.toString(), context);
+    }
+
+    private BundleBaseTimeline getBundleTimelineInternal(final SubscriptionBaseBundle bundle, final String descBundle, final TenantContext context) throws SubscriptionBaseRepairException {
+        try {
+            if (bundle == null) {
+                throw new SubscriptionBaseRepairException(ErrorCode.SUB_REPAIR_UNKNOWN_BUNDLE, descBundle);
+            }
+            final List<SubscriptionDataRepair> subscriptions = convertToSubscriptionsDataRepair(dao.getSubscriptions(bundle.getId(), internalCallContextFactory.createInternalTenantContext(context)));
+            if (subscriptions.size() == 0) {
+                throw new SubscriptionBaseRepairException(ErrorCode.SUB_REPAIR_NO_ACTIVE_SUBSCRIPTIONS, bundle.getId());
+            }
+            final String viewId = getViewId(((DefaultSubscriptionBaseBundle) bundle).getLastSysUpdateDate(), subscriptions);
+            final List<SubscriptionBaseTimeline> repairs = createGetSubscriptionRepairList(subscriptions, Collections.<SubscriptionBaseTimeline>emptyList());
+            return createGetBundleRepair(bundle.getId(), bundle.getExternalKey(), viewId, repairs);
+        } catch (CatalogApiException e) {
+            throw new SubscriptionBaseRepairException(e);
+        }
+    }
+
+    private List<SubscriptionDataRepair> convertToSubscriptionsDataRepair(List<SubscriptionBase> input) {
+        return new ArrayList<SubscriptionDataRepair>(Collections2.transform(input, new Function<SubscriptionBase, SubscriptionDataRepair>() {
+            @Override
+            public SubscriptionDataRepair apply(@Nullable final SubscriptionBase subscription) {
+                return convertToSubscriptionDataRepair((DefaultSubscriptionBase) subscription);
+            }
+        }));
+    }
+    private SubscriptionDataRepair convertToSubscriptionDataRepair(DefaultSubscriptionBase input) {
+        return new SubscriptionDataRepair(input, repairApiService, (SubscriptionDao) repairDao, clock, addonUtils, catalogService, internalCallContextFactory);
+    }
+
+    @Override
+    public BundleBaseTimeline repairBundle(final BundleBaseTimeline input, final boolean dryRun, final CallContext context) throws SubscriptionBaseRepairException {
+        final InternalTenantContext tenantContext = internalCallContextFactory.createInternalTenantContext(context);
+        try {
+            final SubscriptionBaseBundle bundle = dao.getSubscriptionBundleFromId(input.getId(), tenantContext);
+            if (bundle == null) {
+                throw new SubscriptionBaseRepairException(ErrorCode.SUB_REPAIR_UNKNOWN_BUNDLE, input.getId());
+            }
+
+            // Subscriptions are ordered with BASE subscription first-- if exists
+            final List<SubscriptionDataRepair> subscriptions = convertToSubscriptionsDataRepair(dao.getSubscriptions(input.getId(), tenantContext));
+            if (subscriptions.size() == 0) {
+                throw new SubscriptionBaseRepairException(ErrorCode.SUB_REPAIR_NO_ACTIVE_SUBSCRIPTIONS, input.getId());
+            }
+
+            final String viewId = getViewId(((DefaultSubscriptionBaseBundle) bundle).getLastSysUpdateDate(), subscriptions);
+            if (!viewId.equals(input.getViewId())) {
+                throw new SubscriptionBaseRepairException(ErrorCode.SUB_REPAIR_VIEW_CHANGED, input.getId(), input.getViewId(), viewId);
+            }
+
+            DateTime firstDeletedBPEventTime = null;
+            DateTime lastRemainingBPEventTime = null;
+
+            boolean isBasePlanRecreate = false;
+            DateTime newBundleStartDate = null;
+
+            SubscriptionDataRepair baseSubscriptionRepair = null;
+            final List<SubscriptionDataRepair> addOnSubscriptionInRepair = new LinkedList<SubscriptionDataRepair>();
+            final List<SubscriptionDataRepair> inRepair = new LinkedList<SubscriptionDataRepair>();
+            for (final SubscriptionBase cur : subscriptions) {
+                final SubscriptionBaseTimeline curRepair = findAndCreateSubscriptionRepair(cur.getId(), input.getSubscriptions());
+                if (curRepair != null) {
+                    final SubscriptionDataRepair curInputRepair = ((SubscriptionDataRepair) cur);
+                    final List<SubscriptionEvent> remaining = getRemainingEventsAndValidateDeletedEvents(curInputRepair, firstDeletedBPEventTime, curRepair.getDeletedEvents());
+
+                    final boolean isPlanRecreate = (curRepair.getNewEvents().size() > 0
+                                                    && (curRepair.getNewEvents().get(0).getSubscriptionTransitionType() == SubscriptionBaseTransitionType.CREATE
+                                                        || curRepair.getNewEvents().get(0).getSubscriptionTransitionType() == SubscriptionBaseTransitionType.RE_CREATE));
+
+                    final DateTime newSubscriptionStartDate = isPlanRecreate ? curRepair.getNewEvents().get(0).getRequestedDate() : null;
+
+                    if (isPlanRecreate && remaining.size() != 0) {
+                        throw new SubscriptionBaseRepairException(ErrorCode.SUB_REPAIR_SUB_RECREATE_NOT_EMPTY, cur.getId(), cur.getBundleId());
+                    }
+
+                    if (!isPlanRecreate && remaining.size() == 0) {
+                        throw new SubscriptionBaseRepairException(ErrorCode.SUB_REPAIR_SUB_EMPTY, cur.getId(), cur.getBundleId());
+                    }
+
+                    if (cur.getCategory() == ProductCategory.BASE) {
+
+                        final int bpTransitionSize = ((DefaultSubscriptionBase) cur).getAllTransitions().size();
+                        lastRemainingBPEventTime = (remaining.size() > 0) ? curInputRepair.getAllTransitions().get(remaining.size() - 1).getEffectiveTransitionTime() : null;
+                        firstDeletedBPEventTime = (remaining.size() < bpTransitionSize) ? curInputRepair.getAllTransitions().get(remaining.size()).getEffectiveTransitionTime() : null;
+
+                        isBasePlanRecreate = isPlanRecreate;
+                        newBundleStartDate = newSubscriptionStartDate;
+                    }
+
+                    if (curRepair.getNewEvents().size() > 0) {
+                        final DateTime lastRemainingEventTime = (remaining.size() == 0) ? null : curInputRepair.getAllTransitions().get(remaining.size() - 1).getEffectiveTransitionTime();
+                        validateFirstNewEvent(curInputRepair, curRepair.getNewEvents().get(0), lastRemainingBPEventTime, lastRemainingEventTime);
+                    }
+
+                    final SubscriptionDataRepair curOutputRepair = createSubscriptionDataRepair(curInputRepair, newBundleStartDate, newSubscriptionStartDate, remaining);
+                    repairDao.initializeRepair(curInputRepair.getId(), remaining, tenantContext);
+                    inRepair.add(curOutputRepair);
+                    if (curOutputRepair.getCategory() == ProductCategory.ADD_ON) {
+                        // Check if ADD_ON RE_CREATE is before BP start
+                        if (isPlanRecreate && (subscriptions.get(0)).getStartDate().isAfter(curRepair.getNewEvents().get(0).getRequestedDate())) {
+                            throw new SubscriptionBaseRepairException(ErrorCode.SUB_REPAIR_AO_CREATE_BEFORE_BP_START, cur.getId(), cur.getBundleId());
+                        }
+                        addOnSubscriptionInRepair.add(curOutputRepair);
+                    } else if (curOutputRepair.getCategory() == ProductCategory.BASE) {
+                        baseSubscriptionRepair = curOutputRepair;
+                    }
+                }
+            }
+
+            final RepairType repairType = getRepairType(subscriptions.get(0), (baseSubscriptionRepair != null));
+            switch (repairType) {
+                case BASE_REPAIR:
+                    // We need to add any existing addon that are not in the input repair list
+                    for (final SubscriptionBase cur : subscriptions) {
+                        if (cur.getCategory() == ProductCategory.ADD_ON && !inRepair.contains(cur)) {
+                            final SubscriptionDataRepair curOutputRepair = createSubscriptionDataRepair((SubscriptionDataRepair) cur, newBundleStartDate, null, ((SubscriptionDataRepair) cur).getEvents());
+                            repairDao.initializeRepair(curOutputRepair.getId(), ((SubscriptionDataRepair) cur).getEvents(), tenantContext);
+                            inRepair.add(curOutputRepair);
+                            addOnSubscriptionInRepair.add(curOutputRepair);
+                        }
+                    }
+                    break;
+                case ADD_ON_REPAIR:
+                    // We need to set the baseSubscription as it is useful to calculate addon validity
+                    final SubscriptionDataRepair baseSubscription = (SubscriptionDataRepair) subscriptions.get(0);
+                    baseSubscriptionRepair = createSubscriptionDataRepair(baseSubscription, baseSubscription.getBundleStartDate(), baseSubscription.getAlignStartDate(), baseSubscription.getEvents());
+                    break;
+                case STANDALONE_REPAIR:
+                default:
+                    break;
+            }
+
+            validateBasePlanRecreate(isBasePlanRecreate, subscriptions, input.getSubscriptions());
+            validateInputSubscriptionsKnown(subscriptions, input.getSubscriptions());
+
+            final Collection<NewEvent> newEvents = createOrderedNewEventInput(input.getSubscriptions());
+            for (final NewEvent newEvent : newEvents) {
+                final DefaultNewEvent cur = (DefaultNewEvent) newEvent;
+                final SubscriptionDataRepair curDataRepair = findSubscriptionDataRepair(cur.getSubscriptionId(), inRepair);
+                if (curDataRepair == null) {
+                    throw new SubscriptionBaseRepairException(ErrorCode.SUB_REPAIR_UNKNOWN_SUBSCRIPTION, cur.getSubscriptionId());
+                }
+                curDataRepair.addNewRepairEvent(cur, baseSubscriptionRepair, addOnSubscriptionInRepair, context);
+            }
+
+            if (dryRun) {
+                baseSubscriptionRepair.addFutureAddonCancellation(addOnSubscriptionInRepair, context);
+
+                final List<SubscriptionBaseTimeline> repairs = createGetSubscriptionRepairList(subscriptions, convertDataRepair(inRepair));
+                return createGetBundleRepair(input.getId(), bundle.getExternalKey(), input.getViewId(), repairs);
+            } else {
+                dao.repair(bundle.getAccountId(), input.getId(), inRepair, internalCallContextFactory.createInternalCallContext(bundle.getAccountId(), context));
+                return getBundleTimeline(input.getId(), context);
+            }
+        } catch (CatalogApiException e) {
+            throw new SubscriptionBaseRepairException(e);
+        } finally {
+            repairDao.cleanup(tenantContext);
+        }
+    }
+
+    private RepairType getRepairType(final SubscriptionBase firstSubscription, final boolean gotBaseSubscription) {
+        if (firstSubscription.getCategory() == ProductCategory.BASE) {
+            return gotBaseSubscription ? RepairType.BASE_REPAIR : RepairType.ADD_ON_REPAIR;
+        } else {
+            return RepairType.STANDALONE_REPAIR;
+        }
+    }
+
+    private void validateBasePlanRecreate(final boolean isBasePlanRecreate, final List<SubscriptionDataRepair> subscriptions, final List<SubscriptionBaseTimeline> input)
+            throws SubscriptionBaseRepairException {
+        if (!isBasePlanRecreate) {
+            return;
+        }
+        if (subscriptions.size() != input.size()) {
+            throw new SubscriptionBaseRepairException(ErrorCode.SUB_REPAIR_BP_RECREATE_MISSING_AO, subscriptions.get(0).getBundleId());
+        }
+        for (final SubscriptionBaseTimeline cur : input) {
+            if (cur.getNewEvents().size() != 0
+                && (cur.getNewEvents().get(0).getSubscriptionTransitionType() != SubscriptionBaseTransitionType.CREATE
+                    && cur.getNewEvents().get(0).getSubscriptionTransitionType() != SubscriptionBaseTransitionType.RE_CREATE)) {
+                throw new SubscriptionBaseRepairException(ErrorCode.SUB_REPAIR_BP_RECREATE_MISSING_AO_CREATE, subscriptions.get(0).getBundleId());
+            }
+        }
+    }
+
+    private void validateInputSubscriptionsKnown(final List<SubscriptionDataRepair> subscriptions, final List<SubscriptionBaseTimeline> input)
+            throws SubscriptionBaseRepairException {
+        for (final SubscriptionBaseTimeline cur : input) {
+            boolean found = false;
+            for (final SubscriptionBase s : subscriptions) {
+                if (s.getId().equals(cur.getId())) {
+                    found = true;
+                    break;
+                }
+            }
+            if (!found) {
+                throw new SubscriptionBaseRepairException(ErrorCode.SUB_REPAIR_UNKNOWN_SUBSCRIPTION, cur.getId());
+            }
+        }
+    }
+
+    private void validateFirstNewEvent(final DefaultSubscriptionBase data, final NewEvent firstNewEvent, final DateTime lastBPRemainingTime, final DateTime lastRemainingTime)
+            throws SubscriptionBaseRepairException {
+        if (lastBPRemainingTime != null &&
+            firstNewEvent.getRequestedDate().isBefore(lastBPRemainingTime)) {
+            throw new SubscriptionBaseRepairException(ErrorCode.SUB_REPAIR_NEW_EVENT_BEFORE_LAST_BP_REMAINING, firstNewEvent.getSubscriptionTransitionType(), data.getId());
+        }
+        if (lastRemainingTime != null &&
+            firstNewEvent.getRequestedDate().isBefore(lastRemainingTime)) {
+            throw new SubscriptionBaseRepairException(ErrorCode.SUB_REPAIR_NEW_EVENT_BEFORE_LAST_AO_REMAINING, firstNewEvent.getSubscriptionTransitionType(), data.getId());
+        }
+
+    }
+
+    private Collection<NewEvent> createOrderedNewEventInput(final List<SubscriptionBaseTimeline> subscriptionsReapir) {
+        final TreeSet<NewEvent> newEventSet = new TreeSet<SubscriptionBaseTimeline.NewEvent>(new Comparator<NewEvent>() {
+            @Override
+            public int compare(final NewEvent o1, final NewEvent o2) {
+                return o1.getRequestedDate().compareTo(o2.getRequestedDate());
+            }
+        });
+        for (final SubscriptionBaseTimeline cur : subscriptionsReapir) {
+            for (final NewEvent e : cur.getNewEvents()) {
+                newEventSet.add(new DefaultNewEvent(cur.getId(), e.getPlanPhaseSpecifier(), e.getRequestedDate(), e.getSubscriptionTransitionType()));
+            }
+        }
+
+        return newEventSet;
+    }
+
+    private List<SubscriptionEvent> getRemainingEventsAndValidateDeletedEvents(final SubscriptionDataRepair data, final DateTime firstBPDeletedTime,
+                                                                              final List<SubscriptionBaseTimeline.DeletedEvent> deletedEvents)
+            throws SubscriptionBaseRepairException {
+        if (deletedEvents == null || deletedEvents.size() == 0) {
+            return data.getEvents();
+        }
+
+        int nbDeleted = 0;
+        final LinkedList<SubscriptionEvent> result = new LinkedList<SubscriptionEvent>();
+        for (final SubscriptionEvent cur : data.getEvents()) {
+
+            boolean foundDeletedEvent = false;
+            for (final SubscriptionBaseTimeline.DeletedEvent d : deletedEvents) {
+                if (cur.getId().equals(d.getEventId())) {
+                    foundDeletedEvent = true;
+                    nbDeleted++;
+                    break;
+                }
+            }
+            if (!foundDeletedEvent && nbDeleted > 0) {
+                throw new SubscriptionBaseRepairException(ErrorCode.SUB_REPAIR_INVALID_DELETE_SET, cur.getId(), data.getId());
+            }
+            if (firstBPDeletedTime != null &&
+                !cur.getEffectiveDate().isBefore(firstBPDeletedTime) &&
+                !foundDeletedEvent) {
+                throw new SubscriptionBaseRepairException(ErrorCode.SUB_REPAIR_MISSING_AO_DELETE_EVENT, cur.getId(), data.getId());
+            }
+
+            if (nbDeleted == 0) {
+                result.add(cur);
+            }
+        }
+
+        if (nbDeleted != deletedEvents.size()) {
+            for (final SubscriptionBaseTimeline.DeletedEvent d : deletedEvents) {
+                boolean found = false;
+                for (final SubscriptionBaseTransition cur : data.getAllTransitions()) {
+                    if (((SubscriptionBaseTransitionData) cur).getId().equals(d.getEventId())) {
+                        found = true;
+                    }
+                }
+                if (!found) {
+                    throw new SubscriptionBaseRepairException(ErrorCode.SUB_REPAIR_NON_EXISTENT_DELETE_EVENT, d.getEventId(), data.getId());
+                }
+            }
+
+        }
+
+        return result;
+    }
+
+    private String getViewId(final DateTime lastUpdateBundleDate, final List<SubscriptionDataRepair> subscriptions) {
+        final StringBuilder tmp = new StringBuilder();
+        long lastOrderedId = -1;
+        for (final SubscriptionBase cur : subscriptions) {
+            lastOrderedId = lastOrderedId < ((DefaultSubscriptionBase) cur).getLastEventOrderedId() ? ((DefaultSubscriptionBase) cur).getLastEventOrderedId() : lastOrderedId;
+        }
+        tmp.append(lastOrderedId);
+        tmp.append("-");
+        tmp.append(lastUpdateBundleDate.toDate().getTime());
+
+        return tmp.toString();
+    }
+
+    private BundleBaseTimeline createGetBundleRepair(final UUID bundleId, final String externalKey, final String viewId, final List<SubscriptionBaseTimeline> repairList) {
+        return new BundleBaseTimeline() {
+            @Override
+            public String getViewId() {
+                return viewId;
+            }
+
+            @Override
+            public List<SubscriptionBaseTimeline> getSubscriptions() {
+                return repairList;
+            }
+
+            @Override
+            public UUID getId() {
+                return bundleId;
+            }
+
+            @Override
+            public DateTime getCreatedDate() {
+                throw new UnsupportedOperationException();
+            }
+
+            @Override
+            public DateTime getUpdatedDate() {
+                throw new UnsupportedOperationException();
+            }
+
+            @Override
+            public String getExternalKey() {
+                return externalKey;
+            }
+        };
+    }
+
+    private List<SubscriptionBaseTimeline> createGetSubscriptionRepairList(final List<SubscriptionDataRepair> subscriptions, final List<SubscriptionBaseTimeline> inRepair) throws CatalogApiException {
+
+        final List<SubscriptionBaseTimeline> result = new LinkedList<SubscriptionBaseTimeline>();
+        final Set<UUID> repairIds = new TreeSet<UUID>();
+        for (final SubscriptionBaseTimeline cur : inRepair) {
+            repairIds.add(cur.getId());
+            result.add(cur);
+        }
+
+        for (final SubscriptionBase cur : subscriptions) {
+            if (!repairIds.contains(cur.getId())) {
+                result.add(new DefaultSubscriptionBaseTimeline((SubscriptionDataRepair) cur, catalogService.getFullCatalog()));
+            }
+        }
+
+        return result;
+    }
+
+    private List<SubscriptionBaseTimeline> convertDataRepair(final List<SubscriptionDataRepair> input) throws CatalogApiException {
+        final List<SubscriptionBaseTimeline> result = new LinkedList<SubscriptionBaseTimeline>();
+        for (final SubscriptionDataRepair cur : input) {
+            result.add(new DefaultSubscriptionBaseTimeline(cur, catalogService.getFullCatalog()));
+        }
+
+        return result;
+    }
+
+    private SubscriptionDataRepair findSubscriptionDataRepair(final UUID targetId, final List<SubscriptionDataRepair> input) {
+        for (final SubscriptionDataRepair cur : input) {
+            if (cur.getId().equals(targetId)) {
+                return cur;
+            }
+        }
+
+        return null;
+    }
+
+    private SubscriptionDataRepair createSubscriptionDataRepair(final DefaultSubscriptionBase curData, final DateTime newBundleStartDate, final DateTime newSubscriptionStartDate, final List<SubscriptionEvent> initialEvents) {
+        final SubscriptionBuilder builder = new SubscriptionBuilder(curData);
+        builder.setActiveVersion(curData.getActiveVersion() + 1);
+        if (newBundleStartDate != null) {
+            builder.setBundleStartDate(newBundleStartDate);
+        }
+        if (newSubscriptionStartDate != null) {
+            builder.setAlignStartDate(newSubscriptionStartDate);
+        }
+        if (initialEvents.size() > 0) {
+            for (final SubscriptionEvent cur : initialEvents) {
+                cur.setActiveVersion(builder.getActiveVersion());
+            }
+        }
+
+        final SubscriptionDataRepair subscriptiondataRepair = new SubscriptionDataRepair(builder, curData.getEvents(), repairApiService, (SubscriptionDao) repairDao, clock, addonUtils, catalogService, internalCallContextFactory);
+        subscriptiondataRepair.rebuildTransitions(curData.getEvents(), catalogService.getFullCatalog());
+        return subscriptiondataRepair;
+    }
+
+    private SubscriptionBaseTimeline findAndCreateSubscriptionRepair(final UUID target, final List<SubscriptionBaseTimeline> input) {
+        for (final SubscriptionBaseTimeline cur : input) {
+            if (target.equals(cur.getId())) {
+                return new DefaultSubscriptionBaseTimeline(cur);
+            }
+        }
+
+        return null;
+    }
+}
+
diff --git a/subscription/src/main/java/com/ning/billing/subscription/api/timeline/DefaultSubscriptionTimeline.java b/subscription/src/main/java/com/ning/billing/subscription/api/timeline/DefaultSubscriptionTimeline.java
index 5e092e5..e9184f3 100644
--- a/subscription/src/main/java/com/ning/billing/subscription/api/timeline/DefaultSubscriptionTimeline.java
+++ b/subscription/src/main/java/com/ning/billing/subscription/api/timeline/DefaultSubscriptionTimeline.java
@@ -40,7 +40,7 @@ import com.ning.billing.subscription.events.user.ApiEvent;
 import com.ning.billing.subscription.events.user.ApiEventType;
 
 
-public class DefaultSubscriptionTimeline implements SubscriptionTimeline {
+public class DefaultSubscriptionTimeline implements SubscriptionBaseTimeline {
 
     private final UUID id;
     private final List<ExistingEvent> existingEvents;
@@ -51,21 +51,21 @@ public class DefaultSubscriptionTimeline implements SubscriptionTimeline {
     public DefaultSubscriptionTimeline(final UUID id, final long activeVersion) {
         this.id = id;
         this.activeVersion = activeVersion;
-        this.existingEvents = Collections.<SubscriptionTimeline.ExistingEvent>emptyList();
-        this.deletedEvents = Collections.<SubscriptionTimeline.DeletedEvent>emptyList();
-        this.newEvents = Collections.<SubscriptionTimeline.NewEvent>emptyList();
+        this.existingEvents = Collections.<SubscriptionBaseTimeline.ExistingEvent>emptyList();
+        this.deletedEvents = Collections.<SubscriptionBaseTimeline.DeletedEvent>emptyList();
+        this.newEvents = Collections.<SubscriptionBaseTimeline.NewEvent>emptyList();
     }
 
-    public DefaultSubscriptionTimeline(final SubscriptionTimeline input) {
+    public DefaultSubscriptionTimeline(final SubscriptionBaseTimeline input) {
         this.id = input.getId();
         this.activeVersion = input.getActiveVersion();
-        this.existingEvents = (input.getExistingEvents() != null) ? new ArrayList<SubscriptionTimeline.ExistingEvent>(input.getExistingEvents()) :
-                              Collections.<SubscriptionTimeline.ExistingEvent>emptyList();
+        this.existingEvents = (input.getExistingEvents() != null) ? new ArrayList<SubscriptionBaseTimeline.ExistingEvent>(input.getExistingEvents()) :
+                              Collections.<SubscriptionBaseTimeline.ExistingEvent>emptyList();
         sortExistingEvent(this.existingEvents);
-        this.deletedEvents = (input.getDeletedEvents() != null) ? new ArrayList<SubscriptionTimeline.DeletedEvent>(input.getDeletedEvents()) :
-                             Collections.<SubscriptionTimeline.DeletedEvent>emptyList();
-        this.newEvents = (input.getNewEvents() != null) ? new ArrayList<SubscriptionTimeline.NewEvent>(input.getNewEvents()) :
-                         Collections.<SubscriptionTimeline.NewEvent>emptyList();
+        this.deletedEvents = (input.getDeletedEvents() != null) ? new ArrayList<SubscriptionBaseTimeline.DeletedEvent>(input.getDeletedEvents()) :
+                             Collections.<SubscriptionBaseTimeline.DeletedEvent>emptyList();
+        this.newEvents = (input.getNewEvents() != null) ? new ArrayList<SubscriptionBaseTimeline.NewEvent>(input.getNewEvents()) :
+                         Collections.<SubscriptionBaseTimeline.NewEvent>emptyList();
         sortNewEvent(this.newEvents);
     }
 
@@ -81,7 +81,7 @@ public class DefaultSubscriptionTimeline implements SubscriptionTimeline {
     private List<ExistingEvent> toExistingEvents(final Catalog catalog, final long activeVersion, final ProductCategory category, final List<SubscriptionEvent> events)
             throws CatalogApiException {
 
-        final List<ExistingEvent> result = new LinkedList<SubscriptionTimeline.ExistingEvent>();
+        final List<ExistingEvent> result = new LinkedList<SubscriptionBaseTimeline.ExistingEvent>();
 
         String prevProductName = null;
         BillingPeriod prevBillingPeriod = null;
diff --git a/subscription/src/main/java/com/ning/billing/subscription/api/timeline/DefaultSubscriptionTimelineApi.java b/subscription/src/main/java/com/ning/billing/subscription/api/timeline/DefaultSubscriptionTimelineApi.java
index cad246b..fd5a40e 100644
--- a/subscription/src/main/java/com/ning/billing/subscription/api/timeline/DefaultSubscriptionTimelineApi.java
+++ b/subscription/src/main/java/com/ning/billing/subscription/api/timeline/DefaultSubscriptionTimelineApi.java
@@ -47,7 +47,7 @@ import com.ning.billing.subscription.engine.addon.AddonUtils;
 import com.ning.billing.subscription.engine.dao.SubscriptionDao;
 import com.ning.billing.subscription.events.SubscriptionEvent;
 import com.ning.billing.subscription.glue.DefaultSubscriptionModule;
-import com.ning.billing.subscription.api.timeline.SubscriptionTimeline.NewEvent;
+import com.ning.billing.subscription.api.timeline.SubscriptionBaseTimeline.NewEvent;
 import com.ning.billing.subscription.api.SubscriptionBase;
 import com.ning.billing.util.callcontext.CallContext;
 import com.ning.billing.util.callcontext.InternalCallContextFactory;
@@ -90,26 +90,26 @@ public class DefaultSubscriptionTimelineApi extends SubscriptionApiBase implemen
     }
 
     @Override
-    public BundleTimeline getBundleTimeline(final SubscriptionBaseBundle bundle, final TenantContext context)
+    public BundleBaseTimeline getBundleTimeline(final SubscriptionBaseBundle bundle, final TenantContext context)
             throws SubscriptionRepairException {
         return getBundleTimelineInternal(bundle, bundle.getExternalKey(), context);
     }
 
     @Override
-    public BundleTimeline getBundleTimeline(final UUID accountId, final String bundleName, final TenantContext context)
+    public BundleBaseTimeline getBundleTimeline(final UUID accountId, final String bundleName, final TenantContext context)
             throws SubscriptionRepairException {
         final SubscriptionBaseBundle bundle = dao.getSubscriptionBundleFromAccountAndKey(accountId, bundleName, internalCallContextFactory.createInternalTenantContext(context));
         return getBundleTimelineInternal(bundle, bundleName + " [accountId= " + accountId.toString() + "]", context);
     }
 
     @Override
-    public BundleTimeline getBundleTimeline(final UUID bundleId, final TenantContext context) throws SubscriptionRepairException {
+    public BundleBaseTimeline getBundleTimeline(final UUID bundleId, final TenantContext context) throws SubscriptionRepairException {
 
         final SubscriptionBaseBundle bundle = dao.getSubscriptionBundleFromId(bundleId, internalCallContextFactory.createInternalTenantContext(context));
         return getBundleTimelineInternal(bundle, bundleId.toString(), context);
     }
 
-    private BundleTimeline getBundleTimelineInternal(final SubscriptionBaseBundle bundle, final String descBundle, final TenantContext context) throws SubscriptionRepairException {
+    private BundleBaseTimeline getBundleTimelineInternal(final SubscriptionBaseBundle bundle, final String descBundle, final TenantContext context) throws SubscriptionRepairException {
         try {
             if (bundle == null) {
                 throw new SubscriptionRepairException(ErrorCode.SUB_REPAIR_UNKNOWN_BUNDLE, descBundle);
@@ -119,7 +119,7 @@ public class DefaultSubscriptionTimelineApi extends SubscriptionApiBase implemen
                 throw new SubscriptionRepairException(ErrorCode.SUB_REPAIR_NO_ACTIVE_SUBSCRIPTIONS, bundle.getId());
             }
             final String viewId = getViewId(((SubscriptionBundleData) bundle).getLastSysUpdateDate(), subscriptions);
-            final List<SubscriptionTimeline> repairs = createGetSubscriptionRepairList(subscriptions, Collections.<SubscriptionTimeline>emptyList());
+            final List<SubscriptionBaseTimeline> repairs = createGetSubscriptionRepairList(subscriptions, Collections.<SubscriptionBaseTimeline>emptyList());
             return createGetBundleRepair(bundle.getId(), bundle.getExternalKey(), viewId, repairs);
         } catch (CatalogApiException e) {
             throw new SubscriptionRepairException(e);
@@ -139,7 +139,7 @@ public class DefaultSubscriptionTimelineApi extends SubscriptionApiBase implemen
     }
 
     @Override
-    public BundleTimeline repairBundle(final BundleTimeline input, final boolean dryRun, final CallContext context) throws SubscriptionRepairException {
+    public BundleBaseTimeline repairBundle(final BundleBaseTimeline input, final boolean dryRun, final CallContext context) throws SubscriptionRepairException {
         final InternalTenantContext tenantContext = internalCallContextFactory.createInternalTenantContext(context);
         try {
             final SubscriptionBaseBundle bundle = dao.getSubscriptionBundleFromId(input.getId(), tenantContext);
@@ -168,7 +168,7 @@ public class DefaultSubscriptionTimelineApi extends SubscriptionApiBase implemen
             final List<SubscriptionDataRepair> addOnSubscriptionInRepair = new LinkedList<SubscriptionDataRepair>();
             final List<SubscriptionDataRepair> inRepair = new LinkedList<SubscriptionDataRepair>();
             for (final SubscriptionBase cur : subscriptions) {
-                final SubscriptionTimeline curRepair = findAndCreateSubscriptionRepair(cur.getId(), input.getSubscriptions());
+                final SubscriptionBaseTimeline curRepair = findAndCreateSubscriptionRepair(cur.getId(), input.getSubscriptions());
                 if (curRepair != null) {
                     final SubscriptionDataRepair curInputRepair = ((SubscriptionDataRepair) cur);
                     final List<SubscriptionEvent> remaining = getRemainingEventsAndValidateDeletedEvents(curInputRepair, firstDeletedBPEventTime, curRepair.getDeletedEvents());
@@ -256,7 +256,7 @@ public class DefaultSubscriptionTimelineApi extends SubscriptionApiBase implemen
             if (dryRun) {
                 baseSubscriptionRepair.addFutureAddonCancellation(addOnSubscriptionInRepair, context);
 
-                final List<SubscriptionTimeline> repairs = createGetSubscriptionRepairList(subscriptions, convertDataRepair(inRepair));
+                final List<SubscriptionBaseTimeline> repairs = createGetSubscriptionRepairList(subscriptions, convertDataRepair(inRepair));
                 return createGetBundleRepair(input.getId(), bundle.getExternalKey(), input.getViewId(), repairs);
             } else {
                 dao.repair(bundle.getAccountId(), input.getId(), inRepair, internalCallContextFactory.createInternalCallContext(bundle.getAccountId(), context));
@@ -277,7 +277,7 @@ public class DefaultSubscriptionTimelineApi extends SubscriptionApiBase implemen
         }
     }
 
-    private void validateBasePlanRecreate(final boolean isBasePlanRecreate, final List<SubscriptionDataRepair> subscriptions, final List<SubscriptionTimeline> input)
+    private void validateBasePlanRecreate(final boolean isBasePlanRecreate, final List<SubscriptionDataRepair> subscriptions, final List<SubscriptionBaseTimeline> input)
             throws SubscriptionRepairException {
         if (!isBasePlanRecreate) {
             return;
@@ -285,7 +285,7 @@ public class DefaultSubscriptionTimelineApi extends SubscriptionApiBase implemen
         if (subscriptions.size() != input.size()) {
             throw new SubscriptionRepairException(ErrorCode.SUB_REPAIR_BP_RECREATE_MISSING_AO, subscriptions.get(0).getBundleId());
         }
-        for (final SubscriptionTimeline cur : input) {
+        for (final SubscriptionBaseTimeline cur : input) {
             if (cur.getNewEvents().size() != 0
                 && (cur.getNewEvents().get(0).getSubscriptionTransitionType() != SubscriptionBaseTransitionType.CREATE
                     && cur.getNewEvents().get(0).getSubscriptionTransitionType() != SubscriptionBaseTransitionType.RE_CREATE)) {
@@ -294,9 +294,9 @@ public class DefaultSubscriptionTimelineApi extends SubscriptionApiBase implemen
         }
     }
 
-    private void validateInputSubscriptionsKnown(final List<SubscriptionDataRepair> subscriptions, final List<SubscriptionTimeline> input)
+    private void validateInputSubscriptionsKnown(final List<SubscriptionDataRepair> subscriptions, final List<SubscriptionBaseTimeline> input)
             throws SubscriptionRepairException {
-        for (final SubscriptionTimeline cur : input) {
+        for (final SubscriptionBaseTimeline cur : input) {
             boolean found = false;
             for (final SubscriptionBase s : subscriptions) {
                 if (s.getId().equals(cur.getId())) {
@@ -323,14 +323,14 @@ public class DefaultSubscriptionTimelineApi extends SubscriptionApiBase implemen
 
     }
 
-    private Collection<NewEvent> createOrderedNewEventInput(final List<SubscriptionTimeline> subscriptionsReapir) {
-        final TreeSet<NewEvent> newEventSet = new TreeSet<SubscriptionTimeline.NewEvent>(new Comparator<NewEvent>() {
+    private Collection<NewEvent> createOrderedNewEventInput(final List<SubscriptionBaseTimeline> subscriptionsReapir) {
+        final TreeSet<NewEvent> newEventSet = new TreeSet<SubscriptionBaseTimeline.NewEvent>(new Comparator<NewEvent>() {
             @Override
             public int compare(final NewEvent o1, final NewEvent o2) {
                 return o1.getRequestedDate().compareTo(o2.getRequestedDate());
             }
         });
-        for (final SubscriptionTimeline cur : subscriptionsReapir) {
+        for (final SubscriptionBaseTimeline cur : subscriptionsReapir) {
             for (final NewEvent e : cur.getNewEvents()) {
                 newEventSet.add(new DefaultNewEvent(cur.getId(), e.getPlanPhaseSpecifier(), e.getRequestedDate(), e.getSubscriptionTransitionType()));
             }
@@ -340,7 +340,7 @@ public class DefaultSubscriptionTimelineApi extends SubscriptionApiBase implemen
     }
 
     private List<SubscriptionEvent> getRemainingEventsAndValidateDeletedEvents(final SubscriptionDataRepair data, final DateTime firstBPDeletedTime,
-                                                                              final List<SubscriptionTimeline.DeletedEvent> deletedEvents)
+                                                                              final List<SubscriptionBaseTimeline.DeletedEvent> deletedEvents)
             throws SubscriptionRepairException {
         if (deletedEvents == null || deletedEvents.size() == 0) {
             return data.getEvents();
@@ -351,7 +351,7 @@ public class DefaultSubscriptionTimelineApi extends SubscriptionApiBase implemen
         for (final SubscriptionEvent cur : data.getEvents()) {
 
             boolean foundDeletedEvent = false;
-            for (final SubscriptionTimeline.DeletedEvent d : deletedEvents) {
+            for (final SubscriptionBaseTimeline.DeletedEvent d : deletedEvents) {
                 if (cur.getId().equals(d.getEventId())) {
                     foundDeletedEvent = true;
                     nbDeleted++;
@@ -373,7 +373,7 @@ public class DefaultSubscriptionTimelineApi extends SubscriptionApiBase implemen
         }
 
         if (nbDeleted != deletedEvents.size()) {
-            for (final SubscriptionTimeline.DeletedEvent d : deletedEvents) {
+            for (final SubscriptionBaseTimeline.DeletedEvent d : deletedEvents) {
                 boolean found = false;
                 for (final SubscriptionBaseTransition cur : data.getAllTransitions()) {
                     if (((SubscriptionBaseTransitionData) cur).getId().equals(d.getEventId())) {
@@ -403,15 +403,15 @@ public class DefaultSubscriptionTimelineApi extends SubscriptionApiBase implemen
         return tmp.toString();
     }
 
-    private BundleTimeline createGetBundleRepair(final UUID bundleId, final String externalKey, final String viewId, final List<SubscriptionTimeline> repairList) {
-        return new BundleTimeline() {
+    private BundleBaseTimeline createGetBundleRepair(final UUID bundleId, final String externalKey, final String viewId, final List<SubscriptionBaseTimeline> repairList) {
+        return new BundleBaseTimeline() {
             @Override
             public String getViewId() {
                 return viewId;
             }
 
             @Override
-            public List<SubscriptionTimeline> getSubscriptions() {
+            public List<SubscriptionBaseTimeline> getSubscriptions() {
                 return repairList;
             }
 
@@ -437,11 +437,11 @@ public class DefaultSubscriptionTimelineApi extends SubscriptionApiBase implemen
         };
     }
 
-    private List<SubscriptionTimeline> createGetSubscriptionRepairList(final List<SubscriptionDataRepair> subscriptions, final List<SubscriptionTimeline> inRepair) throws CatalogApiException {
+    private List<SubscriptionBaseTimeline> createGetSubscriptionRepairList(final List<SubscriptionDataRepair> subscriptions, final List<SubscriptionBaseTimeline> inRepair) throws CatalogApiException {
 
-        final List<SubscriptionTimeline> result = new LinkedList<SubscriptionTimeline>();
+        final List<SubscriptionBaseTimeline> result = new LinkedList<SubscriptionBaseTimeline>();
         final Set<UUID> repairIds = new TreeSet<UUID>();
-        for (final SubscriptionTimeline cur : inRepair) {
+        for (final SubscriptionBaseTimeline cur : inRepair) {
             repairIds.add(cur.getId());
             result.add(cur);
         }
@@ -455,8 +455,8 @@ public class DefaultSubscriptionTimelineApi extends SubscriptionApiBase implemen
         return result;
     }
 
-    private List<SubscriptionTimeline> convertDataRepair(final List<SubscriptionDataRepair> input) throws CatalogApiException {
-        final List<SubscriptionTimeline> result = new LinkedList<SubscriptionTimeline>();
+    private List<SubscriptionBaseTimeline> convertDataRepair(final List<SubscriptionDataRepair> input) throws CatalogApiException {
+        final List<SubscriptionBaseTimeline> result = new LinkedList<SubscriptionBaseTimeline>();
         for (final SubscriptionDataRepair cur : input) {
             result.add(new DefaultSubscriptionTimeline(cur, catalogService.getFullCatalog()));
         }
@@ -494,8 +494,8 @@ public class DefaultSubscriptionTimelineApi extends SubscriptionApiBase implemen
         return subscriptiondataRepair;
     }
 
-    private SubscriptionTimeline findAndCreateSubscriptionRepair(final UUID target, final List<SubscriptionTimeline> input) {
-        for (final SubscriptionTimeline cur : input) {
+    private SubscriptionBaseTimeline findAndCreateSubscriptionRepair(final UUID target, final List<SubscriptionBaseTimeline> input) {
+        for (final SubscriptionBaseTimeline cur : input) {
             if (target.equals(cur.getId())) {
                 return new DefaultSubscriptionTimeline(cur);
             }
diff --git a/subscription/src/main/java/com/ning/billing/subscription/api/timeline/RepairSubscriptionApiService.java b/subscription/src/main/java/com/ning/billing/subscription/api/timeline/RepairSubscriptionApiService.java
index e1df73f..6e31dd4 100644
--- a/subscription/src/main/java/com/ning/billing/subscription/api/timeline/RepairSubscriptionApiService.java
+++ b/subscription/src/main/java/com/ning/billing/subscription/api/timeline/RepairSubscriptionApiService.java
@@ -21,9 +21,9 @@ import org.joda.time.DateTime;
 import com.ning.billing.catalog.api.CatalogService;
 import com.ning.billing.clock.Clock;
 import com.ning.billing.subscription.alignment.PlanAligner;
-import com.ning.billing.subscription.api.SubscriptionApiService;
-import com.ning.billing.subscription.api.user.DefaultSubscriptionApiService;
-import com.ning.billing.subscription.api.user.SubscriptionData;
+import com.ning.billing.subscription.api.SubscriptionBaseApiService;
+import com.ning.billing.subscription.api.user.DefaultSubscriptionBase;
+import com.ning.billing.subscription.api.user.DefaultSubscriptionBaseApiService;
 import com.ning.billing.subscription.engine.addon.AddonUtils;
 import com.ning.billing.subscription.engine.dao.SubscriptionDao;
 import com.ning.billing.subscription.glue.DefaultSubscriptionModule;
@@ -33,7 +33,7 @@ import com.ning.billing.util.callcontext.InternalCallContextFactory;
 import com.google.inject.Inject;
 import com.google.inject.name.Named;
 
-public class RepairSubscriptionApiService extends DefaultSubscriptionApiService implements SubscriptionApiService {
+public class RepairSubscriptionApiService extends DefaultSubscriptionBaseApiService implements SubscriptionBaseApiService {
 
     @Inject
     public RepairSubscriptionApiService(final Clock clock,
@@ -47,7 +47,7 @@ public class RepairSubscriptionApiService extends DefaultSubscriptionApiService 
 
     // Nothing to do for repair as we pass all the repair events in the stream
     @Override
-    public int cancelAddOnsIfRequired(final SubscriptionData baseSubscription, final DateTime effectiveDate, final InternalCallContext context) {
+    public int cancelAddOnsIfRequired(final DefaultSubscriptionBase baseSubscription, final DateTime effectiveDate, final InternalCallContext context) {
         return 0;
     }
 }
diff --git a/subscription/src/main/java/com/ning/billing/subscription/api/timeline/SubscriptionDataRepair.java b/subscription/src/main/java/com/ning/billing/subscription/api/timeline/SubscriptionDataRepair.java
index 6a6ce7f..ed2871a 100644
--- a/subscription/src/main/java/com/ning/billing/subscription/api/timeline/SubscriptionDataRepair.java
+++ b/subscription/src/main/java/com/ning/billing/subscription/api/timeline/SubscriptionDataRepair.java
@@ -30,12 +30,12 @@ import com.ning.billing.catalog.api.Plan;
 import com.ning.billing.catalog.api.PlanPhaseSpecifier;
 import com.ning.billing.catalog.api.Product;
 import com.ning.billing.catalog.api.ProductCategory;
-import com.ning.billing.subscription.api.SubscriptionApiService;
+import com.ning.billing.subscription.api.SubscriptionBaseApiService;
 import com.ning.billing.subscription.api.SubscriptionBaseTransitionType;
 import com.ning.billing.subscription.api.user.SubscriptionBaseApiException;
 import com.ning.billing.subscription.api.user.SubscriptionBaseTransition;
 import com.ning.billing.subscription.api.user.SubscriptionBuilder;
-import com.ning.billing.subscription.api.user.SubscriptionData;
+import com.ning.billing.subscription.api.user.DefaultSubscriptionBase;
 import com.ning.billing.subscription.engine.addon.AddonUtils;
 import com.ning.billing.subscription.engine.dao.SubscriptionDao;
 import com.ning.billing.subscription.events.SubscriptionEvent;
@@ -50,7 +50,7 @@ import com.ning.billing.clock.Clock;
 import com.google.common.base.Predicate;
 import com.google.common.collect.Collections2;
 
-public class SubscriptionDataRepair extends SubscriptionData {
+public class SubscriptionDataRepair extends DefaultSubscriptionBase {
 
     private final AddonUtils addonUtils;
     private final Clock clock;
@@ -60,7 +60,7 @@ public class SubscriptionDataRepair extends SubscriptionData {
     private final InternalCallContextFactory internalCallContextFactory;
 
 
-    public SubscriptionDataRepair(final SubscriptionBuilder builder, final List<SubscriptionEvent> initialEvents, final SubscriptionApiService apiService,
+    public SubscriptionDataRepair(final SubscriptionBuilder builder, final List<SubscriptionEvent> initialEvents, final SubscriptionBaseApiService apiService,
                                   final SubscriptionDao dao, final Clock clock, final AddonUtils addonUtils, final CatalogService catalogService,
                                   final InternalCallContextFactory internalCallContextFactory) {
         super(builder, apiService, clock);
@@ -74,15 +74,15 @@ public class SubscriptionDataRepair extends SubscriptionData {
 
 
 
-    public SubscriptionDataRepair(final SubscriptionData subscriptionData, final SubscriptionApiService apiService,
+    public SubscriptionDataRepair(final DefaultSubscriptionBase defaultSubscriptionBase, final SubscriptionBaseApiService apiService,
                                   final SubscriptionDao dao, final Clock clock, final AddonUtils addonUtils, final CatalogService catalogService,
                                   final InternalCallContextFactory internalCallContextFactory) {
-        super(subscriptionData, apiService , clock);
+        super(defaultSubscriptionBase, apiService , clock);
         this.repairDao = dao;
         this.addonUtils = addonUtils;
         this.clock = clock;
         this.catalogService = catalogService;
-        this.initialEvents = subscriptionData.getEvents();
+        this.initialEvents = defaultSubscriptionBase.getEvents();
         this.internalCallContextFactory = internalCallContextFactory;
     }
 
@@ -101,7 +101,7 @@ public class SubscriptionDataRepair extends SubscriptionData {
     }
 
     public void addNewRepairEvent(final DefaultNewEvent input, final SubscriptionDataRepair baseSubscription, final List<SubscriptionDataRepair> addonSubscriptions, final CallContext context)
-            throws SubscriptionRepairException {
+            throws SubscriptionBaseRepairException {
 
         try {
             final PlanPhaseSpecifier spec = input.getPlanPhaseSpecifier();
@@ -123,12 +123,12 @@ public class SubscriptionDataRepair extends SubscriptionData {
                 case PHASE:
                     break;
                 default:
-                    throw new SubscriptionRepairException(ErrorCode.SUB_REPAIR_UNKNOWN_TYPE, input.getSubscriptionTransitionType(), id);
+                    throw new SubscriptionBaseRepairException(ErrorCode.SUB_REPAIR_UNKNOWN_TYPE, input.getSubscriptionTransitionType(), id);
             }
         } catch (SubscriptionBaseApiException e) {
-            throw new SubscriptionRepairException(e);
+            throw new SubscriptionBaseRepairException(e);
         } catch (CatalogApiException e) {
-            throw new SubscriptionRepairException(e);
+            throw new SubscriptionBaseRepairException(e);
         }
     }
 
diff --git a/subscription/src/main/java/com/ning/billing/subscription/api/transfer/DefaultSubscriptionBaseTransferApi.java b/subscription/src/main/java/com/ning/billing/subscription/api/transfer/DefaultSubscriptionBaseTransferApi.java
new file mode 100644
index 0000000..a1bae6b
--- /dev/null
+++ b/subscription/src/main/java/com/ning/billing/subscription/api/transfer/DefaultSubscriptionBaseTransferApi.java
@@ -0,0 +1,278 @@
+/*
+ * Copyright 2010-2013 Ning, Inc.
+ *
+ * Ning licenses this file to you under the Apache License, version 2.0
+ * (the "License"); you may not use this file except in compliance with the
+ * License.  You may obtain a copy of the License at:
+ *
+ *    http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
+ * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.  See the
+ * License for the specific language governing permissions and limitations
+ * under the License.
+ */
+
+package com.ning.billing.subscription.api.transfer;
+
+import java.util.LinkedList;
+import java.util.List;
+import java.util.UUID;
+
+import org.joda.time.DateTime;
+
+import com.ning.billing.ErrorCode;
+import com.ning.billing.catalog.api.Catalog;
+import com.ning.billing.catalog.api.CatalogApiException;
+import com.ning.billing.catalog.api.CatalogService;
+import com.ning.billing.catalog.api.PlanPhase;
+import com.ning.billing.catalog.api.PlanPhaseSpecifier;
+import com.ning.billing.catalog.api.ProductCategory;
+import com.ning.billing.subscription.api.SubscriptionApiBase;
+import com.ning.billing.subscription.api.SubscriptionBaseApiService;
+import com.ning.billing.subscription.api.migration.AccountMigrationData.BundleMigrationData;
+import com.ning.billing.subscription.api.migration.AccountMigrationData.SubscriptionMigrationData;
+import com.ning.billing.subscription.api.timeline.BundleBaseTimeline;
+import com.ning.billing.subscription.api.timeline.SubscriptionBaseTimelineApi;
+import com.ning.billing.subscription.api.user.DefaultSubscriptionBase;
+import com.ning.billing.subscription.api.user.DefaultSubscriptionBaseBundle;
+import com.ning.billing.subscription.api.user.SubscriptionBaseBundle;
+import com.ning.billing.subscription.api.user.SubscriptionBuilder;
+import com.ning.billing.subscription.engine.dao.SubscriptionDao;
+import com.ning.billing.subscription.events.SubscriptionEvent;
+import com.ning.billing.subscription.events.phase.PhaseEventData;
+import com.ning.billing.subscription.events.user.ApiEventBuilder;
+import com.ning.billing.subscription.events.user.ApiEventCancel;
+import com.ning.billing.subscription.events.user.ApiEventChange;
+import com.ning.billing.subscription.events.user.ApiEventTransfer;
+import com.ning.billing.subscription.exceptions.SubscriptionBaseError;
+import com.ning.billing.subscription.api.timeline.SubscriptionBaseRepairException;
+import com.ning.billing.subscription.api.timeline.SubscriptionBaseTimeline;
+import com.ning.billing.subscription.api.timeline.SubscriptionBaseTimeline.ExistingEvent;
+
+import com.ning.billing.subscription.api.user.SubscriptionState;
+import com.ning.billing.util.callcontext.CallContext;
+import com.ning.billing.util.callcontext.InternalCallContext;
+import com.ning.billing.util.callcontext.InternalCallContextFactory;
+import com.ning.billing.clock.Clock;
+
+import com.google.common.annotations.VisibleForTesting;
+import com.google.common.collect.ImmutableList;
+import com.google.inject.Inject;
+
+public class DefaultSubscriptionBaseTransferApi extends SubscriptionApiBase implements SubscriptionBaseTransferApi {
+
+    private final CatalogService catalogService;
+    private final SubscriptionBaseTimelineApi timelineApi;
+    private final InternalCallContextFactory internalCallContextFactory;
+
+    @Inject
+    public DefaultSubscriptionBaseTransferApi(final Clock clock, final SubscriptionDao dao, final SubscriptionBaseTimelineApi timelineApi, final CatalogService catalogService,
+                                              final SubscriptionBaseApiService apiService, final InternalCallContextFactory internalCallContextFactory) {
+        super(dao, apiService, clock, catalogService);
+        this.catalogService = catalogService;
+        this.timelineApi = timelineApi;
+        this.internalCallContextFactory = internalCallContextFactory;
+    }
+
+    private SubscriptionEvent createEvent(final boolean firstEvent, final ExistingEvent existingEvent, final DefaultSubscriptionBase subscription, final DateTime transferDate, final CallContext context)
+            throws CatalogApiException {
+
+        SubscriptionEvent newEvent = null;
+
+        final Catalog catalog = catalogService.getFullCatalog();
+
+        final DateTime effectiveDate = existingEvent.getEffectiveDate().isBefore(transferDate) ? transferDate : existingEvent.getEffectiveDate();
+
+        final PlanPhaseSpecifier spec = existingEvent.getPlanPhaseSpecifier();
+        final PlanPhase currentPhase = existingEvent.getPlanPhaseName() != null ? catalog.findPhase(existingEvent.getPlanPhaseName(), effectiveDate, subscription.getAlignStartDate()) : null;
+
+        if (spec == null || currentPhase == null) {
+            // Ignore cancellations - we assume that transferred subscriptions should always be active
+            return null;
+        }
+        final ApiEventBuilder apiBuilder = new ApiEventBuilder()
+                .setSubscriptionId(subscription.getId())
+                .setEventPlan(currentPhase.getPlan().getName())
+                .setEventPlanPhase(currentPhase.getName())
+                .setEventPriceList(spec.getPriceListName())
+                .setActiveVersion(subscription.getActiveVersion())
+                .setProcessedDate(clock.getUTCNow())
+                .setEffectiveDate(effectiveDate)
+                .setRequestedDate(effectiveDate)
+                .setFromDisk(true);
+
+        switch (existingEvent.getSubscriptionTransitionType()) {
+            case TRANSFER:
+            case MIGRATE_ENTITLEMENT:
+            case RE_CREATE:
+            case CREATE:
+                newEvent = new ApiEventTransfer(apiBuilder);
+                break;
+
+            // Should we even keep future change events; product question really
+            case CHANGE:
+                newEvent = firstEvent ? new ApiEventTransfer(apiBuilder) : new ApiEventChange(apiBuilder);
+                break;
+
+            case PHASE:
+                newEvent = firstEvent ? new ApiEventTransfer(apiBuilder) :
+                           PhaseEventData.createNextPhaseEvent(currentPhase.getName(), subscription, clock.getUTCNow(), effectiveDate);
+                break;
+
+            // Ignore these events except if it's the first event for the new subscription
+            case MIGRATE_BILLING:
+                if (firstEvent) {
+                    newEvent = new ApiEventTransfer(apiBuilder);
+                }
+                break;
+            case CANCEL:
+                break;
+
+            default:
+                throw new SubscriptionBaseError(String.format("Unexpected transitionType %s", existingEvent.getSubscriptionTransitionType()));
+        }
+        return newEvent;
+    }
+
+    @VisibleForTesting
+    List<SubscriptionEvent> toEvents(final List<ExistingEvent> existingEvents, final DefaultSubscriptionBase subscription,
+                                    final DateTime transferDate, final CallContext context) throws SubscriptionBaseTransferApiException {
+
+        try {
+            final List<SubscriptionEvent> result = new LinkedList<SubscriptionEvent>();
+
+            SubscriptionEvent event = null;
+            ExistingEvent prevEvent = null;
+            boolean firstEvent = true;
+            for (ExistingEvent cur : existingEvents) {
+                // Skip all events prior to the transferDate
+                if (cur.getEffectiveDate().isBefore(transferDate)) {
+                    prevEvent = cur;
+                    continue;
+                }
+
+                // Add previous event the first time if needed
+                if (prevEvent != null) {
+                    event = createEvent(firstEvent, prevEvent, subscription, transferDate, context);
+                    if (event != null) {
+                        result.add(event);
+                        firstEvent = false;
+                    }
+                    prevEvent = null;
+                }
+
+                event = createEvent(firstEvent, cur, subscription, transferDate, context);
+                if (event != null) {
+                    result.add(event);
+                    firstEvent = false;
+                }
+            }
+
+            // Previous loop did not get anything because transferDate is greater than effectiveDate of last event
+            if (prevEvent != null) {
+                event = createEvent(firstEvent, prevEvent, subscription, transferDate, context);
+                if (event != null) {
+                    result.add(event);
+                }
+                prevEvent = null;
+            }
+
+            return result;
+        } catch (CatalogApiException e) {
+            throw new SubscriptionBaseTransferApiException(e);
+        }
+    }
+
+    @Override
+    public SubscriptionBaseBundle transferBundle(final UUID sourceAccountId, final UUID destAccountId,
+                                             final String bundleKey, final DateTime transferDate, final boolean transferAddOn,
+                                             final boolean cancelImmediately, final CallContext context) throws SubscriptionBaseTransferApiException {
+        final InternalCallContext fromInternalCallContext = internalCallContextFactory.createInternalCallContext(sourceAccountId, context);
+        final InternalCallContext toInternalCallContext = internalCallContextFactory.createInternalCallContext(destAccountId, context);
+
+        try {
+            final DateTime effectiveTransferDate = transferDate == null ? clock.getUTCNow() : transferDate;
+            if (effectiveTransferDate.isAfter(clock.getUTCNow())) {
+                // The transfer event for the migrated bundle will be the first one, which cannot be in the future
+                // (subscription always expects the first event to be in the past)
+                throw new SubscriptionBaseTransferApiException(ErrorCode.SUB_TRANSFER_INVALID_EFF_DATE, effectiveTransferDate);
+            }
+
+            final SubscriptionBaseBundle bundle = dao.getSubscriptionBundleFromAccountAndKey(sourceAccountId, bundleKey, fromInternalCallContext);
+            if (bundle == null) {
+                throw new SubscriptionBaseTransferApiException(ErrorCode.SUB_CREATE_NO_BUNDLE, bundleKey);
+            }
+
+            // Get the bundle timeline for the old account
+            final BundleBaseTimeline bundleBaseTimeline = timelineApi.getBundleTimeline(bundle, context);
+
+            final DefaultSubscriptionBaseBundle subscriptionBundleData = new DefaultSubscriptionBaseBundle(bundleKey, destAccountId, effectiveTransferDate);
+            final List<SubscriptionMigrationData> subscriptionMigrationDataList = new LinkedList<SubscriptionMigrationData>();
+
+            final List<TransferCancelData> transferCancelDataList = new LinkedList<TransferCancelData>();
+
+            DateTime bundleStartdate = null;
+
+            for (final SubscriptionBaseTimeline cur : bundleBaseTimeline.getSubscriptions()) {
+                final DefaultSubscriptionBase oldSubscription = (DefaultSubscriptionBase) dao.getSubscriptionFromId(cur.getId(), fromInternalCallContext);
+                // Skip already cancelled subscriptions
+                if (oldSubscription.getState() == SubscriptionState.CANCELLED) {
+                    continue;
+                }
+                final List<ExistingEvent> existingEvents = cur.getExistingEvents();
+                final ProductCategory productCategory = existingEvents.get(0).getPlanPhaseSpecifier().getProductCategory();
+                if (productCategory == ProductCategory.ADD_ON) {
+                    if (!transferAddOn) {
+                        continue;
+                    }
+                } else {
+
+                    // If BP or STANDALONE subscription, create the cancel event on effectiveCancelDate
+                    final DateTime effectiveCancelDate = !cancelImmediately && oldSubscription.getChargedThroughDate() != null &&
+                                                         effectiveTransferDate.isBefore(oldSubscription.getChargedThroughDate()) ?
+                                                         oldSubscription.getChargedThroughDate() : effectiveTransferDate;
+
+                    final SubscriptionEvent cancelEvent = new ApiEventCancel(new ApiEventBuilder()
+                                                                                    .setSubscriptionId(cur.getId())
+                                                                                    .setActiveVersion(cur.getActiveVersion())
+                                                                                    .setProcessedDate(clock.getUTCNow())
+                                                                                    .setEffectiveDate(effectiveCancelDate)
+                                                                                    .setRequestedDate(effectiveTransferDate)
+                                                                                    .setFromDisk(true));
+
+                    TransferCancelData cancelData = new TransferCancelData(oldSubscription, cancelEvent);
+                    transferCancelDataList.add(cancelData);
+                }
+
+                // We Align with the original subscription
+                final DateTime subscriptionAlignStartDate = oldSubscription.getAlignStartDate();
+                if (bundleStartdate == null) {
+                    bundleStartdate = oldSubscription.getStartDate();
+                }
+
+                // Create the new subscription for the new bundle on the new account
+                final DefaultSubscriptionBase defaultSubscriptionBase = createSubscriptionForApiUse(new SubscriptionBuilder()
+                                                                                              .setId(UUID.randomUUID())
+                                                                                              .setBundleId(subscriptionBundleData.getId())
+                                                                                              .setCategory(productCategory)
+                                                                                              .setBundleStartDate(effectiveTransferDate)
+                                                                                              .setAlignStartDate(subscriptionAlignStartDate),
+                                                                                      ImmutableList.<SubscriptionEvent>of());
+
+                final List<SubscriptionEvent> events = toEvents(existingEvents, defaultSubscriptionBase, effectiveTransferDate, context);
+                final SubscriptionMigrationData curData = new SubscriptionMigrationData(defaultSubscriptionBase, events, null);
+                subscriptionMigrationDataList.add(curData);
+            }
+            BundleMigrationData bundleMigrationData = new BundleMigrationData(subscriptionBundleData, subscriptionMigrationDataList);
+
+            // Atomically cancel all subscription on old account and create new bundle, subscriptions, events for new account
+            dao.transfer(sourceAccountId, destAccountId, bundleMigrationData, transferCancelDataList, fromInternalCallContext, toInternalCallContext);
+
+            return bundle;
+        } catch (SubscriptionBaseRepairException e) {
+            throw new SubscriptionBaseTransferApiException(e);
+        }
+    }
+}
diff --git a/subscription/src/main/java/com/ning/billing/subscription/api/transfer/DefaultSubscriptionTransferApi.java b/subscription/src/main/java/com/ning/billing/subscription/api/transfer/DefaultSubscriptionTransferApi.java
index ab0930c..d8b13a1 100644
--- a/subscription/src/main/java/com/ning/billing/subscription/api/transfer/DefaultSubscriptionTransferApi.java
+++ b/subscription/src/main/java/com/ning/billing/subscription/api/transfer/DefaultSubscriptionTransferApi.java
@@ -33,6 +33,7 @@ import com.ning.billing.subscription.api.SubscriptionApiBase;
 import com.ning.billing.subscription.api.SubscriptionApiService;
 import com.ning.billing.subscription.api.migration.AccountMigrationData.BundleMigrationData;
 import com.ning.billing.subscription.api.migration.AccountMigrationData.SubscriptionMigrationData;
+import com.ning.billing.subscription.api.timeline.BundleBaseTimeline;
 import com.ning.billing.subscription.api.user.SubscriptionBaseBundle;
 import com.ning.billing.subscription.api.user.SubscriptionBuilder;
 import com.ning.billing.subscription.api.user.SubscriptionBundleData;
@@ -45,10 +46,9 @@ import com.ning.billing.subscription.events.user.ApiEventCancel;
 import com.ning.billing.subscription.events.user.ApiEventChange;
 import com.ning.billing.subscription.events.user.ApiEventTransfer;
 import com.ning.billing.subscription.exceptions.SubscriptionError;
-import com.ning.billing.subscription.api.timeline.BundleTimeline;
 import com.ning.billing.subscription.api.timeline.SubscriptionRepairException;
-import com.ning.billing.subscription.api.timeline.SubscriptionTimeline;
-import com.ning.billing.subscription.api.timeline.SubscriptionTimeline.ExistingEvent;
+import com.ning.billing.subscription.api.timeline.SubscriptionBaseTimeline;
+import com.ning.billing.subscription.api.timeline.SubscriptionBaseTimeline.ExistingEvent;
 
 import com.ning.billing.subscription.api.timeline.SubscriptionTimelineApi;
 import com.ning.billing.subscription.api.user.SubscriptionState;
@@ -206,7 +206,7 @@ public class DefaultSubscriptionTransferApi extends SubscriptionApiBase implemen
             }
 
             // Get the bundle timeline for the old account
-            final BundleTimeline bundleTimeline = timelineApi.getBundleTimeline(bundle, context);
+            final BundleBaseTimeline bundleBaseTimeline = timelineApi.getBundleTimeline(bundle, context);
 
             final SubscriptionBundleData subscriptionBundleData = new SubscriptionBundleData(bundleKey, destAccountId, effectiveTransferDate);
             final List<SubscriptionMigrationData> subscriptionMigrationDataList = new LinkedList<SubscriptionMigrationData>();
@@ -215,7 +215,7 @@ public class DefaultSubscriptionTransferApi extends SubscriptionApiBase implemen
 
             DateTime bundleStartdate = null;
 
-            for (final SubscriptionTimeline cur : bundleTimeline.getSubscriptions()) {
+            for (final SubscriptionBaseTimeline cur : bundleBaseTimeline.getSubscriptions()) {
                 final SubscriptionData oldSubscription = (SubscriptionData) dao.getSubscriptionFromId(cur.getId(), fromInternalCallContext);
                 // Skip already cancelled subscriptions
                 if (oldSubscription.getState() == SubscriptionState.CANCELLED) {
diff --git a/subscription/src/main/java/com/ning/billing/subscription/api/transfer/TransferCancelData.java b/subscription/src/main/java/com/ning/billing/subscription/api/transfer/TransferCancelData.java
index 561e2b3..277270e 100644
--- a/subscription/src/main/java/com/ning/billing/subscription/api/transfer/TransferCancelData.java
+++ b/subscription/src/main/java/com/ning/billing/subscription/api/transfer/TransferCancelData.java
@@ -16,21 +16,21 @@
 
 package com.ning.billing.subscription.api.transfer;
 
-import com.ning.billing.subscription.api.user.SubscriptionData;
+import com.ning.billing.subscription.api.user.DefaultSubscriptionBase;
 import com.ning.billing.subscription.events.SubscriptionEvent;
 
 public class TransferCancelData {
 
-    final SubscriptionData subscription;
+    final DefaultSubscriptionBase subscription;
     final SubscriptionEvent cancelEvent;
 
-    public TransferCancelData(final SubscriptionData subscription,
+    public TransferCancelData(final DefaultSubscriptionBase subscription,
                               final SubscriptionEvent cancelEvent) {
         this.subscription = subscription;
         this.cancelEvent = cancelEvent;
     }
 
-    public SubscriptionData getSubscription() {
+    public DefaultSubscriptionBase getSubscription() {
         return subscription;
     }
 
diff --git a/subscription/src/main/java/com/ning/billing/subscription/api/user/DefaultRequestedSubscriptionEvent.java b/subscription/src/main/java/com/ning/billing/subscription/api/user/DefaultRequestedSubscriptionEvent.java
index 99f63af..135f760 100644
--- a/subscription/src/main/java/com/ning/billing/subscription/api/user/DefaultRequestedSubscriptionEvent.java
+++ b/subscription/src/main/java/com/ning/billing/subscription/api/user/DefaultRequestedSubscriptionEvent.java
@@ -55,7 +55,7 @@ public class DefaultRequestedSubscriptionEvent extends DefaultSubscriptionEvent 
               transitionType, remainingEventsForUserOperation, startDate, searchKey1, searchKey2, userToken);
     }
 
-    public DefaultRequestedSubscriptionEvent(final SubscriptionData subscription,
+    public DefaultRequestedSubscriptionEvent(final DefaultSubscriptionBase subscription,
                                              final SubscriptionEvent nextEvent,
                                              final Long searchKey1,
                                              final Long searchKey2,
diff --git a/subscription/src/main/java/com/ning/billing/subscription/api/user/DefaultSubscriptionBase.java b/subscription/src/main/java/com/ning/billing/subscription/api/user/DefaultSubscriptionBase.java
new file mode 100644
index 0000000..266ab02
--- /dev/null
+++ b/subscription/src/main/java/com/ning/billing/subscription/api/user/DefaultSubscriptionBase.java
@@ -0,0 +1,649 @@
+/*
+ * Copyright 2010-2013 Ning, Inc.
+ *
+ * Ning licenses this file to you under the Apache License, version 2.0
+ * (the "License"); you may not use this file except in compliance with the
+ * License.  You may obtain a copy of the License at:
+ *
+ *    http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
+ * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.  See the
+ * License for the specific language governing permissions and limitations
+ * under the License.
+ */
+
+package com.ning.billing.subscription.api.user;
+
+import java.util.ArrayList;
+import java.util.Collections;
+import java.util.LinkedList;
+import java.util.List;
+import java.util.UUID;
+
+import javax.annotation.Nullable;
+
+import org.joda.time.DateTime;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+import com.ning.billing.catalog.api.BillingActionPolicy;
+import com.ning.billing.catalog.api.BillingPeriod;
+import com.ning.billing.catalog.api.Catalog;
+import com.ning.billing.catalog.api.CatalogApiException;
+import com.ning.billing.catalog.api.Plan;
+import com.ning.billing.catalog.api.PlanPhase;
+import com.ning.billing.catalog.api.PlanPhaseSpecifier;
+import com.ning.billing.catalog.api.PriceList;
+import com.ning.billing.catalog.api.ProductCategory;
+import com.ning.billing.clock.Clock;
+import com.ning.billing.entitlement.api.BlockingState;
+import com.ning.billing.subscription.api.SubscriptionBaseApiService;
+import com.ning.billing.subscription.api.SubscriptionBase;
+import com.ning.billing.subscription.api.SubscriptionBaseTransitionType;
+import com.ning.billing.subscription.api.user.SubscriptionBaseTransitionDataIterator.Kind;
+import com.ning.billing.subscription.api.user.SubscriptionBaseTransitionDataIterator.Order;
+import com.ning.billing.subscription.api.user.SubscriptionBaseTransitionDataIterator.TimeLimit;
+import com.ning.billing.subscription.api.user.SubscriptionBaseTransitionDataIterator.Visibility;
+import com.ning.billing.subscription.events.SubscriptionEvent;
+import com.ning.billing.subscription.events.SubscriptionEvent.EventType;
+import com.ning.billing.subscription.events.phase.PhaseEvent;
+import com.ning.billing.subscription.events.user.ApiEvent;
+import com.ning.billing.subscription.events.user.ApiEventType;
+import com.ning.billing.subscription.exceptions.SubscriptionBaseError;
+import com.ning.billing.util.callcontext.CallContext;
+import com.ning.billing.util.entity.EntityBase;
+
+public class DefaultSubscriptionBase extends EntityBase implements SubscriptionBase {
+
+    private static final Logger log = LoggerFactory.getLogger(DefaultSubscriptionBase.class);
+
+    private final Clock clock;
+    private final SubscriptionBaseApiService apiService;
+
+    //
+    // Final subscription fields
+    //
+    private final UUID bundleId;
+    private final DateTime alignStartDate;
+    private final DateTime bundleStartDate;
+    private final ProductCategory category;
+
+    //
+    // Those can be modified through non User APIs, and a new SubscriptionBase
+    // object would be created
+    //
+    private final long activeVersion;
+    private final DateTime chargedThroughDate;
+    private final DateTime paidThroughDate;
+
+    //
+    // User APIs (create, change, cancel,...) will recompute those each time,
+    // so the user holding that subscription object get the correct state when
+    // the call completes
+    //
+    private LinkedList<SubscriptionBaseTransition> transitions;
+
+    // Low level events are ONLY used for Repair APIs
+    protected List<SubscriptionEvent> events;
+
+
+    public List<SubscriptionEvent> getEvents() {
+        return events;
+    }
+
+    // Transient object never returned at the API
+    public DefaultSubscriptionBase(final SubscriptionBuilder builder) {
+        this(builder, null, null);
+    }
+
+    public DefaultSubscriptionBase(final SubscriptionBuilder builder, @Nullable final SubscriptionBaseApiService apiService, @Nullable final Clock clock) {
+        super(builder.getId(), builder.getCreatedDate(), builder.getUpdatedDate());
+        this.apiService = apiService;
+        this.clock = clock;
+        this.bundleId = builder.getBundleId();
+        this.alignStartDate = builder.getAlignStartDate();
+        this.bundleStartDate = builder.getBundleStartDate();
+        this.category = builder.getCategory();
+        this.activeVersion = builder.getActiveVersion();
+        this.chargedThroughDate = builder.getChargedThroughDate();
+        this.paidThroughDate = builder.getPaidThroughDate();
+    }
+
+    // Used for API to make sure we have a clock and an apiService set before we return the object
+    public DefaultSubscriptionBase(final DefaultSubscriptionBase internalSubscription, final SubscriptionBaseApiService apiService, final Clock clock) {
+        super(internalSubscription.getId(), internalSubscription.getCreatedDate(), internalSubscription.getUpdatedDate());
+        this.apiService = apiService;
+        this.clock = clock;
+        this.bundleId = internalSubscription.getBundleId();
+        this.alignStartDate = internalSubscription.getAlignStartDate();
+        this.bundleStartDate = internalSubscription.getBundleStartDate();
+        this.category = internalSubscription.getCategory();
+        this.activeVersion = internalSubscription.getActiveVersion();
+        this.chargedThroughDate = internalSubscription.getChargedThroughDate();
+        this.paidThroughDate = internalSubscription.getPaidThroughDate();
+        this.transitions = new LinkedList<SubscriptionBaseTransition>(internalSubscription.getAllTransitions());
+        this.events = internalSubscription.getEvents();
+    }
+
+    @Override
+    public UUID getBundleId() {
+        return bundleId;
+    }
+
+    @Override
+    public DateTime getStartDate() {
+        return transitions.get(0).getEffectiveTransitionTime();
+    }
+
+    @Override
+    public SubscriptionState getState() {
+        return (getPreviousTransition() == null) ? null
+                                                 : getPreviousTransition().getNextState();
+    }
+
+    @Override
+    public SubscriptionSourceType getSourceType() {
+        if (transitions == null) {
+            return null;
+        }
+        final SubscriptionBaseTransitionData initialTransition = (SubscriptionBaseTransitionData) transitions.get(0);
+        switch (initialTransition.getApiEventType()) {
+            case MIGRATE_BILLING:
+            case MIGRATE_ENTITLEMENT:
+                return SubscriptionSourceType.MIGRATED;
+            case TRANSFER:
+                return SubscriptionSourceType.TRANSFERED;
+            default:
+                return SubscriptionSourceType.NATIVE;
+        }
+    }
+
+    @Override
+    public PlanPhase getCurrentPhase() {
+        return (getPreviousTransition() == null) ? null
+                                                 : getPreviousTransition().getNextPhase();
+    }
+
+    @Override
+    public Plan getCurrentPlan() {
+        return (getPreviousTransition() == null) ? null
+                                                 : getPreviousTransition().getNextPlan();
+    }
+
+    @Override
+    public PriceList getCurrentPriceList() {
+        return (getPreviousTransition() == null) ? null :
+               getPreviousTransition().getNextPriceList();
+
+    }
+
+    @Override
+    public DateTime getEndDate() {
+        final SubscriptionBaseTransition latestTransition = getPreviousTransition();
+        if (latestTransition.getNextState() == SubscriptionState.CANCELLED) {
+            return latestTransition.getEffectiveTransitionTime();
+        }
+        return null;
+    }
+
+    @Override
+    public DateTime getFutureEndDate() {
+        if (transitions == null) {
+            return null;
+        }
+
+        final SubscriptionBaseTransitionDataIterator it = new SubscriptionBaseTransitionDataIterator(
+                clock, transitions, Order.ASC_FROM_PAST, Kind.SUBSCRIPTION,
+                Visibility.ALL, TimeLimit.FUTURE_ONLY);
+        while (it.hasNext()) {
+            final SubscriptionBaseTransition cur = it.next();
+            if (cur.getTransitionType() == SubscriptionBaseTransitionType.CANCEL) {
+                return cur.getEffectiveTransitionTime();
+            }
+        }
+        return null;
+    }
+
+    @Override
+    public boolean cancel(final DateTime requestedDate, final CallContext context) throws SubscriptionBaseApiException {
+        return apiService.cancel(this, requestedDate, context);
+    }
+
+    @Override
+    public boolean cancelWithPolicy(final DateTime requestedDate, final BillingActionPolicy policy, final CallContext context) throws SubscriptionBaseApiException {
+        return apiService.cancelWithPolicy(this, requestedDate, policy, context);
+    }
+
+    @Override
+    public boolean uncancel(final CallContext context)
+            throws SubscriptionBaseApiException {
+        return apiService.uncancel(this, context);
+    }
+
+    @Override
+    public boolean changePlan(final String productName, final BillingPeriod term, final String priceList,
+                              final DateTime requestedDate, final CallContext context) throws SubscriptionBaseApiException {
+        return apiService.changePlan(this, productName, term, priceList, requestedDate, context);
+    }
+
+    @Override
+    public boolean changePlanWithPolicy(final String productName, final BillingPeriod term, final String priceList,
+                                        final DateTime requestedDate, final BillingActionPolicy policy, final CallContext context) throws SubscriptionBaseApiException {
+        return apiService.changePlanWithPolicy(this, productName, term, priceList, requestedDate, policy, context);
+    }
+
+    @Override
+    public boolean recreate(final PlanPhaseSpecifier spec, final DateTime requestedDate,
+                            final CallContext context) throws SubscriptionBaseApiException {
+        return apiService.recreatePlan(this, spec, requestedDate, context);
+    }
+
+    @Override
+    public BlockingState getBlockingState() {
+        throw new UnsupportedOperationException();
+    }
+
+    @Override
+    public SubscriptionBaseTransition getPendingTransition() {
+        if (transitions == null) {
+            return null;
+        }
+        final SubscriptionBaseTransitionDataIterator it = new SubscriptionBaseTransitionDataIterator(
+                clock, transitions, Order.ASC_FROM_PAST, Kind.SUBSCRIPTION,
+                Visibility.ALL, TimeLimit.FUTURE_ONLY);
+        return it.hasNext() ? it.next() : null;
+    }
+
+    @Override
+    public String getLastActiveProductName() {
+        if (getState() == SubscriptionState.CANCELLED) {
+            final SubscriptionBaseTransition data = getPreviousTransition();
+            return data.getPreviousPlan().getProduct().getName();
+        } else {
+            return getCurrentPlan().getProduct().getName();
+        }
+    }
+
+    @Override
+    public String getLastActivePriceListName() {
+        if (getState() == SubscriptionState.CANCELLED) {
+            final SubscriptionBaseTransition data = getPreviousTransition();
+            return data.getPreviousPriceList().getName();
+        } else {
+            return getCurrentPriceList().getName();
+        }
+    }
+
+    @Override
+    public String getLastActiveCategoryName() {
+        if (getState() == SubscriptionState.CANCELLED) {
+            final SubscriptionBaseTransition data = getPreviousTransition();
+            return data.getPreviousPlan().getProduct().getCategory().name();
+        } else {
+            return getCurrentPlan().getProduct().getCategory().name();
+        }
+    }
+
+    @Override
+    public Plan getLastActivePlan() {
+        if (getState() == SubscriptionState.CANCELLED) {
+            final SubscriptionBaseTransition data = getPreviousTransition();
+            return data.getPreviousPlan();
+        } else {
+            return getCurrentPlan();
+        }
+    }
+
+    @Override
+    public String getLastActiveBillingPeriod() {
+        if (getState() == SubscriptionState.CANCELLED) {
+            final SubscriptionBaseTransition data = getPreviousTransition();
+            return data.getPreviousPlan().getBillingPeriod().name();
+        } else {
+            return getCurrentPlan().getBillingPeriod().name();
+        }
+    }
+
+    @Override
+    public SubscriptionBaseTransition getPreviousTransition() {
+        if (transitions == null) {
+            return null;
+        }
+        final SubscriptionBaseTransitionDataIterator it = new SubscriptionBaseTransitionDataIterator(
+                clock, transitions, Order.DESC_FROM_FUTURE, Kind.SUBSCRIPTION,
+                Visibility.FROM_DISK_ONLY, TimeLimit.PAST_OR_PRESENT_ONLY);
+        return it.hasNext() ? it.next() : null;
+    }
+
+    @Override
+    public ProductCategory getCategory() {
+        return category;
+    }
+
+    public DateTime getBundleStartDate() {
+        return bundleStartDate;
+    }
+
+    @Override
+    public DateTime getChargedThroughDate() {
+        return chargedThroughDate;
+    }
+
+    @Override
+    public DateTime getPaidThroughDate() {
+        return paidThroughDate;
+    }
+
+    @Override
+    public List<SubscriptionBaseTransition> getAllTransitions() {
+        if (transitions == null) {
+            return Collections.emptyList();
+        }
+        final List<SubscriptionBaseTransition> result = new ArrayList<SubscriptionBaseTransition>();
+        final SubscriptionBaseTransitionDataIterator it = new SubscriptionBaseTransitionDataIterator(clock, transitions, Order.ASC_FROM_PAST, Kind.ALL, Visibility.ALL, TimeLimit.ALL);
+        while (it.hasNext()) {
+            result.add(it.next());
+        }
+        return result;
+    }
+
+    @Override
+    public int hashCode() {
+        final int prime = 31;
+        int result = 1;
+        result = prime * result
+                 + ((id == null) ? 0 : id.hashCode());
+        return result;
+    }
+
+    @Override
+    public boolean equals(final Object obj) {
+        if (this == obj) {
+            return true;
+        }
+        if (obj == null) {
+            return false;
+        }
+        if (getClass() != obj.getClass()) {
+            return false;
+        }
+        final DefaultSubscriptionBase other = (DefaultSubscriptionBase) obj;
+        if (id == null) {
+            if (other.id != null) {
+                return false;
+            }
+        } else if (!id.equals(other.id)) {
+            return false;
+        }
+        return true;
+    }
+
+
+    public SubscriptionBaseTransitionData getTransitionFromEvent(final SubscriptionEvent event, final int seqId) {
+        if (transitions == null || event == null) {
+            return null;
+        }
+        SubscriptionBaseTransitionData prev = null;
+        for (final SubscriptionBaseTransition cur : transitions) {
+            final SubscriptionBaseTransitionData curData = (SubscriptionBaseTransitionData) cur;
+            if (curData.getId().equals(event.getId())) {
+
+                final SubscriptionBaseTransitionData withSeq = new SubscriptionBaseTransitionData(curData, seqId);
+                return withSeq;
+            }
+            if (curData.getTotalOrdering() < event.getTotalOrdering()) {
+                prev = curData;
+            }
+        }
+        // Since UNCANCEL are not part of the transitions, we compute a new 'UNCANCEL' transition based on the event right before that UNCANCEL
+        // This is used to be able to send a bus event for uncancellation
+        if (prev != null && event.getType() == EventType.API_USER && ((ApiEvent) event).getEventType() == ApiEventType.UNCANCEL) {
+            final SubscriptionBaseTransitionData withSeq = new SubscriptionBaseTransitionData((SubscriptionBaseTransitionData) prev, EventType.API_USER, ApiEventType.UNCANCEL, seqId);
+            return withSeq;
+        }
+        return null;
+    }
+
+    public DateTime getAlignStartDate() {
+        return alignStartDate;
+    }
+
+    public long getLastEventOrderedId() {
+        final SubscriptionBaseTransitionDataIterator it = new SubscriptionBaseTransitionDataIterator(
+                clock, transitions, Order.DESC_FROM_FUTURE, Kind.SUBSCRIPTION,
+                Visibility.FROM_DISK_ONLY, TimeLimit.ALL);
+        return it.hasNext() ? ((SubscriptionBaseTransitionData) it.next()).getTotalOrdering() : -1L;
+    }
+
+    public long getActiveVersion() {
+        return activeVersion;
+    }
+
+    public List<SubscriptionBaseTransition> getBillingTransitions() {
+
+        if (transitions == null) {
+            return Collections.emptyList();
+        }
+        final List<SubscriptionBaseTransition> result = new ArrayList<SubscriptionBaseTransition>();
+        final SubscriptionBaseTransitionDataIterator it = new SubscriptionBaseTransitionDataIterator(
+                clock, transitions, Order.ASC_FROM_PAST, Kind.BILLING,
+                Visibility.ALL, TimeLimit.ALL);
+        // Remove anything prior to first CREATE or MIGRATE_BILLING
+        boolean foundInitialEvent = false;
+        while (it.hasNext()) {
+            final SubscriptionBaseTransitionData curTransition = (SubscriptionBaseTransitionData) it.next();
+            if (!foundInitialEvent) {
+                foundInitialEvent = curTransition.getEventType() == EventType.API_USER &&
+                                    (curTransition.getApiEventType() == ApiEventType.CREATE ||
+                                     curTransition.getApiEventType() == ApiEventType.MIGRATE_BILLING ||
+                                     curTransition.getApiEventType() == ApiEventType.TRANSFER);
+            }
+            if (foundInitialEvent) {
+                result.add(curTransition);
+            }
+        }
+        return result;
+    }
+
+
+    public SubscriptionBaseTransitionData getInitialTransitionForCurrentPlan() {
+        if (transitions == null) {
+            throw new SubscriptionBaseError(String.format("No transitions for subscription %s", getId()));
+        }
+
+        final SubscriptionBaseTransitionDataIterator it = new SubscriptionBaseTransitionDataIterator(clock,
+                                                                                             transitions,
+                                                                                             Order.DESC_FROM_FUTURE,
+                                                                                             Kind.SUBSCRIPTION,
+                                                                                             Visibility.ALL,
+                                                                                             TimeLimit.PAST_OR_PRESENT_ONLY);
+
+        while (it.hasNext()) {
+            final SubscriptionBaseTransitionData cur = (SubscriptionBaseTransitionData) it.next();
+            if (cur.getTransitionType() == SubscriptionBaseTransitionType.CREATE
+                || cur.getTransitionType() == SubscriptionBaseTransitionType.RE_CREATE
+                || cur.getTransitionType() == SubscriptionBaseTransitionType.TRANSFER
+                || cur.getTransitionType() == SubscriptionBaseTransitionType.CHANGE
+                || cur.getTransitionType() == SubscriptionBaseTransitionType.MIGRATE_ENTITLEMENT) {
+                return cur;
+            }
+        }
+
+        throw new SubscriptionBaseError(String.format("Failed to find InitialTransitionForCurrentPlan id = %s", getId()));
+    }
+
+    public boolean isSubscriptionFutureCancelled() {
+        return getFutureEndDate() != null;
+    }
+
+    public DateTime getPlanChangeEffectiveDate(final BillingActionPolicy policy,
+                                               final DateTime requestedDate) {
+
+        if (policy == BillingActionPolicy.IMMEDIATE) {
+            return requestedDate;
+        }
+        if (policy != BillingActionPolicy.END_OF_TERM) {
+            throw new SubscriptionBaseError(String.format(
+                    "Unexpected policy type %s", policy.toString()));
+        }
+
+        if (chargedThroughDate == null) {
+            return requestedDate;
+        } else {
+            return chargedThroughDate.isBefore(requestedDate) ? requestedDate
+                                                              : chargedThroughDate;
+        }
+    }
+
+    public DateTime getCurrentPhaseStart() {
+
+        if (transitions == null) {
+            throw new SubscriptionBaseError(String.format(
+                    "No transitions for subscription %s", getId()));
+        }
+        final SubscriptionBaseTransitionDataIterator it = new SubscriptionBaseTransitionDataIterator(
+                clock, transitions, Order.DESC_FROM_FUTURE, Kind.SUBSCRIPTION,
+                Visibility.ALL, TimeLimit.PAST_OR_PRESENT_ONLY);
+        while (it.hasNext()) {
+            final SubscriptionBaseTransitionData cur = (SubscriptionBaseTransitionData) it.next();
+
+            if (cur.getTransitionType() == SubscriptionBaseTransitionType.PHASE
+                || cur.getTransitionType() == SubscriptionBaseTransitionType.TRANSFER
+                || cur.getTransitionType() == SubscriptionBaseTransitionType.CREATE
+                || cur.getTransitionType() == SubscriptionBaseTransitionType.RE_CREATE
+                || cur.getTransitionType() == SubscriptionBaseTransitionType.CHANGE
+                || cur.getTransitionType() == SubscriptionBaseTransitionType.MIGRATE_ENTITLEMENT) {
+                return cur.getEffectiveTransitionTime();
+            }
+        }
+        throw new SubscriptionBaseError(String.format(
+                "Failed to find CurrentPhaseStart id = %s", getId().toString()));
+    }
+
+    public void rebuildTransitions(final List<SubscriptionEvent> inputEvents, final Catalog catalog) {
+
+        if (inputEvents == null) {
+            return;
+        }
+
+        this.events = inputEvents;
+
+        UUID nextUserToken = null;
+
+        UUID nextEventId = null;
+        DateTime nextCreatedDate = null;
+        SubscriptionState nextState = null;
+        String nextPlanName = null;
+        String nextPhaseName = null;
+        String nextPriceListName = null;
+
+        UUID prevEventId = null;
+        DateTime prevCreatedDate = null;
+        SubscriptionState previousState = null;
+        PriceList previousPriceList = null;
+        Plan previousPlan = null;
+        PlanPhase previousPhase = null;
+
+        transitions = new LinkedList<SubscriptionBaseTransition>();
+
+        for (final SubscriptionEvent cur : inputEvents) {
+
+            if (!cur.isActive() || cur.getActiveVersion() < activeVersion) {
+                continue;
+            }
+
+            ApiEventType apiEventType = null;
+
+            boolean isFromDisk = true;
+
+            nextEventId = cur.getId();
+            nextCreatedDate = cur.getCreatedDate();
+
+            switch (cur.getType()) {
+
+                case PHASE:
+                    final PhaseEvent phaseEV = (PhaseEvent) cur;
+                    nextPhaseName = phaseEV.getPhase();
+                    break;
+
+                case API_USER:
+                    final ApiEvent userEV = (ApiEvent) cur;
+                    apiEventType = userEV.getEventType();
+                    isFromDisk = userEV.isFromDisk();
+
+                    switch (apiEventType) {
+                        case TRANSFER:
+                        case MIGRATE_BILLING:
+                        case MIGRATE_ENTITLEMENT:
+                        case CREATE:
+                        case RE_CREATE:
+                            prevEventId = null;
+                            prevCreatedDate = null;
+                            previousState = null;
+                            previousPlan = null;
+                            previousPhase = null;
+                            previousPriceList = null;
+                            nextState = SubscriptionState.ACTIVE;
+                            nextPlanName = userEV.getEventPlan();
+                            nextPhaseName = userEV.getEventPlanPhase();
+                            nextPriceListName = userEV.getPriceList();
+                            break;
+                        case CHANGE:
+                            nextPlanName = userEV.getEventPlan();
+                            nextPhaseName = userEV.getEventPlanPhase();
+                            nextPriceListName = userEV.getPriceList();
+                            break;
+                        case CANCEL:
+                            nextState = SubscriptionState.CANCELLED;
+                            nextPlanName = null;
+                            nextPhaseName = null;
+                            break;
+                        case UNCANCEL:
+                        default:
+                            throw new SubscriptionBaseError(String.format(
+                                    "Unexpected UserEvent type = %s", userEV
+                                    .getEventType().toString()));
+                    }
+                    break;
+                default:
+                    throw new SubscriptionBaseError(String.format(
+                            "Unexpected Event type = %s", cur.getType()));
+            }
+
+            Plan nextPlan = null;
+            PlanPhase nextPhase = null;
+            PriceList nextPriceList = null;
+
+            try {
+                nextPlan = (nextPlanName != null) ? catalog.findPlan(nextPlanName, cur.getRequestedDate(), getAlignStartDate()) : null;
+                nextPhase = (nextPhaseName != null) ? catalog.findPhase(nextPhaseName, cur.getRequestedDate(), getAlignStartDate()) : null;
+                nextPriceList = (nextPriceListName != null) ? catalog.findPriceList(nextPriceListName, cur.getRequestedDate()) : null;
+            } catch (CatalogApiException e) {
+                log.error(String.format("Failed to build transition for subscription %s", id), e);
+            }
+
+            final SubscriptionBaseTransitionData transition = new SubscriptionBaseTransitionData(
+                    cur.getId(), id, bundleId, cur.getType(), apiEventType,
+                    cur.getRequestedDate(), cur.getEffectiveDate(),
+                    prevEventId, prevCreatedDate,
+                    previousState, previousPlan, previousPhase,
+                    previousPriceList,
+                    nextEventId, nextCreatedDate,
+                    nextState, nextPlan, nextPhase,
+                    nextPriceList, cur.getTotalOrdering(), nextUserToken,
+                    isFromDisk);
+
+            transitions.add(transition);
+
+            previousState = nextState;
+            previousPlan = nextPlan;
+            previousPhase = nextPhase;
+            previousPriceList = nextPriceList;
+            prevEventId = nextEventId;
+            prevCreatedDate = nextCreatedDate;
+
+        }
+    }
+}
diff --git a/subscription/src/main/java/com/ning/billing/subscription/api/user/DefaultSubscriptionBaseApiService.java b/subscription/src/main/java/com/ning/billing/subscription/api/user/DefaultSubscriptionBaseApiService.java
new file mode 100644
index 0000000..08fc4a5
--- /dev/null
+++ b/subscription/src/main/java/com/ning/billing/subscription/api/user/DefaultSubscriptionBaseApiService.java
@@ -0,0 +1,440 @@
+/*
+ * Copyright 2010-2013 Ning, Inc.
+ *
+ * Ning licenses this file to you under the Apache License, version 2.0
+ * (the "License"); you may not use this file except in compliance with the
+ * License.  You may obtain a copy of the License at:
+ *
+ *    http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
+ * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.  See the
+ * License for the specific language governing permissions and limitations
+ * under the License.
+ */
+
+package com.ning.billing.subscription.api.user;
+
+import java.util.ArrayList;
+import java.util.LinkedList;
+import java.util.List;
+import java.util.UUID;
+
+import org.joda.time.DateTime;
+
+import com.ning.billing.ErrorCode;
+import com.ning.billing.ObjectType;
+import com.ning.billing.catalog.api.BillingActionPolicy;
+import com.ning.billing.catalog.api.BillingPeriod;
+import com.ning.billing.catalog.api.CatalogApiException;
+import com.ning.billing.catalog.api.CatalogService;
+import com.ning.billing.catalog.api.PhaseType;
+import com.ning.billing.catalog.api.Plan;
+import com.ning.billing.catalog.api.PlanChangeResult;
+import com.ning.billing.catalog.api.PlanPhase;
+import com.ning.billing.catalog.api.PlanPhaseSpecifier;
+import com.ning.billing.catalog.api.PlanSpecifier;
+import com.ning.billing.catalog.api.PriceList;
+import com.ning.billing.catalog.api.PriceListSet;
+import com.ning.billing.catalog.api.Product;
+import com.ning.billing.catalog.api.ProductCategory;
+import com.ning.billing.subscription.alignment.PlanAligner;
+import com.ning.billing.subscription.alignment.TimedPhase;
+import com.ning.billing.subscription.api.SubscriptionBaseApiService;
+import com.ning.billing.subscription.api.SubscriptionBase;
+import com.ning.billing.subscription.engine.addon.AddonUtils;
+import com.ning.billing.subscription.engine.dao.SubscriptionDao;
+import com.ning.billing.subscription.events.SubscriptionEvent;
+import com.ning.billing.subscription.events.phase.PhaseEvent;
+import com.ning.billing.subscription.events.phase.PhaseEventData;
+import com.ning.billing.subscription.events.user.ApiEvent;
+import com.ning.billing.subscription.events.user.ApiEventBuilder;
+import com.ning.billing.subscription.events.user.ApiEventCancel;
+import com.ning.billing.subscription.events.user.ApiEventChange;
+import com.ning.billing.subscription.events.user.ApiEventCreate;
+import com.ning.billing.subscription.events.user.ApiEventReCreate;
+import com.ning.billing.subscription.events.user.ApiEventUncancel;
+import com.ning.billing.subscription.exceptions.SubscriptionBaseError;
+import com.ning.billing.util.callcontext.CallContext;
+import com.ning.billing.util.callcontext.InternalCallContext;
+import com.ning.billing.util.callcontext.InternalCallContextFactory;
+import com.ning.billing.clock.Clock;
+import com.ning.billing.clock.DefaultClock;
+
+import com.google.inject.Inject;
+
+public class DefaultSubscriptionBaseApiService implements SubscriptionBaseApiService {
+
+    private final Clock clock;
+    private final SubscriptionDao dao;
+    private final CatalogService catalogService;
+    private final PlanAligner planAligner;
+    private final AddonUtils addonUtils;
+    private final InternalCallContextFactory internalCallContextFactory;
+
+    @Inject
+    public DefaultSubscriptionBaseApiService(final Clock clock, final SubscriptionDao dao, final CatalogService catalogService,
+                                             final PlanAligner planAligner, final AddonUtils addonUtils,
+                                             final InternalCallContextFactory internalCallContextFactory) {
+        this.clock = clock;
+        this.catalogService = catalogService;
+        this.planAligner = planAligner;
+        this.dao = dao;
+        this.addonUtils = addonUtils;
+        this.internalCallContextFactory = internalCallContextFactory;
+    }
+
+
+    @Override
+    public DefaultSubscriptionBase createPlan(final SubscriptionBuilder builder, final Plan plan, final PhaseType initialPhase,
+                                       final String realPriceList, final DateTime requestedDate, final DateTime effectiveDate, final DateTime processedDate,
+                                       final CallContext context) throws SubscriptionBaseApiException {
+        final DefaultSubscriptionBase subscription = new DefaultSubscriptionBase(builder, this, clock);
+
+        createFromSubscription(subscription, plan, initialPhase, realPriceList, requestedDate, effectiveDate, processedDate, false, context);
+        return subscription;
+    }
+
+    @Override
+    public boolean recreatePlan(final DefaultSubscriptionBase subscription, final PlanPhaseSpecifier spec, final DateTime requestedDateWithMs, final CallContext context)
+            throws SubscriptionBaseApiException {
+        final SubscriptionState currentState = subscription.getState();
+        if (currentState != null && currentState != SubscriptionState.CANCELLED) {
+            throw new SubscriptionBaseApiException(ErrorCode.SUB_RECREATE_BAD_STATE, subscription.getId(), currentState);
+        }
+
+        final DateTime now = clock.getUTCNow();
+        final DateTime requestedDate = (requestedDateWithMs != null) ? DefaultClock.truncateMs(requestedDateWithMs) : now;
+        validateRequestedDate(subscription, now, requestedDate);
+
+        try {
+            final String realPriceList = (spec.getPriceListName() == null) ? PriceListSet.DEFAULT_PRICELIST_NAME : spec.getPriceListName();
+            final Plan plan = catalogService.getFullCatalog().findPlan(spec.getProductName(), spec.getBillingPeriod(), realPriceList, requestedDate);
+            final PlanPhase phase = plan.getAllPhases()[0];
+            if (phase == null) {
+                throw new SubscriptionBaseError(String.format("No initial PlanPhase for Product %s, term %s and set %s does not exist in the catalog",
+                                                         spec.getProductName(), spec.getBillingPeriod().toString(), realPriceList));
+            }
+
+            final DateTime effectiveDate = requestedDate;
+            final DateTime processedDate = now;
+
+            createFromSubscription(subscription, plan, spec.getPhaseType(), realPriceList, requestedDate, effectiveDate, processedDate, true, context);
+            return true;
+        } catch (CatalogApiException e) {
+            throw new SubscriptionBaseApiException(e);
+        }
+    }
+
+    private void createFromSubscription(final DefaultSubscriptionBase subscription, final Plan plan, final PhaseType initialPhase,
+                                        final String realPriceList, final DateTime requestedDate, final DateTime effectiveDate, final DateTime processedDate,
+                                        final boolean reCreate, final CallContext context) throws SubscriptionBaseApiException {
+        final InternalCallContext internalCallContext = createCallContextFromBundleId(subscription.getBundleId(), context);
+
+        try {
+            final TimedPhase[] curAndNextPhases = planAligner.getCurrentAndNextTimedPhaseOnCreate(subscription, plan, initialPhase, realPriceList, requestedDate, effectiveDate);
+
+            final ApiEventBuilder createBuilder = new ApiEventBuilder()
+                    .setSubscriptionId(subscription.getId())
+                    .setEventPlan(plan.getName())
+                    .setEventPlanPhase(curAndNextPhases[0].getPhase().getName())
+                    .setEventPriceList(realPriceList)
+                    .setActiveVersion(subscription.getActiveVersion())
+                    .setProcessedDate(processedDate)
+                    .setEffectiveDate(effectiveDate)
+                    .setRequestedDate(requestedDate)
+                    .setFromDisk(true);
+            final ApiEvent creationEvent = (reCreate) ? new ApiEventReCreate(createBuilder) : new ApiEventCreate(createBuilder);
+
+            final TimedPhase nextTimedPhase = curAndNextPhases[1];
+            final PhaseEvent nextPhaseEvent = (nextTimedPhase != null) ?
+                                              PhaseEventData.createNextPhaseEvent(nextTimedPhase.getPhase().getName(), subscription, processedDate, nextTimedPhase.getStartPhase()) :
+                                              null;
+            final List<SubscriptionEvent> events = new ArrayList<SubscriptionEvent>();
+            events.add(creationEvent);
+            if (nextPhaseEvent != null) {
+                events.add(nextPhaseEvent);
+            }
+            if (reCreate) {
+                dao.recreateSubscription(subscription, events, internalCallContext);
+            } else {
+                dao.createSubscription(subscription, events, internalCallContext);
+            }
+            subscription.rebuildTransitions(dao.getEventsForSubscription(subscription.getId(), internalCallContext), catalogService.getFullCatalog());
+        } catch (CatalogApiException e) {
+            throw new SubscriptionBaseApiException(e);
+        }
+    }
+
+    @Override
+    public boolean cancel(final DefaultSubscriptionBase subscription, final DateTime requestedDateWithMs, final CallContext context) throws SubscriptionBaseApiException {
+        try {
+            final SubscriptionState currentState = subscription.getState();
+            if (currentState != SubscriptionState.ACTIVE) {
+                throw new SubscriptionBaseApiException(ErrorCode.SUB_CANCEL_BAD_STATE, subscription.getId(), currentState);
+            }
+            final DateTime now = clock.getUTCNow();
+            final DateTime requestedDate = (requestedDateWithMs != null) ? DefaultClock.truncateMs(requestedDateWithMs) : now;
+
+            final Plan currentPlan = subscription.getCurrentPlan();
+            final PlanPhaseSpecifier planPhase = new PlanPhaseSpecifier(currentPlan.getProduct().getName(),
+                                                                        currentPlan.getProduct().getCategory(),
+                                                                        subscription.getCurrentPlan().getBillingPeriod(),
+                                                                        subscription.getCurrentPriceList().getName(),
+                                                                        subscription.getCurrentPhase().getPhaseType());
+
+            final BillingActionPolicy policy = catalogService.getFullCatalog().planCancelPolicy(planPhase, requestedDate);
+
+            return doCancelPlan(subscription, requestedDateWithMs, now, policy, context);
+        } catch (CatalogApiException e) {
+            throw new SubscriptionBaseApiException(e);
+        }
+    }
+
+    @Override
+    public boolean cancelWithPolicy(final DefaultSubscriptionBase subscription, final DateTime requestedDateWithMs, final BillingActionPolicy policy, final CallContext context) throws SubscriptionBaseApiException {
+        final SubscriptionState currentState = subscription.getState();
+        if (currentState != SubscriptionState.ACTIVE) {
+            throw new SubscriptionBaseApiException(ErrorCode.SUB_CANCEL_BAD_STATE, subscription.getId(), currentState);
+        }
+        final DateTime now = clock.getUTCNow();
+        return doCancelPlan(subscription, requestedDateWithMs, now, policy, context);
+    }
+
+    private boolean doCancelPlan(final DefaultSubscriptionBase subscription, final DateTime requestedDateWithMs, final DateTime now, final BillingActionPolicy policy, final CallContext context) throws SubscriptionBaseApiException {
+
+        final DateTime requestedDate = (requestedDateWithMs != null) ? DefaultClock.truncateMs(requestedDateWithMs) : now;
+        validateRequestedDate(subscription, now, requestedDate);
+        final DateTime effectiveDate = subscription.getPlanChangeEffectiveDate(policy, requestedDate);
+
+        final SubscriptionEvent cancelEvent = new ApiEventCancel(new ApiEventBuilder()
+                                                                        .setSubscriptionId(subscription.getId())
+                                                                        .setActiveVersion(subscription.getActiveVersion())
+                                                                        .setProcessedDate(now)
+                                                                        .setEffectiveDate(effectiveDate)
+                                                                        .setRequestedDate(requestedDate)
+                                                                        .setFromDisk(true));
+
+        final InternalCallContext internalCallContext = createCallContextFromBundleId(subscription.getBundleId(), context);
+        dao.cancelSubscription(subscription, cancelEvent, internalCallContext, 0);
+        subscription.rebuildTransitions(dao.getEventsForSubscription(subscription.getId(), internalCallContext), catalogService.getFullCatalog());
+
+        cancelAddOnsIfRequired(subscription, effectiveDate, internalCallContext);
+
+        return (policy == BillingActionPolicy.IMMEDIATE);
+    }
+
+    @Override
+    public boolean uncancel(final DefaultSubscriptionBase subscription, final CallContext context) throws SubscriptionBaseApiException {
+        if (!subscription.isSubscriptionFutureCancelled()) {
+            throw new SubscriptionBaseApiException(ErrorCode.SUB_UNCANCEL_BAD_STATE, subscription.getId().toString());
+        }
+
+        final DateTime now = clock.getUTCNow();
+        final SubscriptionEvent uncancelEvent = new ApiEventUncancel(new ApiEventBuilder()
+                                                                            .setSubscriptionId(subscription.getId())
+                                                                            .setActiveVersion(subscription.getActiveVersion())
+                                                                            .setProcessedDate(now)
+                                                                            .setRequestedDate(now)
+                                                                            .setEffectiveDate(now)
+                                                                            .setFromDisk(true));
+
+        final List<SubscriptionEvent> uncancelEvents = new ArrayList<SubscriptionEvent>();
+        uncancelEvents.add(uncancelEvent);
+
+        final TimedPhase nextTimedPhase = planAligner.getNextTimedPhase(subscription, now, now);
+        final PhaseEvent nextPhaseEvent = (nextTimedPhase != null) ?
+                                          PhaseEventData.createNextPhaseEvent(nextTimedPhase.getPhase().getName(), subscription, now, nextTimedPhase.getStartPhase()) :
+                                          null;
+        if (nextPhaseEvent != null) {
+            uncancelEvents.add(nextPhaseEvent);
+        }
+
+        final InternalCallContext internalCallContext = createCallContextFromBundleId(subscription.getBundleId(), context);
+        dao.uncancelSubscription(subscription, uncancelEvents, internalCallContext);
+        subscription.rebuildTransitions(dao.getEventsForSubscription(subscription.getId(), internalCallContext), catalogService.getFullCatalog());
+
+        return true;
+    }
+
+    @Override
+    public boolean changePlan(final DefaultSubscriptionBase subscription, final String productName, final BillingPeriod term,
+                              final String priceList, final DateTime requestedDateWithMs, final CallContext context)
+            throws SubscriptionBaseApiException {
+        final DateTime now = clock.getUTCNow();
+        final DateTime requestedDate = (requestedDateWithMs != null) ? DefaultClock.truncateMs(requestedDateWithMs) : now;
+
+        validateRequestedDate(subscription, now, requestedDate);
+        validateSubscriptionState(subscription);
+
+        final PlanChangeResult planChangeResult = getPlanChangeResult(subscription, productName, term, priceList, requestedDate);
+        final BillingActionPolicy policy = planChangeResult.getPolicy();
+
+        try {
+            return doChangePlan(subscription, planChangeResult, now, requestedDate, productName, term, policy, context);
+        } catch (CatalogApiException e) {
+            throw new SubscriptionBaseApiException(e);
+        }
+    }
+
+    @Override
+    public boolean changePlanWithPolicy(final DefaultSubscriptionBase subscription, final String productName, final BillingPeriod term,
+                                        final String priceList, final DateTime requestedDateWithMs, final BillingActionPolicy policy, final CallContext context)
+            throws SubscriptionBaseApiException {
+        final DateTime now = clock.getUTCNow();
+        final DateTime requestedDate = (requestedDateWithMs != null) ? DefaultClock.truncateMs(requestedDateWithMs) : now;
+
+        validateRequestedDate(subscription, now, requestedDate);
+        validateSubscriptionState(subscription);
+
+        final PlanChangeResult planChangeResult = getPlanChangeResult(subscription, productName, term, priceList, requestedDate);
+
+        try {
+            return doChangePlan(subscription, planChangeResult, now, requestedDate, productName, term, policy, context);
+        } catch (CatalogApiException e) {
+            throw new SubscriptionBaseApiException(e);
+        }
+    }
+
+    private PlanChangeResult getPlanChangeResult(final DefaultSubscriptionBase subscription, final String productName,
+                                                 final BillingPeriod term, final String priceList, final DateTime requestedDate) throws SubscriptionBaseApiException {
+        final PlanChangeResult planChangeResult;
+        try {
+            final Product destProduct = catalogService.getFullCatalog().findProduct(productName, requestedDate);
+            final Plan currentPlan = subscription.getCurrentPlan();
+            final PriceList currentPriceList = subscription.getCurrentPriceList();
+            final PlanPhaseSpecifier fromPlanPhase = new PlanPhaseSpecifier(currentPlan.getProduct().getName(),
+                                                                            currentPlan.getProduct().getCategory(),
+                                                                            currentPlan.getBillingPeriod(),
+                                                                            currentPriceList.getName(),
+                                                                            subscription.getCurrentPhase().getPhaseType());
+            final PlanSpecifier toPlanPhase = new PlanSpecifier(productName,
+                                                                destProduct.getCategory(),
+                                                                term,
+                                                                priceList);
+
+            planChangeResult = catalogService.getFullCatalog().planChange(fromPlanPhase, toPlanPhase, requestedDate);
+        } catch (CatalogApiException e) {
+            throw new SubscriptionBaseApiException(e);
+        }
+
+        return planChangeResult;
+    }
+
+    private boolean doChangePlan(final DefaultSubscriptionBase subscription, final PlanChangeResult planChangeResult,
+                                 final DateTime now, final DateTime requestedDate, final String productName,
+                                 final BillingPeriod term, final BillingActionPolicy policy, final CallContext context) throws SubscriptionBaseApiException, CatalogApiException {
+        final PriceList newPriceList = planChangeResult.getNewPriceList();
+
+        final Plan newPlan = catalogService.getFullCatalog().findPlan(productName, term, newPriceList.getName(), requestedDate, subscription.getStartDate());
+        final DateTime effectiveDate = subscription.getPlanChangeEffectiveDate(policy, requestedDate);
+
+        final TimedPhase currentTimedPhase = planAligner.getCurrentTimedPhaseOnChange(subscription, newPlan, newPriceList.getName(), requestedDate, effectiveDate);
+
+        final SubscriptionEvent changeEvent = new ApiEventChange(new ApiEventBuilder()
+                                                                        .setSubscriptionId(subscription.getId())
+                                                                        .setEventPlan(newPlan.getName())
+                                                                        .setEventPlanPhase(currentTimedPhase.getPhase().getName())
+                                                                        .setEventPriceList(newPriceList.getName())
+                                                                        .setActiveVersion(subscription.getActiveVersion())
+                                                                        .setProcessedDate(now)
+                                                                        .setEffectiveDate(effectiveDate)
+                                                                        .setRequestedDate(requestedDate)
+                                                                        .setFromDisk(true));
+
+        final TimedPhase nextTimedPhase = planAligner.getNextTimedPhaseOnChange(subscription, newPlan, newPriceList.getName(), requestedDate, effectiveDate);
+        final PhaseEvent nextPhaseEvent = (nextTimedPhase != null) ?
+                                          PhaseEventData.createNextPhaseEvent(nextTimedPhase.getPhase().getName(), subscription, now, nextTimedPhase.getStartPhase()) :
+                                          null;
+
+        final List<SubscriptionEvent> changeEvents = new ArrayList<SubscriptionEvent>();
+        // Only add the PHASE if it does not coincide with the CHANGE, if not this is 'just' a CHANGE.
+        if (nextPhaseEvent != null && !nextPhaseEvent.getEffectiveDate().equals(changeEvent.getEffectiveDate())) {
+            changeEvents.add(nextPhaseEvent);
+        }
+        changeEvents.add(changeEvent);
+
+        final InternalCallContext internalCallContext = createCallContextFromBundleId(subscription.getBundleId(), context);
+        dao.changePlan(subscription, changeEvents, internalCallContext);
+        subscription.rebuildTransitions(dao.getEventsForSubscription(subscription.getId(), internalCallContext), catalogService.getFullCatalog());
+
+        cancelAddOnsIfRequired(subscription, effectiveDate, internalCallContext);
+
+        return (policy == BillingActionPolicy.IMMEDIATE);
+    }
+
+
+    public int cancelAddOnsIfRequired(final DefaultSubscriptionBase baseSubscription, final DateTime effectiveDate, final InternalCallContext context) {
+
+        // If cancellation/change occur in the future, there is nothing to do
+        final DateTime now = clock.getUTCNow();
+        if (effectiveDate.compareTo(now) > 0) {
+            return 0;
+        }
+
+        final Product baseProduct = (baseSubscription.getState() == SubscriptionState.CANCELLED) ? null : baseSubscription.getCurrentPlan().getProduct();
+
+        final List<SubscriptionBase> subscriptions = dao.getSubscriptions(baseSubscription.getBundleId(), context);
+
+        final List<DefaultSubscriptionBase> subscriptionsToBeCancelled = new LinkedList<DefaultSubscriptionBase>();
+        final List<SubscriptionEvent> cancelEvents = new LinkedList<SubscriptionEvent>();
+
+        for (final SubscriptionBase subscription : subscriptions) {
+            final DefaultSubscriptionBase cur = (DefaultSubscriptionBase) subscription;
+            if (cur.getState() == SubscriptionState.CANCELLED ||
+                cur.getCategory() != ProductCategory.ADD_ON) {
+                continue;
+            }
+
+            final Plan addonCurrentPlan = cur.getCurrentPlan();
+            if (baseProduct == null ||
+                addonUtils.isAddonIncluded(baseProduct, addonCurrentPlan) ||
+                !addonUtils.isAddonAvailable(baseProduct, addonCurrentPlan)) {
+                //
+                // Perform AO cancellation using the effectiveDate of the BP
+                //
+                final SubscriptionEvent cancelEvent = new ApiEventCancel(new ApiEventBuilder()
+                                                                                .setSubscriptionId(cur.getId())
+                                                                                .setActiveVersion(cur.getActiveVersion())
+                                                                                .setProcessedDate(now)
+                                                                                .setEffectiveDate(effectiveDate)
+                                                                                .setRequestedDate(now)
+                                                                                .setFromDisk(true));
+                subscriptionsToBeCancelled.add(cur);
+                cancelEvents.add(cancelEvent);
+            }
+        }
+
+        dao.cancelSubscriptions(subscriptionsToBeCancelled, cancelEvents, context);
+        return subscriptionsToBeCancelled.size();
+    }
+
+    private void validateRequestedDate(final DefaultSubscriptionBase subscription, final DateTime now, final DateTime requestedDate)
+            throws SubscriptionBaseApiException {
+
+        if (requestedDate.isAfter(now)) {
+            throw new SubscriptionBaseApiException(ErrorCode.SUB_INVALID_REQUESTED_FUTURE_DATE, requestedDate.toString());
+        }
+
+        final SubscriptionBaseTransition previousTransition = subscription.getPreviousTransition();
+        if (previousTransition != null && previousTransition.getEffectiveTransitionTime().isAfter(requestedDate)) {
+            throw new SubscriptionBaseApiException(ErrorCode.SUB_INVALID_REQUESTED_DATE,
+                                                  requestedDate.toString(), previousTransition.getEffectiveTransitionTime());
+        }
+    }
+
+    private void validateSubscriptionState(final DefaultSubscriptionBase subscription) throws SubscriptionBaseApiException {
+        final SubscriptionState currentState = subscription.getState();
+        if (currentState != SubscriptionState.ACTIVE) {
+            throw new SubscriptionBaseApiException(ErrorCode.SUB_CHANGE_NON_ACTIVE, subscription.getId(), currentState);
+        }
+        if (subscription.isSubscriptionFutureCancelled()) {
+            throw new SubscriptionBaseApiException(ErrorCode.SUB_CHANGE_FUTURE_CANCELLED, subscription.getId());
+        }
+    }
+
+    private InternalCallContext createCallContextFromBundleId(final UUID bundleId, final CallContext context) {
+        return internalCallContextFactory.createInternalCallContext(bundleId, ObjectType.BUNDLE, context);
+    }
+}
diff --git a/subscription/src/main/java/com/ning/billing/subscription/api/user/DefaultSubscriptionBaseBundle.java b/subscription/src/main/java/com/ning/billing/subscription/api/user/DefaultSubscriptionBaseBundle.java
new file mode 100644
index 0000000..e7e1146
--- /dev/null
+++ b/subscription/src/main/java/com/ning/billing/subscription/api/user/DefaultSubscriptionBaseBundle.java
@@ -0,0 +1,129 @@
+/*
+ * Copyright 2010-2013 Ning, Inc.
+ *
+ * Ning licenses this file to you under the Apache License, version 2.0
+ * (the "License"); you may not use this file except in compliance with the
+ * License.  You may obtain a copy of the License at:
+ *
+ *    http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
+ * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.  See the
+ * License for the specific language governing permissions and limitations
+ * under the License.
+ */
+
+package com.ning.billing.subscription.api.user;
+
+import java.util.UUID;
+
+import javax.annotation.Nullable;
+
+import org.joda.time.DateTime;
+
+import com.ning.billing.entitlement.api.BlockingState;
+import com.ning.billing.overdue.OverdueState;
+import com.ning.billing.util.entity.EntityBase;
+
+public class DefaultSubscriptionBaseBundle extends EntityBase implements SubscriptionBaseBundle {
+
+    private final String key;
+    private final UUID accountId;
+    private final DateTime lastSysUpdateDate;
+    private final OverdueState<SubscriptionBaseBundle> overdueState;
+
+    public DefaultSubscriptionBaseBundle(final String name, final UUID accountId, final DateTime startDate) {
+        this(UUID.randomUUID(), name, accountId, startDate);
+    }
+
+    public DefaultSubscriptionBaseBundle(final UUID id, final String key, final UUID accountId, final DateTime lastSysUpdate) {
+        this(id, key, accountId, lastSysUpdate, null);
+    }
+
+    public DefaultSubscriptionBaseBundle(final UUID id, final String key, final UUID accountId, final DateTime lastSysUpdate, @Nullable final OverdueState<SubscriptionBaseBundle> overdueState) {
+        // TODO add column in bundles table
+        super(id, null, null);
+        this.key = key;
+        this.accountId = accountId;
+        this.lastSysUpdateDate = lastSysUpdate;
+        this.overdueState = overdueState;
+    }
+
+    @Override
+    public String getExternalKey() {
+        return key;
+    }
+
+    @Override
+    public UUID getAccountId() {
+        return accountId;
+    }
+
+    public DateTime getLastSysUpdateDate() {
+        return lastSysUpdateDate;
+    }
+
+    @Override
+    public OverdueState<SubscriptionBaseBundle> getOverdueState() {
+        return overdueState;
+    }
+
+    @Override
+    public BlockingState getBlockingState() {
+        throw new UnsupportedOperationException();
+    }
+
+    @Override
+    public String toString() {
+        final StringBuilder sb = new StringBuilder();
+        sb.append("DefaultSubscriptionBaseBundle");
+        sb.append("{accountId=").append(accountId);
+        sb.append(", id=").append(id);
+        sb.append(", key='").append(key).append('\'');
+        sb.append(", lastSysUpdateDate=").append(lastSysUpdateDate);
+        sb.append(", overdueState=").append(overdueState);
+        sb.append('}');
+        return sb.toString();
+    }
+
+    @Override
+    public boolean equals(final Object o) {
+        if (this == o) {
+            return true;
+        }
+        if (o == null || getClass() != o.getClass()) {
+            return false;
+        }
+
+        final DefaultSubscriptionBaseBundle that = (DefaultSubscriptionBaseBundle) o;
+
+        if (accountId != null ? !accountId.equals(that.accountId) : that.accountId != null) {
+            return false;
+        }
+        if (id != null ? !id.equals(that.id) : that.id != null) {
+            return false;
+        }
+        if (key != null ? !key.equals(that.key) : that.key != null) {
+            return false;
+        }
+        if (lastSysUpdateDate != null ? !lastSysUpdateDate.equals(that.lastSysUpdateDate) : that.lastSysUpdateDate != null) {
+            return false;
+        }
+        if (overdueState != null ? !overdueState.equals(that.overdueState) : that.overdueState != null) {
+            return false;
+        }
+
+        return true;
+    }
+
+    @Override
+    public int hashCode() {
+        int result = id != null ? id.hashCode() : 0;
+        result = 31 * result + (key != null ? key.hashCode() : 0);
+        result = 31 * result + (accountId != null ? accountId.hashCode() : 0);
+        result = 31 * result + (lastSysUpdateDate != null ? lastSysUpdateDate.hashCode() : 0);
+        result = 31 * result + (overdueState != null ? overdueState.hashCode() : 0);
+        return result;
+    }
+}
diff --git a/subscription/src/main/java/com/ning/billing/subscription/api/user/SubscriptionBaseTransitionData.java b/subscription/src/main/java/com/ning/billing/subscription/api/user/SubscriptionBaseTransitionData.java
index aafd24e..feded01 100644
--- a/subscription/src/main/java/com/ning/billing/subscription/api/user/SubscriptionBaseTransitionData.java
+++ b/subscription/src/main/java/com/ning/billing/subscription/api/user/SubscriptionBaseTransitionData.java
@@ -26,7 +26,7 @@ import com.ning.billing.catalog.api.PriceList;
 import com.ning.billing.subscription.api.SubscriptionBaseTransitionType;
 import com.ning.billing.subscription.events.SubscriptionEvent.EventType;
 import com.ning.billing.subscription.events.user.ApiEventType;
-import com.ning.billing.subscription.exceptions.SubscriptionError;
+import com.ning.billing.subscription.exceptions.SubscriptionBaseError;
 
 public class SubscriptionBaseTransitionData implements SubscriptionBaseTransition {
     private final Long totalOrdering;
@@ -226,7 +226,7 @@ public class SubscriptionBaseTransitionData implements SubscriptionBaseTransitio
             case PHASE:
                 return SubscriptionBaseTransitionType.PHASE;
             default:
-                throw new SubscriptionError("Unexpected event type " + eventType);
+                throw new SubscriptionBaseError("Unexpected event type " + eventType);
         }
     }
 
diff --git a/subscription/src/main/java/com/ning/billing/subscription/api/user/SubscriptionBaseTransitionDataIterator.java b/subscription/src/main/java/com/ning/billing/subscription/api/user/SubscriptionBaseTransitionDataIterator.java
new file mode 100644
index 0000000..5f35887
--- /dev/null
+++ b/subscription/src/main/java/com/ning/billing/subscription/api/user/SubscriptionBaseTransitionDataIterator.java
@@ -0,0 +1,115 @@
+/*
+ * Copyright 2010-2013 Ning, Inc.
+ *
+ * Ning licenses this file to you under the Apache License, version 2.0
+ * (the "License"); you may not use this file except in compliance with the
+ * License.  You may obtain a copy of the License at:
+ *
+ *    http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
+ * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.  See the
+ * License for the specific language governing permissions and limitations
+ * under the License.
+ */
+
+package com.ning.billing.subscription.api.user;
+
+import java.util.Iterator;
+import java.util.LinkedList;
+
+import com.ning.billing.subscription.exceptions.SubscriptionBaseError;
+import com.ning.billing.subscription.api.SubscriptionBaseTransitionType;
+import com.ning.billing.clock.Clock;
+
+public class SubscriptionBaseTransitionDataIterator implements Iterator<SubscriptionBaseTransition> {
+
+    private final Clock clock;
+    private final Iterator<SubscriptionBaseTransition> it;
+    private final Kind kind;
+    private final TimeLimit timeLimit;
+    private final Visibility visibility;
+
+    private SubscriptionBaseTransition next;
+
+    public enum Order {
+        ASC_FROM_PAST,
+        DESC_FROM_FUTURE
+    }
+
+    public enum Kind {
+        SUBSCRIPTION,
+        BILLING,
+        ALL
+    }
+
+    public enum TimeLimit {
+        FUTURE_ONLY,
+        PAST_OR_PRESENT_ONLY,
+        ALL
+    }
+
+    public enum Visibility {
+        FROM_DISK_ONLY,
+        ALL
+    }
+
+    public SubscriptionBaseTransitionDataIterator(final Clock clock, final LinkedList<SubscriptionBaseTransition> transitions,
+                                                  final Order order, final Kind kind, final Visibility visibility, final TimeLimit timeLimit) {
+        this.it = (order == Order.DESC_FROM_FUTURE) ? transitions.descendingIterator() : transitions.iterator();
+        this.clock = clock;
+        this.kind = kind;
+        this.timeLimit = timeLimit;
+        this.visibility = visibility;
+        this.next = null;
+    }
+
+    @Override
+    public boolean hasNext() {
+        do {
+            final boolean hasNext = it.hasNext();
+            if (!hasNext) {
+                return false;
+            }
+            next = it.next();
+        } while (shouldSkip(next));
+        return true;
+    }
+
+    private boolean shouldSkip(final SubscriptionBaseTransition input) {
+        if (visibility == Visibility.FROM_DISK_ONLY && ! ((SubscriptionBaseTransitionData) input).isFromDisk()) {
+            return true;
+        }
+        if ((kind == Kind.SUBSCRIPTION && shouldSkipForSubscriptionEvents((SubscriptionBaseTransitionData) input)) ||
+            (kind == Kind.BILLING && shouldSkipForBillingEvents((SubscriptionBaseTransitionData) input))) {
+            return true;
+        }
+        if ((timeLimit == TimeLimit.FUTURE_ONLY && !input.getEffectiveTransitionTime().isAfter(clock.getUTCNow())) ||
+                ((timeLimit == TimeLimit.PAST_OR_PRESENT_ONLY && input.getEffectiveTransitionTime().isAfter(clock.getUTCNow())))) {
+            return true;
+        }
+        return false;
+    }
+
+    private boolean shouldSkipForSubscriptionEvents(final SubscriptionBaseTransitionData input) {
+        // SubscriptionBase system knows about all events except for MIGRATE_BILLING
+        return (input.getTransitionType() == SubscriptionBaseTransitionType.MIGRATE_BILLING);
+    }
+
+    private boolean shouldSkipForBillingEvents(final SubscriptionBaseTransitionData input) {
+        // Junction system knows about all events except for MIGRATE_ENTITLEMENT
+        return input.getTransitionType() == SubscriptionBaseTransitionType.MIGRATE_ENTITLEMENT;
+    }
+
+
+    @Override
+    public SubscriptionBaseTransition next() {
+        return next;
+    }
+
+    @Override
+    public void remove() {
+        throw new SubscriptionBaseError("Operation SubscriptionBaseTransitionDataIterator.remove not implemented");
+    }
+}
diff --git a/subscription/src/main/java/com/ning/billing/subscription/api/user/SubscriptionBuilder.java b/subscription/src/main/java/com/ning/billing/subscription/api/user/SubscriptionBuilder.java
index a3cf37a..94f23f7 100644
--- a/subscription/src/main/java/com/ning/billing/subscription/api/user/SubscriptionBuilder.java
+++ b/subscription/src/main/java/com/ning/billing/subscription/api/user/SubscriptionBuilder.java
@@ -22,7 +22,7 @@ import java.util.UUID;
 import org.joda.time.DateTime;
 
 import com.ning.billing.catalog.api.ProductCategory;
-import com.ning.billing.subscription.exceptions.SubscriptionError;
+import com.ning.billing.subscription.exceptions.SubscriptionBaseError;
 
 public class SubscriptionBuilder {
     private UUID id;
@@ -40,7 +40,7 @@ public class SubscriptionBuilder {
         this.activeVersion = SubscriptionEvents.INITIAL_VERSION;
     }
 
-    public SubscriptionBuilder(final SubscriptionData original) {
+    public SubscriptionBuilder(final DefaultSubscriptionBase original) {
         this.id = original.getId();
         this.bundleId = original.getBundleId();
         this.alignStartDate = original.getAlignStartDate();
@@ -146,11 +146,11 @@ public class SubscriptionBuilder {
             try {
                 final Object value = cur.get(this);
                 if (value == null) {
-                    throw new SubscriptionError(String.format("Field %s has not been set for SubscriptionBase",
+                    throw new SubscriptionBaseError(String.format("Field %s has not been set for SubscriptionBase",
                                                              cur.getName()));
                 }
             } catch (IllegalAccessException e) {
-                throw new SubscriptionError(String.format("Failed to access value for field %s for SubscriptionBase",
+                throw new SubscriptionBaseError(String.format("Failed to access value for field %s for SubscriptionBase",
                                                          cur.getName()), e);
             }
         }
diff --git a/subscription/src/main/java/com/ning/billing/subscription/engine/addon/AddonUtils.java b/subscription/src/main/java/com/ning/billing/subscription/engine/addon/AddonUtils.java
index 4efafe0..3687a05 100644
--- a/subscription/src/main/java/com/ning/billing/subscription/engine/addon/AddonUtils.java
+++ b/subscription/src/main/java/com/ning/billing/subscription/engine/addon/AddonUtils.java
@@ -23,8 +23,8 @@ import com.ning.billing.catalog.api.CatalogApiException;
 import com.ning.billing.catalog.api.CatalogService;
 import com.ning.billing.catalog.api.Plan;
 import com.ning.billing.catalog.api.Product;
-import com.ning.billing.subscription.api.user.SubscriptionData;
-import com.ning.billing.subscription.exceptions.SubscriptionError;
+import com.ning.billing.subscription.api.user.DefaultSubscriptionBase;
+import com.ning.billing.subscription.exceptions.SubscriptionBaseError;
 import com.ning.billing.subscription.api.user.SubscriptionState;
 import com.ning.billing.subscription.api.user.SubscriptionBaseApiException;
 
@@ -38,7 +38,7 @@ public class AddonUtils {
         this.catalogService = catalogService;
     }
 
-    public void checkAddonCreationRights(final SubscriptionData baseSubscription, final Plan targetAddOnPlan)
+    public void checkAddonCreationRights(final DefaultSubscriptionBase baseSubscription, final Plan targetAddOnPlan)
             throws SubscriptionBaseApiException, CatalogApiException {
 
         if (baseSubscription.getState() != SubscriptionState.ACTIVE) {
@@ -62,7 +62,7 @@ public class AddonUtils {
             final Product product = catalogService.getFullCatalog().findProduct(baseProductName, requestedDate);
             return isAddonAvailable(product, targetAddOnPlan);
         } catch (CatalogApiException e) {
-            throw new SubscriptionError(e);
+            throw new SubscriptionBaseError(e);
         }
     }
 
@@ -72,7 +72,7 @@ public class AddonUtils {
             final Product product = plan.getProduct();
             return isAddonAvailable(product, targetAddOnPlan);
         } catch (CatalogApiException e) {
-            throw new SubscriptionError(e);
+            throw new SubscriptionBaseError(e);
         }
     }
 
@@ -93,7 +93,7 @@ public class AddonUtils {
             final Product product = catalogService.getFullCatalog().findProduct(baseProductName, requestedDate);
             return isAddonIncluded(product, targetAddOnPlan);
         } catch (CatalogApiException e) {
-            throw new SubscriptionError(e);
+            throw new SubscriptionBaseError(e);
         }
 
     }
@@ -104,7 +104,7 @@ public class AddonUtils {
             final Product product = plan.getProduct();
             return isAddonIncluded(product, targetAddOnPlan);
         } catch (CatalogApiException e) {
-            throw new SubscriptionError(e);
+            throw new SubscriptionBaseError(e);
         }
     }
 
diff --git a/subscription/src/main/java/com/ning/billing/subscription/engine/core/DefaultSubscriptionBaseService.java b/subscription/src/main/java/com/ning/billing/subscription/engine/core/DefaultSubscriptionBaseService.java
new file mode 100644
index 0000000..257cff3
--- /dev/null
+++ b/subscription/src/main/java/com/ning/billing/subscription/engine/core/DefaultSubscriptionBaseService.java
@@ -0,0 +1,200 @@
+/*
+ * Copyright 2010-2013 Ning, Inc.
+ *
+ * Ning licenses this file to you under the Apache License, version 2.0
+ * (the "License"); you may not use this file except in compliance with the
+ * License.  You may obtain a copy of the License at:
+ *
+ *    http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
+ * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.  See the
+ * License for the specific language governing permissions and limitations
+ * under the License.
+ */
+
+package com.ning.billing.subscription.engine.core;
+
+import java.util.UUID;
+
+import org.joda.time.DateTime;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+import com.ning.billing.bus.api.PersistentBus;
+import com.ning.billing.bus.api.PersistentBus.EventBusException;
+import com.ning.billing.catalog.api.ProductCategory;
+import com.ning.billing.subscription.alignment.PlanAligner;
+import com.ning.billing.subscription.alignment.TimedPhase;
+import com.ning.billing.subscription.api.SubscriptionBaseApiService;
+import com.ning.billing.subscription.api.SubscriptionBaseService;
+import com.ning.billing.subscription.api.user.DefaultEffectiveSubscriptionEvent;
+import com.ning.billing.subscription.api.user.DefaultSubscriptionBase;
+import com.ning.billing.subscription.api.user.SubscriptionBaseTransitionData;
+import com.ning.billing.subscription.engine.addon.AddonUtils;
+import com.ning.billing.subscription.engine.dao.SubscriptionDao;
+import com.ning.billing.subscription.events.SubscriptionEvent;
+import com.ning.billing.subscription.events.SubscriptionEvent.EventType;
+import com.ning.billing.subscription.events.phase.PhaseEvent;
+import com.ning.billing.subscription.events.phase.PhaseEventData;
+import com.ning.billing.subscription.events.user.ApiEvent;
+import com.ning.billing.subscription.exceptions.SubscriptionBaseError;
+import com.ning.billing.lifecycle.LifecycleHandlerType;
+import com.ning.billing.lifecycle.LifecycleHandlerType.LifecycleLevel;
+import com.ning.billing.notificationq.api.NotificationEvent;
+import com.ning.billing.notificationq.api.NotificationQueue;
+import com.ning.billing.notificationq.api.NotificationQueueService;
+import com.ning.billing.notificationq.api.NotificationQueueService.NoSuchNotificationQueue;
+import com.ning.billing.notificationq.api.NotificationQueueService.NotificationQueueAlreadyExists;
+import com.ning.billing.notificationq.api.NotificationQueueService.NotificationQueueHandler;
+import com.ning.billing.util.callcontext.CallOrigin;
+import com.ning.billing.util.callcontext.InternalCallContext;
+import com.ning.billing.util.callcontext.InternalCallContextFactory;
+import com.ning.billing.util.callcontext.UserType;
+import com.ning.billing.clock.Clock;
+import com.ning.billing.util.events.EffectiveSubscriptionInternalEvent;
+
+import com.google.inject.Inject;
+
+public class DefaultSubscriptionBaseService implements EventListener, SubscriptionBaseService {
+
+    public static final String NOTIFICATION_QUEUE_NAME = "subscription-events";
+    public static final String SUBSCRIPTION_SERVICE_NAME = "subscription-service";
+
+    private static final Logger log = LoggerFactory.getLogger(DefaultSubscriptionBaseService.class);
+
+    private final Clock clock;
+    private final SubscriptionDao dao;
+    private final PlanAligner planAligner;
+    private final AddonUtils addonUtils;
+    private final PersistentBus eventBus;
+    private final NotificationQueueService notificationQueueService;
+    private final InternalCallContextFactory internalCallContextFactory;
+    private NotificationQueue subscriptionEventQueue;
+    private final SubscriptionBaseApiService apiService;
+
+    @Inject
+    public DefaultSubscriptionBaseService(final Clock clock, final SubscriptionDao dao, final PlanAligner planAligner,
+                                          final AddonUtils addonUtils, final PersistentBus eventBus,
+                                          final NotificationQueueService notificationQueueService,
+                                          final InternalCallContextFactory internalCallContextFactory,
+                                          final SubscriptionBaseApiService apiService) {
+        this.clock = clock;
+        this.dao = dao;
+        this.planAligner = planAligner;
+        this.addonUtils = addonUtils;
+        this.eventBus = eventBus;
+        this.notificationQueueService = notificationQueueService;
+        this.internalCallContextFactory = internalCallContextFactory;
+        this.apiService = apiService;
+    }
+
+    @Override
+    public String getName() {
+        return SUBSCRIPTION_SERVICE_NAME;
+    }
+
+    @LifecycleHandlerType(LifecycleLevel.INIT_SERVICE)
+    public void initialize() {
+        try {
+            final NotificationQueueHandler queueHandler = new NotificationQueueHandler() {
+                @Override
+                public void handleReadyNotification(final NotificationEvent inputKey, final DateTime eventDateTime, final UUID fromNotificationQueueUserToken, final Long accountRecordId, final Long tenantRecordId) {
+                    if (!(inputKey instanceof SubscriptionNotificationKey)) {
+                        log.error("SubscriptionBase service received an unexpected event type {}" + inputKey.getClass().getName());
+                        return;
+                    }
+
+                    final SubscriptionNotificationKey key = (SubscriptionNotificationKey) inputKey;
+                    final SubscriptionEvent event = dao.getEventById(key.getEventId(), internalCallContextFactory.createInternalTenantContext(tenantRecordId, accountRecordId));
+                    if (event == null) {
+                        // This can be expected if the event is soft deleted (is_active = 0)
+                        log.info("Failed to extract event for notification key {}", inputKey);
+                        return;
+                    }
+
+                    final InternalCallContext context = internalCallContextFactory.createInternalCallContext(tenantRecordId, accountRecordId, "SubscriptionEventQueue", CallOrigin.INTERNAL, UserType.SYSTEM, fromNotificationQueueUserToken);
+                    processEventReady(event, key.getSeqId(), context);
+                }
+            };
+
+            subscriptionEventQueue = notificationQueueService.createNotificationQueue(SUBSCRIPTION_SERVICE_NAME,
+                                                                                      NOTIFICATION_QUEUE_NAME,
+                                                                                      queueHandler);
+        } catch (NotificationQueueAlreadyExists e) {
+            throw new RuntimeException(e);
+        }
+    }
+
+    @LifecycleHandlerType(LifecycleLevel.START_SERVICE)
+    public void start() {
+        subscriptionEventQueue.startQueue();
+    }
+
+    @LifecycleHandlerType(LifecycleLevel.STOP_SERVICE)
+    public void stop() throws NoSuchNotificationQueue {
+        if (subscriptionEventQueue != null) {
+            subscriptionEventQueue.stopQueue();
+            notificationQueueService.deleteNotificationQueue(subscriptionEventQueue.getServiceName(), subscriptionEventQueue.getQueueName());
+        }
+    }
+
+    @Override
+    public void processEventReady(final SubscriptionEvent event, final int seqId, final InternalCallContext context) {
+        if (!event.isActive()) {
+            return;
+        }
+
+        final DefaultSubscriptionBase subscription = (DefaultSubscriptionBase) dao.getSubscriptionFromId(event.getSubscriptionId(), context);
+        if (subscription == null) {
+            log.warn("Failed to retrieve subscription for id %s", event.getSubscriptionId());
+            return;
+        }
+        if (subscription.getActiveVersion() > event.getActiveVersion()) {
+            // Skip repaired events
+            return;
+        }
+
+        //
+        // Do any internal processing on that event before we send the event to the bus
+        //
+        int theRealSeqId = seqId;
+        if (event.getType() == EventType.PHASE) {
+            onPhaseEvent(subscription, context);
+        } else if (event.getType() == EventType.API_USER && subscription.getCategory() == ProductCategory.BASE) {
+            theRealSeqId = onBasePlanEvent(subscription, (ApiEvent) event, context);
+        }
+
+        try {
+            final SubscriptionBaseTransitionData transition = (subscription.getTransitionFromEvent(event, theRealSeqId));
+            final EffectiveSubscriptionInternalEvent busEvent = new DefaultEffectiveSubscriptionEvent(transition, subscription.getAlignStartDate(),
+                                                                                                      context.getUserToken(),
+                                                                                                      context.getAccountRecordId(), context.getTenantRecordId());
+            eventBus.post(busEvent);
+        } catch (EventBusException e) {
+            log.warn("Failed to post subscription event " + event, e);
+        }
+    }
+
+    private void onPhaseEvent(final DefaultSubscriptionBase subscription, final InternalCallContext context) {
+        try {
+            final DateTime now = clock.getUTCNow();
+            final TimedPhase nextTimedPhase = planAligner.getNextTimedPhase(subscription, now, now);
+            final PhaseEvent nextPhaseEvent = (nextTimedPhase != null) ?
+                                              PhaseEventData.createNextPhaseEvent(nextTimedPhase.getPhase().getName(), subscription, now, nextTimedPhase.getStartPhase()) :
+                                              null;
+            if (nextPhaseEvent != null) {
+                dao.createNextPhaseEvent(subscription, nextPhaseEvent, context);
+            }
+        } catch (SubscriptionBaseError e) {
+            log.error(String.format("Failed to insert next phase for subscription %s", subscription.getId()), e);
+        }
+    }
+
+    private int onBasePlanEvent(final DefaultSubscriptionBase baseSubscription, final ApiEvent event, final InternalCallContext context) {
+        return apiService.cancelAddOnsIfRequired(baseSubscription, event.getEffectiveDate(), context);
+    }
+
+
+}
diff --git a/subscription/src/main/java/com/ning/billing/subscription/engine/core/DefaultSubscriptionService.java b/subscription/src/main/java/com/ning/billing/subscription/engine/core/DefaultSubscriptionService.java
index 7b0810d..1ed7580 100644
--- a/subscription/src/main/java/com/ning/billing/subscription/engine/core/DefaultSubscriptionService.java
+++ b/subscription/src/main/java/com/ning/billing/subscription/engine/core/DefaultSubscriptionService.java
@@ -28,7 +28,7 @@ import com.ning.billing.catalog.api.ProductCategory;
 import com.ning.billing.subscription.alignment.PlanAligner;
 import com.ning.billing.subscription.alignment.TimedPhase;
 import com.ning.billing.subscription.api.SubscriptionApiService;
-import com.ning.billing.subscription.api.SubscriptionService;
+import com.ning.billing.subscription.api.SubscriptionBaseService;
 import com.ning.billing.subscription.api.user.DefaultEffectiveSubscriptionEvent;
 import com.ning.billing.subscription.api.user.SubscriptionData;
 import com.ning.billing.subscription.api.user.SubscriptionBaseTransitionData;
@@ -57,7 +57,7 @@ import com.ning.billing.util.events.EffectiveSubscriptionInternalEvent;
 
 import com.google.inject.Inject;
 
-public class DefaultSubscriptionService implements EventListener, SubscriptionService {
+public class DefaultSubscriptionService implements EventListener, SubscriptionBaseService {
 
     public static final String NOTIFICATION_QUEUE_NAME = "subscription-events";
     public static final String SUBSCRIPTION_SERVICE_NAME = "subscription-service";
diff --git a/subscription/src/main/java/com/ning/billing/subscription/engine/dao/DefaultSubscriptionDao.java b/subscription/src/main/java/com/ning/billing/subscription/engine/dao/DefaultSubscriptionDao.java
index d5d4318..3ec8cc0 100644
--- a/subscription/src/main/java/com/ning/billing/subscription/engine/dao/DefaultSubscriptionDao.java
+++ b/subscription/src/main/java/com/ning/billing/subscription/engine/dao/DefaultSubscriptionDao.java
@@ -51,13 +51,13 @@ import com.ning.billing.subscription.api.timeline.SubscriptionDataRepair;
 import com.ning.billing.subscription.api.transfer.TransferCancelData;
 import com.ning.billing.subscription.api.user.DefaultEffectiveSubscriptionEvent;
 import com.ning.billing.subscription.api.user.DefaultRequestedSubscriptionEvent;
+import com.ning.billing.subscription.api.user.DefaultSubscriptionBase;
+import com.ning.billing.subscription.api.user.DefaultSubscriptionBaseBundle;
 import com.ning.billing.subscription.api.user.SubscriptionBaseBundle;
 import com.ning.billing.subscription.api.user.SubscriptionBuilder;
-import com.ning.billing.subscription.api.user.SubscriptionBundleData;
-import com.ning.billing.subscription.api.user.SubscriptionData;
 import com.ning.billing.subscription.api.user.SubscriptionBaseTransitionData;
 import com.ning.billing.subscription.engine.addon.AddonUtils;
-import com.ning.billing.subscription.engine.core.DefaultSubscriptionService;
+import com.ning.billing.subscription.engine.core.DefaultSubscriptionBaseService;
 import com.ning.billing.subscription.engine.core.SubscriptionNotificationKey;
 import com.ning.billing.subscription.engine.dao.model.SubscriptionEventModelDao;
 import com.ning.billing.subscription.engine.dao.model.SubscriptionBundleModelDao;
@@ -71,7 +71,7 @@ import com.ning.billing.subscription.events.user.ApiEventCancel;
 import com.ning.billing.subscription.events.user.ApiEventChange;
 import com.ning.billing.subscription.events.user.ApiEventMigrateBilling;
 import com.ning.billing.subscription.events.user.ApiEventType;
-import com.ning.billing.subscription.exceptions.SubscriptionError;
+import com.ning.billing.subscription.exceptions.SubscriptionBaseError;
 import com.ning.billing.notificationq.api.NotificationEvent;
 import com.ning.billing.notificationq.api.NotificationQueue;
 import com.ning.billing.notificationq.api.NotificationQueueService;
@@ -173,7 +173,7 @@ public class DefaultSubscriptionDao implements SubscriptionDao {
     }
 
     @Override
-    public SubscriptionBaseBundle createSubscriptionBundle(final SubscriptionBundleData bundle, final InternalCallContext context) {
+    public SubscriptionBaseBundle createSubscriptionBundle(final DefaultSubscriptionBaseBundle bundle, final InternalCallContext context) {
         return transactionalSqlDao.execute(new EntitySqlDaoTransactionWrapper<SubscriptionBaseBundle>() {
             @Override
             public SubscriptionBaseBundle inTransaction(final EntitySqlDaoWrapperFactory<EntitySqlDao> entitySqlDaoWrapperFactory) throws EntityPersistenceException {
@@ -268,7 +268,7 @@ public class DefaultSubscriptionDao implements SubscriptionDao {
     }
 
     @Override
-    public void updateChargedThroughDate(final SubscriptionData subscription, final InternalCallContext context) {
+    public void updateChargedThroughDate(final DefaultSubscriptionBase subscription, final InternalCallContext context) {
         final Date ctd = (subscription.getChargedThroughDate() != null) ? subscription.getChargedThroughDate().toDate() : null;
 
         transactionalSqlDao.execute(new EntitySqlDaoTransactionWrapper<Void>() {
@@ -286,7 +286,7 @@ public class DefaultSubscriptionDao implements SubscriptionDao {
     }
 
     @Override
-    public void createNextPhaseEvent(final SubscriptionData subscription, final SubscriptionEvent nextPhase, final InternalCallContext context) {
+    public void createNextPhaseEvent(final DefaultSubscriptionBase subscription, final SubscriptionEvent nextPhase, final InternalCallContext context) {
         transactionalSqlDao.execute(new EntitySqlDaoTransactionWrapper<Void>() {
             @Override
             public Void inTransaction(final EntitySqlDaoWrapperFactory<EntitySqlDao> entitySqlDaoWrapperFactory) throws Exception {
@@ -389,7 +389,7 @@ public class DefaultSubscriptionDao implements SubscriptionDao {
     }
 
     @Override
-    public void createSubscription(final SubscriptionData subscription, final List<SubscriptionEvent> initialEvents, final InternalCallContext context) {
+    public void createSubscription(final DefaultSubscriptionBase subscription, final List<SubscriptionEvent> initialEvents, final InternalCallContext context) {
         transactionalSqlDao.execute(new EntitySqlDaoTransactionWrapper<Void>() {
             @Override
             public Void inTransaction(final EntitySqlDaoWrapperFactory<EntitySqlDao> entitySqlDaoWrapperFactory) throws Exception {
@@ -415,7 +415,7 @@ public class DefaultSubscriptionDao implements SubscriptionDao {
 
 
     @Override
-    public void recreateSubscription(final SubscriptionData subscription, final List<SubscriptionEvent> recreateEvents, final InternalCallContext context) {
+    public void recreateSubscription(final DefaultSubscriptionBase subscription, final List<SubscriptionEvent> recreateEvents, final InternalCallContext context) {
         transactionalSqlDao.execute(new EntitySqlDaoTransactionWrapper<Void>() {
             @Override
             public Void inTransaction(final EntitySqlDaoWrapperFactory<EntitySqlDao> entitySqlDaoWrapperFactory) throws Exception {
@@ -437,13 +437,13 @@ public class DefaultSubscriptionDao implements SubscriptionDao {
     }
 
     @Override
-    public void cancelSubscriptions(final List<SubscriptionData> subscriptions, final List<SubscriptionEvent> cancelEvents, final InternalCallContext context) {
+    public void cancelSubscriptions(final List<DefaultSubscriptionBase> subscriptions, final List<SubscriptionEvent> cancelEvents, final InternalCallContext context) {
 
         transactionalSqlDao.execute(new EntitySqlDaoTransactionWrapper<Void>() {
             @Override
             public Void inTransaction(final EntitySqlDaoWrapperFactory<EntitySqlDao> entitySqlDaoWrapperFactory) throws Exception {
                 for (int i = 0; i < subscriptions.size(); i++) {
-                    final SubscriptionData subscription = subscriptions.get(i);
+                    final DefaultSubscriptionBase subscription = subscriptions.get(i);
                     final SubscriptionEvent cancelEvent = cancelEvents.get(i);
                     cancelSubscriptionFromTransaction(subscription, cancelEvent, entitySqlDaoWrapperFactory, context, i);
                 }
@@ -454,7 +454,7 @@ public class DefaultSubscriptionDao implements SubscriptionDao {
 
 
     @Override
-    public void cancelSubscription(final SubscriptionData subscription, final SubscriptionEvent cancelEvent, final InternalCallContext context, final int seqId) {
+    public void cancelSubscription(final DefaultSubscriptionBase subscription, final SubscriptionEvent cancelEvent, final InternalCallContext context, final int seqId) {
         transactionalSqlDao.execute(new EntitySqlDaoTransactionWrapper<Void>() {
             @Override
             public Void inTransaction(final EntitySqlDaoWrapperFactory<EntitySqlDao> entitySqlDaoWrapperFactory) throws Exception {
@@ -465,7 +465,7 @@ public class DefaultSubscriptionDao implements SubscriptionDao {
     }
 
     @Override
-    public void uncancelSubscription(final SubscriptionData subscription, final List<SubscriptionEvent> uncancelEvents, final InternalCallContext context) {
+    public void uncancelSubscription(final DefaultSubscriptionBase subscription, final List<SubscriptionEvent> uncancelEvents, final InternalCallContext context) {
         transactionalSqlDao.execute(new EntitySqlDaoTransactionWrapper<Void>() {
             @Override
             public Void inTransaction(final EntitySqlDaoWrapperFactory<EntitySqlDao> entitySqlDaoWrapperFactory) throws Exception {
@@ -479,7 +479,7 @@ public class DefaultSubscriptionDao implements SubscriptionDao {
                 for (final SubscriptionEventModelDao cur : eventModels) {
                     if (cur.getUserType() == ApiEventType.CANCEL) {
                         if (cancelledEvent != null) {
-                            throw new SubscriptionError(String.format("Found multiple cancel active events for subscriptions %s", subscriptionId.toString()));
+                            throw new SubscriptionBaseError(String.format("Found multiple cancel active events for subscriptions %s", subscriptionId.toString()));
                         }
                         cancelledEvent = cur;
                     }
@@ -506,7 +506,7 @@ public class DefaultSubscriptionDao implements SubscriptionDao {
     }
 
     @Override
-    public void changePlan(final SubscriptionData subscription, final List<SubscriptionEvent> changeEvents, final InternalCallContext context) {
+    public void changePlan(final DefaultSubscriptionBase subscription, final List<SubscriptionEvent> changeEvents, final InternalCallContext context) {
         transactionalSqlDao.execute(new EntitySqlDaoTransactionWrapper<Void>() {
             @Override
             public Void inTransaction(final EntitySqlDaoWrapperFactory<EntitySqlDao> entitySqlDaoWrapperFactory) throws Exception {
@@ -577,7 +577,7 @@ public class DefaultSubscriptionDao implements SubscriptionDao {
                     break;
 
                 default:
-                    throw new SubscriptionError("Unknown event type " + cur.getType());
+                    throw new SubscriptionBaseError("Unknown event type " + cur.getType());
             }
 
             if (cur.getEffectiveDate().compareTo(migrateBillingEvent.getEffectiveDate()) > 0) {
@@ -627,7 +627,7 @@ public class DefaultSubscriptionDao implements SubscriptionDao {
         return changeEvents;
     }
 
-    private void cancelSubscriptionFromTransaction(final SubscriptionData subscription, final SubscriptionEvent cancelEvent, final EntitySqlDaoWrapperFactory<EntitySqlDao> entitySqlDaoWrapperFactory, final InternalCallContext context, final int seqId)
+    private void cancelSubscriptionFromTransaction(final DefaultSubscriptionBase subscription, final SubscriptionEvent cancelEvent, final EntitySqlDaoWrapperFactory<EntitySqlDao> entitySqlDaoWrapperFactory, final InternalCallContext context, final int seqId)
             throws EntityPersistenceException {
         final UUID subscriptionId = subscription.getId();
         cancelFutureEventsFromTransaction(subscriptionId, entitySqlDaoWrapperFactory, context);
@@ -668,7 +668,7 @@ public class DefaultSubscriptionDao implements SubscriptionDao {
             if (cur.getEventType() == type &&
                 (apiType == null || apiType == cur.getUserType())) {
                 if (futureEvent != null) {
-                    throw new SubscriptionError(String.format("Found multiple future events for type %s for subscriptions %s",
+                    throw new SubscriptionBaseError(String.format("Found multiple future events for type %s for subscriptions %s",
                                                              type, subscriptionId.toString()));
                 }
                 futureEvent = cur;
@@ -711,7 +711,7 @@ public class DefaultSubscriptionDao implements SubscriptionDao {
             }
         }
 
-        throw new SubscriptionError("Unexpected code path in buildSubscription");
+        throw new SubscriptionBaseError("Unexpected code path in buildSubscription");
     }
 
     private List<SubscriptionBase> buildBundleSubscriptions(final UUID bundleId, final List<SubscriptionBase> input, final InternalTenantContext context) {
@@ -728,7 +728,7 @@ public class DefaultSubscriptionDao implements SubscriptionDao {
                 } else if (o2.getCategory() == ProductCategory.BASE) {
                     return 1;
                 } else {
-                    return ((SubscriptionData) o1).getAlignStartDate().compareTo(((SubscriptionData) o2).getAlignStartDate());
+                    return ((DefaultSubscriptionBase) o1).getAlignStartDate().compareTo(((DefaultSubscriptionBase) o2).getAlignStartDate());
                 }
             }
         });
@@ -765,7 +765,7 @@ public class DefaultSubscriptionDao implements SubscriptionDao {
                         final DateTime now = clock.getUTCNow();
                         final SubscriptionEvent addOnCancelEvent = new ApiEventCancel(new ApiEventBuilder()
                                                                                              .setSubscriptionId(reloaded.getId())
-                                                                                             .setActiveVersion(((SubscriptionData) reloaded).getActiveVersion())
+                                                                                             .setActiveVersion(((DefaultSubscriptionBase) reloaded).getActiveVersion())
                                                                                              .setProcessedDate(now)
                                                                                              .setEffectiveDate(futureBaseEvent.getEffectiveDate())
                                                                                              .setRequestedDate(now)
@@ -861,8 +861,8 @@ public class DefaultSubscriptionDao implements SubscriptionDao {
         });
     }
 
-    private SubscriptionData createSubscriptionForInternalUse(final SubscriptionBase shellSubscription, final List<SubscriptionEvent> events) {
-        final SubscriptionData result = new SubscriptionData(new SubscriptionBuilder(((SubscriptionData) shellSubscription)), null, clock);
+    private DefaultSubscriptionBase createSubscriptionForInternalUse(final SubscriptionBase shellSubscription, final List<SubscriptionEvent> events) {
+        final DefaultSubscriptionBase result = new DefaultSubscriptionBase(new SubscriptionBuilder(((DefaultSubscriptionBase) shellSubscription)), null, clock);
         if (events.size() > 0) {
             result.rebuildTransitions(events, catalogService.getFullCatalog());
         }
@@ -883,7 +883,7 @@ public class DefaultSubscriptionDao implements SubscriptionDao {
     //
     // Either records a notfication or sends a bus event is operation is immediate
     //
-    private void recordBusOrFutureNotificationFromTransaction(final SubscriptionData subscription, final SubscriptionEvent event, final EntitySqlDaoWrapperFactory<EntitySqlDao> entitySqlDaoWrapperFactory, final boolean busEvent,
+    private void recordBusOrFutureNotificationFromTransaction(final DefaultSubscriptionBase subscription, final SubscriptionEvent event, final EntitySqlDaoWrapperFactory<EntitySqlDao> entitySqlDaoWrapperFactory, final boolean busEvent,
                                                               final int seqId, final InternalCallContext context) {
         if (busEvent) {
             notifyBusOfEffectiveImmediateChange(entitySqlDaoWrapperFactory, subscription, event, seqId, context);
@@ -900,10 +900,10 @@ public class DefaultSubscriptionDao implements SubscriptionDao {
     // - CREATE,
     // - IMM CANCEL or CHANGE
     //
-    private void notifyBusOfEffectiveImmediateChange(final EntitySqlDaoWrapperFactory<EntitySqlDao> entitySqlDaoWrapperFactory, final SubscriptionData subscription,
+    private void notifyBusOfEffectiveImmediateChange(final EntitySqlDaoWrapperFactory<EntitySqlDao> entitySqlDaoWrapperFactory, final DefaultSubscriptionBase subscription,
                                                      final SubscriptionEvent immediateEvent, final int seqId, final InternalCallContext context) {
         try {
-            final SubscriptionData upToDateSubscription = createSubscriptionWithNewEvent(subscription, immediateEvent);
+            final DefaultSubscriptionBase upToDateSubscription = createSubscriptionWithNewEvent(subscription, immediateEvent);
 
             final SubscriptionBaseTransitionData transition = upToDateSubscription.getTransitionFromEvent(immediateEvent, seqId);
             final EffectiveSubscriptionInternalEvent busEvent = new DefaultEffectiveSubscriptionEvent(transition, upToDateSubscription.getAlignStartDate(),
@@ -917,7 +917,7 @@ public class DefaultSubscriptionDao implements SubscriptionDao {
         }
     }
 
-    private void notifyBusOfRequestedChange(final EntitySqlDaoWrapperFactory<EntitySqlDao> entitySqlDaoWrapperFactory, final SubscriptionData subscription,
+    private void notifyBusOfRequestedChange(final EntitySqlDaoWrapperFactory<EntitySqlDao> entitySqlDaoWrapperFactory, final DefaultSubscriptionBase subscription,
                                             final SubscriptionEvent nextEvent, final InternalCallContext context) {
         try {
             eventBus.postFromTransaction(new DefaultRequestedSubscriptionEvent(subscription, nextEvent, context.getAccountRecordId(), context.getTenantRecordId(), context.getUserToken()), entitySqlDaoWrapperFactory.getSqlDao());
@@ -929,8 +929,8 @@ public class DefaultSubscriptionDao implements SubscriptionDao {
     private void recordFutureNotificationFromTransaction(final EntitySqlDaoWrapperFactory<EntitySqlDao> entitySqlDaoWrapperFactory, final DateTime effectiveDate,
                                                          final NotificationEvent notificationKey, final InternalCallContext context) {
         try {
-            final NotificationQueue subscriptionEventQueue = notificationQueueService.getNotificationQueue(DefaultSubscriptionService.SUBSCRIPTION_SERVICE_NAME,
-                                                                                                           DefaultSubscriptionService.NOTIFICATION_QUEUE_NAME);
+            final NotificationQueue subscriptionEventQueue = notificationQueueService.getNotificationQueue(DefaultSubscriptionBaseService.SUBSCRIPTION_SERVICE_NAME,
+                                                                                                           DefaultSubscriptionBaseService.NOTIFICATION_QUEUE_NAME);
             subscriptionEventQueue.recordFutureNotificationFromTransaction(entitySqlDaoWrapperFactory.getSqlDao(), effectiveDate, notificationKey, context.getUserToken(), context.getAccountRecordId(), context.getTenantRecordId());
         } catch (NoSuchNotificationQueue e) {
             throw new RuntimeException(e);
@@ -945,7 +945,7 @@ public class DefaultSubscriptionDao implements SubscriptionDao {
         final SubscriptionSqlDao transSubDao = entitySqlDaoWrapperFactory.become(SubscriptionSqlDao.class);
         final BundleSqlDao transBundleDao = entitySqlDaoWrapperFactory.become(BundleSqlDao.class);
 
-        final SubscriptionBundleData bundleData = bundleTransferData.getData();
+        final DefaultSubscriptionBaseBundle bundleData = bundleTransferData.getData();
 
         final SubscriptionBundleModelDao existingBundleModel = transBundleDao.getBundleFromAccountAndKey(bundleData.getAccountId().toString(), bundleData.getExternalKey(), context);
         if (existingBundleModel != null) {
@@ -954,7 +954,7 @@ public class DefaultSubscriptionDao implements SubscriptionDao {
         }
 
         for (final SubscriptionMigrationData curSubscription : bundleTransferData.getSubscriptions()) {
-            final SubscriptionData subData = curSubscription.getData();
+            final DefaultSubscriptionBase subData = curSubscription.getData();
             for (final SubscriptionEvent curEvent : curSubscription.getInitialEvents()) {
                 transactional.create(new SubscriptionEventModelDao(curEvent), context);
                 recordFutureNotificationFromTransaction(entitySqlDaoWrapperFactory,
@@ -975,9 +975,9 @@ public class DefaultSubscriptionDao implements SubscriptionDao {
     //
     // Creates a copy of the existing subscriptions whose 'transitions' will reflect the new event
     //
-    private SubscriptionData createSubscriptionWithNewEvent(final SubscriptionData subscription, SubscriptionEvent newEvent) {
+    private DefaultSubscriptionBase createSubscriptionWithNewEvent(final DefaultSubscriptionBase subscription, SubscriptionEvent newEvent) {
 
-        final SubscriptionData subscriptionWithNewEvent = new SubscriptionData(subscription, null, clock);
+        final DefaultSubscriptionBase subscriptionWithNewEvent = new DefaultSubscriptionBase(subscription, null, clock);
         final List<SubscriptionEvent> allEvents = new LinkedList<SubscriptionEvent>();
         if (subscriptionWithNewEvent.getEvents() != null) {
             allEvents.addAll(subscriptionWithNewEvent.getEvents());
diff --git a/subscription/src/main/java/com/ning/billing/subscription/engine/dao/model/SubscriptionBundleModelDao.java b/subscription/src/main/java/com/ning/billing/subscription/engine/dao/model/SubscriptionBundleModelDao.java
index 8bb51d7..e480be9 100644
--- a/subscription/src/main/java/com/ning/billing/subscription/engine/dao/model/SubscriptionBundleModelDao.java
+++ b/subscription/src/main/java/com/ning/billing/subscription/engine/dao/model/SubscriptionBundleModelDao.java
@@ -20,7 +20,7 @@ import java.util.UUID;
 
 import org.joda.time.DateTime;
 
-import com.ning.billing.subscription.api.user.SubscriptionBundleData;
+import com.ning.billing.subscription.api.user.DefaultSubscriptionBaseBundle;
 import com.ning.billing.subscription.api.user.SubscriptionBaseBundle;
 import com.ning.billing.util.dao.TableName;
 import com.ning.billing.util.entity.EntityBase;
@@ -42,7 +42,7 @@ public class SubscriptionBundleModelDao extends EntityBase implements EntityMode
         this.lastSysUpdateDate = lastSysUpdateDate;
     }
 
-    public SubscriptionBundleModelDao(final SubscriptionBundleData input) {
+    public SubscriptionBundleModelDao(final DefaultSubscriptionBaseBundle input) {
         this(input.getId(), input.getExternalKey(), input.getAccountId(), input.getLastSysUpdateDate(), input.getCreatedDate(), input.getUpdatedDate());
     }
 
@@ -62,7 +62,7 @@ public class SubscriptionBundleModelDao extends EntityBase implements EntityMode
         if (src == null) {
             return null;
         }
-        return new SubscriptionBundleData(src.getId(), src.getExternalKey(), src.getAccountId(), src.getLastSysUpdateDate());
+        return new DefaultSubscriptionBaseBundle(src.getId(), src.getExternalKey(), src.getAccountId(), src.getLastSysUpdateDate());
     }
 
     @Override
diff --git a/subscription/src/main/java/com/ning/billing/subscription/engine/dao/model/SubscriptionEventModelDao.java b/subscription/src/main/java/com/ning/billing/subscription/engine/dao/model/SubscriptionEventModelDao.java
index 3f5c454..9ddfce6 100644
--- a/subscription/src/main/java/com/ning/billing/subscription/engine/dao/model/SubscriptionEventModelDao.java
+++ b/subscription/src/main/java/com/ning/billing/subscription/engine/dao/model/SubscriptionEventModelDao.java
@@ -37,7 +37,7 @@ import com.ning.billing.subscription.events.user.ApiEventReCreate;
 import com.ning.billing.subscription.events.user.ApiEventTransfer;
 import com.ning.billing.subscription.events.user.ApiEventType;
 import com.ning.billing.subscription.events.user.ApiEventUncancel;
-import com.ning.billing.subscription.exceptions.SubscriptionError;
+import com.ning.billing.subscription.exceptions.SubscriptionBaseError;
 import com.ning.billing.util.dao.TableName;
 import com.ning.billing.util.entity.EntityBase;
 import com.ning.billing.util.entity.dao.EntityModelDao;
@@ -193,7 +193,7 @@ public class SubscriptionEventModelDao extends EntityBase implements EntityModel
                 result = new ApiEventUncancel(builder);
             }
         } else {
-            throw new SubscriptionError(String.format("Can't figure out event %s", src.getEventType()));
+            throw new SubscriptionBaseError(String.format("Can't figure out event %s", src.getEventType()));
         }
         return result;
     }
diff --git a/subscription/src/main/java/com/ning/billing/subscription/engine/dao/model/SubscriptionModelDao.java b/subscription/src/main/java/com/ning/billing/subscription/engine/dao/model/SubscriptionModelDao.java
index d9ae780..861dcf1 100644
--- a/subscription/src/main/java/com/ning/billing/subscription/engine/dao/model/SubscriptionModelDao.java
+++ b/subscription/src/main/java/com/ning/billing/subscription/engine/dao/model/SubscriptionModelDao.java
@@ -22,7 +22,7 @@ import org.joda.time.DateTime;
 
 import com.ning.billing.catalog.api.ProductCategory;
 import com.ning.billing.subscription.api.user.SubscriptionBuilder;
-import com.ning.billing.subscription.api.user.SubscriptionData;
+import com.ning.billing.subscription.api.user.DefaultSubscriptionBase;
 import com.ning.billing.subscription.api.SubscriptionBase;
 import com.ning.billing.util.dao.TableName;
 import com.ning.billing.util.entity.EntityBase;
@@ -52,7 +52,7 @@ public class SubscriptionModelDao extends EntityBase implements EntityModelDao<S
         this.paidThroughDate = paidThroughDate;
     }
 
-    public SubscriptionModelDao(final SubscriptionData src) {
+    public SubscriptionModelDao(final DefaultSubscriptionBase src) {
         this(src.getId(), src.getBundleId(), src.getCategory(), src.getAlignStartDate(), src.getBundleStartDate(), src.getActiveVersion(),
              src.getChargedThroughDate(), src.getPaidThroughDate(), src.getCreatedDate(), src.getUpdatedDate());
     }
@@ -89,7 +89,7 @@ public class SubscriptionModelDao extends EntityBase implements EntityModelDao<S
         if (src == null) {
             return null;
         }
-        return new SubscriptionData(new SubscriptionBuilder()
+        return new DefaultSubscriptionBase(new SubscriptionBuilder()
                                             .setId(src.getId())
                                             .setBundleId(src.getBundleId())
                                             .setCategory(src.getCategory())
diff --git a/subscription/src/main/java/com/ning/billing/subscription/engine/dao/RepairSubscriptionDao.java b/subscription/src/main/java/com/ning/billing/subscription/engine/dao/RepairSubscriptionDao.java
index 35af1f5..60234cb 100644
--- a/subscription/src/main/java/com/ning/billing/subscription/engine/dao/RepairSubscriptionDao.java
+++ b/subscription/src/main/java/com/ning/billing/subscription/engine/dao/RepairSubscriptionDao.java
@@ -32,10 +32,10 @@ import com.ning.billing.subscription.api.migration.AccountMigrationData.BundleMi
 import com.ning.billing.subscription.api.timeline.RepairSubscriptionLifecycleDao;
 import com.ning.billing.subscription.api.timeline.SubscriptionDataRepair;
 import com.ning.billing.subscription.api.transfer.TransferCancelData;
-import com.ning.billing.subscription.api.user.SubscriptionBundleData;
-import com.ning.billing.subscription.api.user.SubscriptionData;
+import com.ning.billing.subscription.api.user.DefaultSubscriptionBase;
+import com.ning.billing.subscription.api.user.DefaultSubscriptionBaseBundle;
 import com.ning.billing.subscription.events.SubscriptionEvent;
-import com.ning.billing.subscription.exceptions.SubscriptionError;
+import com.ning.billing.subscription.exceptions.SubscriptionBaseError;
 import com.ning.billing.subscription.api.SubscriptionBase;
 import com.ning.billing.subscription.api.user.SubscriptionBaseBundle;
 import com.ning.billing.util.callcontext.InternalCallContext;
@@ -157,17 +157,17 @@ public class RepairSubscriptionDao implements SubscriptionDao, RepairSubscriptio
     }
 
     @Override
-    public void createSubscription(final SubscriptionData subscription, final List<SubscriptionEvent> createEvents, final InternalCallContext context) {
+    public void createSubscription(final DefaultSubscriptionBase subscription, final List<SubscriptionEvent> createEvents, final InternalCallContext context) {
         addEvents(subscription.getId(), createEvents);
     }
 
     @Override
-    public void recreateSubscription(final SubscriptionData subscription, final List<SubscriptionEvent> recreateEvents, final InternalCallContext context) {
+    public void recreateSubscription(final DefaultSubscriptionBase subscription, final List<SubscriptionEvent> recreateEvents, final InternalCallContext context) {
         addEvents(subscription.getId(), recreateEvents);
     }
 
     @Override
-    public void cancelSubscription(final SubscriptionData subscription, final SubscriptionEvent cancelEvent, final InternalCallContext context, final int cancelSeq) {
+    public void cancelSubscription(final DefaultSubscriptionBase subscription, final SubscriptionEvent cancelEvent, final InternalCallContext context, final int cancelSeq) {
         final UUID subscriptionId = subscription.getId();
         final long activeVersion = cancelEvent.getActiveVersion();
         addEvents(subscriptionId, Collections.singletonList(cancelEvent));
@@ -183,11 +183,11 @@ public class RepairSubscriptionDao implements SubscriptionDao, RepairSubscriptio
     }
 
     @Override
-    public void cancelSubscriptions(final List<SubscriptionData> subscriptions, final List<SubscriptionEvent> cancelEvents, final InternalCallContext context) {
+    public void cancelSubscriptions(final List<DefaultSubscriptionBase> subscriptions, final List<SubscriptionEvent> cancelEvents, final InternalCallContext context) {
     }
 
     @Override
-    public void changePlan(final SubscriptionData subscription, final List<SubscriptionEvent> changeEvents, final InternalCallContext context) {
+    public void changePlan(final DefaultSubscriptionBase subscription, final List<SubscriptionEvent> changeEvents, final InternalCallContext context) {
         addEvents(subscription.getId(), changeEvents);
     }
 
@@ -198,7 +198,7 @@ public class RepairSubscriptionDao implements SubscriptionDao, RepairSubscriptio
             final SubscriptionRepairEvent value = new SubscriptionRepairEvent(initialEvents);
             map.put(subscriptionId, value);
         } else {
-            throw new SubscriptionError(String.format("Unexpected SubscriptionRepairEvent %s for thread %s", subscriptionId, Thread.currentThread().getName()));
+            throw new SubscriptionBaseError(String.format("Unexpected SubscriptionRepairEvent %s for thread %s", subscriptionId, Thread.currentThread().getName()));
         }
     }
 
@@ -214,100 +214,100 @@ public class RepairSubscriptionDao implements SubscriptionDao, RepairSubscriptio
     }
 
     @Override
-    public void uncancelSubscription(final SubscriptionData subscription, final List<SubscriptionEvent> uncancelEvents, final InternalCallContext context) {
-        throw new SubscriptionError(NOT_IMPLEMENTED);
+    public void uncancelSubscription(final DefaultSubscriptionBase subscription, final List<SubscriptionEvent> uncancelEvents, final InternalCallContext context) {
+        throw new SubscriptionBaseError(NOT_IMPLEMENTED);
     }
 
     @Override
     public List<SubscriptionBaseBundle> getSubscriptionBundleForAccount(final UUID accountId, final InternalTenantContext context) {
-        throw new SubscriptionError(NOT_IMPLEMENTED);
+        throw new SubscriptionBaseError(NOT_IMPLEMENTED);
     }
 
     @Override
     public SubscriptionBaseBundle getSubscriptionBundleFromAccountAndKey(final UUID accountId, final String bundleKey, final InternalTenantContext context) {
-        throw new SubscriptionError(NOT_IMPLEMENTED);
+        throw new SubscriptionBaseError(NOT_IMPLEMENTED);
     }
 
     @Override
     public SubscriptionBaseBundle getSubscriptionBundleFromId(final UUID bundleId, final InternalTenantContext context) {
-        throw new SubscriptionError(NOT_IMPLEMENTED);
+        throw new SubscriptionBaseError(NOT_IMPLEMENTED);
     }
 
     @Override
-    public SubscriptionBaseBundle createSubscriptionBundle(final SubscriptionBundleData bundle, final InternalCallContext context) {
-        throw new SubscriptionError(NOT_IMPLEMENTED);
+    public SubscriptionBaseBundle createSubscriptionBundle(final DefaultSubscriptionBaseBundle bundle, final InternalCallContext context) {
+        throw new SubscriptionBaseError(NOT_IMPLEMENTED);
     }
 
     @Override
     public SubscriptionBase getSubscriptionFromId(final UUID subscriptionId, final InternalTenantContext context) {
-        throw new SubscriptionError(NOT_IMPLEMENTED);
+        throw new SubscriptionBaseError(NOT_IMPLEMENTED);
     }
 
     @Override
     public UUID getAccountIdFromSubscriptionId(final UUID subscriptionId, final InternalTenantContext context) {
-        throw new SubscriptionError(NOT_IMPLEMENTED);
+        throw new SubscriptionBaseError(NOT_IMPLEMENTED);
     }
 
     @Override
     public SubscriptionBase getBaseSubscription(final UUID bundleId, final InternalTenantContext context) {
-        throw new SubscriptionError(NOT_IMPLEMENTED);
+        throw new SubscriptionBaseError(NOT_IMPLEMENTED);
     }
 
     @Override
     public List<SubscriptionBase> getSubscriptions(final UUID bundleId, final InternalTenantContext context) {
-        throw new SubscriptionError(NOT_IMPLEMENTED);
+        throw new SubscriptionBaseError(NOT_IMPLEMENTED);
     }
 
     @Override
     public List<SubscriptionBase> getSubscriptionsForAccountAndKey(final UUID accountId,
                                                                final String bundleKey, final InternalTenantContext context) {
-        throw new SubscriptionError(NOT_IMPLEMENTED);
+        throw new SubscriptionBaseError(NOT_IMPLEMENTED);
     }
 
     @Override
-    public void updateChargedThroughDate(final SubscriptionData subscription, final InternalCallContext context) {
-        throw new SubscriptionError(NOT_IMPLEMENTED);
+    public void updateChargedThroughDate(final DefaultSubscriptionBase subscription, final InternalCallContext context) {
+        throw new SubscriptionBaseError(NOT_IMPLEMENTED);
     }
 
     @Override
-    public void createNextPhaseEvent(final SubscriptionData subscription, final SubscriptionEvent nextPhase, final InternalCallContext context) {
-        throw new SubscriptionError(NOT_IMPLEMENTED);
+    public void createNextPhaseEvent(final DefaultSubscriptionBase subscription, final SubscriptionEvent nextPhase, final InternalCallContext context) {
+        throw new SubscriptionBaseError(NOT_IMPLEMENTED);
     }
 
     @Override
     public SubscriptionEvent getEventById(final UUID eventId, final InternalTenantContext context) {
-        throw new SubscriptionError(NOT_IMPLEMENTED);
+        throw new SubscriptionBaseError(NOT_IMPLEMENTED);
     }
 
     @Override
     public Map<UUID, List<SubscriptionEvent>> getEventsForBundle(final UUID bundleId, final InternalTenantContext context) {
-        throw new SubscriptionError(NOT_IMPLEMENTED);
+        throw new SubscriptionBaseError(NOT_IMPLEMENTED);
     }
 
     @Override
     public List<SubscriptionEvent> getPendingEventsForSubscription(final UUID subscriptionId, final InternalTenantContext context) {
-        throw new SubscriptionError(NOT_IMPLEMENTED);
+        throw new SubscriptionBaseError(NOT_IMPLEMENTED);
     }
 
     @Override
     public void migrate(final UUID accountId, final AccountMigrationData data, final InternalCallContext context) {
-        throw new SubscriptionError(NOT_IMPLEMENTED);
+        throw new SubscriptionBaseError(NOT_IMPLEMENTED);
     }
 
     @Override
     public void repair(final UUID accountId, final UUID bundleId, final List<SubscriptionDataRepair> inRepair, final InternalCallContext context) {
-        throw new SubscriptionError(NOT_IMPLEMENTED);
+        throw new SubscriptionBaseError(NOT_IMPLEMENTED);
     }
 
     @Override
     public void transfer(final UUID srcAccountId, final UUID destAccountId, final BundleMigrationData data,
                          final List<TransferCancelData> transferCancelData, final InternalCallContext fromContext,
                          final InternalCallContext toContext) {
-        throw new SubscriptionError(NOT_IMPLEMENTED);
+        throw new SubscriptionBaseError(NOT_IMPLEMENTED);
     }
 
     @Override
     public List<SubscriptionBaseBundle> getSubscriptionBundlesForKey(final String bundleKey, final InternalTenantContext context) {
-        throw new SubscriptionError(NOT_IMPLEMENTED);
+        throw new SubscriptionBaseError(NOT_IMPLEMENTED);
     }
 }
diff --git a/subscription/src/main/java/com/ning/billing/subscription/engine/dao/SubscriptionDao.java b/subscription/src/main/java/com/ning/billing/subscription/engine/dao/SubscriptionDao.java
index 8b4c194..11b4c55 100644
--- a/subscription/src/main/java/com/ning/billing/subscription/engine/dao/SubscriptionDao.java
+++ b/subscription/src/main/java/com/ning/billing/subscription/engine/dao/SubscriptionDao.java
@@ -24,9 +24,9 @@ import com.ning.billing.subscription.api.migration.AccountMigrationData;
 import com.ning.billing.subscription.api.migration.AccountMigrationData.BundleMigrationData;
 import com.ning.billing.subscription.api.timeline.SubscriptionDataRepair;
 import com.ning.billing.subscription.api.transfer.TransferCancelData;
+import com.ning.billing.subscription.api.user.DefaultSubscriptionBase;
+import com.ning.billing.subscription.api.user.DefaultSubscriptionBaseBundle;
 import com.ning.billing.subscription.api.user.SubscriptionBaseBundle;
-import com.ning.billing.subscription.api.user.SubscriptionBundleData;
-import com.ning.billing.subscription.api.user.SubscriptionData;
 import com.ning.billing.subscription.events.SubscriptionEvent;
 import com.ning.billing.subscription.api.SubscriptionBase;
 import com.ning.billing.util.callcontext.InternalCallContext;
@@ -43,7 +43,7 @@ public interface SubscriptionDao {
 
     public SubscriptionBaseBundle getSubscriptionBundleFromId(UUID bundleId, InternalTenantContext context);
 
-    public SubscriptionBaseBundle createSubscriptionBundle(SubscriptionBundleData bundle, InternalCallContext context);
+    public SubscriptionBaseBundle createSubscriptionBundle(DefaultSubscriptionBaseBundle bundle, InternalCallContext context);
 
     public SubscriptionBase getSubscriptionFromId(UUID subscriptionId, InternalTenantContext context);
 
@@ -58,10 +58,10 @@ public interface SubscriptionDao {
     public List<SubscriptionBase> getSubscriptionsForAccountAndKey(UUID accountId, String bundleKey, InternalTenantContext context);
 
     // Update
-    public void updateChargedThroughDate(SubscriptionData subscription, InternalCallContext context);
+    public void updateChargedThroughDate(DefaultSubscriptionBase subscription, InternalCallContext context);
 
     // Event apis
-    public void createNextPhaseEvent(SubscriptionData subscription, SubscriptionEvent nextPhase, InternalCallContext context);
+    public void createNextPhaseEvent(DefaultSubscriptionBase subscription, SubscriptionEvent nextPhase, InternalCallContext context);
 
     public SubscriptionEvent getEventById(UUID eventId, InternalTenantContext context);
 
@@ -72,17 +72,17 @@ public interface SubscriptionDao {
     public List<SubscriptionEvent> getPendingEventsForSubscription(UUID subscriptionId, InternalTenantContext context);
 
     // SubscriptionBase creation, cancellation, changePlan apis
-    public void createSubscription(SubscriptionData subscription, List<SubscriptionEvent> initialEvents, InternalCallContext context);
+    public void createSubscription(DefaultSubscriptionBase subscription, List<SubscriptionEvent> initialEvents, InternalCallContext context);
 
-    public void recreateSubscription(SubscriptionData subscription, List<SubscriptionEvent> recreateEvents, InternalCallContext context);
+    public void recreateSubscription(DefaultSubscriptionBase subscription, List<SubscriptionEvent> recreateEvents, InternalCallContext context);
 
-    public void cancelSubscription(SubscriptionData subscription, SubscriptionEvent cancelEvent, InternalCallContext context, int cancelSeq);
+    public void cancelSubscription(DefaultSubscriptionBase subscription, SubscriptionEvent cancelEvent, InternalCallContext context, int cancelSeq);
 
-    public void cancelSubscriptions(final List<SubscriptionData> subscriptions, final List<SubscriptionEvent> cancelEvents, final InternalCallContext context);
+    public void cancelSubscriptions(final List<DefaultSubscriptionBase> subscriptions, final List<SubscriptionEvent> cancelEvents, final InternalCallContext context);
 
-    public void uncancelSubscription(SubscriptionData subscription, List<SubscriptionEvent> uncancelEvents, InternalCallContext context);
+    public void uncancelSubscription(DefaultSubscriptionBase subscription, List<SubscriptionEvent> uncancelEvents, InternalCallContext context);
 
-    public void changePlan(SubscriptionData subscription, List<SubscriptionEvent> changeEvents, InternalCallContext context);
+    public void changePlan(DefaultSubscriptionBase subscription, List<SubscriptionEvent> changeEvents, InternalCallContext context);
 
     public void migrate(UUID accountId, AccountMigrationData data, InternalCallContext context);
 
diff --git a/subscription/src/main/java/com/ning/billing/subscription/events/phase/PhaseEventData.java b/subscription/src/main/java/com/ning/billing/subscription/events/phase/PhaseEventData.java
index 174b6e2..e7fcb7d 100644
--- a/subscription/src/main/java/com/ning/billing/subscription/events/phase/PhaseEventData.java
+++ b/subscription/src/main/java/com/ning/billing/subscription/events/phase/PhaseEventData.java
@@ -19,7 +19,7 @@ package com.ning.billing.subscription.events.phase;
 
 import org.joda.time.DateTime;
 
-import com.ning.billing.subscription.api.user.SubscriptionData;
+import com.ning.billing.subscription.api.user.DefaultSubscriptionBase;
 import com.ning.billing.subscription.events.EventBase;
 
 
@@ -56,7 +56,7 @@ public class PhaseEventData extends EventBase implements PhaseEvent {
                 + ", isActive()=" + isActive() + "]\n";
     }
 
-    public static PhaseEvent createNextPhaseEvent(final String phaseName, final SubscriptionData subscription, final DateTime now, final DateTime effectiveDate) {
+    public static PhaseEvent createNextPhaseEvent(final String phaseName, final DefaultSubscriptionBase subscription, final DateTime now, final DateTime effectiveDate) {
         return (phaseName == null) ?
                 null :
                 new PhaseEventData(new PhaseEventBuilder()
diff --git a/subscription/src/main/java/com/ning/billing/subscription/exceptions/SubscriptionBaseError.java b/subscription/src/main/java/com/ning/billing/subscription/exceptions/SubscriptionBaseError.java
new file mode 100644
index 0000000..12ade9c
--- /dev/null
+++ b/subscription/src/main/java/com/ning/billing/subscription/exceptions/SubscriptionBaseError.java
@@ -0,0 +1,38 @@
+/*
+ * Copyright 2010-2013 Ning, Inc.
+ *
+ * Ning licenses this file to you under the Apache License, version 2.0
+ * (the "License"); you may not use this file except in compliance with the
+ * License.  You may obtain a copy of the License at:
+ *
+ *    http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
+ * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.  See the
+ * License for the specific language governing permissions and limitations
+ * under the License.
+ */
+
+package com.ning.billing.subscription.exceptions;
+
+public class SubscriptionBaseError extends Error {
+
+    private static final long serialVersionUID = 131398536;
+
+    public SubscriptionBaseError() {
+        super();
+    }
+
+    public SubscriptionBaseError(final String msg, final Throwable arg1) {
+        super(msg, arg1);
+    }
+
+    public SubscriptionBaseError(final String msg) {
+        super(msg);
+    }
+
+    public SubscriptionBaseError(final Throwable msg) {
+        super(msg);
+    }
+}
diff --git a/subscription/src/main/java/com/ning/billing/subscription/glue/DefaultSubscriptionModule.java b/subscription/src/main/java/com/ning/billing/subscription/glue/DefaultSubscriptionModule.java
index d70a398..7ea4eeb 100644
--- a/subscription/src/main/java/com/ning/billing/subscription/glue/DefaultSubscriptionModule.java
+++ b/subscription/src/main/java/com/ning/billing/subscription/glue/DefaultSubscriptionModule.java
@@ -22,20 +22,20 @@ import org.skife.config.ConfigurationObjectFactory;
 import com.ning.billing.glue.SubscriptionModule;
 import com.ning.billing.subscription.alignment.MigrationPlanAligner;
 import com.ning.billing.subscription.alignment.PlanAligner;
-import com.ning.billing.subscription.api.SubscriptionApiService;
-import com.ning.billing.subscription.api.SubscriptionService;
-import com.ning.billing.subscription.api.migration.DefaultSubscriptionMigrationApi;
-import com.ning.billing.subscription.api.migration.SubscriptionMigrationApi;
+import com.ning.billing.subscription.api.SubscriptionBaseApiService;
+import com.ning.billing.subscription.api.SubscriptionBaseService;
+import com.ning.billing.subscription.api.migration.DefaultSubscriptionBaseMigrationApi;
+import com.ning.billing.subscription.api.migration.SubscriptionBaseMigrationApi;
 import com.ning.billing.subscription.api.svcs.DefaultSubscriptionInternalApi;
-import com.ning.billing.subscription.api.timeline.DefaultSubscriptionTimelineApi;
+import com.ning.billing.subscription.api.timeline.DefaultSubscriptionBaseTimelineApi;
 import com.ning.billing.subscription.api.timeline.RepairSubscriptionApiService;
 import com.ning.billing.subscription.api.timeline.RepairSubscriptionLifecycleDao;
-import com.ning.billing.subscription.api.timeline.SubscriptionTimelineApi;
-import com.ning.billing.subscription.api.transfer.DefaultSubscriptionTransferApi;
-import com.ning.billing.subscription.api.transfer.SubscriptionTransferApi;
-import com.ning.billing.subscription.api.user.DefaultSubscriptionApiService;
+import com.ning.billing.subscription.api.timeline.SubscriptionBaseTimelineApi;
+import com.ning.billing.subscription.api.transfer.DefaultSubscriptionBaseTransferApi;
+import com.ning.billing.subscription.api.transfer.SubscriptionBaseTransferApi;
+import com.ning.billing.subscription.api.user.DefaultSubscriptionBaseApiService;
 import com.ning.billing.subscription.engine.addon.AddonUtils;
-import com.ning.billing.subscription.engine.core.DefaultSubscriptionService;
+import com.ning.billing.subscription.engine.core.DefaultSubscriptionBaseService;
 import com.ning.billing.subscription.engine.dao.DefaultSubscriptionDao;
 import com.ning.billing.subscription.engine.dao.RepairSubscriptionDao;
 import com.ning.billing.subscription.engine.dao.SubscriptionDao;
@@ -69,10 +69,10 @@ public class DefaultSubscriptionModule extends AbstractModule implements Subscri
 
     protected void installSubscriptionCore() {
 
-        bind(SubscriptionApiService.class).annotatedWith(Names.named(REPAIR_NAMED)).to(RepairSubscriptionApiService.class).asEagerSingleton();
-        bind(SubscriptionApiService.class).to(DefaultSubscriptionApiService.class).asEagerSingleton();
+        bind(SubscriptionBaseApiService.class).annotatedWith(Names.named(REPAIR_NAMED)).to(RepairSubscriptionApiService.class).asEagerSingleton();
+        bind(SubscriptionBaseApiService.class).to(DefaultSubscriptionBaseApiService.class).asEagerSingleton();
 
-        bind(DefaultSubscriptionService.class).asEagerSingleton();
+        bind(DefaultSubscriptionBaseService.class).asEagerSingleton();
         bind(PlanAligner.class).asEagerSingleton();
         bind(AddonUtils.class).asEagerSingleton();
         bind(MigrationPlanAligner.class).asEagerSingleton();
@@ -93,17 +93,17 @@ public class DefaultSubscriptionModule extends AbstractModule implements Subscri
 
     @Override
     public void installSubscriptionService() {
-        bind(SubscriptionService.class).to(DefaultSubscriptionService.class).asEagerSingleton();
+        bind(SubscriptionBaseService.class).to(DefaultSubscriptionBaseService.class).asEagerSingleton();
     }
 
     @Override
     public void installSubscriptionTimelineApi() {
-        bind(SubscriptionTimelineApi.class).to(DefaultSubscriptionTimelineApi.class).asEagerSingleton();
+        bind(SubscriptionBaseTimelineApi.class).to(DefaultSubscriptionBaseTimelineApi.class).asEagerSingleton();
     }
 
     @Override
     public void installSubscriptionMigrationApi() {
-        bind(SubscriptionMigrationApi.class).to(DefaultSubscriptionMigrationApi.class).asEagerSingleton();
+        bind(SubscriptionBaseMigrationApi.class).to(DefaultSubscriptionBaseMigrationApi.class).asEagerSingleton();
     }
 
 
@@ -114,6 +114,6 @@ public class DefaultSubscriptionModule extends AbstractModule implements Subscri
 
     @Override
     public void installSubscriptionTransferApi() {
-        bind(SubscriptionTransferApi.class).to(DefaultSubscriptionTransferApi.class).asEagerSingleton();
+        bind(SubscriptionBaseTransferApi.class).to(DefaultSubscriptionBaseTransferApi.class).asEagerSingleton();
     }
 }
diff --git a/subscription/src/test/java/com/ning/billing/subscription/alignment/TestPlanAligner.java b/subscription/src/test/java/com/ning/billing/subscription/alignment/TestPlanAligner.java
index 181d532..3dab04f 100644
--- a/subscription/src/test/java/com/ning/billing/subscription/alignment/TestPlanAligner.java
+++ b/subscription/src/test/java/com/ning/billing/subscription/alignment/TestPlanAligner.java
@@ -34,15 +34,15 @@ import com.ning.billing.catalog.api.PriceListSet;
 import com.ning.billing.catalog.io.VersionedCatalogLoader;
 import com.ning.billing.clock.DefaultClock;
 import com.ning.billing.subscription.SubscriptionTestSuiteNoDB;
+import com.ning.billing.subscription.api.user.DefaultSubscriptionBase;
 import com.ning.billing.subscription.api.user.SubscriptionBaseApiException;
 import com.ning.billing.subscription.api.user.SubscriptionBaseTransition;
 import com.ning.billing.subscription.api.user.SubscriptionBuilder;
-import com.ning.billing.subscription.api.user.SubscriptionData;
 import com.ning.billing.subscription.events.SubscriptionEvent;
 import com.ning.billing.subscription.events.user.ApiEventBase;
 import com.ning.billing.subscription.events.user.ApiEventBuilder;
 import com.ning.billing.subscription.events.user.ApiEventType;
-import com.ning.billing.subscription.exceptions.SubscriptionError;
+import com.ning.billing.subscription.exceptions.SubscriptionBaseError;
 import com.ning.billing.util.config.CatalogConfig;
 
 import com.google.common.collect.ImmutableList;
@@ -81,132 +81,132 @@ public class TestPlanAligner extends SubscriptionTestSuiteNoDB {
     public void testCreationBundleAlignment() throws Exception {
         final String productName = "pistol-monthly";
         final PhaseType initialPhase = PhaseType.TRIAL;
-        final SubscriptionData subscriptionData = createSubscriptionStartedInThePast(productName, initialPhase);
+        final DefaultSubscriptionBase defaultSubscriptionBase = createSubscriptionStartedInThePast(productName, initialPhase);
 
         // Make the creation effective now, after the bundle and the subscription started
         final DateTime effectiveDate = clock.getUTCNow();
-        final TimedPhase[] phases = getTimedPhasesOnCreate(productName, initialPhase, subscriptionData, effectiveDate);
+        final TimedPhase[] phases = getTimedPhasesOnCreate(productName, initialPhase, defaultSubscriptionBase, effectiveDate);
 
         // All plans but Laser-Scope are START_OF_BUNDLE aligned on creation
-        Assert.assertEquals(phases[0].getStartPhase(), subscriptionData.getBundleStartDate());
-        Assert.assertEquals(phases[1].getStartPhase(), subscriptionData.getBundleStartDate().plusDays(30));
+        Assert.assertEquals(phases[0].getStartPhase(), defaultSubscriptionBase.getBundleStartDate());
+        Assert.assertEquals(phases[1].getStartPhase(), defaultSubscriptionBase.getBundleStartDate().plusDays(30));
 
         // Verify the next phase via the other API
-        final TimedPhase nextTimePhase = planAligner.getNextTimedPhase(subscriptionData, effectiveDate, effectiveDate);
-        Assert.assertEquals(nextTimePhase.getStartPhase(), subscriptionData.getBundleStartDate().plusDays(30));
+        final TimedPhase nextTimePhase = planAligner.getNextTimedPhase(defaultSubscriptionBase, effectiveDate, effectiveDate);
+        Assert.assertEquals(nextTimePhase.getStartPhase(), defaultSubscriptionBase.getBundleStartDate().plusDays(30));
 
         // Now look at the past, before the bundle started
-        final DateTime effectiveDateInThePast = subscriptionData.getBundleStartDate().minusHours(10);
-        final TimedPhase[] phasesInThePast = getTimedPhasesOnCreate(productName, initialPhase, subscriptionData, effectiveDateInThePast);
+        final DateTime effectiveDateInThePast = defaultSubscriptionBase.getBundleStartDate().minusHours(10);
+        final TimedPhase[] phasesInThePast = getTimedPhasesOnCreate(productName, initialPhase, defaultSubscriptionBase, effectiveDateInThePast);
         Assert.assertNull(phasesInThePast[0]);
-        Assert.assertEquals(phasesInThePast[1].getStartPhase(), subscriptionData.getBundleStartDate());
+        Assert.assertEquals(phasesInThePast[1].getStartPhase(), defaultSubscriptionBase.getBundleStartDate());
 
         // Verify the next phase via the other API
         try {
-            planAligner.getNextTimedPhase(subscriptionData, effectiveDateInThePast, effectiveDateInThePast);
+            planAligner.getNextTimedPhase(defaultSubscriptionBase, effectiveDateInThePast, effectiveDateInThePast);
             Assert.fail("Can't use getNextTimedPhase(): the effective date is before the initial plan");
-        } catch (SubscriptionError e) {
+        } catch (SubscriptionBaseError e) {
             Assert.assertTrue(true);
         }
 
         // Try a change plan now (simulate an IMMEDIATE policy)
         final String newProductName = "shotgun-monthly";
         final DateTime effectiveChangeDate = clock.getUTCNow();
-        changeSubscription(effectiveChangeDate, subscriptionData, productName, newProductName, initialPhase);
+        changeSubscription(effectiveChangeDate, defaultSubscriptionBase, productName, newProductName, initialPhase);
 
         // All non rescue plans are START_OF_SUBSCRIPTION aligned on change
-        final TimedPhase newPhase = getNextTimedPhaseOnChange(subscriptionData, newProductName, effectiveChangeDate);
-        Assert.assertEquals(newPhase.getStartPhase(), subscriptionData.getStartDate().plusDays(30),
+        final TimedPhase newPhase = getNextTimedPhaseOnChange(defaultSubscriptionBase, newProductName, effectiveChangeDate);
+        Assert.assertEquals(newPhase.getStartPhase(), defaultSubscriptionBase.getStartDate().plusDays(30),
                             String.format("Start phase: %s, but bundle start date: %s and subscription start date: %s",
-                                          newPhase.getStartPhase(), subscriptionData.getBundleStartDate(), subscriptionData.getStartDate()));
+                                          newPhase.getStartPhase(), defaultSubscriptionBase.getBundleStartDate(), defaultSubscriptionBase.getStartDate()));
     }
 
     @Test(groups = "fast")
     public void testCreationSubscriptionAlignment() throws Exception {
         final String productName = "laser-scope-monthly";
         final PhaseType initialPhase = PhaseType.DISCOUNT;
-        final SubscriptionData subscriptionData = createSubscriptionStartedInThePast(productName, initialPhase);
+        final DefaultSubscriptionBase defaultSubscriptionBase = createSubscriptionStartedInThePast(productName, initialPhase);
 
         // Look now, after the bundle and the subscription started
         final DateTime effectiveDate = clock.getUTCNow();
-        final TimedPhase[] phases = getTimedPhasesOnCreate(productName, initialPhase, subscriptionData, effectiveDate);
+        final TimedPhase[] phases = getTimedPhasesOnCreate(productName, initialPhase, defaultSubscriptionBase, effectiveDate);
 
         // Laser-Scope is START_OF_SUBSCRIPTION aligned on creation
-        Assert.assertEquals(phases[0].getStartPhase(), subscriptionData.getStartDate());
-        Assert.assertEquals(phases[1].getStartPhase(), subscriptionData.getStartDate().plusMonths(1));
+        Assert.assertEquals(phases[0].getStartPhase(), defaultSubscriptionBase.getStartDate());
+        Assert.assertEquals(phases[1].getStartPhase(), defaultSubscriptionBase.getStartDate().plusMonths(1));
 
         // Verify the next phase via the other API
-        final TimedPhase nextTimePhase = planAligner.getNextTimedPhase(subscriptionData, effectiveDate, effectiveDate);
-        Assert.assertEquals(nextTimePhase.getStartPhase(), subscriptionData.getStartDate().plusMonths(1));
+        final TimedPhase nextTimePhase = planAligner.getNextTimedPhase(defaultSubscriptionBase, effectiveDate, effectiveDate);
+        Assert.assertEquals(nextTimePhase.getStartPhase(), defaultSubscriptionBase.getStartDate().plusMonths(1));
 
         // Now look at the past, before the subscription started
-        final DateTime effectiveDateInThePast = subscriptionData.getStartDate().minusHours(10);
-        final TimedPhase[] phasesInThePast = getTimedPhasesOnCreate(productName, initialPhase, subscriptionData, effectiveDateInThePast);
+        final DateTime effectiveDateInThePast = defaultSubscriptionBase.getStartDate().minusHours(10);
+        final TimedPhase[] phasesInThePast = getTimedPhasesOnCreate(productName, initialPhase, defaultSubscriptionBase, effectiveDateInThePast);
         Assert.assertNull(phasesInThePast[0]);
-        Assert.assertEquals(phasesInThePast[1].getStartPhase(), subscriptionData.getStartDate());
+        Assert.assertEquals(phasesInThePast[1].getStartPhase(), defaultSubscriptionBase.getStartDate());
 
         // Verify the next phase via the other API
         try {
-            planAligner.getNextTimedPhase(subscriptionData, effectiveDateInThePast, effectiveDateInThePast);
+            planAligner.getNextTimedPhase(defaultSubscriptionBase, effectiveDateInThePast, effectiveDateInThePast);
             Assert.fail("Can't use getNextTimedPhase(): the effective date is before the initial plan");
-        } catch (SubscriptionError e) {
+        } catch (SubscriptionBaseError e) {
             Assert.assertTrue(true);
         }
 
         // Try a change plan (simulate END_OF_TERM policy)
         final String newProductName = "telescopic-scope-monthly";
-        final DateTime effectiveChangeDate = subscriptionData.getStartDate().plusMonths(1);
-        changeSubscription(effectiveChangeDate, subscriptionData, productName, newProductName, initialPhase);
+        final DateTime effectiveChangeDate = defaultSubscriptionBase.getStartDate().plusMonths(1);
+        changeSubscription(effectiveChangeDate, defaultSubscriptionBase, productName, newProductName, initialPhase);
 
         // All non rescue plans are START_OF_SUBSCRIPTION aligned on change. Since we're END_OF_TERM here, we'll
         // never see the discount phase of telescopic-scope-monthly and jump right into evergreen.
         // But in this test, since we didn't create the future change event from discount to evergreen (see changeSubscription,
         // the subscription has only two transitions), we'll see null
-        final TimedPhase newPhase = getNextTimedPhaseOnChange(subscriptionData, newProductName, effectiveChangeDate);
+        final TimedPhase newPhase = getNextTimedPhaseOnChange(defaultSubscriptionBase, newProductName, effectiveChangeDate);
         Assert.assertNull(newPhase);
     }
 
-    private SubscriptionData createSubscriptionStartedInThePast(final String productName, final PhaseType phaseType) {
+    private DefaultSubscriptionBase createSubscriptionStartedInThePast(final String productName, final PhaseType phaseType) {
         final SubscriptionBuilder builder = new SubscriptionBuilder();
         builder.setBundleStartDate(clock.getUTCNow().minusHours(10));
         // Make sure to set the dates apart
         builder.setAlignStartDate(new DateTime(builder.getBundleStartDate().plusHours(5)));
 
         // Create the transitions
-        final SubscriptionData subscriptionData = new SubscriptionData(builder, null, clock);
+        final DefaultSubscriptionBase defaultSubscriptionBase = new DefaultSubscriptionBase(builder, null, clock);
         final SubscriptionEvent event = createSubscriptionEvent(builder.getAlignStartDate(),
                                                                 productName,
                                                                 phaseType,
                                                                 ApiEventType.CREATE,
-                                                                subscriptionData.getActiveVersion());
-        subscriptionData.rebuildTransitions(ImmutableList.<SubscriptionEvent>of(event), catalogService.getFullCatalog());
+                                                                defaultSubscriptionBase.getActiveVersion());
+        defaultSubscriptionBase.rebuildTransitions(ImmutableList.<SubscriptionEvent>of(event), catalogService.getFullCatalog());
 
-        Assert.assertEquals(subscriptionData.getAllTransitions().size(), 1);
-        Assert.assertNull(subscriptionData.getAllTransitions().get(0).getPreviousPhase());
-        Assert.assertNotNull(subscriptionData.getAllTransitions().get(0).getNextPhase());
+        Assert.assertEquals(defaultSubscriptionBase.getAllTransitions().size(), 1);
+        Assert.assertNull(defaultSubscriptionBase.getAllTransitions().get(0).getPreviousPhase());
+        Assert.assertNotNull(defaultSubscriptionBase.getAllTransitions().get(0).getNextPhase());
 
-        return subscriptionData;
+        return defaultSubscriptionBase;
     }
 
     private void changeSubscription(final DateTime effectiveChangeDate,
-                                    final SubscriptionData subscriptionData,
+                                    final DefaultSubscriptionBase defaultSubscriptionBase,
                                     final String previousProductName,
                                     final String newProductName,
                                     final PhaseType commonPhaseType) {
-        final SubscriptionEvent previousEvent = createSubscriptionEvent(subscriptionData.getStartDate(),
+        final SubscriptionEvent previousEvent = createSubscriptionEvent(defaultSubscriptionBase.getStartDate(),
                                                                         previousProductName,
                                                                         commonPhaseType,
                                                                         ApiEventType.CREATE,
-                                                                        subscriptionData.getActiveVersion());
+                                                                        defaultSubscriptionBase.getActiveVersion());
         final SubscriptionEvent event = createSubscriptionEvent(effectiveChangeDate,
                                                                 newProductName,
                                                                 commonPhaseType,
                                                                 ApiEventType.CHANGE,
-                                                                subscriptionData.getActiveVersion());
+                                                                defaultSubscriptionBase.getActiveVersion());
 
-        subscriptionData.rebuildTransitions(ImmutableList.<SubscriptionEvent>of(previousEvent, event), catalogService.getFullCatalog());
+        defaultSubscriptionBase.rebuildTransitions(ImmutableList.<SubscriptionEvent>of(previousEvent, event), catalogService.getFullCatalog());
 
-        final List<SubscriptionBaseTransition> newTransitions = subscriptionData.getAllTransitions();
+        final List<SubscriptionBaseTransition> newTransitions = defaultSubscriptionBase.getAllTransitions();
         Assert.assertEquals(newTransitions.size(), 2);
         Assert.assertNull(newTransitions.get(0).getPreviousPhase());
         Assert.assertEquals(newTransitions.get(0).getNextPhase(), newTransitions.get(1).getPreviousPhase());
@@ -232,24 +232,24 @@ public class TestPlanAligner extends SubscriptionTestSuiteNoDB {
         return new ApiEventBase(eventBuilder.setEventType(apiEventType));
     }
 
-    private TimedPhase getNextTimedPhaseOnChange(final SubscriptionData subscriptionData,
+    private TimedPhase getNextTimedPhaseOnChange(final DefaultSubscriptionBase defaultSubscriptionBase,
                                                  final String newProductName,
                                                  final DateTime effectiveChangeDate) throws CatalogApiException, SubscriptionBaseApiException {
         // The date is used for different catalog versions - we don't care here
         final Plan newPlan = catalogService.getFullCatalog().findPlan(newProductName, clock.getUTCNow());
 
-        return planAligner.getNextTimedPhaseOnChange(subscriptionData, newPlan, priceList, effectiveChangeDate, effectiveChangeDate);
+        return planAligner.getNextTimedPhaseOnChange(defaultSubscriptionBase, newPlan, priceList, effectiveChangeDate, effectiveChangeDate);
     }
 
     private TimedPhase[] getTimedPhasesOnCreate(final String productName,
                                                 final PhaseType initialPhase,
-                                                final SubscriptionData subscriptionData,
+                                                final DefaultSubscriptionBase defaultSubscriptionBase,
                                                 final DateTime effectiveDate) throws CatalogApiException, SubscriptionBaseApiException {
         // The date is used for different catalog versions - we don't care here
         final Plan plan = catalogService.getFullCatalog().findPlan(productName, clock.getUTCNow());
 
         // Same here for the requested date
-        final TimedPhase[] phases = planAligner.getCurrentAndNextTimedPhaseOnCreate(subscriptionData, plan, initialPhase, priceList, clock.getUTCNow(), effectiveDate);
+        final TimedPhase[] phases = planAligner.getCurrentAndNextTimedPhaseOnCreate(defaultSubscriptionBase, plan, initialPhase, priceList, clock.getUTCNow(), effectiveDate);
         Assert.assertEquals(phases.length, 2);
 
         return phases;
diff --git a/subscription/src/test/java/com/ning/billing/subscription/api/migration/TestMigration.java b/subscription/src/test/java/com/ning/billing/subscription/api/migration/TestMigration.java
index 8984615..9cb6168 100644
--- a/subscription/src/test/java/com/ning/billing/subscription/api/migration/TestMigration.java
+++ b/subscription/src/test/java/com/ning/billing/subscription/api/migration/TestMigration.java
@@ -29,10 +29,10 @@ import com.ning.billing.catalog.api.PhaseType;
 import com.ning.billing.catalog.api.PriceListSet;
 import com.ning.billing.catalog.api.ProductCategory;
 import com.ning.billing.subscription.SubscriptionTestSuiteWithEmbeddedDB;
-import com.ning.billing.subscription.api.migration.SubscriptionMigrationApi.AccountMigration;
+import com.ning.billing.subscription.api.migration.SubscriptionBaseMigrationApi.AccountMigration;
+import com.ning.billing.subscription.api.user.DefaultSubscriptionBase;
 import com.ning.billing.subscription.api.user.SubscriptionBaseBundle;
 import com.ning.billing.subscription.api.user.SubscriptionBaseTransition;
-import com.ning.billing.subscription.api.user.SubscriptionData;
 import com.ning.billing.subscription.api.user.SubscriptionBaseTransitionData;
 import com.ning.billing.subscription.events.user.ApiEventType;
 import com.ning.billing.subscription.api.SubscriptionBase;
@@ -74,7 +74,7 @@ public class TestMigration extends SubscriptionTestSuiteWithEmbeddedDB {
             assertEquals(subscription.getChargedThroughDate(), startDate.plusYears(1));
 
             assertListenerStatus();
-        } catch (SubscriptionMigrationApiException e) {
+        } catch (SubscriptionBaseMigrationApiException e) {
             Assert.fail("", e);
         }
     }
@@ -123,7 +123,7 @@ public class TestMigration extends SubscriptionTestSuiteWithEmbeddedDB {
             assertEquals(aoSubscription.getChargedThroughDate(), initalAddonStart.plusMonths(1));
 
             assertListenerStatus();
-        } catch (SubscriptionMigrationApiException e) {
+        } catch (SubscriptionBaseMigrationApiException e) {
             Assert.fail("", e);
         }
     }
@@ -172,7 +172,7 @@ public class TestMigration extends SubscriptionTestSuiteWithEmbeddedDB {
             assertNull(subscription.getCurrentPlan());
 
             assertListenerStatus();
-        } catch (SubscriptionMigrationApiException e) {
+        } catch (SubscriptionBaseMigrationApiException e) {
             Assert.fail("", e);
         }
     }
@@ -219,7 +219,7 @@ public class TestMigration extends SubscriptionTestSuiteWithEmbeddedDB {
             assertEquals(subscription.getCurrentPhase().getName(), "assault-rifle-monthly-evergreen");
 
             assertListenerStatus();
-        } catch (SubscriptionMigrationApiException e) {
+        } catch (SubscriptionBaseMigrationApiException e) {
             Assert.fail("", e);
         }
     }
@@ -266,7 +266,7 @@ public class TestMigration extends SubscriptionTestSuiteWithEmbeddedDB {
 
             assertListenerStatus();
 
-        } catch (SubscriptionMigrationApiException e) {
+        } catch (SubscriptionBaseMigrationApiException e) {
             Assert.fail("", e);
         }
     }
@@ -289,7 +289,7 @@ public class TestMigration extends SubscriptionTestSuiteWithEmbeddedDB {
 
             final List<SubscriptionBase> subscriptions = subscriptionInternalApi.getSubscriptionsForBundle(bundles.get(0).getId(), internalCallContext);
             assertEquals(subscriptions.size(), 1);
-            final SubscriptionData subscription = (SubscriptionData) subscriptions.get(0);
+            final DefaultSubscriptionBase subscription = (DefaultSubscriptionBase) subscriptions.get(0);
 
             final List<SubscriptionBaseTransition> transitions = subscription.getAllTransitions();
             assertEquals(transitions.size(), 2);
@@ -325,7 +325,7 @@ public class TestMigration extends SubscriptionTestSuiteWithEmbeddedDB {
             assertEquals(newBillingTransitions.get(0), newMigrateBilling);
 
 
-        } catch (SubscriptionMigrationApiException e) {
+        } catch (SubscriptionBaseMigrationApiException e) {
             Assert.fail("", e);
         }
 
diff --git a/subscription/src/test/java/com/ning/billing/subscription/api/timeline/TestRepairBP.java b/subscription/src/test/java/com/ning/billing/subscription/api/timeline/TestRepairBP.java
index 5c8374b..b293a5a 100644
--- a/subscription/src/test/java/com/ning/billing/subscription/api/timeline/TestRepairBP.java
+++ b/subscription/src/test/java/com/ning/billing/subscription/api/timeline/TestRepairBP.java
@@ -36,13 +36,13 @@ import com.ning.billing.catalog.api.PriceListSet;
 import com.ning.billing.catalog.api.ProductCategory;
 import com.ning.billing.subscription.SubscriptionTestSuiteWithEmbeddedDB;
 import com.ning.billing.subscription.api.SubscriptionBaseTransitionType;
-import com.ning.billing.subscription.api.user.SubscriptionData;
+import com.ning.billing.subscription.api.user.DefaultSubscriptionBase;
 import com.ning.billing.subscription.api.user.SubscriptionEvents;
 import com.ning.billing.subscription.api.user.TestSubscriptionHelper.TestWithException;
 import com.ning.billing.subscription.api.user.TestSubscriptionHelper.TestWithExceptionCallback;
-import com.ning.billing.subscription.api.timeline.SubscriptionTimeline.DeletedEvent;
-import com.ning.billing.subscription.api.timeline.SubscriptionTimeline.ExistingEvent;
-import com.ning.billing.subscription.api.timeline.SubscriptionTimeline.NewEvent;
+import com.ning.billing.subscription.api.timeline.SubscriptionBaseTimeline.DeletedEvent;
+import com.ning.billing.subscription.api.timeline.SubscriptionBaseTimeline.ExistingEvent;
+import com.ning.billing.subscription.api.timeline.SubscriptionBaseTimeline.NewEvent;
 import com.ning.billing.subscription.api.SubscriptionBase;
 import com.ning.billing.subscription.api.user.SubscriptionState;
 import com.ning.billing.subscription.api.user.SubscriptionBaseApiException;
@@ -67,13 +67,13 @@ public class TestRepairBP extends SubscriptionTestSuiteWithEmbeddedDB {
         final BillingPeriod aoTerm = BillingPeriod.MONTHLY;
         final String aoPriceList = PriceListSet.DEFAULT_PRICELIST_NAME;
 
-        final SubscriptionData aoSubscription = testUtil.createSubscription(bundle, aoProduct, aoTerm, aoPriceList);
+        final DefaultSubscriptionBase aoSubscription = testUtil.createSubscription(bundle, aoProduct, aoTerm, aoPriceList);
 
-        final BundleTimeline bundleRepair = repairApi.getBundleTimeline(bundle.getId(), callContext);
-        final List<SubscriptionTimeline> subscriptionRepair = bundleRepair.getSubscriptions();
+        final BundleBaseTimeline bundleRepair = repairApi.getBundleTimeline(bundle.getId(), callContext);
+        final List<SubscriptionBaseTimeline> subscriptionRepair = bundleRepair.getSubscriptions();
         assertEquals(subscriptionRepair.size(), 2);
 
-        for (final SubscriptionTimeline cur : subscriptionRepair) {
+        for (final SubscriptionBaseTimeline cur : subscriptionRepair) {
             assertNull(cur.getDeletedEvents());
             assertNull(cur.getNewEvents());
 
@@ -129,28 +129,28 @@ public class TestRepairBP extends SubscriptionTestSuiteWithEmbeddedDB {
         final Interval it = new Interval(clock.getUTCNow(), clock.getUTCNow().plusDays(10));
         clock.addDeltaFromReality(it.toDurationMillis());
 
-        final BundleTimeline bundleRepair = repairApi.getBundleTimeline(bundle.getId(), callContext);
+        final BundleBaseTimeline bundleRepair = repairApi.getBundleTimeline(bundle.getId(), callContext);
         testUtil.sortEventsOnBundle(bundleRepair);
 
-        final List<DeletedEvent> des = new LinkedList<SubscriptionTimeline.DeletedEvent>();
+        final List<DeletedEvent> des = new LinkedList<SubscriptionBaseTimeline.DeletedEvent>();
         des.add(testUtil.createDeletedEvent(bundleRepair.getSubscriptions().get(0).getExistingEvents().get(1).getEventId()));
         final NewEvent ne = testUtil.createNewEvent(SubscriptionBaseTransitionType.CANCEL, baseSubscription.getStartDate(), null);
 
-        final SubscriptionTimeline sRepair = testUtil.createSubscriptionRepair(baseSubscription.getId(), des, Collections.singletonList(ne));
+        final SubscriptionBaseTimeline sRepair = testUtil.createSubscriptionRepair(baseSubscription.getId(), des, Collections.singletonList(ne));
 
         // FIRST ISSUE DRY RUN
-        final BundleTimeline bRepair = testUtil.createBundleRepair(bundle.getId(), bundleRepair.getViewId(), Collections.singletonList(sRepair));
+        final BundleBaseTimeline bRepair = testUtil.createBundleRepair(bundle.getId(), bundleRepair.getViewId(), Collections.singletonList(sRepair));
 
         boolean dryRun = true;
-        final BundleTimeline dryRunBundleRepair = repairApi.repairBundle(bRepair, dryRun, callContext);
+        final BundleBaseTimeline dryRunBundleRepair = repairApi.repairBundle(bRepair, dryRun, callContext);
         testUtil.sortEventsOnBundle(dryRunBundleRepair);
-        List<SubscriptionTimeline> subscriptionRepair = dryRunBundleRepair.getSubscriptions();
+        List<SubscriptionBaseTimeline> subscriptionRepair = dryRunBundleRepair.getSubscriptions();
         assertEquals(subscriptionRepair.size(), 1);
-        SubscriptionTimeline cur = subscriptionRepair.get(0);
+        SubscriptionBaseTimeline cur = subscriptionRepair.get(0);
         int index = 0;
         final List<ExistingEvent> events = subscriptionRepair.get(0).getExistingEvents();
         assertEquals(events.size(), 2);
-        final List<ExistingEvent> expected = new LinkedList<SubscriptionTimeline.ExistingEvent>();
+        final List<ExistingEvent> expected = new LinkedList<SubscriptionBaseTimeline.ExistingEvent>();
         expected.add(testUtil.createExistingEventForAssertion(SubscriptionBaseTransitionType.CREATE, baseProduct, PhaseType.TRIAL,
                                                               ProductCategory.BASE, PriceListSet.DEFAULT_PRICELIST_NAME, BillingPeriod.NO_BILLING_PERIOD, baseSubscription.getStartDate()));
         expected.add(testUtil.createExistingEventForAssertion(SubscriptionBaseTransitionType.CANCEL, baseProduct, PhaseType.TRIAL,
@@ -160,7 +160,7 @@ public class TestRepairBP extends SubscriptionTestSuiteWithEmbeddedDB {
             testUtil.validateExistingEventForAssertion(e, events.get(index++));
         }
 
-        final SubscriptionData dryRunBaseSubscription = (SubscriptionData) subscriptionInternalApi.getSubscriptionFromId(baseSubscription.getId(), internalCallContext);
+        final DefaultSubscriptionBase dryRunBaseSubscription = (DefaultSubscriptionBase) subscriptionInternalApi.getSubscriptionFromId(baseSubscription.getId(), internalCallContext);
 
         assertEquals(dryRunBaseSubscription.getActiveVersion(), SubscriptionEvents.INITIAL_VERSION);
         assertEquals(dryRunBaseSubscription.getBundleId(), bundle.getId());
@@ -179,7 +179,7 @@ public class TestRepairBP extends SubscriptionTestSuiteWithEmbeddedDB {
         // SECOND RE-ISSUE CALL-- NON DRY RUN
         dryRun = false;
         testListener.pushExpectedEvent(NextEvent.REPAIR_BUNDLE);
-        final BundleTimeline realRunBundleRepair = repairApi.repairBundle(bRepair, dryRun, callContext);
+        final BundleBaseTimeline realRunBundleRepair = repairApi.repairBundle(bRepair, dryRun, callContext);
         assertTrue(testListener.isCompleted(5000));
 
         subscriptionRepair = realRunBundleRepair.getSubscriptions();
@@ -190,7 +190,7 @@ public class TestRepairBP extends SubscriptionTestSuiteWithEmbeddedDB {
         for (final ExistingEvent e : expected) {
             testUtil.validateExistingEventForAssertion(e, events.get(index++));
         }
-        final SubscriptionData realRunBaseSubscription = (SubscriptionData) subscriptionInternalApi.getSubscriptionFromId(baseSubscription.getId(), internalCallContext);
+        final DefaultSubscriptionBase realRunBaseSubscription = (DefaultSubscriptionBase) subscriptionInternalApi.getSubscriptionFromId(baseSubscription.getId(), internalCallContext);
         assertEquals(realRunBaseSubscription.getAllTransitions().size(), 2);
 
         assertEquals(realRunBaseSubscription.getActiveVersion(), SubscriptionEvents.INITIAL_VERSION + 1);
@@ -210,7 +210,7 @@ public class TestRepairBP extends SubscriptionTestSuiteWithEmbeddedDB {
         final DateTime startDate = clock.getUTCNow();
         final int clockShift = -1;
         final DateTime restartDate = startDate.plusDays(clockShift).minusDays(1);
-        final LinkedList<ExistingEvent> expected = new LinkedList<SubscriptionTimeline.ExistingEvent>();
+        final LinkedList<ExistingEvent> expected = new LinkedList<SubscriptionBaseTimeline.ExistingEvent>();
 
         expected.add(testUtil.createExistingEventForAssertion(SubscriptionBaseTransitionType.CREATE, newBaseProduct, PhaseType.TRIAL,
                                                               ProductCategory.BASE, PriceListSet.DEFAULT_PRICELIST_NAME, BillingPeriod.NO_BILLING_PERIOD, restartDate));
@@ -229,7 +229,7 @@ public class TestRepairBP extends SubscriptionTestSuiteWithEmbeddedDB {
         final DateTime startDate = clock.getUTCNow();
         final int clockShift = 10;
         final DateTime restartDate = startDate.plusDays(clockShift).minusDays(1);
-        final LinkedList<ExistingEvent> expected = new LinkedList<SubscriptionTimeline.ExistingEvent>();
+        final LinkedList<ExistingEvent> expected = new LinkedList<SubscriptionBaseTimeline.ExistingEvent>();
 
         expected.add(testUtil.createExistingEventForAssertion(SubscriptionBaseTransitionType.CREATE, newBaseProduct, PhaseType.TRIAL,
                                                               ProductCategory.BASE, PriceListSet.DEFAULT_PRICELIST_NAME, BillingPeriod.NO_BILLING_PERIOD, restartDate));
@@ -244,7 +244,7 @@ public class TestRepairBP extends SubscriptionTestSuiteWithEmbeddedDB {
         assertTrue(testListener.isCompleted(5000));
 
         // CHECK WHAT"S GOING ON AFTER WE MOVE CLOCK-- FUTURE MOTIFICATION SHOULD KICK IN
-        final SubscriptionData subscription = (SubscriptionData) subscriptionInternalApi.getSubscriptionFromId(baseSubscriptionId, internalCallContext);
+        final DefaultSubscriptionBase subscription = (DefaultSubscriptionBase) subscriptionInternalApi.getSubscriptionFromId(baseSubscriptionId, internalCallContext);
 
         assertEquals(subscription.getActiveVersion(), SubscriptionEvents.INITIAL_VERSION + 1);
         assertEquals(subscription.getBundleId(), bundle.getId());
@@ -272,7 +272,7 @@ public class TestRepairBP extends SubscriptionTestSuiteWithEmbeddedDB {
         final DateTime startDate = clock.getUTCNow();
         final int clockShift = 40;
         final DateTime restartDate = startDate.plusDays(clockShift).minusDays(1);
-        final LinkedList<ExistingEvent> expected = new LinkedList<SubscriptionTimeline.ExistingEvent>();
+        final LinkedList<ExistingEvent> expected = new LinkedList<SubscriptionBaseTimeline.ExistingEvent>();
 
         expected.add(testUtil.createExistingEventForAssertion(SubscriptionBaseTransitionType.CREATE, newBaseProduct, PhaseType.TRIAL,
                                                               ProductCategory.BASE, PriceListSet.DEFAULT_PRICELIST_NAME, BillingPeriod.NO_BILLING_PERIOD, restartDate));
@@ -301,7 +301,7 @@ public class TestRepairBP extends SubscriptionTestSuiteWithEmbeddedDB {
             }
         }
 
-        final BundleTimeline bundleRepair = repairApi.getBundleTimeline(bundle.getId(), callContext);
+        final BundleBaseTimeline bundleRepair = repairApi.getBundleTimeline(bundle.getId(), callContext);
         testUtil.sortEventsOnBundle(bundleRepair);
 
         final DateTime newCreateTime = baseSubscription.getStartDate().plusDays(clockShift - 1);
@@ -309,20 +309,20 @@ public class TestRepairBP extends SubscriptionTestSuiteWithEmbeddedDB {
         final PlanPhaseSpecifier spec = new PlanPhaseSpecifier(newBaseProduct, ProductCategory.BASE, BillingPeriod.MONTHLY, PriceListSet.DEFAULT_PRICELIST_NAME, PhaseType.TRIAL);
 
         final NewEvent ne = testUtil.createNewEvent(SubscriptionBaseTransitionType.CREATE, newCreateTime, spec);
-        final List<DeletedEvent> des = new LinkedList<SubscriptionTimeline.DeletedEvent>();
+        final List<DeletedEvent> des = new LinkedList<SubscriptionBaseTimeline.DeletedEvent>();
         des.add(testUtil.createDeletedEvent(bundleRepair.getSubscriptions().get(0).getExistingEvents().get(0).getEventId()));
         des.add(testUtil.createDeletedEvent(bundleRepair.getSubscriptions().get(0).getExistingEvents().get(1).getEventId()));
 
-        final SubscriptionTimeline sRepair = testUtil.createSubscriptionRepair(baseSubscription.getId(), des, Collections.singletonList(ne));
+        final SubscriptionBaseTimeline sRepair = testUtil.createSubscriptionRepair(baseSubscription.getId(), des, Collections.singletonList(ne));
 
         // FIRST ISSUE DRY RUN
-        final BundleTimeline bRepair = testUtil.createBundleRepair(bundle.getId(), bundleRepair.getViewId(), Collections.singletonList(sRepair));
+        final BundleBaseTimeline bRepair = testUtil.createBundleRepair(bundle.getId(), bundleRepair.getViewId(), Collections.singletonList(sRepair));
 
         boolean dryRun = true;
-        final BundleTimeline dryRunBundleRepair = repairApi.repairBundle(bRepair, dryRun, callContext);
-        List<SubscriptionTimeline> subscriptionRepair = dryRunBundleRepair.getSubscriptions();
+        final BundleBaseTimeline dryRunBundleRepair = repairApi.repairBundle(bRepair, dryRun, callContext);
+        List<SubscriptionBaseTimeline> subscriptionRepair = dryRunBundleRepair.getSubscriptions();
         assertEquals(subscriptionRepair.size(), 1);
-        SubscriptionTimeline cur = subscriptionRepair.get(0);
+        SubscriptionBaseTimeline cur = subscriptionRepair.get(0);
         assertEquals(cur.getId(), baseSubscription.getId());
 
         List<ExistingEvent> events = cur.getExistingEvents();
@@ -331,7 +331,7 @@ public class TestRepairBP extends SubscriptionTestSuiteWithEmbeddedDB {
         for (final ExistingEvent e : expectedEvents) {
             testUtil.validateExistingEventForAssertion(e, events.get(index++));
         }
-        final SubscriptionData dryRunBaseSubscription = (SubscriptionData) subscriptionInternalApi.getSubscriptionFromId(baseSubscription.getId(), internalCallContext);
+        final DefaultSubscriptionBase dryRunBaseSubscription = (DefaultSubscriptionBase) subscriptionInternalApi.getSubscriptionFromId(baseSubscription.getId(), internalCallContext);
 
         assertEquals(dryRunBaseSubscription.getActiveVersion(), SubscriptionEvents.INITIAL_VERSION);
         assertEquals(dryRunBaseSubscription.getBundleId(), bundle.getId());
@@ -354,7 +354,7 @@ public class TestRepairBP extends SubscriptionTestSuiteWithEmbeddedDB {
         // SECOND RE-ISSUE CALL-- NON DRY RUN
         dryRun = false;
         testListener.pushExpectedEvent(NextEvent.REPAIR_BUNDLE);
-        final BundleTimeline realRunBundleRepair = repairApi.repairBundle(bRepair, dryRun, callContext);
+        final BundleBaseTimeline realRunBundleRepair = repairApi.repairBundle(bRepair, dryRun, callContext);
         assertTrue(testListener.isCompleted(5000));
         subscriptionRepair = realRunBundleRepair.getSubscriptions();
         assertEquals(subscriptionRepair.size(), 1);
@@ -370,7 +370,7 @@ public class TestRepairBP extends SubscriptionTestSuiteWithEmbeddedDB {
         for (final ExistingEvent e : expectedEvents) {
             testUtil.validateExistingEventForAssertion(e, events.get(index++));
         }
-        final SubscriptionData realRunBaseSubscription = (SubscriptionData) subscriptionInternalApi.getSubscriptionFromId(baseSubscription.getId(), internalCallContext);
+        final DefaultSubscriptionBase realRunBaseSubscription = (DefaultSubscriptionBase) subscriptionInternalApi.getSubscriptionFromId(baseSubscription.getId(), internalCallContext);
         assertEquals(realRunBaseSubscription.getAllTransitions().size(), 2);
 
         assertEquals(realRunBaseSubscription.getActiveVersion(), SubscriptionEvents.INITIAL_VERSION + 1);
@@ -398,7 +398,7 @@ public class TestRepairBP extends SubscriptionTestSuiteWithEmbeddedDB {
         final DateTime startDate = clock.getUTCNow();
         final int clockShift = 10;
         final DateTime changeDate = startDate.plusDays(clockShift).minusDays(1);
-        final LinkedList<ExistingEvent> expected = new LinkedList<SubscriptionTimeline.ExistingEvent>();
+        final LinkedList<ExistingEvent> expected = new LinkedList<SubscriptionBaseTimeline.ExistingEvent>();
 
         expected.add(testUtil.createExistingEventForAssertion(SubscriptionBaseTransitionType.CREATE, baseProduct, PhaseType.TRIAL,
                                                               ProductCategory.BASE, PriceListSet.DEFAULT_PRICELIST_NAME, BillingPeriod.NO_BILLING_PERIOD, startDate));
@@ -414,7 +414,7 @@ public class TestRepairBP extends SubscriptionTestSuiteWithEmbeddedDB {
         final Interval it = new Interval(clock.getUTCNow(), clock.getUTCNow().plusDays(32));
         clock.addDeltaFromReality(it.toDurationMillis());
         assertTrue(testListener.isCompleted(5000));
-        final SubscriptionData subscription = (SubscriptionData) subscriptionInternalApi.getSubscriptionFromId(baseSubscriptionId, internalCallContext);
+        final DefaultSubscriptionBase subscription = (DefaultSubscriptionBase) subscriptionInternalApi.getSubscriptionFromId(baseSubscriptionId, internalCallContext);
 
         assertEquals(subscription.getActiveVersion(), SubscriptionEvents.INITIAL_VERSION + 1);
         assertEquals(subscription.getBundleId(), bundle.getId());
@@ -443,7 +443,7 @@ public class TestRepairBP extends SubscriptionTestSuiteWithEmbeddedDB {
         final int clockShift = 40;
         final DateTime changeDate = startDate.plusDays(clockShift).minusDays(1);
 
-        final LinkedList<ExistingEvent> expected = new LinkedList<SubscriptionTimeline.ExistingEvent>();
+        final LinkedList<ExistingEvent> expected = new LinkedList<SubscriptionBaseTimeline.ExistingEvent>();
         expected.add(testUtil.createExistingEventForAssertion(SubscriptionBaseTransitionType.CREATE, baseProduct, PhaseType.TRIAL,
                                                               ProductCategory.BASE, PriceListSet.DEFAULT_PRICELIST_NAME, BillingPeriod.NO_BILLING_PERIOD, startDate));
         expected.add(testUtil.createExistingEventForAssertion(SubscriptionBaseTransitionType.PHASE, baseProduct, PhaseType.EVERGREEN,
@@ -471,7 +471,7 @@ public class TestRepairBP extends SubscriptionTestSuiteWithEmbeddedDB {
             assertTrue(testListener.isCompleted(5000));
         }
 
-        final BundleTimeline bundleRepair = repairApi.getBundleTimeline(bundle.getId(), callContext);
+        final BundleBaseTimeline bundleRepair = repairApi.getBundleTimeline(bundle.getId(), callContext);
         testUtil.sortEventsOnBundle(bundleRepair);
 
         final DateTime changeTime = baseSubscription.getStartDate().plusDays(clockShift - 1);
@@ -479,21 +479,21 @@ public class TestRepairBP extends SubscriptionTestSuiteWithEmbeddedDB {
         final PlanPhaseSpecifier spec = new PlanPhaseSpecifier(newBaseProduct, ProductCategory.BASE, BillingPeriod.MONTHLY, PriceListSet.DEFAULT_PRICELIST_NAME, PhaseType.TRIAL);
 
         final NewEvent ne = testUtil.createNewEvent(SubscriptionBaseTransitionType.CHANGE, changeTime, spec);
-        final List<DeletedEvent> des = new LinkedList<SubscriptionTimeline.DeletedEvent>();
+        final List<DeletedEvent> des = new LinkedList<SubscriptionBaseTimeline.DeletedEvent>();
         if (inTrial) {
             des.add(testUtil.createDeletedEvent(bundleRepair.getSubscriptions().get(0).getExistingEvents().get(1).getEventId()));
         }
-        final SubscriptionTimeline sRepair = testUtil.createSubscriptionRepair(baseSubscription.getId(), des, Collections.singletonList(ne));
+        final SubscriptionBaseTimeline sRepair = testUtil.createSubscriptionRepair(baseSubscription.getId(), des, Collections.singletonList(ne));
 
         // FIRST ISSUE DRY RUN
-        final BundleTimeline bRepair = testUtil.createBundleRepair(bundle.getId(), bundleRepair.getViewId(), Collections.singletonList(sRepair));
+        final BundleBaseTimeline bRepair = testUtil.createBundleRepair(bundle.getId(), bundleRepair.getViewId(), Collections.singletonList(sRepair));
 
         boolean dryRun = true;
-        final BundleTimeline dryRunBundleRepair = repairApi.repairBundle(bRepair, dryRun, callContext);
+        final BundleBaseTimeline dryRunBundleRepair = repairApi.repairBundle(bRepair, dryRun, callContext);
 
-        List<SubscriptionTimeline> subscriptionRepair = dryRunBundleRepair.getSubscriptions();
+        List<SubscriptionBaseTimeline> subscriptionRepair = dryRunBundleRepair.getSubscriptions();
         assertEquals(subscriptionRepair.size(), 1);
-        SubscriptionTimeline cur = subscriptionRepair.get(0);
+        SubscriptionBaseTimeline cur = subscriptionRepair.get(0);
         assertEquals(cur.getId(), baseSubscription.getId());
 
         List<ExistingEvent> events = cur.getExistingEvents();
@@ -502,7 +502,7 @@ public class TestRepairBP extends SubscriptionTestSuiteWithEmbeddedDB {
         for (final ExistingEvent e : expectedEvents) {
             testUtil.validateExistingEventForAssertion(e, events.get(index++));
         }
-        final SubscriptionData dryRunBaseSubscription = (SubscriptionData) subscriptionInternalApi.getSubscriptionFromId(baseSubscription.getId(), internalCallContext);
+        final DefaultSubscriptionBase dryRunBaseSubscription = (DefaultSubscriptionBase) subscriptionInternalApi.getSubscriptionFromId(baseSubscription.getId(), internalCallContext);
 
         assertEquals(dryRunBaseSubscription.getActiveVersion(), SubscriptionEvents.INITIAL_VERSION);
         assertEquals(dryRunBaseSubscription.getBundleId(), bundle.getId());
@@ -525,7 +525,7 @@ public class TestRepairBP extends SubscriptionTestSuiteWithEmbeddedDB {
         // SECOND RE-ISSUE CALL-- NON DRY RUN
         dryRun = false;
         testListener.pushExpectedEvent(NextEvent.REPAIR_BUNDLE);
-        final BundleTimeline realRunBundleRepair = repairApi.repairBundle(bRepair, dryRun, callContext);
+        final BundleBaseTimeline realRunBundleRepair = repairApi.repairBundle(bRepair, dryRun, callContext);
         assertTrue(testListener.isCompleted(5000));
 
         subscriptionRepair = realRunBundleRepair.getSubscriptions();
@@ -539,7 +539,7 @@ public class TestRepairBP extends SubscriptionTestSuiteWithEmbeddedDB {
         for (final ExistingEvent e : expectedEvents) {
             testUtil.validateExistingEventForAssertion(e, events.get(index++));
         }
-        final SubscriptionData realRunBaseSubscription = (SubscriptionData) subscriptionInternalApi.getSubscriptionFromId(baseSubscription.getId(), internalCallContext);
+        final DefaultSubscriptionBase realRunBaseSubscription = (DefaultSubscriptionBase) subscriptionInternalApi.getSubscriptionFromId(baseSubscription.getId(), internalCallContext);
         assertEquals(realRunBaseSubscription.getAllTransitions().size(), expectedTransitions);
 
         assertEquals(realRunBaseSubscription.getActiveVersion(), SubscriptionEvents.INITIAL_VERSION + 1);
@@ -592,19 +592,19 @@ public class TestRepairBP extends SubscriptionTestSuiteWithEmbeddedDB {
         assertEquals(currentPlan.getBillingPeriod(), BillingPeriod.MONTHLY);
 
         final DateTime repairTime = clock.getUTCNow().minusDays(1);
-        final BundleTimeline bundleRepair = repairApi.getBundleTimeline(bundle.getId(), callContext);
+        final BundleBaseTimeline bundleRepair = repairApi.getBundleTimeline(bundle.getId(), callContext);
         testUtil.sortEventsOnBundle(bundleRepair);
 
         final PlanPhaseSpecifier spec = new PlanPhaseSpecifier("Assault-Rifle", ProductCategory.BASE, BillingPeriod.MONTHLY, PriceListSet.DEFAULT_PRICELIST_NAME, PhaseType.EVERGREEN);
 
         final NewEvent ne = testUtil.createNewEvent(SubscriptionBaseTransitionType.CHANGE, repairTime, spec);
-        final List<DeletedEvent> des = new LinkedList<SubscriptionTimeline.DeletedEvent>();
+        final List<DeletedEvent> des = new LinkedList<SubscriptionBaseTimeline.DeletedEvent>();
         des.add(testUtil.createDeletedEvent(bundleRepair.getSubscriptions().get(0).getExistingEvents().get(2).getEventId()));
 
-        final SubscriptionTimeline sRepair = testUtil.createSubscriptionRepair(baseSubscription.getId(), des, Collections.singletonList(ne));
+        final SubscriptionBaseTimeline sRepair = testUtil.createSubscriptionRepair(baseSubscription.getId(), des, Collections.singletonList(ne));
 
         // SKIP DRY RUN AND DO REPAIR...
-        final BundleTimeline bRepair = testUtil.createBundleRepair(bundle.getId(), bundleRepair.getViewId(), Collections.singletonList(sRepair));
+        final BundleBaseTimeline bRepair = testUtil.createBundleRepair(bundle.getId(), bundleRepair.getViewId(), Collections.singletonList(sRepair));
 
         final boolean dryRun = false;
         testListener.pushExpectedEvent(NextEvent.REPAIR_BUNDLE);
@@ -613,7 +613,7 @@ public class TestRepairBP extends SubscriptionTestSuiteWithEmbeddedDB {
 
         baseSubscription = subscriptionInternalApi.getSubscriptionFromId(baseSubscription.getId(), internalCallContext);
 
-        assertEquals(((SubscriptionData) baseSubscription).getActiveVersion(), SubscriptionEvents.INITIAL_VERSION + 1);
+        assertEquals(((DefaultSubscriptionBase) baseSubscription).getActiveVersion(), SubscriptionEvents.INITIAL_VERSION + 1);
         assertEquals(baseSubscription.getBundleId(), bundle.getId());
         assertEquals(baseSubscription.getStartDate(), baseSubscription.getStartDate());
 
@@ -640,18 +640,18 @@ public class TestRepairBP extends SubscriptionTestSuiteWithEmbeddedDB {
 
         test.withException(new TestWithExceptionCallback() {
             @Override
-            public void doTest() throws SubscriptionRepairException, SubscriptionBaseApiException {
+            public void doTest() throws SubscriptionBaseRepairException, SubscriptionBaseApiException {
 
-                final BundleTimeline bundleRepair = repairApi.getBundleTimeline(bundle.getId(), callContext);
+                final BundleBaseTimeline bundleRepair = repairApi.getBundleTimeline(bundle.getId(), callContext);
                 testUtil.sortEventsOnBundle(bundleRepair);
                 final PlanPhaseSpecifier spec = new PlanPhaseSpecifier("Assault-Rifle", ProductCategory.BASE, BillingPeriod.MONTHLY, PriceListSet.DEFAULT_PRICELIST_NAME, PhaseType.EVERGREEN);
                 final NewEvent ne = testUtil.createNewEvent(SubscriptionBaseTransitionType.CHANGE, baseSubscription.getStartDate().plusDays(10), spec);
-                final List<DeletedEvent> des = new LinkedList<SubscriptionTimeline.DeletedEvent>();
+                final List<DeletedEvent> des = new LinkedList<SubscriptionBaseTimeline.DeletedEvent>();
                 des.add(testUtil.createDeletedEvent(bundleRepair.getSubscriptions().get(0).getExistingEvents().get(0).getEventId()));
                 des.add(testUtil.createDeletedEvent(bundleRepair.getSubscriptions().get(0).getExistingEvents().get(1).getEventId()));
-                final SubscriptionTimeline sRepair = testUtil.createSubscriptionRepair(baseSubscription.getId(), des, Collections.singletonList(ne));
+                final SubscriptionBaseTimeline sRepair = testUtil.createSubscriptionRepair(baseSubscription.getId(), des, Collections.singletonList(ne));
 
-                final BundleTimeline bRepair = testUtil.createBundleRepair(bundle.getId(), bundleRepair.getViewId(), Collections.singletonList(sRepair));
+                final BundleBaseTimeline bRepair = testUtil.createBundleRepair(bundle.getId(), bundleRepair.getViewId(), Collections.singletonList(sRepair));
 
                 testListener.pushExpectedEvent(NextEvent.CHANGE);
                 final DateTime changeTime = clock.getUTCNow();
@@ -673,18 +673,18 @@ public class TestRepairBP extends SubscriptionTestSuiteWithEmbeddedDB {
 
         test.withException(new TestWithExceptionCallback() {
             @Override
-            public void doTest() throws SubscriptionRepairException, SubscriptionBaseApiException {
+            public void doTest() throws SubscriptionBaseRepairException, SubscriptionBaseApiException {
 
-                final BundleTimeline bundleRepair = repairApi.getBundleTimeline(bundle.getId(), callContext);
+                final BundleBaseTimeline bundleRepair = repairApi.getBundleTimeline(bundle.getId(), callContext);
                 testUtil.sortEventsOnBundle(bundleRepair);
                 final PlanPhaseSpecifier spec = new PlanPhaseSpecifier("Assault-Rifle", ProductCategory.BASE, BillingPeriod.MONTHLY, PriceListSet.DEFAULT_PRICELIST_NAME, PhaseType.EVERGREEN);
                 final NewEvent ne = testUtil.createNewEvent(SubscriptionBaseTransitionType.CHANGE, baseSubscription.getStartDate().plusDays(10), spec);
-                final List<DeletedEvent> des = new LinkedList<SubscriptionTimeline.DeletedEvent>();
+                final List<DeletedEvent> des = new LinkedList<SubscriptionBaseTimeline.DeletedEvent>();
                 des.add(testUtil.createDeletedEvent(bundleRepair.getSubscriptions().get(0).getExistingEvents().get(0).getEventId()));
                 des.add(testUtil.createDeletedEvent(bundleRepair.getSubscriptions().get(0).getExistingEvents().get(1).getEventId()));
-                final SubscriptionTimeline sRepair = testUtil.createSubscriptionRepair(baseSubscription.getId(), des, Collections.singletonList(ne));
+                final SubscriptionBaseTimeline sRepair = testUtil.createSubscriptionRepair(baseSubscription.getId(), des, Collections.singletonList(ne));
 
-                final BundleTimeline bRepair = testUtil.createBundleRepair(bundle.getId(), bundleRepair.getViewId(), Collections.singletonList(sRepair));
+                final BundleBaseTimeline bRepair = testUtil.createBundleRepair(bundle.getId(), bundleRepair.getViewId(), Collections.singletonList(sRepair));
 
                 final DateTime newChargedThroughDate = baseSubscription.getStartDate().plusDays(30).plusMonths(1);
 
diff --git a/subscription/src/test/java/com/ning/billing/subscription/api/timeline/TestRepairWithAO.java b/subscription/src/test/java/com/ning/billing/subscription/api/timeline/TestRepairWithAO.java
index 417b0eb..d66a27b 100644
--- a/subscription/src/test/java/com/ning/billing/subscription/api/timeline/TestRepairWithAO.java
+++ b/subscription/src/test/java/com/ning/billing/subscription/api/timeline/TestRepairWithAO.java
@@ -34,11 +34,11 @@ import com.ning.billing.catalog.api.PriceListSet;
 import com.ning.billing.catalog.api.ProductCategory;
 import com.ning.billing.subscription.SubscriptionTestSuiteWithEmbeddedDB;
 import com.ning.billing.subscription.api.SubscriptionBaseTransitionType;
-import com.ning.billing.subscription.api.user.SubscriptionData;
+import com.ning.billing.subscription.api.user.DefaultSubscriptionBase;
 import com.ning.billing.subscription.api.user.SubscriptionEvents;
-import com.ning.billing.subscription.api.timeline.SubscriptionTimeline.DeletedEvent;
-import com.ning.billing.subscription.api.timeline.SubscriptionTimeline.ExistingEvent;
-import com.ning.billing.subscription.api.timeline.SubscriptionTimeline.NewEvent;
+import com.ning.billing.subscription.api.timeline.SubscriptionBaseTimeline.DeletedEvent;
+import com.ning.billing.subscription.api.timeline.SubscriptionBaseTimeline.ExistingEvent;
+import com.ning.billing.subscription.api.timeline.SubscriptionBaseTimeline.NewEvent;
 import com.ning.billing.subscription.api.user.SubscriptionState;
 
 import static org.testng.Assert.assertEquals;
@@ -55,36 +55,36 @@ public class TestRepairWithAO extends SubscriptionTestSuiteWithEmbeddedDB {
         final String basePriceList = PriceListSet.DEFAULT_PRICELIST_NAME;
 
         // CREATE BP
-        final SubscriptionData baseSubscription = testUtil.createSubscription(bundle, baseProduct, baseTerm, basePriceList);
+        final DefaultSubscriptionBase baseSubscription = testUtil.createSubscription(bundle, baseProduct, baseTerm, basePriceList);
 
         // MOVE CLOCK A LITTLE BIT-- STILL IN TRIAL
         Interval it = new Interval(clock.getUTCNow(), clock.getUTCNow().plusDays(4));
         clock.addDeltaFromReality(it.toDurationMillis());
 
-        final SubscriptionData aoSubscription = testUtil.createSubscription(bundle, "Telescopic-Scope", BillingPeriod.MONTHLY, PriceListSet.DEFAULT_PRICELIST_NAME);
+        final DefaultSubscriptionBase aoSubscription = testUtil.createSubscription(bundle, "Telescopic-Scope", BillingPeriod.MONTHLY, PriceListSet.DEFAULT_PRICELIST_NAME);
 
-        final SubscriptionData aoSubscription2 = testUtil.createSubscription(bundle, "Laser-Scope", BillingPeriod.MONTHLY, PriceListSet.DEFAULT_PRICELIST_NAME);
+        final DefaultSubscriptionBase aoSubscription2 = testUtil.createSubscription(bundle, "Laser-Scope", BillingPeriod.MONTHLY, PriceListSet.DEFAULT_PRICELIST_NAME);
 
         // MOVE CLOCK A LITTLE BIT MORE -- STILL IN TRIAL
         it = new Interval(clock.getUTCNow(), clock.getUTCNow().plusDays(3));
         clock.addDeltaFromReality(it.toDurationMillis());
 
-        BundleTimeline bundleRepair = repairApi.getBundleTimeline(bundle.getId(), callContext);
+        BundleBaseTimeline bundleRepair = repairApi.getBundleTimeline(bundle.getId(), callContext);
         testUtil.sortEventsOnBundle(bundleRepair);
 
         // Quick check
-        SubscriptionTimeline bpRepair = testUtil.getSubscriptionRepair(baseSubscription.getId(), bundleRepair);
+        SubscriptionBaseTimeline bpRepair = testUtil.getSubscriptionRepair(baseSubscription.getId(), bundleRepair);
         assertEquals(bpRepair.getExistingEvents().size(), 2);
 
-        SubscriptionTimeline aoRepair = testUtil.getSubscriptionRepair(aoSubscription.getId(), bundleRepair);
+        SubscriptionBaseTimeline aoRepair = testUtil.getSubscriptionRepair(aoSubscription.getId(), bundleRepair);
         assertEquals(aoRepair.getExistingEvents().size(), 2);
 
-        SubscriptionTimeline aoRepair2 = testUtil.getSubscriptionRepair(aoSubscription2.getId(), bundleRepair);
+        SubscriptionBaseTimeline aoRepair2 = testUtil.getSubscriptionRepair(aoSubscription2.getId(), bundleRepair);
         assertEquals(aoRepair2.getExistingEvents().size(), 2);
 
         final DateTime bpChangeDate = clock.getUTCNow().minusDays(1);
 
-        final List<DeletedEvent> des = new LinkedList<SubscriptionTimeline.DeletedEvent>();
+        final List<DeletedEvent> des = new LinkedList<SubscriptionBaseTimeline.DeletedEvent>();
         des.add(testUtil.createDeletedEvent(bpRepair.getExistingEvents().get(1).getEventId()));
 
         final PlanPhaseSpecifier spec = new PlanPhaseSpecifier("Assault-Rifle", ProductCategory.BASE, BillingPeriod.MONTHLY, PriceListSet.DEFAULT_PRICELIST_NAME, PhaseType.TRIAL);
@@ -95,7 +95,7 @@ public class TestRepairWithAO extends SubscriptionTestSuiteWithEmbeddedDB {
         bundleRepair = testUtil.createBundleRepair(bundle.getId(), bundleRepair.getViewId(), Collections.singletonList(bpRepair));
 
         boolean dryRun = true;
-        final BundleTimeline dryRunBundleRepair = repairApi.repairBundle(bundleRepair, dryRun, callContext);
+        final BundleBaseTimeline dryRunBundleRepair = repairApi.repairBundle(bundleRepair, dryRun, callContext);
 
         aoRepair = testUtil.getSubscriptionRepair(aoSubscription.getId(), dryRunBundleRepair);
         assertEquals(aoRepair.getExistingEvents().size(), 2);
@@ -107,7 +107,7 @@ public class TestRepairWithAO extends SubscriptionTestSuiteWithEmbeddedDB {
         assertEquals(bpRepair.getExistingEvents().size(), 3);
 
         // Check expected for AO
-        final List<ExistingEvent> expectedAO = new LinkedList<SubscriptionTimeline.ExistingEvent>();
+        final List<ExistingEvent> expectedAO = new LinkedList<SubscriptionBaseTimeline.ExistingEvent>();
         expectedAO.add(testUtil.createExistingEventForAssertion(SubscriptionBaseTransitionType.CREATE, "Telescopic-Scope", PhaseType.DISCOUNT,
                                                                 ProductCategory.ADD_ON, PriceListSet.DEFAULT_PRICELIST_NAME, BillingPeriod.MONTHLY, aoSubscription.getStartDate()));
         expectedAO.add(testUtil.createExistingEventForAssertion(SubscriptionBaseTransitionType.CANCEL, "Telescopic-Scope", PhaseType.DISCOUNT,
@@ -117,7 +117,7 @@ public class TestRepairWithAO extends SubscriptionTestSuiteWithEmbeddedDB {
             testUtil.validateExistingEventForAssertion(e, aoRepair.getExistingEvents().get(index++));
         }
 
-        final List<ExistingEvent> expectedAO2 = new LinkedList<SubscriptionTimeline.ExistingEvent>();
+        final List<ExistingEvent> expectedAO2 = new LinkedList<SubscriptionBaseTimeline.ExistingEvent>();
         expectedAO2.add(testUtil.createExistingEventForAssertion(SubscriptionBaseTransitionType.CREATE, "Laser-Scope", PhaseType.DISCOUNT,
                                                                  ProductCategory.ADD_ON, PriceListSet.DEFAULT_PRICELIST_NAME, BillingPeriod.MONTHLY, aoSubscription2.getStartDate()));
         expectedAO2.add(testUtil.createExistingEventForAssertion(SubscriptionBaseTransitionType.PHASE, "Laser-Scope", PhaseType.EVERGREEN,
@@ -128,7 +128,7 @@ public class TestRepairWithAO extends SubscriptionTestSuiteWithEmbeddedDB {
         }
 
         // Check expected for BP
-        final List<ExistingEvent> expectedBP = new LinkedList<SubscriptionTimeline.ExistingEvent>();
+        final List<ExistingEvent> expectedBP = new LinkedList<SubscriptionBaseTimeline.ExistingEvent>();
         expectedBP.add(testUtil.createExistingEventForAssertion(SubscriptionBaseTransitionType.CREATE, "Shotgun", PhaseType.TRIAL,
                                                                 ProductCategory.BASE, PriceListSet.DEFAULT_PRICELIST_NAME, BillingPeriod.NO_BILLING_PERIOD, baseSubscription.getStartDate()));
         expectedBP.add(testUtil.createExistingEventForAssertion(SubscriptionBaseTransitionType.CHANGE, "Assault-Rifle", PhaseType.TRIAL,
@@ -140,24 +140,24 @@ public class TestRepairWithAO extends SubscriptionTestSuiteWithEmbeddedDB {
             testUtil.validateExistingEventForAssertion(e, bpRepair.getExistingEvents().get(index++));
         }
 
-        SubscriptionData newAoSubscription = (SubscriptionData) subscriptionInternalApi.getSubscriptionFromId(aoSubscription.getId(), internalCallContext);
+        DefaultSubscriptionBase newAoSubscription = (DefaultSubscriptionBase) subscriptionInternalApi.getSubscriptionFromId(aoSubscription.getId(), internalCallContext);
         assertEquals(newAoSubscription.getState(), SubscriptionState.ACTIVE);
         assertEquals(newAoSubscription.getAllTransitions().size(), 2);
         assertEquals(newAoSubscription.getActiveVersion(), SubscriptionEvents.INITIAL_VERSION);
 
-        SubscriptionData newAoSubscription2 = (SubscriptionData) subscriptionInternalApi.getSubscriptionFromId(aoSubscription2.getId(), internalCallContext);
+        DefaultSubscriptionBase newAoSubscription2 = (DefaultSubscriptionBase) subscriptionInternalApi.getSubscriptionFromId(aoSubscription2.getId(), internalCallContext);
         assertEquals(newAoSubscription2.getState(), SubscriptionState.ACTIVE);
         assertEquals(newAoSubscription2.getAllTransitions().size(), 2);
         assertEquals(newAoSubscription2.getActiveVersion(), SubscriptionEvents.INITIAL_VERSION);
 
-        SubscriptionData newBaseSubscription = (SubscriptionData) subscriptionInternalApi.getSubscriptionFromId(baseSubscription.getId(), internalCallContext);
+        DefaultSubscriptionBase newBaseSubscription = (DefaultSubscriptionBase) subscriptionInternalApi.getSubscriptionFromId(baseSubscription.getId(), internalCallContext);
         assertEquals(newBaseSubscription.getState(), SubscriptionState.ACTIVE);
         assertEquals(newBaseSubscription.getAllTransitions().size(), 2);
         assertEquals(newBaseSubscription.getActiveVersion(), SubscriptionEvents.INITIAL_VERSION);
 
         dryRun = false;
         testListener.pushExpectedEvent(NextEvent.REPAIR_BUNDLE);
-        final BundleTimeline realRunBundleRepair = repairApi.repairBundle(bundleRepair, dryRun, callContext);
+        final BundleBaseTimeline realRunBundleRepair = repairApi.repairBundle(bundleRepair, dryRun, callContext);
         assertTrue(testListener.isCompleted(5000));
 
         aoRepair = testUtil.getSubscriptionRepair(aoSubscription.getId(), realRunBundleRepair);
@@ -181,17 +181,17 @@ public class TestRepairWithAO extends SubscriptionTestSuiteWithEmbeddedDB {
             testUtil.validateExistingEventForAssertion(e, bpRepair.getExistingEvents().get(index++));
         }
 
-        newAoSubscription = (SubscriptionData) subscriptionInternalApi.getSubscriptionFromId(aoSubscription.getId(), internalCallContext);
+        newAoSubscription = (DefaultSubscriptionBase) subscriptionInternalApi.getSubscriptionFromId(aoSubscription.getId(), internalCallContext);
         assertEquals(newAoSubscription.getState(), SubscriptionState.CANCELLED);
         assertEquals(newAoSubscription.getAllTransitions().size(), 2);
         assertEquals(newAoSubscription.getActiveVersion(), SubscriptionEvents.INITIAL_VERSION + 1);
 
-        newAoSubscription2 = (SubscriptionData) subscriptionInternalApi.getSubscriptionFromId(aoSubscription2.getId(), internalCallContext);
+        newAoSubscription2 = (DefaultSubscriptionBase) subscriptionInternalApi.getSubscriptionFromId(aoSubscription2.getId(), internalCallContext);
         assertEquals(newAoSubscription2.getState(), SubscriptionState.ACTIVE);
         assertEquals(newAoSubscription2.getAllTransitions().size(), 2);
         assertEquals(newAoSubscription2.getActiveVersion(), SubscriptionEvents.INITIAL_VERSION + 1);
 
-        newBaseSubscription = (SubscriptionData) subscriptionInternalApi.getSubscriptionFromId(baseSubscription.getId(), internalCallContext);
+        newBaseSubscription = (DefaultSubscriptionBase) subscriptionInternalApi.getSubscriptionFromId(baseSubscription.getId(), internalCallContext);
         assertEquals(newBaseSubscription.getState(), SubscriptionState.ACTIVE);
         assertEquals(newBaseSubscription.getAllTransitions().size(), 3);
         assertEquals(newBaseSubscription.getActiveVersion(), SubscriptionEvents.INITIAL_VERSION + 1);
@@ -204,13 +204,13 @@ public class TestRepairWithAO extends SubscriptionTestSuiteWithEmbeddedDB {
         final String basePriceList = PriceListSet.DEFAULT_PRICELIST_NAME;
 
         // CREATE BP
-        final SubscriptionData baseSubscription = testUtil.createSubscription(bundle, baseProduct, baseTerm, basePriceList);
+        final DefaultSubscriptionBase baseSubscription = testUtil.createSubscription(bundle, baseProduct, baseTerm, basePriceList);
 
         // MOVE CLOCK A LITTLE BIT-- STILL IN TRIAL
         Interval it = new Interval(clock.getUTCNow(), clock.getUTCNow().plusDays(3));
         clock.addDeltaFromReality(it.toDurationMillis());
 
-        final SubscriptionData aoSubscription = testUtil.createSubscription(bundle, "Telescopic-Scope", BillingPeriod.MONTHLY, PriceListSet.DEFAULT_PRICELIST_NAME);
+        final DefaultSubscriptionBase aoSubscription = testUtil.createSubscription(bundle, "Telescopic-Scope", BillingPeriod.MONTHLY, PriceListSet.DEFAULT_PRICELIST_NAME);
 
         // MOVE CLOCK A LITTLE BIT MORE -- AFTER TRIAL
         testListener.pushExpectedEvent(NextEvent.PHASE);
@@ -220,14 +220,14 @@ public class TestRepairWithAO extends SubscriptionTestSuiteWithEmbeddedDB {
         clock.addDeltaFromReality(it.toDurationMillis());
         assertTrue(testListener.isCompleted(7000));
 
-        BundleTimeline bundleRepair = repairApi.getBundleTimeline(bundle.getId(), callContext);
+        BundleBaseTimeline bundleRepair = repairApi.getBundleTimeline(bundle.getId(), callContext);
         testUtil.sortEventsOnBundle(bundleRepair);
 
         // Quick check
-        SubscriptionTimeline bpRepair = testUtil.getSubscriptionRepair(baseSubscription.getId(), bundleRepair);
+        SubscriptionBaseTimeline bpRepair = testUtil.getSubscriptionRepair(baseSubscription.getId(), bundleRepair);
         assertEquals(bpRepair.getExistingEvents().size(), 2);
 
-        SubscriptionTimeline aoRepair = testUtil.getSubscriptionRepair(aoSubscription.getId(), bundleRepair);
+        SubscriptionBaseTimeline aoRepair = testUtil.getSubscriptionRepair(aoSubscription.getId(), bundleRepair);
         assertEquals(aoRepair.getExistingEvents().size(), 2);
 
         final DateTime bpChangeDate = clock.getUTCNow().minusDays(1);
@@ -235,12 +235,12 @@ public class TestRepairWithAO extends SubscriptionTestSuiteWithEmbeddedDB {
         final PlanPhaseSpecifier spec = new PlanPhaseSpecifier("Pistol", ProductCategory.BASE, BillingPeriod.MONTHLY, PriceListSet.DEFAULT_PRICELIST_NAME, PhaseType.EVERGREEN);
         final NewEvent ne = testUtil.createNewEvent(SubscriptionBaseTransitionType.CHANGE, bpChangeDate, spec);
 
-        bpRepair = testUtil.createSubscriptionRepair(baseSubscription.getId(), Collections.<SubscriptionTimeline.DeletedEvent>emptyList(), Collections.singletonList(ne));
+        bpRepair = testUtil.createSubscriptionRepair(baseSubscription.getId(), Collections.<SubscriptionBaseTimeline.DeletedEvent>emptyList(), Collections.singletonList(ne));
 
         bundleRepair = testUtil.createBundleRepair(bundle.getId(), bundleRepair.getViewId(), Collections.singletonList(bpRepair));
 
         boolean dryRun = true;
-        final BundleTimeline dryRunBundleRepair = repairApi.repairBundle(bundleRepair, dryRun, callContext);
+        final BundleBaseTimeline dryRunBundleRepair = repairApi.repairBundle(bundleRepair, dryRun, callContext);
 
         aoRepair = testUtil.getSubscriptionRepair(aoSubscription.getId(), dryRunBundleRepair);
         assertEquals(aoRepair.getExistingEvents().size(), 3);
@@ -249,7 +249,7 @@ public class TestRepairWithAO extends SubscriptionTestSuiteWithEmbeddedDB {
         assertEquals(bpRepair.getExistingEvents().size(), 3);
 
         // Check expected for AO
-        final List<ExistingEvent> expectedAO = new LinkedList<SubscriptionTimeline.ExistingEvent>();
+        final List<ExistingEvent> expectedAO = new LinkedList<SubscriptionBaseTimeline.ExistingEvent>();
         expectedAO.add(testUtil.createExistingEventForAssertion(SubscriptionBaseTransitionType.CREATE, "Telescopic-Scope", PhaseType.DISCOUNT,
                                                                 ProductCategory.ADD_ON, PriceListSet.DEFAULT_PRICELIST_NAME, BillingPeriod.MONTHLY, aoSubscription.getStartDate()));
         expectedAO.add(testUtil.createExistingEventForAssertion(SubscriptionBaseTransitionType.CREATE, "Telescopic-Scope", PhaseType.EVERGREEN,
@@ -262,7 +262,7 @@ public class TestRepairWithAO extends SubscriptionTestSuiteWithEmbeddedDB {
         }
 
         // Check expected for BP
-        final List<ExistingEvent> expectedBP = new LinkedList<SubscriptionTimeline.ExistingEvent>();
+        final List<ExistingEvent> expectedBP = new LinkedList<SubscriptionBaseTimeline.ExistingEvent>();
         expectedBP.add(testUtil.createExistingEventForAssertion(SubscriptionBaseTransitionType.CREATE, "Shotgun", PhaseType.TRIAL,
                                                                 ProductCategory.BASE, PriceListSet.DEFAULT_PRICELIST_NAME, BillingPeriod.NO_BILLING_PERIOD, baseSubscription.getStartDate()));
         expectedBP.add(testUtil.createExistingEventForAssertion(SubscriptionBaseTransitionType.PHASE, "Shotgun", PhaseType.EVERGREEN,
@@ -274,19 +274,19 @@ public class TestRepairWithAO extends SubscriptionTestSuiteWithEmbeddedDB {
             testUtil.validateExistingEventForAssertion(e, bpRepair.getExistingEvents().get(index++));
         }
 
-        SubscriptionData newAoSubscription = (SubscriptionData) subscriptionInternalApi.getSubscriptionFromId(aoSubscription.getId(), internalCallContext);
+        DefaultSubscriptionBase newAoSubscription = (DefaultSubscriptionBase) subscriptionInternalApi.getSubscriptionFromId(aoSubscription.getId(), internalCallContext);
         assertEquals(newAoSubscription.getState(), SubscriptionState.ACTIVE);
         assertEquals(newAoSubscription.getAllTransitions().size(), 2);
         assertEquals(newAoSubscription.getActiveVersion(), SubscriptionEvents.INITIAL_VERSION);
 
-        SubscriptionData newBaseSubscription = (SubscriptionData) subscriptionInternalApi.getSubscriptionFromId(baseSubscription.getId(), internalCallContext);
+        DefaultSubscriptionBase newBaseSubscription = (DefaultSubscriptionBase) subscriptionInternalApi.getSubscriptionFromId(baseSubscription.getId(), internalCallContext);
         assertEquals(newBaseSubscription.getState(), SubscriptionState.ACTIVE);
         assertEquals(newBaseSubscription.getAllTransitions().size(), 2);
         assertEquals(newBaseSubscription.getActiveVersion(), SubscriptionEvents.INITIAL_VERSION);
 
         dryRun = false;
         testListener.pushExpectedEvent(NextEvent.REPAIR_BUNDLE);
-        final BundleTimeline realRunBundleRepair = repairApi.repairBundle(bundleRepair, dryRun, callContext);
+        final BundleBaseTimeline realRunBundleRepair = repairApi.repairBundle(bundleRepair, dryRun, callContext);
         assertTrue(testListener.isCompleted(5000));
 
         aoRepair = testUtil.getSubscriptionRepair(aoSubscription.getId(), realRunBundleRepair);
@@ -305,12 +305,12 @@ public class TestRepairWithAO extends SubscriptionTestSuiteWithEmbeddedDB {
             testUtil.validateExistingEventForAssertion(e, bpRepair.getExistingEvents().get(index++));
         }
 
-        newAoSubscription = (SubscriptionData) subscriptionInternalApi.getSubscriptionFromId(aoSubscription.getId(), internalCallContext);
+        newAoSubscription = (DefaultSubscriptionBase) subscriptionInternalApi.getSubscriptionFromId(aoSubscription.getId(), internalCallContext);
         assertEquals(newAoSubscription.getState(), SubscriptionState.CANCELLED);
         assertEquals(newAoSubscription.getAllTransitions().size(), 3);
         assertEquals(newAoSubscription.getActiveVersion(), SubscriptionEvents.INITIAL_VERSION + 1);
 
-        newBaseSubscription = (SubscriptionData) subscriptionInternalApi.getSubscriptionFromId(baseSubscription.getId(), internalCallContext);
+        newBaseSubscription = (DefaultSubscriptionBase) subscriptionInternalApi.getSubscriptionFromId(baseSubscription.getId(), internalCallContext);
         assertEquals(newBaseSubscription.getState(), SubscriptionState.ACTIVE);
         assertEquals(newBaseSubscription.getAllTransitions().size(), 3);
         assertEquals(newBaseSubscription.getActiveVersion(), SubscriptionEvents.INITIAL_VERSION + 1);
@@ -323,13 +323,13 @@ public class TestRepairWithAO extends SubscriptionTestSuiteWithEmbeddedDB {
         final String basePriceList = PriceListSet.DEFAULT_PRICELIST_NAME;
 
         // CREATE BP
-        SubscriptionData baseSubscription = testUtil.createSubscription(bundle, baseProduct, baseTerm, basePriceList);
+        DefaultSubscriptionBase baseSubscription = testUtil.createSubscription(bundle, baseProduct, baseTerm, basePriceList);
 
         // MOVE CLOCK A LITTLE BIT-- STILL IN TRIAL
         Interval it = new Interval(clock.getUTCNow(), clock.getUTCNow().plusDays(4));
         clock.addDeltaFromReality(it.toDurationMillis());
 
-        final SubscriptionData aoSubscription = testUtil.createSubscription(bundle, "Telescopic-Scope", BillingPeriod.MONTHLY, PriceListSet.DEFAULT_PRICELIST_NAME);
+        final DefaultSubscriptionBase aoSubscription = testUtil.createSubscription(bundle, "Telescopic-Scope", BillingPeriod.MONTHLY, PriceListSet.DEFAULT_PRICELIST_NAME);
 
         // MOVE CLOCK A LITTLE BIT MORE -- AFTER TRIAL
         testListener.pushExpectedEvent(NextEvent.PHASE);
@@ -342,25 +342,25 @@ public class TestRepairWithAO extends SubscriptionTestSuiteWithEmbeddedDB {
         // SET CTD to BASE SUBSCRIPTION SP CANCEL OCCURS EOT
         final DateTime newChargedThroughDate = baseSubscription.getStartDate().plusDays(30).plusMonths(1);
         subscriptionInternalApi.setChargedThroughDate(baseSubscription.getId(), newChargedThroughDate, internalCallContext);
-        baseSubscription = (SubscriptionData) subscriptionInternalApi.getSubscriptionFromId(baseSubscription.getId(), internalCallContext);
+        baseSubscription = (DefaultSubscriptionBase) subscriptionInternalApi.getSubscriptionFromId(baseSubscription.getId(), internalCallContext);
 
-        BundleTimeline bundleRepair = repairApi.getBundleTimeline(bundle.getId(), callContext);
+        BundleBaseTimeline bundleRepair = repairApi.getBundleTimeline(bundle.getId(), callContext);
         testUtil.sortEventsOnBundle(bundleRepair);
 
         // Quick check
-        SubscriptionTimeline bpRepair = testUtil.getSubscriptionRepair(baseSubscription.getId(), bundleRepair);
+        SubscriptionBaseTimeline bpRepair = testUtil.getSubscriptionRepair(baseSubscription.getId(), bundleRepair);
         assertEquals(bpRepair.getExistingEvents().size(), 2);
 
-        SubscriptionTimeline aoRepair = testUtil.getSubscriptionRepair(aoSubscription.getId(), bundleRepair);
+        SubscriptionBaseTimeline aoRepair = testUtil.getSubscriptionRepair(aoSubscription.getId(), bundleRepair);
         assertEquals(aoRepair.getExistingEvents().size(), 2);
 
         final DateTime bpCancelDate = clock.getUTCNow().minusDays(1);
         final NewEvent ne = testUtil.createNewEvent(SubscriptionBaseTransitionType.CANCEL, bpCancelDate, null);
-        bpRepair = testUtil.createSubscriptionRepair(baseSubscription.getId(), Collections.<SubscriptionTimeline.DeletedEvent>emptyList(), Collections.singletonList(ne));
+        bpRepair = testUtil.createSubscriptionRepair(baseSubscription.getId(), Collections.<SubscriptionBaseTimeline.DeletedEvent>emptyList(), Collections.singletonList(ne));
         bundleRepair = testUtil.createBundleRepair(bundle.getId(), bundleRepair.getViewId(), Collections.singletonList(bpRepair));
 
         boolean dryRun = true;
-        final BundleTimeline dryRunBundleRepair = repairApi.repairBundle(bundleRepair, dryRun, callContext);
+        final BundleBaseTimeline dryRunBundleRepair = repairApi.repairBundle(bundleRepair, dryRun, callContext);
 
         aoRepair = testUtil.getSubscriptionRepair(aoSubscription.getId(), dryRunBundleRepair);
         assertEquals(aoRepair.getExistingEvents().size(), 3);
@@ -369,7 +369,7 @@ public class TestRepairWithAO extends SubscriptionTestSuiteWithEmbeddedDB {
         assertEquals(bpRepair.getExistingEvents().size(), 3);
 
         // Check expected for AO
-        final List<ExistingEvent> expectedAO = new LinkedList<SubscriptionTimeline.ExistingEvent>();
+        final List<ExistingEvent> expectedAO = new LinkedList<SubscriptionBaseTimeline.ExistingEvent>();
         expectedAO.add(testUtil.createExistingEventForAssertion(SubscriptionBaseTransitionType.CREATE, "Telescopic-Scope", PhaseType.DISCOUNT,
                                                                 ProductCategory.ADD_ON, PriceListSet.DEFAULT_PRICELIST_NAME, BillingPeriod.MONTHLY, aoSubscription.getStartDate()));
         expectedAO.add(testUtil.createExistingEventForAssertion(SubscriptionBaseTransitionType.PHASE, "Telescopic-Scope", PhaseType.EVERGREEN,
@@ -383,7 +383,7 @@ public class TestRepairWithAO extends SubscriptionTestSuiteWithEmbeddedDB {
         }
 
         // Check expected for BP
-        final List<ExistingEvent> expectedBP = new LinkedList<SubscriptionTimeline.ExistingEvent>();
+        final List<ExistingEvent> expectedBP = new LinkedList<SubscriptionBaseTimeline.ExistingEvent>();
         expectedBP.add(testUtil.createExistingEventForAssertion(SubscriptionBaseTransitionType.CREATE, "Shotgun", PhaseType.TRIAL,
                                                                 ProductCategory.BASE, PriceListSet.DEFAULT_PRICELIST_NAME, BillingPeriod.NO_BILLING_PERIOD, baseSubscription.getStartDate()));
         expectedBP.add(testUtil.createExistingEventForAssertion(SubscriptionBaseTransitionType.PHASE, "Shotgun", PhaseType.EVERGREEN,
@@ -395,19 +395,19 @@ public class TestRepairWithAO extends SubscriptionTestSuiteWithEmbeddedDB {
             testUtil.validateExistingEventForAssertion(e, bpRepair.getExistingEvents().get(index++));
         }
 
-        SubscriptionData newAoSubscription = (SubscriptionData) subscriptionInternalApi.getSubscriptionFromId(aoSubscription.getId(), internalCallContext);
+        DefaultSubscriptionBase newAoSubscription = (DefaultSubscriptionBase) subscriptionInternalApi.getSubscriptionFromId(aoSubscription.getId(), internalCallContext);
         assertEquals(newAoSubscription.getState(), SubscriptionState.ACTIVE);
         assertEquals(newAoSubscription.getAllTransitions().size(), 2);
         assertEquals(newAoSubscription.getActiveVersion(), SubscriptionEvents.INITIAL_VERSION);
 
-        SubscriptionData newBaseSubscription = (SubscriptionData) subscriptionInternalApi.getSubscriptionFromId(baseSubscription.getId(), internalCallContext);
+        DefaultSubscriptionBase newBaseSubscription = (DefaultSubscriptionBase) subscriptionInternalApi.getSubscriptionFromId(baseSubscription.getId(), internalCallContext);
         assertEquals(newBaseSubscription.getState(), SubscriptionState.ACTIVE);
         assertEquals(newBaseSubscription.getAllTransitions().size(), 2);
         assertEquals(newBaseSubscription.getActiveVersion(), SubscriptionEvents.INITIAL_VERSION);
 
         dryRun = false;
         testListener.pushExpectedEvent(NextEvent.REPAIR_BUNDLE);
-        final BundleTimeline realRunBundleRepair = repairApi.repairBundle(bundleRepair, dryRun, callContext);
+        final BundleBaseTimeline realRunBundleRepair = repairApi.repairBundle(bundleRepair, dryRun, callContext);
         assertTrue(testListener.isCompleted(5000));
 
         aoRepair = testUtil.getSubscriptionRepair(aoSubscription.getId(), realRunBundleRepair);
@@ -426,12 +426,12 @@ public class TestRepairWithAO extends SubscriptionTestSuiteWithEmbeddedDB {
             testUtil.validateExistingEventForAssertion(e, bpRepair.getExistingEvents().get(index++));
         }
 
-        newAoSubscription = (SubscriptionData) subscriptionInternalApi.getSubscriptionFromId(aoSubscription.getId(), internalCallContext);
+        newAoSubscription = (DefaultSubscriptionBase) subscriptionInternalApi.getSubscriptionFromId(aoSubscription.getId(), internalCallContext);
         assertEquals(newAoSubscription.getState(), SubscriptionState.ACTIVE);
         assertEquals(newAoSubscription.getAllTransitions().size(), 3);
         assertEquals(newAoSubscription.getActiveVersion(), SubscriptionEvents.INITIAL_VERSION + 1);
 
-        newBaseSubscription = (SubscriptionData) subscriptionInternalApi.getSubscriptionFromId(baseSubscription.getId(), internalCallContext);
+        newBaseSubscription = (DefaultSubscriptionBase) subscriptionInternalApi.getSubscriptionFromId(baseSubscription.getId(), internalCallContext);
         assertEquals(newBaseSubscription.getState(), SubscriptionState.ACTIVE);
         assertEquals(newBaseSubscription.getAllTransitions().size(), 3);
         assertEquals(newBaseSubscription.getActiveVersion(), SubscriptionEvents.INITIAL_VERSION + 1);
@@ -444,12 +444,12 @@ public class TestRepairWithAO extends SubscriptionTestSuiteWithEmbeddedDB {
         clock.addDeltaFromReality(it.toDurationMillis());
         assertTrue(testListener.isCompleted(7000));
 
-        newAoSubscription = (SubscriptionData) subscriptionInternalApi.getSubscriptionFromId(aoSubscription.getId(), internalCallContext);
+        newAoSubscription = (DefaultSubscriptionBase) subscriptionInternalApi.getSubscriptionFromId(aoSubscription.getId(), internalCallContext);
         assertEquals(newAoSubscription.getState(), SubscriptionState.CANCELLED);
         assertEquals(newAoSubscription.getAllTransitions().size(), 3);
         assertEquals(newAoSubscription.getActiveVersion(), SubscriptionEvents.INITIAL_VERSION + 1);
 
-        newBaseSubscription = (SubscriptionData) subscriptionInternalApi.getSubscriptionFromId(baseSubscription.getId(), internalCallContext);
+        newBaseSubscription = (DefaultSubscriptionBase) subscriptionInternalApi.getSubscriptionFromId(baseSubscription.getId(), internalCallContext);
         assertEquals(newBaseSubscription.getState(), SubscriptionState.CANCELLED);
         assertEquals(newBaseSubscription.getAllTransitions().size(), 3);
         assertEquals(newBaseSubscription.getActiveVersion(), SubscriptionEvents.INITIAL_VERSION + 1);
@@ -462,40 +462,40 @@ public class TestRepairWithAO extends SubscriptionTestSuiteWithEmbeddedDB {
         final String basePriceList = PriceListSet.DEFAULT_PRICELIST_NAME;
 
         // CREATE BP
-        final SubscriptionData baseSubscription = testUtil.createSubscription(bundle, baseProduct, baseTerm, basePriceList);
+        final DefaultSubscriptionBase baseSubscription = testUtil.createSubscription(bundle, baseProduct, baseTerm, basePriceList);
 
         // MOVE CLOCK A LITTLE BIT-- STILL IN TRIAL
         Interval it = new Interval(clock.getUTCNow(), clock.getUTCNow().plusDays(4));
         clock.addDeltaFromReality(it.toDurationMillis());
 
-        final SubscriptionData aoSubscription = testUtil.createSubscription(bundle, "Telescopic-Scope", BillingPeriod.MONTHLY, PriceListSet.DEFAULT_PRICELIST_NAME);
+        final DefaultSubscriptionBase aoSubscription = testUtil.createSubscription(bundle, "Telescopic-Scope", BillingPeriod.MONTHLY, PriceListSet.DEFAULT_PRICELIST_NAME);
 
         // MOVE CLOCK A LITTLE BIT MORE -- STILL IN TRIAL
         it = new Interval(clock.getUTCNow(), clock.getUTCNow().plusDays(3));
         clock.addDeltaFromReality(it.toDurationMillis());
 
-        final BundleTimeline bundleRepair = repairApi.getBundleTimeline(bundle.getId(), callContext);
+        final BundleBaseTimeline bundleRepair = repairApi.getBundleTimeline(bundle.getId(), callContext);
         testUtil.sortEventsOnBundle(bundleRepair);
 
         // Quick check
-        SubscriptionTimeline bpRepair = testUtil.getSubscriptionRepair(baseSubscription.getId(), bundleRepair);
+        SubscriptionBaseTimeline bpRepair = testUtil.getSubscriptionRepair(baseSubscription.getId(), bundleRepair);
         assertEquals(bpRepair.getExistingEvents().size(), 2);
 
-        SubscriptionTimeline aoRepair = testUtil.getSubscriptionRepair(aoSubscription.getId(), bundleRepair);
+        SubscriptionBaseTimeline aoRepair = testUtil.getSubscriptionRepair(aoSubscription.getId(), bundleRepair);
         assertEquals(aoRepair.getExistingEvents().size(), 2);
 
-        final List<DeletedEvent> des = new LinkedList<SubscriptionTimeline.DeletedEvent>();
+        final List<DeletedEvent> des = new LinkedList<SubscriptionBaseTimeline.DeletedEvent>();
         des.add(testUtil.createDeletedEvent(aoRepair.getExistingEvents().get(1).getEventId()));
         final DateTime aoCancelDate = aoSubscription.getStartDate().plusDays(1);
 
         final NewEvent ne = testUtil.createNewEvent(SubscriptionBaseTransitionType.CANCEL, aoCancelDate, null);
 
-        final SubscriptionTimeline saoRepair = testUtil.createSubscriptionRepair(aoSubscription.getId(), des, Collections.singletonList(ne));
+        final SubscriptionBaseTimeline saoRepair = testUtil.createSubscriptionRepair(aoSubscription.getId(), des, Collections.singletonList(ne));
 
-        final BundleTimeline bRepair = testUtil.createBundleRepair(bundle.getId(), bundleRepair.getViewId(), Collections.singletonList(saoRepair));
+        final BundleBaseTimeline bRepair = testUtil.createBundleRepair(bundle.getId(), bundleRepair.getViewId(), Collections.singletonList(saoRepair));
 
         boolean dryRun = true;
-        final BundleTimeline dryRunBundleRepair = repairApi.repairBundle(bRepair, dryRun, callContext);
+        final BundleBaseTimeline dryRunBundleRepair = repairApi.repairBundle(bRepair, dryRun, callContext);
 
         aoRepair = testUtil.getSubscriptionRepair(aoSubscription.getId(), dryRunBundleRepair);
         assertEquals(aoRepair.getExistingEvents().size(), 2);
@@ -503,7 +503,7 @@ public class TestRepairWithAO extends SubscriptionTestSuiteWithEmbeddedDB {
         bpRepair = testUtil.getSubscriptionRepair(baseSubscription.getId(), bundleRepair);
         assertEquals(bpRepair.getExistingEvents().size(), 2);
 
-        final List<ExistingEvent> expected = new LinkedList<SubscriptionTimeline.ExistingEvent>();
+        final List<ExistingEvent> expected = new LinkedList<SubscriptionBaseTimeline.ExistingEvent>();
         expected.add(testUtil.createExistingEventForAssertion(SubscriptionBaseTransitionType.CREATE, "Telescopic-Scope", PhaseType.DISCOUNT,
                                                               ProductCategory.ADD_ON, PriceListSet.DEFAULT_PRICELIST_NAME, BillingPeriod.MONTHLY, aoSubscription.getStartDate()));
         expected.add(testUtil.createExistingEventForAssertion(SubscriptionBaseTransitionType.CANCEL, "Telescopic-Scope", PhaseType.DISCOUNT,
@@ -512,19 +512,19 @@ public class TestRepairWithAO extends SubscriptionTestSuiteWithEmbeddedDB {
         for (final ExistingEvent e : expected) {
             testUtil.validateExistingEventForAssertion(e, aoRepair.getExistingEvents().get(index++));
         }
-        SubscriptionData newAoSubscription = (SubscriptionData) subscriptionInternalApi.getSubscriptionFromId(aoSubscription.getId(), internalCallContext);
+        DefaultSubscriptionBase newAoSubscription = (DefaultSubscriptionBase) subscriptionInternalApi.getSubscriptionFromId(aoSubscription.getId(), internalCallContext);
         assertEquals(newAoSubscription.getState(), SubscriptionState.ACTIVE);
         assertEquals(newAoSubscription.getAllTransitions().size(), 2);
         assertEquals(newAoSubscription.getActiveVersion(), SubscriptionEvents.INITIAL_VERSION);
 
-        SubscriptionData newBaseSubscription = (SubscriptionData) subscriptionInternalApi.getSubscriptionFromId(baseSubscription.getId(), internalCallContext);
+        DefaultSubscriptionBase newBaseSubscription = (DefaultSubscriptionBase) subscriptionInternalApi.getSubscriptionFromId(baseSubscription.getId(), internalCallContext);
         assertEquals(newBaseSubscription.getState(), SubscriptionState.ACTIVE);
         assertEquals(newBaseSubscription.getAllTransitions().size(), 2);
         assertEquals(newBaseSubscription.getActiveVersion(), SubscriptionEvents.INITIAL_VERSION);
 
         dryRun = false;
         testListener.pushExpectedEvent(NextEvent.REPAIR_BUNDLE);
-        final BundleTimeline realRunBundleRepair = repairApi.repairBundle(bRepair, dryRun, callContext);
+        final BundleBaseTimeline realRunBundleRepair = repairApi.repairBundle(bRepair, dryRun, callContext);
         assertTrue(testListener.isCompleted(5000));
 
         aoRepair = testUtil.getSubscriptionRepair(aoSubscription.getId(), realRunBundleRepair);
@@ -534,12 +534,12 @@ public class TestRepairWithAO extends SubscriptionTestSuiteWithEmbeddedDB {
             testUtil.validateExistingEventForAssertion(e, aoRepair.getExistingEvents().get(index++));
         }
 
-        newAoSubscription = (SubscriptionData) subscriptionInternalApi.getSubscriptionFromId(aoSubscription.getId(), internalCallContext);
+        newAoSubscription = (DefaultSubscriptionBase) subscriptionInternalApi.getSubscriptionFromId(aoSubscription.getId(), internalCallContext);
         assertEquals(newAoSubscription.getState(), SubscriptionState.CANCELLED);
         assertEquals(newAoSubscription.getAllTransitions().size(), 2);
         assertEquals(newAoSubscription.getActiveVersion(), SubscriptionEvents.INITIAL_VERSION + 1);
 
-        newBaseSubscription = (SubscriptionData) subscriptionInternalApi.getSubscriptionFromId(baseSubscription.getId(), internalCallContext);
+        newBaseSubscription = (DefaultSubscriptionBase) subscriptionInternalApi.getSubscriptionFromId(baseSubscription.getId(), internalCallContext);
         assertEquals(newBaseSubscription.getState(), SubscriptionState.ACTIVE);
         assertEquals(newBaseSubscription.getAllTransitions().size(), 2);
         assertEquals(newBaseSubscription.getActiveVersion(), SubscriptionEvents.INITIAL_VERSION);
@@ -552,29 +552,29 @@ public class TestRepairWithAO extends SubscriptionTestSuiteWithEmbeddedDB {
         final String basePriceList = PriceListSet.DEFAULT_PRICELIST_NAME;
 
         // CREATE BP
-        final SubscriptionData baseSubscription = testUtil.createSubscription(bundle, baseProduct, baseTerm, basePriceList);
+        final DefaultSubscriptionBase baseSubscription = testUtil.createSubscription(bundle, baseProduct, baseTerm, basePriceList);
 
         // MOVE CLOCK A LITTLE BIT-- STILL IN TRIAL
         Interval it = new Interval(clock.getUTCNow(), clock.getUTCNow().plusDays(4));
         clock.addDeltaFromReality(it.toDurationMillis());
 
-        final SubscriptionData aoSubscription = testUtil.createSubscription(bundle, "Telescopic-Scope", BillingPeriod.MONTHLY, PriceListSet.DEFAULT_PRICELIST_NAME);
+        final DefaultSubscriptionBase aoSubscription = testUtil.createSubscription(bundle, "Telescopic-Scope", BillingPeriod.MONTHLY, PriceListSet.DEFAULT_PRICELIST_NAME);
 
         // MOVE CLOCK A LITTLE BIT MORE -- STILL IN TRIAL
         it = new Interval(clock.getUTCNow(), clock.getUTCNow().plusDays(3));
         clock.addDeltaFromReality(it.toDurationMillis());
 
-        final BundleTimeline bundleRepair = repairApi.getBundleTimeline(bundle.getId(), callContext);
+        final BundleBaseTimeline bundleRepair = repairApi.getBundleTimeline(bundle.getId(), callContext);
         testUtil.sortEventsOnBundle(bundleRepair);
 
         // Quick check
-        final SubscriptionTimeline bpRepair = testUtil.getSubscriptionRepair(baseSubscription.getId(), bundleRepair);
+        final SubscriptionBaseTimeline bpRepair = testUtil.getSubscriptionRepair(baseSubscription.getId(), bundleRepair);
         assertEquals(bpRepair.getExistingEvents().size(), 2);
 
-        SubscriptionTimeline aoRepair = testUtil.getSubscriptionRepair(aoSubscription.getId(), bundleRepair);
+        SubscriptionBaseTimeline aoRepair = testUtil.getSubscriptionRepair(aoSubscription.getId(), bundleRepair);
         assertEquals(aoRepair.getExistingEvents().size(), 2);
 
-        final List<DeletedEvent> des = new LinkedList<SubscriptionTimeline.DeletedEvent>();
+        final List<DeletedEvent> des = new LinkedList<SubscriptionBaseTimeline.DeletedEvent>();
         des.add(testUtil.createDeletedEvent(aoRepair.getExistingEvents().get(0).getEventId()));
         des.add(testUtil.createDeletedEvent(aoRepair.getExistingEvents().get(1).getEventId()));
 
@@ -582,17 +582,17 @@ public class TestRepairWithAO extends SubscriptionTestSuiteWithEmbeddedDB {
         final PlanPhaseSpecifier spec = new PlanPhaseSpecifier("Telescopic-Scope", ProductCategory.ADD_ON, BillingPeriod.MONTHLY, PriceListSet.DEFAULT_PRICELIST_NAME, PhaseType.DISCOUNT);
         final NewEvent ne = testUtil.createNewEvent(SubscriptionBaseTransitionType.CREATE, aoRecreateDate, spec);
 
-        final SubscriptionTimeline saoRepair = testUtil.createSubscriptionRepair(aoSubscription.getId(), des, Collections.singletonList(ne));
+        final SubscriptionBaseTimeline saoRepair = testUtil.createSubscriptionRepair(aoSubscription.getId(), des, Collections.singletonList(ne));
 
-        final BundleTimeline bRepair = testUtil.createBundleRepair(bundle.getId(), bundleRepair.getViewId(), Collections.singletonList(saoRepair));
+        final BundleBaseTimeline bRepair = testUtil.createBundleRepair(bundle.getId(), bundleRepair.getViewId(), Collections.singletonList(saoRepair));
 
         boolean dryRun = true;
-        final BundleTimeline dryRunBundleRepair = repairApi.repairBundle(bRepair, dryRun, callContext);
+        final BundleBaseTimeline dryRunBundleRepair = repairApi.repairBundle(bRepair, dryRun, callContext);
 
         aoRepair = testUtil.getSubscriptionRepair(aoSubscription.getId(), dryRunBundleRepair);
         assertEquals(aoRepair.getExistingEvents().size(), 2);
 
-        final List<ExistingEvent> expected = new LinkedList<SubscriptionTimeline.ExistingEvent>();
+        final List<ExistingEvent> expected = new LinkedList<SubscriptionBaseTimeline.ExistingEvent>();
         expected.add(testUtil.createExistingEventForAssertion(SubscriptionBaseTransitionType.CREATE, "Telescopic-Scope", PhaseType.DISCOUNT,
                                                               ProductCategory.ADD_ON, PriceListSet.DEFAULT_PRICELIST_NAME, BillingPeriod.MONTHLY, aoRecreateDate));
         expected.add(testUtil.createExistingEventForAssertion(SubscriptionBaseTransitionType.PHASE, "Telescopic-Scope", PhaseType.EVERGREEN,
@@ -601,7 +601,7 @@ public class TestRepairWithAO extends SubscriptionTestSuiteWithEmbeddedDB {
         for (final ExistingEvent e : expected) {
             testUtil.validateExistingEventForAssertion(e, aoRepair.getExistingEvents().get(index++));
         }
-        SubscriptionData newAoSubscription = (SubscriptionData) subscriptionInternalApi.getSubscriptionFromId(aoSubscription.getId(), internalCallContext);
+        DefaultSubscriptionBase newAoSubscription = (DefaultSubscriptionBase) subscriptionInternalApi.getSubscriptionFromId(aoSubscription.getId(), internalCallContext);
         assertEquals(newAoSubscription.getState(), SubscriptionState.ACTIVE);
         assertEquals(newAoSubscription.getAllTransitions().size(), 2);
         assertEquals(newAoSubscription.getStartDate(), aoSubscription.getStartDate());
@@ -610,7 +610,7 @@ public class TestRepairWithAO extends SubscriptionTestSuiteWithEmbeddedDB {
         // NOW COMMIT
         dryRun = false;
         testListener.pushExpectedEvent(NextEvent.REPAIR_BUNDLE);
-        final BundleTimeline realRunBundleRepair = repairApi.repairBundle(bRepair, dryRun, callContext);
+        final BundleBaseTimeline realRunBundleRepair = repairApi.repairBundle(bRepair, dryRun, callContext);
         assertTrue(testListener.isCompleted(5000));
 
         aoRepair = testUtil.getSubscriptionRepair(aoSubscription.getId(), realRunBundleRepair);
@@ -620,7 +620,7 @@ public class TestRepairWithAO extends SubscriptionTestSuiteWithEmbeddedDB {
             testUtil.validateExistingEventForAssertion(e, aoRepair.getExistingEvents().get(index++));
         }
 
-        newAoSubscription = (SubscriptionData) subscriptionInternalApi.getSubscriptionFromId(aoSubscription.getId(), internalCallContext);
+        newAoSubscription = (DefaultSubscriptionBase) subscriptionInternalApi.getSubscriptionFromId(aoSubscription.getId(), internalCallContext);
         assertEquals(newAoSubscription.getState(), SubscriptionState.ACTIVE);
         assertEquals(newAoSubscription.getAllTransitions().size(), 2);
         assertEquals(newAoSubscription.getStartDate(), aoRecreateDate);
@@ -643,45 +643,45 @@ public class TestRepairWithAO extends SubscriptionTestSuiteWithEmbeddedDB {
         final String basePriceList = PriceListSet.DEFAULT_PRICELIST_NAME;
 
         // CREATE BP
-        final SubscriptionData baseSubscription = testUtil.createSubscription(bundle, baseProduct, baseTerm, basePriceList);
+        final DefaultSubscriptionBase baseSubscription = testUtil.createSubscription(bundle, baseProduct, baseTerm, basePriceList);
 
         // MOVE CLOCK A LITTLE BIT-- STILL IN TRIAL
         Interval it = new Interval(clock.getUTCNow(), clock.getUTCNow().plusDays(4));
         clock.addDeltaFromReality(it.toDurationMillis());
 
-        final SubscriptionData aoSubscription = testUtil.createSubscription(bundle, "Telescopic-Scope", BillingPeriod.MONTHLY, PriceListSet.DEFAULT_PRICELIST_NAME);
+        final DefaultSubscriptionBase aoSubscription = testUtil.createSubscription(bundle, "Telescopic-Scope", BillingPeriod.MONTHLY, PriceListSet.DEFAULT_PRICELIST_NAME);
 
         // MOVE CLOCK A LITTLE BIT MORE -- STILL IN TRIAL
         it = new Interval(clock.getUTCNow(), clock.getUTCNow().plusDays(3));
         clock.addDeltaFromReality(it.toDurationMillis());
 
-        final BundleTimeline bundleRepair = repairApi.getBundleTimeline(bundle.getId(), callContext);
+        final BundleBaseTimeline bundleRepair = repairApi.getBundleTimeline(bundle.getId(), callContext);
         testUtil.sortEventsOnBundle(bundleRepair);
 
         // Quick check
-        final SubscriptionTimeline bpRepair = testUtil.getSubscriptionRepair(baseSubscription.getId(), bundleRepair);
+        final SubscriptionBaseTimeline bpRepair = testUtil.getSubscriptionRepair(baseSubscription.getId(), bundleRepair);
         assertEquals(bpRepair.getExistingEvents().size(), 2);
 
-        SubscriptionTimeline aoRepair = testUtil.getSubscriptionRepair(aoSubscription.getId(), bundleRepair);
+        SubscriptionBaseTimeline aoRepair = testUtil.getSubscriptionRepair(aoSubscription.getId(), bundleRepair);
         assertEquals(aoRepair.getExistingEvents().size(), 2);
 
-        final List<DeletedEvent> des = new LinkedList<SubscriptionTimeline.DeletedEvent>();
+        final List<DeletedEvent> des = new LinkedList<SubscriptionBaseTimeline.DeletedEvent>();
         des.add(testUtil.createDeletedEvent(aoRepair.getExistingEvents().get(1).getEventId()));
         final DateTime aoChangeDate = aoSubscription.getStartDate().plusDays(1);
         final PlanPhaseSpecifier spec = new PlanPhaseSpecifier("Laser-Scope", ProductCategory.ADD_ON, BillingPeriod.MONTHLY, PriceListSet.DEFAULT_PRICELIST_NAME, PhaseType.TRIAL);
         final NewEvent ne = testUtil.createNewEvent(SubscriptionBaseTransitionType.CHANGE, aoChangeDate, spec);
 
-        final SubscriptionTimeline saoRepair = testUtil.createSubscriptionRepair(aoSubscription.getId(), des, Collections.singletonList(ne));
+        final SubscriptionBaseTimeline saoRepair = testUtil.createSubscriptionRepair(aoSubscription.getId(), des, Collections.singletonList(ne));
 
-        final BundleTimeline bRepair = testUtil.createBundleRepair(bundle.getId(), bundleRepair.getViewId(), Collections.singletonList(saoRepair));
+        final BundleBaseTimeline bRepair = testUtil.createBundleRepair(bundle.getId(), bundleRepair.getViewId(), Collections.singletonList(saoRepair));
 
         boolean dryRun = true;
-        final BundleTimeline dryRunBundleRepair = repairApi.repairBundle(bRepair, dryRun, callContext);
+        final BundleBaseTimeline dryRunBundleRepair = repairApi.repairBundle(bRepair, dryRun, callContext);
 
         aoRepair = testUtil.getSubscriptionRepair(aoSubscription.getId(), dryRunBundleRepair);
         assertEquals(aoRepair.getExistingEvents().size(), 3);
 
-        final List<ExistingEvent> expected = new LinkedList<SubscriptionTimeline.ExistingEvent>();
+        final List<ExistingEvent> expected = new LinkedList<SubscriptionBaseTimeline.ExistingEvent>();
         expected.add(testUtil.createExistingEventForAssertion(SubscriptionBaseTransitionType.CREATE, "Telescopic-Scope", PhaseType.DISCOUNT,
                                                               ProductCategory.ADD_ON, PriceListSet.DEFAULT_PRICELIST_NAME, BillingPeriod.MONTHLY, aoSubscription.getStartDate()));
         expected.add(testUtil.createExistingEventForAssertion(SubscriptionBaseTransitionType.CHANGE, "Laser-Scope", PhaseType.DISCOUNT,
@@ -694,14 +694,14 @@ public class TestRepairWithAO extends SubscriptionTestSuiteWithEmbeddedDB {
         for (final ExistingEvent e : expected) {
             testUtil.validateExistingEventForAssertion(e, aoRepair.getExistingEvents().get(index++));
         }
-        SubscriptionData newAoSubscription = (SubscriptionData) subscriptionInternalApi.getSubscriptionFromId(aoSubscription.getId(), internalCallContext);
+        DefaultSubscriptionBase newAoSubscription = (DefaultSubscriptionBase) subscriptionInternalApi.getSubscriptionFromId(aoSubscription.getId(), internalCallContext);
         assertEquals(newAoSubscription.getState(), SubscriptionState.ACTIVE);
         assertEquals(newAoSubscription.getAllTransitions().size(), 2);
 
         // AND NOW COMMIT
         dryRun = false;
         testListener.pushExpectedEvent(NextEvent.REPAIR_BUNDLE);
-        final BundleTimeline realRunBundleRepair = repairApi.repairBundle(bRepair, dryRun, callContext);
+        final BundleBaseTimeline realRunBundleRepair = repairApi.repairBundle(bRepair, dryRun, callContext);
         assertTrue(testListener.isCompleted(5000));
 
         aoRepair = testUtil.getSubscriptionRepair(aoSubscription.getId(), realRunBundleRepair);
@@ -711,7 +711,7 @@ public class TestRepairWithAO extends SubscriptionTestSuiteWithEmbeddedDB {
             testUtil.validateExistingEventForAssertion(e, aoRepair.getExistingEvents().get(index++));
         }
 
-        newAoSubscription = (SubscriptionData) subscriptionInternalApi.getSubscriptionFromId(aoSubscription.getId(), internalCallContext);
+        newAoSubscription = (DefaultSubscriptionBase) subscriptionInternalApi.getSubscriptionFromId(aoSubscription.getId(), internalCallContext);
         assertEquals(newAoSubscription.getState(), SubscriptionState.ACTIVE);
         assertEquals(newAoSubscription.getAllTransitions().size(), 3);
 
@@ -737,7 +737,7 @@ public class TestRepairWithAO extends SubscriptionTestSuiteWithEmbeddedDB {
         clock.addDeltaFromReality(it.toDurationMillis());
         assertTrue(testListener.isCompleted(5000));
 
-        newAoSubscription = (SubscriptionData) subscriptionInternalApi.getSubscriptionFromId(aoSubscription.getId(), internalCallContext);
+        newAoSubscription = (DefaultSubscriptionBase) subscriptionInternalApi.getSubscriptionFromId(aoSubscription.getId(), internalCallContext);
         currentPhase = newAoSubscription.getCurrentPhase();
         assertNotNull(currentPhase);
         assertEquals(currentPhase.getPhaseType(), PhaseType.EVERGREEN);
diff --git a/subscription/src/test/java/com/ning/billing/subscription/api/timeline/TestRepairWithError.java b/subscription/src/test/java/com/ning/billing/subscription/api/timeline/TestRepairWithError.java
index be175fb..cda8a39 100644
--- a/subscription/src/test/java/com/ning/billing/subscription/api/timeline/TestRepairWithError.java
+++ b/subscription/src/test/java/com/ning/billing/subscription/api/timeline/TestRepairWithError.java
@@ -36,11 +36,11 @@ import com.ning.billing.catalog.api.ProductCategory;
 import com.ning.billing.subscription.SubscriptionTestSuiteNoDB;
 import com.ning.billing.subscription.api.SubscriptionBaseTransitionType;
 import com.ning.billing.subscription.api.user.SubscriptionBaseApiException;
-import com.ning.billing.subscription.api.user.SubscriptionData;
+import com.ning.billing.subscription.api.user.DefaultSubscriptionBase;
 import com.ning.billing.subscription.api.user.TestSubscriptionHelper.TestWithException;
 import com.ning.billing.subscription.api.user.TestSubscriptionHelper.TestWithExceptionCallback;
-import com.ning.billing.subscription.api.timeline.SubscriptionTimeline.DeletedEvent;
-import com.ning.billing.subscription.api.timeline.SubscriptionTimeline.NewEvent;
+import com.ning.billing.subscription.api.timeline.SubscriptionBaseTimeline.DeletedEvent;
+import com.ning.billing.subscription.api.timeline.SubscriptionBaseTimeline.NewEvent;
 import com.ning.billing.subscription.api.SubscriptionBase;
 
 import static org.testng.Assert.assertTrue;
@@ -65,7 +65,7 @@ public class TestRepairWithError extends SubscriptionTestSuiteNoDB {
     public void testENT_REPAIR_NEW_EVENT_BEFORE_LAST_BP_REMAINING() throws Exception {
         test.withException(new TestWithExceptionCallback() {
             @Override
-            public void doTest() throws SubscriptionRepairException {
+            public void doTest() throws SubscriptionBaseRepairException {
                 // MOVE AFTER TRIAL
                 testListener.pushExpectedEvent(NextEvent.PHASE);
 
@@ -74,14 +74,14 @@ public class TestRepairWithError extends SubscriptionTestSuiteNoDB {
 
                 assertTrue(testListener.isCompleted(5000));
 
-                final BundleTimeline bundleRepair = repairApi.getBundleTimeline(bundle.getId(), callContext);
+                final BundleBaseTimeline bundleRepair = repairApi.getBundleTimeline(bundle.getId(), callContext);
                 testUtil.sortEventsOnBundle(bundleRepair);
                 final PlanPhaseSpecifier spec = new PlanPhaseSpecifier("Assault-Rifle", ProductCategory.BASE, BillingPeriod.MONTHLY, PriceListSet.DEFAULT_PRICELIST_NAME, PhaseType.EVERGREEN);
                 final NewEvent ne = testUtil.createNewEvent(SubscriptionBaseTransitionType.CHANGE, baseSubscription.getStartDate().plusDays(10), spec);
 
-                final SubscriptionTimeline sRepair = testUtil.createSubscriptionRepair(baseSubscription.getId(), Collections.<DeletedEvent>emptyList(), Collections.singletonList(ne));
+                final SubscriptionBaseTimeline sRepair = testUtil.createSubscriptionRepair(baseSubscription.getId(), Collections.<DeletedEvent>emptyList(), Collections.singletonList(ne));
 
-                final BundleTimeline bRepair = testUtil.createBundleRepair(bundle.getId(), bundleRepair.getViewId(), Collections.singletonList(sRepair));
+                final BundleBaseTimeline bRepair = testUtil.createBundleRepair(bundle.getId(), bundleRepair.getViewId(), Collections.singletonList(sRepair));
 
                 repairApi.repairBundle(bRepair, true, callContext);
             }
@@ -92,7 +92,7 @@ public class TestRepairWithError extends SubscriptionTestSuiteNoDB {
     public void testENT_REPAIR_INVALID_DELETE_SET() throws Exception {
         test.withException(new TestWithExceptionCallback() {
             @Override
-            public void doTest() throws SubscriptionRepairException, SubscriptionBaseApiException {
+            public void doTest() throws SubscriptionBaseRepairException, SubscriptionBaseApiException {
 
                 Interval it = new Interval(clock.getUTCNow(), clock.getUTCNow().plusDays(3));
                 clock.addDeltaFromReality(it.toDurationMillis());
@@ -108,14 +108,14 @@ public class TestRepairWithError extends SubscriptionTestSuiteNoDB {
                 clock.addDeltaFromReality(it.toDurationMillis());
                 assertTrue(testListener.isCompleted(5000));
 
-                final BundleTimeline bundleRepair = repairApi.getBundleTimeline(bundle.getId(), callContext);
+                final BundleBaseTimeline bundleRepair = repairApi.getBundleTimeline(bundle.getId(), callContext);
                 testUtil.sortEventsOnBundle(bundleRepair);
                 final PlanPhaseSpecifier spec = new PlanPhaseSpecifier("Assault-Rifle", ProductCategory.BASE, BillingPeriod.MONTHLY, PriceListSet.DEFAULT_PRICELIST_NAME, PhaseType.EVERGREEN);
                 final NewEvent ne = testUtil.createNewEvent(SubscriptionBaseTransitionType.CHANGE, baseSubscription.getStartDate().plusDays(10), spec);
                 final DeletedEvent de = testUtil.createDeletedEvent(bundleRepair.getSubscriptions().get(0).getExistingEvents().get(1).getEventId());
 
-                final SubscriptionTimeline sRepair = testUtil.createSubscriptionRepair(baseSubscription.getId(), Collections.singletonList(de), Collections.singletonList(ne));
-                final BundleTimeline bRepair = testUtil.createBundleRepair(bundle.getId(), bundleRepair.getViewId(), Collections.singletonList(sRepair));
+                final SubscriptionBaseTimeline sRepair = testUtil.createSubscriptionRepair(baseSubscription.getId(), Collections.singletonList(de), Collections.singletonList(ne));
+                final BundleBaseTimeline bRepair = testUtil.createBundleRepair(bundle.getId(), bundleRepair.getViewId(), Collections.singletonList(sRepair));
 
                 repairApi.repairBundle(bRepair, true, callContext);
             }
@@ -126,16 +126,16 @@ public class TestRepairWithError extends SubscriptionTestSuiteNoDB {
     public void testENT_REPAIR_NON_EXISTENT_DELETE_EVENT() throws Exception {
         test.withException(new TestWithExceptionCallback() {
             @Override
-            public void doTest() throws SubscriptionRepairException {
+            public void doTest() throws SubscriptionBaseRepairException {
 
-                final BundleTimeline bundleRepair = repairApi.getBundleTimeline(bundle.getId(), callContext);
+                final BundleBaseTimeline bundleRepair = repairApi.getBundleTimeline(bundle.getId(), callContext);
                 testUtil.sortEventsOnBundle(bundleRepair);
                 final PlanPhaseSpecifier spec = new PlanPhaseSpecifier("Assault-Rifle", ProductCategory.BASE, BillingPeriod.MONTHLY, PriceListSet.DEFAULT_PRICELIST_NAME, PhaseType.EVERGREEN);
                 final NewEvent ne = testUtil.createNewEvent(SubscriptionBaseTransitionType.CHANGE, baseSubscription.getStartDate().plusDays(10), spec);
                 final DeletedEvent de = testUtil.createDeletedEvent(UUID.randomUUID());
-                final SubscriptionTimeline sRepair = testUtil.createSubscriptionRepair(baseSubscription.getId(), Collections.singletonList(de), Collections.singletonList(ne));
+                final SubscriptionBaseTimeline sRepair = testUtil.createSubscriptionRepair(baseSubscription.getId(), Collections.singletonList(de), Collections.singletonList(ne));
 
-                final BundleTimeline bRepair = testUtil.createBundleRepair(bundle.getId(), bundleRepair.getViewId(), Collections.singletonList(sRepair));
+                final BundleBaseTimeline bRepair = testUtil.createBundleRepair(bundle.getId(), bundleRepair.getViewId(), Collections.singletonList(sRepair));
 
                 repairApi.repairBundle(bRepair, true, callContext);
             }
@@ -146,7 +146,7 @@ public class TestRepairWithError extends SubscriptionTestSuiteNoDB {
     public void testENT_REPAIR_SUB_RECREATE_NOT_EMPTY() throws Exception {
         test.withException(new TestWithExceptionCallback() {
             @Override
-            public void doTest() throws SubscriptionRepairException {
+            public void doTest() throws SubscriptionBaseRepairException {
 
                 // MOVE AFTER TRIAL
                 testListener.pushExpectedEvent(NextEvent.PHASE);
@@ -154,15 +154,15 @@ public class TestRepairWithError extends SubscriptionTestSuiteNoDB {
                 clock.addDeltaFromReality(it.toDurationMillis());
                 assertTrue(testListener.isCompleted(5000));
 
-                final BundleTimeline bundleRepair = repairApi.getBundleTimeline(bundle.getId(), callContext);
+                final BundleBaseTimeline bundleRepair = repairApi.getBundleTimeline(bundle.getId(), callContext);
                 testUtil.sortEventsOnBundle(bundleRepair);
                 final PlanPhaseSpecifier spec = new PlanPhaseSpecifier("Assault-Rifle", ProductCategory.BASE, BillingPeriod.MONTHLY, PriceListSet.DEFAULT_PRICELIST_NAME, PhaseType.EVERGREEN);
                 final NewEvent ne = testUtil.createNewEvent(SubscriptionBaseTransitionType.CREATE, baseSubscription.getStartDate().plusDays(10), spec);
-                final List<DeletedEvent> des = new LinkedList<SubscriptionTimeline.DeletedEvent>();
+                final List<DeletedEvent> des = new LinkedList<SubscriptionBaseTimeline.DeletedEvent>();
                 des.add(testUtil.createDeletedEvent(bundleRepair.getSubscriptions().get(0).getExistingEvents().get(1).getEventId()));
-                final SubscriptionTimeline sRepair = testUtil.createSubscriptionRepair(baseSubscription.getId(), des, Collections.singletonList(ne));
+                final SubscriptionBaseTimeline sRepair = testUtil.createSubscriptionRepair(baseSubscription.getId(), des, Collections.singletonList(ne));
 
-                final BundleTimeline bRepair = testUtil.createBundleRepair(bundle.getId(), bundleRepair.getViewId(), Collections.singletonList(sRepair));
+                final BundleBaseTimeline bRepair = testUtil.createBundleRepair(bundle.getId(), bundleRepair.getViewId(), Collections.singletonList(sRepair));
 
                 repairApi.repairBundle(bRepair, true, callContext);
 
@@ -175,7 +175,7 @@ public class TestRepairWithError extends SubscriptionTestSuiteNoDB {
         test.withException(new TestWithExceptionCallback() {
 
             @Override
-            public void doTest() throws SubscriptionRepairException {
+            public void doTest() throws SubscriptionBaseRepairException {
 
                 // MOVE AFTER TRIAL
                 testListener.pushExpectedEvent(NextEvent.PHASE);
@@ -183,16 +183,16 @@ public class TestRepairWithError extends SubscriptionTestSuiteNoDB {
                 clock.addDeltaFromReality(it.toDurationMillis());
                 assertTrue(testListener.isCompleted(5000));
 
-                final BundleTimeline bundleRepair = repairApi.getBundleTimeline(bundle.getId(), callContext);
+                final BundleBaseTimeline bundleRepair = repairApi.getBundleTimeline(bundle.getId(), callContext);
                 testUtil.sortEventsOnBundle(bundleRepair);
                 final PlanPhaseSpecifier spec = new PlanPhaseSpecifier("Assault-Rifle", ProductCategory.BASE, BillingPeriod.MONTHLY, PriceListSet.DEFAULT_PRICELIST_NAME, PhaseType.EVERGREEN);
                 final NewEvent ne = testUtil.createNewEvent(SubscriptionBaseTransitionType.CHANGE, baseSubscription.getStartDate().plusDays(10), spec);
-                final List<DeletedEvent> des = new LinkedList<SubscriptionTimeline.DeletedEvent>();
+                final List<DeletedEvent> des = new LinkedList<SubscriptionBaseTimeline.DeletedEvent>();
                 des.add(testUtil.createDeletedEvent(bundleRepair.getSubscriptions().get(0).getExistingEvents().get(0).getEventId()));
                 des.add(testUtil.createDeletedEvent(bundleRepair.getSubscriptions().get(0).getExistingEvents().get(1).getEventId()));
-                final SubscriptionTimeline sRepair = testUtil.createSubscriptionRepair(baseSubscription.getId(), des, Collections.singletonList(ne));
+                final SubscriptionBaseTimeline sRepair = testUtil.createSubscriptionRepair(baseSubscription.getId(), des, Collections.singletonList(ne));
 
-                final BundleTimeline bRepair = testUtil.createBundleRepair(bundle.getId(), bundleRepair.getViewId(), Collections.singletonList(sRepair));
+                final BundleBaseTimeline bRepair = testUtil.createBundleRepair(bundle.getId(), bundleRepair.getViewId(), Collections.singletonList(sRepair));
 
                 repairApi.repairBundle(bRepair, true, callContext);
             }
@@ -203,27 +203,27 @@ public class TestRepairWithError extends SubscriptionTestSuiteNoDB {
     public void testENT_REPAIR_AO_CREATE_BEFORE_BP_START() throws Exception {
         test.withException(new TestWithExceptionCallback() {
             @Override
-            public void doTest() throws SubscriptionRepairException, SubscriptionBaseApiException {
+            public void doTest() throws SubscriptionBaseRepairException, SubscriptionBaseApiException {
                 // MOVE CLOCK A LITTLE BIT-- STILL IN TRIAL
                 Interval it = new Interval(clock.getUTCNow(), clock.getUTCNow().plusDays(4));
                 clock.addDeltaFromReality(it.toDurationMillis());
-                final SubscriptionData aoSubscription = testUtil.createSubscription(bundle, "Telescopic-Scope", BillingPeriod.MONTHLY, PriceListSet.DEFAULT_PRICELIST_NAME);
+                final DefaultSubscriptionBase aoSubscription = testUtil.createSubscription(bundle, "Telescopic-Scope", BillingPeriod.MONTHLY, PriceListSet.DEFAULT_PRICELIST_NAME);
 
                 // MOVE CLOCK A LITTLE BIT MORE -- STILL IN TRIAL
                 it = new Interval(clock.getUTCNow(), clock.getUTCNow().plusDays(4));
                 clock.addDeltaFromReality(it.toDurationMillis());
 
-                final BundleTimeline bundleRepair = repairApi.getBundleTimeline(bundle.getId(), callContext);
+                final BundleBaseTimeline bundleRepair = repairApi.getBundleTimeline(bundle.getId(), callContext);
                 testUtil.sortEventsOnBundle(bundleRepair);
 
                 // Quick check
-                final SubscriptionTimeline bpRepair = testUtil.getSubscriptionRepair(baseSubscription.getId(), bundleRepair);
+                final SubscriptionBaseTimeline bpRepair = testUtil.getSubscriptionRepair(baseSubscription.getId(), bundleRepair);
                 assertEquals(bpRepair.getExistingEvents().size(), 2);
 
-                final SubscriptionTimeline aoRepair = testUtil.getSubscriptionRepair(aoSubscription.getId(), bundleRepair);
+                final SubscriptionBaseTimeline aoRepair = testUtil.getSubscriptionRepair(aoSubscription.getId(), bundleRepair);
                 assertEquals(aoRepair.getExistingEvents().size(), 2);
 
-                final List<DeletedEvent> des = new LinkedList<SubscriptionTimeline.DeletedEvent>();
+                final List<DeletedEvent> des = new LinkedList<SubscriptionBaseTimeline.DeletedEvent>();
                 des.add(testUtil.createDeletedEvent(aoRepair.getExistingEvents().get(0).getEventId()));
                 des.add(testUtil.createDeletedEvent(aoRepair.getExistingEvents().get(1).getEventId()));
 
@@ -231,9 +231,9 @@ public class TestRepairWithError extends SubscriptionTestSuiteNoDB {
                 final PlanPhaseSpecifier spec = new PlanPhaseSpecifier("Telescopic-Scope", ProductCategory.ADD_ON, BillingPeriod.MONTHLY, PriceListSet.DEFAULT_PRICELIST_NAME, PhaseType.DISCOUNT);
                 final NewEvent ne = testUtil.createNewEvent(SubscriptionBaseTransitionType.CREATE, aoRecreateDate, spec);
 
-                final SubscriptionTimeline saoRepair = testUtil.createSubscriptionRepair(aoSubscription.getId(), des, Collections.singletonList(ne));
+                final SubscriptionBaseTimeline saoRepair = testUtil.createSubscriptionRepair(aoSubscription.getId(), des, Collections.singletonList(ne));
 
-                final BundleTimeline bRepair = testUtil.createBundleRepair(bundle.getId(), bundleRepair.getViewId(), Collections.singletonList(saoRepair));
+                final BundleBaseTimeline bRepair = testUtil.createBundleRepair(bundle.getId(), bundleRepair.getViewId(), Collections.singletonList(saoRepair));
 
                 final boolean dryRun = true;
                 repairApi.repairBundle(bRepair, dryRun, callContext);
@@ -245,34 +245,34 @@ public class TestRepairWithError extends SubscriptionTestSuiteNoDB {
     public void testENT_REPAIR_NEW_EVENT_BEFORE_LAST_AO_REMAINING() throws Exception {
         test.withException(new TestWithExceptionCallback() {
             @Override
-            public void doTest() throws SubscriptionRepairException, SubscriptionBaseApiException {
+            public void doTest() throws SubscriptionBaseRepairException, SubscriptionBaseApiException {
 
                 // MOVE CLOCK A LITTLE BIT-- STILL IN TRIAL
                 Interval it = new Interval(clock.getUTCNow(), clock.getUTCNow().plusDays(4));
                 clock.addDeltaFromReality(it.toDurationMillis());
-                final SubscriptionData aoSubscription = testUtil.createSubscription(bundle, "Telescopic-Scope", BillingPeriod.MONTHLY, PriceListSet.DEFAULT_PRICELIST_NAME);
+                final DefaultSubscriptionBase aoSubscription = testUtil.createSubscription(bundle, "Telescopic-Scope", BillingPeriod.MONTHLY, PriceListSet.DEFAULT_PRICELIST_NAME);
 
                 // MOVE CLOCK A LITTLE BIT MORE -- STILL IN TRIAL
                 it = new Interval(clock.getUTCNow(), clock.getUTCNow().plusDays(4));
                 clock.addDeltaFromReality(it.toDurationMillis());
 
-                BundleTimeline bundleRepair = repairApi.getBundleTimeline(bundle.getId(), callContext);
+                BundleBaseTimeline bundleRepair = repairApi.getBundleTimeline(bundle.getId(), callContext);
                 testUtil.sortEventsOnBundle(bundleRepair);
 
                 // Quick check
-                final SubscriptionTimeline bpRepair = testUtil.getSubscriptionRepair(baseSubscription.getId(), bundleRepair);
+                final SubscriptionBaseTimeline bpRepair = testUtil.getSubscriptionRepair(baseSubscription.getId(), bundleRepair);
                 assertEquals(bpRepair.getExistingEvents().size(), 2);
 
-                final SubscriptionTimeline aoRepair = testUtil.getSubscriptionRepair(aoSubscription.getId(), bundleRepair);
+                final SubscriptionBaseTimeline aoRepair = testUtil.getSubscriptionRepair(aoSubscription.getId(), bundleRepair);
                 assertEquals(aoRepair.getExistingEvents().size(), 2);
 
-                final List<DeletedEvent> des = new LinkedList<SubscriptionTimeline.DeletedEvent>();
+                final List<DeletedEvent> des = new LinkedList<SubscriptionBaseTimeline.DeletedEvent>();
                 //des.add(createDeletedEvent(aoRepair.getExistingEvents().get(1).getEventId()));        
                 final DateTime aoCancelDate = aoSubscription.getStartDate().plusDays(10);
 
                 final NewEvent ne = testUtil.createNewEvent(SubscriptionBaseTransitionType.CANCEL, aoCancelDate, null);
 
-                final SubscriptionTimeline saoRepair = testUtil.createSubscriptionRepair(aoSubscription.getId(), des, Collections.singletonList(ne));
+                final SubscriptionBaseTimeline saoRepair = testUtil.createSubscriptionRepair(aoSubscription.getId(), des, Collections.singletonList(ne));
 
                 bundleRepair = testUtil.createBundleRepair(bundle.getId(), bundleRepair.getViewId(), Collections.singletonList(saoRepair));
 
@@ -286,7 +286,7 @@ public class TestRepairWithError extends SubscriptionTestSuiteNoDB {
     public void testENT_REPAIR_BP_RECREATE_MISSING_AO() throws Exception {
         test.withException(new TestWithExceptionCallback() {
             @Override
-            public void doTest() throws SubscriptionRepairException, SubscriptionBaseApiException {
+            public void doTest() throws SubscriptionBaseRepairException, SubscriptionBaseApiException {
 
                 //testListener.pushExpectedEvent(NextEvent.PHASE);
 
@@ -294,9 +294,9 @@ public class TestRepairWithError extends SubscriptionTestSuiteNoDB {
                 clock.addDeltaFromReality(it.toDurationMillis());
                 //assertTrue(testListener.isCompleted(5000));
 
-                final SubscriptionData aoSubscription = testUtil.createSubscription(bundle, "Laser-Scope", BillingPeriod.MONTHLY, PriceListSet.DEFAULT_PRICELIST_NAME);
+                final DefaultSubscriptionBase aoSubscription = testUtil.createSubscription(bundle, "Laser-Scope", BillingPeriod.MONTHLY, PriceListSet.DEFAULT_PRICELIST_NAME);
 
-                final BundleTimeline bundleRepair = repairApi.getBundleTimeline(bundle.getId(), callContext);
+                final BundleBaseTimeline bundleRepair = repairApi.getBundleTimeline(bundle.getId(), callContext);
                 testUtil.sortEventsOnBundle(bundleRepair);
 
                 final DateTime newCreateTime = baseSubscription.getStartDate().plusDays(3);
@@ -304,14 +304,14 @@ public class TestRepairWithError extends SubscriptionTestSuiteNoDB {
                 final PlanPhaseSpecifier spec = new PlanPhaseSpecifier("Pistol", ProductCategory.BASE, BillingPeriod.MONTHLY, PriceListSet.DEFAULT_PRICELIST_NAME, PhaseType.TRIAL);
 
                 final NewEvent ne = testUtil.createNewEvent(SubscriptionBaseTransitionType.CREATE, newCreateTime, spec);
-                final List<DeletedEvent> des = new LinkedList<SubscriptionTimeline.DeletedEvent>();
+                final List<DeletedEvent> des = new LinkedList<SubscriptionBaseTimeline.DeletedEvent>();
                 des.add(testUtil.createDeletedEvent(bundleRepair.getSubscriptions().get(0).getExistingEvents().get(0).getEventId()));
                 des.add(testUtil.createDeletedEvent(bundleRepair.getSubscriptions().get(0).getExistingEvents().get(1).getEventId()));
 
-                final SubscriptionTimeline sRepair = testUtil.createSubscriptionRepair(baseSubscription.getId(), des, Collections.singletonList(ne));
+                final SubscriptionBaseTimeline sRepair = testUtil.createSubscriptionRepair(baseSubscription.getId(), des, Collections.singletonList(ne));
 
                 // FIRST ISSUE DRY RUN
-                final BundleTimeline bRepair = testUtil.createBundleRepair(bundle.getId(), bundleRepair.getViewId(), Collections.singletonList(sRepair));
+                final BundleBaseTimeline bRepair = testUtil.createBundleRepair(bundle.getId(), bundleRepair.getViewId(), Collections.singletonList(sRepair));
 
                 final boolean dryRun = true;
                 repairApi.repairBundle(bRepair, dryRun, callContext);
@@ -326,7 +326,7 @@ public class TestRepairWithError extends SubscriptionTestSuiteNoDB {
     public void testENT_REPAIR_BP_RECREATE_MISSING_AO_CREATE() throws Exception {
         test.withException(new TestWithExceptionCallback() {
             @Override
-            public void doTest() throws SubscriptionRepairException, SubscriptionBaseApiException {
+            public void doTest() throws SubscriptionBaseRepairException, SubscriptionBaseApiException {
                 /*
               //testListener.pushExpectedEvent(NextEvent.PHASE);
 
@@ -334,7 +334,7 @@ public class TestRepairWithError extends SubscriptionTestSuiteNoDB {
                 clock.addDeltaFromReality(it.toDurationMillis());
 
 
-                SubscriptionData aoSubscription = createSubscription("Laser-Scope", BillingPeriod.MONTHLY, PriceListSet.DEFAULT_PRICELIST_NAME);
+                DefaultSubscriptionBase aoSubscription = createSubscription("Laser-Scope", BillingPeriod.MONTHLY, PriceListSet.DEFAULT_PRICELIST_NAME);
                 
                 BundleRepair bundleRepair = repairApi.getBundleRepair(bundle.getId());
                 sortEventsOnBundle(bundleRepair);
@@ -372,7 +372,7 @@ public class TestRepairWithError extends SubscriptionTestSuiteNoDB {
     public void testENT_REPAIR_MISSING_AO_DELETE_EVENT() throws Exception {
         test.withException(new TestWithExceptionCallback() {
             @Override
-            public void doTest() throws SubscriptionRepairException, SubscriptionBaseApiException {
+            public void doTest() throws SubscriptionBaseRepairException, SubscriptionBaseApiException {
 
                 /*
                 // MOVE CLOCK -- JUST BEFORE END OF TRIAL
@@ -382,7 +382,7 @@ public class TestRepairWithError extends SubscriptionTestSuiteNoDB {
 
                 clock.setDeltaFromReality(getDurationDay(29), 0);
                 
-                SubscriptionData aoSubscription = createSubscription("Laser-Scope", BillingPeriod.MONTHLY, PriceListSet.DEFAULT_PRICELIST_NAME);
+                DefaultSubscriptionBase aoSubscription = createSubscription("Laser-Scope", BillingPeriod.MONTHLY, PriceListSet.DEFAULT_PRICELIST_NAME);
                 
                 // MOVE CLOCK -- RIGHT OUT OF TRIAL
                 testListener.pushExpectedEvent(NextEvent.PHASE);                
diff --git a/subscription/src/test/java/com/ning/billing/subscription/api/transfer/TestDefaultSubscriptionTransferApi.java b/subscription/src/test/java/com/ning/billing/subscription/api/transfer/TestDefaultSubscriptionTransferApi.java
index 521fa80..e628f87 100644
--- a/subscription/src/test/java/com/ning/billing/subscription/api/transfer/TestDefaultSubscriptionTransferApi.java
+++ b/subscription/src/test/java/com/ning/billing/subscription/api/transfer/TestDefaultSubscriptionTransferApi.java
@@ -34,27 +34,27 @@ import com.ning.billing.catalog.api.PlanPhaseSpecifier;
 import com.ning.billing.catalog.api.PriceListSet;
 import com.ning.billing.catalog.api.ProductCategory;
 import com.ning.billing.subscription.SubscriptionTestSuiteNoDB;
-import com.ning.billing.subscription.api.SubscriptionApiService;
+import com.ning.billing.subscription.api.SubscriptionBaseApiService;
 import com.ning.billing.subscription.api.SubscriptionBaseTransitionType;
+import com.ning.billing.subscription.api.timeline.SubscriptionBaseTimelineApi;
+import com.ning.billing.subscription.api.user.DefaultSubscriptionBase;
 import com.ning.billing.subscription.api.user.SubscriptionBuilder;
-import com.ning.billing.subscription.api.user.SubscriptionData;
 import com.ning.billing.subscription.engine.dao.SubscriptionDao;
 import com.ning.billing.subscription.events.SubscriptionEvent;
 import com.ning.billing.subscription.events.SubscriptionEvent.EventType;
 import com.ning.billing.subscription.events.user.ApiEventTransfer;
 import com.ning.billing.subscription.events.user.ApiEventType;
-import com.ning.billing.subscription.api.timeline.SubscriptionTimeline.ExistingEvent;
-import com.ning.billing.subscription.api.timeline.SubscriptionTimelineApi;
+import com.ning.billing.subscription.api.timeline.SubscriptionBaseTimeline.ExistingEvent;
 import com.ning.billing.util.cache.CacheControllerDispatcher;
 import com.ning.billing.util.callcontext.InternalCallContextFactory;
 import com.ning.billing.util.dao.NonEntityDao;
 
 import com.google.common.collect.ImmutableList;
 
-// Simple unit tests for DefaultSubscriptionTransferApi, see TestTransfer for more advanced tests with dao
+// Simple unit tests for DefaultSubscriptionBaseTransferApi, see TestTransfer for more advanced tests with dao
 public class TestDefaultSubscriptionTransferApi extends SubscriptionTestSuiteNoDB {
 
-    private DefaultSubscriptionTransferApi transferApi;
+    private DefaultSubscriptionBaseTransferApi transferApi;
 
     @Override
     @BeforeMethod(groups = "fast")
@@ -63,10 +63,10 @@ public class TestDefaultSubscriptionTransferApi extends SubscriptionTestSuiteNoD
         final NonEntityDao nonEntityDao = Mockito.mock(NonEntityDao.class);
         final SubscriptionDao dao = Mockito.mock(SubscriptionDao.class);
         final CatalogService catalogService = new MockCatalogService(new MockCatalog());
-        final SubscriptionApiService apiService = Mockito.mock(SubscriptionApiService.class);
-        final SubscriptionTimelineApi timelineApi = Mockito.mock(SubscriptionTimelineApi.class);
+        final SubscriptionBaseApiService apiService = Mockito.mock(SubscriptionBaseApiService.class);
+        final SubscriptionBaseTimelineApi timelineApi = Mockito.mock(SubscriptionBaseTimelineApi.class);
         final InternalCallContextFactory internalCallContextFactory = new InternalCallContextFactory(clock, nonEntityDao, new CacheControllerDispatcher());
-        transferApi = new DefaultSubscriptionTransferApi(clock, dao, timelineApi, catalogService, apiService, internalCallContextFactory);
+        transferApi = new DefaultSubscriptionBaseTransferApi(clock, dao, timelineApi, catalogService, apiService, internalCallContextFactory);
     }
 
     @Test(groups = "fast")
@@ -76,7 +76,7 @@ public class TestDefaultSubscriptionTransferApi extends SubscriptionTestSuiteNoD
         final ImmutableList<ExistingEvent> existingEvents = ImmutableList.<ExistingEvent>of(createEvent(subscriptionStartTime, SubscriptionBaseTransitionType.CREATE),
                                                                                             createEvent(subscriptionCancelTime, SubscriptionBaseTransitionType.CANCEL));
         final SubscriptionBuilder subscriptionBuilder = new SubscriptionBuilder();
-        final SubscriptionData subscription = new SubscriptionData(subscriptionBuilder);
+        final DefaultSubscriptionBase subscription = new DefaultSubscriptionBase(subscriptionBuilder);
 
         final DateTime transferDate = subscriptionStartTime.plusDays(10);
         final List<SubscriptionEvent> events = transferApi.toEvents(existingEvents, subscription, transferDate, callContext);
@@ -91,7 +91,7 @@ public class TestDefaultSubscriptionTransferApi extends SubscriptionTestSuiteNoD
         final ImmutableList<ExistingEvent> existingEvents = ImmutableList.<ExistingEvent>of(createEvent(subscriptionStartTime, SubscriptionBaseTransitionType.CREATE),
                                                                                             createEvent(subscriptionCancelTime, SubscriptionBaseTransitionType.CANCEL));
         final SubscriptionBuilder subscriptionBuilder = new SubscriptionBuilder();
-        final SubscriptionData subscription = new SubscriptionData(subscriptionBuilder);
+        final DefaultSubscriptionBase subscription = new DefaultSubscriptionBase(subscriptionBuilder);
 
         final DateTime transferDate = subscriptionStartTime.plusHours(1);
         final List<SubscriptionEvent> events = transferApi.toEvents(existingEvents, subscription, transferDate, callContext);
@@ -159,10 +159,10 @@ public class TestDefaultSubscriptionTransferApi extends SubscriptionTestSuiteNoD
     }
 
     private List<SubscriptionEvent> transferBundle(final DateTime migrateSubscriptionEventEffectiveDate, final DateTime migrateBillingEventEffectiveDate,
-                                                  final DateTime transferDate) throws SubscriptionTransferApiException {
+                                                  final DateTime transferDate) throws SubscriptionBaseTransferApiException {
         final ImmutableList<ExistingEvent> existingEvents = createMigrateEvents(migrateSubscriptionEventEffectiveDate, migrateBillingEventEffectiveDate);
         final SubscriptionBuilder subscriptionBuilder = new SubscriptionBuilder();
-        final SubscriptionData subscription = new SubscriptionData(subscriptionBuilder);
+        final DefaultSubscriptionBase subscription = new DefaultSubscriptionBase(subscriptionBuilder);
 
         return transferApi.toEvents(existingEvents, subscription, transferDate, callContext);
     }
diff --git a/subscription/src/test/java/com/ning/billing/subscription/api/transfer/TestTransfer.java b/subscription/src/test/java/com/ning/billing/subscription/api/transfer/TestTransfer.java
index 1dc6f63..fc165c3 100644
--- a/subscription/src/test/java/com/ning/billing/subscription/api/transfer/TestTransfer.java
+++ b/subscription/src/test/java/com/ning/billing/subscription/api/transfer/TestTransfer.java
@@ -32,10 +32,10 @@ import com.ning.billing.catalog.api.Plan;
 import com.ning.billing.catalog.api.PriceListSet;
 import com.ning.billing.catalog.api.Product;
 import com.ning.billing.subscription.SubscriptionTestSuiteWithEmbeddedDB;
-import com.ning.billing.subscription.api.migration.SubscriptionMigrationApi.AccountMigration;
-import com.ning.billing.subscription.api.migration.SubscriptionMigrationApiException;
+import com.ning.billing.subscription.api.migration.SubscriptionBaseMigrationApi.AccountMigration;
+import com.ning.billing.subscription.api.migration.SubscriptionBaseMigrationApiException;
+import com.ning.billing.subscription.api.user.DefaultSubscriptionBase;
 import com.ning.billing.subscription.api.user.SubscriptionBaseBundle;
-import com.ning.billing.subscription.api.user.SubscriptionData;
 import com.ning.billing.subscription.api.SubscriptionBaseTransitionType;
 import com.ning.billing.subscription.api.SubscriptionBase;
 import com.ning.billing.subscription.api.user.SubscriptionState;
@@ -102,7 +102,7 @@ public class TestTransfer extends SubscriptionTestSuiteWithEmbeddedDB {
             assertEquals(subscriptionInternalApi.getBillingTransitions(oldBaseSubscription, internalCallContext).size(), 0);
             //assertEquals(subscriptionInternalApi.getBillingTransitions(oldBaseSubscription, internalCallContext).get(0).getTransitionType(), SubscriptionBaseTransitionType.CANCEL);
 
-        } catch (SubscriptionMigrationApiException e) {
+        } catch (SubscriptionBaseMigrationApiException e) {
             Assert.fail("", e);
         }
 
@@ -121,7 +121,7 @@ public class TestTransfer extends SubscriptionTestSuiteWithEmbeddedDB {
         // CREATE BP
         final SubscriptionBase baseSubscription = testUtil.createSubscription(bundle, baseProduct, baseTerm, basePriceList);
 
-        final DateTime evergreenPhaseDate = ((SubscriptionData) baseSubscription).getPendingTransition().getEffectiveTransitionTime();
+        final DateTime evergreenPhaseDate = ((DefaultSubscriptionBase) baseSubscription).getPendingTransition().getEffectiveTransitionTime();
 
         // MOVE A LITTLE, STILL IN TRIAL
         clock.addDays(20);
@@ -148,7 +148,7 @@ public class TestTransfer extends SubscriptionTestSuiteWithEmbeddedDB {
         assertEquals(subscriptions.size(), 1);
 
         final SubscriptionBase newBaseSubscription = subscriptions.get(0);
-        assertTrue(((SubscriptionData) newBaseSubscription).getAlignStartDate().compareTo(((SubscriptionData) oldBaseSubscription).getAlignStartDate()) == 0);
+        assertTrue(((DefaultSubscriptionBase) newBaseSubscription).getAlignStartDate().compareTo(((DefaultSubscriptionBase) oldBaseSubscription).getAlignStartDate()) == 0);
 
         // CHECK NEXT PENDING PHASE IS ALIGNED WITH OLD SUBSCRIPTION START DATE
         assertEquals(subscriptionInternalApi.getAllTransitions(newBaseSubscription, internalCallContext).size(), 2);
@@ -175,7 +175,7 @@ public class TestTransfer extends SubscriptionTestSuiteWithEmbeddedDB {
 
         subscriptionInternalApi.setChargedThroughDate(baseSubscription.getId(), ctd, internalCallContext);
 
-        final DateTime evergreenPhaseDate = ((SubscriptionData) baseSubscription).getPendingTransition().getEffectiveTransitionTime();
+        final DateTime evergreenPhaseDate = ((DefaultSubscriptionBase) baseSubscription).getPendingTransition().getEffectiveTransitionTime();
 
         // MOVE A LITTLE, STILL IN TRIAL
         clock.addDays(20);
@@ -197,7 +197,7 @@ public class TestTransfer extends SubscriptionTestSuiteWithEmbeddedDB {
         assertEquals(subscriptions.size(), 1);
 
         final SubscriptionBase newBaseSubscription = subscriptions.get(0);
-        assertTrue(((SubscriptionData) newBaseSubscription).getAlignStartDate().compareTo(((SubscriptionData) oldBaseSubscription).getAlignStartDate()) == 0);
+        assertTrue(((DefaultSubscriptionBase) newBaseSubscription).getAlignStartDate().compareTo(((DefaultSubscriptionBase) oldBaseSubscription).getAlignStartDate()) == 0);
 
         // CHECK NEXT PENDING PHASE IS ALIGNED WITH OLD SUBSCRIPTION START DATE
         assertEquals(subscriptionInternalApi.getAllTransitions(newBaseSubscription, internalCallContext).size(), 2);
@@ -247,7 +247,7 @@ public class TestTransfer extends SubscriptionTestSuiteWithEmbeddedDB {
         assertEquals(subscriptions.size(), 1);
 
         final SubscriptionBase newBaseSubscription = subscriptions.get(0);
-        assertTrue(((SubscriptionData) newBaseSubscription).getAlignStartDate().compareTo(((SubscriptionData) baseSubscription).getAlignStartDate()) == 0);
+        assertTrue(((DefaultSubscriptionBase) newBaseSubscription).getAlignStartDate().compareTo(((DefaultSubscriptionBase) baseSubscription).getAlignStartDate()) == 0);
 
         // CHECK ONLY ONE PHASE EXISTS
         assertEquals(subscriptionInternalApi.getAllTransitions(newBaseSubscription, internalCallContext).size(), 1);
@@ -296,7 +296,7 @@ public class TestTransfer extends SubscriptionTestSuiteWithEmbeddedDB {
         assertEquals(subscriptions.size(), 1);
 
         final SubscriptionBase newBaseSubscription = subscriptions.get(0);
-        assertTrue(((SubscriptionData) newBaseSubscription).getAlignStartDate().compareTo(((SubscriptionData) baseSubscription).getAlignStartDate()) == 0);
+        assertTrue(((DefaultSubscriptionBase) newBaseSubscription).getAlignStartDate().compareTo(((DefaultSubscriptionBase) baseSubscription).getAlignStartDate()) == 0);
 
         // CHECK ONLY ONE PHASE EXISTS
         assertEquals(subscriptionInternalApi.getAllTransitions(newBaseSubscription, internalCallContext).size(), 1);
@@ -333,8 +333,8 @@ public class TestTransfer extends SubscriptionTestSuiteWithEmbeddedDB {
         assertEquals(newPlan.getProduct().getName(), newBaseProduct1);
         assertEquals(newBaseSubscriptionWithCtd.getCurrentPhase().getPhaseType(), PhaseType.EVERGREEN);
 
-        assertNotNull(((SubscriptionData) newBaseSubscriptionWithCtd).getPendingTransition());
-        assertEquals(((SubscriptionData) newBaseSubscriptionWithCtd).getPendingTransition().getEffectiveTransitionTime(), newCtd);
+        assertNotNull(((DefaultSubscriptionBase) newBaseSubscriptionWithCtd).getPendingTransition());
+        assertEquals(((DefaultSubscriptionBase) newBaseSubscriptionWithCtd).getPendingTransition().getEffectiveTransitionTime(), newCtd);
     }
 
     @Test(groups = "slow")
@@ -353,7 +353,7 @@ public class TestTransfer extends SubscriptionTestSuiteWithEmbeddedDB {
         clock.addDays(3);
         final String aoProduct1 = "Telescopic-Scope";
         final BillingPeriod aoTerm1 = BillingPeriod.MONTHLY;
-        final SubscriptionData aoSubscription1 = testUtil.createSubscription(bundle, aoProduct1, aoTerm1, basePriceList);
+        final DefaultSubscriptionBase aoSubscription1 = testUtil.createSubscription(bundle, aoProduct1, aoTerm1, basePriceList);
         assertEquals(aoSubscription1.getState(), SubscriptionState.ACTIVE);
 
         // MOVE ANOTHER 25 DAYS AND CREATE AO2 [ BP STILL IN TRIAL]
@@ -361,7 +361,7 @@ public class TestTransfer extends SubscriptionTestSuiteWithEmbeddedDB {
         clock.addDays(25);
         final String aoProduct2 = "Laser-Scope";
         final BillingPeriod aoTerm2 = BillingPeriod.MONTHLY;
-        final SubscriptionData aoSubscription2 = testUtil.createSubscription(bundle, aoProduct2, aoTerm2, basePriceList);
+        final DefaultSubscriptionBase aoSubscription2 = testUtil.createSubscription(bundle, aoProduct2, aoTerm2, basePriceList);
         assertEquals(aoSubscription2.getState(), SubscriptionState.ACTIVE);
 
         // MOVE AFTER TRIAL AND AO DISCOUNT PHASE [LASER SCOPE STILL IN DISCOUNT]
@@ -393,16 +393,16 @@ public class TestTransfer extends SubscriptionTestSuiteWithEmbeddedDB {
             final Product curProduct = curPlan.getProduct();
             if (curProduct.getName().equals(baseProduct)) {
                 foundBP = true;
-                assertTrue(((SubscriptionData) cur).getAlignStartDate().compareTo(((SubscriptionData) baseSubscription).getAlignStartDate()) == 0);
-                assertNull(((SubscriptionData) cur).getPendingTransition());
+                assertTrue(((DefaultSubscriptionBase) cur).getAlignStartDate().compareTo(((DefaultSubscriptionBase) baseSubscription).getAlignStartDate()) == 0);
+                assertNull(((DefaultSubscriptionBase) cur).getPendingTransition());
             } else if (curProduct.getName().equals(aoProduct1)) {
                 foundAO1 = true;
-                assertTrue(((SubscriptionData) cur).getAlignStartDate().compareTo((aoSubscription1).getAlignStartDate()) == 0);
-                assertNull(((SubscriptionData) cur).getPendingTransition());
+                assertTrue(((DefaultSubscriptionBase) cur).getAlignStartDate().compareTo((aoSubscription1).getAlignStartDate()) == 0);
+                assertNull(((DefaultSubscriptionBase) cur).getPendingTransition());
             } else if (curProduct.getName().equals(aoProduct2)) {
                 foundAO2 = true;
-                assertTrue(((SubscriptionData) cur).getAlignStartDate().compareTo((aoSubscription2).getAlignStartDate()) == 0);
-                assertNotNull(((SubscriptionData) cur).getPendingTransition());
+                assertTrue(((DefaultSubscriptionBase) cur).getAlignStartDate().compareTo((aoSubscription2).getAlignStartDate()) == 0);
+                assertNotNull(((DefaultSubscriptionBase) cur).getPendingTransition());
             } else {
                 Assert.fail("Unexpected product " + curProduct.getName());
             }
@@ -447,7 +447,7 @@ public class TestTransfer extends SubscriptionTestSuiteWithEmbeddedDB {
         clock.addDays(3);
         final String aoProduct1 = "Telescopic-Scope";
         final BillingPeriod aoTerm1 = BillingPeriod.MONTHLY;
-        final SubscriptionData aoSubscription1 = testUtil.createSubscription(bundle, aoProduct1, aoTerm1, basePriceList);
+        final DefaultSubscriptionBase aoSubscription1 = testUtil.createSubscription(bundle, aoProduct1, aoTerm1, basePriceList);
         assertEquals(aoSubscription1.getState(), SubscriptionState.ACTIVE);
 
         testListener.pushExpectedEvent(NextEvent.PHASE);
diff --git a/subscription/src/test/java/com/ning/billing/subscription/api/user/TestSubscriptionHelper.java b/subscription/src/test/java/com/ning/billing/subscription/api/user/TestSubscriptionHelper.java
index f11d5d5..75cb4a8 100644
--- a/subscription/src/test/java/com/ning/billing/subscription/api/user/TestSubscriptionHelper.java
+++ b/subscription/src/test/java/com/ning/billing/subscription/api/user/TestSubscriptionHelper.java
@@ -44,21 +44,21 @@ import com.ning.billing.catalog.api.ProductCategory;
 import com.ning.billing.catalog.api.TimeUnit;
 import com.ning.billing.clock.Clock;
 import com.ning.billing.subscription.api.SubscriptionBaseTransitionType;
-import com.ning.billing.subscription.api.migration.SubscriptionMigrationApi.AccountMigration;
-import com.ning.billing.subscription.api.migration.SubscriptionMigrationApi.BundleMigration;
-import com.ning.billing.subscription.api.migration.SubscriptionMigrationApi.SubscriptionMigration;
-import com.ning.billing.subscription.api.migration.SubscriptionMigrationApi.SubscriptionMigrationCase;
+import com.ning.billing.subscription.api.migration.SubscriptionBaseMigrationApi.AccountMigration;
+import com.ning.billing.subscription.api.migration.SubscriptionBaseMigrationApi.BundleMigration;
+import com.ning.billing.subscription.api.migration.SubscriptionBaseMigrationApi.SubscriptionMigration;
+import com.ning.billing.subscription.api.migration.SubscriptionBaseMigrationApi.SubscriptionMigrationCase;
+import com.ning.billing.subscription.api.timeline.SubscriptionBaseRepairException;
+import com.ning.billing.subscription.api.timeline.SubscriptionBaseTimeline;
 import com.ning.billing.subscription.engine.dao.SubscriptionDao;
 import com.ning.billing.subscription.events.SubscriptionEvent;
 import com.ning.billing.subscription.events.phase.PhaseEvent;
 import com.ning.billing.subscription.events.user.ApiEvent;
 import com.ning.billing.subscription.events.user.ApiEventType;
-import com.ning.billing.subscription.api.timeline.BundleTimeline;
-import com.ning.billing.subscription.api.timeline.SubscriptionRepairException;
-import com.ning.billing.subscription.api.timeline.SubscriptionTimeline;
-import com.ning.billing.subscription.api.timeline.SubscriptionTimeline.DeletedEvent;
-import com.ning.billing.subscription.api.timeline.SubscriptionTimeline.ExistingEvent;
-import com.ning.billing.subscription.api.timeline.SubscriptionTimeline.NewEvent;
+import com.ning.billing.subscription.api.timeline.BundleBaseTimeline;
+import com.ning.billing.subscription.api.timeline.SubscriptionBaseTimeline.DeletedEvent;
+import com.ning.billing.subscription.api.timeline.SubscriptionBaseTimeline.ExistingEvent;
+import com.ning.billing.subscription.api.timeline.SubscriptionBaseTimeline.NewEvent;
 import com.ning.billing.util.callcontext.InternalCallContext;
 import com.ning.billing.util.events.EffectiveSubscriptionInternalEvent;
 import com.ning.billing.util.svcapi.subscription.SubscriptionBaseInternalApi;
@@ -93,20 +93,20 @@ public class TestSubscriptionHelper {
     }
 
 
-    public SubscriptionData createSubscription(final SubscriptionBaseBundle bundle, final String productName, final BillingPeriod term, final String planSet, final DateTime requestedDate)
+    public DefaultSubscriptionBase createSubscription(final SubscriptionBaseBundle bundle, final String productName, final BillingPeriod term, final String planSet, final DateTime requestedDate)
             throws SubscriptionBaseApiException {
         return createSubscriptionWithBundle(bundle.getId(), productName, term, planSet, requestedDate);
     }
 
-    public SubscriptionData createSubscription(final SubscriptionBaseBundle bundle, final String productName, final BillingPeriod term, final String planSet)
+    public DefaultSubscriptionBase createSubscription(final SubscriptionBaseBundle bundle, final String productName, final BillingPeriod term, final String planSet)
             throws SubscriptionBaseApiException {
         return createSubscriptionWithBundle(bundle.getId(), productName, term, planSet, null);
     }
 
-    public SubscriptionData createSubscriptionWithBundle(final UUID bundleId, final String productName, final BillingPeriod term, final String planSet, final DateTime requestedDate)
+    public DefaultSubscriptionBase createSubscriptionWithBundle(final UUID bundleId, final String productName, final BillingPeriod term, final String planSet, final DateTime requestedDate)
             throws SubscriptionBaseApiException {
         testListener.pushExpectedEvent(NextEvent.CREATE);
-        final SubscriptionData subscription = (SubscriptionData) subscriptionApi.createSubscription(bundleId,
+        final DefaultSubscriptionBase subscription = (DefaultSubscriptionBase) subscriptionApi.createSubscription(bundleId,
                                                                                                    new PlanPhaseSpecifier(productName, ProductCategory.BASE, term, planSet, null),
                                                                                                    requestedDate == null ? clock.getUTCNow() : requestedDate, callContext);
         assertNotNull(subscription);
@@ -115,7 +115,7 @@ public class TestSubscriptionHelper {
         return subscription;
     }
 
-    public void checkNextPhaseChange(final SubscriptionData subscription, final int expPendingEvents, final DateTime expPhaseChange) {
+    public void checkNextPhaseChange(final DefaultSubscriptionBase subscription, final int expPendingEvents, final DateTime expPhaseChange) {
         final List<SubscriptionEvent> events = dao.getPendingEventsForSubscription(subscription.getId(), callContext);
         assertNotNull(events);
         printEvents(events);
@@ -388,8 +388,8 @@ public class TestSubscriptionHelper {
     }
 
 
-    public SubscriptionTimeline createSubscriptionRepair(final UUID id, final List<DeletedEvent> deletedEvents, final List<NewEvent> newEvents) {
-        return new SubscriptionTimeline() {
+    public SubscriptionBaseTimeline createSubscriptionRepair(final UUID id, final List<DeletedEvent> deletedEvents, final List<NewEvent> newEvents) {
+        return new SubscriptionBaseTimeline() {
             @Override
             public UUID getId() {
                 return id;
@@ -427,15 +427,15 @@ public class TestSubscriptionHelper {
         };
     }
 
-    public BundleTimeline createBundleRepair(final UUID bundleId, final String viewId, final List<SubscriptionTimeline> subscriptionRepair) {
-        return new BundleTimeline() {
+    public BundleBaseTimeline createBundleRepair(final UUID bundleId, final String viewId, final List<SubscriptionBaseTimeline> subscriptionRepair) {
+        return new BundleBaseTimeline() {
             @Override
             public String getViewId() {
                 return viewId;
             }
 
             @Override
-            public List<SubscriptionTimeline> getSubscriptions() {
+            public List<SubscriptionBaseTimeline> getSubscriptions() {
                 return subscriptionRepair;
             }
 
@@ -498,8 +498,8 @@ public class TestSubscriptionHelper {
         };
     }
 
-    public SubscriptionTimeline getSubscriptionRepair(final UUID id, final BundleTimeline bundleRepair) {
-        for (final SubscriptionTimeline cur : bundleRepair.getSubscriptions()) {
+    public SubscriptionBaseTimeline getSubscriptionRepair(final UUID id, final BundleBaseTimeline bundleRepair) {
+        for (final SubscriptionBaseTimeline cur : bundleRepair.getSubscriptions()) {
             if (cur.getId().equals(id)) {
                 return cur;
             }
@@ -551,11 +551,11 @@ public class TestSubscriptionHelper {
         };
     }
 
-    public void sortEventsOnBundle(final BundleTimeline bundle) {
+    public void sortEventsOnBundle(final BundleBaseTimeline bundle) {
         if (bundle.getSubscriptions() == null) {
             return;
         }
-        for (final SubscriptionTimeline cur : bundle.getSubscriptions()) {
+        for (final SubscriptionBaseTimeline cur : bundle.getSubscriptions()) {
             if (cur.getExistingEvents() != null) {
                 sortExistingEvent(cur.getExistingEvents());
             }
@@ -665,7 +665,7 @@ public class TestSubscriptionHelper {
 
     public interface TestWithExceptionCallback {
 
-        public void doTest() throws SubscriptionRepairException, SubscriptionBaseApiException;
+        public void doTest() throws SubscriptionBaseRepairException, SubscriptionBaseApiException;
     }
 
     public static class TestWithException {
@@ -674,7 +674,7 @@ public class TestSubscriptionHelper {
             try {
                 callback.doTest();
                 Assert.fail("Failed to catch exception " + code);
-            } catch (SubscriptionRepairException e) {
+            } catch (SubscriptionBaseRepairException e) {
                 assertEquals(e.getCode(), code.getCode());
             }
         }
diff --git a/subscription/src/test/java/com/ning/billing/subscription/api/user/TestUserApiAddOn.java b/subscription/src/test/java/com/ning/billing/subscription/api/user/TestUserApiAddOn.java
index 32f1675..5ed83c8 100644
--- a/subscription/src/test/java/com/ning/billing/subscription/api/user/TestUserApiAddOn.java
+++ b/subscription/src/test/java/com/ning/billing/subscription/api/user/TestUserApiAddOn.java
@@ -53,13 +53,13 @@ public class TestUserApiAddOn extends SubscriptionTestSuiteWithEmbeddedDB {
             final BillingPeriod baseTerm = BillingPeriod.ANNUAL;
             final String basePriceList = PriceListSet.DEFAULT_PRICELIST_NAME;
 
-            SubscriptionData baseSubscription = testUtil.createSubscription(bundle, baseProduct, baseTerm, basePriceList);
+            DefaultSubscriptionBase baseSubscription = testUtil.createSubscription(bundle, baseProduct, baseTerm, basePriceList);
 
             final String aoProduct = "Telescopic-Scope";
             final BillingPeriod aoTerm = BillingPeriod.MONTHLY;
             final String aoPriceList = PriceListSet.DEFAULT_PRICELIST_NAME;
 
-            SubscriptionData aoSubscription = testUtil.createSubscription(bundle, aoProduct, aoTerm, aoPriceList);
+            DefaultSubscriptionBase aoSubscription = testUtil.createSubscription(bundle, aoProduct, aoTerm, aoPriceList);
             assertEquals(aoSubscription.getState(), SubscriptionState.ACTIVE);
 
             testListener.pushExpectedEvent(NextEvent.CANCEL);
@@ -67,7 +67,7 @@ public class TestUserApiAddOn extends SubscriptionTestSuiteWithEmbeddedDB {
             aoSubscription.cancel(now, callContext);
 
             assertTrue(testListener.isCompleted(5000));
-            aoSubscription = (SubscriptionData) subscriptionInternalApi.getSubscriptionFromId(aoSubscription.getId(), internalCallContext);
+            aoSubscription = (DefaultSubscriptionBase) subscriptionInternalApi.getSubscriptionFromId(aoSubscription.getId(), internalCallContext);
             assertEquals(aoSubscription.getState(), SubscriptionState.CANCELLED);
 
 
@@ -84,13 +84,13 @@ public class TestUserApiAddOn extends SubscriptionTestSuiteWithEmbeddedDB {
             final BillingPeriod baseTerm = BillingPeriod.ANNUAL;
             final String basePriceList = PriceListSet.DEFAULT_PRICELIST_NAME;
 
-            SubscriptionData baseSubscription = testUtil.createSubscription(bundle, baseProduct, baseTerm, basePriceList);
+            DefaultSubscriptionBase baseSubscription = testUtil.createSubscription(bundle, baseProduct, baseTerm, basePriceList);
 
             final String aoProduct = "Telescopic-Scope";
             final BillingPeriod aoTerm = BillingPeriod.MONTHLY;
             final String aoPriceList = PriceListSet.DEFAULT_PRICELIST_NAME;
 
-            SubscriptionData aoSubscription = testUtil.createSubscription(bundle, aoProduct, aoTerm, aoPriceList);
+            DefaultSubscriptionBase aoSubscription = testUtil.createSubscription(bundle, aoProduct, aoTerm, aoPriceList);
             assertEquals(aoSubscription.getState(), SubscriptionState.ACTIVE);
 
             // Move clock after a month
@@ -111,25 +111,25 @@ public class TestUserApiAddOn extends SubscriptionTestSuiteWithEmbeddedDB {
             final DateTime newBPChargedThroughDate = TestSubscriptionHelper.addDuration(now, bpCtd);
             subscriptionInternalApi.setChargedThroughDate(baseSubscription.getId(), newBPChargedThroughDate, internalCallContext);
 
-            baseSubscription = (SubscriptionData) subscriptionInternalApi.getSubscriptionFromId(baseSubscription.getId(), internalCallContext);
-            aoSubscription = (SubscriptionData) subscriptionInternalApi.getSubscriptionFromId(aoSubscription.getId(), internalCallContext);
+            baseSubscription = (DefaultSubscriptionBase) subscriptionInternalApi.getSubscriptionFromId(baseSubscription.getId(), internalCallContext);
+            aoSubscription = (DefaultSubscriptionBase) subscriptionInternalApi.getSubscriptionFromId(aoSubscription.getId(), internalCallContext);
 
             it = new Interval(clock.getUTCNow(), clock.getUTCNow().plusDays(1));
             clock.addDeltaFromReality(it.toDurationMillis());
 
             // CANCEL AO
             aoSubscription.cancel(clock.getUTCNow(), callContext);
-            aoSubscription = (SubscriptionData) subscriptionInternalApi.getSubscriptionFromId(aoSubscription.getId(), internalCallContext);
+            aoSubscription = (DefaultSubscriptionBase) subscriptionInternalApi.getSubscriptionFromId(aoSubscription.getId(), internalCallContext);
             assertEquals(aoSubscription.getState(), SubscriptionState.ACTIVE);
             assertTrue(aoSubscription.isSubscriptionFutureCancelled());
 
             // CANCEL BASE NOW
             baseSubscription.cancel(clock.getUTCNow(), callContext);
-            baseSubscription = (SubscriptionData) subscriptionInternalApi.getSubscriptionFromId(baseSubscription.getId(), internalCallContext);
+            baseSubscription = (DefaultSubscriptionBase) subscriptionInternalApi.getSubscriptionFromId(baseSubscription.getId(), internalCallContext);
             assertEquals(baseSubscription.getState(), SubscriptionState.ACTIVE);
             assertTrue(baseSubscription.isSubscriptionFutureCancelled());
 
-            aoSubscription = (SubscriptionData) subscriptionInternalApi.getSubscriptionFromId(aoSubscription.getId(), internalCallContext);
+            aoSubscription = (DefaultSubscriptionBase) subscriptionInternalApi.getSubscriptionFromId(aoSubscription.getId(), internalCallContext);
             List<SubscriptionBaseTransition> aoTransitions =  aoSubscription.getAllTransitions();
             assertEquals(aoTransitions.size(), 3);
             assertEquals(aoTransitions.get(0).getTransitionType(), SubscriptionBaseTransitionType.CREATE);
@@ -141,7 +141,7 @@ public class TestUserApiAddOn extends SubscriptionTestSuiteWithEmbeddedDB {
             aoSubscription.uncancel(callContext);
             assertTrue(testListener.isCompleted(5000));
 
-            aoSubscription = (SubscriptionData) subscriptionInternalApi.getSubscriptionFromId(aoSubscription.getId(), internalCallContext);
+            aoSubscription = (DefaultSubscriptionBase) subscriptionInternalApi.getSubscriptionFromId(aoSubscription.getId(), internalCallContext);
             aoTransitions =  aoSubscription.getAllTransitions();
             assertEquals(aoTransitions.size(), 3);
             assertEquals(aoTransitions.get(0).getTransitionType(), SubscriptionBaseTransitionType.CREATE);
@@ -166,13 +166,13 @@ public class TestUserApiAddOn extends SubscriptionTestSuiteWithEmbeddedDB {
             final String basePriceList = PriceListSet.DEFAULT_PRICELIST_NAME;
 
             // CREATE BP
-            SubscriptionData baseSubscription = testUtil.createSubscription(bundle, baseProduct, baseTerm, basePriceList);
+            DefaultSubscriptionBase baseSubscription = testUtil.createSubscription(bundle, baseProduct, baseTerm, basePriceList);
 
             final String aoProduct = "Telescopic-Scope";
             final BillingPeriod aoTerm = BillingPeriod.MONTHLY;
             final String aoPriceList = PriceListSet.DEFAULT_PRICELIST_NAME;
 
-            SubscriptionData aoSubscription = testUtil.createSubscription(bundle, aoProduct, aoTerm, aoPriceList);
+            DefaultSubscriptionBase aoSubscription = testUtil.createSubscription(bundle, aoProduct, aoTerm, aoPriceList);
 
             testListener.reset();
             testListener.pushExpectedEvent(NextEvent.PHASE);
@@ -189,13 +189,13 @@ public class TestUserApiAddOn extends SubscriptionTestSuiteWithEmbeddedDB {
             // Why not just use clock.getUTCNow().plusMonths(1) ?
             final DateTime newChargedThroughDate = TestSubscriptionHelper.addDuration(now, ctd);
             subscriptionInternalApi.setChargedThroughDate(baseSubscription.getId(), newChargedThroughDate, internalCallContext);
-            baseSubscription = (SubscriptionData) subscriptionInternalApi.getSubscriptionFromId(baseSubscription.getId(), internalCallContext);
+            baseSubscription = (DefaultSubscriptionBase) subscriptionInternalApi.getSubscriptionFromId(baseSubscription.getId(), internalCallContext);
 
             // FUTURE CANCELLATION
             baseSubscription.cancel(now, callContext);
 
             // REFETCH AO SUBSCRIPTION AND CHECK THIS IS ACTIVE
-            aoSubscription = (SubscriptionData) subscriptionInternalApi.getSubscriptionFromId(aoSubscription.getId(), internalCallContext);
+            aoSubscription = (DefaultSubscriptionBase) subscriptionInternalApi.getSubscriptionFromId(aoSubscription.getId(), internalCallContext);
             assertEquals(aoSubscription.getState(), SubscriptionState.ACTIVE);
             assertTrue(aoSubscription.isSubscriptionFutureCancelled());
 
@@ -209,7 +209,7 @@ public class TestUserApiAddOn extends SubscriptionTestSuiteWithEmbeddedDB {
             assertTrue(testListener.isCompleted(5000));
 
             // REFETCH AO SUBSCRIPTION AND CHECK THIS IS CANCELLED
-            aoSubscription = (SubscriptionData) subscriptionInternalApi.getSubscriptionFromId(aoSubscription.getId(), internalCallContext);
+            aoSubscription = (DefaultSubscriptionBase) subscriptionInternalApi.getSubscriptionFromId(aoSubscription.getId(), internalCallContext);
             assertEquals(aoSubscription.getState(), SubscriptionState.CANCELLED);
 
             assertListenerStatus();
@@ -228,13 +228,13 @@ public class TestUserApiAddOn extends SubscriptionTestSuiteWithEmbeddedDB {
             final String basePriceList = PriceListSet.DEFAULT_PRICELIST_NAME;
 
             // CREATE BP
-            SubscriptionData baseSubscription = testUtil.createSubscription(bundle, baseProduct, baseTerm, basePriceList);
+            DefaultSubscriptionBase baseSubscription = testUtil.createSubscription(bundle, baseProduct, baseTerm, basePriceList);
 
             final String aoProduct = "Telescopic-Scope";
             final BillingPeriod aoTerm = BillingPeriod.MONTHLY;
             final String aoPriceList = PriceListSet.DEFAULT_PRICELIST_NAME;
 
-            SubscriptionData aoSubscription = testUtil.createSubscription(bundle, aoProduct, aoTerm, aoPriceList);
+            DefaultSubscriptionBase aoSubscription = testUtil.createSubscription(bundle, aoProduct, aoTerm, aoPriceList);
 
             testListener.reset();
             testListener.pushExpectedEvent(NextEvent.PHASE);
@@ -251,24 +251,24 @@ public class TestUserApiAddOn extends SubscriptionTestSuiteWithEmbeddedDB {
             // Why not just use clock.getUTCNow().plusMonths(1) ?
             final DateTime newChargedThroughDate = TestSubscriptionHelper.addDuration(now, ctd);
             subscriptionInternalApi.setChargedThroughDate(baseSubscription.getId(), newChargedThroughDate, internalCallContext);
-            baseSubscription = (SubscriptionData) subscriptionInternalApi.getSubscriptionFromId(baseSubscription.getId(), internalCallContext);
+            baseSubscription = (DefaultSubscriptionBase) subscriptionInternalApi.getSubscriptionFromId(baseSubscription.getId(), internalCallContext);
 
             // FUTURE CANCELLATION
             baseSubscription.cancel(now, callContext);
 
             // REFETCH AO SUBSCRIPTION AND CHECK THIS IS ACTIVE
-            aoSubscription = (SubscriptionData) subscriptionInternalApi.getSubscriptionFromId(aoSubscription.getId(), internalCallContext);
+            aoSubscription = (DefaultSubscriptionBase) subscriptionInternalApi.getSubscriptionFromId(aoSubscription.getId(), internalCallContext);
             assertEquals(aoSubscription.getState(), SubscriptionState.ACTIVE);
             assertTrue(aoSubscription.isSubscriptionFutureCancelled());
 
 
             testListener.reset();
             testListener.pushExpectedEvent(NextEvent.UNCANCEL);
-            baseSubscription = (SubscriptionData) subscriptionInternalApi.getSubscriptionFromId(baseSubscription.getId(), internalCallContext);
+            baseSubscription = (DefaultSubscriptionBase) subscriptionInternalApi.getSubscriptionFromId(baseSubscription.getId(), internalCallContext);
             baseSubscription.uncancel(callContext);
             assertTrue(testListener.isCompleted(5000));
 
-            aoSubscription = (SubscriptionData) subscriptionInternalApi.getSubscriptionFromId(aoSubscription.getId(), internalCallContext);
+            aoSubscription = (DefaultSubscriptionBase) subscriptionInternalApi.getSubscriptionFromId(aoSubscription.getId(), internalCallContext);
             assertEquals(aoSubscription.getState(), SubscriptionState.ACTIVE);
             assertFalse(aoSubscription.isSubscriptionFutureCancelled());
 
@@ -276,13 +276,13 @@ public class TestUserApiAddOn extends SubscriptionTestSuiteWithEmbeddedDB {
             it = new Interval(clock.getUTCNow(), clock.getUTCNow().plusDays(1));
             clock.addDeltaFromReality(it.toDurationMillis());
 
-            baseSubscription = (SubscriptionData) subscriptionInternalApi.getSubscriptionFromId(baseSubscription.getId(), internalCallContext);
+            baseSubscription = (DefaultSubscriptionBase) subscriptionInternalApi.getSubscriptionFromId(baseSubscription.getId(), internalCallContext);
             baseSubscription.cancel(clock.getUTCNow(), callContext);
-            baseSubscription = (SubscriptionData) subscriptionInternalApi.getSubscriptionFromId(baseSubscription.getId(), internalCallContext);
+            baseSubscription = (DefaultSubscriptionBase) subscriptionInternalApi.getSubscriptionFromId(baseSubscription.getId(), internalCallContext);
             assertEquals(baseSubscription.getState(), SubscriptionState.ACTIVE);
             assertTrue(baseSubscription.isSubscriptionFutureCancelled());
 
-            aoSubscription = (SubscriptionData) subscriptionInternalApi.getSubscriptionFromId(aoSubscription.getId(), internalCallContext);
+            aoSubscription = (DefaultSubscriptionBase) subscriptionInternalApi.getSubscriptionFromId(aoSubscription.getId(), internalCallContext);
             assertEquals(aoSubscription.getState(), SubscriptionState.ACTIVE);
             assertTrue(aoSubscription.isSubscriptionFutureCancelled());
             assertListenerStatus();
@@ -303,13 +303,13 @@ public class TestUserApiAddOn extends SubscriptionTestSuiteWithEmbeddedDB {
             final String basePriceList = PriceListSet.DEFAULT_PRICELIST_NAME;
 
             // CREATE BP
-            SubscriptionData baseSubscription = testUtil.createSubscription(bundle, baseProduct, baseTerm, basePriceList);
+            DefaultSubscriptionBase baseSubscription = testUtil.createSubscription(bundle, baseProduct, baseTerm, basePriceList);
 
             final String aoProduct = "Telescopic-Scope";
             final BillingPeriod aoTerm = BillingPeriod.MONTHLY;
             final String aoPriceList = PriceListSet.DEFAULT_PRICELIST_NAME;
 
-            SubscriptionData aoSubscription = testUtil.createSubscription(bundle, aoProduct, aoTerm, aoPriceList);
+            DefaultSubscriptionBase aoSubscription = testUtil.createSubscription(bundle, aoProduct, aoTerm, aoPriceList);
 
             testListener.reset();
             testListener.pushExpectedEvent(NextEvent.PHASE);
@@ -325,7 +325,7 @@ public class TestUserApiAddOn extends SubscriptionTestSuiteWithEmbeddedDB {
             final Duration ctd = testUtil.getDurationMonth(1);
             final DateTime newChargedThroughDate = TestSubscriptionHelper.addDuration(now, ctd);
             subscriptionInternalApi.setChargedThroughDate(baseSubscription.getId(), newChargedThroughDate, internalCallContext);
-            baseSubscription = (SubscriptionData) subscriptionInternalApi.getSubscriptionFromId(baseSubscription.getId(), internalCallContext);
+            baseSubscription = (DefaultSubscriptionBase) subscriptionInternalApi.getSubscriptionFromId(baseSubscription.getId(), internalCallContext);
 
             // CHANGE IMMEDIATELY WITH TO BP WITH NON INCLUDED ADDON
             final String newBaseProduct = "Assault-Rifle";
@@ -349,7 +349,7 @@ public class TestUserApiAddOn extends SubscriptionTestSuiteWithEmbeddedDB {
             assertTrue(testListener.isCompleted(5000));
 
             // REFETCH AO SUBSCRIPTION AND CHECK THIS CANCELLED
-            aoSubscription = (SubscriptionData) subscriptionInternalApi.getSubscriptionFromId(aoSubscription.getId(), internalCallContext);
+            aoSubscription = (DefaultSubscriptionBase) subscriptionInternalApi.getSubscriptionFromId(aoSubscription.getId(), internalCallContext);
             assertEquals(aoSubscription.getState(), SubscriptionState.CANCELLED);
 
             assertListenerStatus();
@@ -366,13 +366,13 @@ public class TestUserApiAddOn extends SubscriptionTestSuiteWithEmbeddedDB {
             final String basePriceList = PriceListSet.DEFAULT_PRICELIST_NAME;
 
             // CREATE BP
-            SubscriptionData baseSubscription = testUtil.createSubscription(bundle, baseProduct, baseTerm, basePriceList);
+            DefaultSubscriptionBase baseSubscription = testUtil.createSubscription(bundle, baseProduct, baseTerm, basePriceList);
 
             final String aoProduct = "Telescopic-Scope";
             final BillingPeriod aoTerm = BillingPeriod.MONTHLY;
             final String aoPriceList = PriceListSet.DEFAULT_PRICELIST_NAME;
 
-            SubscriptionData aoSubscription = testUtil.createSubscription(bundle, aoProduct, aoTerm, aoPriceList);
+            DefaultSubscriptionBase aoSubscription = testUtil.createSubscription(bundle, aoProduct, aoTerm, aoPriceList);
 
             testListener.reset();
             testListener.pushExpectedEvent(NextEvent.PHASE);
@@ -388,7 +388,7 @@ public class TestUserApiAddOn extends SubscriptionTestSuiteWithEmbeddedDB {
             final Duration ctd = testUtil.getDurationMonth(1);
             final DateTime newChargedThroughDate = TestSubscriptionHelper.addDuration(now, ctd);
             subscriptionInternalApi.setChargedThroughDate(baseSubscription.getId(), newChargedThroughDate, internalCallContext);
-            baseSubscription = (SubscriptionData) subscriptionInternalApi.getSubscriptionFromId(baseSubscription.getId(), internalCallContext);
+            baseSubscription = (DefaultSubscriptionBase) subscriptionInternalApi.getSubscriptionFromId(baseSubscription.getId(), internalCallContext);
 
             // CHANGE IMMEDIATELY WITH TO BP WITH NON AVAILABLE ADDON
             final String newBaseProduct = "Pistol";
@@ -408,7 +408,7 @@ public class TestUserApiAddOn extends SubscriptionTestSuiteWithEmbeddedDB {
             baseSubscription.changePlan(newBaseProduct, newBaseTerm, newBasePriceList, now, callContext);
 
             // REFETCH AO SUBSCRIPTION AND CHECK THIS IS ACTIVE
-            aoSubscription = (SubscriptionData) subscriptionInternalApi.getSubscriptionFromId(aoSubscription.getId(), internalCallContext);
+            aoSubscription = (DefaultSubscriptionBase) subscriptionInternalApi.getSubscriptionFromId(aoSubscription.getId(), internalCallContext);
             assertEquals(aoSubscription.getState(), SubscriptionState.ACTIVE);
             assertTrue(aoSubscription.isSubscriptionFutureCancelled());
 
@@ -421,7 +421,7 @@ public class TestUserApiAddOn extends SubscriptionTestSuiteWithEmbeddedDB {
             assertTrue(testListener.isCompleted(5000));
 
             // REFETCH AO SUBSCRIPTION AND CHECK THIS CANCELLED
-            aoSubscription = (SubscriptionData) subscriptionInternalApi.getSubscriptionFromId(aoSubscription.getId(), internalCallContext);
+            aoSubscription = (DefaultSubscriptionBase) subscriptionInternalApi.getSubscriptionFromId(aoSubscription.getId(), internalCallContext);
             assertEquals(aoSubscription.getState(), SubscriptionState.CANCELLED);
 
             assertListenerStatus();
@@ -483,7 +483,7 @@ public class TestUserApiAddOn extends SubscriptionTestSuiteWithEmbeddedDB {
             final String basePriceList = PriceListSet.DEFAULT_PRICELIST_NAME;
 
             // CREATE BP
-            final SubscriptionData baseSubscription = testUtil.createSubscription(bundle, baseProduct, baseTerm, basePriceList);
+            final DefaultSubscriptionBase baseSubscription = testUtil.createSubscription(bundle, baseProduct, baseTerm, basePriceList);
 
             // MOVE CLOCK 14 DAYS LATER
             Interval it = new Interval(clock.getUTCNow(), clock.getUTCNow().plusDays(14));
@@ -491,7 +491,7 @@ public class TestUserApiAddOn extends SubscriptionTestSuiteWithEmbeddedDB {
 
             // CREATE ADDON
             final DateTime beforeAOCreation = clock.getUTCNow();
-            SubscriptionData aoSubscription = testUtil.createSubscription(bundle, aoProduct, aoTerm, aoPriceList);
+            DefaultSubscriptionBase aoSubscription = testUtil.createSubscription(bundle, aoProduct, aoTerm, aoPriceList);
             final DateTime afterAOCreation = clock.getUTCNow();
 
             // CHECK EVERYTHING
@@ -527,7 +527,7 @@ public class TestUserApiAddOn extends SubscriptionTestSuiteWithEmbeddedDB {
             assertTrue(testListener.isCompleted(5000));
 
             // CHECK EVERYTHING AGAIN
-            aoSubscription = (SubscriptionData) subscriptionInternalApi.getSubscriptionFromId(aoSubscription.getId(), internalCallContext);
+            aoSubscription = (DefaultSubscriptionBase) subscriptionInternalApi.getSubscriptionFromId(aoSubscription.getId(), internalCallContext);
 
             aoCurrentPlan = aoSubscription.getCurrentPlan();
             assertNotNull(aoCurrentPlan);
@@ -539,7 +539,7 @@ public class TestUserApiAddOn extends SubscriptionTestSuiteWithEmbeddedDB {
             assertNotNull(aoCurrentPhase);
             assertEquals(aoCurrentPhase.getPhaseType(), PhaseType.EVERGREEN);
 
-            aoSubscription = (SubscriptionData) subscriptionInternalApi.getSubscriptionFromId(aoSubscription.getId(), internalCallContext);
+            aoSubscription = (DefaultSubscriptionBase) subscriptionInternalApi.getSubscriptionFromId(aoSubscription.getId(), internalCallContext);
             aoPendingTranstion = aoSubscription.getPendingTransition();
             assertNull(aoPendingTranstion);
         } catch (SubscriptionBaseApiException e) {
diff --git a/subscription/src/test/java/com/ning/billing/subscription/api/user/TestUserApiCancel.java b/subscription/src/test/java/com/ning/billing/subscription/api/user/TestUserApiCancel.java
index 3911d5c..6c610d3 100644
--- a/subscription/src/test/java/com/ning/billing/subscription/api/user/TestUserApiCancel.java
+++ b/subscription/src/test/java/com/ning/billing/subscription/api/user/TestUserApiCancel.java
@@ -48,7 +48,7 @@ public class TestUserApiCancel extends SubscriptionTestSuiteWithEmbeddedDB {
             final String planSet = PriceListSet.DEFAULT_PRICELIST_NAME;
 
             // CREATE
-            final SubscriptionData subscription = testUtil.createSubscription(bundle, prod, term, planSet);
+            final DefaultSubscriptionBase subscription = testUtil.createSubscription(bundle, prod, term, planSet);
             PlanPhase currentPhase = subscription.getCurrentPhase();
             assertEquals(currentPhase.getPhaseType(), PhaseType.TRIAL);
 
@@ -93,7 +93,7 @@ public class TestUserApiCancel extends SubscriptionTestSuiteWithEmbeddedDB {
             final String planSet = PriceListSet.DEFAULT_PRICELIST_NAME;
 
             // CREATE
-            SubscriptionData subscription = testUtil.createSubscription(bundle, prod, term, planSet);
+            DefaultSubscriptionBase subscription = testUtil.createSubscription(bundle, prod, term, planSet);
             PlanPhase trialPhase = subscription.getCurrentPhase();
             assertEquals(trialPhase.getPhaseType(), PhaseType.TRIAL);
 
@@ -114,7 +114,7 @@ public class TestUserApiCancel extends SubscriptionTestSuiteWithEmbeddedDB {
             final Duration ctd = testUtil.getDurationMonth(1);
             final DateTime newChargedThroughDate = TestSubscriptionHelper.addDuration(expectedPhaseTrialChange, ctd);
             subscriptionInternalApi.setChargedThroughDate(subscription.getId(), newChargedThroughDate, internalCallContext);
-            subscription = (SubscriptionData) subscriptionInternalApi.getSubscriptionFromId(subscription.getId(), internalCallContext);
+            subscription = (DefaultSubscriptionBase) subscriptionInternalApi.getSubscriptionFromId(subscription.getId(), internalCallContext);
 
             assertEquals(subscription.getLastActiveProductName(), prod);
             assertEquals(subscription.getLastActivePriceListName(), planSet);
@@ -170,7 +170,7 @@ public class TestUserApiCancel extends SubscriptionTestSuiteWithEmbeddedDB {
             final String planSet = PriceListSet.DEFAULT_PRICELIST_NAME;
 
             // CREATE
-            final SubscriptionData subscription = testUtil.createSubscription(bundle, prod, term, planSet);
+            final DefaultSubscriptionBase subscription = testUtil.createSubscription(bundle, prod, term, planSet);
             PlanPhase trialPhase = subscription.getCurrentPhase();
             assertEquals(trialPhase.getPhaseType(), PhaseType.TRIAL);
 
@@ -214,7 +214,7 @@ public class TestUserApiCancel extends SubscriptionTestSuiteWithEmbeddedDB {
             final String planSet = PriceListSet.DEFAULT_PRICELIST_NAME;
 
             // CREATE
-            SubscriptionData subscription = testUtil.createSubscription(bundle, prod, term, planSet);
+            DefaultSubscriptionBase subscription = testUtil.createSubscription(bundle, prod, term, planSet);
             final PlanPhase trialPhase = subscription.getCurrentPhase();
             assertEquals(trialPhase.getPhaseType(), PhaseType.TRIAL);
 
@@ -234,7 +234,7 @@ public class TestUserApiCancel extends SubscriptionTestSuiteWithEmbeddedDB {
             final Duration ctd = testUtil.getDurationMonth(1);
             final DateTime newChargedThroughDate = TestSubscriptionHelper.addDuration(expectedPhaseTrialChange, ctd);
             subscriptionInternalApi.setChargedThroughDate(subscription.getId(), newChargedThroughDate, internalCallContext);
-            subscription = (SubscriptionData) subscriptionInternalApi.getSubscriptionFromId(subscription.getId(), internalCallContext);
+            subscription = (DefaultSubscriptionBase) subscriptionInternalApi.getSubscriptionFromId(subscription.getId(), internalCallContext);
 
             // CANCEL EOT
             subscription.cancel(clock.getUTCNow(), callContext);
diff --git a/subscription/src/test/java/com/ning/billing/subscription/api/user/TestUserApiChangePlan.java b/subscription/src/test/java/com/ning/billing/subscription/api/user/TestUserApiChangePlan.java
index aab03fb..bf9da35 100644
--- a/subscription/src/test/java/com/ning/billing/subscription/api/user/TestUserApiChangePlan.java
+++ b/subscription/src/test/java/com/ning/billing/subscription/api/user/TestUserApiChangePlan.java
@@ -44,7 +44,7 @@ import static org.testng.Assert.assertTrue;
 
 public class TestUserApiChangePlan extends SubscriptionTestSuiteWithEmbeddedDB {
 
-    private void checkChangePlan(final SubscriptionData subscription, final String expProduct, final ProductCategory expCategory,
+    private void checkChangePlan(final DefaultSubscriptionBase subscription, final String expProduct, final ProductCategory expCategory,
                                  final BillingPeriod expBillingPeriod, final PhaseType expPhase) {
 
         final Plan currentPlan = subscription.getCurrentPlan();
@@ -67,7 +67,7 @@ public class TestUserApiChangePlan extends SubscriptionTestSuiteWithEmbeddedDB {
                                                                   final String toProd, final BillingPeriod toTerm, final String toPlanSet) {
         try {
             // CREATE
-            final SubscriptionData subscription = testUtil.createSubscription(bundle, fromProd, fromTerm, fromPlanSet);
+            final DefaultSubscriptionBase subscription = testUtil.createSubscription(bundle, fromProd, fromTerm, fromPlanSet);
 
             // MOVE TO NEXT PHASE
             PlanPhase currentPhase = subscription.getCurrentPhase();
@@ -105,7 +105,7 @@ public class TestUserApiChangePlan extends SubscriptionTestSuiteWithEmbeddedDB {
                                                                    final String toProd, final BillingPeriod toTerm, final String toPlanSet) throws SubscriptionBillingApiException {
         try {
             // CREATE
-            SubscriptionData subscription = testUtil.createSubscription(bundle, fromProd, fromTerm, fromPlanSet);
+            DefaultSubscriptionBase subscription = testUtil.createSubscription(bundle, fromProd, fromTerm, fromPlanSet);
             final PlanPhase trialPhase = subscription.getCurrentPhase();
             final DateTime expectedPhaseTrialChange = TestSubscriptionHelper.addDuration(subscription.getStartDate(), trialPhase.getDuration());
             assertEquals(trialPhase.getPhaseType(), PhaseType.TRIAL);
@@ -126,7 +126,7 @@ public class TestUserApiChangePlan extends SubscriptionTestSuiteWithEmbeddedDB {
             // RE READ SUBSCRIPTION + CHANGE PLAN
             testListener.setNonExpectedMode();
             testListener.pushExpectedEvent(NextEvent.CHANGE);
-            subscription = (SubscriptionData) subscriptionInternalApi.getSubscriptionFromId(subscription.getId(), internalCallContext);
+            subscription = (DefaultSubscriptionBase) subscriptionInternalApi.getSubscriptionFromId(subscription.getId(), internalCallContext);
             subscription.changePlan(toProd, toTerm, toPlanSet, clock.getUTCNow(), callContext);
             assertFalse(testListener.isCompleted(3000));
             testListener.reset();
@@ -149,7 +149,7 @@ public class TestUserApiChangePlan extends SubscriptionTestSuiteWithEmbeddedDB {
             clock.addDeltaFromReality(it.toDurationMillis());
             assertTrue(testListener.isCompleted(5000));
 
-            subscription = (SubscriptionData) subscriptionInternalApi.getSubscriptionFromId(subscription.getId(), internalCallContext);
+            subscription = (DefaultSubscriptionBase) subscriptionInternalApi.getSubscriptionFromId(subscription.getId(), internalCallContext);
             currentPhase = subscription.getCurrentPhase();
             checkChangePlan(subscription, toProd, ProductCategory.BASE, toTerm, PhaseType.DISCOUNT);
 
@@ -168,7 +168,7 @@ public class TestUserApiChangePlan extends SubscriptionTestSuiteWithEmbeddedDB {
                                            final String toProd, final BillingPeriod toTerm, final String toPlanSet) {
 
         try {
-            final SubscriptionData subscription = testUtil.createSubscription(bundle, fromProd, fromTerm, fromPlanSet);
+            final DefaultSubscriptionBase subscription = testUtil.createSubscription(bundle, fromProd, fromTerm, fromPlanSet);
 
             testListener.pushExpectedEvent(NextEvent.CHANGE);
 
@@ -210,7 +210,7 @@ public class TestUserApiChangePlan extends SubscriptionTestSuiteWithEmbeddedDB {
         try {
             DateTime currentTime = clock.getUTCNow();
 
-            SubscriptionData subscription = testUtil.createSubscription(bundle, fromProd, fromTerm, fromPlanSet);
+            DefaultSubscriptionBase subscription = testUtil.createSubscription(bundle, fromProd, fromTerm, fromPlanSet);
             final PlanPhase trialPhase = subscription.getCurrentPhase();
             final DateTime expectedPhaseTrialChange = TestSubscriptionHelper.addDuration(subscription.getStartDate(), trialPhase.getDuration());
             assertEquals(trialPhase.getPhaseType(), PhaseType.TRIAL);
@@ -229,7 +229,7 @@ public class TestUserApiChangePlan extends SubscriptionTestSuiteWithEmbeddedDB {
             subscriptionInternalApi.setChargedThroughDate(subscription.getId(), newChargedThroughDate, internalCallContext);
 
             // RE READ SUBSCRIPTION + CHECK CURRENT PHASE
-            subscription = (SubscriptionData) subscriptionInternalApi.getSubscriptionFromId(subscription.getId(), internalCallContext);
+            subscription = (DefaultSubscriptionBase) subscriptionInternalApi.getSubscriptionFromId(subscription.getId(), internalCallContext);
             PlanPhase currentPhase = subscription.getCurrentPhase();
             assertNotNull(currentPhase);
             assertEquals(currentPhase.getPhaseType(), PhaseType.EVERGREEN);
@@ -290,7 +290,7 @@ public class TestUserApiChangePlan extends SubscriptionTestSuiteWithEmbeddedDB {
     @Test(groups = "slow")
     public void testMultipleChangeLastIMM() throws SubscriptionBillingApiException {
         try {
-            SubscriptionData subscription = testUtil.createSubscription(bundle, "Assault-Rifle", BillingPeriod.MONTHLY, "gunclubDiscount");
+            DefaultSubscriptionBase subscription = testUtil.createSubscription(bundle, "Assault-Rifle", BillingPeriod.MONTHLY, "gunclubDiscount");
             final PlanPhase trialPhase = subscription.getCurrentPhase();
             assertEquals(trialPhase.getPhaseType(), PhaseType.TRIAL);
 
@@ -309,7 +309,7 @@ public class TestUserApiChangePlan extends SubscriptionTestSuiteWithEmbeddedDB {
             final Duration ctd = testUtil.getDurationMonth(1);
             final DateTime newChargedThroughDate = TestSubscriptionHelper.addDuration(startDiscountPhase, ctd);
             subscriptionInternalApi.setChargedThroughDate(subscription.getId(), newChargedThroughDate, internalCallContext);
-            subscription = (SubscriptionData) subscriptionInternalApi.getSubscriptionFromId(subscription.getId(), internalCallContext);
+            subscription = (DefaultSubscriptionBase) subscriptionInternalApi.getSubscriptionFromId(subscription.getId(), internalCallContext);
 
             // CHANGE EOT
             testListener.setNonExpectedMode();
@@ -342,7 +342,7 @@ public class TestUserApiChangePlan extends SubscriptionTestSuiteWithEmbeddedDB {
     @Test(groups = "slow")
     public void testMultipleChangeLastEOT() throws SubscriptionBillingApiException {
         try {
-            SubscriptionData subscription = testUtil.createSubscription(bundle, "Assault-Rifle", BillingPeriod.ANNUAL, "gunclubDiscount");
+            DefaultSubscriptionBase subscription = testUtil.createSubscription(bundle, "Assault-Rifle", BillingPeriod.ANNUAL, "gunclubDiscount");
             final PlanPhase trialPhase = subscription.getCurrentPhase();
             assertEquals(trialPhase.getPhaseType(), PhaseType.TRIAL);
 
@@ -358,7 +358,7 @@ public class TestUserApiChangePlan extends SubscriptionTestSuiteWithEmbeddedDB {
             final Duration ctd = testUtil.getDurationMonth(1);
             final DateTime newChargedThroughDate = TestSubscriptionHelper.addDuration(startDiscountPhase, ctd);
             subscriptionInternalApi.setChargedThroughDate(subscription.getId(), newChargedThroughDate, internalCallContext);
-            subscription = (SubscriptionData) subscriptionInternalApi.getSubscriptionFromId(subscription.getId(), internalCallContext);
+            subscription = (DefaultSubscriptionBase) subscriptionInternalApi.getSubscriptionFromId(subscription.getId(), internalCallContext);
 
             // CHANGE EOT
             testListener.setNonExpectedMode();
@@ -407,7 +407,7 @@ public class TestUserApiChangePlan extends SubscriptionTestSuiteWithEmbeddedDB {
             it = new Interval(clock.getUTCNow(), clock.getUTCNow().plusMonths(6));
             clock.addDeltaFromReality(it.toDurationMillis());
             assertTrue(testListener.isCompleted(5000));
-            subscription = (SubscriptionData) subscriptionInternalApi.getSubscriptionFromId(subscription.getId(), internalCallContext);
+            subscription = (DefaultSubscriptionBase) subscriptionInternalApi.getSubscriptionFromId(subscription.getId(), internalCallContext);
 
             currentPlan = subscription.getCurrentPlan();
             assertNotNull(currentPlan);
@@ -428,7 +428,7 @@ public class TestUserApiChangePlan extends SubscriptionTestSuiteWithEmbeddedDB {
     @Test(groups = "slow")
     public void testCorrectPhaseAlignmentOnChange() {
         try {
-            SubscriptionData subscription = testUtil.createSubscription(bundle, "Shotgun", BillingPeriod.MONTHLY, PriceListSet.DEFAULT_PRICELIST_NAME);
+            DefaultSubscriptionBase subscription = testUtil.createSubscription(bundle, "Shotgun", BillingPeriod.MONTHLY, PriceListSet.DEFAULT_PRICELIST_NAME);
             PlanPhase trialPhase = subscription.getCurrentPhase();
             assertEquals(trialPhase.getPhaseType(), PhaseType.TRIAL);
 
@@ -464,7 +464,7 @@ public class TestUserApiChangePlan extends SubscriptionTestSuiteWithEmbeddedDB {
             trialPhase = subscription.getCurrentPhase();
             assertEquals(trialPhase.getPhaseType(), PhaseType.DISCOUNT);
 
-            subscription = (SubscriptionData) subscriptionInternalApi.getSubscriptionFromId(subscription.getId(), internalCallContext);
+            subscription = (DefaultSubscriptionBase) subscriptionInternalApi.getSubscriptionFromId(subscription.getId(), internalCallContext);
 
             final DateTime expectedNextPhaseDate = subscription.getStartDate().plusDays(30).plusMonths(6);
             final SubscriptionBaseTransition nextPhase = subscription.getPendingTransition();
diff --git a/subscription/src/test/java/com/ning/billing/subscription/api/user/TestUserApiCreate.java b/subscription/src/test/java/com/ning/billing/subscription/api/user/TestUserApiCreate.java
index 2d87693..4ff94e5 100644
--- a/subscription/src/test/java/com/ning/billing/subscription/api/user/TestUserApiCreate.java
+++ b/subscription/src/test/java/com/ning/billing/subscription/api/user/TestUserApiCreate.java
@@ -57,7 +57,7 @@ public class TestUserApiCreate extends SubscriptionTestSuiteWithEmbeddedDB {
             testListener.pushExpectedEvent(NextEvent.PHASE);
             testListener.pushExpectedEvent(NextEvent.CREATE);
 
-            final SubscriptionData subscription = (SubscriptionData) subscriptionInternalApi.createSubscription(bundle.getId(),
+            final DefaultSubscriptionBase subscription = (DefaultSubscriptionBase) subscriptionInternalApi.createSubscription(bundle.getId(),
                                                                                                        testUtil.getProductSpecifier(productName, planSetName, term, null), requestedDate, internalCallContext);
             assertNotNull(subscription);
 
@@ -105,7 +105,7 @@ public class TestUserApiCreate extends SubscriptionTestSuiteWithEmbeddedDB {
 
             testListener.pushExpectedEvent(NextEvent.CREATE);
 
-            final SubscriptionData subscription = (SubscriptionData) subscriptionInternalApi.createSubscription(bundle.getId(),
+            final DefaultSubscriptionBase subscription = (DefaultSubscriptionBase) subscriptionInternalApi.createSubscription(bundle.getId(),
                                                                                                        testUtil.getProductSpecifier(productName, planSetName, term, PhaseType.EVERGREEN), clock.getUTCNow(), internalCallContext);
             assertNotNull(subscription);
 
@@ -143,7 +143,7 @@ public class TestUserApiCreate extends SubscriptionTestSuiteWithEmbeddedDB {
 
             testListener.pushExpectedEvent(NextEvent.CREATE);
 
-            final SubscriptionData subscription = (SubscriptionData) subscriptionInternalApi.createSubscription(bundle.getId(),
+            final DefaultSubscriptionBase subscription = (DefaultSubscriptionBase) subscriptionInternalApi.createSubscription(bundle.getId(),
                                                                                                        testUtil.getProductSpecifier(productName, planSetName, term, null),
                                                                                                        clock.getUTCNow(), internalCallContext);
             assertNotNull(subscription);
@@ -199,7 +199,7 @@ public class TestUserApiCreate extends SubscriptionTestSuiteWithEmbeddedDB {
             testListener.pushExpectedEvent(NextEvent.CREATE);
 
             // CREATE SUBSCRIPTION
-            SubscriptionData subscription = (SubscriptionData) subscriptionInternalApi.createSubscription(bundle.getId(),
+            DefaultSubscriptionBase subscription = (DefaultSubscriptionBase) subscriptionInternalApi.createSubscription(bundle.getId(),
                                                                                                  testUtil.getProductSpecifier(productName, planSetName, term, null), clock.getUTCNow(), internalCallContext);
             assertNotNull(subscription);
 
@@ -223,7 +223,7 @@ public class TestUserApiCreate extends SubscriptionTestSuiteWithEmbeddedDB {
             clock.addDeltaFromReality(it.toDurationMillis());
             assertTrue(testListener.isCompleted(5000));
 
-            subscription = (SubscriptionData) subscriptionInternalApi.getSubscriptionFromId(subscription.getId(), internalCallContext);
+            subscription = (DefaultSubscriptionBase) subscriptionInternalApi.getSubscriptionFromId(subscription.getId(), internalCallContext);
             currentPhase = subscription.getCurrentPhase();
             assertNotNull(currentPhase);
             assertEquals(currentPhase.getPhaseType(), PhaseType.EVERGREEN);
@@ -243,7 +243,7 @@ public class TestUserApiCreate extends SubscriptionTestSuiteWithEmbeddedDB {
 
             testListener.pushExpectedEvent(NextEvent.CREATE);
 
-            final SubscriptionData subscription = (SubscriptionData) subscriptionInternalApi.createSubscription(bundle.getId(),
+            final DefaultSubscriptionBase subscription = (DefaultSubscriptionBase) subscriptionInternalApi.createSubscription(bundle.getId(),
                                                                                                        testUtil.getProductSpecifier(productName, planSetName, term, null), clock.getUTCNow(), internalCallContext);
             assertNotNull(subscription);
 
diff --git a/subscription/src/test/java/com/ning/billing/subscription/api/user/TestUserApiError.java b/subscription/src/test/java/com/ning/billing/subscription/api/user/TestUserApiError.java
index 6732835..7166ab2 100644
--- a/subscription/src/test/java/com/ning/billing/subscription/api/user/TestUserApiError.java
+++ b/subscription/src/test/java/com/ning/billing/subscription/api/user/TestUserApiError.java
@@ -35,7 +35,7 @@ import com.ning.billing.catalog.api.PlanPhase;
 import com.ning.billing.catalog.api.PriceListSet;
 import com.ning.billing.subscription.SubscriptionTestSuiteNoDB;
 import com.ning.billing.subscription.api.SubscriptionBase;
-import com.ning.billing.subscription.exceptions.SubscriptionError;
+import com.ning.billing.subscription.exceptions.SubscriptionBaseError;
 import com.ning.billing.util.callcontext.TenantContext;
 
 import static org.testng.Assert.assertEquals;
@@ -83,7 +83,7 @@ public class TestUserApiError extends SubscriptionTestSuiteNoDB {
     @Test(groups = "fast")
     public void testRecreateSubscriptionBPNotCancelled() {
         try {
-            final SubscriptionData subscription = testUtil.createSubscription(bundle, "Shotgun", BillingPeriod.ANNUAL, PriceListSet.DEFAULT_PRICELIST_NAME);
+            final DefaultSubscriptionBase subscription = testUtil.createSubscription(bundle, "Shotgun", BillingPeriod.ANNUAL, PriceListSet.DEFAULT_PRICELIST_NAME);
             try {
                 subscription.recreate(testUtil.getProductSpecifier("Pistol", PriceListSet.DEFAULT_PRICELIST_NAME, BillingPeriod.MONTHLY, null), clock.getUTCNow(), callContext);
                 Assert.assertFalse(true);
@@ -166,7 +166,7 @@ public class TestUserApiError extends SubscriptionTestSuiteNoDB {
         try {
             subscription.changePlanWithPolicy("Shotgun", BillingPeriod.MONTHLY, PriceListSet.DEFAULT_PRICELIST_NAME, clock.getUTCNow(), BillingActionPolicy.ILLEGAL, callContext);
             Assert.fail();
-        } catch (SubscriptionError error) {
+        } catch (SubscriptionBaseError error) {
             assertTrue(true);
             assertEquals(subscriptionInternalApi.getSubscriptionFromId(subscription.getId(), internalCallContext).getCurrentPlan().getBillingPeriod(), BillingPeriod.ANNUAL);
         }
diff --git a/subscription/src/test/java/com/ning/billing/subscription/api/user/TestUserApiRecreate.java b/subscription/src/test/java/com/ning/billing/subscription/api/user/TestUserApiRecreate.java
index 6a30a74..ceea47d 100644
--- a/subscription/src/test/java/com/ning/billing/subscription/api/user/TestUserApiRecreate.java
+++ b/subscription/src/test/java/com/ning/billing/subscription/api/user/TestUserApiRecreate.java
@@ -57,7 +57,7 @@ public abstract class TestUserApiRecreate extends SubscriptionTestSuiteWithEmbed
         }
     }
 
-    private SubscriptionData testCreateAndRecreate(final boolean fromUserAPi) throws SubscriptionBaseApiException {
+    private DefaultSubscriptionBase testCreateAndRecreate(final boolean fromUserAPi) throws SubscriptionBaseApiException {
         final DateTime init = clock.getUTCNow();
         final DateTime requestedDate = init.minusYears(1);
 
@@ -67,7 +67,7 @@ public abstract class TestUserApiRecreate extends SubscriptionTestSuiteWithEmbed
 
         testListener.pushExpectedEvent(NextEvent.PHASE);
         testListener.pushExpectedEvent(NextEvent.CREATE);
-        SubscriptionData subscription = (SubscriptionData) subscriptionInternalApi.createSubscription(bundle.getId(),
+        DefaultSubscriptionBase subscription = (DefaultSubscriptionBase) subscriptionInternalApi.createSubscription(bundle.getId(),
                                                                                              testUtil.getProductSpecifier(productName, planSetName, term, null), requestedDate, internalCallContext);
         assertNotNull(subscription);
         assertEquals(subscription.getActiveVersion(), SubscriptionEvents.INITIAL_VERSION);
@@ -84,7 +84,7 @@ public abstract class TestUserApiRecreate extends SubscriptionTestSuiteWithEmbed
         try {
 
             if (fromUserAPi) {
-                subscription = (SubscriptionData) subscriptionInternalApi.createSubscription(bundle.getId(),
+                subscription = (DefaultSubscriptionBase) subscriptionInternalApi.createSubscription(bundle.getId(),
                                                                                     testUtil.getProductSpecifier(productName, planSetName, term, null), requestedDate, internalCallContext);
             } else {
                 subscription.recreate(testUtil.getProductSpecifier(productName, planSetName, term, null), requestedDate, callContext);
@@ -109,7 +109,7 @@ public abstract class TestUserApiRecreate extends SubscriptionTestSuiteWithEmbed
         }
 
         if (fromUserAPi) {
-            subscription = (SubscriptionData) subscriptionInternalApi.createSubscription(bundle.getId(),
+            subscription = (DefaultSubscriptionBase) subscriptionInternalApi.createSubscription(bundle.getId(),
                                                                                 testUtil.getProductSpecifier(productName, planSetName, term, null), requestedDate, internalCallContext);
         } else {
             subscription.recreate(testUtil.getProductSpecifier(productName, planSetName, term, null), clock.getUTCNow(), callContext);
diff --git a/subscription/src/test/java/com/ning/billing/subscription/DefaultSubscriptionTestInitializer.java b/subscription/src/test/java/com/ning/billing/subscription/DefaultSubscriptionTestInitializer.java
index da0a20e..058a22d 100644
--- a/subscription/src/test/java/com/ning/billing/subscription/DefaultSubscriptionTestInitializer.java
+++ b/subscription/src/test/java/com/ning/billing/subscription/DefaultSubscriptionTestInitializer.java
@@ -32,9 +32,9 @@ import com.ning.billing.catalog.api.CatalogService;
 import com.ning.billing.catalog.api.Currency;
 import com.ning.billing.clock.ClockMock;
 import com.ning.billing.mock.MockAccountBuilder;
-import com.ning.billing.subscription.api.SubscriptionService;
+import com.ning.billing.subscription.api.SubscriptionBaseService;
 import com.ning.billing.subscription.api.user.SubscriptionBaseBundle;
-import com.ning.billing.subscription.engine.core.DefaultSubscriptionService;
+import com.ning.billing.subscription.engine.core.DefaultSubscriptionBaseService;
 import com.ning.billing.util.callcontext.InternalCallContext;
 import com.ning.billing.util.svcapi.subscription.SubscriptionBaseInternalApi;
 import com.ning.billing.util.svcsapi.bus.BusService;
@@ -88,7 +88,7 @@ public class DefaultSubscriptionTestInitializer implements SubscriptionTestIniti
                                   final TestListenerStatus testListenerStatus,
                                   final ClockMock clock,
                                   final BusService busService,
-                                  final SubscriptionService subscriptionService) throws Exception {
+                                  final SubscriptionBaseService subscriptionBaseService) throws Exception {
         log.warn("STARTING TEST FRAMEWORK");
 
         resetTestListener(testListener, testListenerStatus);
@@ -97,18 +97,18 @@ public class DefaultSubscriptionTestInitializer implements SubscriptionTestIniti
 
         startBusAndRegisterListener(busService, testListener);
 
-        restartSubscriptionService(subscriptionService);
+        restartSubscriptionService(subscriptionBaseService);
 
         log.warn("STARTED TEST FRAMEWORK");
     }
 
     public void stopTestFramework(final TestApiListener testListener,
                                   final BusService busService,
-                                  final SubscriptionService subscriptionService) throws Exception {
+                                  final SubscriptionBaseService subscriptionBaseService) throws Exception {
         log.warn("STOPPING TEST FRAMEWORK");
         stopBusAndUnregisterListener(busService, testListener);
 
-        stopSubscriptionService(subscriptionService);
+        stopSubscriptionService(subscriptionBaseService);
 
         log.warn("STOPPED TEST FRAMEWORK");
     }
@@ -135,10 +135,10 @@ public class DefaultSubscriptionTestInitializer implements SubscriptionTestIniti
         busService.getBus().register(testListener);
     }
 
-    private void restartSubscriptionService(final SubscriptionService subscriptionService) {
+    private void restartSubscriptionService(final SubscriptionBaseService subscriptionBaseService) {
         // START NOTIFICATION QUEUE FOR SUBSCRIPTION
-        ((DefaultSubscriptionService) subscriptionService).initialize();
-        ((DefaultSubscriptionService) subscriptionService).start();
+        ((DefaultSubscriptionBaseService) subscriptionBaseService).initialize();
+        ((DefaultSubscriptionBaseService) subscriptionBaseService).start();
     }
 
     private void stopBusAndUnregisterListener(final BusService busService, final TestApiListener testListener) throws Exception {
@@ -146,7 +146,7 @@ public class DefaultSubscriptionTestInitializer implements SubscriptionTestIniti
         busService.getBus().stop();
     }
 
-    private void stopSubscriptionService(final SubscriptionService subscriptionService) throws Exception {
-        ((DefaultSubscriptionService) subscriptionService).stop();
+    private void stopSubscriptionService(final SubscriptionBaseService subscriptionBaseService) throws Exception {
+        ((DefaultSubscriptionBaseService) subscriptionBaseService).stop();
     }
 }
diff --git a/subscription/src/test/java/com/ning/billing/subscription/engine/dao/MockSubscriptionDaoMemory.java b/subscription/src/test/java/com/ning/billing/subscription/engine/dao/MockSubscriptionDaoMemory.java
index ed9c81b..c9a8320 100644
--- a/subscription/src/test/java/com/ning/billing/subscription/engine/dao/MockSubscriptionDaoMemory.java
+++ b/subscription/src/test/java/com/ning/billing/subscription/engine/dao/MockSubscriptionDaoMemory.java
@@ -39,11 +39,11 @@ import com.ning.billing.subscription.api.migration.AccountMigrationData.BundleMi
 import com.ning.billing.subscription.api.migration.AccountMigrationData.SubscriptionMigrationData;
 import com.ning.billing.subscription.api.timeline.SubscriptionDataRepair;
 import com.ning.billing.subscription.api.transfer.TransferCancelData;
+import com.ning.billing.subscription.api.user.DefaultSubscriptionBase;
+import com.ning.billing.subscription.api.user.DefaultSubscriptionBaseBundle;
 import com.ning.billing.subscription.api.user.SubscriptionBaseBundle;
 import com.ning.billing.subscription.api.user.SubscriptionBuilder;
-import com.ning.billing.subscription.api.user.SubscriptionBundleData;
-import com.ning.billing.subscription.api.user.SubscriptionData;
-import com.ning.billing.subscription.engine.core.DefaultSubscriptionService;
+import com.ning.billing.subscription.engine.core.DefaultSubscriptionBaseService;
 import com.ning.billing.subscription.engine.core.SubscriptionNotificationKey;
 import com.ning.billing.subscription.events.SubscriptionEvent;
 import com.ning.billing.subscription.events.SubscriptionEvent.EventType;
@@ -134,7 +134,7 @@ public class MockSubscriptionDaoMemory implements SubscriptionDao {
     }
 
     @Override
-    public SubscriptionBaseBundle createSubscriptionBundle(final SubscriptionBundleData bundle, final InternalCallContext context) {
+    public SubscriptionBaseBundle createSubscriptionBundle(final DefaultSubscriptionBaseBundle bundle, final InternalCallContext context) {
         bundles.add(bundle);
         return getSubscriptionBundleFromId(bundle.getId(), context);
     }
@@ -143,7 +143,7 @@ public class MockSubscriptionDaoMemory implements SubscriptionDao {
     public SubscriptionBase getSubscriptionFromId(final UUID subscriptionId, final InternalTenantContext context) {
         for (final SubscriptionBase cur : subscriptions) {
             if (cur.getId().equals(subscriptionId)) {
-                return buildSubscription((SubscriptionData) cur, context);
+                return buildSubscription((DefaultSubscriptionBase) cur, context);
             }
         }
         return null;
@@ -166,7 +166,7 @@ public class MockSubscriptionDaoMemory implements SubscriptionDao {
     }
 
     @Override
-    public void createSubscription(final SubscriptionData subscription, final List<SubscriptionEvent> initialEvents,
+    public void createSubscription(final DefaultSubscriptionBase subscription, final List<SubscriptionEvent> initialEvents,
                                    final InternalCallContext context) {
         synchronized (events) {
             events.addAll(initialEvents);
@@ -179,7 +179,7 @@ public class MockSubscriptionDaoMemory implements SubscriptionDao {
     }
 
     @Override
-    public void recreateSubscription(final SubscriptionData subscription, final List<SubscriptionEvent> recreateEvents, final InternalCallContext context) {
+    public void recreateSubscription(final DefaultSubscriptionBase subscription, final List<SubscriptionEvent> recreateEvents, final InternalCallContext context) {
         synchronized (events) {
             events.addAll(recreateEvents);
             for (final SubscriptionEvent cur : recreateEvents) {
@@ -193,7 +193,7 @@ public class MockSubscriptionDaoMemory implements SubscriptionDao {
         final List<SubscriptionBase> results = new ArrayList<SubscriptionBase>();
         for (final SubscriptionBase cur : subscriptions) {
             if (cur.getBundleId().equals(bundleId)) {
-                results.add(buildSubscription((SubscriptionData) cur, context));
+                results.add(buildSubscription((DefaultSubscriptionBase) cur, context));
             }
         }
         return results;
@@ -232,20 +232,20 @@ public class MockSubscriptionDaoMemory implements SubscriptionDao {
         for (final SubscriptionBase cur : subscriptions) {
             if (cur.getBundleId().equals(bundleId) &&
                 cur.getCurrentPlan().getProduct().getCategory() == ProductCategory.BASE) {
-                return buildSubscription((SubscriptionData) cur, context);
+                return buildSubscription((DefaultSubscriptionBase) cur, context);
             }
         }
         return null;
     }
 
     @Override
-    public void createNextPhaseEvent(final SubscriptionData subscription, final SubscriptionEvent nextPhase, final InternalCallContext context) {
+    public void createNextPhaseEvent(final DefaultSubscriptionBase subscription, final SubscriptionEvent nextPhase, final InternalCallContext context) {
         cancelNextPhaseEvent(subscription.getId(), context);
         insertEvent(nextPhase, context);
     }
 
-    private SubscriptionBase buildSubscription(final SubscriptionData in, final InternalTenantContext context) {
-        final SubscriptionData subscription = new SubscriptionData(new SubscriptionBuilder(in), null, clock);
+    private SubscriptionBase buildSubscription(final DefaultSubscriptionBase in, final InternalTenantContext context) {
+        final DefaultSubscriptionBase subscription = new DefaultSubscriptionBase(new SubscriptionBuilder(in), null, clock);
         if (events.size() > 0) {
             subscription.rebuildTransitions(getEventsForSubscription(in.getId(), context), catalogService.getFullCatalog());
         }
@@ -254,7 +254,7 @@ public class MockSubscriptionDaoMemory implements SubscriptionDao {
     }
 
     @Override
-    public void updateChargedThroughDate(final SubscriptionData subscription, final InternalCallContext context) {
+    public void updateChargedThroughDate(final DefaultSubscriptionBase subscription, final InternalCallContext context) {
         boolean found = false;
         final Iterator<SubscriptionBase> it = subscriptions.iterator();
         while (it.hasNext()) {
@@ -271,7 +271,7 @@ public class MockSubscriptionDaoMemory implements SubscriptionDao {
     }
 
     @Override
-    public void cancelSubscription(final SubscriptionData subscription, final SubscriptionEvent cancelEvent,
+    public void cancelSubscription(final DefaultSubscriptionBase subscription, final SubscriptionEvent cancelEvent,
                                    final InternalCallContext context, final int seqId) {
         synchronized (events) {
             cancelNextPhaseEvent(subscription.getId(), context);
@@ -280,7 +280,7 @@ public class MockSubscriptionDaoMemory implements SubscriptionDao {
     }
 
     @Override
-    public void cancelSubscriptions(final List<SubscriptionData> subscriptions, final List<SubscriptionEvent> cancelEvents, final InternalCallContext context) {
+    public void cancelSubscriptions(final List<DefaultSubscriptionBase> subscriptions, final List<SubscriptionEvent> cancelEvents, final InternalCallContext context) {
         synchronized (events) {
             for (int i = 0; i < subscriptions.size(); i++) {
                 cancelSubscription(subscriptions.get(i), cancelEvents.get(i), context, 0);
@@ -289,7 +289,7 @@ public class MockSubscriptionDaoMemory implements SubscriptionDao {
     }
 
     @Override
-    public void changePlan(final SubscriptionData subscription, final List<SubscriptionEvent> changeEvents, final InternalCallContext context) {
+    public void changePlan(final DefaultSubscriptionBase subscription, final List<SubscriptionEvent> changeEvents, final InternalCallContext context) {
         synchronized (events) {
             cancelNextChangeEvent(subscription.getId());
             cancelNextPhaseEvent(subscription.getId(), context);
@@ -353,7 +353,7 @@ public class MockSubscriptionDaoMemory implements SubscriptionDao {
     }
 
     @Override
-    public void uncancelSubscription(final SubscriptionData subscription, final List<SubscriptionEvent> uncancelEvents,
+    public void uncancelSubscription(final DefaultSubscriptionBase subscription, final List<SubscriptionEvent> uncancelEvents,
                                      final InternalCallContext context) {
 
         synchronized (events) {
@@ -384,9 +384,9 @@ public class MockSubscriptionDaoMemory implements SubscriptionDao {
         synchronized (events) {
 
             for (final BundleMigrationData curBundle : accountData.getData()) {
-                final SubscriptionBundleData bundleData = curBundle.getData();
+                final DefaultSubscriptionBaseBundle bundleData = curBundle.getData();
                 for (final SubscriptionMigrationData curSubscription : curBundle.getSubscriptions()) {
-                    final SubscriptionData subData = curSubscription.getData();
+                    final DefaultSubscriptionBase subData = curSubscription.getData();
                     for (final SubscriptionEvent curEvent : curSubscription.getInitialEvents()) {
                         events.add(curEvent);
                         recordFutureNotificationFromTransaction(null, curEvent.getEffectiveDate(),
@@ -415,8 +415,8 @@ public class MockSubscriptionDaoMemory implements SubscriptionDao {
     private void recordFutureNotificationFromTransaction(final EntitySqlDaoWrapperFactory<EntitySqlDao> transactionalDao, final DateTime effectiveDate,
                                                          final NotificationEvent notificationKey, final InternalCallContext context) {
         try {
-            final NotificationQueue subscriptionEventQueue = notificationQueueService.getNotificationQueue(DefaultSubscriptionService.SUBSCRIPTION_SERVICE_NAME,
-                                                                                                           DefaultSubscriptionService.NOTIFICATION_QUEUE_NAME);
+            final NotificationQueue subscriptionEventQueue = notificationQueueService.getNotificationQueue(DefaultSubscriptionBaseService.SUBSCRIPTION_SERVICE_NAME,
+                                                                                                           DefaultSubscriptionBaseService.NOTIFICATION_QUEUE_NAME);
             subscriptionEventQueue.recordFutureNotificationFromTransaction(null, effectiveDate, notificationKey, context.getUserToken(), context.getAccountRecordId(), context.getTenantRecordId());
         } catch (NoSuchNotificationQueue e) {
             throw new RuntimeException(e);
diff --git a/subscription/src/test/java/com/ning/billing/subscription/SubscriptionTestInitializer.java b/subscription/src/test/java/com/ning/billing/subscription/SubscriptionTestInitializer.java
index 60df587..62bcf86 100644
--- a/subscription/src/test/java/com/ning/billing/subscription/SubscriptionTestInitializer.java
+++ b/subscription/src/test/java/com/ning/billing/subscription/SubscriptionTestInitializer.java
@@ -22,7 +22,7 @@ import com.ning.billing.api.TestListenerStatus;
 import com.ning.billing.catalog.api.Catalog;
 import com.ning.billing.catalog.api.CatalogService;
 import com.ning.billing.clock.ClockMock;
-import com.ning.billing.subscription.api.SubscriptionService;
+import com.ning.billing.subscription.api.SubscriptionBaseService;
 import com.ning.billing.subscription.api.user.SubscriptionBaseBundle;
 import com.ning.billing.util.callcontext.InternalCallContext;
 import com.ning.billing.util.svcapi.subscription.SubscriptionBaseInternalApi;
@@ -40,9 +40,9 @@ public interface SubscriptionTestInitializer {
                                   final TestListenerStatus testListenerStatus,
                                   final ClockMock clock,
                                   final BusService busService,
-                                  final SubscriptionService subscriptionService) throws Exception;
+                                  final SubscriptionBaseService subscriptionBaseService) throws Exception;
 
     public void stopTestFramework(final TestApiListener testListener,
                                   final BusService busService,
-                                  final SubscriptionService subscriptionService) throws Exception;
+                                  final SubscriptionBaseService subscriptionBaseService) throws Exception;
 }
diff --git a/subscription/src/test/java/com/ning/billing/subscription/SubscriptionTestSuiteNoDB.java b/subscription/src/test/java/com/ning/billing/subscription/SubscriptionTestSuiteNoDB.java
index 62c2fc7..ebb12c2 100644
--- a/subscription/src/test/java/com/ning/billing/subscription/SubscriptionTestSuiteNoDB.java
+++ b/subscription/src/test/java/com/ning/billing/subscription/SubscriptionTestSuiteNoDB.java
@@ -37,10 +37,10 @@ import com.ning.billing.api.TestListenerStatus;
 import com.ning.billing.catalog.api.Catalog;
 import com.ning.billing.catalog.api.CatalogService;
 import com.ning.billing.clock.ClockMock;
-import com.ning.billing.subscription.api.SubscriptionService;
-import com.ning.billing.subscription.api.migration.SubscriptionMigrationApi;
-import com.ning.billing.subscription.api.timeline.SubscriptionTimelineApi;
-import com.ning.billing.subscription.api.transfer.SubscriptionTransferApi;
+import com.ning.billing.subscription.api.SubscriptionBaseService;
+import com.ning.billing.subscription.api.migration.SubscriptionBaseMigrationApi;
+import com.ning.billing.subscription.api.timeline.SubscriptionBaseTimelineApi;
+import com.ning.billing.subscription.api.transfer.SubscriptionBaseTransferApi;
 import com.ning.billing.subscription.api.user.SubscriptionBaseBundle;
 import com.ning.billing.subscription.api.user.TestSubscriptionHelper;
 import com.ning.billing.subscription.engine.dao.MockSubscriptionDaoMemory;
@@ -59,16 +59,16 @@ public class SubscriptionTestSuiteNoDB extends GuicyKillbillTestSuiteNoDB {
     protected static final Logger log = LoggerFactory.getLogger(SubscriptionTestSuiteNoDB.class);
 
     @Inject
-    protected SubscriptionService subscriptionService;
+    protected SubscriptionBaseService subscriptionBaseService;
     @Inject
     protected SubscriptionBaseInternalApi subscriptionInternalApi;
     @Inject
-    protected SubscriptionTransferApi transferApi;
+    protected SubscriptionBaseTransferApi transferApi;
 
     @Inject
-    protected SubscriptionMigrationApi migrationApi;
+    protected SubscriptionBaseMigrationApi migrationApi;
     @Inject
-    protected SubscriptionTimelineApi repairApi;
+    protected SubscriptionBaseTimelineApi repairApi;
 
     @Inject
     protected CatalogService catalogService;
@@ -122,7 +122,7 @@ public class SubscriptionTestSuiteNoDB extends GuicyKillbillTestSuiteNoDB {
         // CLEANUP ALL DB TABLES OR IN MEMORY STRUCTURES
         ((MockSubscriptionDaoMemory) dao).reset();
 
-        subscriptionTestInitializer.startTestFamework(testListener, testListenerStatus, clock, busService, subscriptionService);
+        subscriptionTestInitializer.startTestFamework(testListener, testListenerStatus, clock, busService, subscriptionBaseService);
 
         this.catalog = subscriptionTestInitializer.initCatalog(catalogService);
         this.accountData = subscriptionTestInitializer.initAccountData();
@@ -131,7 +131,7 @@ public class SubscriptionTestSuiteNoDB extends GuicyKillbillTestSuiteNoDB {
 
     @AfterMethod(groups = "fast")
     public void afterMethod() throws Exception {
-        subscriptionTestInitializer.stopTestFramework(testListener, busService, subscriptionService);
+        subscriptionTestInitializer.stopTestFramework(testListener, busService, subscriptionBaseService);
     }
 
     protected void assertListenerStatus() {
diff --git a/subscription/src/test/java/com/ning/billing/subscription/SubscriptionTestSuiteWithEmbeddedDB.java b/subscription/src/test/java/com/ning/billing/subscription/SubscriptionTestSuiteWithEmbeddedDB.java
index 6ccf906..5a62532 100644
--- a/subscription/src/test/java/com/ning/billing/subscription/SubscriptionTestSuiteWithEmbeddedDB.java
+++ b/subscription/src/test/java/com/ning/billing/subscription/SubscriptionTestSuiteWithEmbeddedDB.java
@@ -34,10 +34,10 @@ import com.ning.billing.api.TestListenerStatus;
 import com.ning.billing.catalog.api.Catalog;
 import com.ning.billing.catalog.api.CatalogService;
 import com.ning.billing.clock.ClockMock;
-import com.ning.billing.subscription.api.SubscriptionService;
-import com.ning.billing.subscription.api.migration.SubscriptionMigrationApi;
-import com.ning.billing.subscription.api.timeline.SubscriptionTimelineApi;
-import com.ning.billing.subscription.api.transfer.SubscriptionTransferApi;
+import com.ning.billing.subscription.api.SubscriptionBaseService;
+import com.ning.billing.subscription.api.migration.SubscriptionBaseMigrationApi;
+import com.ning.billing.subscription.api.timeline.SubscriptionBaseTimelineApi;
+import com.ning.billing.subscription.api.transfer.SubscriptionBaseTransferApi;
 import com.ning.billing.subscription.api.user.SubscriptionBaseBundle;
 import com.ning.billing.subscription.api.user.TestSubscriptionHelper;
 import com.ning.billing.subscription.engine.dao.SubscriptionDao;
@@ -55,16 +55,16 @@ public class SubscriptionTestSuiteWithEmbeddedDB extends GuicyKillbillTestSuiteW
     protected static final Logger log = LoggerFactory.getLogger(SubscriptionTestSuiteWithEmbeddedDB.class);
 
     @Inject
-    protected SubscriptionService subscriptionService;
+    protected SubscriptionBaseService subscriptionBaseService;
     @Inject
     protected SubscriptionBaseInternalApi subscriptionInternalApi;
     @Inject
-    protected SubscriptionTransferApi transferApi;
+    protected SubscriptionBaseTransferApi transferApi;
 
     @Inject
-    protected SubscriptionMigrationApi migrationApi;
+    protected SubscriptionBaseMigrationApi migrationApi;
     @Inject
-    protected SubscriptionTimelineApi repairApi;
+    protected SubscriptionBaseTimelineApi repairApi;
 
     @Inject
     protected CatalogService catalogService;
@@ -109,7 +109,7 @@ public class SubscriptionTestSuiteWithEmbeddedDB extends GuicyKillbillTestSuiteW
     @BeforeMethod(groups = "slow")
     public void beforeMethod() throws Exception {
         super.beforeMethod();
-        subscriptionTestInitializer.startTestFamework(testListener, testListenerStatus, clock, busService, subscriptionService);
+        subscriptionTestInitializer.startTestFamework(testListener, testListenerStatus, clock, busService, subscriptionBaseService);
 
         this.catalog = subscriptionTestInitializer.initCatalog(catalogService);
         this.accountData = subscriptionTestInitializer.initAccountData();
@@ -118,7 +118,7 @@ public class SubscriptionTestSuiteWithEmbeddedDB extends GuicyKillbillTestSuiteW
 
     @AfterMethod(groups = "slow")
     public void afterMethod() throws Exception {
-        subscriptionTestInitializer.stopTestFramework(testListener, busService, subscriptionService);
+        subscriptionTestInitializer.stopTestFramework(testListener, busService, subscriptionBaseService);
     }
 
     protected void assertListenerStatus() {
diff --git a/util/src/main/java/com/ning/billing/util/audit/api/DefaultAuditUserApi.java b/util/src/main/java/com/ning/billing/util/audit/api/DefaultAuditUserApi.java
index 97a192e..b2d98da 100644
--- a/util/src/main/java/com/ning/billing/util/audit/api/DefaultAuditUserApi.java
+++ b/util/src/main/java/com/ning/billing/util/audit/api/DefaultAuditUserApi.java
@@ -24,12 +24,11 @@ import java.util.UUID;
 import javax.inject.Inject;
 
 import com.ning.billing.ObjectType;
-import com.ning.billing.account.api.AccountApiException;
-import com.ning.billing.subscription.api.timeline.BundleTimeline;
+import com.ning.billing.subscription.api.timeline.BundleBaseTimeline;
+import com.ning.billing.subscription.api.timeline.SubscriptionBaseTimeline;
 import com.ning.billing.subscription.api.timeline.SubscriptionRepairException;
 import com.ning.billing.subscription.api.timeline.SubscriptionTimelineApi;
-import com.ning.billing.subscription.api.timeline.SubscriptionTimeline;
-import com.ning.billing.subscription.api.timeline.SubscriptionTimeline.ExistingEvent;
+import com.ning.billing.subscription.api.timeline.SubscriptionBaseTimeline.ExistingEvent;
 import com.ning.billing.invoice.api.Invoice;
 import com.ning.billing.invoice.api.InvoiceItem;
 import com.ning.billing.invoice.api.InvoicePayment;
@@ -78,7 +77,7 @@ public class DefaultAuditUserApi implements AuditUserApi {
     public AuditLogsForBundles getAuditLogsForBundle(final UUID bundleId, final AuditLevel auditLevel, final TenantContext context)  {
 
         try {
-            return getAuditLogsForBundles(ImmutableList.<BundleTimeline>of(timelineApi.getBundleTimeline(bundleId, context)), auditLevel, context);
+            return getAuditLogsForBundles(ImmutableList.<BundleBaseTimeline>of(timelineApi.getBundleTimeline(bundleId, context)), auditLevel, context);
         } catch (SubscriptionRepairException e) {
             // STEPH_ENT
             e.printStackTrace();  //To change body of catch statement use File | Settings | File Templates.
@@ -86,13 +85,13 @@ public class DefaultAuditUserApi implements AuditUserApi {
         }
     }
 
-    public AuditLogsForBundles getAuditLogsForBundles(final List<BundleTimeline> bundles, final AuditLevel auditLevel, final TenantContext context) {
+    public AuditLogsForBundles getAuditLogsForBundles(final List<BundleBaseTimeline> bundles, final AuditLevel auditLevel, final TenantContext context) {
         final Map<UUID, List<AuditLog>> bundlesAuditLogs = new HashMap<UUID, List<AuditLog>>();
         final Map<UUID, List<AuditLog>> subscriptionsAuditLogs = new HashMap<UUID, List<AuditLog>>();
         final Map<UUID, List<AuditLog>> subscriptionEventsAuditLogs = new HashMap<UUID, List<AuditLog>>();
-        for (final BundleTimeline bundle : bundles) {
+        for (final BundleBaseTimeline bundle : bundles) {
             bundlesAuditLogs.put(bundle.getId(), getAuditLogs(bundle.getId(), ObjectType.BUNDLE, auditLevel, context));
-            for (final SubscriptionTimeline subscriptionTimeline : bundle.getSubscriptions()) {
+            for (final SubscriptionBaseTimeline subscriptionTimeline : bundle.getSubscriptions()) {
                 subscriptionsAuditLogs.put(subscriptionTimeline.getId(), getAuditLogs(subscriptionTimeline.getId(), ObjectType.SUBSCRIPTION, auditLevel, context));
                 for (final ExistingEvent event : subscriptionTimeline.getExistingEvents()) {
                     subscriptionEventsAuditLogs.put(event.getEventId(), getAuditLogs(event.getEventId(), ObjectType.SUBSCRIPTION_EVENT, auditLevel, context));
diff --git a/util/src/test/java/com/ning/billing/mock/glue/MockSubscriptionModule.java b/util/src/test/java/com/ning/billing/mock/glue/MockSubscriptionModule.java
index bc73c0c..1efce03 100644
--- a/util/src/test/java/com/ning/billing/mock/glue/MockSubscriptionModule.java
+++ b/util/src/test/java/com/ning/billing/mock/glue/MockSubscriptionModule.java
@@ -19,7 +19,7 @@ package com.ning.billing.mock.glue;
 import org.mockito.Mockito;
 
 import com.ning.billing.glue.SubscriptionModule;
-import com.ning.billing.subscription.api.SubscriptionService;
+import com.ning.billing.subscription.api.SubscriptionBaseService;
 import com.ning.billing.subscription.api.migration.SubscriptionMigrationApi;
 import com.ning.billing.subscription.api.timeline.SubscriptionTimelineApi;
 import com.ning.billing.subscription.api.transfer.SubscriptionTransferApi;
@@ -31,7 +31,7 @@ public class MockSubscriptionModule extends AbstractModule implements Subscripti
 
     @Override
     public void installSubscriptionService() {
-        bind(SubscriptionService.class).toInstance(Mockito.mock(SubscriptionService.class));
+        bind(SubscriptionBaseService.class).toInstance(Mockito.mock(SubscriptionBaseService.class));
     }
 
 
diff --git a/util/src/test/java/com/ning/billing/util/audit/api/TestDefaultAuditUserApi.java b/util/src/test/java/com/ning/billing/util/audit/api/TestDefaultAuditUserApi.java
index 5e9c9bb..b4e18b0 100644
--- a/util/src/test/java/com/ning/billing/util/audit/api/TestDefaultAuditUserApi.java
+++ b/util/src/test/java/com/ning/billing/util/audit/api/TestDefaultAuditUserApi.java
@@ -24,27 +24,23 @@ import java.util.UUID;
 import org.mockito.Mockito;
 import org.testng.Assert;
 import org.testng.annotations.BeforeClass;
-import org.testng.annotations.BeforeTest;
 import org.testng.annotations.Test;
 
 import com.ning.billing.ObjectType;
-import com.ning.billing.subscription.api.timeline.BundleTimeline;
+import com.ning.billing.subscription.api.timeline.BundleBaseTimeline;
 import com.ning.billing.invoice.api.Invoice;
 import com.ning.billing.invoice.api.InvoiceItem;
 import com.ning.billing.invoice.api.InvoicePayment;
 import com.ning.billing.payment.api.Payment;
 import com.ning.billing.payment.api.Refund;
 import com.ning.billing.util.api.AuditLevel;
-import com.ning.billing.util.api.AuditUserApi;
 import com.ning.billing.util.audit.AuditLog;
-import com.ning.billing.util.audit.AuditLogsForBundles;
 import com.ning.billing.util.audit.AuditLogsForInvoicePayments;
 import com.ning.billing.util.audit.AuditLogsForInvoices;
 import com.ning.billing.util.audit.AuditLogsForPayments;
 import com.ning.billing.util.audit.AuditLogsForRefunds;
 import com.ning.billing.util.audit.AuditLogsTestBase;
 import com.ning.billing.util.audit.dao.MockAuditDao;
-import com.ning.billing.util.callcontext.InternalCallContextFactory;
 import com.ning.billing.util.dao.TableName;
 import com.ning.billing.util.entity.Entity;
 
@@ -76,9 +72,9 @@ public class TestDefaultAuditUserApi extends AuditLogsTestBase {
 
     @Test(groups = "fast")
     public void testForBundles() throws Exception {
-        final List<BundleTimeline> bundles = new ArrayList<BundleTimeline>();
+        final List<BundleBaseTimeline> bundles = new ArrayList<BundleBaseTimeline>();
         for (final UUID objectId : objectIds) {
-            final BundleTimeline entity = Mockito.mock(BundleTimeline.class);
+            final BundleBaseTimeline entity = Mockito.mock(BundleBaseTimeline.class);
             Mockito.when(entity.getId()).thenReturn(objectId);
             bundles.add(entity);
         }
diff --git a/util/src/test/java/com/ning/billing/util/glue/TestUtilModule.java b/util/src/test/java/com/ning/billing/util/glue/TestUtilModule.java
index 6fffa80..f38fc02 100644
--- a/util/src/test/java/com/ning/billing/util/glue/TestUtilModule.java
+++ b/util/src/test/java/com/ning/billing/util/glue/TestUtilModule.java
@@ -31,7 +31,7 @@ public class TestUtilModule extends AbstractModule {
         this.configSource = configSource;
     }
 
-    // TODO STEPH this is bad-- because DefaultAuditUserApi is using SubscriptionTimeline API
+    // TODO STEPH this is bad-- because DefaultAuditUserApi is using SubscriptionBaseTimeline API
     public void installHack() {
         bind(SubscriptionTimelineApi.class).toInstance(Mockito.mock(SubscriptionTimelineApi.class));
     }