killbill-memoizeit

Changes

account/pom.xml 2(+1 -1)

api/pom.xml 2(+1 -1)

beatrix/pom.xml 2(+1 -1)

catalog/pom.xml 2(+1 -1)

invoice/pom.xml 2(+1 -1)

jaxrs/pom.xml 2(+1 -1)

junction/pom.xml 2(+1 -1)

osgi/pom.xml 2(+1 -1)

overdue/pom.xml 2(+1 -1)

payment/pom.xml 2(+1 -1)

pom.xml 2(+1 -1)

server/pom.xml 2(+1 -1)

tenant/pom.xml 2(+1 -1)

usage/pom.xml 2(+1 -1)

util/pom.xml 2(+1 -1)

Details

account/pom.xml 2(+1 -1)

diff --git a/account/pom.xml b/account/pom.xml
index 72d9dc3..2e4fe3e 100644
--- a/account/pom.xml
+++ b/account/pom.xml
@@ -20,7 +20,7 @@
     <parent>
         <groupId>com.ning.billing</groupId>
         <artifactId>killbill</artifactId>
-        <version>0.1.62-SNAPSHOT</version>
+        <version>0.1.64-SNAPSHOT</version>
         <relativePath>../pom.xml</relativePath>
     </parent>
     <artifactId>killbill-account</artifactId>
diff --git a/account/src/test/java/com/ning/billing/account/dao/TestAccountDao.java b/account/src/test/java/com/ning/billing/account/dao/TestAccountDao.java
index d58f6d7..e92996d 100644
--- a/account/src/test/java/com/ning/billing/account/dao/TestAccountDao.java
+++ b/account/src/test/java/com/ning/billing/account/dao/TestAccountDao.java
@@ -111,7 +111,7 @@ public class TestAccountDao extends AccountTestSuiteWithEmbeddedDB {
         final CustomField field = new StringCustomField(fieldName, fieldValue, ObjectType.ACCOUNT, accountId, internalCallContext.getCreatedDate());
         customFieldDao.create(new CustomFieldModelDao(field), internalCallContext);
 
-        final List<CustomFieldModelDao> customFieldMap = customFieldDao.getCustomFields(accountId, ObjectType.ACCOUNT, internalCallContext);
+        final List<CustomFieldModelDao> customFieldMap = customFieldDao.getCustomFieldsForObject(accountId, ObjectType.ACCOUNT, internalCallContext);
         Assert.assertEquals(customFieldMap.size(), 1);
 
         final CustomFieldModelDao customField = customFieldMap.get(0);
@@ -126,7 +126,7 @@ public class TestAccountDao extends AccountTestSuiteWithEmbeddedDB {
         final Tag tag = new DescriptiveTag(tagDefinition.getId(), ObjectType.ACCOUNT, account.getId(), internalCallContext.getCreatedDate());
         tagDao.create(new TagModelDao(tag), internalCallContext);
 
-        final List<TagModelDao> tags = tagDao.getTags(account.getId(), ObjectType.ACCOUNT, internalCallContext);
+        final List<TagModelDao> tags = tagDao.getTagsForObject(account.getId(), ObjectType.ACCOUNT, internalCallContext);
         Assert.assertEquals(tags.size(), 1);
         Assert.assertEquals(tags.get(0).getTagDefinitionId(), tagDefinition.getId());
         Assert.assertEquals(tags.get(0).getObjectId(), account.getId());
diff --git a/analytics/pom.xml b/analytics/pom.xml
index 945c1d4..e70ca46 100644
--- a/analytics/pom.xml
+++ b/analytics/pom.xml
@@ -20,7 +20,7 @@
     <parent>
         <groupId>com.ning.billing</groupId>
         <artifactId>killbill</artifactId>
-        <version>0.1.62-SNAPSHOT</version>
+        <version>0.1.64-SNAPSHOT</version>
         <relativePath>../pom.xml</relativePath>
     </parent>
     <artifactId>killbill-analytics</artifactId>
diff --git a/analytics/src/main/java/com/ning/billing/analytics/BusinessOverdueStatusDao.java b/analytics/src/main/java/com/ning/billing/analytics/BusinessOverdueStatusDao.java
index a74e847..076843f 100644
--- a/analytics/src/main/java/com/ning/billing/analytics/BusinessOverdueStatusDao.java
+++ b/analytics/src/main/java/com/ning/billing/analytics/BusinessOverdueStatusDao.java
@@ -35,6 +35,7 @@ import com.ning.billing.entitlement.api.user.EntitlementUserApiException;
 import com.ning.billing.entitlement.api.user.SubscriptionBundle;
 import com.ning.billing.junction.api.Blockable;
 import com.ning.billing.junction.api.BlockingState;
+import com.ning.billing.junction.api.JunctionApi;
 import com.ning.billing.util.callcontext.InternalCallContext;
 import com.ning.billing.util.svcapi.account.AccountInternalApi;
 import com.ning.billing.util.svcapi.entitlement.EntitlementInternalApi;
@@ -51,16 +52,16 @@ public class BusinessOverdueStatusDao {
 
     private final AccountInternalApi accountApi;
     private final EntitlementInternalApi entitlementApi;
-    private final BlockingInternalApi blockingApi;
+    private final JunctionApi junctionApi;
 
     @Inject
     public BusinessOverdueStatusDao(final BusinessOverdueStatusSqlDao overdueStatusSqlDao, final AccountInternalApi accountApi,
-                                    final EntitlementInternalApi entitlementApi, final BlockingInternalApi blockingApi) {
+                                    final EntitlementInternalApi entitlementApi, final JunctionApi junctionApi) {
 
         this.overdueStatusSqlDao = overdueStatusSqlDao;
         this.accountApi = accountApi;
         this.entitlementApi = entitlementApi;
-        this.blockingApi = blockingApi;
+        this.junctionApi = junctionApi;
     }
 
     public void overdueStatusChanged(final Blockable.Type objectType, final UUID objectId, final InternalCallContext context) {
@@ -96,7 +97,7 @@ public class BusinessOverdueStatusDao {
             public Void inTransaction(final BusinessOverdueStatusSqlDao transactional, final TransactionStatus status) throws Exception {
                 log.info("Started rebuilding overdue statuses for bundle id {}", bundleId);
                 transactional.deleteOverdueStatusesForBundle(bundleId.toString(), context);
-                final List<BlockingState> blockingHistory = blockingApi.getBlockingHistory(bundleId, context);
+                final List<BlockingState> blockingHistory = junctionApi.getBlockingHistory(bundleId, context.toTenantContext());
                 if (blockingHistory != null && blockingHistory.size() > 0) {
                     final List<BlockingState> overdueStates = ImmutableList.<BlockingState>copyOf(blockingHistory);
                     final List<BlockingState> overdueStatesReversed = Lists.reverse(overdueStates);
diff --git a/analytics/src/test/java/com/ning/billing/analytics/AnalyticsTestSuiteWithEmbeddedDB.java b/analytics/src/test/java/com/ning/billing/analytics/AnalyticsTestSuiteWithEmbeddedDB.java
index 0f70b21..3629261 100644
--- a/analytics/src/test/java/com/ning/billing/analytics/AnalyticsTestSuiteWithEmbeddedDB.java
+++ b/analytics/src/test/java/com/ning/billing/analytics/AnalyticsTestSuiteWithEmbeddedDB.java
@@ -44,6 +44,7 @@ import com.ning.billing.catalog.api.CatalogService;
 import com.ning.billing.entitlement.api.user.EntitlementUserApi;
 import com.ning.billing.invoice.api.InvoiceUserApi;
 import com.ning.billing.invoice.dao.InvoiceDao;
+import com.ning.billing.junction.api.JunctionApi;
 import com.ning.billing.payment.dao.PaymentDao;
 import com.ning.billing.util.glue.RealImplementation;
 import com.ning.billing.util.svcapi.account.AccountInternalApi;
@@ -123,6 +124,8 @@ public abstract class AnalyticsTestSuiteWithEmbeddedDB extends GuicyKillbillTest
     protected BusinessSubscriptionTransitionSqlDao subscriptionTransitionSqlDao;
     @Inject
     protected BusinessTagDao tagDao;
+    @Inject
+    protected JunctionApi junctionApi;
 
     @BeforeClass(groups = "slow")
     protected void beforeClass() throws Exception {
diff --git a/analytics/src/test/java/com/ning/billing/analytics/api/TestAnalyticsService.java b/analytics/src/test/java/com/ning/billing/analytics/api/TestAnalyticsService.java
index ace0c73..9a0b572 100644
--- a/analytics/src/test/java/com/ning/billing/analytics/api/TestAnalyticsService.java
+++ b/analytics/src/test/java/com/ning/billing/analytics/api/TestAnalyticsService.java
@@ -27,7 +27,6 @@ import org.testng.annotations.BeforeMethod;
 import org.testng.annotations.Test;
 
 import com.ning.billing.account.api.Account;
-import com.ning.billing.account.api.AccountApiException;
 import com.ning.billing.account.api.user.DefaultAccountCreationEvent;
 import com.ning.billing.account.dao.AccountModelDao;
 import com.ning.billing.analytics.AnalyticsTestSuiteWithEmbeddedDB;
@@ -153,6 +152,10 @@ public class TestAnalyticsService extends AnalyticsTestSuiteWithEmbeddedDB {
                 null,
                 null,
                 null,
+                null,
+                null,
+                null,
+                null,
                 Subscription.SubscriptionState.ACTIVE,
                 plan,
                 phase,

api/pom.xml 2(+1 -1)

diff --git a/api/pom.xml b/api/pom.xml
index 6aaddd1..d7a3297 100644
--- a/api/pom.xml
+++ b/api/pom.xml
@@ -20,7 +20,7 @@
     <parent>
         <groupId>com.ning.billing</groupId>
         <artifactId>killbill</artifactId>
-        <version>0.1.62-SNAPSHOT</version>
+        <version>0.1.64-SNAPSHOT</version>
         <relativePath>../pom.xml</relativePath>
     </parent>
     <artifactId>killbill-api</artifactId>
diff --git a/api/src/main/java/com/ning/billing/beatrix/bus/api/ExtBusEventType.java b/api/src/main/java/com/ning/billing/beatrix/bus/api/ExtBusEventType.java
index 940e34b..ac4fe08 100644
--- a/api/src/main/java/com/ning/billing/beatrix/bus/api/ExtBusEventType.java
+++ b/api/src/main/java/com/ning/billing/beatrix/bus/api/ExtBusEventType.java
@@ -16,8 +16,9 @@
 package com.ning.billing.beatrix.bus.api;
 
 /**
- * The enum {@code ExtBusEventType} rerpesents the user visible bus event types.
+ * The enum {@code ExtBusEventType} represents the user visible bus event types.
  */
+
 public enum ExtBusEventType {
     ACCOUNT_CREATION,
     ACCOUNT_CHANGE,
@@ -26,6 +27,11 @@ public enum ExtBusEventType {
     SUBSCRIPTION_CANCEL,
     OVERDUE_CHANGE,
     INVOICE_CREATION,
+    INVOICE_ADJUSTMENT,
     PAYMENT_SUCCESS,
-    PAYMENT_FAILED
+    PAYMENT_FAILED,
+    TAG_CREATION,
+    TAG_DELETION,
+    CUSTOM_FIELD_CREATION,
+    CUSTOM_FIELD_DELETION
 }
diff --git a/api/src/main/java/com/ning/billing/entitlement/api/user/Subscription.java b/api/src/main/java/com/ning/billing/entitlement/api/user/Subscription.java
index 289a7b9..b4eeaba 100644
--- a/api/src/main/java/com/ning/billing/entitlement/api/user/Subscription.java
+++ b/api/src/main/java/com/ning/billing/entitlement/api/user/Subscription.java
@@ -16,6 +16,7 @@
 
 package com.ning.billing.entitlement.api.user;
 
+import java.util.List;
 import java.util.UUID;
 
 import org.joda.time.DateTime;
@@ -100,4 +101,6 @@ public interface Subscription extends Entity, Blockable {
     public SubscriptionTransition getPendingTransition();
 
     public SubscriptionTransition getPreviousTransition();
+
+    public List<SubscriptionTransition> getAllTransitions();
 }
diff --git a/api/src/main/java/com/ning/billing/entitlement/api/user/SubscriptionTransition.java b/api/src/main/java/com/ning/billing/entitlement/api/user/SubscriptionTransition.java
index c8a8bca..76ff799 100644
--- a/api/src/main/java/com/ning/billing/entitlement/api/user/SubscriptionTransition.java
+++ b/api/src/main/java/com/ning/billing/entitlement/api/user/SubscriptionTransition.java
@@ -35,12 +35,20 @@ public interface SubscriptionTransition {
 
     public SubscriptionState getNextState();
 
+    public UUID getPreviousEventId();
+
+    public DateTime getPreviousEventCreatedDate();
+
     public Plan getPreviousPlan();
 
     public Plan getNextPlan();
 
     public PlanPhase getPreviousPhase();
 
+    public UUID getNextEventId();
+
+    public DateTime getNextEventCreatedDate();
+
     public PlanPhase getNextPhase();
 
     public PriceList getPreviousPriceList();
diff --git a/api/src/main/java/com/ning/billing/ErrorCode.java b/api/src/main/java/com/ning/billing/ErrorCode.java
index 50e4fde..aff1bd1 100644
--- a/api/src/main/java/com/ning/billing/ErrorCode.java
+++ b/api/src/main/java/com/ning/billing/ErrorCode.java
@@ -271,6 +271,7 @@ public enum ErrorCode {
 
     PAYMENT_PLUGIN_TIMEOUT(7100, "Plugin timeout for account %s and invoice %s"),
     PAYMENT_PLUGIN_ACCOUNT_INIT(7101, "Account initialization for account %s and plugin % s failed: %s"),
+    PAYMENT_PLUGIN_GET_PAYMENT_INFO(7102, "Failed to retrieve payment plugin info for payment %s: %s"),
 
     /*
     *
diff --git a/api/src/main/java/com/ning/billing/glue/JunctionModule.java b/api/src/main/java/com/ning/billing/glue/JunctionModule.java
index 62cad80..1393732 100644
--- a/api/src/main/java/com/ning/billing/glue/JunctionModule.java
+++ b/api/src/main/java/com/ning/billing/glue/JunctionModule.java
@@ -27,4 +27,6 @@ public interface JunctionModule {
 
     public void installEntitlementUserApi();
 
+    public void installJunctionApi();
+
 }
diff --git a/api/src/main/java/com/ning/billing/invoice/api/Invoice.java b/api/src/main/java/com/ning/billing/invoice/api/Invoice.java
index c9ef16e..402ad8d 100644
--- a/api/src/main/java/com/ning/billing/invoice/api/Invoice.java
+++ b/api/src/main/java/com/ning/billing/invoice/api/Invoice.java
@@ -28,26 +28,76 @@ import com.ning.billing.util.entity.Entity;
 
 public interface Invoice extends Entity {
 
+    /**
+     *
+     * @param item the invoice ietm to add
+     * @return true if successful
+     */
     boolean addInvoiceItem(InvoiceItem item);
 
+    /**
+     *
+     * @param items the list of ietms to add
+     * @return true is successful
+     */
     boolean addInvoiceItems(Collection<InvoiceItem> items);
 
+    /**
+     *
+     * @return the list of items on that invoice
+     */
     List<InvoiceItem> getInvoiceItems();
 
+    /**
+     *
+     * @param clazz the filter class for the items
+     * @param <T>   a InvoiceItem type
+     * @return      the list of invoice ietms on that invoice for that type
+     */
     public <T extends InvoiceItem> List<InvoiceItem> getInvoiceItems(Class<T> clazz);
 
+    /**
+     *
+     * @return the number of items on that invoice
+     */
     int getNumberOfItems();
 
+    /**
+     *
+     * @param payment the successful payment for that invoice
+     * @return        true if we were able to add the payment
+     */
     boolean addPayment(InvoicePayment payment);
 
+    /**
+     *
+     * @param payments  the list of payments to add on that invoice
+     * @return          true if we were able to add the payments
+     */
     boolean addPayments(Collection<InvoicePayment> payments);
 
+    /**
+     *
+     * @return the list of payments associated with that invoice
+     */
     List<InvoicePayment> getPayments();
 
+    /**
+     *
+     * @return the number of payments on that invoice
+     */
     int getNumberOfPayments();
 
+    /**
+     *
+     * @return the accountId
+     */
     UUID getAccountId();
 
+    /**
+     *
+     * @return the invoice number
+     */
     Integer getInvoiceNumber();
 
     /**
@@ -62,21 +112,63 @@ public interface Invoice extends Entity {
      */
     LocalDate getTargetDate();
 
+    /**
+     *
+     * @return the currency associated with that invoice
+     */
     Currency getCurrency();
 
+    /**
+     *
+     * @return the amount that was paid on that invoice
+     */
     BigDecimal getPaidAmount();
 
+    /**
+     *
+     * @return the original charged amount when the invoice was created
+     */
+    BigDecimal getOriginalChargedAmount();
+
+    /**
+     *
+     * @return the current charged amount for that invoice
+     */
     BigDecimal getChargedAmount();
 
+    /**
+     *
+     * @return the amount of account credit on that invoice
+     */
     BigDecimal getCBAAmount();
 
+    /**
+     *
+     * @return the total adjusted amount on that invoice
+     */
     BigDecimal getTotalAdjAmount();
 
+    /**
+     *
+     * @return the total credit amount on that invoice
+     */
     BigDecimal getCreditAdjAmount();
 
+    /**
+     *
+     * @return the total refunded amount on that invoice
+     */
     BigDecimal getRefundAdjAmount();
 
+    /**
+     *
+     * @return the current balance on that invoice
+     */
     BigDecimal getBalance();
 
+    /**
+     *
+     * @return true if this is a migration invoice
+     */
     boolean isMigrationInvoice();
 }
diff --git a/api/src/main/java/com/ning/billing/junction/api/JunctionApi.java b/api/src/main/java/com/ning/billing/junction/api/JunctionApi.java
new file mode 100644
index 0000000..70bdd44
--- /dev/null
+++ b/api/src/main/java/com/ning/billing/junction/api/JunctionApi.java
@@ -0,0 +1,35 @@
+/*
+ * 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.junction.api;
+
+import java.util.List;
+import java.util.UUID;
+
+import com.ning.billing.util.callcontext.TenantContext;
+
+public interface JunctionApi {
+
+    /**
+     *
+     * @param overdueableId the uuid of the object potentially in an overduabke state
+     * @param context       the context associated to that call
+     * @return              a list of all the blocking states for that object
+     */
+    public List<BlockingState> getBlockingHistory(UUID overdueableId, TenantContext context);
+}
+
+
diff --git a/api/src/main/java/com/ning/billing/osgi/api/OSGIKillbill.java b/api/src/main/java/com/ning/billing/osgi/api/OSGIKillbill.java
index 646afd9..1b5b9bf 100644
--- a/api/src/main/java/com/ning/billing/osgi/api/OSGIKillbill.java
+++ b/api/src/main/java/com/ning/billing/osgi/api/OSGIKillbill.java
@@ -27,6 +27,7 @@ import com.ning.billing.entitlement.api.user.EntitlementUserApi;
 import com.ning.billing.invoice.api.InvoiceMigrationApi;
 import com.ning.billing.invoice.api.InvoicePaymentApi;
 import com.ning.billing.invoice.api.InvoiceUserApi;
+import com.ning.billing.junction.api.JunctionApi;
 import com.ning.billing.osgi.api.config.PluginConfigServiceApi;
 import com.ning.billing.overdue.OverdueUserApi;
 import com.ning.billing.payment.api.PaymentApi;
@@ -35,6 +36,7 @@ import com.ning.billing.usage.api.UsageUserApi;
 import com.ning.billing.util.api.AuditUserApi;
 import com.ning.billing.util.api.CustomFieldUserApi;
 import com.ning.billing.util.api.ExportUserApi;
+import com.ning.billing.util.api.RecordIdApi;
 import com.ning.billing.util.api.TagUserApi;
 
 /**
@@ -85,6 +87,9 @@ public interface OSGIKillbill {
 
     public TagUserApi getTagUserApi();
 
+    public JunctionApi getJunctionApi();
+
+    public RecordIdApi getRecordIdApi();
     /**
      * Used by the OSGI bundles to discover their configuration
      *
diff --git a/api/src/main/java/com/ning/billing/payment/api/Payment.java b/api/src/main/java/com/ning/billing/payment/api/Payment.java
index a1edee9..6801101 100644
--- a/api/src/main/java/com/ning/billing/payment/api/Payment.java
+++ b/api/src/main/java/com/ning/billing/payment/api/Payment.java
@@ -22,44 +22,124 @@ import java.util.UUID;
 import org.joda.time.DateTime;
 
 import com.ning.billing.catalog.api.Currency;
+import com.ning.billing.payment.plugin.api.PaymentInfoPlugin;
 import com.ning.billing.util.entity.Entity;
 
 public interface Payment extends Entity {
 
-    public UUID getAccountId();
-
-    public UUID getInvoiceId();
-
-    public UUID getPaymentMethodId();
-
-    public Integer getPaymentNumber();
-
-    public BigDecimal getAmount();
-
-    public BigDecimal getPaidAmount();
-
-    public DateTime getEffectiveDate();
-
-    public Currency getCurrency();
-
-    public PaymentStatus getPaymentStatus();
-
-    public List<PaymentAttempt> getAttempts();
-
-    public String getExtFirstPaymentIdRef();
-
-    public String getExtSecondPaymentIdRef();
-
+    /**
+     *
+     * @return the account id
+     */
+    UUID getAccountId();
+
+    /**
+     *
+     * @return the invoice id
+     */
+    UUID getInvoiceId();
+
+    /**
+     *
+     * @return the payment method id
+     */
+    UUID getPaymentMethodId();
+
+    /**
+     *
+     * @return the payment number
+     */
+    Integer getPaymentNumber();
+
+    /**
+     *
+     * @return the amount that needs to be paid
+     */
+    BigDecimal getAmount();
+
+    /**
+     *
+     * @return the paid amount
+     */
+    BigDecimal getPaidAmount();
+
+    /**
+     * If the payment is successful, this date is the date of payment, otherwise this is the date of the last attempt
+     *
+     * @return the effective date of the payment
+     */
+    DateTime getEffectiveDate();
+
+    /**
+     *
+     * @return the currency associated with that payment
+     */
+    Currency getCurrency();
+
+    /**
+     *
+     * @return the payment status
+     */
+    PaymentStatus getPaymentStatus();
+
+    /**
+     *
+     * @return the list of attempts on that payment
+     */
+    List<PaymentAttempt> getAttempts();
+
+    /**
+     *
+     * @return the first payment ref id from the plugin
+     */
+    @Deprecated
+    String getExtFirstPaymentIdRef();
+
+    /**
+     *
+     * @return the second payment ref id from the plugin
+     */
+    @Deprecated
+    String getExtSecondPaymentIdRef();
+
+    /**
+     * This will only be filled when the call requires the detail from the plugin
+     *
+     * @return the addtional info from the plugin
+     */
+    PaymentInfoPlugin getPaymentInfoPlugin();
+
+    
     public interface PaymentAttempt extends Entity {
 
-        public UUID getId();
-
-        public DateTime getEffectiveDate();
-
-        public String getGatewayErrorCode();
-
-        public String getGatewayErrorMsg();
-
-        public PaymentStatus getPaymentStatus();
+        /**
+         *
+         * @return the payment attempt id
+         */
+        UUID getId();
+
+        /**
+         *
+         * @return the date when that attempt was made
+         */
+        DateTime getEffectiveDate();
+
+        /**
+         *
+         * @return the error code from the gateway
+         */
+        String getGatewayErrorCode();
+
+        /**
+         *
+         * @return the error message from the gateway
+         */
+        String getGatewayErrorMsg();
+
+        /**
+         *
+         * @return the status for that attempt
+         */
+        PaymentStatus getPaymentStatus();
     }
 }
diff --git a/api/src/main/java/com/ning/billing/payment/api/PaymentApi.java b/api/src/main/java/com/ning/billing/payment/api/PaymentApi.java
index 23778b8..b1413ae 100644
--- a/api/src/main/java/com/ning/billing/payment/api/PaymentApi.java
+++ b/api/src/main/java/com/ning/billing/payment/api/PaymentApi.java
@@ -28,14 +28,28 @@ import com.ning.billing.util.callcontext.TenantContext;
 
 public interface PaymentApi {
 
+    /**
+     * @param account   the account
+     * @param invoiceId the invoice id
+     * @param amount    the amount to pay
+     * @param context   the call context
+     * @return the payment
+     * @throws PaymentApiException
+     */
     public Payment createPayment(Account account, UUID invoiceId, BigDecimal amount, CallContext context)
             throws PaymentApiException;
 
+    /**
+     * @param account   the account
+     * @param invoiceId the invoice id
+     * @param amount    the amount to pay
+     * @param context   the call context
+     * @return the payment
+     * @throws PaymentApiException
+     */
     public Payment createExternalPayment(Account account, UUID invoiceId, BigDecimal amount, CallContext context)
             throws PaymentApiException;
 
-    public Refund getRefund(UUID refundId, TenantContext context)
-            throws PaymentApiException;
 
     /**
      * Create a refund for a given payment. The associated invoice is not adjusted.
@@ -51,6 +65,15 @@ public interface PaymentApi {
             throws PaymentApiException;
 
     /**
+     * @param refundId       the refund id
+     * @param withPluginInfo whether to fetch plugin info
+     * @param context        the call context  @return the refund
+     * @throws PaymentApiException
+     */
+    public Refund getRefund(UUID refundId, final boolean withPluginInfo, TenantContext context)
+            throws PaymentApiException;
+
+    /**
      * Create a refund for a given payment. The associated invoice is adjusted.
      *
      * @param account      account to refund
@@ -91,41 +114,117 @@ public interface PaymentApi {
     public Refund createRefundWithItemsAdjustments(Account account, UUID paymentId, Map<UUID, BigDecimal> invoiceItemIdsWithAmounts, CallContext context)
             throws PaymentApiException;
 
+    /**
+     * @param account the account
+     * @param context the call context
+     * @return the list of refund on this account
+     * @throws PaymentApiException
+     */
     public List<Refund> getAccountRefunds(Account account, TenantContext context)
             throws PaymentApiException;
 
+    /**
+     * @param paymentId the payment id
+     * @param context   the call context
+     * @return the list of refund on this account
+     * @throws PaymentApiException
+     */
     public List<Refund> getPaymentRefunds(UUID paymentId, TenantContext context)
             throws PaymentApiException;
 
+
+    /**
+     * @param invoiceId the invoice id
+     * @param context   the call context
+     * @return the list of payment on this invoice
+     * @throws PaymentApiException
+     */
     public List<Payment> getInvoicePayments(UUID invoiceId, TenantContext context)
             throws PaymentApiException;
 
+    /**
+     * @param accountId the account id
+     * @param context   the call context
+     * @return the list of payment on this account
+     * @throws PaymentApiException
+     */
     public List<Payment> getAccountPayments(UUID accountId, TenantContext context)
             throws PaymentApiException;
 
-    public Payment getPayment(UUID paymentId, TenantContext context)
+    /**
+     * @param paymentId      the payment id
+     * @param withPluginInfo whether to fetch plugin info
+     * @param context        the call context
+     * @return the payment
+     * @throws PaymentApiException
+     */
+    public Payment getPayment(UUID paymentId, final boolean withPluginInfo, TenantContext context)
             throws PaymentApiException;
 
-    /*
-     * Payment method Apis
+    /**
+     * @return a list of all the payment plugins registered
      */
     public Set<String> getAvailablePlugins();
 
+    /**
+     * @param pluginName        the plugin name
+     * @param account           the account
+     * @param setDefault        whether this should be set as a default payment method
+     * @param paymentMethodInfo the details for the payment method
+     * @param context           the call context
+     * @return the uuid of the payment method
+     * @throws PaymentApiException
+     */
     public UUID addPaymentMethod(String pluginName, Account account, boolean setDefault, PaymentMethodPlugin paymentMethodInfo, CallContext context)
             throws PaymentApiException;
 
+    /**
+     * @param account        the account id
+     * @param withPluginInfo whether we want to retrieve the plugin info for that payment method
+     * @param context        the call context
+     * @return the list of payment methods
+     * @throws PaymentApiException
+     */
     public List<PaymentMethod> getPaymentMethods(Account account, final boolean withPluginInfo, TenantContext context)
             throws PaymentApiException;
 
+    /**
+     * @param paymentMethodId the payment methid id
+     * @param withPluginInfo  whether we want to retrieve the plugin info for that payment method
+     * @param context         the call context
+     * @return the payment method
+     * @throws PaymentApiException
+     */
     public PaymentMethod getPaymentMethodById(UUID paymentMethodId, final boolean withPluginInfo, TenantContext context)
             throws PaymentApiException;
 
+    /**
+     * @param account         the account
+     * @param paymentMethodId the id of the payment  method
+     * @param deleteDefaultPaymentMethodWithAutoPayOff
+     *                        whether to allow deletion of default payment method and set account into AUTO_PAY_OFF
+     * @param context         the call context
+     * @throws PaymentApiException
+     */
     public void deletedPaymentMethod(Account account, UUID paymentMethodId, boolean deleteDefaultPaymentMethodWithAutoPayOff, CallContext context)
             throws PaymentApiException;
 
+    /**
+     * @param account         the account
+     * @param paymentMethodId the payment method id
+     * @param context         the call context
+     * @throws PaymentApiException
+     */
     public void setDefaultPaymentMethod(Account account, UUID paymentMethodId, CallContext context)
             throws PaymentApiException;
 
+    /**
+     * @param pluginName the name of the plugin
+     * @param account    the account
+     * @param context    the call context
+     * @return the list of payment methods for that account
+     * @throws PaymentApiException
+     */
     public List<PaymentMethod> refreshPaymentMethods(String pluginName, Account account, CallContext context)
             throws PaymentApiException;
 
diff --git a/api/src/main/java/com/ning/billing/payment/api/PaymentMethodPlugin.java b/api/src/main/java/com/ning/billing/payment/api/PaymentMethodPlugin.java
index 0433003..1c3d2a1 100644
--- a/api/src/main/java/com/ning/billing/payment/api/PaymentMethodPlugin.java
+++ b/api/src/main/java/com/ning/billing/payment/api/PaymentMethodPlugin.java
@@ -21,14 +21,104 @@ import java.util.List;
 public interface PaymentMethodPlugin {
 
 
+    /**
+     *
+     * @return the id from the plugin
+     */
     public String getExternalPaymentMethodId();
 
+    /**
+     *
+     * @return whether plugin sees that PM as being the default
+     */
     public boolean isDefaultPaymentMethod();
 
+    /**
+     *
+     * @return the list of key/value pair set by the plugin
+     */
     public List<PaymentMethodKVInfo> getProperties();
 
+    /**
+     *
+     * @param key the key for which to get the value
+     * @return the value associated with the key
+     */
     public String getValueString(String key);
 
+    /**
+     *
+     * @return the payment method type name if applicable
+     */
+    public String getType();
+
+    /**
+     *
+     * @return the credit card name if applicable
+     */
+    public String getCCName();
+
+    /**
+     *
+     * @return the credit card type if applicable
+     */
+    public String getCCType();
+
+    /**
+     *
+     * @return the credit card expiration month
+     */
+    public String getCCExprirationMonth();
+
+    /**
+     *
+     * @return the credit card expiration year
+     */
+    public String getCCExprirationYear();
+
+    /**
+     *
+     * @return the credit card last 4 numbers
+     */
+    public String getCCLast4();
+
+    /**
+     *
+     * @return the address line 1
+     */
+    public String getAddress1();
+
+    /**
+     *
+     * @return the address line 2
+     */
+    public String getAddress2();
+
+    /**
+     *
+     * @return the city
+     */
+    public String getCity();
+
+    /**
+     *
+     * @return the state
+     */
+    public String getState();
+
+    /**
+     *
+     * @return the zip
+     */
+    public String getZip();
+
+    /**
+     *
+     * @return the country
+     */
+    public String getCountry();
+
+
     public class PaymentMethodKVInfo {
 
         private final String key;
@@ -53,6 +143,8 @@ public interface PaymentMethodPlugin {
             return isUpdatable;
         }
 
+
+
         @Override
         public String toString() {
             final StringBuilder sb = new StringBuilder();
diff --git a/api/src/main/java/com/ning/billing/payment/api/Refund.java b/api/src/main/java/com/ning/billing/payment/api/Refund.java
index 8c3e66b..da6d3a8 100644
--- a/api/src/main/java/com/ning/billing/payment/api/Refund.java
+++ b/api/src/main/java/com/ning/billing/payment/api/Refund.java
@@ -22,6 +22,7 @@ import java.util.UUID;
 import org.joda.time.DateTime;
 
 import com.ning.billing.catalog.api.Currency;
+import com.ning.billing.payment.plugin.api.RefundInfoPlugin;
 import com.ning.billing.util.entity.Entity;
 
 public interface Refund extends Entity {
@@ -37,4 +38,6 @@ public interface Refund extends Entity {
     public Currency getCurrency();
 
     public DateTime getEffectiveDate();
+
+    public RefundInfoPlugin getPluginDetail();
 }
diff --git a/api/src/main/java/com/ning/billing/payment/plugin/api/PaymentInfoPlugin.java b/api/src/main/java/com/ning/billing/payment/plugin/api/PaymentInfoPlugin.java
index 50a2ac9..13965bc 100644
--- a/api/src/main/java/com/ning/billing/payment/plugin/api/PaymentInfoPlugin.java
+++ b/api/src/main/java/com/ning/billing/payment/plugin/api/PaymentInfoPlugin.java
@@ -57,4 +57,17 @@ public interface PaymentInfoPlugin {
      * @return gateway error code, if any
      */
     public String getGatewayErrorCode();
+
+    /**
+     *
+     * @return the first payment reference id
+     */
+    public String getFirstPaymentReferenceId();
+
+    /**
+     *
+     * @return the first payment reference id
+     */
+    public String getSecondPaymentReferenceId();
+
 }
diff --git a/api/src/main/java/com/ning/billing/payment/plugin/api/PaymentPluginApi.java b/api/src/main/java/com/ning/billing/payment/plugin/api/PaymentPluginApi.java
index f2d0687..9ac1f20 100644
--- a/api/src/main/java/com/ning/billing/payment/plugin/api/PaymentPluginApi.java
+++ b/api/src/main/java/com/ning/billing/payment/plugin/api/PaymentPluginApi.java
@@ -30,25 +30,25 @@ public interface PaymentPluginApi {
     /**
      * Charge a specific amount in the Gateway. Required.
      *
-     * @param kbAccountId        killbill accountId
-     * @param kbPaymentId        killbill payment id (for reference)
-     * @param kbPaymentMethodId  killbill payment method id
-     * @param amount             amount to charge
-     * @param currency           currency
-     * @param context            call context
+     * @param kbAccountId       killbill accountId
+     * @param kbPaymentId       killbill payment id (for reference)
+     * @param kbPaymentMethodId killbill payment method id
+     * @param amount            amount to charge
+     * @param currency          currency
+     * @param context           call context
      * @return information about the payment in the gateway
      * @throws PaymentPluginApiException
      */
     public PaymentInfoPlugin processPayment(UUID kbAccountId, UUID kbPaymentId, UUID kbPaymentMethodId, BigDecimal amount, Currency currency, CallContext context)
             throws PaymentPluginApiException;
 
+
     /**
      * Retrieve information about a given payment. Optional (not all gateways will support it).
      *
-     *
-     * @param kbAccountId      killbill accountId
-     * @param kbPaymentId      killbill payment id (for reference)
-     * @param context          call context
+     * @param kbAccountId killbill accountId
+     * @param kbPaymentId killbill payment id (for reference)
+     * @param context     call context
      * @return information about the payment in the gateway
      * @throws PaymentPluginApiException
      */
@@ -58,21 +58,32 @@ public interface PaymentPluginApi {
     /**
      * Process a refund against a given payment. Required.
      *
-     *
-     * @param kbAccountId      killbill accountId
-     * @param kbPaymentId      killbill payment id (for reference)
-     * @param refundAmount     refund amount
-     * @param currency         currency
-     * @param context          call context
+     * @param kbAccountId  killbill accountId
+     * @param kbPaymentId  killbill payment id (for reference)
+     * @param refundAmount refund amount
+     * @param currency     currency
+     * @param context      call context
      * @return information about the refund in the gateway
      * @throws PaymentPluginApiException
      */
     public RefundInfoPlugin processRefund(UUID kbAccountId, UUID kbPaymentId, BigDecimal refundAmount, Currency currency, CallContext context)
             throws PaymentPluginApiException;
 
+
+    /**
+     * @param kbAccountId killbill account id
+     * @param kbPaymentId killbill payment id
+     * @param context     call context
+     * @return information about the refunds in the gateway
+     * @throws PaymentPluginApiException
+     */
+    public List<RefundInfoPlugin> getRefundInfo(UUID kbAccountId, UUID kbPaymentId, TenantContext context)
+            throws PaymentPluginApiException;
+
+
     /**
      * Add a payment method for a Killbill account in the gateway. Optional.
-     *
+     * <p/>
      * Note: the payment method doesn't exist yet in Killbill when receiving the call in
      * the plugin (kbPaymentMethodId is a placeholder).
      *
@@ -88,9 +99,9 @@ public interface PaymentPluginApi {
     /**
      * Delete a payment method in the gateway. Optional.
      *
-     * @param kbAccountId        killbill accountId
-     * @param kbPaymentMethodId      killbill payment method id
-     * @param context                call context
+     * @param kbAccountId       killbill accountId
+     * @param kbPaymentMethodId killbill payment method id
+     * @param context           call context
      * @throws PaymentPluginApiException
      */
     public void deletePaymentMethod(UUID kbAccountId, UUID kbPaymentMethodId, CallContext context)
@@ -111,25 +122,24 @@ public interface PaymentPluginApi {
     /**
      * Set a payment method as default in the gateway. Optional.
      *
-     * @param kbAccountId        killbill accountId
-     * @param kbPaymentMethodId      killbill payment method id
-     * @param context                call context
+     * @param kbAccountId       killbill accountId
+     * @param kbPaymentMethodId killbill payment method id
+     * @param context           call context
      * @throws PaymentPluginApiException
      */
     public void setDefaultPaymentMethod(UUID kbAccountId, UUID kbPaymentMethodId, CallContext context)
             throws PaymentPluginApiException;
 
     /**
-     *
      * This is used to see the view of paymentMethods kept by the plugin or the view of
      * existing payment method on the gateway.
-     *
+     * <p/>
      * Sometimes payment methods have to be added directly to the gateway for PCI compliance issues
      * and so Killbill needs to refresh its state.
      *
-     * @param kbAccountId           killbill accountId
-     * @param refreshFromGateway    fetch the list of existing  payment methods from gateway-- if supported
-     * @param context               call context
+     * @param kbAccountId        killbill accountId
+     * @param refreshFromGateway fetch the list of existing  payment methods from gateway-- if supported
+     * @param context            call context
      * @return
      */
     public List<PaymentMethodInfoPlugin> getPaymentMethods(UUID kbAccountId, boolean refreshFromGateway, CallContext context)
@@ -138,8 +148,8 @@ public interface PaymentPluginApi {
     /**
      * This is used after Killbill decided to refresh its state from the gateway
      *
-     * @param kbAccountId        killbill accountId
-     * @param paymentMethods        the list of payment methods
+     * @param kbAccountId    killbill accountId
+     * @param paymentMethods the list of payment methods
      */
     public void resetPaymentMethods(UUID kbAccountId, List<PaymentMethodInfoPlugin> paymentMethods)
             throws PaymentPluginApiException;
diff --git a/api/src/main/java/com/ning/billing/payment/plugin/api/RefundInfoPlugin.java b/api/src/main/java/com/ning/billing/payment/plugin/api/RefundInfoPlugin.java
index c0c6662..4ac0695 100644
--- a/api/src/main/java/com/ning/billing/payment/plugin/api/RefundInfoPlugin.java
+++ b/api/src/main/java/com/ning/billing/payment/plugin/api/RefundInfoPlugin.java
@@ -57,4 +57,10 @@ public interface RefundInfoPlugin {
      * @return gateway error code, if any
      */
     public String getGatewayErrorCode();
+
+    /**
+     *
+     * @return the reference id
+     */
+    public String getReferenceId();
 }
diff --git a/api/src/main/java/com/ning/billing/util/api/CustomFieldUserApi.java b/api/src/main/java/com/ning/billing/util/api/CustomFieldUserApi.java
index 12f278b..25905e8 100644
--- a/api/src/main/java/com/ning/billing/util/api/CustomFieldUserApi.java
+++ b/api/src/main/java/com/ning/billing/util/api/CustomFieldUserApi.java
@@ -25,10 +25,43 @@ import com.ning.billing.ObjectType;
 import com.ning.billing.util.callcontext.CallContext;
 import com.ning.billing.util.callcontext.TenantContext;
 import com.ning.billing.util.customfield.CustomField;
+import com.ning.billing.util.tag.Tag;
 
 public interface CustomFieldUserApi {
 
-    List<CustomField> getCustomFields(UUID objectId, ObjectType objectType, TenantContext context);
-
+    /**
+     *
+     * @param fields the list of fields to add
+     * @param context the call context
+     * @throws CustomFieldApiException
+     */
     void addCustomFields(List<CustomField> fields, CallContext context) throws CustomFieldApiException;
+
+    /**
+     *
+     * @param objectId the object id
+     * @param objectType the object type
+     * @param context the call context
+     * @return the list of custom fields associated with that object
+     */
+    List<CustomField> getCustomFieldsForObject(UUID objectId, ObjectType objectType, TenantContext context);
+
+
+    /**
+     *
+     * @param accountId the account id
+     * @param objectType the object type
+     * @param context the call context
+     * @return  the list of custom fields associated with that account for the specified type
+     */
+    List<CustomField> getCustomFieldsForAccountType(UUID accountId, ObjectType objectType, TenantContext context);
+
+
+    /**
+     *
+     * @param accountId the account id
+     * @param context the call context
+     * @return  the list of custom fields associated with that account
+     */
+    List<CustomField> getCustomFieldsForAccount(UUID accountId, TenantContext context);
 }
diff --git a/api/src/main/java/com/ning/billing/util/api/RecordIdApi.java b/api/src/main/java/com/ning/billing/util/api/RecordIdApi.java
new file mode 100644
index 0000000..d2fb17f
--- /dev/null
+++ b/api/src/main/java/com/ning/billing/util/api/RecordIdApi.java
@@ -0,0 +1,37 @@
+/*
+ * 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.util.api;
+
+import java.util.UUID;
+
+import com.ning.billing.ObjectType;
+import com.ning.billing.util.callcontext.TenantContext;
+
+public interface RecordIdApi {
+
+    /**
+     *
+     * This can be used by external plugins to keep the mapping between UUID  and recordId
+     *
+     *
+     * @param objectId the uuid of the object
+     * @param objectType the object type
+     * @param tenantContext the context associated with the call
+     * @return the record id associated with that object
+     */
+    Long getRecordId(UUID objectId, ObjectType objectType, final TenantContext tenantContext);
+}
diff --git a/api/src/main/java/com/ning/billing/util/api/TagUserApi.java b/api/src/main/java/com/ning/billing/util/api/TagUserApi.java
index f8760f8..38d9e48 100644
--- a/api/src/main/java/com/ning/billing/util/api/TagUserApi.java
+++ b/api/src/main/java/com/ning/billing/util/api/TagUserApi.java
@@ -18,7 +18,6 @@ package com.ning.billing.util.api;
 
 import java.util.Collection;
 import java.util.List;
-import java.util.Map;
 import java.util.UUID;
 
 import com.ning.billing.ObjectType;
@@ -51,18 +50,65 @@ public interface TagUserApi {
      */
     public void deleteTagDefinition(UUID tagDefinitionId, CallContext context) throws TagDefinitionApiException;
 
+    /**
+     * @param tagDefinitionId The tag definition id
+     * @param context         The call context, for auditing purposes
+     * @return The Tag definition
+     * @throws TagDefinitionApiException
+     */
     public TagDefinition getTagDefinition(UUID tagDefinitionId, TenantContext context) throws TagDefinitionApiException;
 
+    /**
+     * @param tageDefinitionName The tag definition name
+     * @param context            The call context, for auditing purposes
+     * @return the tag definition
+     * @throws TagDefinitionApiException
+     */
     public TagDefinition getTagDefinitionForName(String tageDefinitionName, TenantContext context) throws TagDefinitionApiException;
 
+    /**
+     * @param tagDefinitionIds The collection of the defintion ids
+     * @param context          The call context, for auditing purposes
+     * @return the tag definition
+     * @throws TagDefinitionApiException
+     * @throws TagDefinitionApiException
+     */
     public List<TagDefinition> getTagDefinitions(Collection<UUID> tagDefinitionIds, TenantContext context) throws TagDefinitionApiException;
 
+    /**
+     * @param objectId         The id for the object on which to add tags
+     * @param objectType       The object type
+     * @param tagDefinitionIds The collection of tag definition ids
+     * @param context          The call context, for auditing purposes
+     * @throws TagApiException
+     */
     public void addTags(UUID objectId, ObjectType objectType, Collection<UUID> tagDefinitionIds, CallContext context) throws TagApiException;
 
+    /**
+     * @param objectId        The id for the object on which to add tags
+     * @param objectType      The object type
+     * @param tagDefinitionId The tag definition id
+     * @param context         The call context, for auditing purposes
+     * @throws TagApiException
+     */
     public void addTag(UUID objectId, ObjectType objectType, UUID tagDefinitionId, CallContext context) throws TagApiException;
 
+    /**
+     * @param objectId       The id for the object on which to add tags
+     * @param objectType     The object type
+     * @param tagDefinitions The collection of tag definition ids
+     * @param context        The call context, for auditing purposes
+     * @throws TagApiException
+     */
     public void removeTags(UUID objectId, ObjectType objectType, Collection<UUID> tagDefinitions, CallContext context) throws TagApiException;
 
+    /**
+     * @param objectId        The id for the object on which to add tags
+     * @param objectType      The object type
+     * @param tagDefinitionId The tage definition id
+     * @param context         The call context, for auditing purposes
+     * @throws TagApiException
+     */
     public void removeTag(UUID objectId, ObjectType objectType, UUID tagDefinitionId, CallContext context) throws TagApiException;
 
     /**
@@ -71,5 +117,22 @@ public interface TagUserApi {
      * @param context    The tenant context
      * @return A map of tag, key being the tagId, and value the tag
      */
-    public List<Tag> getTags(UUID objectId, ObjectType objectType, TenantContext context);
+    public List<Tag> getTagsForObject(UUID objectId, ObjectType objectType, TenantContext context);
+
+    /**
+     * @param accountId  The account id
+     * @param objectType The type of object on which to retrieve the tags
+     * @param context    The tenant context
+     * @return A list of tags for that object type and that given account
+     */
+    public List<Tag> getTagsForAccountType(UUID accountId, ObjectType objectType, TenantContext context);
+
+
+    /**
+     *
+     * @param accountId The account id
+     * @param context   The tenant context
+     * @return A list of tags for that given account
+     */
+    public List<Tag> getTagsForAccount(UUID accountId, TenantContext context);
 }
diff --git a/api/src/main/java/com/ning/billing/util/tag/ControlTagType.java b/api/src/main/java/com/ning/billing/util/tag/ControlTagType.java
index 3101622..f270c64 100644
--- a/api/src/main/java/com/ning/billing/util/tag/ControlTagType.java
+++ b/api/src/main/java/com/ning/billing/util/tag/ControlTagType.java
@@ -29,7 +29,9 @@ public enum ControlTagType {
     AUTO_INVOICING_OFF(new UUID(0, 2), "Suspends invoicing until removed.", false, true, Collections.<ObjectType>singletonList(ObjectType.ACCOUNT)),
     OVERDUE_ENFORCEMENT_OFF(new UUID(0, 3), "Suspends overdue enforcement behaviour until removed.", false, false, Collections.<ObjectType>singletonList(ObjectType.ACCOUNT)),
     WRITTEN_OFF(new UUID(0, 4), "Indicates that an invoice is written off. No billing or payment effect.", false, false, Collections.<ObjectType>singletonList(ObjectType.INVOICE)),
-    MANUAL_PAY(new UUID(0, 5), "Indicates that Killbill doesn't process payments for that account (external payments only)", true, false, Collections.<ObjectType>singletonList(ObjectType.ACCOUNT));
+    MANUAL_PAY(new UUID(0, 5), "Indicates that Killbill doesn't process payments for that account (external payments only)", true, false, Collections.<ObjectType>singletonList(ObjectType.ACCOUNT)),
+    TEST(new UUID(0, 6), "Indicates that this is a test account", false, false, Collections.<ObjectType>singletonList(com.ning.billing.ObjectType.ACCOUNT)),
+    PARTNER(new UUID(0, 7), "Indicates that this is a partner account", false, false, Collections.<ObjectType>singletonList(com.ning.billing.ObjectType.ACCOUNT));
 
     private final UUID id;
     private final String description;

beatrix/pom.xml 2(+1 -1)

diff --git a/beatrix/pom.xml b/beatrix/pom.xml
index 47de85f..3893760 100644
--- a/beatrix/pom.xml
+++ b/beatrix/pom.xml
@@ -20,7 +20,7 @@
     <parent>
         <groupId>com.ning.billing</groupId>
         <artifactId>killbill</artifactId>
-        <version>0.1.62-SNAPSHOT</version>
+        <version>0.1.64-SNAPSHOT</version>
         <relativePath>../pom.xml</relativePath>
     </parent>
     <artifactId>killbill-beatrix</artifactId>
diff --git a/beatrix/src/main/java/com/ning/billing/beatrix/extbus/BeatrixListener.java b/beatrix/src/main/java/com/ning/billing/beatrix/extbus/BeatrixListener.java
index 2f87e4a..07b4cf7 100644
--- a/beatrix/src/main/java/com/ning/billing/beatrix/extbus/BeatrixListener.java
+++ b/beatrix/src/main/java/com/ning/billing/beatrix/extbus/BeatrixListener.java
@@ -35,8 +35,20 @@ import com.ning.billing.util.callcontext.UserType;
 import com.ning.billing.util.events.AccountChangeInternalEvent;
 import com.ning.billing.util.events.AccountCreationInternalEvent;
 import com.ning.billing.util.events.BusInternalEvent;
+import com.ning.billing.util.events.ControlTagCreationInternalEvent;
+import com.ning.billing.util.events.ControlTagDeletionInternalEvent;
+import com.ning.billing.util.events.CustomFieldCreationEvent;
+import com.ning.billing.util.events.CustomFieldDeletionEvent;
+import com.ning.billing.util.events.InvoiceAdjustmentInternalEvent;
+import com.ning.billing.util.events.InvoiceCreationInternalEvent;
+import com.ning.billing.util.events.InvoiceInternalEvent;
 import com.ning.billing.util.events.OverdueChangeInternalEvent;
+import com.ning.billing.util.events.PaymentErrorInternalEvent;
+import com.ning.billing.util.events.PaymentInfoInternalEvent;
 import com.ning.billing.util.events.SubscriptionInternalEvent;
+import com.ning.billing.util.events.UserTagCreationInternalEvent;
+import com.ning.billing.util.events.UserTagDefinitionCreationInternalEvent;
+import com.ning.billing.util.events.UserTagDefinitionDeletionInternalEvent;
 import com.ning.billing.util.svcsapi.bus.InternalBus.EventBusException;
 
 import com.google.common.eventbus.Subscribe;
@@ -59,24 +71,6 @@ public class BeatrixListener {
 
     @Subscribe
     public void handleAllInternalKillbillEvents(final BusInternalEvent event) {
-        switch(event.getBusEventType()) {
-            case ACCOUNT_CREATE:
-                break;
-            case ACCOUNT_CHANGE:
-                break;
-            case SUBSCRIPTION_TRANSITION:
-                break;
-            case INVOICE_CREATION:
-                break;
-            case PAYMENT_INFO:
-                break;
-            case PAYMENT_ERROR:
-                break;
-            case OVERDUE_CHANGE:
-                break;
-            default:
-                // Ignore for now.
-        }
         final ExtBusEventEntry externalEvent = computeExtBusEventEntryFromBusInternalEvent(event);
         try {
 
@@ -89,6 +83,7 @@ public class BeatrixListener {
         }
     }
 
+
     private ExtBusEventEntry computeExtBusEventEntryFromBusInternalEvent(final BusInternalEvent event) {
 
         ObjectType objectType  = null;
@@ -122,14 +117,36 @@ public class BeatrixListener {
             } else if (realEventST.getTransitionType() == SubscriptionTransitionType.CHANGE) {
                 eventBusType = ExtBusEventType.SUBSCRIPTION_CHANGE;
             }
-
             break;
+
         case INVOICE_CREATION:
+            InvoiceCreationInternalEvent realEventInv = (InvoiceCreationInternalEvent) event;
+            objectType = ObjectType.INVOICE;
+            objectId = realEventInv.getInvoiceId();
+            eventBusType = ExtBusEventType.INVOICE_CREATION;
+            break;
+
+        case INVOICE_ADJUSTMENT:
+            InvoiceAdjustmentInternalEvent realEventInvAdj = (InvoiceAdjustmentInternalEvent) event;
+            objectType = ObjectType.INVOICE;
+            objectId = realEventInvAdj.getInvoiceId();
+            eventBusType = ExtBusEventType.INVOICE_ADJUSTMENT;
             break;
+
         case PAYMENT_INFO:
+            PaymentInfoInternalEvent realEventPay = (PaymentInfoInternalEvent) event;
+            objectType = ObjectType.PAYMENT;
+            objectId = realEventPay.getPaymentId();
+            eventBusType = ExtBusEventType.PAYMENT_SUCCESS;
             break;
+
         case PAYMENT_ERROR:
+            PaymentErrorInternalEvent realEventPayErr = (PaymentErrorInternalEvent) event;
+            objectType = ObjectType.PAYMENT;
+            objectId = realEventPayErr.getPaymentId();
+            eventBusType = ExtBusEventType.PAYMENT_FAILED;
             break;
+
         case OVERDUE_CHANGE:
             OverdueChangeInternalEvent realEventOC = (OverdueChangeInternalEvent) event;
             // TODO When Killbil supports more than overdue for bundle, this will break...
@@ -137,6 +154,49 @@ public class BeatrixListener {
             objectId = realEventOC.getOverdueObjectId();
             eventBusType = ExtBusEventType.OVERDUE_CHANGE;
             break;
+
+       case USER_TAG_CREATION:
+           UserTagCreationInternalEvent realUserTagEventCr = (UserTagCreationInternalEvent) event;
+           objectType = ObjectType.TAG;
+           objectId = realUserTagEventCr.getTagId();
+           eventBusType = ExtBusEventType.TAG_CREATION;
+           break;
+
+       case CONTROL_TAG_CREATION:
+           ControlTagCreationInternalEvent realTagEventCr = (ControlTagCreationInternalEvent) event;
+           objectType = ObjectType.TAG;
+           objectId = realTagEventCr.getTagId();
+           eventBusType = ExtBusEventType.TAG_CREATION;
+           break;
+
+       case USER_TAG_DELETION:
+           UserTagDefinitionDeletionInternalEvent realUserTagEventDel = (UserTagDefinitionDeletionInternalEvent) event;
+           objectType = ObjectType.TAG;
+           objectId = null; // TODO missing..
+           eventBusType = ExtBusEventType.TAG_DELETION;
+           break;
+
+       case CONTROL_TAG_DELETION:
+           ControlTagDeletionInternalEvent realTagEventDel = (ControlTagDeletionInternalEvent) event;
+           objectType = ObjectType.TAG;
+           objectId = realTagEventDel.getTagId();
+           eventBusType = ExtBusEventType.TAG_DELETION;
+           break;
+
+       case CUSTOM_FIELD_CREATION:
+           CustomFieldCreationEvent realCustomEveventCr = (CustomFieldCreationEvent) event;
+           objectType = ObjectType.CUSTOM_FIELD;
+           objectId = realCustomEveventCr.getCustomFieldId();
+           eventBusType = ExtBusEventType.CUSTOM_FIELD_CREATION;
+           break;
+
+       case CUSTOM_FIELD_DELETION:
+           CustomFieldDeletionEvent realCustomEveventDel = (CustomFieldDeletionEvent) event;
+           objectType = ObjectType.CUSTOM_FIELD;
+           objectId = realCustomEveventDel.getCustomFieldId();
+           eventBusType = ExtBusEventType.CUSTOM_FIELD_DELETION;
+           break;
+
         default:
         }
         return eventBusType != null ?
diff --git a/beatrix/src/main/java/com/ning/billing/beatrix/extbus/dao/ExtBusSqlDao.java b/beatrix/src/main/java/com/ning/billing/beatrix/extbus/dao/ExtBusSqlDao.java
index 913b94a..6a40311 100644
--- a/beatrix/src/main/java/com/ning/billing/beatrix/extbus/dao/ExtBusSqlDao.java
+++ b/beatrix/src/main/java/com/ning/billing/beatrix/extbus/dao/ExtBusSqlDao.java
@@ -83,16 +83,24 @@ public interface ExtBusSqlDao extends Transactional<ExtBusSqlDao>, CloseMe {
 
         @Override
         public void bind(@SuppressWarnings("rawtypes") final SQLStatement stmt, final Bind bind, final ExtBusEventEntry evt) {
-            stmt.bind("eventType", evt.getExtBusType().toString());
-            stmt.bind("objectId", evt.getObjectId().toString());
-            stmt.bind("objectType", evt.getObjectType().toString());
+            stmt.bind("eventType", extractWithNullValue(evt.getExtBusType().toString()));
+            stmt.bind("objectId", extractWithNullValue(evt.getObjectId().toString()));
+            stmt.bind("objectType", extractWithNullValue(evt.getObjectType().toString()));
             stmt.bind("userToken", getUUIDString(evt.getUserToken()));
             stmt.bind("createdDate", getDate(new DateTime()));
-            stmt.bind("creatingOwner", evt.getCreatedOwner());
+            stmt.bind("creatingOwner", extractWithNullValue(evt.getCreatedOwner()));
             stmt.bind("processingAvailableDate", getDate(evt.getNextAvailableDate()));
-            stmt.bind("processingOwner", evt.getOwner());
+            stmt.bind("processingOwner", extractWithNullValue(evt.getOwner()));
             stmt.bind("processingState", PersistentQueueEntryLifecycleState.AVAILABLE.toString());
         }
+
+        private String extractWithNullValue(Object obj) {
+            if (obj == null) {
+                return null;
+            }
+            return obj.toString();
+        }
+
     }
 
     public static class ExtBusSqlMapper extends MapperBase implements ResultSetMapper<ExtBusEventEntry> {
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 776b127..66f3169 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
@@ -67,6 +67,7 @@ import com.ning.billing.util.glue.ExportModule;
 import com.ning.billing.util.glue.GlobalLockerModule;
 import com.ning.billing.util.glue.NonEntityDaoModule;
 import com.ning.billing.util.glue.NotificationQueueModule;
+import com.ning.billing.util.glue.RecordIdModule;
 import com.ning.billing.util.glue.TagStoreModule;
 import com.ning.billing.util.svcsapi.bus.BusService;
 
@@ -122,6 +123,7 @@ public class BeatrixIntegrationModule extends AbstractModule {
         install(new ExportModule());
         install(new DefaultOSGIModule(configSource));
         install(new NonEntityDaoModule());
+        install(new RecordIdModule());
 
         bind(AccountChecker.class).asEagerSingleton();
         bind(EntitlementChecker.class).asEagerSingleton();
diff --git a/beatrix/src/test/java/com/ning/billing/beatrix/integration/overdue/TestOverdueBase.java b/beatrix/src/test/java/com/ning/billing/beatrix/integration/overdue/TestOverdueBase.java
index 3594ec2..f035a12 100644
--- a/beatrix/src/test/java/com/ning/billing/beatrix/integration/overdue/TestOverdueBase.java
+++ b/beatrix/src/test/java/com/ning/billing/beatrix/integration/overdue/TestOverdueBase.java
@@ -13,11 +13,8 @@
  * License for the specific language governing permissions and limitations
  * under the License.
  */
-package com.ning.billing.beatrix.integration.overdue;
 
-import static com.jayway.awaitility.Awaitility.await;
-import static java.util.concurrent.TimeUnit.SECONDS;
-import static org.testng.Assert.assertNotNull;
+package com.ning.billing.beatrix.integration.overdue;
 
 import java.io.ByteArrayInputStream;
 import java.io.InputStream;
@@ -35,8 +32,13 @@ import com.ning.billing.catalog.api.BillingPeriod;
 import com.ning.billing.entitlement.api.user.SubscriptionBundle;
 import com.ning.billing.overdue.config.OverdueConfig;
 import com.ning.billing.payment.api.PaymentMethodPlugin;
+import com.ning.billing.payment.api.TestPaymentMethodPluginBase;
 import com.ning.billing.util.config.catalog.XMLLoader;
 
+import static com.jayway.awaitility.Awaitility.await;
+import static java.util.concurrent.TimeUnit.SECONDS;
+import static org.testng.Assert.assertNotNull;
+
 public abstract class TestOverdueBase extends TestIntegrationBase {
 
 
@@ -48,31 +50,11 @@ public abstract class TestOverdueBase extends TestIntegrationBase {
 
     public abstract String getOverdueConfig();
 
-    final PaymentMethodPlugin paymentMethodPlugin = new PaymentMethodPlugin() {
-        @Override
-        public boolean isDefaultPaymentMethod() {
-            return false;
-        }
-
-        @Override
-        public String getValueString(final String key) {
-            return null;
-        }
-
-        @Override
-        public List<PaymentMethodKVInfo> getProperties() {
-            return null;
-        }
-
-        @Override
-        public String getExternalPaymentMethodId() {
-            return UUID.randomUUID().toString();
-        }
-    };
+    final PaymentMethodPlugin paymentMethodPlugin = new TestPaymentMethodPluginBase();
 
     @Override
     @BeforeMethod(groups = "slow")
-    public void beforeMethod( ) throws Exception {
+    public void beforeMethod() throws Exception {
         super.beforeMethod();
         final String configXml = getOverdueConfig();
         final InputStream is = new ByteArrayInputStream(configXml.getBytes());
@@ -110,6 +92,4 @@ public abstract class TestOverdueBase extends TestIntegrationBase {
             Assert.assertEquals(blockingApi.getBlockingStateFor(bundle, internalCallContext).getStateName(), expected, "Got exception: " + e.toString());
         }
     }
-
-
 }
diff --git a/beatrix/src/test/java/com/ning/billing/beatrix/integration/overdue/TestOverdueIntegration.java b/beatrix/src/test/java/com/ning/billing/beatrix/integration/overdue/TestOverdueIntegration.java
index 5ad8c97..94f8e77 100644
--- a/beatrix/src/test/java/com/ning/billing/beatrix/integration/overdue/TestOverdueIntegration.java
+++ b/beatrix/src/test/java/com/ning/billing/beatrix/integration/overdue/TestOverdueIntegration.java
@@ -366,7 +366,7 @@ public class TestOverdueIntegration extends TestOverdueBase {
         checkODState(DefaultBlockingState.CLEAR_STATE_NAME);
 
         // Now, refund the second (first non-zero dollar) invoice
-        final Payment payment = paymentApi.getPayment(invoiceUserApi.getInvoicesByAccount(account.getId(), callContext).get(1).getPayments().get(0).getPaymentId(), callContext);
+        final Payment payment = paymentApi.getPayment(invoiceUserApi.getInvoicesByAccount(account.getId(), callContext).get(1).getPayments().get(0).getPaymentId(), false, callContext);
         refundPaymentAndCheckForCompletion(account, payment, NextEvent.INVOICE_ADJUSTMENT);
         // We should now be in OD1
         checkODState("OD1");
diff --git a/beatrix/src/test/java/com/ning/billing/beatrix/integration/TestCustomFieldApi.java b/beatrix/src/test/java/com/ning/billing/beatrix/integration/TestCustomFieldApi.java
new file mode 100644
index 0000000..8ee396a
--- /dev/null
+++ b/beatrix/src/test/java/com/ning/billing/beatrix/integration/TestCustomFieldApi.java
@@ -0,0 +1,147 @@
+/*
+ * 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.beatrix.integration;
+
+import java.util.ArrayList;
+import java.util.List;
+import java.util.UUID;
+
+import org.joda.time.DateTime;
+import org.testng.Assert;
+import org.testng.annotations.BeforeMethod;
+import org.testng.annotations.Test;
+
+import com.ning.billing.ObjectType;
+import com.ning.billing.account.api.Account;
+import com.ning.billing.api.TestApiListener.NextEvent;
+import com.ning.billing.catalog.api.BillingPeriod;
+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.entitlement.api.user.EntitlementUserApiException;
+import com.ning.billing.entitlement.api.user.SubscriptionBundle;
+import com.ning.billing.entitlement.api.user.SubscriptionData;
+import com.ning.billing.invoice.api.Invoice;
+import com.ning.billing.util.api.CustomFieldApiException;
+import com.ning.billing.util.api.CustomFieldUserApi;
+import com.ning.billing.util.customfield.CustomField;
+import com.ning.billing.util.customfield.StringCustomField;
+
+import com.google.inject.Inject;
+
+import static org.testng.Assert.assertNotNull;
+import static org.testng.Assert.assertTrue;
+
+public class TestCustomFieldApi extends TestIntegrationBase {
+
+
+    private Account account;
+
+    @Inject
+    private CustomFieldUserApi customFieldApi;
+
+    @Override
+    @BeforeMethod(groups = {"slow"})
+    public void beforeMethod() throws Exception {
+        super.beforeMethod();
+        account = createAccountWithNonOsgiPaymentMethod(getAccountData(25));
+        assertNotNull(account);
+    }
+
+    @Test(groups = "slow")
+    public void testCustomFieldForAccount() throws CustomFieldApiException {
+        addCustomField("name1", "value1", account.getId(), ObjectType.ACCOUNT, clock.getUTCNow());
+        addCustomField("name2", "value2", account.getId(), ObjectType.ACCOUNT, clock.getUTCNow());
+
+        List<CustomField> fields = customFieldApi.getCustomFieldsForAccount(account.getId(), callContext);
+        Assert.assertEquals(fields.size(), 2);
+
+        fields = customFieldApi.getCustomFieldsForAccountType(account.getId(), ObjectType.ACCOUNT, callContext);
+        Assert.assertEquals(fields.size(), 2);
+
+        fields = customFieldApi.getCustomFieldsForObject(account.getId(), ObjectType.ACCOUNT, callContext);
+        Assert.assertEquals(fields.size(), 2);
+    }
+
+
+    @Test(groups = "slow")
+    public void testCustomFieldForInvoice() throws CustomFieldApiException, EntitlementUserApiException {
+
+        //
+        // Create necessary logic to end up with an Invoice object on that account.
+        //
+        final SubscriptionBundle bundle = entitlementUserApi.createBundleForAccount(account.getId(), "whatever", callContext);
+
+        final String productName = "Shotgun";
+        final BillingPeriod term = BillingPeriod.ANNUAL;
+        final String planSetName = PriceListSet.DEFAULT_PRICELIST_NAME;
+
+        busHandler.pushExpectedEvents(NextEvent.CREATE, NextEvent.INVOICE);
+        final PlanPhaseSpecifier bpPlanPhaseSpecifier = new PlanPhaseSpecifier(productName, ProductCategory.BASE, term, planSetName, null);
+        final SubscriptionData bpSubscription = subscriptionDataFromSubscription(entitlementUserApi.createSubscription(bundle.getId(),
+                                                                                                                       bpPlanPhaseSpecifier,
+                                                                                                                       null,
+                                                                                                                       callContext));
+        assertNotNull(bpSubscription);
+        assertTrue(busHandler.isCompleted(DELAY));
+        assertListenerStatus();
+
+        final List<Invoice> invoices = invoiceUserApi.getInvoicesByAccount(account.getId(), callContext);
+        Assert.assertEquals(invoices.size(), 1);
+
+        final Invoice invoice = invoices.get(0);
+        Assert.assertEquals(invoice.getAccountId(), account.getId());
+
+
+        addCustomField("name1", "value1", invoice.getId(), ObjectType.INVOICE, clock.getUTCNow());
+        addCustomField("name2", "value2", invoice.getId(), ObjectType.INVOICE, clock.getUTCNow());
+
+        List<CustomField> fields = customFieldApi.getCustomFieldsForAccount(invoice.getId(), callContext);
+        Assert.assertEquals(fields.size(), 2);
+
+        fields = customFieldApi.getCustomFieldsForAccountType(invoice.getId(), ObjectType.INVOICE, callContext);
+        Assert.assertEquals(fields.size(), 2);
+
+        fields = customFieldApi.getCustomFieldsForObject(invoice.getId(), ObjectType.INVOICE, callContext);
+        Assert.assertEquals(fields.size(), 2);
+
+        //
+        // Add custom field on account and retry
+        //
+        addCustomField("foo", "bar", account.getId(), ObjectType.ACCOUNT, clock.getUTCNow());
+
+        fields = customFieldApi.getCustomFieldsForAccount(invoice.getId(), callContext);
+        Assert.assertEquals(fields.size(), 3);
+
+        fields = customFieldApi.getCustomFieldsForAccountType(invoice.getId(), ObjectType.INVOICE, callContext);
+        Assert.assertEquals(fields.size(), 2);
+
+        fields = customFieldApi.getCustomFieldsForObject(invoice.getId(), ObjectType.INVOICE, callContext);
+        Assert.assertEquals(fields.size(), 2);
+    }
+
+    private void addCustomField(String name, String value, UUID objectId, ObjectType type, DateTime createdDate) throws CustomFieldApiException {
+        CustomField f = new StringCustomField(name, value, type, objectId, clock.getUTCNow());
+        busHandler.pushExpectedEvents(NextEvent.CUSTOM_FIELD);
+        List<CustomField> fields = new ArrayList<CustomField>();
+        fields.add(f);
+        customFieldApi.addCustomFields(fields, callContext);
+        assertTrue(busHandler.isCompleted(DELAY));
+
+    }
+
+}
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 8ca8e55..9c83c43 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
@@ -79,6 +79,7 @@ import com.ning.billing.payment.api.Payment;
 import com.ning.billing.payment.api.PaymentApi;
 import com.ning.billing.payment.api.PaymentApiException;
 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.util.api.TagUserApi;
 import com.ning.billing.util.config.OSGIConfig;
@@ -331,32 +332,18 @@ public class TestIntegrationBase extends BeatrixTestSuiteWithEmbeddedDB implemen
         return accountUserApi.getAccountById(account.getId(), callContext);
     }
 
+    private class TestPaymentMethodPlugin extends TestPaymentMethodPluginBase {
+        @Override
+        public List<PaymentMethodKVInfo> getProperties() {
+            PaymentMethodKVInfo prop = new PaymentMethodKVInfo("whatever", "cool", Boolean.TRUE);
+            List<PaymentMethodKVInfo> res = new ArrayList<PaymentMethodKVInfo>();
+            res.add(prop);
+            return res;
+        }
+    }
 
     protected PaymentMethodPlugin createPaymentMethodPlugin() {
-        return new PaymentMethodPlugin() {
-            @Override
-            public boolean isDefaultPaymentMethod() {
-                return false;
-            }
-
-            @Override
-            public String getValueString(final String key) {
-                return null;
-            }
-
-            @Override
-            public List<PaymentMethodKVInfo> getProperties() {
-                PaymentMethodKVInfo prop = new PaymentMethodKVInfo("whatever", "cool", Boolean.TRUE);
-                List<PaymentMethodKVInfo> res = new ArrayList<PaymentMethodKVInfo>();
-                res.add(prop);
-                return res;
-            }
-
-            @Override
-            public String getExternalPaymentMethodId() {
-                return UUID.randomUUID().toString();
-            }
-        };
+        return new TestPaymentMethodPlugin();
     }
 
     protected AccountData getAccountData(final int billingDay) {
diff --git a/beatrix/src/test/java/com/ning/billing/beatrix/integration/TestIntegrationWithAutoInvoiceOffTag.java b/beatrix/src/test/java/com/ning/billing/beatrix/integration/TestIntegrationWithAutoInvoiceOffTag.java
index 3fe7604..aaca80d 100644
--- a/beatrix/src/test/java/com/ning/billing/beatrix/integration/TestIntegrationWithAutoInvoiceOffTag.java
+++ b/beatrix/src/test/java/com/ning/billing/beatrix/integration/TestIntegrationWithAutoInvoiceOffTag.java
@@ -174,7 +174,7 @@ public class TestIntegrationWithAutoInvoiceOffTag extends TestIntegrationBase {
 
     private void add_AUTO_INVOICING_OFF_Tag(final UUID id, final ObjectType type) throws TagDefinitionApiException, TagApiException {
         tagApi.addTag(id, type, ControlTagType.AUTO_INVOICING_OFF.getId(), callContext);
-        final List<Tag> tags = tagApi.getTags(id, type, callContext);
+        final List<Tag> tags = tagApi.getTagsForObject(id, type, callContext);
         assertEquals(tags.size(), 1);
     }
 
diff --git a/beatrix/src/test/java/com/ning/billing/beatrix/integration/TestIntegrationWithAutoPayOff.java b/beatrix/src/test/java/com/ning/billing/beatrix/integration/TestIntegrationWithAutoPayOff.java
index ae23993..bb46d0c 100644
--- a/beatrix/src/test/java/com/ning/billing/beatrix/integration/TestIntegrationWithAutoPayOff.java
+++ b/beatrix/src/test/java/com/ning/billing/beatrix/integration/TestIntegrationWithAutoPayOff.java
@@ -281,7 +281,7 @@ public class TestIntegrationWithAutoPayOff extends TestIntegrationBase {
         busHandler.pushExpectedEvent(NextEvent.TAG);
         tagApi.addTag(id, type, ControlTagType.AUTO_PAY_OFF.getId(), callContext);
         assertTrue(busHandler.isCompleted(DELAY));
-        final List<Tag> tags = tagApi.getTags(id, type, callContext);
+        final List<Tag> tags = tagApi.getTagsForObject(id, type, callContext);
         assertEquals(tags.size(), 1);
     }
 
diff --git a/beatrix/src/test/java/com/ning/billing/beatrix/integration/TestTagApi.java b/beatrix/src/test/java/com/ning/billing/beatrix/integration/TestTagApi.java
new file mode 100644
index 0000000..91249e5
--- /dev/null
+++ b/beatrix/src/test/java/com/ning/billing/beatrix/integration/TestTagApi.java
@@ -0,0 +1,162 @@
+/*
+ * 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.beatrix.integration;
+
+import java.util.List;
+
+import org.testng.Assert;
+import org.testng.annotations.BeforeMethod;
+import org.testng.annotations.Test;
+
+import com.ning.billing.ObjectType;
+import com.ning.billing.account.api.Account;
+import com.ning.billing.api.TestApiListener.NextEvent;
+import com.ning.billing.catalog.api.BillingPeriod;
+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.entitlement.api.user.SubscriptionBundle;
+import com.ning.billing.entitlement.api.user.SubscriptionData;
+import com.ning.billing.invoice.api.Invoice;
+import com.ning.billing.util.api.TagUserApi;
+import com.ning.billing.util.callcontext.CallContext;
+import com.ning.billing.util.callcontext.CallContextBase;
+import com.ning.billing.util.callcontext.DefaultCallContext;
+import com.ning.billing.util.tag.ControlTagType;
+import com.ning.billing.util.tag.Tag;
+import com.ning.billing.util.tag.TagDefinition;
+
+import com.google.inject.Inject;
+
+import static org.testng.Assert.assertNotNull;
+import static org.testng.Assert.assertTrue;
+
+public class TestTagApi extends TestIntegrationBase {
+
+
+    private Account account;
+
+    @Inject
+    private TagUserApi tagApi;
+
+    @Override
+    @BeforeMethod(groups = {"slow"})
+    public void beforeMethod() throws Exception {
+        super.beforeMethod();
+        account = createAccountWithNonOsgiPaymentMethod(getAccountData(25));
+        assertNotNull(account);
+    }
+
+    @Test(groups = {"slow"}, enabled = true)
+    public void testApiTagOnAccount() throws Exception {
+
+        busHandler.pushExpectedEvents(NextEvent.TAG);
+        tagApi.addTag(account.getId(), ObjectType.ACCOUNT, ControlTagType.AUTO_INVOICING_OFF.getId(), callContext);
+        assertTrue(busHandler.isCompleted(DELAY));
+
+        busHandler.pushExpectedEvents(NextEvent.TAG);
+        tagApi.addTag(account.getId(), ObjectType.ACCOUNT, ControlTagType.AUTO_PAY_OFF.getId(), callContext);
+        assertTrue(busHandler.isCompleted(DELAY));
+
+        List<Tag> tags = tagApi.getTagsForAccount(account.getId(), callContext);
+        Assert.assertEquals(tags.size(), 2);
+
+        tags = tagApi.getTagsForObject(account.getId(), ObjectType.ACCOUNT, callContext);
+        Assert.assertEquals(tags.size(), 2);
+
+        tags = tagApi.getTagsForAccountType(account.getId(), ObjectType.ACCOUNT, callContext);
+        Assert.assertEquals(tags.size(), 2);
+    }
+
+
+    @Test(groups = {"slow"}, enabled = true)
+    public void testApiTagOnInvoice() throws Exception {
+
+        //
+        // Create necessary logic to end up with an Invoice object on that account.
+        //
+        final SubscriptionBundle bundle = entitlementUserApi.createBundleForAccount(account.getId(), "whatever", callContext);
+
+        final String productName = "Shotgun";
+        final BillingPeriod term = BillingPeriod.ANNUAL;
+        final String planSetName = PriceListSet.DEFAULT_PRICELIST_NAME;
+
+        busHandler.pushExpectedEvents(NextEvent.CREATE, NextEvent.INVOICE);
+        final PlanPhaseSpecifier bpPlanPhaseSpecifier = new PlanPhaseSpecifier(productName, ProductCategory.BASE, term, planSetName, null);
+        final SubscriptionData bpSubscription = subscriptionDataFromSubscription(entitlementUserApi.createSubscription(bundle.getId(),
+                                                                                                                       bpPlanPhaseSpecifier,
+                                                                                                                       null,
+                                                                                                                       callContext));
+        assertNotNull(bpSubscription);
+        assertTrue(busHandler.isCompleted(DELAY));
+        assertListenerStatus();
+
+        final List<Invoice> invoices = invoiceUserApi.getInvoicesByAccount(account.getId(), callContext);
+        Assert.assertEquals(invoices.size(), 1);
+
+        final Invoice invoice = invoices.get(0);
+        Assert.assertEquals(invoice.getAccountId(), account.getId());
+
+        //
+        // Create a new tag definition
+        //
+        busHandler.pushExpectedEvents(NextEvent.TAG_DEFINITION);
+        TagDefinition tagDefinition = tagApi.create("foo", "foo desc", callContext);
+        assertTrue(busHandler.isCompleted(DELAY));
+
+        //
+        // Add 2 Tags on the invoice (1 control tag and 1 user tag)
+        //
+        busHandler.pushExpectedEvents(NextEvent.TAG);
+        tagApi.addTag(invoice.getId(), ObjectType.INVOICE, ControlTagType.WRITTEN_OFF.getId(), callContext);
+        assertTrue(busHandler.isCompleted(DELAY));
+
+        busHandler.pushExpectedEvents(NextEvent.TAG);
+        tagApi.addTag(invoice.getId(), ObjectType.INVOICE, tagDefinition.getId(), callContext);
+        assertTrue(busHandler.isCompleted(DELAY));
+
+        List<Tag> tags = tagApi.getTagsForAccount(account.getId(), callContext);
+        Assert.assertEquals(tags.size(), 2);
+
+        tags = tagApi.getTagsForObject(invoice.getId(), ObjectType.INVOICE, callContext);
+        Assert.assertEquals(tags.size(), 2);
+
+        tags = tagApi.getTagsForAccountType(account.getId(), ObjectType.INVOICE, callContext);
+        Assert.assertEquals(tags.size(), 2);
+
+
+        //
+        // Add a tag on the account itself and retry
+        //
+        busHandler.pushExpectedEvents(NextEvent.TAG);
+        tagApi.addTag(account.getId(), ObjectType.ACCOUNT, ControlTagType.AUTO_PAY_OFF.getId(), callContext);
+        assertTrue(busHandler.isCompleted(DELAY));
+
+        tags = tagApi.getTagsForAccount(account.getId(), callContext);
+        Assert.assertEquals(tags.size(), 3);
+
+        tags = tagApi.getTagsForObject(invoice.getId(), ObjectType.INVOICE, callContext);
+        Assert.assertEquals(tags.size(), 2);
+
+        tags = tagApi.getTagsForAccountType(account.getId(), ObjectType.INVOICE, callContext);
+        Assert.assertEquals(tags.size(), 2);
+
+
+    }
+
+
+}
diff --git a/beatrix/src/test/java/com/ning/billing/beatrix/util/EntitlementChecker.java b/beatrix/src/test/java/com/ning/billing/beatrix/util/EntitlementChecker.java
index 593fc8c..bdf75f8 100644
--- a/beatrix/src/test/java/com/ning/billing/beatrix/util/EntitlementChecker.java
+++ b/beatrix/src/test/java/com/ning/billing/beatrix/util/EntitlementChecker.java
@@ -31,6 +31,7 @@ import com.ning.billing.entitlement.api.user.EntitlementUserApiException;
 import com.ning.billing.entitlement.api.user.Subscription;
 import com.ning.billing.entitlement.api.user.SubscriptionBundle;
 import com.ning.billing.entitlement.api.user.SubscriptionData;
+import com.ning.billing.entitlement.api.user.SubscriptionTransition;
 import com.ning.billing.entitlement.api.user.SubscriptionTransitionData;
 import com.ning.billing.junction.plumbing.api.BlockingSubscription;
 import com.ning.billing.util.callcontext.CallContext;
@@ -68,15 +69,15 @@ public class EntitlementChecker {
         Assert.assertNotNull(subscription);
         auditChecker.checkSubscriptionCreated(subscription.getBundleId(), subscriptionId, context);
 
-        List<SubscriptionTransitionData> subscriptionEvents = getSubscriptionEvents(subscription);
+        List<SubscriptionTransition> subscriptionEvents = getSubscriptionEvents(subscription);
         Assert.assertTrue(subscriptionEvents.size() >= 1);
-        auditChecker.checkSubscriptionEventCreated(subscription.getBundleId(), subscriptionEvents.get(0).getId(), context);
+        auditChecker.checkSubscriptionEventCreated(subscription.getBundleId(), ((SubscriptionTransitionData) subscriptionEvents.get(0)).getId(), context);
 
         auditChecker.checkBundleCreated(subscription.getBundleId(), context);
         return subscription;
     }
 
-    private List<SubscriptionTransitionData> getSubscriptionEvents(final Subscription subscription) {
+    private List<SubscriptionTransition> getSubscriptionEvents(final Subscription subscription) {
         return ((SubscriptionData) ((BlockingSubscription) subscription).getDelegateSubscription()).getAllTransitions();
     }
 

catalog/pom.xml 2(+1 -1)

diff --git a/catalog/pom.xml b/catalog/pom.xml
index b5a4a89..09f6608 100644
--- a/catalog/pom.xml
+++ b/catalog/pom.xml
@@ -20,7 +20,7 @@
     <parent>
         <groupId>com.ning.billing</groupId>
         <artifactId>killbill</artifactId>
-        <version>0.1.62-SNAPSHOT</version>
+        <version>0.1.64-SNAPSHOT</version>
         <relativePath>../pom.xml</relativePath>
     </parent>
     <artifactId>killbill-catalog</artifactId>
diff --git a/catalog/src/main/java/com/ning/billing/catalog/api/user/DefaultCatalogUserApi.java b/catalog/src/main/java/com/ning/billing/catalog/api/user/DefaultCatalogUserApi.java
index 6b60bbd..24b3972 100644
--- a/catalog/src/main/java/com/ning/billing/catalog/api/user/DefaultCatalogUserApi.java
+++ b/catalog/src/main/java/com/ning/billing/catalog/api/user/DefaultCatalogUserApi.java
@@ -16,14 +16,26 @@
 
 package com.ning.billing.catalog.api.user;
 
+import javax.inject.Inject;
+
 import com.ning.billing.catalog.api.Catalog;
+import com.ning.billing.catalog.api.CatalogService;
 import com.ning.billing.catalog.api.CatalogUserApi;
 import com.ning.billing.util.callcontext.TenantContext;
 
 public class DefaultCatalogUserApi implements CatalogUserApi {
 
+    private final CatalogService catalogService;
+
+    @Inject
+    public DefaultCatalogUserApi(final CatalogService catalogService) {
+        this.catalogService = catalogService;
+    }
+
     @Override
     public Catalog getCatalog(final String catalogName, final TenantContext context) {
-        throw new UnsupportedOperationException();
+        // STEPH TODO this is  hack until we decides what do do exactly:
+        // Probably we want one catalog for tenant but but TBD
+        return catalogService.getFullCatalog();
     }
 }
diff --git a/entitlement/pom.xml b/entitlement/pom.xml
index 2a97161..dc20393 100644
--- a/entitlement/pom.xml
+++ b/entitlement/pom.xml
@@ -20,7 +20,7 @@
     <parent>
         <groupId>com.ning.billing</groupId>
         <artifactId>killbill</artifactId>
-        <version>0.1.62-SNAPSHOT</version>
+        <version>0.1.64-SNAPSHOT</version>
         <relativePath>../pom.xml</relativePath>
     </parent>
     <artifactId>killbill-entitlement</artifactId>
diff --git a/entitlement/src/main/java/com/ning/billing/entitlement/api/svcs/DefaultEntitlementInternalApi.java b/entitlement/src/main/java/com/ning/billing/entitlement/api/svcs/DefaultEntitlementInternalApi.java
index 4eba14f..08dceae 100644
--- a/entitlement/src/main/java/com/ning/billing/entitlement/api/svcs/DefaultEntitlementInternalApi.java
+++ b/entitlement/src/main/java/com/ning/billing/entitlement/api/svcs/DefaultEntitlementInternalApi.java
@@ -38,6 +38,7 @@ import com.ning.billing.entitlement.api.user.Subscription;
 import com.ning.billing.entitlement.api.user.SubscriptionBuilder;
 import com.ning.billing.entitlement.api.user.SubscriptionBundle;
 import com.ning.billing.entitlement.api.user.SubscriptionData;
+import com.ning.billing.entitlement.api.user.SubscriptionTransition;
 import com.ning.billing.entitlement.api.user.SubscriptionTransitionData;
 import com.ning.billing.entitlement.engine.dao.EntitlementDao;
 import com.ning.billing.util.callcontext.InternalCallContext;
@@ -124,23 +125,23 @@ public class DefaultEntitlementInternalApi extends EntitlementApiBase implements
 
     @Override
     public List<EffectiveSubscriptionInternalEvent> getAllTransitions(final Subscription subscription, final InternalTenantContext context) {
-        final List<SubscriptionTransitionData> transitions = ((SubscriptionData) subscription).getAllTransitions();
+        final List<SubscriptionTransition> transitions = ((SubscriptionData) subscription).getAllTransitions();
         return convertEffectiveSubscriptionInternalEventFromSubscriptionTransitions(subscription, context, transitions);
     }
 
     @Override
     public List<EffectiveSubscriptionInternalEvent> getBillingTransitions(final Subscription subscription, final InternalTenantContext context) {
-        final List<SubscriptionTransitionData> transitions = ((SubscriptionData) subscription).getBillingTransitions();
+        final List<SubscriptionTransition> transitions = ((SubscriptionData) subscription).getBillingTransitions();
         return convertEffectiveSubscriptionInternalEventFromSubscriptionTransitions(subscription, context, transitions);
     }
 
     private List<EffectiveSubscriptionInternalEvent> convertEffectiveSubscriptionInternalEventFromSubscriptionTransitions(final Subscription subscription,
-                                                                                                                          final InternalTenantContext context, final List<SubscriptionTransitionData> transitions) {
-        return ImmutableList.<EffectiveSubscriptionInternalEvent>copyOf(Collections2.transform(transitions, new Function<SubscriptionTransitionData, EffectiveSubscriptionInternalEvent>() {
+                                                                                                                          final InternalTenantContext context, final List<SubscriptionTransition> transitions) {
+        return ImmutableList.<EffectiveSubscriptionInternalEvent>copyOf(Collections2.transform(transitions, new Function<SubscriptionTransition, EffectiveSubscriptionInternalEvent>() {
             @Override
             @Nullable
-            public EffectiveSubscriptionInternalEvent apply(@Nullable SubscriptionTransitionData input) {
-                return new DefaultEffectiveSubscriptionEvent(input, ((SubscriptionData) subscription).getAlignStartDate(), null, context.getAccountRecordId(), context.getTenantRecordId());
+            public EffectiveSubscriptionInternalEvent apply(@Nullable SubscriptionTransition input) {
+                return new DefaultEffectiveSubscriptionEvent((SubscriptionTransitionData) input, ((SubscriptionData) subscription).getAlignStartDate(), null, context.getAccountRecordId(), context.getTenantRecordId());
             }
         }));
     }
diff --git a/entitlement/src/main/java/com/ning/billing/entitlement/api/timeline/DefaultEntitlementTimelineApi.java b/entitlement/src/main/java/com/ning/billing/entitlement/api/timeline/DefaultEntitlementTimelineApi.java
index fef4559..8855655 100644
--- a/entitlement/src/main/java/com/ning/billing/entitlement/api/timeline/DefaultEntitlementTimelineApi.java
+++ b/entitlement/src/main/java/com/ning/billing/entitlement/api/timeline/DefaultEntitlementTimelineApi.java
@@ -43,6 +43,7 @@ import com.ning.billing.entitlement.api.user.SubscriptionBuilder;
 import com.ning.billing.entitlement.api.user.SubscriptionBundle;
 import com.ning.billing.entitlement.api.user.SubscriptionBundleData;
 import com.ning.billing.entitlement.api.user.SubscriptionData;
+import com.ning.billing.entitlement.api.user.SubscriptionTransition;
 import com.ning.billing.entitlement.api.user.SubscriptionTransitionData;
 import com.ning.billing.entitlement.engine.addon.AddonUtils;
 import com.ning.billing.entitlement.engine.dao.EntitlementDao;
@@ -374,8 +375,8 @@ public class DefaultEntitlementTimelineApi extends EntitlementApiBase implements
         if (nbDeleted != deletedEvents.size()) {
             for (final SubscriptionTimeline.DeletedEvent d : deletedEvents) {
                 boolean found = false;
-                for (final SubscriptionTransitionData cur : data.getAllTransitions()) {
-                    if (cur.getId().equals(d.getEventId())) {
+                for (final SubscriptionTransition cur : data.getAllTransitions()) {
+                    if (((SubscriptionTransitionData) cur).getId().equals(d.getEventId())) {
                         found = true;
                     }
                 }
diff --git a/entitlement/src/main/java/com/ning/billing/entitlement/api/user/SubscriptionData.java b/entitlement/src/main/java/com/ning/billing/entitlement/api/user/SubscriptionData.java
index 3b632d7..5841a98 100644
--- a/entitlement/src/main/java/com/ning/billing/entitlement/api/user/SubscriptionData.java
+++ b/entitlement/src/main/java/com/ning/billing/entitlement/api/user/SubscriptionData.java
@@ -28,7 +28,6 @@ import org.joda.time.DateTime;
 import org.slf4j.Logger;
 import org.slf4j.LoggerFactory;
 
-import com.ning.billing.ErrorCode;
 import com.ning.billing.catalog.api.ActionPolicy;
 import com.ning.billing.catalog.api.BillingPeriod;
 import com.ning.billing.catalog.api.Catalog;
@@ -83,7 +82,7 @@ public class SubscriptionData extends EntityBase implements Subscription {
     // so the user holding that subscription object get the correct state when
     // the call completes
     //
-    private LinkedList<SubscriptionTransitionData> transitions;
+    private LinkedList<SubscriptionTransition> transitions;
 
     // Low level events are ONLY used for Repair APIs
     protected List<EntitlementEvent> events;
@@ -123,7 +122,7 @@ public class SubscriptionData extends EntityBase implements Subscription {
         this.activeVersion = internalSubscription.getActiveVersion();
         this.chargedThroughDate = internalSubscription.getChargedThroughDate();
         this.paidThroughDate = internalSubscription.getPaidThroughDate();
-        this.transitions = new LinkedList<SubscriptionTransitionData>(internalSubscription.getAllTransitions());
+        this.transitions = new LinkedList<SubscriptionTransition>(internalSubscription.getAllTransitions());
         this.events = internalSubscription.getEvents();
     }
 
@@ -148,7 +147,7 @@ public class SubscriptionData extends EntityBase implements Subscription {
         if (transitions == null) {
             return null;
         }
-        final SubscriptionTransitionData initialTransition = transitions.get(0);
+        final SubscriptionTransitionData initialTransition = (SubscriptionTransitionData) transitions.get(0);
         switch (initialTransition.getApiEventType()) {
         case MIGRATE_BILLING:
         case MIGRATE_ENTITLEMENT:
@@ -197,7 +196,7 @@ public class SubscriptionData extends EntityBase implements Subscription {
                 clock, transitions, Order.ASC_FROM_PAST, Kind.ENTITLEMENT,
                 Visibility.ALL, TimeLimit.FUTURE_ONLY);
         while (it.hasNext()) {
-            final SubscriptionTransitionData cur = it.next();
+            final SubscriptionTransition cur = it.next();
             if (cur.getTransitionType() == SubscriptionTransitionType.CANCEL) {
                 return cur.getEffectiveTransitionTime();
             }
@@ -336,6 +335,19 @@ public class SubscriptionData extends EntityBase implements Subscription {
     }
 
     @Override
+    public List<SubscriptionTransition> getAllTransitions() {
+        if (transitions == null) {
+            return Collections.emptyList();
+        }
+        final List<SubscriptionTransition> result = new ArrayList<SubscriptionTransition>();
+        final SubscriptionTransitionDataIterator it = new SubscriptionTransitionDataIterator(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;
@@ -371,9 +383,9 @@ public class SubscriptionData extends EntityBase implements Subscription {
         if (transitions == null || event == null) {
             return null;
         }
-        for (final SubscriptionTransitionData cur : transitions) {
-            if (cur.getId().equals(event.getId())) {
-                final SubscriptionTransitionData withSeq = new SubscriptionTransitionData(cur, seqId);
+        for (final SubscriptionTransition cur : transitions) {
+            if (((SubscriptionTransitionData) cur).getId().equals(event.getId())) {
+                final SubscriptionTransitionData withSeq = new SubscriptionTransitionData((SubscriptionTransitionData)cur, seqId);
                 return withSeq;
             }
         }
@@ -388,26 +400,26 @@ public class SubscriptionData extends EntityBase implements Subscription {
         final SubscriptionTransitionDataIterator it = new SubscriptionTransitionDataIterator(
                 clock, transitions, Order.DESC_FROM_FUTURE, Kind.ENTITLEMENT,
                 Visibility.FROM_DISK_ONLY, TimeLimit.ALL);
-        return it.hasNext() ? it.next().getTotalOrdering() : -1L;
+        return it.hasNext() ? ((SubscriptionTransitionData)it.next()).getTotalOrdering() : -1L;
     }
 
     public long getActiveVersion() {
         return activeVersion;
     }
 
-    public List<SubscriptionTransitionData> getBillingTransitions() {
+    public List<SubscriptionTransition> getBillingTransitions() {
 
         if (transitions == null) {
             return Collections.emptyList();
         }
-        final List<SubscriptionTransitionData> result = new ArrayList<SubscriptionTransitionData>();
+        final List<SubscriptionTransition> result = new ArrayList<SubscriptionTransition>();
         final SubscriptionTransitionDataIterator it = new SubscriptionTransitionDataIterator(
                 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 SubscriptionTransitionData curTransition = it.next();
+            final SubscriptionTransitionData curTransition = (SubscriptionTransitionData) it.next();
             if (!foundInitialEvent) {
                 foundInitialEvent = curTransition.getEventType() == EventType.API_USER &&
                                     (curTransition.getApiEventType() == ApiEventType.CREATE ||
@@ -422,18 +434,6 @@ public class SubscriptionData extends EntityBase implements Subscription {
     }
 
 
-    public List<SubscriptionTransitionData> getAllTransitions() {
-        if (transitions == null) {
-            return Collections.emptyList();
-        }
-        final List<SubscriptionTransitionData> result = new ArrayList<SubscriptionTransitionData>();
-        final SubscriptionTransitionDataIterator it = new SubscriptionTransitionDataIterator(clock, transitions, Order.ASC_FROM_PAST, Kind.ALL, Visibility.ALL, TimeLimit.ALL);
-        while (it.hasNext()) {
-            result.add(it.next());
-        }
-        return result;
-    }
-
     public SubscriptionTransitionData getInitialTransitionForCurrentPlan() {
         if (transitions == null) {
             throw new EntitlementError(String.format("No transitions for subscription %s", getId()));
@@ -447,7 +447,7 @@ public class SubscriptionData extends EntityBase implements Subscription {
                 TimeLimit.PAST_OR_PRESENT_ONLY);
 
         while (it.hasNext()) {
-            final SubscriptionTransitionData cur = it.next();
+            final SubscriptionTransitionData cur = (SubscriptionTransitionData) it.next();
             if (cur.getTransitionType() == SubscriptionTransitionType.CREATE
                     || cur.getTransitionType() == SubscriptionTransitionType.RE_CREATE
                     || cur.getTransitionType() == SubscriptionTransitionType.TRANSFER
@@ -493,7 +493,7 @@ public class SubscriptionData extends EntityBase implements Subscription {
                 clock, transitions, Order.DESC_FROM_FUTURE, Kind.ENTITLEMENT,
                 Visibility.ALL, TimeLimit.PAST_OR_PRESENT_ONLY);
         while (it.hasNext()) {
-            final SubscriptionTransitionData cur = it.next();
+            final SubscriptionTransitionData cur = (SubscriptionTransitionData) it.next();
 
             if (cur.getTransitionType() == SubscriptionTransitionType.PHASE
                     || cur.getTransitionType() == SubscriptionTransitionType.TRANSFER
@@ -516,19 +516,24 @@ public class SubscriptionData extends EntityBase implements Subscription {
 
         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 nextUserToken = null;
 
+        UUID prevEventId = null;
+        DateTime prevCreatedDate = null;
         SubscriptionState previousState = null;
         PriceList previousPriceList = null;
-
-        transitions = new LinkedList<SubscriptionTransitionData>();
         Plan previousPlan = null;
         PlanPhase previousPhase = null;
 
+        transitions = new LinkedList<SubscriptionTransition>();
+
         for (final EntitlementEvent cur : inputEvents) {
 
             if (!cur.isActive() || cur.getActiveVersion() < activeVersion) {
@@ -539,6 +544,9 @@ public class SubscriptionData extends EntityBase implements Subscription {
 
             boolean isFromDisk = true;
 
+            nextEventId = cur.getId();
+            nextCreatedDate = cur.getCreatedDate();
+
             switch (cur.getType()) {
 
             case PHASE:
@@ -557,6 +565,8 @@ public class SubscriptionData extends EntityBase implements Subscription {
                 case MIGRATE_ENTITLEMENT:
                 case CREATE:
                 case RE_CREATE:
+                    prevEventId = null;
+                    prevCreatedDate = null;
                     previousState = null;
                     previousPlan = null;
                     previousPhase = null;
@@ -604,8 +614,11 @@ public class SubscriptionData extends EntityBase implements Subscription {
             final SubscriptionTransitionData transition = new SubscriptionTransitionData(
                     cur.getId(), id, bundleId, cur.getType(), apiEventType,
                     cur.getRequestedDate(), cur.getEffectiveDate(),
+                    prevEventId, prevCreatedDate,
                     previousState, previousPlan, previousPhase,
-                    previousPriceList, nextState, nextPlan, nextPhase,
+                    previousPriceList,
+                    nextEventId, nextCreatedDate,
+                    nextState, nextPlan, nextPhase,
                     nextPriceList, cur.getTotalOrdering(), nextUserToken,
                     isFromDisk);
 
@@ -615,8 +628,9 @@ public class SubscriptionData extends EntityBase implements Subscription {
             previousPlan = nextPlan;
             previousPhase = nextPhase;
             previousPriceList = nextPriceList;
+            prevEventId = nextEventId;
+            prevCreatedDate = nextCreatedDate;
+
         }
     }
-
-
 }
diff --git a/entitlement/src/main/java/com/ning/billing/entitlement/api/user/SubscriptionTransitionData.java b/entitlement/src/main/java/com/ning/billing/entitlement/api/user/SubscriptionTransitionData.java
index 7e6db65..2cadced 100644
--- a/entitlement/src/main/java/com/ning/billing/entitlement/api/user/SubscriptionTransitionData.java
+++ b/entitlement/src/main/java/com/ning/billing/entitlement/api/user/SubscriptionTransitionData.java
@@ -40,8 +40,12 @@ public class SubscriptionTransitionData implements SubscriptionTransition {
     private final DateTime effectiveTransitionTime;
     private final SubscriptionState previousState;
     private final PriceList previousPriceList;
+    private final UUID previousEventId;
+    private final DateTime previousEventCreatedDate;
     private final Plan previousPlan;
     private final PlanPhase previousPhase;
+    private final UUID nextEventId;
+    private final DateTime nextEventCreatedDate;
     private final SubscriptionState nextState;
     private final PriceList nextPriceList;
     private final Plan nextPlan;
@@ -57,10 +61,14 @@ public class SubscriptionTransitionData implements SubscriptionTransition {
                                       final ApiEventType apiEventType,
                                       final DateTime requestedTransitionTime,
                                       final DateTime effectiveTransitionTime,
+                                      final UUID previousEventId,
+                                      final DateTime previousEventCreatedDate,
                                       final SubscriptionState previousState,
                                       final Plan previousPlan,
                                       final PlanPhase previousPhase,
                                       final PriceList previousPriceList,
+                                      final UUID nextEventId,
+                                      final DateTime nextEventCreatedDate,
                                       final SubscriptionState nextState,
                                       final Plan nextPlan,
                                       final PlanPhase nextPhase,
@@ -84,12 +92,16 @@ public class SubscriptionTransitionData implements SubscriptionTransition {
         this.nextPriceList = nextPriceList;
         this.nextPhase = nextPhase;
         this.totalOrdering = totalOrdering;
+        this.previousEventId = previousEventId;
+        this.previousEventCreatedDate = previousEventCreatedDate;
+        this.nextEventId = nextEventId;
+        this.nextEventCreatedDate = nextEventCreatedDate;
         this.isFromDisk = isFromDisk;
         this.userToken = userToken;
         this.remainingEventsForUserOperation = 0;
     }
 
-    public SubscriptionTransitionData(final SubscriptionTransitionData input, final int remainingEventsForUserOperation) {
+    public SubscriptionTransitionData(final SubscriptionTransitionData input, int remainingEventsForUserOperation) {
         super();
         this.eventId = input.getId();
         this.subscriptionId = input.getSubscriptionId();
@@ -98,10 +110,14 @@ public class SubscriptionTransitionData implements SubscriptionTransition {
         this.apiEventType = input.getApiEventType();
         this.requestedTransitionTime = input.getRequestedTransitionTime();
         this.effectiveTransitionTime = input.getEffectiveTransitionTime();
+        this.previousEventId = input.getPreviousEventId();
+        this.previousEventCreatedDate = input.getPreviousEventCreatedDate();
         this.previousState = input.getPreviousState();
         this.previousPriceList = input.getPreviousPriceList();
         this.previousPlan = input.getPreviousPlan();
         this.previousPhase = input.getPreviousPhase();
+        this.nextEventId = input.getNextEventId();
+        this.nextEventCreatedDate = input.getNextEventCreatedDate();
         this.nextState = input.getNextState();
         this.nextPlan = input.getNextPlan();
         this.nextPriceList = input.getNextPriceList();
@@ -142,6 +158,16 @@ public class SubscriptionTransitionData implements SubscriptionTransition {
     }
 
     @Override
+    public UUID getNextEventId() {
+        return nextEventId;
+    }
+
+    @Override
+    public DateTime getNextEventCreatedDate() {
+        return nextEventCreatedDate;
+    }
+
+    @Override
     public Plan getNextPlan() {
         return nextPlan;
     }
@@ -157,6 +183,16 @@ public class SubscriptionTransitionData implements SubscriptionTransition {
     }
 
     @Override
+    public UUID getPreviousEventId() {
+        return previousEventId;
+    }
+
+    @Override
+    public DateTime getPreviousEventCreatedDate() {
+        return previousEventCreatedDate;
+    }
+
+    @Override
     public PriceList getPreviousPriceList() {
         return previousPriceList;
     }
diff --git a/entitlement/src/main/java/com/ning/billing/entitlement/api/user/SubscriptionTransitionDataIterator.java b/entitlement/src/main/java/com/ning/billing/entitlement/api/user/SubscriptionTransitionDataIterator.java
index 8de654f..9da28ea 100644
--- a/entitlement/src/main/java/com/ning/billing/entitlement/api/user/SubscriptionTransitionDataIterator.java
+++ b/entitlement/src/main/java/com/ning/billing/entitlement/api/user/SubscriptionTransitionDataIterator.java
@@ -23,15 +23,15 @@ import com.ning.billing.entitlement.api.SubscriptionTransitionType;
 import com.ning.billing.entitlement.exceptions.EntitlementError;
 import com.ning.billing.util.clock.Clock;
 
-public class SubscriptionTransitionDataIterator implements Iterator<SubscriptionTransitionData> {
+public class SubscriptionTransitionDataIterator implements Iterator<SubscriptionTransition> {
 
     private final Clock clock;
-    private final Iterator<SubscriptionTransitionData> it;
+    private final Iterator<SubscriptionTransition> it;
     private final Kind kind;
     private final TimeLimit timeLimit;
     private final Visibility visibility;
 
-    private SubscriptionTransitionData next;
+    private SubscriptionTransition next;
 
     public enum Order {
         ASC_FROM_PAST,
@@ -55,7 +55,7 @@ public class SubscriptionTransitionDataIterator implements Iterator<Subscription
         ALL
     }
 
-    public SubscriptionTransitionDataIterator(final Clock clock, final LinkedList<SubscriptionTransitionData> transitions,
+    public SubscriptionTransitionDataIterator(final Clock clock, final LinkedList<SubscriptionTransition> 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;
@@ -77,12 +77,12 @@ public class SubscriptionTransitionDataIterator implements Iterator<Subscription
         return true;
     }
 
-    private boolean shouldSkip(final SubscriptionTransitionData input) {
-        if (visibility == Visibility.FROM_DISK_ONLY && !input.isFromDisk()) {
+    private boolean shouldSkip(final SubscriptionTransition input) {
+        if (visibility == Visibility.FROM_DISK_ONLY && ! ((SubscriptionTransitionData) input).isFromDisk()) {
             return true;
         }
-        if ((kind == Kind.ENTITLEMENT && shouldSkipForEntitlementEvents(input)) ||
-            (kind == Kind.BILLING && shouldSkipForBillingEvents(input))) {
+        if ((kind == Kind.ENTITLEMENT && shouldSkipForEntitlementEvents((SubscriptionTransitionData)input)) ||
+            (kind == Kind.BILLING && shouldSkipForBillingEvents((SubscriptionTransitionData) input))) {
             return true;
         }
         if ((timeLimit == TimeLimit.FUTURE_ONLY && !input.getEffectiveTransitionTime().isAfter(clock.getUTCNow())) ||
@@ -106,7 +106,7 @@ public class SubscriptionTransitionDataIterator implements Iterator<Subscription
 
 
     @Override
-    public SubscriptionTransitionData next() {
+    public SubscriptionTransition next() {
         return next;
     }
 
diff --git a/entitlement/src/main/java/com/ning/billing/entitlement/events/EventBaseBuilder.java b/entitlement/src/main/java/com/ning/billing/entitlement/events/EventBaseBuilder.java
index 87d8533..4321cd1 100644
--- a/entitlement/src/main/java/com/ning/billing/entitlement/events/EventBaseBuilder.java
+++ b/entitlement/src/main/java/com/ning/billing/entitlement/events/EventBaseBuilder.java
@@ -46,7 +46,7 @@ public class EventBaseBuilder<T extends EventBaseBuilder<T>> {
         this.requestedDate = copy.requestedDate;
         this.effectiveDate = copy.effectiveDate;
         this.processedDate = copy.processedDate;
-
+        this.createdDate = copy.getCreatedDate();
         this.activeVersion = copy.activeVersion;
         this.isActive = copy.isActive;
         this.totalOrdering = copy.totalOrdering;
diff --git a/entitlement/src/test/java/com/ning/billing/entitlement/alignment/TestPlanAligner.java b/entitlement/src/test/java/com/ning/billing/entitlement/alignment/TestPlanAligner.java
index 16deb9d..282ffb6 100644
--- a/entitlement/src/test/java/com/ning/billing/entitlement/alignment/TestPlanAligner.java
+++ b/entitlement/src/test/java/com/ning/billing/entitlement/alignment/TestPlanAligner.java
@@ -35,6 +35,7 @@ import com.ning.billing.catalog.api.PriceListSet;
 import com.ning.billing.catalog.io.VersionedCatalogLoader;
 import com.ning.billing.entitlement.EntitlementTestSuiteNoDB;
 import com.ning.billing.entitlement.api.user.SubscriptionBuilder;
+import com.ning.billing.entitlement.api.user.SubscriptionTransition;
 import com.ning.billing.util.config.CatalogConfig;
 import com.ning.billing.entitlement.api.user.EntitlementUserApiException;
 import com.ning.billing.entitlement.api.user.SubscriptionData;
@@ -206,7 +207,7 @@ public class TestPlanAligner extends EntitlementTestSuiteNoDB {
 
         subscriptionData.rebuildTransitions(ImmutableList.<EntitlementEvent>of(previousEvent, event), catalogService.getFullCatalog());
 
-        final List<SubscriptionTransitionData> newTransitions = subscriptionData.getAllTransitions();
+        final List<SubscriptionTransition> newTransitions = subscriptionData.getAllTransitions();
         Assert.assertEquals(newTransitions.size(), 2);
         Assert.assertNull(newTransitions.get(0).getPreviousPhase());
         Assert.assertEquals(newTransitions.get(0).getNextPhase(), newTransitions.get(1).getPreviousPhase());
diff --git a/entitlement/src/test/java/com/ning/billing/entitlement/api/migration/TestMigration.java b/entitlement/src/test/java/com/ning/billing/entitlement/api/migration/TestMigration.java
index c5af7fe..17d12d1 100644
--- a/entitlement/src/test/java/com/ning/billing/entitlement/api/migration/TestMigration.java
+++ b/entitlement/src/test/java/com/ning/billing/entitlement/api/migration/TestMigration.java
@@ -39,6 +39,7 @@ import com.ning.billing.entitlement.api.user.Subscription;
 import com.ning.billing.entitlement.api.user.Subscription.SubscriptionState;
 import com.ning.billing.entitlement.api.user.SubscriptionBundle;
 import com.ning.billing.entitlement.api.user.SubscriptionData;
+import com.ning.billing.entitlement.api.user.SubscriptionTransition;
 import com.ning.billing.entitlement.api.user.SubscriptionTransitionData;
 import com.ning.billing.entitlement.events.user.ApiEventType;
 
@@ -165,7 +166,6 @@ public class TestMigration extends EntitlementTestSuiteWithEmbeddedDB {
 
             assertTrue(subscription.getStartDate().compareTo(startDate) == 0);
             assertNotNull(subscription.getEndDate());
-            assertTrue(subscription.getEndDate().isAfterNow());
             assertEquals(subscription.getCurrentPriceList().getName(), PriceListSet.DEFAULT_PRICELIST_NAME);
             assertEquals(subscription.getCurrentPhase(), null);
             assertEquals(subscription.getState(), SubscriptionState.CANCELLED);
@@ -291,28 +291,28 @@ public class TestMigration extends EntitlementTestSuiteWithEmbeddedDB {
             assertEquals(subscriptions.size(), 1);
             final SubscriptionData subscription = (SubscriptionData) subscriptions.get(0);
 
-            final List<SubscriptionTransitionData> transitions = subscription.getAllTransitions();
+            final List<SubscriptionTransition> transitions = subscription.getAllTransitions();
             assertEquals(transitions.size(), 2);
-            final SubscriptionTransitionData initialMigrateBilling = transitions.get(1);
+            final SubscriptionTransitionData initialMigrateBilling = (SubscriptionTransitionData) transitions.get(1);
             assertEquals(initialMigrateBilling.getApiEventType(), ApiEventType.MIGRATE_BILLING);
             assertTrue(initialMigrateBilling.getEffectiveTransitionTime().compareTo(subscription.getChargedThroughDate()) == 0);
             assertEquals(initialMigrateBilling.getNextPlan().getName(), "shotgun-annual");
             assertEquals(initialMigrateBilling.getNextPhase().getName(), "shotgun-annual-evergreen");
 
-            final List<SubscriptionTransitionData> billingTransitions = subscription.getBillingTransitions();
+            final List<SubscriptionTransition> billingTransitions = subscription.getBillingTransitions();
             assertEquals(billingTransitions.size(), 1);
             assertEquals(billingTransitions.get(0), initialMigrateBilling);
 
             // Now make an IMMEDIATE change of plan
             subscription.changePlan("Assault-Rifle", BillingPeriod.MONTHLY, PriceListSet.DEFAULT_PRICELIST_NAME, clock.getUTCNow(), callContext);
 
-            final List<SubscriptionTransitionData> newTransitions = subscription.getAllTransitions();
+            final List<SubscriptionTransition> newTransitions = subscription.getAllTransitions();
             assertEquals(newTransitions.size(), 3);
 
-            final SubscriptionTransitionData changeTransition = newTransitions.get(1);
+            final SubscriptionTransitionData changeTransition = (SubscriptionTransitionData) newTransitions.get(1);
             assertEquals(changeTransition.getApiEventType(), ApiEventType.CHANGE);
 
-            final SubscriptionTransitionData newMigrateBilling = newTransitions.get(2);
+            final SubscriptionTransitionData newMigrateBilling = (SubscriptionTransitionData) newTransitions.get(2);
             assertEquals(newMigrateBilling.getApiEventType(), ApiEventType.MIGRATE_BILLING);
             assertTrue(newMigrateBilling.getEffectiveTransitionTime().compareTo(subscription.getChargedThroughDate()) == 0);
             assertTrue(newMigrateBilling.getEffectiveTransitionTime().compareTo(initialMigrateBilling.getEffectiveTransitionTime()) == 0);
@@ -320,7 +320,7 @@ public class TestMigration extends EntitlementTestSuiteWithEmbeddedDB {
             assertEquals(newMigrateBilling.getNextPhase().getName(), "assault-rifle-monthly-evergreen");
 
 
-            final List<SubscriptionTransitionData> newBillingTransitions = subscription.getBillingTransitions();
+            final List<SubscriptionTransition> newBillingTransitions = subscription.getBillingTransitions();
             assertEquals(newBillingTransitions.size(), 1);
             assertEquals(newBillingTransitions.get(0), newMigrateBilling);
 
diff --git a/entitlement/src/test/java/com/ning/billing/entitlement/api/user/TestUserApiChangePlan.java b/entitlement/src/test/java/com/ning/billing/entitlement/api/user/TestUserApiChangePlan.java
index da23035..d3c1929 100644
--- a/entitlement/src/test/java/com/ning/billing/entitlement/api/user/TestUserApiChangePlan.java
+++ b/entitlement/src/test/java/com/ning/billing/entitlement/api/user/TestUserApiChangePlan.java
@@ -433,6 +433,7 @@ public class TestUserApiChangePlan extends EntitlementTestSuiteWithEmbeddedDB {
             PlanPhase trialPhase = subscription.getCurrentPhase();
             assertEquals(trialPhase.getPhaseType(), PhaseType.TRIAL);
 
+
             // MOVE 2 DAYS AHEAD
             Interval it = new Interval(clock.getUTCNow(), clock.getUTCNow().plusDays(2));
             clock.addDeltaFromReality(it.toDurationMillis());
@@ -468,8 +469,8 @@ public class TestUserApiChangePlan extends EntitlementTestSuiteWithEmbeddedDB {
 
             final DateTime expectedNextPhaseDate = subscription.getStartDate().plusDays(30).plusMonths(6);
             final SubscriptionTransition nextPhase = subscription.getPendingTransition();
-            final DateTime nextPhaseEffectiveDate = nextPhase.getEffectiveTransitionTime();
 
+            final DateTime nextPhaseEffectiveDate = nextPhase.getEffectiveTransitionTime();
             assertEquals(nextPhaseEffectiveDate, expectedNextPhaseDate);
 
             assertListenerStatus();
diff --git a/entitlement/src/test/java/com/ning/billing/entitlement/api/user/TestUserApiCreate.java b/entitlement/src/test/java/com/ning/billing/entitlement/api/user/TestUserApiCreate.java
index 22a09cc..ef3e65f 100644
--- a/entitlement/src/test/java/com/ning/billing/entitlement/api/user/TestUserApiCreate.java
+++ b/entitlement/src/test/java/com/ning/billing/entitlement/api/user/TestUserApiCreate.java
@@ -62,15 +62,33 @@ public class TestUserApiCreate extends EntitlementTestSuiteWithEmbeddedDB {
                                                                                                        testUtil.getProductSpecifier(productName, planSetName, term, null), requestedDate, callContext);
             assertNotNull(subscription);
 
+            //
+            // In addition to Alignment phase we also test SubscriptionTransition eventIds and created dates.
+            // Keep tracks of row events to compare with ids and created dates returned by SubscriptionTransition later.
+            //
+            final List<EntitlementEvent> events = subscription.getEvents();
+            Assert.assertEquals(events.size(), 2);
+
+            final EntitlementEvent trialEvent = events.get(0);
+            final EntitlementEvent phaseEvent = events.get(1);
+
+
             assertEquals(subscription.getActiveVersion(), SubscriptionEvents.INITIAL_VERSION);
             //assertEquals(subscription.getAccount(), account.getId());
             assertEquals(subscription.getBundleId(), bundle.getId());
             assertEquals(subscription.getStartDate(), requestedDate);
 
             assertTrue(testListener.isCompleted(5000));
-
             assertListenerStatus();
 
+            final SubscriptionTransition transition = subscription.getPreviousTransition();
+
+            assertEquals(transition.getPreviousEventId(), trialEvent.getId());
+            assertEquals(transition.getNextEventId(), phaseEvent.getId());
+
+            assertEquals(transition.getPreviousEventCreatedDate().compareTo(trialEvent.getCreatedDate()), 0);
+            assertEquals(transition.getNextEventCreatedDate().compareTo(phaseEvent.getCreatedDate()), 0);
+
         } catch (EntitlementUserApiException e) {
             log.error("Unexpected exception", e);
             Assert.fail(e.getMessage());

invoice/pom.xml 2(+1 -1)

diff --git a/invoice/pom.xml b/invoice/pom.xml
index 5bd0349..15600b8 100644
--- a/invoice/pom.xml
+++ b/invoice/pom.xml
@@ -20,7 +20,7 @@
     <parent>
         <groupId>com.ning.billing</groupId>
         <artifactId>killbill</artifactId>
-        <version>0.1.62-SNAPSHOT</version>
+        <version>0.1.64-SNAPSHOT</version>
         <relativePath>../pom.xml</relativePath>
     </parent>
     <artifactId>killbill-invoice</artifactId>
diff --git a/invoice/src/main/java/com/ning/billing/invoice/model/DefaultInvoice.java b/invoice/src/main/java/com/ning/billing/invoice/model/DefaultInvoice.java
index 50ec651..1f4309d 100644
--- a/invoice/src/main/java/com/ning/billing/invoice/model/DefaultInvoice.java
+++ b/invoice/src/main/java/com/ning/billing/invoice/model/DefaultInvoice.java
@@ -189,6 +189,17 @@ public class DefaultInvoice extends EntityBase implements Invoice {
     }
 
     @Override
+    public BigDecimal getOriginalChargedAmount() {
+        BigDecimal result = BigDecimal.ZERO;
+        for (final InvoiceItem cur :  invoiceItems) {
+            if (cur.getCreatedDate().compareTo(getCreatedDate()) == 0) {
+                result = result.add(cur.getAmount());
+            }
+        }
+        return result;
+    }
+
+    @Override
     public BigDecimal getChargedAmount() {
         return invoiceItems.getChargedAmount();
     }
diff --git a/invoice/src/main/java/com/ning/billing/invoice/template/formatters/DefaultInvoiceFormatter.java b/invoice/src/main/java/com/ning/billing/invoice/template/formatters/DefaultInvoiceFormatter.java
index 0c020f7..f75197f 100644
--- a/invoice/src/main/java/com/ning/billing/invoice/template/formatters/DefaultInvoiceFormatter.java
+++ b/invoice/src/main/java/com/ning/billing/invoice/template/formatters/DefaultInvoiceFormatter.java
@@ -183,6 +183,11 @@ public class DefaultInvoiceFormatter implements InvoiceFormatter {
     }
 
     @Override
+    public BigDecimal getOriginalChargedAmount() {
+        return round(Objects.firstNonNull(invoice.getOriginalChargedAmount(), BigDecimal.ZERO));
+    }
+
+    @Override
     public BigDecimal getCBAAmount() {
         return round(Objects.firstNonNull(invoice.getCBAAmount(), BigDecimal.ZERO));
     }
diff --git a/invoice/src/test/java/com/ning/billing/invoice/api/user/TestDefaultInvoiceUserApi.java b/invoice/src/test/java/com/ning/billing/invoice/api/user/TestDefaultInvoiceUserApi.java
index 33d66ba..5edcfa7 100644
--- a/invoice/src/test/java/com/ning/billing/invoice/api/user/TestDefaultInvoiceUserApi.java
+++ b/invoice/src/test/java/com/ning/billing/invoice/api/user/TestDefaultInvoiceUserApi.java
@@ -30,11 +30,15 @@ import com.ning.billing.ErrorCode;
 import com.ning.billing.ObjectType;
 import com.ning.billing.account.api.Account;
 import com.ning.billing.invoice.InvoiceTestSuiteWithEmbeddedDB;
+import com.ning.billing.invoice.api.Invoice;
 import com.ning.billing.invoice.api.InvoiceApiException;
 import com.ning.billing.invoice.api.InvoiceItem;
 import com.ning.billing.invoice.api.InvoiceItemType;
 import com.ning.billing.invoice.model.InvoicingConfiguration;
 import com.ning.billing.util.api.TagApiException;
+import com.ning.billing.util.callcontext.CallContext;
+import com.ning.billing.util.callcontext.DefaultCallContext;
+import com.ning.billing.util.clock.ClockMock;
 import com.ning.billing.util.tag.ControlTagType;
 import com.ning.billing.util.tag.Tag;
 
@@ -109,7 +113,6 @@ public class TestDefaultInvoiceUserApi extends InvoiceTestSuiteWithEmbeddedDB {
         // Verify the initial account balance
         final BigDecimal accountBalance = invoiceUserApi.getAccountBalance(accountId, callContext);
         Assert.assertEquals(accountBalance, invoiceBalance);
-
         // Post an external charge
         final BigDecimal externalChargeAmount = BigDecimal.TEN;
         final InvoiceItem externalChargeInvoiceItem = invoiceUserApi.insertExternalChargeForInvoice(accountId, invoiceId,
@@ -119,6 +122,33 @@ public class TestDefaultInvoiceUserApi extends InvoiceTestSuiteWithEmbeddedDB {
     }
 
     @Test(groups = "slow")
+    public void testOriginalAmountCharged() throws Exception {
+
+        final Invoice initialInvoice = invoiceUserApi.getInvoice(invoiceId, callContext);
+        final BigDecimal originalAmountCharged = initialInvoice.getOriginalChargedAmount();
+        final BigDecimal amountCharged = initialInvoice.getChargedAmount();
+        Assert.assertEquals(originalAmountCharged.compareTo(amountCharged), 0);
+
+        ((ClockMock) clock).addDays(1);
+
+        // Sleep at least one sec to make sure created_date for the external charge is different than the created date for the invoice itself
+        CallContext newCallContextLater = new DefaultCallContext(callContext.getTenantId(), callContext.getUserName(), callContext.getCallOrigin(), callContext.getUserType(), callContext.getUserToken(), clock);
+        // Post an external charge
+        final BigDecimal externalChargeAmount = BigDecimal.TEN;
+        final InvoiceItem externalChargeInvoiceItem = invoiceUserApi.insertExternalChargeForInvoice(accountId, invoiceId,
+                                                                                                    externalChargeAmount, UUID.randomUUID().toString(),
+                                                                                                    clock.getUTCToday(), accountCurrency, newCallContextLater);
+
+        final Invoice newInvoice = invoiceUserApi.getInvoice(invoiceId, callContext);
+        final BigDecimal newOriginalAmountCharged = newInvoice.getOriginalChargedAmount();
+        final BigDecimal newAmountCharged = newInvoice.getChargedAmount();
+        final BigDecimal expectedChargedAmount = newInvoice.getOriginalChargedAmount().add(externalChargeInvoiceItem.getAmount());
+
+        Assert.assertEquals(originalAmountCharged.compareTo(newOriginalAmountCharged), 0);
+        Assert.assertEquals(newAmountCharged.compareTo(expectedChargedAmount), 0);
+    }
+
+    @Test(groups = "slow")
     public void testPostExternalChargeForBundleOnExistingInvoice() throws Exception {
         // Verify the initial invoice balance
         final BigDecimal invoiceBalance = invoiceUserApi.getInvoice(invoiceId, callContext).getBalance();
@@ -320,12 +350,12 @@ public class TestDefaultInvoiceUserApi extends InvoiceTestSuiteWithEmbeddedDB {
     public void testAddRemoveWrittenOffTag() throws InvoiceApiException, TagApiException {
         invoiceUserApi.tagInvoiceAsWrittenOff(invoiceId, callContext);
 
-        List<Tag> tags = tagUserApi.getTags(invoiceId, ObjectType.INVOICE, callContext);
+        List<Tag> tags = tagUserApi.getTagsForObject(invoiceId, ObjectType.INVOICE, callContext);
         assertEquals(tags.size(), 1);
         assertEquals(tags.get(0).getTagDefinitionId(), ControlTagType.WRITTEN_OFF.getId());
 
         invoiceUserApi.tagInvoiceAsNotWrittenOff(invoiceId, callContext);
-        tags = tagUserApi.getTags(invoiceId, ObjectType.INVOICE, callContext);
+        tags = tagUserApi.getTagsForObject(invoiceId, ObjectType.INVOICE, callContext);
         assertEquals(tags.size(), 0);
     }
 }

jaxrs/pom.xml 2(+1 -1)

diff --git a/jaxrs/pom.xml b/jaxrs/pom.xml
index 39496c9..3dc04aa 100644
--- a/jaxrs/pom.xml
+++ b/jaxrs/pom.xml
@@ -20,7 +20,7 @@
     <parent>
         <groupId>com.ning.billing</groupId>
         <artifactId>killbill</artifactId>
-        <version>0.1.62-SNAPSHOT</version>
+        <version>0.1.64-SNAPSHOT</version>
         <relativePath>../pom.xml</relativePath>
     </parent>
     <artifactId>killbill-jaxrs</artifactId>
diff --git a/jaxrs/src/main/java/com/ning/billing/jaxrs/json/PaymentMethodJson.java b/jaxrs/src/main/java/com/ning/billing/jaxrs/json/PaymentMethodJson.java
index 29dbb7b..1a7e1c9 100644
--- a/jaxrs/src/main/java/com/ning/billing/jaxrs/json/PaymentMethodJson.java
+++ b/jaxrs/src/main/java/com/ning/billing/jaxrs/json/PaymentMethodJson.java
@@ -121,6 +121,78 @@ public class PaymentMethodJson {
                     }
 
                     @Override
+                    public String getType() {
+                        // N/A
+                        return null;
+                    }
+
+                    @Override
+                    public String getCCName() {
+                        // N/A
+                        return null;
+                    }
+
+                    @Override
+                    public String getCCType() {
+                        // N/A
+                        return null;
+                    }
+
+                    @Override
+                    public String getCCExprirationMonth() {
+                        // N/A
+                        return null;
+                    }
+
+                    @Override
+                    public String getCCExprirationYear() {
+                        // N/A
+                        return null;
+                    }
+
+                    @Override
+                    public String getCCLast4() {
+                        // N/A
+                        return null;
+                    }
+
+                    @Override
+                    public String getAddress1() {
+                        // N/A
+                        return null;
+                    }
+
+                    @Override
+                    public String getAddress2() {
+                        // N/A
+                        return null;
+                    }
+
+                    @Override
+                    public String getCity() {
+                        // N/A
+                        return null;
+                    }
+
+                    @Override
+                    public String getState() {
+                        // N/A
+                        return null;
+                    }
+
+                    @Override
+                    public String getZip() {
+                        // N/A
+                        return null;
+                    }
+
+                    @Override
+                    public String getCountry() {
+                        // N/A
+                        return null;
+                    }
+
+                    @Override
                     public String getExternalPaymentMethodId() {
                         return pluginInfo.getExternalPaymentId();
                     }
diff --git a/jaxrs/src/main/java/com/ning/billing/jaxrs/resources/JaxRsResourceBase.java b/jaxrs/src/main/java/com/ning/billing/jaxrs/resources/JaxRsResourceBase.java
index cd88edc..40092a2 100644
--- a/jaxrs/src/main/java/com/ning/billing/jaxrs/resources/JaxRsResourceBase.java
+++ b/jaxrs/src/main/java/com/ning/billing/jaxrs/resources/JaxRsResourceBase.java
@@ -31,7 +31,6 @@ import org.joda.time.format.ISODateTimeFormat;
 import org.slf4j.Logger;
 import org.slf4j.LoggerFactory;
 
-import com.ning.billing.BillingExceptionBase;
 import com.ning.billing.ErrorCode;
 import com.ning.billing.ObjectType;
 import com.ning.billing.jaxrs.json.CustomFieldJson;
@@ -84,7 +83,7 @@ public abstract class JaxRsResourceBase implements JaxrsResource {
     }
 
     protected Response getTags(final UUID id, final boolean withAudit, final TenantContext context) throws TagDefinitionApiException {
-        final List<Tag> tags = tagUserApi.getTags(id, getObjectType(), context);
+        final List<Tag> tags = tagUserApi.getTagsForObject(id, getObjectType(), context);
         final Collection<UUID> tagIdList = (tags.size() == 0) ?
                                            Collections.<UUID>emptyList() :
                                            Collections2.transform(tags, new Function<Tag, UUID>() {
@@ -154,7 +153,7 @@ public abstract class JaxRsResourceBase implements JaxrsResource {
     }
 
     protected Response getCustomFields(final UUID id, final TenantContext context) {
-        final List<CustomField> fields = customFieldUserApi.getCustomFields(id, getObjectType(), context);
+        final List<CustomField> fields = customFieldUserApi.getCustomFieldsForObject(id, getObjectType(), context);
 
         final List<CustomFieldJson> result = new LinkedList<CustomFieldJson>();
         for (final CustomField cur : fields) {
diff --git a/jaxrs/src/main/java/com/ning/billing/jaxrs/resources/PaymentResource.java b/jaxrs/src/main/java/com/ning/billing/jaxrs/resources/PaymentResource.java
index a694f3f..4d41e06 100644
--- a/jaxrs/src/main/java/com/ning/billing/jaxrs/resources/PaymentResource.java
+++ b/jaxrs/src/main/java/com/ning/billing/jaxrs/resources/PaymentResource.java
@@ -106,7 +106,7 @@ public class PaymentResource extends JaxRsResourceBase {
         final TenantContext tenantContext = context.createContext(request);
 
         final UUID paymentId = UUID.fromString(paymentIdString);
-        final Payment payment = paymentApi.getPayment(paymentId, tenantContext);
+        final Payment payment = paymentApi.getPayment(paymentId, false, tenantContext);
 
         final PaymentJsonSimple paymentJsonSimple;
         if (withRefundsAndChargebacks) {
@@ -167,7 +167,7 @@ public class PaymentResource extends JaxRsResourceBase {
         final CallContext callContext = context.createContext(createdBy, reason, comment, request);
 
         final UUID paymentUuid = UUID.fromString(paymentId);
-        final Payment payment = paymentApi.getPayment(paymentUuid, callContext);
+        final Payment payment = paymentApi.getPayment(paymentUuid, false, callContext);
         final Account account = accountApi.getAccountById(payment.getAccountId(), callContext);
 
         final Refund result;
diff --git a/jaxrs/src/main/java/com/ning/billing/jaxrs/resources/RefundResource.java b/jaxrs/src/main/java/com/ning/billing/jaxrs/resources/RefundResource.java
index 1db623d..5a0bade 100644
--- a/jaxrs/src/main/java/com/ning/billing/jaxrs/resources/RefundResource.java
+++ b/jaxrs/src/main/java/com/ning/billing/jaxrs/resources/RefundResource.java
@@ -62,7 +62,7 @@ public class RefundResource extends JaxRsResourceBase {
     @Produces(APPLICATION_JSON)
     public Response getRefund(@PathParam("refundId") final String refundId,
                               @javax.ws.rs.core.Context final HttpServletRequest request) throws PaymentApiException {
-        final Refund refund = paymentApi.getRefund(UUID.fromString(refundId), context.createContext(request));
+        final Refund refund = paymentApi.getRefund(UUID.fromString(refundId), false, context.createContext(request));
         // TODO Return adjusted items and audits
         return Response.status(Status.OK).entity(new RefundJson(refund, null, null)).build();
     }

junction/pom.xml 2(+1 -1)

diff --git a/junction/pom.xml b/junction/pom.xml
index c861440..68cfc03 100644
--- a/junction/pom.xml
+++ b/junction/pom.xml
@@ -20,7 +20,7 @@
     <parent>
         <groupId>com.ning.billing</groupId>
         <artifactId>killbill</artifactId>
-        <version>0.1.62-SNAPSHOT</version>
+        <version>0.1.64-SNAPSHOT</version>
         <relativePath>../pom.xml</relativePath>
     </parent>
     <artifactId>killbill-junction</artifactId>
diff --git a/junction/src/main/java/com/ning/billing/junction/api/DefaultJunctionApi.java b/junction/src/main/java/com/ning/billing/junction/api/DefaultJunctionApi.java
new file mode 100644
index 0000000..ee81e49
--- /dev/null
+++ b/junction/src/main/java/com/ning/billing/junction/api/DefaultJunctionApi.java
@@ -0,0 +1,44 @@
+/*
+ * 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.junction.api;
+
+import java.util.List;
+import java.util.UUID;
+
+import javax.inject.Inject;
+
+import com.ning.billing.junction.dao.BlockingStateDao;
+import com.ning.billing.util.callcontext.InternalCallContextFactory;
+import com.ning.billing.util.callcontext.TenantContext;
+
+public class DefaultJunctionApi implements JunctionApi {
+
+    private final BlockingStateDao dao;
+    private final InternalCallContextFactory internalCallContextFactory;
+
+    @Inject
+    public DefaultJunctionApi(final BlockingStateDao dao, final InternalCallContextFactory internalCallContextFactory) {
+        this.dao = dao;
+        this.internalCallContextFactory = internalCallContextFactory;
+    }
+
+
+    @Override
+    public List<BlockingState> getBlockingHistory(final UUID overdueableId, final TenantContext context) {
+        return dao.getBlockingHistoryFor(overdueableId, internalCallContextFactory.createInternalTenantContext(context));
+    }
+}
diff --git a/junction/src/main/java/com/ning/billing/junction/glue/DefaultJunctionModule.java b/junction/src/main/java/com/ning/billing/junction/glue/DefaultJunctionModule.java
index ce80386..d92e52a 100644
--- a/junction/src/main/java/com/ning/billing/junction/glue/DefaultJunctionModule.java
+++ b/junction/src/main/java/com/ning/billing/junction/glue/DefaultJunctionModule.java
@@ -21,6 +21,8 @@ import org.skife.config.ConfigSource;
 import com.ning.billing.account.api.AccountUserApi;
 import com.ning.billing.entitlement.api.user.EntitlementUserApi;
 import com.ning.billing.glue.JunctionModule;
+import com.ning.billing.junction.api.DefaultJunctionApi;
+import com.ning.billing.junction.api.JunctionApi;
 import com.ning.billing.junction.api.svcs.DefaultInternalBlockingApi;
 import com.ning.billing.junction.block.BlockingChecker;
 import com.ning.billing.junction.block.DefaultBlockingChecker;
@@ -51,6 +53,7 @@ public class DefaultJunctionModule extends AbstractModule implements JunctionMod
         installBillingApi();
         installEntitlementUserApi();
         installBlockingChecker();
+        installJunctionApi();
 
         // Internal
         installBlockingCalculator();
@@ -84,4 +87,9 @@ public class DefaultJunctionModule extends AbstractModule implements JunctionMod
     public void installBlockingCalculator() {
         bind(BlockingCalculator.class).asEagerSingleton();
     }
+
+    @Override
+    public void installJunctionApi() {
+        bind(JunctionApi.class).to(DefaultJunctionApi.class).asEagerSingleton();
+    }
 }
diff --git a/junction/src/main/java/com/ning/billing/junction/plumbing/api/BlockingSubscription.java b/junction/src/main/java/com/ning/billing/junction/plumbing/api/BlockingSubscription.java
index 249f976..9bd4d4b 100644
--- a/junction/src/main/java/com/ning/billing/junction/plumbing/api/BlockingSubscription.java
+++ b/junction/src/main/java/com/ning/billing/junction/plumbing/api/BlockingSubscription.java
@@ -16,6 +16,7 @@
 
 package com.ning.billing.junction.plumbing.api;
 
+import java.util.List;
 import java.util.UUID;
 
 import org.joda.time.DateTime;
@@ -220,6 +221,11 @@ public class BlockingSubscription implements Subscription {
         return subscription.getPreviousTransition();
     }
 
+    @Override
+    public List<SubscriptionTransition> getAllTransitions() {
+        return subscription.getAllTransitions();
+    }
+
     public Subscription getDelegateSubscription() {
         return subscription;
     }

osgi/pom.xml 2(+1 -1)

diff --git a/osgi/pom.xml b/osgi/pom.xml
index 3de957f..00782bb 100644
--- a/osgi/pom.xml
+++ b/osgi/pom.xml
@@ -20,7 +20,7 @@
     <parent>
         <groupId>com.ning.billing</groupId>
         <artifactId>killbill</artifactId>
-        <version>0.1.62-SNAPSHOT</version>
+        <version>0.1.64-SNAPSHOT</version>
         <relativePath>../pom.xml</relativePath>
     </parent>
     <artifactId>killbill-osgi</artifactId>
diff --git a/osgi/src/main/java/com/ning/billing/osgi/DefaultOSGIKillbill.java b/osgi/src/main/java/com/ning/billing/osgi/DefaultOSGIKillbill.java
index ea43446..18014ed 100644
--- a/osgi/src/main/java/com/ning/billing/osgi/DefaultOSGIKillbill.java
+++ b/osgi/src/main/java/com/ning/billing/osgi/DefaultOSGIKillbill.java
@@ -31,6 +31,7 @@ import com.ning.billing.entitlement.api.user.EntitlementUserApi;
 import com.ning.billing.invoice.api.InvoiceMigrationApi;
 import com.ning.billing.invoice.api.InvoicePaymentApi;
 import com.ning.billing.invoice.api.InvoiceUserApi;
+import com.ning.billing.junction.api.JunctionApi;
 import com.ning.billing.osgi.api.OSGIKillbill;
 import com.ning.billing.osgi.api.config.PluginConfigServiceApi;
 import com.ning.billing.osgi.glue.DefaultOSGIModule;
@@ -41,6 +42,7 @@ import com.ning.billing.usage.api.UsageUserApi;
 import com.ning.billing.util.api.AuditUserApi;
 import com.ning.billing.util.api.CustomFieldUserApi;
 import com.ning.billing.util.api.ExportUserApi;
+import com.ning.billing.util.api.RecordIdApi;
 import com.ning.billing.util.api.TagUserApi;
 
 public class DefaultOSGIKillbill implements OSGIKillbill {
@@ -64,6 +66,9 @@ public class DefaultOSGIKillbill implements OSGIKillbill {
     private final CustomFieldUserApi customFieldUserApi;
     private final ExportUserApi exportUserApi;
     private final TagUserApi tagUserApi;
+    private final JunctionApi junctionApi;
+    private final RecordIdApi recordIdApi;
+
     private final PluginConfigServiceApi configServiceApi;
 
     @Inject
@@ -86,6 +91,8 @@ public class DefaultOSGIKillbill implements OSGIKillbill {
                                final CustomFieldUserApi customFieldUserApi,
                                final ExportUserApi exportUserApi,
                                final TagUserApi tagUserApi,
+                               final JunctionApi junctionApi,
+                               final RecordIdApi recordIdApi,
                                final PluginConfigServiceApi configServiceApi) {
         this.accountUserApi = accountUserApi;
         this.analyticsSanityApi = analyticsSanityApi;
@@ -106,6 +113,8 @@ public class DefaultOSGIKillbill implements OSGIKillbill {
         this.customFieldUserApi = customFieldUserApi;
         this.exportUserApi = exportUserApi;
         this.tagUserApi = tagUserApi;
+        this.junctionApi = junctionApi;
+        this.recordIdApi = recordIdApi;
         this.configServiceApi = configServiceApi;
     }
 
@@ -205,6 +214,16 @@ public class DefaultOSGIKillbill implements OSGIKillbill {
     }
 
     @Override
+    public JunctionApi getJunctionApi() {
+        return junctionApi;
+    }
+
+    @Override
+    public RecordIdApi getRecordIdApi() {
+        return recordIdApi;
+    }
+
+    @Override
     public PluginConfigServiceApi getPluginConfigServiceApi() {
         return configServiceApi;
     }
diff --git a/osgi-bundles/bundles/jruby/pom.xml b/osgi-bundles/bundles/jruby/pom.xml
index 0437c0e..5eeebc8 100644
--- a/osgi-bundles/bundles/jruby/pom.xml
+++ b/osgi-bundles/bundles/jruby/pom.xml
@@ -20,7 +20,7 @@
     <parent>
         <groupId>com.ning.billing</groupId>
         <artifactId>killbill-osgi-bundles</artifactId>
-        <version>0.1.62-SNAPSHOT</version>
+        <version>0.1.64-SNAPSHOT</version>
         <relativePath>../pom.xml</relativePath>
     </parent>
     <artifactId>killbill-osgi-bundles-jruby</artifactId>
diff --git a/osgi-bundles/bundles/jruby/src/main/java/com/ning/billing/osgi/bundles/jruby/JRubyPaymentPlugin.java b/osgi-bundles/bundles/jruby/src/main/java/com/ning/billing/osgi/bundles/jruby/JRubyPaymentPlugin.java
index ddd411e..99ab86b 100644
--- a/osgi-bundles/bundles/jruby/src/main/java/com/ning/billing/osgi/bundles/jruby/JRubyPaymentPlugin.java
+++ b/osgi-bundles/bundles/jruby/src/main/java/com/ning/billing/osgi/bundles/jruby/JRubyPaymentPlugin.java
@@ -104,6 +104,16 @@ public class JRubyPaymentPlugin extends JRubyPlugin implements PaymentPluginApi 
     }
 
     @Override
+    public List<RefundInfoPlugin> getRefundInfo(final UUID kbAccountId, final UUID kbPaymentId, final TenantContext context) throws PaymentPluginApiException {
+        return callWithRuntimeAndChecking(new PluginCallback()  {
+            @Override
+            public List<RefundInfoPlugin> doCall(final Ruby runtime) throws PaymentPluginApiException {
+                return ((PaymentPluginApi) pluginInstance).getRefundInfo(kbAccountId, kbPaymentId, context);
+            }
+        });
+    }
+
+    @Override
     public void addPaymentMethod(final UUID kbAccountId, final UUID kbPaymentMethodId, final PaymentMethodPlugin paymentMethodProps, final boolean setDefault, final CallContext context) throws PaymentPluginApiException {
 
         callWithRuntimeAndChecking(new PluginCallback() {
diff --git a/osgi-bundles/bundles/jruby/src/main/java/com/ning/billing/osgi/bundles/jruby/JRubyPlugin.java b/osgi-bundles/bundles/jruby/src/main/java/com/ning/billing/osgi/bundles/jruby/JRubyPlugin.java
index e6b8f5d..d45ee1a 100644
--- a/osgi-bundles/bundles/jruby/src/main/java/com/ning/billing/osgi/bundles/jruby/JRubyPlugin.java
+++ b/osgi-bundles/bundles/jruby/src/main/java/com/ning/billing/osgi/bundles/jruby/JRubyPlugin.java
@@ -195,7 +195,8 @@ public abstract class JRubyPlugin {
             builder.append("begin\n")
                    .append("require '").append(pluginGemName).append("'\n")
                    .append("rescue LoadError\n")
-                   .append("warn \"WARN: unable to require ").append(pluginGemName).append("\"\n")
+                   // Could be useful for debugging
+                   //.append("warn \"WARN: unable to require ").append(pluginGemName).append("\"\n")
                    .append("end\n");
             // Load the extra require file, if specified
             if (rubyRequire != null) {
diff --git a/osgi-bundles/bundles/logger/pom.xml b/osgi-bundles/bundles/logger/pom.xml
index 390d388..e3adae0 100644
--- a/osgi-bundles/bundles/logger/pom.xml
+++ b/osgi-bundles/bundles/logger/pom.xml
@@ -20,7 +20,7 @@
     <parent>
         <groupId>com.ning.billing</groupId>
         <artifactId>killbill-osgi-bundles</artifactId>
-        <version>0.1.62-SNAPSHOT</version>
+        <version>0.1.64-SNAPSHOT</version>
         <relativePath>../pom.xml</relativePath>
     </parent>
     <artifactId>killbill-osgi-bundles-logger</artifactId>
diff --git a/osgi-bundles/bundles/meter/pom.xml b/osgi-bundles/bundles/meter/pom.xml
index bd972c8..959ee5d 100644
--- a/osgi-bundles/bundles/meter/pom.xml
+++ b/osgi-bundles/bundles/meter/pom.xml
@@ -13,7 +13,7 @@
     <parent>
         <groupId>com.ning.billing</groupId>
         <artifactId>killbill-osgi-bundles</artifactId>
-        <version>0.1.62-SNAPSHOT</version>
+        <version>0.1.64-SNAPSHOT</version>
         <relativePath>../pom.xml</relativePath>
     </parent>
     <artifactId>killbill-osgi-bundles-meter</artifactId>
diff --git a/osgi-bundles/bundles/pom.xml b/osgi-bundles/bundles/pom.xml
index 82dab13..2b1d69c 100644
--- a/osgi-bundles/bundles/pom.xml
+++ b/osgi-bundles/bundles/pom.xml
@@ -20,7 +20,7 @@
     <parent>
         <groupId>com.ning.billing</groupId>
         <artifactId>killbill-osgi-all-bundles</artifactId>
-        <version>0.1.62-SNAPSHOT</version>
+        <version>0.1.64-SNAPSHOT</version>
         <relativePath>../pom.xml</relativePath>
     </parent>
     <artifactId>killbill-osgi-bundles</artifactId>
diff --git a/osgi-bundles/bundles/webconsolebranding/pom.xml b/osgi-bundles/bundles/webconsolebranding/pom.xml
index 9e9fe1c..699d8c2 100644
--- a/osgi-bundles/bundles/webconsolebranding/pom.xml
+++ b/osgi-bundles/bundles/webconsolebranding/pom.xml
@@ -20,7 +20,7 @@
     <parent>
         <groupId>com.ning.billing</groupId>
         <artifactId>killbill-osgi-bundles</artifactId>
-        <version>0.1.62-SNAPSHOT</version>
+        <version>0.1.64-SNAPSHOT</version>
         <relativePath>../pom.xml</relativePath>
     </parent>
     <artifactId>killbill-osgi-bundles-webconsolebranding</artifactId>
diff --git a/osgi-bundles/defaultbundles/pom.xml b/osgi-bundles/defaultbundles/pom.xml
index 1e88c52..b345275 100644
--- a/osgi-bundles/defaultbundles/pom.xml
+++ b/osgi-bundles/defaultbundles/pom.xml
@@ -20,7 +20,7 @@
     <parent>
         <groupId>com.ning.billing</groupId>
         <artifactId>killbill-osgi-all-bundles</artifactId>
-        <version>0.1.62-SNAPSHOT</version>
+        <version>0.1.64-SNAPSHOT</version>
         <relativePath>../pom.xml</relativePath>
     </parent>
     <artifactId>killbill-osgi-bundles-defaultbundles</artifactId>
diff --git a/osgi-bundles/libs/killbill/pom.xml b/osgi-bundles/libs/killbill/pom.xml
index a852e85..e146ca7 100644
--- a/osgi-bundles/libs/killbill/pom.xml
+++ b/osgi-bundles/libs/killbill/pom.xml
@@ -20,7 +20,7 @@
     <parent>
         <groupId>com.ning.billing</groupId>
         <artifactId>killbill-osgi-lib-bundles</artifactId>
-        <version>0.1.62-SNAPSHOT</version>
+        <version>0.1.64-SNAPSHOT</version>
         <relativePath>../pom.xml</relativePath>
     </parent>
     <artifactId>killbill-osgi-bundles-lib-killbill</artifactId>
diff --git a/osgi-bundles/libs/killbill/src/main/java/com/ning/killbill/osgi/libs/killbill/OSGIKillbillAPI.java b/osgi-bundles/libs/killbill/src/main/java/com/ning/killbill/osgi/libs/killbill/OSGIKillbillAPI.java
index 47ca336..5cc50a7 100644
--- a/osgi-bundles/libs/killbill/src/main/java/com/ning/killbill/osgi/libs/killbill/OSGIKillbillAPI.java
+++ b/osgi-bundles/libs/killbill/src/main/java/com/ning/killbill/osgi/libs/killbill/OSGIKillbillAPI.java
@@ -30,6 +30,7 @@ import com.ning.billing.entitlement.api.user.EntitlementUserApi;
 import com.ning.billing.invoice.api.InvoiceMigrationApi;
 import com.ning.billing.invoice.api.InvoicePaymentApi;
 import com.ning.billing.invoice.api.InvoiceUserApi;
+import com.ning.billing.junction.api.JunctionApi;
 import com.ning.billing.osgi.api.OSGIKillbill;
 import com.ning.billing.osgi.api.config.PluginConfigServiceApi;
 import com.ning.billing.overdue.OverdueUserApi;
@@ -39,6 +40,7 @@ import com.ning.billing.usage.api.UsageUserApi;
 import com.ning.billing.util.api.AuditUserApi;
 import com.ning.billing.util.api.CustomFieldUserApi;
 import com.ning.billing.util.api.ExportUserApi;
+import com.ning.billing.util.api.RecordIdApi;
 import com.ning.billing.util.api.TagUserApi;
 
 public class OSGIKillbillAPI extends OSGIKillbillLibraryBase implements OSGIKillbill {
@@ -251,6 +253,26 @@ public class OSGIKillbillAPI extends OSGIKillbillLibraryBase implements OSGIKill
     }
 
     @Override
+    public JunctionApi getJunctionApi() {
+        return withServiceTracker(killbillTracker, new APICallback<JunctionApi, OSGIKillbill>(KILLBILL_SERVICE_NAME) {
+            @Override
+            public JunctionApi executeWithService(final OSGIKillbill service) {
+                return service.getJunctionApi();
+            }
+        });
+    }
+
+    @Override
+    public RecordIdApi getRecordIdApi() {
+        return withServiceTracker(killbillTracker, new APICallback<RecordIdApi, OSGIKillbill>(KILLBILL_SERVICE_NAME) {
+            @Override
+            public RecordIdApi executeWithService(final OSGIKillbill service) {
+                return service.getRecordIdApi();
+            }
+        });
+    }
+
+    @Override
     public PluginConfigServiceApi getPluginConfigServiceApi() {
         return withServiceTracker(killbillTracker, new APICallback<PluginConfigServiceApi, OSGIKillbill>(KILLBILL_SERVICE_NAME) {
             @Override
diff --git a/osgi-bundles/libs/pom.xml b/osgi-bundles/libs/pom.xml
index b424ea6..df8695b 100644
--- a/osgi-bundles/libs/pom.xml
+++ b/osgi-bundles/libs/pom.xml
@@ -20,7 +20,7 @@
     <parent>
         <groupId>com.ning.billing</groupId>
         <artifactId>killbill-osgi-all-bundles</artifactId>
-        <version>0.1.62-SNAPSHOT</version>
+        <version>0.1.64-SNAPSHOT</version>
         <relativePath>../pom.xml</relativePath>
     </parent>
     <artifactId>killbill-osgi-lib-bundles</artifactId>
diff --git a/osgi-bundles/libs/slf4j-osgi/pom.xml b/osgi-bundles/libs/slf4j-osgi/pom.xml
index 4f186cd..3f899a9 100644
--- a/osgi-bundles/libs/slf4j-osgi/pom.xml
+++ b/osgi-bundles/libs/slf4j-osgi/pom.xml
@@ -20,7 +20,7 @@
     <parent>
         <groupId>com.ning.billing</groupId>
         <artifactId>killbill-osgi-lib-bundles</artifactId>
-        <version>0.1.62-SNAPSHOT</version>
+        <version>0.1.64-SNAPSHOT</version>
         <relativePath>../pom.xml</relativePath>
     </parent>
     <artifactId>killbill-osgi-bundles-lib-slf4j-osgi</artifactId>
diff --git a/osgi-bundles/pom.xml b/osgi-bundles/pom.xml
index 65c526f..836fab1 100644
--- a/osgi-bundles/pom.xml
+++ b/osgi-bundles/pom.xml
@@ -20,7 +20,7 @@
     <parent>
         <groupId>com.ning.billing</groupId>
         <artifactId>killbill</artifactId>
-        <version>0.1.62-SNAPSHOT</version>
+        <version>0.1.64-SNAPSHOT</version>
         <relativePath>../pom.xml</relativePath>
     </parent>
     <artifactId>killbill-osgi-all-bundles</artifactId>
diff --git a/osgi-bundles/tests/beatrix/pom.xml b/osgi-bundles/tests/beatrix/pom.xml
index c2b1b39..cd003f2 100644
--- a/osgi-bundles/tests/beatrix/pom.xml
+++ b/osgi-bundles/tests/beatrix/pom.xml
@@ -20,7 +20,7 @@
     <parent>
         <groupId>com.ning.billing</groupId>
         <artifactId>killbill-osgi-test-bundles</artifactId>
-        <version>0.1.62-SNAPSHOT</version>
+        <version>0.1.64-SNAPSHOT</version>
         <relativePath>../pom.xml</relativePath>
     </parent>
     <artifactId>killbill-osgi-bundles-test-beatrix</artifactId>
diff --git a/osgi-bundles/tests/beatrix/src/test/java/com/ning/billing/osgi/bundles/test/TestPaymentPluginApi.java b/osgi-bundles/tests/beatrix/src/test/java/com/ning/billing/osgi/bundles/test/TestPaymentPluginApi.java
index ee22e5a..b010a8b 100644
--- a/osgi-bundles/tests/beatrix/src/test/java/com/ning/billing/osgi/bundles/test/TestPaymentPluginApi.java
+++ b/osgi-bundles/tests/beatrix/src/test/java/com/ning/billing/osgi/bundles/test/TestPaymentPluginApi.java
@@ -17,6 +17,7 @@
 package com.ning.billing.osgi.bundles.test;
 
 import java.math.BigDecimal;
+import java.util.Collections;
 import java.util.List;
 import java.util.UUID;
 
@@ -71,6 +72,16 @@ public class TestPaymentPluginApi implements PaymentPluginApi {
             public String getGatewayErrorCode() {
                 return null;
             }
+
+            @Override
+            public String getFirstPaymentReferenceId() {
+                return null;
+            }
+
+            @Override
+            public String getSecondPaymentReferenceId() {
+                return null;
+            }
         };
     }
 
@@ -85,6 +96,11 @@ public class TestPaymentPluginApi implements PaymentPluginApi {
     }
 
     @Override
+    public List<RefundInfoPlugin> getRefundInfo(final UUID kbAccountId, final UUID kbPaymentId, final TenantContext context) {
+        return Collections.<RefundInfoPlugin>emptyList();
+    }
+
+    @Override
     public void addPaymentMethod(final UUID kbAccountId, final UUID kbPaymentMethodId, final PaymentMethodPlugin paymentMethodProps, final boolean setDefault, final CallContext context) throws PaymentPluginApiException {
     }
 
diff --git a/osgi-bundles/tests/payment/pom.xml b/osgi-bundles/tests/payment/pom.xml
index d5db3bb..c0c3548 100644
--- a/osgi-bundles/tests/payment/pom.xml
+++ b/osgi-bundles/tests/payment/pom.xml
@@ -20,7 +20,7 @@
     <parent>
         <groupId>com.ning.billing</groupId>
         <artifactId>killbill-osgi-test-bundles</artifactId>
-        <version>0.1.62-SNAPSHOT</version>
+        <version>0.1.64-SNAPSHOT</version>
         <relativePath>../pom.xml</relativePath>
     </parent>
     <artifactId>killbill-osgi-bundles-test-payment</artifactId>
diff --git a/osgi-bundles/tests/payment/src/test/java/com/ning/billing/osgi/bundles/test/TestPaymentPluginApi.java b/osgi-bundles/tests/payment/src/test/java/com/ning/billing/osgi/bundles/test/TestPaymentPluginApi.java
index 82acb4b..5cbf7e1 100644
--- a/osgi-bundles/tests/payment/src/test/java/com/ning/billing/osgi/bundles/test/TestPaymentPluginApi.java
+++ b/osgi-bundles/tests/payment/src/test/java/com/ning/billing/osgi/bundles/test/TestPaymentPluginApi.java
@@ -17,6 +17,7 @@
 package com.ning.billing.osgi.bundles.test;
 
 import java.math.BigDecimal;
+import java.util.Collections;
 import java.util.List;
 import java.util.UUID;
 
@@ -71,6 +72,16 @@ public class TestPaymentPluginApi implements PaymentPluginApiWithTestControl {
             public String getGatewayErrorCode() {
                 return null;
             }
+
+            @Override
+            public String getFirstPaymentReferenceId() {
+                return null;
+            }
+
+            @Override
+            public String getSecondPaymentReferenceId() {
+                return null;
+            }
         });
     }
 
@@ -103,6 +114,16 @@ public class TestPaymentPluginApi implements PaymentPluginApiWithTestControl {
             public String getGatewayErrorCode() {
                 return null;
             }
+
+            @Override
+            public String getFirstPaymentReferenceId() {
+                return null;
+            }
+
+            @Override
+            public String getSecondPaymentReferenceId() {
+                return null;
+            }
         });
     }
 
@@ -135,10 +156,20 @@ public class TestPaymentPluginApi implements PaymentPluginApiWithTestControl {
             public String getGatewayErrorCode() {
                 return null;
             }
+
+            @Override
+            public String getReferenceId() {
+                return null;
+            }
         });
     }
 
     @Override
+    public List<RefundInfoPlugin> getRefundInfo(final UUID kbAccountId, final UUID kbPaymentId, final TenantContext context) {
+        return Collections.<RefundInfoPlugin>emptyList();
+    }
+
+    @Override
     public void addPaymentMethod(final UUID kbAccountId, final UUID kbPaymentMethodId, final PaymentMethodPlugin paymentMethodProps, final boolean setDefault, final CallContext context) throws PaymentPluginApiException {
     }
 
diff --git a/osgi-bundles/tests/pom.xml b/osgi-bundles/tests/pom.xml
index da1322d..9e172d7 100644
--- a/osgi-bundles/tests/pom.xml
+++ b/osgi-bundles/tests/pom.xml
@@ -20,7 +20,7 @@
     <parent>
         <groupId>com.ning.billing</groupId>
         <artifactId>killbill-osgi-all-bundles</artifactId>
-        <version>0.1.62-SNAPSHOT</version>
+        <version>0.1.64-SNAPSHOT</version>
         <relativePath>../pom.xml</relativePath>
     </parent>
     <artifactId>killbill-osgi-test-bundles</artifactId>

overdue/pom.xml 2(+1 -1)

diff --git a/overdue/pom.xml b/overdue/pom.xml
index ed86cd3..5039da3 100644
--- a/overdue/pom.xml
+++ b/overdue/pom.xml
@@ -20,7 +20,7 @@
     <parent>
         <groupId>com.ning.billing</groupId>
         <artifactId>killbill</artifactId>
-        <version>0.1.62-SNAPSHOT</version>
+        <version>0.1.64-SNAPSHOT</version>
         <relativePath>../pom.xml</relativePath>
     </parent>
     <artifactId>killbill-overdue</artifactId>

payment/pom.xml 2(+1 -1)

diff --git a/payment/pom.xml b/payment/pom.xml
index 38a6e6f..31ad5aa 100644
--- a/payment/pom.xml
+++ b/payment/pom.xml
@@ -20,7 +20,7 @@
     <parent>
         <groupId>com.ning.billing</groupId>
         <artifactId>killbill</artifactId>
-        <version>0.1.62-SNAPSHOT</version>
+        <version>0.1.64-SNAPSHOT</version>
         <relativePath>../pom.xml</relativePath>
     </parent>
     <artifactId>killbill-payment</artifactId>
diff --git a/payment/src/main/java/com/ning/billing/payment/api/DefaultPayment.java b/payment/src/main/java/com/ning/billing/payment/api/DefaultPayment.java
index a9ed30d..a036ed0 100644
--- a/payment/src/main/java/com/ning/billing/payment/api/DefaultPayment.java
+++ b/payment/src/main/java/com/ning/billing/payment/api/DefaultPayment.java
@@ -31,6 +31,7 @@ import com.ning.billing.payment.dao.PaymentAttemptModelDao;
 import com.ning.billing.payment.dao.PaymentModelDao;
 import com.ning.billing.payment.dao.RefundModelDao;
 import com.ning.billing.payment.dao.RefundModelDao.RefundStatus;
+import com.ning.billing.payment.plugin.api.PaymentInfoPlugin;
 import com.ning.billing.util.entity.EntityBase;
 
 import com.google.common.base.Function;
@@ -50,11 +51,14 @@ public class DefaultPayment extends EntityBase implements Payment {
     private final String extFirstPaymentIdRef;
     private final String extSecondPaymentIdRef;
     private final List<PaymentAttempt> attempts;
+    private final PaymentInfoPlugin paymentPluginInfo;
 
     private DefaultPayment(final UUID id, @Nullable final DateTime createdDate, @Nullable final DateTime updatedDate, final UUID accountId, final UUID invoiceId,
                            final UUID paymentMethodId, final BigDecimal amount, final BigDecimal paidAmount, final Currency currency,
                            final DateTime effectiveDate, final Integer paymentNumber,
-                           final PaymentStatus paymentStatus, final String paymentError, final String extFirstPaymentIdRef,
+                           final PaymentStatus paymentStatus, final String paymentError,
+                           final PaymentInfoPlugin paymentPluginInfo,
+                           final String extFirstPaymentIdRef,
                            final String extSecondPaymentIdRef, final List<PaymentAttempt> attempts) {
         super(id, createdDate, updatedDate);
         this.accountId = accountId;
@@ -69,9 +73,10 @@ public class DefaultPayment extends EntityBase implements Payment {
         this.extFirstPaymentIdRef = extFirstPaymentIdRef;
         this.extSecondPaymentIdRef = extSecondPaymentIdRef;
         this.attempts = attempts;
+        this.paymentPluginInfo = paymentPluginInfo;
     }
 
-    public DefaultPayment(final PaymentModelDao src, final List<PaymentAttemptModelDao> attempts, final List<RefundModelDao> refunds) {
+    public DefaultPayment(final PaymentModelDao src, final PaymentInfoPlugin paymentPluginInfo, final List<PaymentAttemptModelDao> attempts, final List<RefundModelDao> refunds) {
         this(src.getId(),
              src.getCreatedDate(),
              src.getUpdatedDate(),
@@ -85,6 +90,7 @@ public class DefaultPayment extends EntityBase implements Payment {
              src.getPaymentNumber(),
              src.getPaymentStatus(),
              null,
+             paymentPluginInfo,
              src.getExtFirstPaymentRefId(),
              src.getExtSecondPaymentRefId(),
              toPaymentAttempts(attempts));
@@ -146,6 +152,11 @@ public class DefaultPayment extends EntityBase implements Payment {
     }
 
     @Override
+    public PaymentInfoPlugin getPaymentInfoPlugin() {
+        return paymentPluginInfo;
+    }
+
+    @Override
     public List<PaymentAttempt> getAttempts() {
         return attempts;
     }
diff --git a/payment/src/main/java/com/ning/billing/payment/api/DefaultPaymentApi.java b/payment/src/main/java/com/ning/billing/payment/api/DefaultPaymentApi.java
index 8777ae4..b996ecf 100644
--- a/payment/src/main/java/com/ning/billing/payment/api/DefaultPaymentApi.java
+++ b/payment/src/main/java/com/ning/billing/payment/api/DefaultPaymentApi.java
@@ -67,8 +67,8 @@ public class DefaultPaymentApi implements PaymentApi {
     }
 
     @Override
-    public Payment getPayment(final UUID paymentId, final TenantContext context) throws PaymentApiException {
-        final Payment payment = paymentProcessor.getPayment(paymentId, internalCallContextFactory.createInternalTenantContext(context));
+    public Payment getPayment(final UUID paymentId, final boolean withPluginInfo, final TenantContext context) throws PaymentApiException {
+        final Payment payment = paymentProcessor.getPayment(paymentId, withPluginInfo, internalCallContextFactory.createInternalTenantContext(context));
         if (payment == null) {
             throw new PaymentApiException(ErrorCode.PAYMENT_NO_SUCH_PAYMENT, paymentId);
         }
@@ -87,8 +87,8 @@ public class DefaultPaymentApi implements PaymentApi {
     }
 
     @Override
-    public Refund getRefund(final UUID refundId, final TenantContext context) throws PaymentApiException {
-        return refundProcessor.getRefund(refundId, internalCallContextFactory.createInternalTenantContext(context));
+    public Refund getRefund(final UUID refundId, final boolean withPluginInfo, final TenantContext context) throws PaymentApiException {
+        return refundProcessor.getRefund(refundId, withPluginInfo, internalCallContextFactory.createInternalTenantContext(context));
     }
 
     @Override
diff --git a/payment/src/main/java/com/ning/billing/payment/api/DefaultRefund.java b/payment/src/main/java/com/ning/billing/payment/api/DefaultRefund.java
index 5cc7297..6d512ca 100644
--- a/payment/src/main/java/com/ning/billing/payment/api/DefaultRefund.java
+++ b/payment/src/main/java/com/ning/billing/payment/api/DefaultRefund.java
@@ -24,6 +24,7 @@ import javax.annotation.Nullable;
 import org.joda.time.DateTime;
 
 import com.ning.billing.catalog.api.Currency;
+import com.ning.billing.payment.plugin.api.RefundInfoPlugin;
 import com.ning.billing.util.entity.EntityBase;
 
 public class DefaultRefund extends EntityBase implements Refund {
@@ -71,6 +72,12 @@ public class DefaultRefund extends EntityBase implements Refund {
     }
 
     @Override
+    public RefundInfoPlugin getPluginDetail() {
+        // TODO not implemented
+        return null;
+    }
+
+    @Override
     public String toString() {
         final StringBuilder sb = new StringBuilder();
         sb.append("DefaultRefund");
diff --git a/payment/src/main/java/com/ning/billing/payment/api/svcs/DefaultPaymentInternalApi.java b/payment/src/main/java/com/ning/billing/payment/api/svcs/DefaultPaymentInternalApi.java
index 673ea85..8368304 100644
--- a/payment/src/main/java/com/ning/billing/payment/api/svcs/DefaultPaymentInternalApi.java
+++ b/payment/src/main/java/com/ning/billing/payment/api/svcs/DefaultPaymentInternalApi.java
@@ -44,7 +44,7 @@ public class DefaultPaymentInternalApi implements PaymentInternalApi {
 
     @Override
     public Payment getPayment(final UUID paymentId, final InternalTenantContext context) throws PaymentApiException {
-        final Payment payment = paymentProcessor.getPayment(paymentId, context);
+        final Payment payment = paymentProcessor.getPayment(paymentId, false, context);
         if (payment == null) {
             throw new PaymentApiException(ErrorCode.PAYMENT_NO_SUCH_PAYMENT, paymentId);
         }
diff --git a/payment/src/main/java/com/ning/billing/payment/core/PaymentProcessor.java b/payment/src/main/java/com/ning/billing/payment/core/PaymentProcessor.java
index f33a55e..dc45727 100644
--- a/payment/src/main/java/com/ning/billing/payment/core/PaymentProcessor.java
+++ b/payment/src/main/java/com/ning/billing/payment/core/PaymentProcessor.java
@@ -117,12 +117,21 @@ public class PaymentProcessor extends ProcessorBase {
         this.voidPluginDispatcher = new PluginDispatcher<Void>(executor);
     }
 
-    public Payment getPayment(final UUID paymentId, final InternalTenantContext context) {
+    public Payment getPayment(final UUID paymentId, final boolean withPluginInfo, final InternalTenantContext context) throws PaymentApiException {
         final PaymentModelDao model = paymentDao.getPayment(paymentId, context);
         if (model == null) {
             return null;
         }
-        return getPayments(Collections.singletonList(model), context).get(0);
+        final PaymentPluginApi plugin = withPluginInfo ? getPaymentProviderPlugin(model.getPaymentMethodId(), context) : null;
+        PaymentInfoPlugin pluginInfo = null;
+        if (plugin != null) {
+            try {
+                pluginInfo = plugin.getPaymentInfo(model.getAccountId(), paymentId, context.toTenantContext());
+            } catch (PaymentPluginApiException e) {
+                throw new PaymentApiException(ErrorCode.PAYMENT_PLUGIN_GET_PAYMENT_INFO, paymentId, e.toString());
+            }
+        }
+        return fromPaymentModelDao(model, pluginInfo, context);
     }
 
 
@@ -141,14 +150,19 @@ public class PaymentProcessor extends ProcessorBase {
         }
         final List<Payment> result = new LinkedList<Payment>();
         for (final PaymentModelDao cur : payments) {
-            final List<PaymentAttemptModelDao> attempts = paymentDao.getAttemptsForPayment(cur.getId(), context);
-            final List<RefundModelDao> refunds = paymentDao.getRefundsForPayment(cur.getId(), context);
-            final Payment entry = new DefaultPayment(cur, attempts, refunds);
+            final Payment entry = fromPaymentModelDao(cur, null, context);
             result.add(entry);
         }
         return result;
     }
 
+    private Payment fromPaymentModelDao(final PaymentModelDao input, final PaymentInfoPlugin pluginInfo, final InternalTenantContext context) {
+        final List<PaymentAttemptModelDao> attempts = paymentDao.getAttemptsForPayment(input.getId(), context);
+        final List<RefundModelDao> refunds = paymentDao.getRefundsForPayment(input.getId(), context);
+        final Payment payment = new DefaultPayment(input, pluginInfo, attempts, refunds);
+        return payment;
+    }
+
     public void process_AUTO_PAY_OFF_removal(final Account account, final InternalCallContext context) throws PaymentApiException {
 
         try {
@@ -388,7 +402,7 @@ public class PaymentProcessor extends ProcessorBase {
         final PaymentAttemptModelDao attempt = new PaymentAttemptModelDao(account.getId(), invoice.getId(), paymentInfo.getId(), paymentStatus, clock.getUTCNow(), requestedAmount);
 
         paymentDao.insertPaymentWithAttempt(paymentInfo, attempt, context);
-        return new DefaultPayment(paymentInfo, Collections.singletonList(attempt), Collections.<RefundModelDao>emptyList());
+        return fromPaymentModelDao(paymentInfo, null, context);
     }
 
     private Payment processNewPaymentWithAccountLocked(final UUID paymentMethodId, final PaymentPluginApi plugin, final Account account, final Invoice invoice,
@@ -414,22 +428,29 @@ public class PaymentProcessor extends ProcessorBase {
 
         List<PaymentAttemptModelDao> allAttempts = null;
         if (paymentConfig.isPaymentOff()) {
-            paymentDao.updateStatusForPaymentWithAttempt(paymentInput.getId(), PaymentStatus.PAYMENT_SYSTEM_OFF, null, null, attemptInput.getId(), context);
+            paymentDao.updateStatusAndEffectiveDateForPaymentWithAttempt(paymentInput.getId(), PaymentStatus.PAYMENT_SYSTEM_OFF, clock.getUTCNow(), attemptInput.getId(), null, null,  context);
             allAttempts = paymentDao.getAttemptsForPayment(paymentInput.getId(), context);
-            return new DefaultPayment(paymentInput, allAttempts, Collections.<RefundModelDao>emptyList());
+            return new DefaultPayment(paymentInput, null, allAttempts, Collections.<RefundModelDao>emptyList());
         }
 
         PaymentModelDao payment = null;
         BusInternalEvent event = null;
         PaymentStatus paymentStatus;
+        final PaymentInfoPlugin paymentPluginInfo;
         try {
 
-            final PaymentInfoPlugin paymentPluginInfo = plugin.processPayment(account.getId(), paymentInput.getId(), paymentInput.getPaymentMethodId(), attemptInput.getRequestedAmount(), account.getCurrency(), context.toCallContext());
+            paymentPluginInfo = plugin.processPayment(account.getId(), paymentInput.getId(), paymentInput.getPaymentMethodId(), attemptInput.getRequestedAmount(), account.getCurrency(), context.toCallContext());
             switch (paymentPluginInfo.getStatus()) {
                 case PROCESSED:
                     // Update Payment/PaymentAttempt status
                     paymentStatus = PaymentStatus.SUCCESS;
-                    paymentDao.updateStatusForPaymentWithAttempt(paymentInput.getId(), paymentStatus, paymentPluginInfo.getGatewayErrorCode(), null, attemptInput.getId(), context);
+
+                    /*
+                    UUID paymentId, PaymentStatus paymentStatus, DateTime newEffectiveDate,
+                                                                  String gatewayErrorMsg, UUID attemptId, InternalCallContext context, String gatewayErrorCode
+                     */
+
+                    paymentDao.updateStatusAndEffectiveDateForPaymentWithAttempt(paymentInput.getId(), paymentStatus, clock.getUTCNow(), attemptInput.getId(), paymentPluginInfo.getGatewayErrorCode(), null,  context);
 
                     // Fetch latest objects
                     allAttempts = paymentDao.getAttemptsForPayment(paymentInput.getId(), context);
@@ -458,7 +479,7 @@ public class PaymentProcessor extends ProcessorBase {
                         paymentStatus = PaymentStatus.PAYMENT_FAILURE_ABORTED;
                     }
 
-                    paymentDao.updateStatusForPaymentWithAttempt(paymentInput.getId(), paymentStatus, paymentPluginInfo.getGatewayErrorCode(), paymentPluginInfo.getGatewayError(), attemptInput.getId(), context);
+                    paymentDao.updateStatusAndEffectiveDateForPaymentWithAttempt(paymentInput.getId(), paymentStatus, clock.getUTCNow(), attemptInput.getId(), paymentPluginInfo.getGatewayErrorCode(), paymentPluginInfo.getGatewayError(),  context);
 
                     log.info(String.format("Could not process payment for account %s, invoice %s, error = %s",
                                            account.getId(), invoice.getId(), paymentPluginInfo.getGatewayError()));
@@ -480,7 +501,7 @@ public class PaymentProcessor extends ProcessorBase {
             paymentStatus = isInstantPayment ? PaymentStatus.PAYMENT_FAILURE_ABORTED : scheduleRetryOnPluginFailure(paymentInput.getId(), context);
             // STEPH message might need truncation to fit??
 
-            paymentDao.updateStatusForPaymentWithAttempt(paymentInput.getId(), paymentStatus, null, e.getMessage(), attemptInput.getId(), context);
+            paymentDao.updateStatusAndEffectiveDateForPaymentWithAttempt(paymentInput.getId(), paymentStatus, clock.getUTCNow(), attemptInput.getId(), null, e.getMessage(), context);
 
             throw new PaymentApiException(ErrorCode.PAYMENT_CREATE_PAYMENT, account.getId(), e.toString());
 
@@ -491,7 +512,8 @@ public class PaymentProcessor extends ProcessorBase {
                 postPaymentEvent(event, account.getId(), context);
             }
         }
-        return new DefaultPayment(payment, allAttempts, Collections.<RefundModelDao>emptyList());
+
+        return new DefaultPayment(payment, paymentPluginInfo, allAttempts, Collections.<RefundModelDao>emptyList());
     }
 
     private PaymentStatus scheduleRetryOnPluginFailure(final UUID paymentId, final InternalTenantContext context) {
diff --git a/payment/src/main/java/com/ning/billing/payment/core/RefundProcessor.java b/payment/src/main/java/com/ning/billing/payment/core/RefundProcessor.java
index 6778994..86068e9 100644
--- a/payment/src/main/java/com/ning/billing/payment/core/RefundProcessor.java
+++ b/payment/src/main/java/com/ning/billing/payment/core/RefundProcessor.java
@@ -183,7 +183,7 @@ public class RefundProcessor extends ProcessorBase {
         throw new IllegalArgumentException("Unable to find invoice item for id " + itemId);
     }
 
-    public Refund getRefund(final UUID refundId, final InternalTenantContext context)
+    public Refund getRefund(final UUID refundId, final boolean withPluginInfo /* not yet implemented */ , final InternalTenantContext context)
             throws PaymentApiException {
         RefundModelDao result = paymentDao.getRefund(refundId, context);
         if (result == null) {
diff --git a/payment/src/main/java/com/ning/billing/payment/dao/DefaultPaymentDao.java b/payment/src/main/java/com/ning/billing/payment/dao/DefaultPaymentDao.java
index 7e81ac1..05fbfa6 100644
--- a/payment/src/main/java/com/ning/billing/payment/dao/DefaultPaymentDao.java
+++ b/payment/src/main/java/com/ning/billing/payment/dao/DefaultPaymentDao.java
@@ -23,6 +23,7 @@ import java.util.UUID;
 
 import javax.inject.Inject;
 
+import org.joda.time.DateTime;
 import org.skife.jdbi.v2.IDBI;
 
 import com.ning.billing.payment.api.PaymentStatus;
@@ -92,17 +93,18 @@ public class DefaultPaymentDao implements PaymentDao {
     }
 
     @Override
-    public void updateStatusForPaymentWithAttempt(final UUID paymentId,
-                                                  final PaymentStatus paymentStatus,
-                                                  final String gatewayErrorCode,
-                                                  final String gatewayErrorMsg,
-                                                  final UUID attemptId,
-                                                  final InternalCallContext context) {
+    public void updateStatusAndEffectiveDateForPaymentWithAttempt(final UUID paymentId,
+                                                                  final PaymentStatus paymentStatus,
+                                                                  final DateTime newEffectiveDate,
+                                                                  final UUID attemptId,
+                                                                  final String gatewayErrorCode,
+                                                                  final String gatewayErrorMsg,
+                                                                  final InternalCallContext context) {
         transactionalSqlDao.execute(new EntitySqlDaoTransactionWrapper<Void>() {
 
             @Override
             public Void inTransaction(final EntitySqlDaoWrapperFactory<EntitySqlDao> entitySqlDaoWrapperFactory) throws Exception {
-                entitySqlDaoWrapperFactory.become(PaymentSqlDao.class).updatePaymentStatus(paymentId.toString(), paymentStatus.toString(), context);
+                entitySqlDaoWrapperFactory.become(PaymentSqlDao.class).updatePaymentStatus(paymentId.toString(), paymentStatus.toString(), newEffectiveDate.toDate(), context);
                 entitySqlDaoWrapperFactory.become(PaymentAttemptSqlDao.class).updatePaymentAttemptStatus(attemptId.toString(), paymentStatus.toString(), gatewayErrorCode, gatewayErrorMsg, context);
                 return null;
             }
diff --git a/payment/src/main/java/com/ning/billing/payment/dao/PaymentDao.java b/payment/src/main/java/com/ning/billing/payment/dao/PaymentDao.java
index a5eaef5..304a03f 100644
--- a/payment/src/main/java/com/ning/billing/payment/dao/PaymentDao.java
+++ b/payment/src/main/java/com/ning/billing/payment/dao/PaymentDao.java
@@ -19,6 +19,8 @@ package com.ning.billing.payment.dao;
 import java.util.List;
 import java.util.UUID;
 
+import org.joda.time.DateTime;
+
 import com.ning.billing.payment.api.PaymentStatus;
 import com.ning.billing.payment.dao.RefundModelDao.RefundStatus;
 import com.ning.billing.util.callcontext.InternalCallContext;
@@ -31,9 +33,8 @@ public interface PaymentDao {
 
     public PaymentAttemptModelDao insertNewAttemptForPayment(UUID paymentId, PaymentAttemptModelDao attempt, InternalCallContext context);
 
-    public void updateStatusForPaymentWithAttempt(UUID paymentId, PaymentStatus paymentStatus, String gatewayErrorCode,
-                                                  String gatewayErrorMsg,
-                                                  UUID attemptId, InternalCallContext context);
+    public void updateStatusAndEffectiveDateForPaymentWithAttempt(UUID paymentId, PaymentStatus paymentStatus, DateTime newEffectiveDate,
+                                                                  UUID attemptId, String gatewayErrorMsg, String gatewayErrorCode, InternalCallContext context);
 
     public PaymentAttemptModelDao getPaymentAttempt(UUID attemptId, InternalTenantContext context);
 
diff --git a/payment/src/main/java/com/ning/billing/payment/dao/PaymentSqlDao.java b/payment/src/main/java/com/ning/billing/payment/dao/PaymentSqlDao.java
index 5b289ea..2033bc6 100644
--- a/payment/src/main/java/com/ning/billing/payment/dao/PaymentSqlDao.java
+++ b/payment/src/main/java/com/ning/billing/payment/dao/PaymentSqlDao.java
@@ -17,6 +17,7 @@
 package com.ning.billing.payment.dao;
 
 import java.math.BigDecimal;
+import java.util.Date;
 import java.util.List;
 
 import org.skife.jdbi.v2.sqlobject.Bind;
@@ -39,6 +40,7 @@ public interface PaymentSqlDao extends EntitySqlDao<PaymentModelDao, Payment> {
     @Audited(ChangeType.UPDATE)
     void updatePaymentStatus(@Bind("id") final String paymentId,
                              @Bind("paymentStatus") final String paymentStatus,
+                             @Bind("effectiveDate") final Date effectiveDate,
                              @BindBean final InternalCallContext context);
 
     @SqlUpdate
diff --git a/payment/src/main/java/com/ning/billing/payment/provider/DefaultNoOpPaymentInfoPlugin.java b/payment/src/main/java/com/ning/billing/payment/provider/DefaultNoOpPaymentInfoPlugin.java
index bf10051..6c52b9d 100644
--- a/payment/src/main/java/com/ning/billing/payment/provider/DefaultNoOpPaymentInfoPlugin.java
+++ b/payment/src/main/java/com/ning/billing/payment/provider/DefaultNoOpPaymentInfoPlugin.java
@@ -70,6 +70,16 @@ public class DefaultNoOpPaymentInfoPlugin implements PaymentInfoPlugin {
     }
 
     @Override
+    public String getFirstPaymentReferenceId() {
+        return null;
+    }
+
+    @Override
+    public String getSecondPaymentReferenceId() {
+        return null;
+    }
+
+    @Override
     public String toString() {
         final StringBuilder sb = new StringBuilder();
         sb.append("DefaultNoOpPaymentInfoPlugin");
diff --git a/payment/src/main/java/com/ning/billing/payment/provider/DefaultNoOpPaymentMethodPlugin.java b/payment/src/main/java/com/ning/billing/payment/provider/DefaultNoOpPaymentMethodPlugin.java
index a124373..9f135da 100644
--- a/payment/src/main/java/com/ning/billing/payment/provider/DefaultNoOpPaymentMethodPlugin.java
+++ b/payment/src/main/java/com/ning/billing/payment/provider/DefaultNoOpPaymentMethodPlugin.java
@@ -75,6 +75,66 @@ public class DefaultNoOpPaymentMethodPlugin implements PaymentMethodPlugin {
     }
 
     @Override
+    public String getType() {
+        return "noop";
+    }
+
+    @Override
+    public String getCCName() {
+        return null;
+    }
+
+    @Override
+    public String getCCType() {
+        return null;
+    }
+
+    @Override
+    public String getCCExprirationMonth() {
+        return null;
+    }
+
+    @Override
+    public String getCCExprirationYear() {
+        return null;
+    }
+
+    @Override
+    public String getCCLast4() {
+        return null;
+    }
+
+    @Override
+    public String getAddress1() {
+        return null;
+    }
+
+    @Override
+    public String getAddress2() {
+        return null;
+    }
+
+    @Override
+    public String getCity() {
+        return null;
+    }
+
+    @Override
+    public String getState() {
+        return null;
+    }
+
+    @Override
+    public String getZip() {
+        return null;
+    }
+
+    @Override
+    public String getCountry() {
+        return null;
+    }
+
+    @Override
     public String toString() {
         final StringBuilder sb = new StringBuilder();
         sb.append("DefaultNoOpPaymentMethodPlugin");
diff --git a/payment/src/main/java/com/ning/billing/payment/provider/DefaultNoOpPaymentProviderPlugin.java b/payment/src/main/java/com/ning/billing/payment/provider/DefaultNoOpPaymentProviderPlugin.java
index bc046b0..51fa4b2 100644
--- a/payment/src/main/java/com/ning/billing/payment/provider/DefaultNoOpPaymentProviderPlugin.java
+++ b/payment/src/main/java/com/ning/billing/payment/provider/DefaultNoOpPaymentProviderPlugin.java
@@ -37,6 +37,7 @@ import com.ning.billing.util.callcontext.CallContext;
 import com.ning.billing.util.callcontext.TenantContext;
 import com.ning.billing.util.clock.Clock;
 
+import com.google.common.collect.ImmutableList;
 import com.google.common.collect.LinkedListMultimap;
 import com.google.common.collect.Multimap;
 import com.google.inject.Inject;
@@ -178,4 +179,9 @@ public class DefaultNoOpPaymentProviderPlugin implements NoOpPaymentPluginApi {
 
         return refundInfoPlugin;
     }
+
+    @Override
+    public List<RefundInfoPlugin> getRefundInfo(final UUID kbAccountId, final UUID kbPaymentId, final TenantContext context) {
+        return ImmutableList.<RefundInfoPlugin>copyOf(refunds.get(kbPaymentId.toString()));
+    }
 }
diff --git a/payment/src/main/java/com/ning/billing/payment/provider/DefaultNoOpRefundInfoPlugin.java b/payment/src/main/java/com/ning/billing/payment/provider/DefaultNoOpRefundInfoPlugin.java
index d9b9805..0be96d2 100644
--- a/payment/src/main/java/com/ning/billing/payment/provider/DefaultNoOpRefundInfoPlugin.java
+++ b/payment/src/main/java/com/ning/billing/payment/provider/DefaultNoOpRefundInfoPlugin.java
@@ -70,6 +70,11 @@ public class DefaultNoOpRefundInfoPlugin implements RefundInfoPlugin {
     }
 
     @Override
+    public String getReferenceId() {
+        return null;
+    }
+
+    @Override
     public String toString() {
         final StringBuilder sb = new StringBuilder();
         sb.append("DefaultNoOpRefundInfoPlugin");
diff --git a/payment/src/main/resources/com/ning/billing/payment/dao/PaymentSqlDao.sql.stg b/payment/src/main/resources/com/ning/billing/payment/dao/PaymentSqlDao.sql.stg
index 15c9203..b7bc670 100644
--- a/payment/src/main/resources/com/ning/billing/payment/dao/PaymentSqlDao.sql.stg
+++ b/payment/src/main/resources/com/ning/billing/payment/dao/PaymentSqlDao.sql.stg
@@ -71,7 +71,8 @@ order by effective_date desc limit 1
 
 updatePaymentStatus() ::= <<
 update payments
-set payment_status = :paymentStatus
+set payment_status = :paymentStatus,
+effective_date = :effectiveDate
 where id = :id
 <AND_CHECK_TENANT()>
 ;
diff --git a/payment/src/test/java/com/ning/billing/payment/dao/MockPaymentDao.java b/payment/src/test/java/com/ning/billing/payment/dao/MockPaymentDao.java
index 7a51f36..8eba46f 100644
--- a/payment/src/test/java/com/ning/billing/payment/dao/MockPaymentDao.java
+++ b/payment/src/test/java/com/ning/billing/payment/dao/MockPaymentDao.java
@@ -25,6 +25,8 @@ import java.util.List;
 import java.util.Map;
 import java.util.UUID;
 
+import org.joda.time.DateTime;
+
 import com.ning.billing.payment.api.PaymentStatus;
 import com.ning.billing.payment.dao.RefundModelDao.RefundStatus;
 import com.ning.billing.util.callcontext.InternalCallContext;
@@ -56,9 +58,9 @@ public class MockPaymentDao implements PaymentDao {
     }
 
     @Override
-    public void updateStatusForPaymentWithAttempt(final UUID paymentId, final PaymentStatus paymentStatus, final String gatewayErrorCode,
-                                                  final String gatewayErrorMsg,
-                                                  final UUID attemptId, final InternalCallContext context) {
+    public void updateStatusAndEffectiveDateForPaymentWithAttempt(final UUID paymentId, final PaymentStatus paymentStatus, final DateTime effectibeDate,  final UUID attemptId, final String gatewayErrorCode,
+                                                                  final String gatewayErrorMsg,
+                                                                  final InternalCallContext context) {
         synchronized (this) {
             final PaymentModelDao entry = payments.remove(paymentId);
             if (entry != null) {
diff --git a/payment/src/test/java/com/ning/billing/payment/dao/TestPaymentDao.java b/payment/src/test/java/com/ning/billing/payment/dao/TestPaymentDao.java
index a17fcac..0557324 100644
--- a/payment/src/test/java/com/ning/billing/payment/dao/TestPaymentDao.java
+++ b/payment/src/test/java/com/ning/billing/payment/dao/TestPaymentDao.java
@@ -25,6 +25,7 @@ import org.joda.time.DateTime;
 import org.testng.annotations.Test;
 
 import com.ning.billing.catalog.api.Currency;
+import com.ning.billing.catalog.api.Duration;
 import com.ning.billing.payment.PaymentTestSuiteWithEmbeddedDB;
 import com.ning.billing.payment.api.PaymentStatus;
 import com.ning.billing.payment.dao.RefundModelDao.RefundStatus;
@@ -95,11 +96,14 @@ public class TestPaymentDao extends PaymentTestSuiteWithEmbeddedDB {
         final PaymentModelDao payment = new PaymentModelDao(accountId, invoiceId, paymentMethodId, amount, currency, effectiveDate);
         final PaymentAttemptModelDao attempt = new PaymentAttemptModelDao(accountId, invoiceId, payment.getId(), clock.getUTCNow(), amount);
         PaymentModelDao savedPayment = paymentDao.insertPaymentWithAttempt(payment, attempt, internalCallContext);
+        assertEquals(savedPayment.getEffectiveDate().compareTo(effectiveDate), 0);
 
         final PaymentStatus paymentStatus = PaymentStatus.SUCCESS;
         final String gatewayErrorCode = "OK";
 
-        paymentDao.updateStatusForPaymentWithAttempt(payment.getId(), paymentStatus, gatewayErrorCode, null, attempt.getId(), internalCallContext);
+        clock.addDays(1);
+        final DateTime newEffectiveDate = clock.getUTCNow();
+        paymentDao.updateStatusAndEffectiveDateForPaymentWithAttempt(payment.getId(), paymentStatus, newEffectiveDate, attempt.getId(), gatewayErrorCode, null,  internalCallContext);
 
         final List<PaymentModelDao> payments = paymentDao.getPaymentsForInvoice(invoiceId, internalCallContext);
         assertEquals(payments.size(), 1);
@@ -110,7 +114,7 @@ public class TestPaymentDao extends PaymentTestSuiteWithEmbeddedDB {
         assertEquals(savedPayment.getPaymentMethodId(), paymentMethodId);
         assertEquals(savedPayment.getAmount().compareTo(amount), 0);
         assertEquals(savedPayment.getCurrency(), currency);
-        assertEquals(savedPayment.getEffectiveDate().compareTo(effectiveDate), 0);
+        assertEquals(savedPayment.getEffectiveDate().compareTo(newEffectiveDate), 0);
         assertEquals(savedPayment.getPaymentStatus(), PaymentStatus.SUCCESS);
 
         final List<PaymentAttemptModelDao> attempts = paymentDao.getAttemptsForPayment(payment.getId(), internalCallContext);
diff --git a/payment/src/test/java/com/ning/billing/payment/MockInvoice.java b/payment/src/test/java/com/ning/billing/payment/MockInvoice.java
index 2173e16..38dbecb 100644
--- a/payment/src/test/java/com/ning/billing/payment/MockInvoice.java
+++ b/payment/src/test/java/com/ning/billing/payment/MockInvoice.java
@@ -162,6 +162,7 @@ public class MockInvoice extends EntityBase implements Invoice {
         return amountPaid;
     }
 
+
     @Override
     public BigDecimal getChargedAmount() {
         BigDecimal result = BigDecimal.ZERO;
@@ -174,6 +175,7 @@ public class MockInvoice extends EntityBase implements Invoice {
         return result;
     }
 
+
     @Override
     public BigDecimal getCreditAdjAmount() {
         BigDecimal result = BigDecimal.ZERO;
@@ -198,17 +200,22 @@ public class MockInvoice extends EntityBase implements Invoice {
 
     @Override
     public BigDecimal getCBAAmount() {
-        return null;
+        throw new UnsupportedOperationException();
     }
 
     @Override
     public BigDecimal getTotalAdjAmount() {
-        return null;
+        throw new UnsupportedOperationException();
     }
 
     @Override
     public BigDecimal getRefundAdjAmount() {
-        return null;
+        throw new UnsupportedOperationException();
+    }
+
+    @Override
+    public BigDecimal getOriginalChargedAmount() {
+        throw new UnsupportedOperationException();
     }
 }
 
diff --git a/payment/src/test/java/com/ning/billing/payment/provider/MockPaymentProviderPlugin.java b/payment/src/test/java/com/ning/billing/payment/provider/MockPaymentProviderPlugin.java
index 33497c4..64f8a47 100644
--- a/payment/src/test/java/com/ning/billing/payment/provider/MockPaymentProviderPlugin.java
+++ b/payment/src/test/java/com/ning/billing/payment/provider/MockPaymentProviderPlugin.java
@@ -17,6 +17,7 @@
 package com.ning.billing.payment.provider;
 
 import java.math.BigDecimal;
+import java.util.Collections;
 import java.util.List;
 import java.util.Map;
 import java.util.UUID;
@@ -24,7 +25,7 @@ import java.util.concurrent.ConcurrentHashMap;
 import java.util.concurrent.atomic.AtomicBoolean;
 
 import com.ning.billing.catalog.api.Currency;
-import com.ning.billing.payment.api.DefaultPaymentMethodPlugin;
+import com.ning.billing.payment.api.TestPaymentMethodPlugin;
 import com.ning.billing.payment.api.PaymentMethodPlugin;
 import com.ning.billing.payment.plugin.api.NoOpPaymentPluginApi;
 import com.ning.billing.payment.plugin.api.PaymentInfoPlugin;
@@ -115,7 +116,7 @@ public class MockPaymentProviderPlugin implements NoOpPaymentPluginApi {
     @Override
     public void addPaymentMethod(final UUID kbAccountId, final UUID kbPaymentMethodId, final PaymentMethodPlugin paymentMethodProps, final boolean setDefault, final CallContext context) throws PaymentPluginApiException {
         // externalPaymentMethodId is set to a random value
-        final PaymentMethodPlugin realWithID = new DefaultPaymentMethodPlugin(paymentMethodProps, UUID.randomUUID().toString());
+        final PaymentMethodPlugin realWithID = new TestPaymentMethodPlugin(paymentMethodProps, UUID.randomUUID().toString());
         paymentMethods.put(kbPaymentMethodId.toString(), realWithID);
 
         final PaymentMethodInfoPlugin realInfoWithID = new DefaultPaymentMethodInfoPlugin(kbAccountId, kbPaymentMethodId, setDefault, UUID.randomUUID().toString());
@@ -173,4 +174,9 @@ public class MockPaymentProviderPlugin implements NoOpPaymentPluginApi {
 
         return refundInfoPlugin;
     }
+
+    @Override
+    public List<RefundInfoPlugin> getRefundInfo(final UUID kbAccountId, final UUID kbPaymentId, final TenantContext context) throws PaymentPluginApiException {
+        return Collections.<RefundInfoPlugin>emptyList();
+    }
 }

pom.xml 2(+1 -1)

diff --git a/pom.xml b/pom.xml
index 6a24b00..41f2baa 100644
--- a/pom.xml
+++ b/pom.xml
@@ -24,7 +24,7 @@
     <groupId>com.ning.billing</groupId>
     <artifactId>killbill</artifactId>
     <packaging>pom</packaging>
-    <version>0.1.62-SNAPSHOT</version>
+    <version>0.1.64-SNAPSHOT</version>
     <name>killbill</name>
     <description>Library for managing recurring subscriptions and the associated billing</description>
     <url>http://github.com/killbill/killbill</url>

server/pom.xml 2(+1 -1)

diff --git a/server/pom.xml b/server/pom.xml
index b3fc5f7..efa31c7 100644
--- a/server/pom.xml
+++ b/server/pom.xml
@@ -20,7 +20,7 @@
     <parent>
         <groupId>com.ning.billing</groupId>
         <artifactId>killbill</artifactId>
-        <version>0.1.62-SNAPSHOT</version>
+        <version>0.1.64-SNAPSHOT</version>
         <relativePath>../pom.xml</relativePath>
     </parent>
     <artifactId>killbill-server</artifactId>
diff --git a/server/src/main/java/com/ning/billing/server/modules/KillbillServerModule.java b/server/src/main/java/com/ning/billing/server/modules/KillbillServerModule.java
index e6ff204..7690c01 100644
--- a/server/src/main/java/com/ning/billing/server/modules/KillbillServerModule.java
+++ b/server/src/main/java/com/ning/billing/server/modules/KillbillServerModule.java
@@ -60,6 +60,7 @@ import com.ning.billing.util.glue.ExportModule;
 import com.ning.billing.util.glue.GlobalLockerModule;
 import com.ning.billing.util.glue.NonEntityDaoModule;
 import com.ning.billing.util.glue.NotificationQueueModule;
+import com.ning.billing.util.glue.RecordIdModule;
 import com.ning.billing.util.glue.TagStoreModule;
 
 import com.google.inject.AbstractModule;
@@ -135,6 +136,7 @@ public class KillbillServerModule extends AbstractModule {
         install(new NonEntityDaoModule());
         install(new DefaultOSGIModule(configSource));
         install(new UsageModule(configSource));
+        install(new RecordIdModule());
 
         installClock();
     }
diff --git a/server/src/test/java/com/ning/billing/jaxrs/TestJaxrsBase.java b/server/src/test/java/com/ning/billing/jaxrs/TestJaxrsBase.java
index 421caef..b2882cf 100644
--- a/server/src/test/java/com/ning/billing/jaxrs/TestJaxrsBase.java
+++ b/server/src/test/java/com/ning/billing/jaxrs/TestJaxrsBase.java
@@ -70,6 +70,7 @@ import com.ning.billing.util.glue.CustomFieldModule;
 import com.ning.billing.util.glue.ExportModule;
 import com.ning.billing.util.glue.NonEntityDaoModule;
 import com.ning.billing.util.glue.NotificationQueueModule;
+import com.ning.billing.util.glue.RecordIdModule;
 import com.ning.billing.util.glue.TagStoreModule;
 import com.ning.http.client.AsyncHttpClient;
 import com.ning.http.client.AsyncHttpClientConfig;
@@ -206,6 +207,7 @@ public class TestJaxrsBase extends KillbillClient {
             install(new ExportModule());
             install(new DefaultOSGIModule(configSource));
             install(new UsageModule(configSource));
+            install(new RecordIdModule());
             installClock();
         }
     }

tenant/pom.xml 2(+1 -1)

diff --git a/tenant/pom.xml b/tenant/pom.xml
index 412dca9..e1c8645 100644
--- a/tenant/pom.xml
+++ b/tenant/pom.xml
@@ -20,7 +20,7 @@
     <parent>
         <groupId>com.ning.billing</groupId>
         <artifactId>killbill</artifactId>
-        <version>0.1.62-SNAPSHOT</version>
+        <version>0.1.64-SNAPSHOT</version>
         <relativePath>../pom.xml</relativePath>
     </parent>
     <artifactId>killbill-tenant</artifactId>

usage/pom.xml 2(+1 -1)

diff --git a/usage/pom.xml b/usage/pom.xml
index 2325d8d..98616da 100644
--- a/usage/pom.xml
+++ b/usage/pom.xml
@@ -20,7 +20,7 @@
     <parent>
         <groupId>com.ning.billing</groupId>
         <artifactId>killbill</artifactId>
-        <version>0.1.62-SNAPSHOT</version>
+        <version>0.1.64-SNAPSHOT</version>
         <relativePath>../pom.xml</relativePath>
     </parent>
     <artifactId>killbill-usage</artifactId>

util/pom.xml 2(+1 -1)

diff --git a/util/pom.xml b/util/pom.xml
index bb1d0e0..f9adf2f 100644
--- a/util/pom.xml
+++ b/util/pom.xml
@@ -13,7 +13,7 @@
     <parent>
         <groupId>com.ning.billing</groupId>
         <artifactId>killbill</artifactId>
-        <version>0.1.62-SNAPSHOT</version>
+        <version>0.1.64-SNAPSHOT</version>
         <relativePath>../pom.xml</relativePath>
     </parent>
     <artifactId>killbill-util</artifactId>
diff --git a/util/src/main/java/com/ning/billing/util/callcontext/InternalCallContextFactory.java b/util/src/main/java/com/ning/billing/util/callcontext/InternalCallContextFactory.java
index 5a61f63..450d29b 100644
--- a/util/src/main/java/com/ning/billing/util/callcontext/InternalCallContextFactory.java
+++ b/util/src/main/java/com/ning/billing/util/callcontext/InternalCallContextFactory.java
@@ -73,14 +73,22 @@ public class InternalCallContextFactory {
         return new InternalTenantContext(tenantRecordId, accountRecordId);
     }
 
-    /**
-     * Crate an internal call context from a call context, and retrieving the account_record_id from another table
-     *
-     * @param objectId   the id of the row in the table pointed by object type where to look for account_record_id
-     * @param objectType the object type pointed by this objectId
-     * @param context    original call context
-     * @return internal call context from context, with a non null account_record_id (if found)
-     */
+    public InternalTenantContext createInternalTenantContext(final UUID accountId, final TenantContext context) {
+        final Long tenantRecordId = getTenantRecordId(context);
+        final Long accountRecordId = nonEntityDao.retrieveAccountRecordIdFromObject(accountId, ObjectType.ACCOUNT, cacheControllerDispatcher.getCacheController(CacheType.ACCOUNT_RECORD_ID));
+        return new InternalTenantContext(tenantRecordId, accountRecordId);
+    }
+
+
+
+        /**
+         * Crate an internal call context from a call context, and retrieving the account_record_id from another table
+         *
+         * @param objectId   the id of the row in the table pointed by object type where to look for account_record_id
+         * @param objectType the object type pointed by this objectId
+         * @param context    original call context
+         * @return internal call context from context, with a non null account_record_id (if found)
+         */
     public InternalCallContext createInternalCallContext(final UUID objectId, final ObjectType objectType, final CallContext context) {
         // The context may come from a user API - for security, check we're not doing cross-tenants operations
         //final Long tenantRecordIdFromObject = retrieveTenantRecordIdFromObject(objectId, objectType);
@@ -194,6 +202,8 @@ public class InternalCallContextFactory {
         return new InternalCallContext(tenantRecordId, null, context);
     }
 
+
+
     // Used when we need to re-hydrate the context with the account_record_id (when creating the account)
     public InternalCallContext createInternalCallContext(final Long accountRecordId, final InternalCallContext context) {
         return new InternalCallContext(context.getTenantRecordId(), accountRecordId, context.getUserToken(), context.getCreatedBy(),
diff --git a/util/src/main/java/com/ning/billing/util/customfield/api/DefaultCustomFieldCreationEvent.java b/util/src/main/java/com/ning/billing/util/customfield/api/DefaultCustomFieldCreationEvent.java
new file mode 100644
index 0000000..fe085d6
--- /dev/null
+++ b/util/src/main/java/com/ning/billing/util/customfield/api/DefaultCustomFieldCreationEvent.java
@@ -0,0 +1,100 @@
+/*
+ * 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.util.customfield.api;
+
+import java.util.UUID;
+
+import com.ning.billing.ObjectType;
+import com.ning.billing.util.events.CustomFieldCreationEvent;
+import com.ning.billing.util.events.DefaultBusInternalEvent;
+import com.ning.billing.util.tag.TagDefinition;
+
+import com.fasterxml.jackson.annotation.JsonCreator;
+import com.fasterxml.jackson.annotation.JsonIgnore;
+import com.fasterxml.jackson.annotation.JsonProperty;
+
+public class DefaultCustomFieldCreationEvent extends DefaultBusInternalEvent implements CustomFieldCreationEvent {
+
+    private final UUID customFieldId;
+    private final UUID objectId;
+    private final ObjectType objectType;
+
+    @JsonCreator
+    public DefaultCustomFieldCreationEvent(@JsonProperty("customFieldId") final UUID customFieldId,
+                                       @JsonProperty("objectId") final UUID objectId,
+                                       @JsonProperty("objectType") final ObjectType objectType,
+                                       @JsonProperty("userToken") final UUID userToken,
+                                       @JsonProperty("accountRecordId") final Long accountRecordId,
+                                       @JsonProperty("tenantRecordId") final Long tenantRecordId) {
+        super(userToken, accountRecordId, tenantRecordId);
+        this.customFieldId = customFieldId;
+        this.objectId = objectId;
+        this.objectType = objectType;
+    }
+
+    @Override
+    public UUID getCustomFieldId() {
+        return customFieldId;
+    }
+
+    @Override
+    public UUID getObjectId() {
+        return objectId;
+    }
+
+    @Override
+    public ObjectType getObjectType() {
+        return objectType;
+    }
+
+    @JsonIgnore
+    @Override
+    public BusInternalEventType getBusEventType() {
+        return BusInternalEventType.CUSTOM_FIELD_CREATION;
+    }
+
+    @Override
+    public boolean equals(final Object o) {
+        if (this == o) {
+            return true;
+        }
+        if (!(o instanceof DefaultCustomFieldCreationEvent)) {
+            return false;
+        }
+
+        final DefaultCustomFieldCreationEvent that = (DefaultCustomFieldCreationEvent) o;
+
+        if (customFieldId != null ? !customFieldId.equals(that.customFieldId) : that.customFieldId != null) {
+            return false;
+        }
+        if (objectId != null ? !objectId.equals(that.objectId) : that.objectId != null) {
+            return false;
+        }
+        if (objectType != that.objectType) {
+            return false;
+        }
+        return true;
+    }
+
+    @Override
+    public int hashCode() {
+        int result = customFieldId != null ? customFieldId.hashCode() : 0;
+        result = 31 * result + (objectId != null ? objectId.hashCode() : 0);
+        result = 31 * result + (objectType != null ? objectType.hashCode() : 0);
+        return result;
+    }
+}
diff --git a/util/src/main/java/com/ning/billing/util/customfield/api/DefaultCustomFieldDeletionEvent.java b/util/src/main/java/com/ning/billing/util/customfield/api/DefaultCustomFieldDeletionEvent.java
new file mode 100644
index 0000000..b17adb4
--- /dev/null
+++ b/util/src/main/java/com/ning/billing/util/customfield/api/DefaultCustomFieldDeletionEvent.java
@@ -0,0 +1,100 @@
+/*
+ * 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.util.customfield.api;
+
+import java.util.UUID;
+
+import com.ning.billing.ObjectType;
+import com.ning.billing.util.events.CustomFieldDeletionEvent;
+import com.ning.billing.util.events.DefaultBusInternalEvent;
+
+import com.fasterxml.jackson.annotation.JsonCreator;
+import com.fasterxml.jackson.annotation.JsonIgnore;
+import com.fasterxml.jackson.annotation.JsonProperty;
+
+public class DefaultCustomFieldDeletionEvent extends DefaultBusInternalEvent implements CustomFieldDeletionEvent {
+
+    private final UUID customFieldId;
+    private final UUID objectId;
+    private final ObjectType objectType;
+
+    @JsonCreator
+    public DefaultCustomFieldDeletionEvent(@JsonProperty("customFieldId") final UUID customFieldId,
+                                           @JsonProperty("objectId") final UUID objectId,
+                                           @JsonProperty("objectType") final ObjectType objectType,
+                                           @JsonProperty("userToken") final UUID userToken,
+                                           @JsonProperty("accountRecordId") final Long accountRecordId,
+                                           @JsonProperty("tenantRecordId") final Long tenantRecordId) {
+        super(userToken, accountRecordId, tenantRecordId);
+        this.customFieldId = customFieldId;
+        this.objectId = objectId;
+        this.objectType = objectType;
+    }
+
+    @Override
+    public UUID getCustomFieldId() {
+        return customFieldId;
+    }
+
+    @Override
+    public UUID getObjectId() {
+        return objectId;
+    }
+
+    @Override
+    public ObjectType getObjectType() {
+        return objectType;
+    }
+
+    @JsonIgnore
+    @Override
+    public BusInternalEventType getBusEventType() {
+        return BusInternalEventType.CUSTOM_FIELD_DELETION;
+    }
+
+    @Override
+    public boolean equals(final Object o) {
+        if (this == o) {
+            return true;
+        }
+        if (!(o instanceof DefaultCustomFieldDeletionEvent)) {
+            return false;
+        }
+
+        final DefaultCustomFieldDeletionEvent that = (DefaultCustomFieldDeletionEvent) o;
+
+        if (customFieldId != null ? !customFieldId.equals(that.customFieldId) : that.customFieldId != null) {
+            return false;
+        }
+        if (objectId != null ? !objectId.equals(that.objectId) : that.objectId != null) {
+            return false;
+        }
+        if (objectType != that.objectType) {
+            return false;
+        }
+
+        return true;
+    }
+
+    @Override
+    public int hashCode() {
+        int result = customFieldId != null ? customFieldId.hashCode() : 0;
+        result = 31 * result + (objectId != null ? objectId.hashCode() : 0);
+        result = 31 * result + (objectType != null ? objectType.hashCode() : 0);
+        return result;
+    }
+}
diff --git a/util/src/main/java/com/ning/billing/util/customfield/api/DefaultCustomFieldUserApi.java b/util/src/main/java/com/ning/billing/util/customfield/api/DefaultCustomFieldUserApi.java
index b1f0a38..e0e543d 100644
--- a/util/src/main/java/com/ning/billing/util/customfield/api/DefaultCustomFieldUserApi.java
+++ b/util/src/main/java/com/ning/billing/util/customfield/api/DefaultCustomFieldUserApi.java
@@ -47,21 +47,35 @@ public class DefaultCustomFieldUserApi implements CustomFieldUserApi {
     }
 
     @Override
-    public List<CustomField> getCustomFields(final UUID objectId, final ObjectType objectType, final TenantContext context) {
-        return ImmutableList.<CustomField>copyOf(Collections2.transform(customFieldDao.getCustomFields(objectId, objectType, internalCallContextFactory.createInternalTenantContext(context)),
-                                                                        new Function<CustomFieldModelDao, CustomField>() {
-                                                                            @Override
-                                                                            public CustomField apply(final CustomFieldModelDao input) {
-                                                                                return new StringCustomField(input);
-                                                                            }
-                                                                        }));
-    }
-
-    @Override
     public void addCustomFields(final List<CustomField> fields, final CallContext context) throws CustomFieldApiException {
         // TODO make it transactional
         for (final CustomField cur : fields) {
             customFieldDao.create(new CustomFieldModelDao(cur), internalCallContextFactory.createInternalCallContext(cur.getObjectId(), cur.getObjectType(), context));
         }
     }
+
+    @Override
+    public List<CustomField> getCustomFieldsForObject(final UUID objectId, final ObjectType objectType, final TenantContext context) {
+        return withCustomFieldsTransform(customFieldDao.getCustomFieldsForObject(objectId, objectType, internalCallContextFactory.createInternalTenantContext(context)));
+    }
+
+    @Override
+    public List<CustomField> getCustomFieldsForAccountType(final UUID accountId, final ObjectType objectType, final TenantContext context) {
+        return withCustomFieldsTransform(customFieldDao.getCustomFieldsForAccountType(objectType, internalCallContextFactory.createInternalTenantContext(accountId, context)));
+    }
+
+    @Override
+    public List<CustomField> getCustomFieldsForAccount(final UUID accountId, final TenantContext context) {
+        return withCustomFieldsTransform(customFieldDao.getCustomFieldsForAccount(internalCallContextFactory.createInternalTenantContext(accountId, context)));
+    }
+
+    private List<CustomField> withCustomFieldsTransform(List<CustomFieldModelDao> input) {
+        return ImmutableList.<CustomField>copyOf(Collections2.transform(input, new Function<CustomFieldModelDao, CustomField>() {
+            @Override
+            public CustomField apply(final CustomFieldModelDao input) {
+                return new StringCustomField(input);
+            }
+        }));
+    }
+
 }
diff --git a/util/src/main/java/com/ning/billing/util/customfield/dao/CustomFieldDao.java b/util/src/main/java/com/ning/billing/util/customfield/dao/CustomFieldDao.java
index ead8b57..6b9e9e0 100644
--- a/util/src/main/java/com/ning/billing/util/customfield/dao/CustomFieldDao.java
+++ b/util/src/main/java/com/ning/billing/util/customfield/dao/CustomFieldDao.java
@@ -22,10 +22,16 @@ import java.util.UUID;
 import com.ning.billing.ObjectType;
 import com.ning.billing.util.api.CustomFieldApiException;
 import com.ning.billing.util.callcontext.InternalTenantContext;
+import com.ning.billing.util.callcontext.TenantContext;
 import com.ning.billing.util.customfield.CustomField;
 import com.ning.billing.util.entity.dao.EntityDao;
 
 public interface CustomFieldDao extends EntityDao<CustomFieldModelDao, CustomField, CustomFieldApiException> {
 
-    public List<CustomFieldModelDao> getCustomFields(final UUID objectId, final ObjectType objectType, final InternalTenantContext context);
+    public List<CustomFieldModelDao> getCustomFieldsForObject(final UUID objectId, final ObjectType objectType, final InternalTenantContext context);
+
+    public List<CustomFieldModelDao> getCustomFieldsForAccountType(final ObjectType objectType, final InternalTenantContext context);
+
+    public List<CustomFieldModelDao> getCustomFieldsForAccount(final InternalTenantContext context);
+
 }
diff --git a/util/src/main/java/com/ning/billing/util/customfield/dao/DefaultCustomFieldDao.java b/util/src/main/java/com/ning/billing/util/customfield/dao/DefaultCustomFieldDao.java
index 7f19fb0..61f6f03 100644
--- a/util/src/main/java/com/ning/billing/util/customfield/dao/DefaultCustomFieldDao.java
+++ b/util/src/main/java/com/ning/billing/util/customfield/dao/DefaultCustomFieldDao.java
@@ -19,34 +19,53 @@ package com.ning.billing.util.customfield.dao;
 import java.util.List;
 import java.util.UUID;
 
+import javax.annotation.Nullable;
+
 import org.skife.jdbi.v2.IDBI;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
 
+import com.ning.billing.BillingExceptionBase;
 import com.ning.billing.ErrorCode;
 import com.ning.billing.ObjectType;
 import com.ning.billing.util.api.CustomFieldApiException;
+import com.ning.billing.util.audit.ChangeType;
 import com.ning.billing.util.cache.CacheControllerDispatcher;
 import com.ning.billing.util.callcontext.InternalCallContext;
 import com.ning.billing.util.callcontext.InternalTenantContext;
 import com.ning.billing.util.clock.Clock;
 import com.ning.billing.util.customfield.CustomField;
+import com.ning.billing.util.customfield.api.DefaultCustomFieldCreationEvent;
+import com.ning.billing.util.customfield.api.DefaultCustomFieldDeletionEvent;
 import com.ning.billing.util.dao.NonEntityDao;
 import com.ning.billing.util.entity.dao.EntityDaoBase;
 import com.ning.billing.util.entity.dao.EntitySqlDao;
 import com.ning.billing.util.entity.dao.EntitySqlDaoTransactionWrapper;
 import com.ning.billing.util.entity.dao.EntitySqlDaoTransactionalJdbiWrapper;
 import com.ning.billing.util.entity.dao.EntitySqlDaoWrapperFactory;
+import com.ning.billing.util.events.BusInternalEvent;
+import com.ning.billing.util.svcsapi.bus.InternalBus;
+import com.ning.billing.util.tag.dao.TagModelDao;
 
+import com.google.common.base.Predicate;
+import com.google.common.collect.Collections2;
+import com.google.common.collect.ImmutableList;
 import com.google.inject.Inject;
 
 public class DefaultCustomFieldDao extends EntityDaoBase<CustomFieldModelDao, CustomField, CustomFieldApiException> implements CustomFieldDao {
 
+    private final static Logger log = LoggerFactory.getLogger(DefaultCustomFieldDao.class);
+
+    private final InternalBus bus;
+
     @Inject
-    public DefaultCustomFieldDao(final IDBI dbi, final Clock clock, final CacheControllerDispatcher controllerDispatcher, final NonEntityDao nonEntityDao) {
+    public DefaultCustomFieldDao(final IDBI dbi, final Clock clock, final CacheControllerDispatcher controllerDispatcher, final NonEntityDao nonEntityDao, final InternalBus bus) {
         super(new EntitySqlDaoTransactionalJdbiWrapper(dbi, clock, controllerDispatcher, nonEntityDao), CustomFieldSqlDao.class);
+        this.bus = bus;
     }
 
     @Override
-    public List<CustomFieldModelDao> getCustomFields(final UUID objectId, final ObjectType objectType, final InternalTenantContext context) {
+    public List<CustomFieldModelDao> getCustomFieldsForObject(final UUID objectId, final ObjectType objectType, final InternalTenantContext context) {
         return transactionalSqlDao.execute(new EntitySqlDaoTransactionWrapper<List<CustomFieldModelDao>>() {
             @Override
             public List<CustomFieldModelDao> inTransaction(final EntitySqlDaoWrapperFactory<EntitySqlDao> entitySqlDaoWrapperFactory) throws Exception {
@@ -56,7 +75,56 @@ public class DefaultCustomFieldDao extends EntityDaoBase<CustomFieldModelDao, Cu
     }
 
     @Override
+    public List<CustomFieldModelDao> getCustomFieldsForAccountType(final ObjectType objectType, final InternalTenantContext context) {
+        final List<CustomFieldModelDao> allFields = getCustomFieldsForAccount(context);
+
+        return ImmutableList.<CustomFieldModelDao>copyOf(Collections2.filter(allFields, new Predicate<CustomFieldModelDao>() {
+            @Override
+            public boolean apply(@Nullable final CustomFieldModelDao input) {
+                return input.getObjectType() == objectType;
+            }
+        }));
+    }
+
+    @Override
+    public List<CustomFieldModelDao> getCustomFieldsForAccount(final InternalTenantContext context) {
+        return transactionalSqlDao.execute(new EntitySqlDaoTransactionWrapper<List<CustomFieldModelDao>>() {
+            @Override
+            public List<CustomFieldModelDao> inTransaction(final EntitySqlDaoWrapperFactory<EntitySqlDao> entitySqlDaoWrapperFactory) throws Exception {
+                return entitySqlDaoWrapperFactory.become(CustomFieldSqlDao.class).getByAccountRecordId(context);
+            }
+        });
+    }
+
+    @Override
     protected CustomFieldApiException generateAlreadyExistsException(final CustomFieldModelDao entity, final InternalCallContext context) {
         return new CustomFieldApiException(ErrorCode.CUSTOM_FIELD_ALREADY_EXISTS, entity.getId());
     }
+
+    @Override
+    protected void postBusEventFromTransaction(final CustomFieldModelDao customField, final CustomFieldModelDao savedCustomField, final ChangeType changeType,
+                                               final EntitySqlDaoWrapperFactory<EntitySqlDao> entitySqlDaoWrapperFactory, final InternalCallContext context)
+            throws BillingExceptionBase {
+
+        BusInternalEvent customFieldEvent = null;
+        switch(changeType) {
+            case INSERT:
+                customFieldEvent = new DefaultCustomFieldCreationEvent(customField.getId(), customField.getObjectId(), customField.getObjectType(), context.getUserToken(), context.getAccountRecordId(), context.getTenantRecordId());
+                break;
+            case DELETE:
+                customFieldEvent = new DefaultCustomFieldDeletionEvent(customField.getId(), customField.getObjectId(), customField.getObjectType(), context.getUserToken(), context.getAccountRecordId(), context.getTenantRecordId());
+
+                break;
+            default:
+                return;
+        }
+
+        try {
+            bus.postFromTransaction(customFieldEvent, entitySqlDaoWrapperFactory, context);
+        } catch (InternalBus.EventBusException e) {
+            log.warn("Failed to post tag event for custom field " + customField.getId().toString(), e);
+        }
+
+    }
+
 }
diff --git a/util/src/main/java/com/ning/billing/util/entity/dao/EntitySqlDao.java b/util/src/main/java/com/ning/billing/util/entity/dao/EntitySqlDao.java
index 418dbee..25f8e6c 100644
--- a/util/src/main/java/com/ning/billing/util/entity/dao/EntitySqlDao.java
+++ b/util/src/main/java/com/ning/billing/util/entity/dao/EntitySqlDao.java
@@ -56,6 +56,10 @@ public interface EntitySqlDao<M extends EntityModelDao<E>, E extends Entity> ext
                            @BindBean final InternalTenantContext context);
 
     @SqlQuery
+    public List<M> getByAccountRecordId(@BindBean final InternalTenantContext context);
+
+
+    @SqlQuery
     @Cachable(CacheType.RECORD_ID)
     public Long getRecordId(@Bind("id") final String id,
                             @BindBean final InternalTenantContext context);
diff --git a/util/src/main/java/com/ning/billing/util/events/BusInternalEvent.java b/util/src/main/java/com/ning/billing/util/events/BusInternalEvent.java
index c4b2d4a..0b64bf4 100644
--- a/util/src/main/java/com/ning/billing/util/events/BusInternalEvent.java
+++ b/util/src/main/java/com/ning/billing/util/events/BusInternalEvent.java
@@ -38,7 +38,9 @@ public interface BusInternalEvent {
         CONTROL_TAGDEFINITION_DELETION,
         USER_TAGDEFINITION_CREATION,
         USER_TAGDEFINITION_DELETION,
-        OVERDUE_CHANGE
+        OVERDUE_CHANGE,
+        CUSTOM_FIELD_CREATION,
+        CUSTOM_FIELD_DELETION,
     }
 
     public BusInternalEventType getBusEventType();
diff --git a/util/src/main/java/com/ning/billing/util/events/CustomFieldCreationEvent.java b/util/src/main/java/com/ning/billing/util/events/CustomFieldCreationEvent.java
new file mode 100644
index 0000000..4699c1b
--- /dev/null
+++ b/util/src/main/java/com/ning/billing/util/events/CustomFieldCreationEvent.java
@@ -0,0 +1,20 @@
+/*
+ * 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.util.events;
+
+public interface CustomFieldCreationEvent extends CustomFieldEvent {
+}
diff --git a/util/src/main/java/com/ning/billing/util/events/CustomFieldDeletionEvent.java b/util/src/main/java/com/ning/billing/util/events/CustomFieldDeletionEvent.java
new file mode 100644
index 0000000..a72b615
--- /dev/null
+++ b/util/src/main/java/com/ning/billing/util/events/CustomFieldDeletionEvent.java
@@ -0,0 +1,24 @@
+/*
+ * 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.util.events;
+
+import java.util.UUID;
+
+import com.ning.billing.ObjectType;
+
+public interface CustomFieldDeletionEvent  extends CustomFieldEvent {
+}
diff --git a/util/src/main/java/com/ning/billing/util/events/CustomFieldEvent.java b/util/src/main/java/com/ning/billing/util/events/CustomFieldEvent.java
new file mode 100644
index 0000000..d981a3c
--- /dev/null
+++ b/util/src/main/java/com/ning/billing/util/events/CustomFieldEvent.java
@@ -0,0 +1,30 @@
+/*
+ * 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.util.events;
+
+import java.util.UUID;
+
+import com.ning.billing.ObjectType;
+
+public interface CustomFieldEvent extends BusInternalEvent {
+
+    UUID getCustomFieldId();
+
+    UUID getObjectId();
+
+    ObjectType getObjectType();
+}
diff --git a/util/src/main/java/com/ning/billing/util/glue/RecordIdModule.java b/util/src/main/java/com/ning/billing/util/glue/RecordIdModule.java
new file mode 100644
index 0000000..2d1d019
--- /dev/null
+++ b/util/src/main/java/com/ning/billing/util/glue/RecordIdModule.java
@@ -0,0 +1,31 @@
+/*
+ * 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.util.glue;
+
+import com.ning.billing.util.api.RecordIdApi;
+import com.ning.billing.util.recordid.DefaultRecordIdApi;
+
+import com.google.inject.AbstractModule;
+
+public class RecordIdModule extends AbstractModule {
+
+
+    @Override
+    protected void configure() {
+        bind(RecordIdApi.class).to(DefaultRecordIdApi.class).asEagerSingleton();
+    }
+}
diff --git a/util/src/main/java/com/ning/billing/util/recordid/DefaultRecordIdApi.java b/util/src/main/java/com/ning/billing/util/recordid/DefaultRecordIdApi.java
new file mode 100644
index 0000000..f16c347
--- /dev/null
+++ b/util/src/main/java/com/ning/billing/util/recordid/DefaultRecordIdApi.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.util.recordid;
+
+import java.util.UUID;
+
+import javax.inject.Inject;
+
+import com.ning.billing.ObjectType;
+import com.ning.billing.util.api.RecordIdApi;
+import com.ning.billing.util.cache.Cachable.CacheType;
+import com.ning.billing.util.cache.CacheControllerDispatcher;
+import com.ning.billing.util.callcontext.TenantContext;
+import com.ning.billing.util.dao.NonEntityDao;
+
+public class DefaultRecordIdApi implements RecordIdApi  {
+
+    private final NonEntityDao nonEntityDao;
+    private final CacheControllerDispatcher cacheControllerDispatcher;
+
+    @Inject
+    public DefaultRecordIdApi(final NonEntityDao nonEntityDao, final CacheControllerDispatcher cacheControllerDispatcher) {
+        this.nonEntityDao = nonEntityDao;
+        this.cacheControllerDispatcher = cacheControllerDispatcher;
+    }
+
+
+    @Override
+    public Long getRecordId(final UUID objectId, final ObjectType objectType, final TenantContext tenantContext) {
+        return nonEntityDao.retrieveRecordIdFromObject(objectId, objectType, cacheControllerDispatcher.getCacheController(CacheType.RECORD_ID));
+    }
+}
diff --git a/util/src/main/java/com/ning/billing/util/svcapi/tag/DefaultTagInternalApi.java b/util/src/main/java/com/ning/billing/util/svcapi/tag/DefaultTagInternalApi.java
index 774e20c..f2eed5c 100644
--- a/util/src/main/java/com/ning/billing/util/svcapi/tag/DefaultTagInternalApi.java
+++ b/util/src/main/java/com/ning/billing/util/svcapi/tag/DefaultTagInternalApi.java
@@ -66,7 +66,7 @@ public class DefaultTagInternalApi implements TagInternalApi {
 
     @Override
     public List<Tag> getTags(final UUID objectId, final ObjectType objectType, final InternalTenantContext context) {
-        return ImmutableList.<Tag>copyOf(Collections2.transform(tagDao.getTags(objectId, objectType, context),
+        return ImmutableList.<Tag>copyOf(Collections2.transform(tagDao.getTagsForObject(objectId, objectType, context),
                                                                 new Function<TagModelDao, Tag>() {
                                                                     @Override
                                                                     public Tag apply(final TagModelDao input) {
diff --git a/util/src/main/java/com/ning/billing/util/tag/api/DefaultTagUserApi.java b/util/src/main/java/com/ning/billing/util/tag/api/DefaultTagUserApi.java
index ae12ebc..0e4c188 100644
--- a/util/src/main/java/com/ning/billing/util/tag/api/DefaultTagUserApi.java
+++ b/util/src/main/java/com/ning/billing/util/tag/api/DefaultTagUserApi.java
@@ -127,22 +127,35 @@ public class DefaultTagUserApi implements TagUserApi {
     }
 
     @Override
-    public List<Tag> getTags(final UUID objectId, final ObjectType objectType, final TenantContext context) {
-        return ImmutableList.<Tag>copyOf(Collections2.transform(tagDao.getTags(objectId, objectType, internalCallContextFactory.createInternalTenantContext(context)),
-                                                                new Function<TagModelDao, Tag>() {
-                                                                    @Override
-                                                                    public Tag apply(final TagModelDao input) {
-                                                                        return TagModelDaoHelper.isControlTag(input.getTagDefinitionId()) ?
-                                                                               new DefaultControlTag(ControlTagType.getTypeFromId(input.getTagDefinitionId()), objectType, objectId, input.getCreatedDate()) :
-                                                                               new DescriptiveTag(input.getTagDefinitionId(), objectType, objectId, input.getCreatedDate());
-                                                                    }
-                                                                }));
-    }
-
-    @Override
     public TagDefinition getTagDefinitionForName(final String tagDefinitionName, final TenantContext context)
             throws TagDefinitionApiException {
         return new DefaultTagDefinition(tagDefinitionDao.getByName(tagDefinitionName, internalCallContextFactory.createInternalTenantContext(context)),
                                         TagModelDaoHelper.isControlTag(tagDefinitionName));
     }
+
+    @Override
+    public List<Tag> getTagsForObject(final UUID objectId, final ObjectType objectType, final TenantContext context) {
+        return withModelTransform(tagDao.getTagsForObject(objectId, objectType, internalCallContextFactory.createInternalTenantContext(context)));
+    }
+
+    @Override
+    public List<Tag> getTagsForAccountType(final UUID accountId, final ObjectType objectType, final TenantContext context) {
+        return withModelTransform(tagDao.getTagsForAccountType(accountId, objectType, internalCallContextFactory.createInternalTenantContext(accountId, context)));
+    }
+
+    @Override
+    public List<Tag> getTagsForAccount(final UUID accountId, final TenantContext context) {
+        return withModelTransform(tagDao.getTagsForAccount(accountId, internalCallContextFactory.createInternalTenantContext(accountId, context)));
+    }
+
+    private List<Tag> withModelTransform(final List<TagModelDao> input) {
+        return ImmutableList.<Tag>copyOf(Collections2.transform(input, new Function<TagModelDao, Tag>() {
+            @Override
+            public Tag apply(final TagModelDao input) {
+                return TagModelDaoHelper.isControlTag(input.getTagDefinitionId()) ?
+                       new DefaultControlTag(ControlTagType.getTypeFromId(input.getTagDefinitionId()), input.getObjectType(), input.getObjectId(), input.getCreatedDate()) :
+                       new DescriptiveTag(input.getTagDefinitionId(), input.getObjectType(), input.getObjectId(), input.getCreatedDate());
+            }
+        }));
+    }
 }
diff --git a/util/src/main/java/com/ning/billing/util/tag/dao/DefaultTagDao.java b/util/src/main/java/com/ning/billing/util/tag/dao/DefaultTagDao.java
index cd5a164..6ae85a9 100644
--- a/util/src/main/java/com/ning/billing/util/tag/dao/DefaultTagDao.java
+++ b/util/src/main/java/com/ning/billing/util/tag/dao/DefaultTagDao.java
@@ -19,6 +19,8 @@ package com.ning.billing.util.tag.dao;
 import java.util.List;
 import java.util.UUID;
 
+import javax.annotation.Nullable;
+
 import org.skife.jdbi.v2.IDBI;
 import org.slf4j.Logger;
 import org.slf4j.LoggerFactory;
@@ -28,6 +30,7 @@ import com.ning.billing.ErrorCode;
 import com.ning.billing.ObjectType;
 import com.ning.billing.util.api.TagApiException;
 import com.ning.billing.util.audit.ChangeType;
+import com.ning.billing.util.cache.Cachable.CacheType;
 import com.ning.billing.util.cache.CacheControllerDispatcher;
 import com.ning.billing.util.callcontext.InternalCallContext;
 import com.ning.billing.util.callcontext.InternalTenantContext;
@@ -44,6 +47,9 @@ import com.ning.billing.util.tag.ControlTagType;
 import com.ning.billing.util.tag.Tag;
 import com.ning.billing.util.tag.api.user.TagEventBuilder;
 
+import com.google.common.base.Predicate;
+import com.google.common.collect.Collections2;
+import com.google.common.collect.ImmutableList;
 import com.google.inject.Inject;
 
 public class DefaultTagDao extends EntityDaoBase<TagModelDao, Tag, TagApiException> implements TagDao {
@@ -62,7 +68,7 @@ public class DefaultTagDao extends EntityDaoBase<TagModelDao, Tag, TagApiExcepti
     }
 
     @Override
-    public List<TagModelDao> getTags(final UUID objectId, final ObjectType objectType, final InternalTenantContext internalTenantContext) {
+    public List<TagModelDao> getTagsForObject(final UUID objectId, final ObjectType objectType, final InternalTenantContext internalTenantContext) {
         return transactionalSqlDao.execute(new EntitySqlDaoTransactionWrapper<List<TagModelDao>>() {
             @Override
             public List<TagModelDao> inTransaction(final EntitySqlDaoWrapperFactory<EntitySqlDao> entitySqlDaoWrapperFactory) throws Exception {
@@ -72,6 +78,30 @@ public class DefaultTagDao extends EntityDaoBase<TagModelDao, Tag, TagApiExcepti
     }
 
     @Override
+    public List<TagModelDao> getTagsForAccountType(final UUID accountId, final ObjectType objectType, final InternalTenantContext internalTenantContext) {
+
+        final List<TagModelDao> allTags = getTagsForAccount(accountId, internalTenantContext);
+        return ImmutableList.<TagModelDao>copyOf(Collections2.filter(allTags, new Predicate<TagModelDao>() {
+            @Override
+            public boolean apply(@Nullable final TagModelDao input) {
+                return input.getObjectType() == objectType;
+            }
+        }));
+    }
+
+    @Override
+    public List<TagModelDao> getTagsForAccount(final UUID accountId, final InternalTenantContext internalTenantContext) {
+
+        return transactionalSqlDao.execute(new EntitySqlDaoTransactionWrapper<List<TagModelDao>>() {
+            @Override
+            public List<TagModelDao> inTransaction(final EntitySqlDaoWrapperFactory<EntitySqlDao> entitySqlDaoWrapperFactory) throws Exception {
+                return entitySqlDaoWrapperFactory.become(TagSqlDao.class).getByAccountRecordId(internalTenantContext);
+            }
+        });
+    }
+
+
+    @Override
     protected void postBusEventFromTransaction(final TagModelDao tag, final TagModelDao savedTag, final ChangeType changeType,
                                                final EntitySqlDaoWrapperFactory<EntitySqlDao> entitySqlDaoWrapperFactory, final InternalCallContext context)
             throws BillingExceptionBase {
diff --git a/util/src/main/java/com/ning/billing/util/tag/dao/TagDao.java b/util/src/main/java/com/ning/billing/util/tag/dao/TagDao.java
index 152dfbf..9fd3ed8 100644
--- a/util/src/main/java/com/ning/billing/util/tag/dao/TagDao.java
+++ b/util/src/main/java/com/ning/billing/util/tag/dao/TagDao.java
@@ -32,5 +32,9 @@ public interface TagDao {
 
     TagModelDao getById(UUID tagId, InternalTenantContext context);
 
-    List<TagModelDao> getTags(UUID objectId, ObjectType objectType, InternalTenantContext internalTenantContext);
+    List<TagModelDao> getTagsForObject(UUID objectId, ObjectType objectType, InternalTenantContext internalTenantContext);
+
+    List<TagModelDao> getTagsForAccountType(UUID accountId, ObjectType objectType, InternalTenantContext internalTenantContext);
+
+    List<TagModelDao> getTagsForAccount(UUID accountId, InternalTenantContext internalTenantContext);
 }
diff --git a/util/src/main/resources/com/ning/billing/util/entity/dao/EntitySqlDao.sql.stg b/util/src/main/resources/com/ning/billing/util/entity/dao/EntitySqlDao.sql.stg
index 6610aa5..9a2c236 100644
--- a/util/src/main/resources/com/ning/billing/util/entity/dao/EntitySqlDao.sql.stg
+++ b/util/src/main/resources/com/ning/billing/util/entity/dao/EntitySqlDao.sql.stg
@@ -162,6 +162,16 @@ where <recordIdField("t.")> = :recordId
 ;
 >>
 
+getByAccountRecordId(accountRecordId) ::= <<
+select
+<allTableFields("t.")>
+from <tableName()> t
+where <accountRecordIdField("t.")> = :accountRecordId
+<AND_CHECK_TENANT("t.")>
+;
+>>
+
+
 getHistoryTargetRecordId(recordId) ::= <<
 select
 <targetRecordIdField("t.")>
diff --git a/util/src/test/java/com/ning/billing/api/TestApiListener.java b/util/src/test/java/com/ning/billing/api/TestApiListener.java
index c18bceb..d09806b 100644
--- a/util/src/test/java/com/ning/billing/api/TestApiListener.java
+++ b/util/src/test/java/com/ning/billing/api/TestApiListener.java
@@ -26,6 +26,7 @@ import org.joda.time.DateTime;
 import org.slf4j.Logger;
 import org.slf4j.LoggerFactory;
 
+import com.ning.billing.util.events.CustomFieldEvent;
 import com.ning.billing.util.events.EffectiveSubscriptionInternalEvent;
 import com.ning.billing.util.events.InvoiceAdjustmentInternalEvent;
 import com.ning.billing.util.events.InvoiceCreationInternalEvent;
@@ -76,7 +77,8 @@ public class TestApiListener {
         PAYMENT_ERROR,
         REPAIR_BUNDLE,
         TAG,
-        TAG_DEFINITION
+        TAG_DEFINITION,
+        CUSTOM_FIELD
     }
 
     public void setNonExpectedMode() {
@@ -145,6 +147,14 @@ public class TestApiListener {
     }
 
     @Subscribe
+    public synchronized void processCustomFieldEvent(final CustomFieldEvent event) {
+        log.info(String.format("Got CustomFieldEvent event %s", event.toString()));
+        assertEqualsNicely(NextEvent.CUSTOM_FIELD);
+        notifyIfStackEmpty();
+    }
+
+
+    @Subscribe
     public synchronized void processTagDefinitonEvent(final TagDefinitionInternalEvent event) {
         log.info(String.format("Got TagDefinitionInternalEvent event %s", event.toString()));
         assertEqualsNicely(NextEvent.TAG_DEFINITION);
diff --git a/util/src/test/java/com/ning/billing/mock/glue/MockJunctionModule.java b/util/src/test/java/com/ning/billing/mock/glue/MockJunctionModule.java
index 89967e0..ac47120 100644
--- a/util/src/test/java/com/ning/billing/mock/glue/MockJunctionModule.java
+++ b/util/src/test/java/com/ning/billing/mock/glue/MockJunctionModule.java
@@ -21,6 +21,7 @@ import org.mockito.Mockito;
 import com.ning.billing.account.api.AccountUserApi;
 import com.ning.billing.entitlement.api.user.EntitlementUserApi;
 import com.ning.billing.glue.JunctionModule;
+import com.ning.billing.junction.api.JunctionApi;
 import com.ning.billing.util.svcapi.junction.BillingInternalApi;
 import com.ning.billing.util.svcapi.junction.BlockingInternalApi;
 
@@ -31,6 +32,7 @@ public class MockJunctionModule extends AbstractModule implements JunctionModule
     private final BlockingInternalApi blockingApi = Mockito.mock(BlockingInternalApi.class);
     private final AccountUserApi userApi = Mockito.mock(AccountUserApi.class);
     private final EntitlementUserApi entUserApi = Mockito.mock(EntitlementUserApi.class);
+    private final JunctionApi junctionApi = Mockito.mock(JunctionApi.class);
 
     @Override
     protected void configure() {
@@ -38,6 +40,7 @@ public class MockJunctionModule extends AbstractModule implements JunctionModule
         installAccountUserApi();
         installBillingApi();
         installEntitlementUserApi();
+        installJunctionApi();
     }
 
     @Override
@@ -60,4 +63,9 @@ public class MockJunctionModule extends AbstractModule implements JunctionModule
         bind(EntitlementUserApi.class).toInstance(entUserApi);
     }
 
+    @Override
+    public void installJunctionApi() {
+         bind(JunctionApi.class).toInstance(junctionApi);
+    }
+
 }
diff --git a/util/src/test/java/com/ning/billing/mock/MockSubscription.java b/util/src/test/java/com/ning/billing/mock/MockSubscription.java
index c1127cd..307d4a0 100644
--- a/util/src/test/java/com/ning/billing/mock/MockSubscription.java
+++ b/util/src/test/java/com/ning/billing/mock/MockSubscription.java
@@ -226,4 +226,9 @@ public class MockSubscription implements Subscription {
         // TODO Auto-generated method stub
         return null;
     }
+
+    @Override
+    public List<SubscriptionTransition> getAllTransitions() {
+        return null;
+    }
 }
diff --git a/util/src/test/java/com/ning/billing/payment/api/TestPaymentMethodPluginBase.java b/util/src/test/java/com/ning/billing/payment/api/TestPaymentMethodPluginBase.java
new file mode 100644
index 0000000..da02ef1
--- /dev/null
+++ b/util/src/test/java/com/ning/billing/payment/api/TestPaymentMethodPluginBase.java
@@ -0,0 +1,105 @@
+/*
+ * 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.payment.api;
+
+import java.util.List;
+import java.util.UUID;
+
+import com.google.common.collect.ImmutableList;
+
+public class TestPaymentMethodPluginBase implements PaymentMethodPlugin {
+
+    @Override
+    public String getExternalPaymentMethodId() {
+        return UUID.randomUUID().toString();
+    }
+
+    @Override
+    public boolean isDefaultPaymentMethod() {
+        return false;
+    }
+
+    @Override
+    public String getValueString(final String key) {
+        throw new UnsupportedOperationException();
+    }
+
+    @Override
+    public String getType() {
+        throw new UnsupportedOperationException();
+    }
+
+    @Override
+    public String getCCName() {
+        throw new UnsupportedOperationException();
+    }
+
+    @Override
+    public String getCCType() {
+        throw new UnsupportedOperationException();
+    }
+
+    @Override
+    public String getCCExprirationMonth() {
+        throw new UnsupportedOperationException();
+    }
+
+    @Override
+    public String getCCExprirationYear() {
+        throw new UnsupportedOperationException();
+    }
+
+    @Override
+    public String getCCLast4() {
+        throw new UnsupportedOperationException();
+    }
+
+    @Override
+    public String getAddress1() {
+        throw new UnsupportedOperationException();
+    }
+
+    @Override
+    public String getAddress2() {
+        throw new UnsupportedOperationException();
+    }
+
+    @Override
+    public String getCity() {
+        throw new UnsupportedOperationException();
+    }
+
+    @Override
+    public String getState() {
+        throw new UnsupportedOperationException();
+    }
+
+    @Override
+    public String getZip() {
+        throw new UnsupportedOperationException();
+    }
+
+    @Override
+    public String getCountry() {
+        throw new UnsupportedOperationException();
+    }
+
+    @Override
+    public List<PaymentMethodKVInfo> getProperties() {
+        return ImmutableList.<PaymentMethodKVInfo>of();
+    }
+}
diff --git a/util/src/test/java/com/ning/billing/util/audit/dao/TestDefaultAuditDao.java b/util/src/test/java/com/ning/billing/util/audit/dao/TestDefaultAuditDao.java
index 111d8fe..8ed8aa5 100644
--- a/util/src/test/java/com/ning/billing/util/audit/dao/TestDefaultAuditDao.java
+++ b/util/src/test/java/com/ning/billing/util/audit/dao/TestDefaultAuditDao.java
@@ -78,7 +78,7 @@ public class TestDefaultAuditDao extends UtilTestSuiteWithEmbeddedDB {
         final Tag tag = new DescriptiveTag(tagDefinition.getId(), ObjectType.ACCOUNT, objectId, clock.getUTCNow());
 
         tagDao.create(new TagModelDao(tag), internalCallContext);
-        final List<TagModelDao> tags = tagDao.getTags(objectId, ObjectType.ACCOUNT, internalCallContext);
+        final List<TagModelDao> tags = tagDao.getTagsForObject(objectId, ObjectType.ACCOUNT, internalCallContext);
         Assert.assertEquals(tags.size(), 1);
         final TagModelDao savedTag = tags.get(0);
         Assert.assertEquals(savedTag.getTagDefinitionId(), tagDefinition.getId());
diff --git a/util/src/test/java/com/ning/billing/util/customfield/api/TestDefaultCustomFieldCreationEvent.java b/util/src/test/java/com/ning/billing/util/customfield/api/TestDefaultCustomFieldCreationEvent.java
new file mode 100644
index 0000000..78421e3
--- /dev/null
+++ b/util/src/test/java/com/ning/billing/util/customfield/api/TestDefaultCustomFieldCreationEvent.java
@@ -0,0 +1,65 @@
+/*
+ * 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.util.customfield.api;
+
+import java.util.UUID;
+
+import org.testng.Assert;
+import org.testng.annotations.Test;
+
+import com.ning.billing.ObjectType;
+import com.ning.billing.util.events.BusInternalEvent.BusInternalEventType;
+import com.ning.billing.util.jackson.ObjectMapper;
+
+public class TestDefaultCustomFieldCreationEvent {
+
+
+    @Test(groups = "fast")
+    public void testPojo() throws Exception {
+        final UUID customFieldId = UUID.randomUUID();
+        final UUID objectId = UUID.randomUUID();
+        final ObjectType objectType = ObjectType.ACCOUNT_EMAIL;
+        final UUID userToken = UUID.randomUUID();
+
+        final DefaultCustomFieldCreationEvent event = new DefaultCustomFieldCreationEvent(customFieldId, objectId, objectType, userToken, 1L, 1L);
+        Assert.assertEquals(event.getBusEventType(), BusInternalEventType.CUSTOM_FIELD_CREATION);
+
+        Assert.assertEquals(event.getObjectId(), objectId);
+        Assert.assertEquals(event.getObjectType(), objectType);
+        Assert.assertEquals(event.getUserToken(), userToken);
+
+        Assert.assertEquals(event, event);
+        Assert.assertEquals(event, new DefaultCustomFieldCreationEvent(customFieldId, objectId, objectType, userToken, 1L, 1L));
+    }
+
+    @Test(groups = "fast")
+    public void testSerialization() throws Exception {
+
+        final ObjectMapper objectMapper = new ObjectMapper();
+
+        final UUID customFieldId = UUID.randomUUID();
+        final UUID objectId = UUID.randomUUID();
+        final ObjectType objectType = ObjectType.ACCOUNT_EMAIL;
+        final UUID userToken = UUID.randomUUID();
+
+        final DefaultCustomFieldCreationEvent event = new DefaultCustomFieldCreationEvent(customFieldId, objectId, objectType, userToken, 1L, 1L);
+
+        final String json = objectMapper.writeValueAsString(event);
+        final DefaultCustomFieldCreationEvent fromJson = objectMapper.readValue(json, DefaultCustomFieldCreationEvent.class);
+        Assert.assertEquals(fromJson, event);
+    }
+}
diff --git a/util/src/test/java/com/ning/billing/util/customfield/api/TestDefaultCustomFieldDeletionEvent.java b/util/src/test/java/com/ning/billing/util/customfield/api/TestDefaultCustomFieldDeletionEvent.java
new file mode 100644
index 0000000..e0c5b28
--- /dev/null
+++ b/util/src/test/java/com/ning/billing/util/customfield/api/TestDefaultCustomFieldDeletionEvent.java
@@ -0,0 +1,65 @@
+/*
+ * 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.util.customfield.api;
+
+import java.util.UUID;
+
+import org.testng.Assert;
+import org.testng.annotations.Test;
+
+import com.ning.billing.ObjectType;
+import com.ning.billing.util.events.BusInternalEvent.BusInternalEventType;
+import com.ning.billing.util.jackson.ObjectMapper;
+
+public class TestDefaultCustomFieldDeletionEvent {
+
+
+    @Test(groups = "fast")
+    public void testPojo() throws Exception {
+        final UUID customFieldId = UUID.randomUUID();
+        final UUID objectId = UUID.randomUUID();
+        final ObjectType objectType = ObjectType.ACCOUNT_EMAIL;
+        final UUID userToken = UUID.randomUUID();
+
+        final DefaultCustomFieldDeletionEvent event = new DefaultCustomFieldDeletionEvent(customFieldId, objectId, objectType, userToken, 1L, 1L);
+        Assert.assertEquals(event.getBusEventType(), BusInternalEventType.CUSTOM_FIELD_DELETION);
+
+        Assert.assertEquals(event.getObjectId(), objectId);
+        Assert.assertEquals(event.getObjectType(), objectType);
+        Assert.assertEquals(event.getUserToken(), userToken);
+
+        Assert.assertEquals(event, event);
+        Assert.assertEquals(event, new DefaultCustomFieldDeletionEvent(customFieldId, objectId, objectType, userToken, 1L, 1L));
+    }
+
+    @Test(groups = "fast")
+    public void testSerialization() throws Exception {
+
+        final ObjectMapper objectMapper = new ObjectMapper();
+
+        final UUID customFieldId = UUID.randomUUID();
+        final UUID objectId = UUID.randomUUID();
+        final ObjectType objectType = ObjectType.ACCOUNT_EMAIL;
+        final UUID userToken = UUID.randomUUID();
+
+        final DefaultCustomFieldDeletionEvent event = new DefaultCustomFieldDeletionEvent(customFieldId, objectId, objectType, userToken, 1L, 1L);
+
+        final String json = objectMapper.writeValueAsString(event);
+        final DefaultCustomFieldDeletionEvent fromJson = objectMapper.readValue(json, DefaultCustomFieldDeletionEvent.class);
+        Assert.assertEquals(fromJson, event);
+    }
+}
diff --git a/util/src/test/java/com/ning/billing/util/customfield/api/TestDefaultCustomFieldUserApi.java b/util/src/test/java/com/ning/billing/util/customfield/api/TestDefaultCustomFieldUserApi.java
index c5522ad..ac85be2 100644
--- a/util/src/test/java/com/ning/billing/util/customfield/api/TestDefaultCustomFieldUserApi.java
+++ b/util/src/test/java/com/ning/billing/util/customfield/api/TestDefaultCustomFieldUserApi.java
@@ -56,7 +56,7 @@ public class TestDefaultCustomFieldUserApi extends UtilTestSuiteWithEmbeddedDB {
         customFieldUserApi.addCustomFields(ImmutableList.<CustomField>of(customField), callContext);
 
         // Verify the field was saved
-        final List<CustomField> customFields = customFieldUserApi.getCustomFields(accountId, ObjectType.ACCOUNT, callContext);
+        final List<CustomField> customFields = customFieldUserApi.getCustomFieldsForObject(accountId, ObjectType.ACCOUNT, callContext);
         Assert.assertEquals(customFields.size(), 1);
         Assert.assertEquals(customFields.get(0), customField);
         // Verify the account_record_id was populated
diff --git a/util/src/test/java/com/ning/billing/util/customfield/dao/MockCustomFieldDao.java b/util/src/test/java/com/ning/billing/util/customfield/dao/MockCustomFieldDao.java
index 354da71..2694248 100644
--- a/util/src/test/java/com/ning/billing/util/customfield/dao/MockCustomFieldDao.java
+++ b/util/src/test/java/com/ning/billing/util/customfield/dao/MockCustomFieldDao.java
@@ -29,7 +29,7 @@ import com.ning.billing.util.entity.dao.MockEntityDaoBase;
 public class MockCustomFieldDao extends MockEntityDaoBase<CustomFieldModelDao, CustomField, CustomFieldApiException> implements CustomFieldDao {
 
     @Override
-    public List<CustomFieldModelDao> getCustomFields(final UUID objectId, final ObjectType objectType, final InternalTenantContext context) {
+    public List<CustomFieldModelDao> getCustomFieldsForObject(final UUID objectId, final ObjectType objectType, final InternalTenantContext context) {
         final List<CustomFieldModelDao> result = new ArrayList<CustomFieldModelDao>();
         final List<CustomFieldModelDao> all = get(context);
         for (final CustomFieldModelDao cur : all) {
@@ -39,4 +39,14 @@ public class MockCustomFieldDao extends MockEntityDaoBase<CustomFieldModelDao, C
         }
         return result;
     }
+
+    @Override
+    public List<CustomFieldModelDao> getCustomFieldsForAccountType(final ObjectType objectType, final InternalTenantContext context) {
+        throw new UnsupportedOperationException();
+    }
+
+    @Override
+    public List<CustomFieldModelDao> getCustomFieldsForAccount(final InternalTenantContext context) {
+        throw new UnsupportedOperationException();
+    }
 }
diff --git a/util/src/test/java/com/ning/billing/util/tag/dao/MockTagDao.java b/util/src/test/java/com/ning/billing/util/tag/dao/MockTagDao.java
index 053232f..f80d600 100644
--- a/util/src/test/java/com/ning/billing/util/tag/dao/MockTagDao.java
+++ b/util/src/test/java/com/ning/billing/util/tag/dao/MockTagDao.java
@@ -65,7 +65,7 @@ public class MockTagDao implements TagDao {
     }
 
     @Override
-    public List<TagModelDao> getTags(final UUID objectId, final ObjectType objectType, final InternalTenantContext internalTenantContext) {
+    public List<TagModelDao> getTagsForObject(final UUID objectId, final ObjectType objectType, final InternalTenantContext internalTenantContext) {
         if (tagStore.get(objectId) == null) {
             return ImmutableList.<TagModelDao>of();
         }
@@ -78,6 +78,16 @@ public class MockTagDao implements TagDao {
         }));
     }
 
+    @Override
+    public List<TagModelDao> getTagsForAccountType(final UUID accountId, final ObjectType objectType, final InternalTenantContext internalTenantContext) {
+        throw new UnsupportedOperationException();
+    }
+
+    @Override
+    public List<TagModelDao> getTagsForAccount(final UUID accountId, final InternalTenantContext internalTenantContext) {
+        throw new UnsupportedOperationException();
+    }
+
     public void clear() {
         tagStore.clear();
     }
diff --git a/util/src/test/java/com/ning/billing/util/tag/dao/TestDefaultTagDao.java b/util/src/test/java/com/ning/billing/util/tag/dao/TestDefaultTagDao.java
index e1c95b0..90a84a4 100644
--- a/util/src/test/java/com/ning/billing/util/tag/dao/TestDefaultTagDao.java
+++ b/util/src/test/java/com/ning/billing/util/tag/dao/TestDefaultTagDao.java
@@ -16,42 +16,24 @@
 
 package com.ning.billing.util.tag.dao;
 
-import java.io.IOException;
 import java.util.ArrayList;
 import java.util.List;
 import java.util.UUID;
 
 import org.testng.Assert;
-import org.testng.annotations.AfterClass;
 import org.testng.annotations.AfterMethod;
-import org.testng.annotations.BeforeClass;
 import org.testng.annotations.BeforeMethod;
-import org.testng.annotations.Guice;
 import org.testng.annotations.Test;
 
 import com.ning.billing.ObjectType;
 import com.ning.billing.api.TestApiListener;
 import com.ning.billing.api.TestApiListener.NextEvent;
-import com.ning.billing.api.TestListenerStatus;
-import com.ning.billing.mock.glue.MockDbHelperModule;
 import com.ning.billing.util.UtilTestSuiteWithEmbeddedDB;
 import com.ning.billing.util.api.TagDefinitionApiException;
-import com.ning.billing.util.bus.InMemoryBusModule;
-import com.ning.billing.util.clock.Clock;
-import com.ning.billing.util.events.BusInternalEvent;
-import com.ning.billing.util.events.TagInternalEvent;
-import com.ning.billing.util.glue.CacheModule;
-import com.ning.billing.util.glue.ClockModule;
-import com.ning.billing.util.glue.NonEntityDaoModule;
-import com.ning.billing.util.glue.TagStoreModule;
-import com.ning.billing.util.svcsapi.bus.InternalBus;
 import com.ning.billing.util.tag.ControlTagType;
 import com.ning.billing.util.tag.DescriptiveTag;
 import com.ning.billing.util.tag.Tag;
 
-import com.google.common.eventbus.Subscribe;
-import com.google.inject.Inject;
-
 import static org.testng.Assert.assertEquals;
 
 public class TestDefaultTagDao extends UtilTestSuiteWithEmbeddedDB {
@@ -159,7 +141,7 @@ public class TestDefaultTagDao extends UtilTestSuiteWithEmbeddedDB {
         Assert.assertTrue(eventsListener.isCompleted(2000));
 
         // Make sure we can retrieve it via the DAO
-        final List<TagModelDao> foundTags = tagDao.getTags(objectId, objectType, internalCallContext);
+        final List<TagModelDao> foundTags = tagDao.getTagsForObject(objectId, objectType, internalCallContext);
         Assert.assertEquals(foundTags.size(), 1);
         Assert.assertEquals(foundTags.get(0).getTagDefinitionId(), createdTagDefinition.getId());
 
@@ -179,7 +161,7 @@ public class TestDefaultTagDao extends UtilTestSuiteWithEmbeddedDB {
         Assert.assertTrue(eventsListener.isCompleted(2000));
 
         // Make sure the tag is deleted
-        Assert.assertEquals(tagDao.getTags(objectId, objectType, internalCallContext).size(), 0);
+        Assert.assertEquals(tagDao.getTagsForObject(objectId, objectType, internalCallContext).size(), 0);
 
         /*
         final TagInternalEvent tagSecondEventReceived = eventsListener.getTagEvents().get(1);