killbill-uncached

Changes

Details

diff --git a/api/src/main/java/com/ning/billing/entitlement/api/timeline/BundleTimeline.java b/api/src/main/java/com/ning/billing/entitlement/api/timeline/BundleTimeline.java
index ff8823f..150af02 100644
--- a/api/src/main/java/com/ning/billing/entitlement/api/timeline/BundleTimeline.java
+++ b/api/src/main/java/com/ning/billing/entitlement/api/timeline/BundleTimeline.java
@@ -13,6 +13,7 @@
  * License for the specific language governing permissions and limitations
  * under the License.
  */
+
 package com.ning.billing.entitlement.api.timeline;
 
 import java.util.List;
diff --git a/api/src/main/java/com/ning/billing/util/api/AuditLevel.java b/api/src/main/java/com/ning/billing/util/api/AuditLevel.java
new file mode 100644
index 0000000..53e6bd6
--- /dev/null
+++ b/api/src/main/java/com/ning/billing/util/api/AuditLevel.java
@@ -0,0 +1,26 @@
+/*
+ * Copyright 2010-2012 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;
+
+public enum AuditLevel {
+    // All audits
+    FULL,
+    // Initial inserts only
+    MINIMAL,
+    // No audit
+    NONE
+}
diff --git a/api/src/main/java/com/ning/billing/util/api/AuditUserApi.java b/api/src/main/java/com/ning/billing/util/api/AuditUserApi.java
index 266eb3b..6bf4220 100644
--- a/api/src/main/java/com/ning/billing/util/api/AuditUserApi.java
+++ b/api/src/main/java/com/ning/billing/util/api/AuditUserApi.java
@@ -19,7 +19,7 @@ package com.ning.billing.util.api;
 import java.util.List;
 import java.util.UUID;
 
-import com.ning.billing.entitlement.api.user.SubscriptionBundle;
+import com.ning.billing.entitlement.api.timeline.BundleTimeline;
 import com.ning.billing.invoice.api.Invoice;
 import com.ning.billing.invoice.api.InvoicePayment;
 import com.ning.billing.payment.api.Payment;
@@ -37,49 +37,55 @@ public interface AuditUserApi {
     /**
      * Fetch all audit logs for bundles.
      *
-     * @param bundles the bundles to lookup
+     * @param bundles    the bundles to lookup
+     * @param auditLevel audit level (verbosity)
      * @return all audit logs for these refunds
      */
-    public AuditLogsForBundles getAuditLogsForBundles(final List<SubscriptionBundle> bundles);
+    public AuditLogsForBundles getAuditLogsForBundles(final List<BundleTimeline> bundles, final AuditLevel auditLevel);
 
     /**
      * Fetch all audit logs for invoice payments.
      *
      * @param invoicePayments the invoice payments to lookup
+     * @param auditLevel      audit level (verbosity)
      * @return all audit logs for these invoice payments
      */
-    public AuditLogsForInvoicePayments getAuditLogsForInvoicePayments(final List<InvoicePayment> invoicePayments);
+    public AuditLogsForInvoicePayments getAuditLogsForInvoicePayments(final List<InvoicePayment> invoicePayments, final AuditLevel auditLevel);
 
     /**
      * Fetch all audit logs for refunds.
      *
-     * @param refunds the refunds to lookup
+     * @param refunds    the refunds to lookup
+     * @param auditLevel audit level (verbosity)
      * @return all audit logs for these refunds
      */
-    public AuditLogsForRefunds getAuditLogsForRefunds(final List<Refund> refunds);
+    public AuditLogsForRefunds getAuditLogsForRefunds(final List<Refund> refunds, final AuditLevel auditLevel);
 
     /**
      * Fetch all audit logs for payments.
      *
-     * @param payments the payments to lookup
+     * @param payments   the payments to lookup
+     * @param auditLevel audit level (verbosity)
      * @return all audit logs for these payments
      */
-    public AuditLogsForPayments getAuditLogsForPayments(final List<Payment> payments);
+    public AuditLogsForPayments getAuditLogsForPayments(final List<Payment> payments, final AuditLevel auditLevel);
 
     /**
      * Fetch all audit logs for invoices and associated invoice items.
      *
-     * @param invoices the invoices to lookup
+     * @param invoices   the invoices to lookup
+     * @param auditLevel audit level (verbosity)
      * @return all audit logs for these invoices
      */
-    public AuditLogsForInvoices getAuditLogsForInvoices(final List<Invoice> invoices);
+    public AuditLogsForInvoices getAuditLogsForInvoices(final List<Invoice> invoices, final AuditLevel auditLevel);
 
     /**
      * Get all the audit entries for a given object.
      *
      * @param objectId   the object id
      * @param objectType the type of object
+     * @param auditLevel audit level (verbosity)
      * @return all audit entries for that object
      */
-    public List<AuditLog> getAuditLogs(final UUID objectId, final ObjectType objectType);
+    public List<AuditLog> getAuditLogs(final UUID objectId, final ObjectType objectType, final AuditLevel auditLevel);
 }
diff --git a/api/src/main/java/com/ning/billing/util/audit/AuditLogsForBundles.java b/api/src/main/java/com/ning/billing/util/audit/AuditLogsForBundles.java
index 0eecc75..4ae73cb 100644
--- a/api/src/main/java/com/ning/billing/util/audit/AuditLogsForBundles.java
+++ b/api/src/main/java/com/ning/billing/util/audit/AuditLogsForBundles.java
@@ -28,6 +28,11 @@ public interface AuditLogsForBundles {
     public Map<UUID, List<AuditLog>> getBundlesAuditLogs();
 
     /**
+     * @return mapping between subscription id and associated audit logs
+     */
+    public Map<UUID, List<AuditLog>> getSubscriptionsAuditLogs();
+
+    /**
      * @return mapping between subscription event id and associated audit logs
      */
     public Map<UUID, List<AuditLog>> getSubscriptionEventsAuditLogs();
diff --git a/api/src/main/java/com/ning/billing/util/dao/ObjectType.java b/api/src/main/java/com/ning/billing/util/dao/ObjectType.java
index 7fcf838..1eb1537 100644
--- a/api/src/main/java/com/ning/billing/util/dao/ObjectType.java
+++ b/api/src/main/java/com/ning/billing/util/dao/ObjectType.java
@@ -25,6 +25,7 @@ public enum ObjectType {
     INVOICE_ITEM("invoice item"),
     INVOICE_PAYMENT("invoice payment"),
     SUBSCRIPTION("subscription"),
+    SUBSCRIPTION_EVENT("subscription event"),
     PAYMENT_METHOD("payment method"),
     REFUND("refund"),
     TAG_DEFINITION("tag definition");
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 ee3e5a4..39ee3ec 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
@@ -206,8 +206,7 @@ public class TestDefaultInvoiceUserApi extends InvoiceApiTestBase {
         // Verify the adjusted invoice balance
         final BigDecimal adjustedInvoiceBalance = invoiceUserApi.getInvoice(invoiceId).getBalance();
         // Note! The invoice code will round (see InvoiceItemList)
-        Assert.assertEquals(adjustedInvoiceBalance, invoiceBalance.add(creditAmount.negate()).setScale(InvoicingConfiguration.getNumberOfDecimals(),
-                                                                                                       InvoicingConfiguration.getRoundingMode()));
+        verifyAdjustedInvoiceBalance(invoiceBalance, creditAmount, adjustedInvoiceBalance);
 
         // Verify the adjusted account balance
         final BigDecimal adjustedAccountBalance = invoiceUserApi.getAccountBalance(accountId);
@@ -251,8 +250,7 @@ public class TestDefaultInvoiceUserApi extends InvoiceApiTestBase {
         // Verify the adjusted invoice balance
         final BigDecimal adjustedInvoiceBalance = invoiceUserApi.getInvoice(invoiceId).getBalance();
         // Note! The invoice code will round (see InvoiceItemList)
-        Assert.assertEquals(adjustedInvoiceBalance, invoiceBalance.add(invoiceItem.getAmount().negate()).setScale(InvoicingConfiguration.getNumberOfDecimals(),
-                                                                                                                  InvoicingConfiguration.getRoundingMode()));
+        verifyAdjustedInvoiceBalance(invoiceBalance, invoiceItem.getAmount(), adjustedInvoiceBalance);
 
         // Verify the adjusted account balance
         final BigDecimal adjustedAccountBalance = invoiceUserApi.getAccountBalance(accountId);
@@ -288,8 +286,7 @@ public class TestDefaultInvoiceUserApi extends InvoiceApiTestBase {
         // Verify the adjusted invoice balance
         final BigDecimal adjustedInvoiceBalance = invoiceUserApi.getInvoice(invoiceId).getBalance();
         // Note! The invoice code will round (see InvoiceItemList)
-        Assert.assertEquals(adjustedInvoiceBalance, invoiceBalance.add(adjAmount.negate()).setScale(InvoicingConfiguration.getNumberOfDecimals(),
-                                                                                                    InvoicingConfiguration.getRoundingMode()));
+        verifyAdjustedInvoiceBalance(invoiceBalance, adjAmount, adjustedInvoiceBalance);
 
         // Verify the adjusted account balance
         final BigDecimal adjustedAccountBalance = invoiceUserApi.getAccountBalance(accountId);
@@ -308,4 +305,11 @@ public class TestDefaultInvoiceUserApi extends InvoiceApiTestBase {
             Assert.assertEquals(e.getCode(), ErrorCode.INVOICE_ITEM_ADJUSTMENT_AMOUNT_INVALID.getCode());
         }
     }
+
+    private void verifyAdjustedInvoiceBalance(final BigDecimal invoiceBalance, final BigDecimal adjAmount, final BigDecimal adjustedInvoiceBalance) {
+        Assert.assertEquals(adjustedInvoiceBalance.compareTo(invoiceBalance.add(adjAmount.negate().setScale(InvoicingConfiguration.getNumberOfDecimals(),
+                                                                                                            InvoicingConfiguration.getRoundingMode()))
+                                                                           .setScale(InvoicingConfiguration.getNumberOfDecimals(),
+                                                                                     InvoicingConfiguration.getRoundingMode())), 0);
+    }
 }
diff --git a/jaxrs/src/main/java/com/ning/billing/jaxrs/json/AccountTimelineJson.java b/jaxrs/src/main/java/com/ning/billing/jaxrs/json/AccountTimelineJson.java
index 633b6a3..0a177e8 100644
--- a/jaxrs/src/main/java/com/ning/billing/jaxrs/json/AccountTimelineJson.java
+++ b/jaxrs/src/main/java/com/ning/billing/jaxrs/json/AccountTimelineJson.java
@@ -106,19 +106,23 @@ public class AccountTimelineJson {
              paymentsAuditLogs == null ? ImmutableMap.<UUID, List<AuditLog>>of() : paymentsAuditLogs.getPaymentsAuditLogs(),
              refundsAuditLogs == null ? ImmutableMap.<UUID, List<AuditLog>>of() : refundsAuditLogs.getRefundsAuditLogs(),
              chargebacksAuditLogs == null ? ImmutableMap.<UUID, List<AuditLog>>of() : chargebacksAuditLogs.getInvoicePaymentsAuditLogs(),
-             bundlesAuditLogs == null ? ImmutableMap.<UUID, List<AuditLog>>of() : bundlesAuditLogs.getBundlesAuditLogs());
+             bundlesAuditLogs == null ? ImmutableMap.<UUID, List<AuditLog>>of() : bundlesAuditLogs.getBundlesAuditLogs(),
+             bundlesAuditLogs == null ? ImmutableMap.<UUID, List<AuditLog>>of() : bundlesAuditLogs.getSubscriptionsAuditLogs(),
+             bundlesAuditLogs == null ? ImmutableMap.<UUID, List<AuditLog>>of() : bundlesAuditLogs.getSubscriptionEventsAuditLogs());
     }
 
     public AccountTimelineJson(final Account account, final List<Invoice> invoices, final List<Payment> payments, final List<BundleTimeline> bundles,
                                final Multimap<UUID, Refund> refundsByPayment, final Multimap<UUID, InvoicePayment> chargebacksByPayment,
                                final Map<UUID, List<AuditLog>> invoiceAuditLogs, final Map<UUID, List<AuditLog>> invoiceItemsAuditLogs,
                                final Map<UUID, List<AuditLog>> paymentsAuditLogs, final Map<UUID, List<AuditLog>> refundsAuditLogs,
-                               final Map<UUID, List<AuditLog>> chargebacksAuditLogs, final Map<UUID, List<AuditLog>> bundlesAuditLogs) {
+                               final Map<UUID, List<AuditLog>> chargebacksAuditLogs, final Map<UUID, List<AuditLog>> bundlesAuditLogs,
+                               final Map<UUID, List<AuditLog>> subscriptionsAuditLogs, final Map<UUID, List<AuditLog>> subscriptionEventsAuditLogs) {
         this.account = new AccountJsonSimple(account.getId().toString(), account.getExternalKey());
         this.bundles = new LinkedList<BundleJsonWithSubscriptions>();
         for (final BundleTimeline bundle : bundles) {
-            final List<AuditLog> auditLogs = bundlesAuditLogs.get(bundle.getBundleId());
-            final BundleJsonWithSubscriptions jsonWithSubscriptions = new BundleJsonWithSubscriptions(account.getId(), bundle, auditLogs);
+            final List<AuditLog> bundleAuditLogs = bundlesAuditLogs.get(bundle.getBundleId());
+            final BundleJsonWithSubscriptions jsonWithSubscriptions = new BundleJsonWithSubscriptions(bundle, bundleAuditLogs,
+                                                                                                      subscriptionsAuditLogs, subscriptionEventsAuditLogs);
             this.bundles.add(jsonWithSubscriptions);
         }
 
diff --git a/jaxrs/src/main/java/com/ning/billing/jaxrs/json/BundleJsonWithSubscriptions.java b/jaxrs/src/main/java/com/ning/billing/jaxrs/json/BundleJsonWithSubscriptions.java
index be03ceb..8fd820e 100644
--- a/jaxrs/src/main/java/com/ning/billing/jaxrs/json/BundleJsonWithSubscriptions.java
+++ b/jaxrs/src/main/java/com/ning/billing/jaxrs/json/BundleJsonWithSubscriptions.java
@@ -18,6 +18,7 @@ package com.ning.billing.jaxrs.json;
 
 import java.util.LinkedList;
 import java.util.List;
+import java.util.Map;
 import java.util.UUID;
 
 import javax.annotation.Nullable;
@@ -47,11 +48,13 @@ public class BundleJsonWithSubscriptions extends BundleJsonSimple {
         return subscriptions;
     }
 
-    public BundleJsonWithSubscriptions(@Nullable final UUID accountId, final BundleTimeline bundle, final List<AuditLog> auditLogs) {
+    public BundleJsonWithSubscriptions(final BundleTimeline bundle, final List<AuditLog> auditLogs,
+                                       final Map<UUID, List<AuditLog>> subscriptionsAuditLogs, final Map<UUID, List<AuditLog>> subscriptionEventsAuditLogs) {
         super(bundle.getBundleId(), bundle.getExternalKey(), auditLogs);
         this.subscriptions = new LinkedList<SubscriptionJsonWithEvents>();
-        for (final SubscriptionTimeline cur : bundle.getSubscriptions()) {
-            this.subscriptions.add(new SubscriptionJsonWithEvents(bundle.getBundleId(), cur));
+        for (final SubscriptionTimeline subscriptionTimeline : bundle.getSubscriptions()) {
+            this.subscriptions.add(new SubscriptionJsonWithEvents(bundle.getBundleId(), subscriptionTimeline,
+                                                                  subscriptionsAuditLogs.get(subscriptionTimeline.getId()), subscriptionEventsAuditLogs));
         }
     }
 
diff --git a/jaxrs/src/main/java/com/ning/billing/jaxrs/json/SubscriptionJsonNoEvents.java b/jaxrs/src/main/java/com/ning/billing/jaxrs/json/SubscriptionJsonNoEvents.java
index a03076f..4d5ecb6 100644
--- a/jaxrs/src/main/java/com/ning/billing/jaxrs/json/SubscriptionJsonNoEvents.java
+++ b/jaxrs/src/main/java/com/ning/billing/jaxrs/json/SubscriptionJsonNoEvents.java
@@ -16,29 +16,27 @@
 
 package com.ning.billing.jaxrs.json;
 
+import java.util.List;
+
 import javax.annotation.Nullable;
 
 import org.joda.time.DateTime;
 
+import com.ning.billing.entitlement.api.user.Subscription;
+import com.ning.billing.util.audit.AuditLog;
+
 import com.fasterxml.jackson.annotation.JsonCreator;
 import com.fasterxml.jackson.annotation.JsonProperty;
-import com.ning.billing.entitlement.api.user.Subscription;
 
 public class SubscriptionJsonNoEvents extends SubscriptionJsonSimple {
-    private final DateTime startDate;
 
+    private final DateTime startDate;
     private final String bundleId;
-
     private final String productName;
-
     private final String productCategory;
-
     private final String billingPeriod;
-
     private final String priceList;
-
     private final DateTime chargedThroughDate;
-
     private final DateTime cancelledDate;
 
     @JsonCreator
@@ -50,8 +48,9 @@ public class SubscriptionJsonNoEvents extends SubscriptionJsonSimple {
                                     @JsonProperty("billingPeriod") @Nullable final String billingPeriod,
                                     @JsonProperty("priceList") @Nullable final String priceList,
                                     @JsonProperty("chargedThroughDate") @Nullable final DateTime chargedThroughDate,
-                                    @JsonProperty("cancelledDate") @Nullable final DateTime cancelledDate) {
-        super(subscriptionId);
+                                    @JsonProperty("cancelledDate") @Nullable final DateTime cancelledDate,
+                                    @JsonProperty("auditLogs") @Nullable final List<AuditLogJson> auditLogs) {
+        super(subscriptionId, auditLogs);
         this.bundleId = bundleId;
         this.startDate = startDate;
         this.productName = productName;
@@ -62,20 +61,17 @@ public class SubscriptionJsonNoEvents extends SubscriptionJsonSimple {
         this.cancelledDate = cancelledDate;
     }
 
-    public SubscriptionJsonNoEvents() {
-        this(null, null, null, null, null, null, null, null, null);
-    }
-
-    public SubscriptionJsonNoEvents(final Subscription data) {
+    public SubscriptionJsonNoEvents(final Subscription data, @Nullable final List<AuditLog> auditLogs) {
         this(data.getId().toString(),
              data.getBundleId().toString(),
              data.getStartDate(),
              data.getCurrentPlan() != null ? data.getCurrentPlan().getProduct().getName() : null,
-             data.getCurrentPlan() != null ?data.getCurrentPlan().getProduct().getCategory().toString() : null,
-             data.getCurrentPlan() != null ?data.getCurrentPlan().getBillingPeriod().toString() : null,
+             data.getCurrentPlan() != null ? data.getCurrentPlan().getProduct().getCategory().toString() : null,
+             data.getCurrentPlan() != null ? data.getCurrentPlan().getBillingPeriod().toString() : null,
              data.getCurrentPriceList() != null ? data.getCurrentPriceList().getName() : null,
              data.getChargedThroughDate(),
-             data.getEndDate() != null ? data.getEndDate() : data.getFutureEndDate());
+             data.getEndDate() != null ? data.getEndDate() : data.getFutureEndDate(),
+             toAuditLogJson(auditLogs));
     }
 
     @Override
@@ -118,9 +114,9 @@ public class SubscriptionJsonNoEvents extends SubscriptionJsonSimple {
     @Override
     public String toString() {
         return "SubscriptionJson [subscriptionId=" + subscriptionId
-                + ", bundleId=" + bundleId + ", productName=" + productName
-                + ", productCategory=" + productCategory + ", billingPeriod="
-                + billingPeriod + ", priceList=" + priceList + "]";
+               + ", bundleId=" + bundleId + ", productName=" + productName
+               + ", productCategory=" + productCategory + ", billingPeriod="
+               + billingPeriod + ", priceList=" + priceList + "]";
     }
 
     @Override
@@ -128,8 +124,8 @@ public class SubscriptionJsonNoEvents extends SubscriptionJsonSimple {
         if (equalsNoSubscriptionIdNoStartDateNoCTD(o) && super.equals(o)) {
             final SubscriptionJsonNoEvents that = (SubscriptionJsonNoEvents) o;
             return ((startDate == null && that.startDate == null) || (startDate != null && that.startDate != null && startDate.compareTo(that.startDate) == 0)) &&
-                    ((chargedThroughDate == null && that.chargedThroughDate == null) || (chargedThroughDate != null && that.chargedThroughDate != null &&
-                            chargedThroughDate.compareTo(that.chargedThroughDate) == 0));
+                   ((chargedThroughDate == null && that.chargedThroughDate == null) || (chargedThroughDate != null && that.chargedThroughDate != null &&
+                                                                                        chargedThroughDate.compareTo(that.chargedThroughDate) == 0));
         } else {
             return false;
         }
diff --git a/jaxrs/src/main/java/com/ning/billing/jaxrs/json/SubscriptionJsonSimple.java b/jaxrs/src/main/java/com/ning/billing/jaxrs/json/SubscriptionJsonSimple.java
index 28d5365..acdd875 100644
--- a/jaxrs/src/main/java/com/ning/billing/jaxrs/json/SubscriptionJsonSimple.java
+++ b/jaxrs/src/main/java/com/ning/billing/jaxrs/json/SubscriptionJsonSimple.java
@@ -13,23 +13,24 @@
  * License for the specific language governing permissions and limitations
  * under the License.
  */
+
 package com.ning.billing.jaxrs.json;
 
+import java.util.List;
+
 import javax.annotation.Nullable;
 
 import com.fasterxml.jackson.annotation.JsonCreator;
 import com.fasterxml.jackson.annotation.JsonProperty;
 
-public class SubscriptionJsonSimple {
+public class SubscriptionJsonSimple extends JsonBase {
 
     protected final String subscriptionId;
 
-    public SubscriptionJsonSimple() {
-        this(null);
-    }
-
     @JsonCreator
-    public SubscriptionJsonSimple(@JsonProperty("subscriptionId") @Nullable final String subscriptionId) {
+    public SubscriptionJsonSimple(@JsonProperty("subscriptionId") @Nullable final String subscriptionId,
+                                  @JsonProperty("auditLogs") @Nullable final List<AuditLogJson> auditLogs) {
+        super(auditLogs);
         this.subscriptionId = subscriptionId;
     }
 
@@ -38,6 +39,15 @@ public class SubscriptionJsonSimple {
     }
 
     @Override
+    public String toString() {
+        final StringBuilder sb = new StringBuilder();
+        sb.append("SubscriptionJsonSimple");
+        sb.append("{subscriptionId='").append(subscriptionId).append('\'');
+        sb.append('}');
+        return sb.toString();
+    }
+
+    @Override
     public boolean equals(final Object o) {
         if (this == o) {
             return true;
diff --git a/jaxrs/src/main/java/com/ning/billing/jaxrs/json/SubscriptionJsonWithEvents.java b/jaxrs/src/main/java/com/ning/billing/jaxrs/json/SubscriptionJsonWithEvents.java
index 73508ad..674a9d2 100644
--- a/jaxrs/src/main/java/com/ning/billing/jaxrs/json/SubscriptionJsonWithEvents.java
+++ b/jaxrs/src/main/java/com/ning/billing/jaxrs/json/SubscriptionJsonWithEvents.java
@@ -13,23 +13,28 @@
  * License for the specific language governing permissions and limitations
  * under the License.
  */
+
 package com.ning.billing.jaxrs.json;
 
-import javax.annotation.Nullable;
 import java.util.LinkedList;
 import java.util.List;
+import java.util.Map;
 import java.util.UUID;
 
+import javax.annotation.Nullable;
+
 import org.joda.time.DateTime;
 
-import com.fasterxml.jackson.annotation.JsonCreator;
-import com.fasterxml.jackson.annotation.JsonProperty;
 import com.ning.billing.catalog.api.PlanPhaseSpecifier;
 import com.ning.billing.entitlement.api.timeline.SubscriptionTimeline;
 import com.ning.billing.entitlement.api.timeline.SubscriptionTimeline.ExistingEvent;
 import com.ning.billing.entitlement.api.user.Subscription;
+import com.ning.billing.util.audit.AuditLog;
 import com.ning.billing.util.clock.DefaultClock;
 
+import com.fasterxml.jackson.annotation.JsonCreator;
+import com.fasterxml.jackson.annotation.JsonProperty;
+
 public class SubscriptionJsonWithEvents extends SubscriptionJsonSimple {
 
     private final List<SubscriptionReadEventJson> events;
@@ -41,15 +46,8 @@ public class SubscriptionJsonWithEvents extends SubscriptionJsonSimple {
     public static class SubscriptionReadEventJson extends SubscriptionBaseEventJson {
 
         private final String eventId;
-
         private final DateTime effectiveDate;
 
-        public SubscriptionReadEventJson() {
-            super();
-            this.eventId = null;
-            this.effectiveDate = null;
-        }
-
         @JsonCreator
         public SubscriptionReadEventJson(@JsonProperty("eventId") final String eventId,
                                          @JsonProperty("billingPeriod") final String billingPeriod,
@@ -58,8 +56,9 @@ public class SubscriptionJsonWithEvents extends SubscriptionJsonSimple {
                                          @JsonProperty("product") final String product,
                                          @JsonProperty("priceList") final String priceList,
                                          @JsonProperty("eventType") final String eventType,
-                                         @JsonProperty("phase") final String phase) {
-            super(billingPeriod, requestedDate, product, priceList, eventType, phase);
+                                         @JsonProperty("phase") final String phase,
+                                         @JsonProperty("auditLogs") @Nullable final List<AuditLogJson> auditLogs) {
+            super(billingPeriod, requestedDate, product, priceList, eventType, phase, auditLogs);
             this.eventId = eventId;
             this.effectiveDate = effectiveDate;
         }
@@ -75,14 +74,14 @@ public class SubscriptionJsonWithEvents extends SubscriptionJsonSimple {
         @Override
         public String toString() {
             return "SubscriptionReadEventJson [eventId=" + eventId
-                    + ", effectiveDate=" + effectiveDate
-                    + ", getBillingPeriod()=" + getBillingPeriod()
-                    + ", getRequestedDate()=" + getRequestedDate()
-                    + ", getProduct()=" + getProduct() + ", getPriceList()="
-                    + getPriceList() + ", getEventType()=" + getEventType()
-                    + ", getPhase()=" + getPhase() + ", getClass()="
-                    + getClass() + ", hashCode()=" + hashCode()
-                    + ", toString()=" + super.toString() + "]";
+                   + ", effectiveDate=" + effectiveDate
+                   + ", getBillingPeriod()=" + getBillingPeriod()
+                   + ", getRequestedDate()=" + getRequestedDate()
+                   + ", getProduct()=" + getProduct() + ", getPriceList()="
+                   + getPriceList() + ", getEventType()=" + getEventType()
+                   + ", getPhase()=" + getPhase() + ", getClass()="
+                   + getClass() + ", hashCode()=" + hashCode()
+                   + ", toString()=" + super.toString() + "]";
         }
 
         @Override
@@ -115,6 +114,7 @@ public class SubscriptionJsonWithEvents extends SubscriptionJsonSimple {
     }
 
     public static class SubscriptionDeletedEventJson extends SubscriptionReadEventJson {
+
         @JsonCreator
         public SubscriptionDeletedEventJson(@JsonProperty("event_id") final String eventId,
                                             @JsonProperty("billing_period") final String billingPeriod,
@@ -123,66 +123,56 @@ public class SubscriptionJsonWithEvents extends SubscriptionJsonSimple {
                                             @JsonProperty("product") final String product,
                                             @JsonProperty("price_list") final String priceList,
                                             @JsonProperty("event_type") final String eventType,
-                                            @JsonProperty("phase") final String phase) {
-            super(eventId, billingPeriod, requestedDate, effectiveDate, product, priceList, eventType, phase);
+                                            @JsonProperty("phase") final String phase,
+                                            @JsonProperty("auditLogs") @Nullable final List<AuditLogJson> auditLogs) {
+            super(eventId, billingPeriod, requestedDate, effectiveDate, product, priceList, eventType, phase, auditLogs);
         }
     }
 
     public static class SubscriptionNewEventJson extends SubscriptionBaseEventJson {
+
         @JsonCreator
         public SubscriptionNewEventJson(@JsonProperty("billing_period") final String billingPeriod,
                                         @JsonProperty("requested_date") final DateTime requestedDate,
                                         @JsonProperty("product") final String product,
                                         @JsonProperty("price_list") final String priceList,
                                         @JsonProperty("event_type") final String eventType,
-                                        @JsonProperty("phase") final String phase) {
-            super(billingPeriod, requestedDate, product, priceList, eventType, phase);
+                                        @JsonProperty("phase") final String phase,
+                                        @JsonProperty("auditLogs") @Nullable final List<AuditLogJson> auditLogs) {
+            super(billingPeriod, requestedDate, product, priceList, eventType, phase, auditLogs);
         }
 
         @Override
         public String toString() {
             return "SubscriptionNewEventJson [getBillingPeriod()="
-                    + getBillingPeriod() + ", getRequestedDate()="
-                    + getRequestedDate() + ", getProduct()=" + getProduct()
-                    + ", getPriceList()=" + getPriceList()
-                    + ", getEventType()=" + getEventType() + ", getPhase()="
-                    + getPhase() + ", getClass()=" + getClass()
-                    + ", hashCode()=" + hashCode() + ", toString()="
-                    + super.toString() + "]";
+                   + getBillingPeriod() + ", getRequestedDate()="
+                   + getRequestedDate() + ", getProduct()=" + getProduct()
+                   + ", getPriceList()=" + getPriceList()
+                   + ", getEventType()=" + getEventType() + ", getPhase()="
+                   + getPhase() + ", getClass()=" + getClass()
+                   + ", hashCode()=" + hashCode() + ", toString()="
+                   + super.toString() + "]";
         }
     }
 
-    public static class SubscriptionBaseEventJson {
+    public abstract static class SubscriptionBaseEventJson extends JsonBase {
 
         private final String billingPeriod;
-
         private final DateTime requestedDate;
-
         private final String product;
-
         private final String priceList;
-
         private final String eventType;
-
         private final String phase;
 
-        public SubscriptionBaseEventJson() {
-            this.billingPeriod = null;
-            this.requestedDate = null;
-            this.product = null;
-            this.priceList = null;
-            this.eventType = null;
-            this.phase = null;
-        }
-
         @JsonCreator
         public SubscriptionBaseEventJson(@JsonProperty("billing_period") final String billingPeriod,
                                          @JsonProperty("requested_date") final DateTime requestedDate,
                                          @JsonProperty("product") final String product,
                                          @JsonProperty("price_list") final String priceList,
                                          @JsonProperty("event_type") final String eventType,
-                                         @JsonProperty("phase") final String phase) {
-            super();
+                                         @JsonProperty("phase") final String phase,
+                                         @JsonProperty("auditLogs") @Nullable final List<AuditLogJson> auditLogs) {
+            super(auditLogs);
             this.billingPeriod = billingPeriod;
             this.requestedDate = DefaultClock.toUTCDateTime(requestedDate);
             this.product = product;
@@ -216,6 +206,20 @@ public class SubscriptionJsonWithEvents extends SubscriptionJsonSimple {
         }
 
         @Override
+        public String toString() {
+            final StringBuilder sb = new StringBuilder();
+            sb.append("SubscriptionBaseEventJson");
+            sb.append("{billingPeriod='").append(billingPeriod).append('\'');
+            sb.append(", requestedDate=").append(requestedDate);
+            sb.append(", product='").append(product).append('\'');
+            sb.append(", priceList='").append(priceList).append('\'');
+            sb.append(", eventType='").append(eventType).append('\'');
+            sb.append(", phase='").append(phase).append('\'');
+            sb.append('}');
+            return sb.toString();
+        }
+
+        @Override
         public boolean equals(final Object o) {
             if (this == o) {
                 return true;
@@ -264,31 +268,32 @@ public class SubscriptionJsonWithEvents extends SubscriptionJsonSimple {
     public SubscriptionJsonWithEvents(@JsonProperty("subscription_id") @Nullable final String subscriptionId,
                                       @JsonProperty("events") @Nullable final List<SubscriptionReadEventJson> events,
                                       @JsonProperty("new_events") @Nullable final List<SubscriptionNewEventJson> newEvents,
-                                      @JsonProperty("deleted_events") @Nullable final List<SubscriptionDeletedEventJson> deletedEvents) {
-        super(subscriptionId);
+                                      @JsonProperty("deleted_events") @Nullable final List<SubscriptionDeletedEventJson> deletedEvents,
+                                      @JsonProperty("auditLogs") @Nullable final List<AuditLogJson> auditLogs) {
+        super(subscriptionId, auditLogs);
         this.events = events;
         this.deletedEvents = deletedEvents;
         this.newEvents = newEvents;
     }
 
-    public SubscriptionJsonWithEvents() {
-        this((String) null, null, null, null);
-    }
-
     public SubscriptionJsonWithEvents(final Subscription data,
                                       @Nullable final List<SubscriptionReadEventJson> events,
                                       @Nullable final List<SubscriptionNewEventJson> newEvents,
-                                      @Nullable final List<SubscriptionDeletedEventJson> deletedEvents) {
-        this(data.getId().toString(), events, newEvents, deletedEvents);
+                                      @Nullable final List<SubscriptionDeletedEventJson> deletedEvents,
+                                      @Nullable final List<AuditLog> auditLogs) {
+        this(data.getId().toString(), events, newEvents, deletedEvents, toAuditLogJson(auditLogs));
     }
 
-    public SubscriptionJsonWithEvents(@Nullable final UUID bundleId, final SubscriptionTimeline input) {
-        super(input.getId().toString());
+    public SubscriptionJsonWithEvents(@Nullable final UUID bundleId, final SubscriptionTimeline input,
+                                      final List<AuditLog> bundleAuditLogs, final Map<UUID, List<AuditLog>> subscriptionEventsAuditLogs) {
+        super(input.getId().toString(), toAuditLogJson(bundleAuditLogs));
+
         this.events = new LinkedList<SubscriptionReadEventJson>();
-        for (final ExistingEvent cur : input.getExistingEvents()) {
-            final PlanPhaseSpecifier spec = cur.getPlanPhaseSpecifier();
-            this.events.add(new SubscriptionReadEventJson(cur.getEventId().toString(), spec.getBillingPeriod().toString(), cur.getRequestedDate(), cur.getEffectiveDate(),
-                                                          spec.getProductName(), spec.getPriceListName(), cur.getSubscriptionTransitionType().toString(), spec.getPhaseType().toString()));
+        for (final ExistingEvent event : input.getExistingEvents()) {
+            final PlanPhaseSpecifier spec = event.getPlanPhaseSpecifier();
+            this.events.add(new SubscriptionReadEventJson(event.getEventId().toString(), spec.getBillingPeriod().toString(), event.getRequestedDate(), event.getEffectiveDate(),
+                                                          spec.getProductName(), spec.getPriceListName(), event.getSubscriptionTransitionType().toString(), spec.getPhaseType().toString(),
+                                                          toAuditLogJson(subscriptionEventsAuditLogs.get(event.getEventId()))));
         }
         this.newEvents = null;
         this.deletedEvents = null;
@@ -311,6 +316,17 @@ public class SubscriptionJsonWithEvents extends SubscriptionJsonSimple {
     }
 
     @Override
+    public String toString() {
+        final StringBuilder sb = new StringBuilder();
+        sb.append("SubscriptionJsonWithEvents");
+        sb.append("{events=").append(events);
+        sb.append(", deletedEvents=").append(deletedEvents);
+        sb.append(", newEvents=").append(newEvents);
+        sb.append('}');
+        return sb.toString();
+    }
+
+    @Override
     public boolean equals(final Object o) {
         if (this == o) {
             return true;
diff --git a/jaxrs/src/main/java/com/ning/billing/jaxrs/resources/AccountResource.java b/jaxrs/src/main/java/com/ning/billing/jaxrs/resources/AccountResource.java
index d06ec99..3c97ee0 100644
--- a/jaxrs/src/main/java/com/ning/billing/jaxrs/resources/AccountResource.java
+++ b/jaxrs/src/main/java/com/ning/billing/jaxrs/resources/AccountResource.java
@@ -220,30 +220,21 @@ public class AccountResource extends JaxRsResourceBase {
     @Path("/{accountId:" + UUID_PATTERN + "}/" + TIMELINE)
     @Produces(APPLICATION_JSON)
     public Response getAccountTimeline(@PathParam("accountId") final String accountIdString,
-                                       @QueryParam(QUERY_AUDIT) @DefaultValue("false") final Boolean withAudit) throws AccountApiException, PaymentApiException, EntitlementRepairException {
+                                       @QueryParam(QUERY_AUDIT) @DefaultValue("NONE") final AuditMode auditMode) throws AccountApiException, PaymentApiException, EntitlementRepairException {
         final UUID accountId = UUID.fromString(accountIdString);
         final Account account = accountApi.getAccountById(accountId);
 
         // Get the invoices
         final List<Invoice> invoices = invoiceApi.getInvoicesByAccount(account.getId());
-        AuditLogsForInvoices invoicesAuditLogs = null;
-        if (withAudit) {
-            invoicesAuditLogs = auditUserApi.getAuditLogsForInvoices(invoices);
-        }
+        final AuditLogsForInvoices invoicesAuditLogs = auditUserApi.getAuditLogsForInvoices(invoices, auditMode.getLevel());
 
         // Get the payments
         final List<Payment> payments = paymentApi.getAccountPayments(accountId);
-        AuditLogsForPayments paymentsAuditLogs = null;
-        if (withAudit) {
-            paymentsAuditLogs = auditUserApi.getAuditLogsForPayments(payments);
-        }
+        final AuditLogsForPayments paymentsAuditLogs = auditUserApi.getAuditLogsForPayments(payments, auditMode.getLevel());
 
         // Get the refunds
         final List<Refund> refunds = paymentApi.getAccountRefunds(account);
-        AuditLogsForRefunds refundsAuditLogs = null;
-        if (withAudit) {
-            refundsAuditLogs = auditUserApi.getAuditLogsForRefunds(refunds);
-        }
+        final AuditLogsForRefunds refundsAuditLogs = auditUserApi.getAuditLogsForRefunds(refunds, auditMode.getLevel());
         final Multimap<UUID, Refund> refundsByPayment = ArrayListMultimap.<UUID, Refund>create();
         for (final Refund refund : refunds) {
             refundsByPayment.put(refund.getPaymentId(), refund);
@@ -251,10 +242,7 @@ public class AccountResource extends JaxRsResourceBase {
 
         // Get the chargebacks
         final List<InvoicePayment> chargebacks = invoicePaymentApi.getChargebacksByAccountId(accountId);
-        AuditLogsForInvoicePayments chargebacksAuditLogs = null;
-        if (withAudit) {
-            chargebacksAuditLogs = auditUserApi.getAuditLogsForInvoicePayments(chargebacks);
-        }
+        final AuditLogsForInvoicePayments chargebacksAuditLogs = auditUserApi.getAuditLogsForInvoicePayments(chargebacks, auditMode.getLevel());
         final Multimap<UUID, InvoicePayment> chargebacksByPayment = ArrayListMultimap.<UUID, InvoicePayment>create();
         for (final InvoicePayment chargeback : chargebacks) {
             chargebacksByPayment.put(chargeback.getPaymentId(), chargeback);
@@ -262,14 +250,11 @@ public class AccountResource extends JaxRsResourceBase {
 
         // Get the bundles
         final List<SubscriptionBundle> bundles = entitlementApi.getBundlesForAccount(account.getId());
-        AuditLogsForBundles bundlesAuditLogs = null;
-        if (withAudit) {
-            bundlesAuditLogs = auditUserApi.getAuditLogsForBundles(bundles);
-        }
         final List<BundleTimeline> bundlesTimeline = new LinkedList<BundleTimeline>();
         for (final SubscriptionBundle bundle : bundles) {
             bundlesTimeline.add(timelineApi.getBundleTimeline(bundle.getId()));
         }
+        final AuditLogsForBundles bundlesAuditLogs = auditUserApi.getAuditLogsForBundles(bundlesTimeline, auditMode.getLevel());
 
         final AccountTimelineJson json = new AccountTimelineJson(account, invoices, payments, bundlesTimeline,
                                                                  refundsByPayment, chargebacksByPayment,
diff --git a/jaxrs/src/main/java/com/ning/billing/jaxrs/resources/AuditMode.java b/jaxrs/src/main/java/com/ning/billing/jaxrs/resources/AuditMode.java
new file mode 100644
index 0000000..e9ea7a1
--- /dev/null
+++ b/jaxrs/src/main/java/com/ning/billing/jaxrs/resources/AuditMode.java
@@ -0,0 +1,68 @@
+/*
+ * Copyright 2010-2012 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.jaxrs.resources;
+
+import com.ning.billing.util.api.AuditLevel;
+
+public class AuditMode {
+
+    private final AuditLevel level;
+
+    public AuditMode(final String auditModeString) {
+        this.level = AuditLevel.valueOf(auditModeString.toUpperCase());
+    }
+
+    public AuditLevel getLevel() {
+        return level;
+    }
+
+    public boolean withAudit() {
+        return !AuditLevel.NONE.equals(level);
+    }
+
+    @Override
+    public String toString() {
+        final StringBuilder sb = new StringBuilder();
+        sb.append("AuditMode");
+        sb.append("{level=").append(level);
+        sb.append('}');
+        return sb.toString();
+    }
+
+    @Override
+    public boolean equals(final Object o) {
+        if (this == o) {
+            return true;
+        }
+        if (o == null || getClass() != o.getClass()) {
+            return false;
+        }
+
+        final AuditMode auditMode = (AuditMode) o;
+
+        if (level != auditMode.level) {
+            return false;
+        }
+
+        return true;
+    }
+
+    @Override
+    public int hashCode() {
+        return level != null ? level.hashCode() : 0;
+    }
+}
diff --git a/jaxrs/src/main/java/com/ning/billing/jaxrs/resources/BundleResource.java b/jaxrs/src/main/java/com/ning/billing/jaxrs/resources/BundleResource.java
index 889795d..81429b4 100644
--- a/jaxrs/src/main/java/com/ning/billing/jaxrs/resources/BundleResource.java
+++ b/jaxrs/src/main/java/com/ning/billing/jaxrs/resources/BundleResource.java
@@ -95,7 +95,6 @@ public class BundleResource extends JaxRsResourceBase {
         return Response.status(Status.OK).entity(json).build();
     }
 
-
     @POST
     @Consumes(APPLICATION_JSON)
     @Produces(APPLICATION_JSON)
@@ -122,7 +121,7 @@ public class BundleResource extends JaxRsResourceBase {
         final Collection<SubscriptionJsonNoEvents> result = Collections2.transform(bundles, new Function<Subscription, SubscriptionJsonNoEvents>() {
             @Override
             public SubscriptionJsonNoEvents apply(final Subscription input) {
-                return new SubscriptionJsonNoEvents(input);
+                return new SubscriptionJsonNoEvents(input, null);
             }
         });
         return Response.status(Status.OK).entity(result).build();
@@ -173,19 +172,19 @@ public class BundleResource extends JaxRsResourceBase {
     @Consumes(APPLICATION_JSON)
     @Produces(APPLICATION_JSON)
     public Response transferBundle(@PathParam(ID_PARAM_NAME) final String id,
-            @QueryParam(QUERY_REQUESTED_DT) final String requestedDate,
-            @QueryParam(QUERY_BUNDLE_TRANSFER_ADDON) @DefaultValue("true") final Boolean transferAddOn,
-            @QueryParam(QUERY_BUNDLE_TRANSFER_CANCEL_IMM) @DefaultValue("false") final Boolean cancelImmediatley,
-            final BundleJsonNoSubscriptions json,
-            @HeaderParam(HDR_CREATED_BY) final String createdBy,
-            @HeaderParam(HDR_REASON) final String reason,
-            @HeaderParam(HDR_COMMENT) final String comment,
-            @javax.ws.rs.core.Context final UriInfo uriInfo) throws EntitlementUserApiException, EntitlementTransferApiException {
+                                   @QueryParam(QUERY_REQUESTED_DT) final String requestedDate,
+                                   @QueryParam(QUERY_BUNDLE_TRANSFER_ADDON) @DefaultValue("true") final Boolean transferAddOn,
+                                   @QueryParam(QUERY_BUNDLE_TRANSFER_CANCEL_IMM) @DefaultValue("false") final Boolean cancelImmediatley,
+                                   final BundleJsonNoSubscriptions json,
+                                   @HeaderParam(HDR_CREATED_BY) final String createdBy,
+                                   @HeaderParam(HDR_REASON) final String reason,
+                                   @HeaderParam(HDR_COMMENT) final String comment,
+                                   @javax.ws.rs.core.Context final UriInfo uriInfo) throws EntitlementUserApiException, EntitlementTransferApiException {
 
         final SubscriptionBundle bundle = entitlementApi.getBundleFromId(UUID.fromString(id));
         final DateTime inputDate = (requestedDate != null) ? DATE_TIME_FORMATTER.parseDateTime(requestedDate) : null;
         final SubscriptionBundle newBundle = transferApi.transferBundle(bundle.getAccountId(), UUID.fromString(json.getAccountId()), bundle.getKey(), inputDate, transferAddOn,
-                cancelImmediatley, context.createContext(createdBy, reason, comment));
+                                                                        cancelImmediatley, context.createContext(createdBy, reason, comment));
 
         return uriBuilder.buildResponse(BundleResource.class, "getBundle", newBundle.getId(), uriInfo.getBaseUri().toString());
     }
diff --git a/jaxrs/src/main/java/com/ning/billing/jaxrs/resources/InvoiceResource.java b/jaxrs/src/main/java/com/ning/billing/jaxrs/resources/InvoiceResource.java
index 816eaf3..73f981f 100644
--- a/jaxrs/src/main/java/com/ning/billing/jaxrs/resources/InvoiceResource.java
+++ b/jaxrs/src/main/java/com/ning/billing/jaxrs/resources/InvoiceResource.java
@@ -38,8 +38,6 @@ import javax.ws.rs.core.UriInfo;
 
 import org.joda.time.DateTime;
 import org.joda.time.LocalDate;
-import org.joda.time.format.DateTimeFormatter;
-import org.joda.time.format.ISODateTimeFormat;
 import org.slf4j.Logger;
 import org.slf4j.LoggerFactory;
 
@@ -85,8 +83,6 @@ public class InvoiceResource extends JaxRsResourceBase {
     private static final String CUSTOM_FIELD_URI = JaxrsResource.CUSTOM_FIELDS + "/{" + ID_PARAM_NAME + ":" + UUID_PATTERN + "}";
     private static final String TAG_URI = JaxrsResource.TAGS + "/{" + ID_PARAM_NAME + ":" + UUID_PATTERN + "}";
 
-    private final DateTimeFormatter DATE_TIME_FORMATTER = ISODateTimeFormat.dateTime();
-
     private final AccountUserApi accountApi;
     private final InvoiceUserApi invoiceApi;
     private final PaymentApi paymentApi;
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 7066e05..1f08c34 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
@@ -61,7 +61,7 @@ public abstract class JaxRsResourceBase implements JaxrsResource {
     protected final CustomFieldUserApi customFieldUserApi;
     protected final AuditUserApi auditUserApi;
 
-    protected final DateTimeFormatter DATE_TIME_FORMATTER = ISODateTimeFormat.dateTime();
+    protected final DateTimeFormatter DATE_TIME_FORMATTER = ISODateTimeFormat.dateTimeParser();
 
     public JaxRsResourceBase(final JaxrsUriBuilder uriBuilder,
                              final TagUserApi tagUserApi,
diff --git a/jaxrs/src/main/java/com/ning/billing/jaxrs/resources/SubscriptionResource.java b/jaxrs/src/main/java/com/ning/billing/jaxrs/resources/SubscriptionResource.java
index 69ebb23..68dacad 100644
--- a/jaxrs/src/main/java/com/ning/billing/jaxrs/resources/SubscriptionResource.java
+++ b/jaxrs/src/main/java/com/ning/billing/jaxrs/resources/SubscriptionResource.java
@@ -102,7 +102,7 @@ public class SubscriptionResource extends JaxRsResourceBase {
     public Response getSubscription(@PathParam("subscriptionId") final String subscriptionId) throws EntitlementUserApiException {
         final UUID uuid = UUID.fromString(subscriptionId);
         final Subscription subscription = entitlementApi.getSubscriptionFromId(uuid);
-        final SubscriptionJsonNoEvents json = new SubscriptionJsonNoEvents(subscription);
+        final SubscriptionJsonNoEvents json = new SubscriptionJsonNoEvents(subscription, null);
         return Response.status(Status.OK).entity(json).build();
     }
 
diff --git a/jaxrs/src/test/java/com/ning/billing/jaxrs/json/TestBundleJsonWithSubscriptions.java b/jaxrs/src/test/java/com/ning/billing/jaxrs/json/TestBundleJsonWithSubscriptions.java
index 36e328b..8f3ac82 100644
--- a/jaxrs/src/test/java/com/ning/billing/jaxrs/json/TestBundleJsonWithSubscriptions.java
+++ b/jaxrs/src/test/java/com/ning/billing/jaxrs/json/TestBundleJsonWithSubscriptions.java
@@ -33,9 +33,11 @@ import com.ning.billing.entitlement.api.SubscriptionTransitionType;
 import com.ning.billing.entitlement.api.timeline.BundleTimeline;
 import com.ning.billing.entitlement.api.timeline.SubscriptionTimeline;
 import com.ning.billing.jaxrs.JaxrsTestSuite;
+import com.ning.billing.util.audit.AuditLog;
 import com.ning.billing.util.clock.DefaultClock;
 
 import com.google.common.collect.ImmutableList;
+import com.google.common.collect.ImmutableMap;
 
 public class TestBundleJsonWithSubscriptions extends JaxrsTestSuite {
 
@@ -58,7 +60,7 @@ public class TestBundleJsonWithSubscriptions extends JaxrsTestSuite {
 
         final UUID bundleId = UUID.randomUUID();
         final String externalKey = UUID.randomUUID().toString();
-        final SubscriptionJsonWithEvents subscription = new SubscriptionJsonWithEvents(bundleId, subscriptionTimeline);
+        final SubscriptionJsonWithEvents subscription = new SubscriptionJsonWithEvents(bundleId, subscriptionTimeline, null, ImmutableMap.<UUID, List<AuditLog>>of());
         final List<AuditLogJson> auditLogs = createAuditLogsJson();
         final BundleJsonWithSubscriptions bundleJsonWithSubscriptions = new BundleJsonWithSubscriptions(bundleId.toString(), externalKey, ImmutableList.<SubscriptionJsonWithEvents>of(subscription), auditLogs);
         Assert.assertEquals(bundleJsonWithSubscriptions.getBundleId(), bundleId.toString());
@@ -95,7 +97,9 @@ public class TestBundleJsonWithSubscriptions extends JaxrsTestSuite {
         Mockito.when(bundleTimeline.getExternalKey()).thenReturn(externalKey);
         Mockito.when(bundleTimeline.getSubscriptions()).thenReturn(ImmutableList.<SubscriptionTimeline>of(subscriptionTimeline));
 
-        final BundleJsonWithSubscriptions bundleJsonWithSubscriptions = new BundleJsonWithSubscriptions(null, bundleTimeline, null);
+        final BundleJsonWithSubscriptions bundleJsonWithSubscriptions = new BundleJsonWithSubscriptions(bundleTimeline, null,
+                                                                                                        ImmutableMap.<UUID, List<AuditLog>>of(),
+                                                                                                        ImmutableMap.<UUID, List<AuditLog>>of());
         Assert.assertEquals(bundleJsonWithSubscriptions.getBundleId(), bundleId.toString());
         Assert.assertEquals(bundleJsonWithSubscriptions.getExternalKey(), externalKey);
         Assert.assertEquals(bundleJsonWithSubscriptions.getSubscriptions().size(), 1);
@@ -117,7 +121,9 @@ public class TestBundleJsonWithSubscriptions extends JaxrsTestSuite {
         Mockito.when(bundle.getBundleId()).thenReturn(bundleId);
         Mockito.when(bundle.getExternalKey()).thenReturn(externalKey);
 
-        final BundleJsonWithSubscriptions bundleJsonWithSubscriptions = new BundleJsonWithSubscriptions(null, bundle, null);
+        final BundleJsonWithSubscriptions bundleJsonWithSubscriptions = new BundleJsonWithSubscriptions(bundle, null,
+                                                                                                        ImmutableMap.<UUID, List<AuditLog>>of(),
+                                                                                                        ImmutableMap.<UUID, List<AuditLog>>of());
         Assert.assertEquals(bundleJsonWithSubscriptions.getBundleId(), bundleId.toString());
         Assert.assertEquals(bundleJsonWithSubscriptions.getExternalKey(), externalKey);
         Assert.assertEquals(bundleJsonWithSubscriptions.getSubscriptions().size(), 0);
diff --git a/jaxrs/src/test/java/com/ning/billing/jaxrs/json/TestBundleTimelineJson.java b/jaxrs/src/test/java/com/ning/billing/jaxrs/json/TestBundleTimelineJson.java
index 17df65d..572b678 100644
--- a/jaxrs/src/test/java/com/ning/billing/jaxrs/json/TestBundleTimelineJson.java
+++ b/jaxrs/src/test/java/com/ning/billing/jaxrs/json/TestBundleTimelineJson.java
@@ -17,6 +17,7 @@
 package com.ning.billing.jaxrs.json;
 
 import java.math.BigDecimal;
+import java.util.List;
 import java.util.UUID;
 
 import org.joda.time.DateTime;
@@ -32,10 +33,12 @@ import com.ning.billing.catalog.api.ProductCategory;
 import com.ning.billing.entitlement.api.SubscriptionTransitionType;
 import com.ning.billing.entitlement.api.timeline.SubscriptionTimeline;
 import com.ning.billing.jaxrs.JaxrsTestSuite;
+import com.ning.billing.util.audit.AuditLog;
 import com.ning.billing.util.clock.Clock;
 import com.ning.billing.util.clock.DefaultClock;
 
 import com.google.common.collect.ImmutableList;
+import com.google.common.collect.ImmutableMap;
 
 public class TestBundleTimelineJson extends JaxrsTestSuite {
 
@@ -80,7 +83,7 @@ public class TestBundleTimelineJson extends JaxrsTestSuite {
 
         final UUID bundleId = UUID.randomUUID();
         final String externalKey = UUID.randomUUID().toString();
-        final SubscriptionJsonWithEvents subscription = new SubscriptionJsonWithEvents(bundleId, subscriptionTimeline);
+        final SubscriptionJsonWithEvents subscription = new SubscriptionJsonWithEvents(bundleId, subscriptionTimeline, null, ImmutableMap.<UUID, List<AuditLog>>of());
 
         return new BundleJsonWithSubscriptions(bundleId.toString(), externalKey, ImmutableList.<SubscriptionJsonWithEvents>of(subscription), null);
     }
diff --git a/jaxrs/src/test/java/com/ning/billing/jaxrs/json/TestSubscriptionJsonNoEvents.java b/jaxrs/src/test/java/com/ning/billing/jaxrs/json/TestSubscriptionJsonNoEvents.java
index d4e62f0..34ada37 100644
--- a/jaxrs/src/test/java/com/ning/billing/jaxrs/json/TestSubscriptionJsonNoEvents.java
+++ b/jaxrs/src/test/java/com/ning/billing/jaxrs/json/TestSubscriptionJsonNoEvents.java
@@ -16,6 +16,7 @@
 
 package com.ning.billing.jaxrs.json;
 
+import java.util.List;
 import java.util.UUID;
 
 import org.joda.time.DateTime;
@@ -24,9 +25,6 @@ import org.mockito.Mockito;
 import org.testng.Assert;
 import org.testng.annotations.Test;
 
-import com.fasterxml.jackson.databind.ObjectMapper;
-import com.fasterxml.jackson.databind.SerializationFeature;
-import com.fasterxml.jackson.datatype.joda.JodaModule;
 import com.ning.billing.catalog.api.BillingPeriod;
 import com.ning.billing.catalog.api.InternationalPrice;
 import com.ning.billing.catalog.api.Plan;
@@ -37,7 +35,12 @@ import com.ning.billing.catalog.api.ProductCategory;
 import com.ning.billing.entitlement.api.user.Subscription;
 import com.ning.billing.jaxrs.JaxrsTestSuite;
 
+import com.fasterxml.jackson.databind.ObjectMapper;
+import com.fasterxml.jackson.databind.SerializationFeature;
+import com.fasterxml.jackson.datatype.joda.JodaModule;
+
 public class TestSubscriptionJsonNoEvents extends JaxrsTestSuite {
+
     private static final ObjectMapper mapper = new ObjectMapper();
 
     static {
@@ -56,10 +59,11 @@ public class TestSubscriptionJsonNoEvents extends JaxrsTestSuite {
         final String priceList = UUID.randomUUID().toString();
         final DateTime chargedThroughDate = new DateTime(DateTimeZone.UTC);
         final DateTime endDate = new DateTime(DateTimeZone.UTC);
-
+        final List<AuditLogJson> auditLogs = createAuditLogsJson();
         final SubscriptionJsonNoEvents subscriptionJsonNoEvents = new SubscriptionJsonNoEvents(subscriptionId, bundleId, startDate,
                                                                                                productName, productCategory, billingPeriod,
-                                                                                               priceList, chargedThroughDate, endDate);
+                                                                                               priceList, chargedThroughDate, endDate,
+                                                                                               auditLogs);
         Assert.assertEquals(subscriptionJsonNoEvents.getSubscriptionId(), subscriptionId);
         Assert.assertEquals(subscriptionJsonNoEvents.getBundleId(), bundleId);
         Assert.assertEquals(subscriptionJsonNoEvents.getStartDate(), startDate);
@@ -68,17 +72,9 @@ public class TestSubscriptionJsonNoEvents extends JaxrsTestSuite {
         Assert.assertEquals(subscriptionJsonNoEvents.getBillingPeriod(), billingPeriod);
         Assert.assertEquals(subscriptionJsonNoEvents.getPriceList(), priceList);
         Assert.assertEquals(subscriptionJsonNoEvents.getChargedThroughDate(), chargedThroughDate);
+        Assert.assertEquals(subscriptionJsonNoEvents.getAuditLogs(), auditLogs);
 
         final String asJson = mapper.writeValueAsString(subscriptionJsonNoEvents);
-        Assert.assertEquals(asJson, "{\"subscriptionId\":\"" + subscriptionJsonNoEvents.getSubscriptionId() + "\"," +
-                "\"bundleId\":\"" + subscriptionJsonNoEvents.getBundleId() + "\"," +
-                "\"startDate\":\"" + subscriptionJsonNoEvents.getStartDate().toDateTimeISO().toString() + "\"," +
-                "\"productName\":\"" + subscriptionJsonNoEvents.getProductName() + "\"," +
-                "\"productCategory\":\"" + subscriptionJsonNoEvents.getProductCategory() + "\"," +
-                "\"billingPeriod\":\"" + subscriptionJsonNoEvents.getBillingPeriod() + "\"," +
-                "\"priceList\":\"" + subscriptionJsonNoEvents.getPriceList() + "\"," +
-                "\"chargedThroughDate\":\"" + subscriptionJsonNoEvents.getChargedThroughDate().toDateTimeISO().toString() + "\"," +
-                "\"cancelledDate\":\"" + subscriptionJsonNoEvents.getCancelledDate().toDateTimeISO().toString() + "\"}");
 
         final SubscriptionJsonNoEvents fromJson = mapper.readValue(asJson, SubscriptionJsonNoEvents.class);
         Assert.assertEquals(fromJson, subscriptionJsonNoEvents);
@@ -110,7 +106,7 @@ public class TestSubscriptionJsonNoEvents extends JaxrsTestSuite {
         Mockito.when(subscription.getCurrentPriceList()).thenReturn(priceList);
         Mockito.when(subscription.getChargedThroughDate()).thenReturn(new DateTime(DateTimeZone.UTC));
 
-        final SubscriptionJsonNoEvents subscriptionJsonNoEvents = new SubscriptionJsonNoEvents(subscription);
+        final SubscriptionJsonNoEvents subscriptionJsonNoEvents = new SubscriptionJsonNoEvents(subscription, null);
         Assert.assertEquals(subscriptionJsonNoEvents.getSubscriptionId(), subscription.getId().toString());
         Assert.assertEquals(subscriptionJsonNoEvents.getStartDate(), subscription.getStartDate());
         Assert.assertEquals(subscriptionJsonNoEvents.getBundleId(), subscription.getBundleId().toString());
@@ -118,5 +114,6 @@ public class TestSubscriptionJsonNoEvents extends JaxrsTestSuite {
         Assert.assertEquals(subscriptionJsonNoEvents.getProductCategory(), subscription.getCurrentPlan().getProduct().getCategory().toString());
         Assert.assertEquals(subscriptionJsonNoEvents.getBillingPeriod(), subscription.getCurrentPlan().getBillingPeriod().toString());
         Assert.assertEquals(subscriptionJsonNoEvents.getChargedThroughDate(), subscription.getChargedThroughDate());
+        Assert.assertNull(subscriptionJsonNoEvents.getAuditLogs());
     }
 }
diff --git a/jaxrs/src/test/java/com/ning/billing/jaxrs/json/TestSubscriptionJsonSimple.java b/jaxrs/src/test/java/com/ning/billing/jaxrs/json/TestSubscriptionJsonSimple.java
index e4631f9..a4ab2fc 100644
--- a/jaxrs/src/test/java/com/ning/billing/jaxrs/json/TestSubscriptionJsonSimple.java
+++ b/jaxrs/src/test/java/com/ning/billing/jaxrs/json/TestSubscriptionJsonSimple.java
@@ -16,25 +16,25 @@
 
 package com.ning.billing.jaxrs.json;
 
+import java.util.List;
 import java.util.UUID;
 
 import org.testng.Assert;
 import org.testng.annotations.Test;
 
-import com.fasterxml.jackson.databind.ObjectMapper;
 import com.ning.billing.jaxrs.JaxrsTestSuite;
 
 public class TestSubscriptionJsonSimple extends JaxrsTestSuite {
-    private static final ObjectMapper mapper = new ObjectMapper();
 
     @Test(groups = "fast")
     public void testJson() throws Exception {
         final String subscriptionId = UUID.randomUUID().toString();
-        final SubscriptionJsonSimple subscriptionJsonSimple = new SubscriptionJsonSimple(subscriptionId);
+        final List<AuditLogJson> auditLogs = createAuditLogsJson();
+        final SubscriptionJsonSimple subscriptionJsonSimple = new SubscriptionJsonSimple(subscriptionId, auditLogs);
         Assert.assertEquals(subscriptionJsonSimple.getSubscriptionId(), subscriptionId);
+        Assert.assertEquals(subscriptionJsonSimple.getAuditLogs(), auditLogs);
 
         final String asJson = mapper.writeValueAsString(subscriptionJsonSimple);
-        Assert.assertEquals(asJson, "{\"subscriptionId\":\"" + subscriptionJsonSimple.getSubscriptionId() + "\"}");
 
         final SubscriptionJsonSimple fromJson = mapper.readValue(asJson, SubscriptionJsonSimple.class);
         Assert.assertEquals(fromJson, subscriptionJsonSimple);
diff --git a/jaxrs/src/test/java/com/ning/billing/jaxrs/json/TestSubscriptionJsonWithEvents.java b/jaxrs/src/test/java/com/ning/billing/jaxrs/json/TestSubscriptionJsonWithEvents.java
index a0dac08..010de17 100644
--- a/jaxrs/src/test/java/com/ning/billing/jaxrs/json/TestSubscriptionJsonWithEvents.java
+++ b/jaxrs/src/test/java/com/ning/billing/jaxrs/json/TestSubscriptionJsonWithEvents.java
@@ -16,6 +16,7 @@
 
 package com.ning.billing.jaxrs.json;
 
+import java.util.List;
 import java.util.UUID;
 
 import org.joda.time.DateTime;
@@ -24,10 +25,6 @@ import org.mockito.Mockito;
 import org.testng.Assert;
 import org.testng.annotations.Test;
 
-import com.fasterxml.jackson.databind.ObjectMapper;
-import com.fasterxml.jackson.databind.SerializationFeature;
-import com.fasterxml.jackson.datatype.joda.JodaModule;
-import com.google.common.collect.ImmutableList;
 import com.ning.billing.catalog.api.BillingPeriod;
 import com.ning.billing.catalog.api.PhaseType;
 import com.ning.billing.catalog.api.PlanPhaseSpecifier;
@@ -36,15 +33,13 @@ import com.ning.billing.entitlement.api.SubscriptionTransitionType;
 import com.ning.billing.entitlement.api.timeline.SubscriptionTimeline;
 import com.ning.billing.entitlement.api.user.Subscription;
 import com.ning.billing.jaxrs.JaxrsTestSuite;
+import com.ning.billing.util.audit.AuditLog;
 import com.ning.billing.util.clock.DefaultClock;
 
-public class TestSubscriptionJsonWithEvents extends JaxrsTestSuite {
-    private static final ObjectMapper mapper = new ObjectMapper();
+import com.google.common.collect.ImmutableList;
+import com.google.common.collect.ImmutableMap;
 
-    static {
-        mapper.registerModule(new JodaModule());
-        mapper.disable(SerializationFeature.WRITE_DATES_AS_TIMESTAMPS);
-    }
+public class TestSubscriptionJsonWithEvents extends JaxrsTestSuite {
 
     @Test(groups = "fast")
     public void testJson() throws Exception {
@@ -52,6 +47,7 @@ public class TestSubscriptionJsonWithEvents extends JaxrsTestSuite {
         final DateTime requestedDate = DefaultClock.toUTCDateTime(new DateTime(DateTimeZone.UTC));
         final DateTime effectiveDate = DefaultClock.toUTCDateTime(new DateTime(DateTimeZone.UTC));
         final UUID eventId = UUID.randomUUID();
+        final List<AuditLogJson> auditLogs = createAuditLogsJson();
         final SubscriptionJsonWithEvents.SubscriptionReadEventJson newEvent = new SubscriptionJsonWithEvents.SubscriptionReadEventJson(eventId.toString(),
                                                                                                                                        BillingPeriod.NO_BILLING_PERIOD.toString(),
                                                                                                                                        requestedDate,
@@ -59,25 +55,15 @@ public class TestSubscriptionJsonWithEvents extends JaxrsTestSuite {
                                                                                                                                        UUID.randomUUID().toString(),
                                                                                                                                        UUID.randomUUID().toString(),
                                                                                                                                        SubscriptionTransitionType.CREATE.toString(),
-                                                                                                                                       PhaseType.DISCOUNT.toString());
+                                                                                                                                       PhaseType.DISCOUNT.toString(),
+                                                                                                                                       auditLogs);
         final SubscriptionJsonWithEvents subscriptionJsonWithEvents = new SubscriptionJsonWithEvents(subscriptionId,
                                                                                                      ImmutableList.<SubscriptionJsonWithEvents.SubscriptionReadEventJson>of(newEvent),
                                                                                                      null,
+                                                                                                     null,
                                                                                                      null);
 
         final String asJson = mapper.writeValueAsString(subscriptionJsonWithEvents);
-        final SubscriptionJsonWithEvents.SubscriptionReadEventJson event = subscriptionJsonWithEvents.getEvents().get(0);
-        Assert.assertEquals(asJson, "{\"events\":[{\"eventId\":\"" + event.getEventId() + "\"," +
-                "\"billingPeriod\":\"" + event.getBillingPeriod() + "\"," +
-                "\"product\":\"" + event.getProduct() + "\"," +
-                "\"priceList\":\"" + event.getPriceList() + "\"," +
-                "\"eventType\":\"" + event.getEventType() + "\"," +
-                "\"phase\":\"" + event.getPhase() + "\"," +
-                "\"requestedDate\":\"" + event.getRequestedDate() + "\"," +
-                "\"effectiveDate\":\"" + event.getEffectiveDate() + "\"}]," +
-                "\"subscriptionId\":\"" + subscriptionJsonWithEvents.getSubscriptionId() + "\"," +
-                "\"deletedEvents\":null," +
-                "\"newEvents\":null}");
 
         final SubscriptionJsonWithEvents fromJson = mapper.readValue(asJson, SubscriptionJsonWithEvents.class);
         Assert.assertEquals(fromJson, subscriptionJsonWithEvents);
@@ -88,6 +74,7 @@ public class TestSubscriptionJsonWithEvents extends JaxrsTestSuite {
         final DateTime requestedDate = DefaultClock.toUTCDateTime(new DateTime(DateTimeZone.UTC));
         final DateTime effectiveDate = DefaultClock.toUTCDateTime(new DateTime(DateTimeZone.UTC));
         final UUID eventId = UUID.randomUUID();
+        final List<AuditLogJson> auditLogs = createAuditLogsJson();
         final SubscriptionJsonWithEvents.SubscriptionReadEventJson newEvent = new SubscriptionJsonWithEvents.SubscriptionReadEventJson(eventId.toString(),
                                                                                                                                        BillingPeriod.NO_BILLING_PERIOD.toString(),
                                                                                                                                        requestedDate,
@@ -95,7 +82,8 @@ public class TestSubscriptionJsonWithEvents extends JaxrsTestSuite {
                                                                                                                                        UUID.randomUUID().toString(),
                                                                                                                                        UUID.randomUUID().toString(),
                                                                                                                                        SubscriptionTransitionType.CREATE.toString(),
-                                                                                                                                       PhaseType.DISCOUNT.toString());
+                                                                                                                                       PhaseType.DISCOUNT.toString(),
+                                                                                                                                       auditLogs);
 
         final Subscription subscription = Mockito.mock(Subscription.class);
         Mockito.when(subscription.getId()).thenReturn(UUID.randomUUID());
@@ -103,6 +91,7 @@ public class TestSubscriptionJsonWithEvents extends JaxrsTestSuite {
         final SubscriptionJsonWithEvents subscriptionJsonWithEvents = new SubscriptionJsonWithEvents(subscription,
                                                                                                      ImmutableList.<SubscriptionJsonWithEvents.SubscriptionReadEventJson>of(newEvent),
                                                                                                      null,
+                                                                                                     null,
                                                                                                      null);
         Assert.assertEquals(subscriptionJsonWithEvents.getSubscriptionId(), subscription.getId().toString());
         Assert.assertNull(subscriptionJsonWithEvents.getNewEvents());
@@ -110,6 +99,7 @@ public class TestSubscriptionJsonWithEvents extends JaxrsTestSuite {
         Assert.assertEquals(subscriptionJsonWithEvents.getEvents().size(), 1);
         Assert.assertEquals(subscriptionJsonWithEvents.getEvents().get(0).getEffectiveDate(), newEvent.getEffectiveDate());
         Assert.assertEquals(subscriptionJsonWithEvents.getEvents().get(0).getEventId(), newEvent.getEventId());
+        Assert.assertEquals(subscriptionJsonWithEvents.getEvents().get(0).getAuditLogs(), auditLogs);
     }
 
     @Test(groups = "fast")
@@ -131,7 +121,8 @@ public class TestSubscriptionJsonWithEvents extends JaxrsTestSuite {
 
         final UUID bundleId = UUID.randomUUID();
 
-        final SubscriptionJsonWithEvents subscriptionJsonWithEvents = new SubscriptionJsonWithEvents(bundleId, subscriptionTimeline);
+        final SubscriptionJsonWithEvents subscriptionJsonWithEvents = new SubscriptionJsonWithEvents(bundleId, subscriptionTimeline,
+                                                                                                     null, ImmutableMap.<UUID, List<AuditLog>>of());
         Assert.assertEquals(subscriptionJsonWithEvents.getSubscriptionId(), subscriptionTimeline.getId().toString());
         Assert.assertNull(subscriptionJsonWithEvents.getNewEvents());
         Assert.assertNull(subscriptionJsonWithEvents.getDeletedEvents());
diff --git a/server/src/test/java/com/ning/billing/jaxrs/TestAccount.java b/server/src/test/java/com/ning/billing/jaxrs/TestAccount.java
index c234411..9b62599 100644
--- a/server/src/test/java/com/ning/billing/jaxrs/TestAccount.java
+++ b/server/src/test/java/com/ning/billing/jaxrs/TestAccount.java
@@ -16,14 +16,12 @@
 
 package com.ning.billing.jaxrs;
 
-import java.math.BigDecimal;
 import java.util.HashMap;
 import java.util.LinkedList;
 import java.util.List;
 import java.util.Map;
 import java.util.UUID;
 
-import javax.annotation.Nullable;
 import javax.ws.rs.core.Response.Status;
 
 import org.joda.time.DateTime;
@@ -32,20 +30,14 @@ import org.testng.annotations.Test;
 
 import com.ning.billing.jaxrs.json.AccountJson;
 import com.ning.billing.jaxrs.json.AccountTimelineJson;
-import com.ning.billing.jaxrs.json.AuditLogJson;
 import com.ning.billing.jaxrs.json.BillCycleDayJson;
-import com.ning.billing.jaxrs.json.ChargebackJson;
-import com.ning.billing.jaxrs.json.CreditJson;
 import com.ning.billing.jaxrs.json.CustomFieldJson;
-import com.ning.billing.jaxrs.json.InvoiceJsonSimple;
 import com.ning.billing.jaxrs.json.PaymentJsonSimple;
-import com.ning.billing.jaxrs.json.PaymentJsonWithBundleKeys;
 import com.ning.billing.jaxrs.json.PaymentMethodJson;
 import com.ning.billing.jaxrs.json.RefundJson;
 import com.ning.billing.jaxrs.json.TagDefinitionJson;
 import com.ning.billing.jaxrs.json.TagJson;
 import com.ning.billing.jaxrs.resources.JaxrsResource;
-import com.ning.billing.util.ChangeType;
 import com.ning.http.client.Response;
 
 import com.fasterxml.jackson.core.type.TypeReference;
@@ -112,100 +104,6 @@ public class TestAccount extends TestJaxrsBase {
         Assert.assertEquals(timeline.getBundles().get(0).getSubscriptions().get(0).getEvents().size(), 2);
     }
 
-    @Test
-    public void testAccountTimelineWithAudits() throws Exception {
-        final DateTime startTime = clock.getUTCNow();
-        final AccountJson accountJson = createAccountWithPMBundleAndSubscriptionAndWaitForFirstInvoice();
-        final DateTime endTime = clock.getUTCNow();
-
-        // Add credit
-        final InvoiceJsonSimple invoice = getInvoicesForAccount(accountJson.getAccountId()).get(1);
-        final DateTime creditEffectiveDate = clock.getUTCNow();
-        final BigDecimal creditAmount = BigDecimal.ONE;
-        createCreditForInvoice(accountJson.getAccountId(), invoice.getInvoiceId(),
-                               creditAmount, clock.getUTCNow(), creditEffectiveDate);
-
-        // Add refund
-        final PaymentJsonSimple postedPayment = getPaymentsForAccount(accountJson.getAccountId()).get(0);
-        final BigDecimal refundAmount = BigDecimal.ONE;
-        createRefund(postedPayment.getPaymentId(), refundAmount);
-
-        // Add chargeback
-        final BigDecimal chargebackAmount = BigDecimal.ONE;
-        createChargeBack(postedPayment.getPaymentId(), chargebackAmount);
-
-        final AccountTimelineJson timeline = getAccountTimelineWithAudits(accountJson.getAccountId());
-
-        // Verify payments
-        Assert.assertEquals(timeline.getPayments().size(), 1);
-        final PaymentJsonWithBundleKeys paymentJson = timeline.getPayments().get(0);
-        final List<AuditLogJson> paymentAuditLogs = paymentJson.getAuditLogs();
-        Assert.assertEquals(paymentAuditLogs.size(), 2);
-        verifyAuditLog(paymentAuditLogs.get(0), ChangeType.INSERT, null, null, "PaymentRequestProcessor", startTime, endTime);
-        verifyAuditLog(paymentAuditLogs.get(1), ChangeType.UPDATE, null, null, "PaymentRequestProcessor", startTime, endTime);
-
-        // Verify refunds
-        Assert.assertEquals(paymentJson.getRefunds().size(), 1);
-        final RefundJson refundJson = paymentJson.getRefunds().get(0);
-        Assert.assertEquals(refundJson.getPaymentId(), paymentJson.getPaymentId());
-        Assert.assertEquals(refundJson.getRefundAmount().compareTo(refundAmount), 0);
-        final List<AuditLogJson> refundAuditLogs = refundJson.getAuditLogs();
-        Assert.assertEquals(refundAuditLogs.size(), 3);
-        verifyAuditLog(refundAuditLogs.get(0), ChangeType.INSERT, reason, comment, createdBy, startTime, endTime);
-        verifyAuditLog(refundAuditLogs.get(1), ChangeType.UPDATE, reason, comment, createdBy, startTime, endTime);
-        verifyAuditLog(refundAuditLogs.get(2), ChangeType.UPDATE, reason, comment, createdBy, startTime, endTime);
-
-        // Verify chargebacks
-        Assert.assertEquals(paymentJson.getChargebacks().size(), 1);
-        final ChargebackJson chargebackJson = paymentJson.getChargebacks().get(0);
-        Assert.assertEquals(chargebackJson.getPaymentId(), paymentJson.getPaymentId());
-        Assert.assertEquals(chargebackJson.getChargebackAmount().compareTo(chargebackAmount), 0);
-        final List<AuditLogJson> chargebackAuditLogs = chargebackJson.getAuditLogs();
-        Assert.assertEquals(chargebackAuditLogs.size(), 1);
-        verifyAuditLog(chargebackAuditLogs.get(0), ChangeType.INSERT, reason, comment, createdBy, startTime, endTime);
-
-        // Verify invoices
-        Assert.assertEquals(timeline.getInvoices().size(), 2);
-        final List<AuditLogJson> firstInvoiceAuditLogs = timeline.getInvoices().get(0).getAuditLogs();
-        Assert.assertEquals(firstInvoiceAuditLogs.size(), 1);
-        verifyAuditLog(firstInvoiceAuditLogs.get(0), ChangeType.INSERT, null, null, "Transition", startTime, endTime);
-        final List<AuditLogJson> secondInvoiceAuditLogs = timeline.getInvoices().get(1).getAuditLogs();
-        Assert.assertEquals(secondInvoiceAuditLogs.size(), 1);
-        verifyAuditLog(secondInvoiceAuditLogs.get(0), ChangeType.INSERT, null, null, "Transition", startTime, endTime);
-
-        // Verify credits
-        final List<CreditJson> credits = timeline.getInvoices().get(1).getCredits();
-        Assert.assertEquals(credits.size(), 1);
-        Assert.assertEquals(credits.get(0).getCreditAmount().compareTo(creditAmount.negate()), 0);
-        final List<AuditLogJson> creditAuditLogs = credits.get(0).getAuditLogs();
-        Assert.assertEquals(creditAuditLogs.size(), 1);
-        verifyAuditLog(creditAuditLogs.get(0), ChangeType.INSERT, reason, comment, createdBy, startTime, endTime);
-
-        // Verify bundles
-        Assert.assertEquals(timeline.getBundles().size(), 1);
-        Assert.assertEquals(timeline.getBundles().get(0).getSubscriptions().size(), 1);
-        Assert.assertEquals(timeline.getBundles().get(0).getSubscriptions().get(0).getEvents().size(), 2);
-        final List<AuditLogJson> bundleAuditLogs = timeline.getBundles().get(0).getAuditLogs();
-        Assert.assertEquals(bundleAuditLogs.size(), 3);
-        verifyAuditLog(bundleAuditLogs.get(0), ChangeType.INSERT, reason, comment, createdBy, startTime, endTime);
-        verifyAuditLog(bundleAuditLogs.get(1), ChangeType.UPDATE, null, null, "Transition", startTime, endTime);
-        verifyAuditLog(bundleAuditLogs.get(2), ChangeType.UPDATE, null, null, "Transition", startTime, endTime);
-
-        // TODO subscription events audit logs
-    }
-
-    private void verifyAuditLog(final AuditLogJson auditLogJson, final ChangeType changeType, @Nullable final String reasonCode,
-                                @Nullable final String comments, @Nullable final String changedBy,
-                                final DateTime startTime, final DateTime endTime) {
-        Assert.assertEquals(auditLogJson.getChangeType(), changeType.toString());
-        Assert.assertFalse(auditLogJson.getChangeDate().isBefore(startTime));
-        // Flaky
-        //Assert.assertFalse(auditLogJson.getChangeDate().isAfter(endTime));
-        Assert.assertEquals(auditLogJson.getReasonCode(), reasonCode);
-        Assert.assertEquals(auditLogJson.getComments(), comments);
-        Assert.assertEquals(auditLogJson.getChangedBy(), changedBy);
-    }
-
     @Test(groups = "slow")
     public void testAccountPaymentMethods() throws Exception {
 
diff --git a/server/src/test/java/com/ning/billing/jaxrs/TestAccountTimeline.java b/server/src/test/java/com/ning/billing/jaxrs/TestAccountTimeline.java
new file mode 100644
index 0000000..189add2
--- /dev/null
+++ b/server/src/test/java/com/ning/billing/jaxrs/TestAccountTimeline.java
@@ -0,0 +1,258 @@
+/*
+ * Copyright 2010-2012 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.jaxrs;
+
+import java.math.BigDecimal;
+import java.util.List;
+
+import javax.annotation.Nullable;
+
+import org.joda.time.DateTime;
+import org.testng.Assert;
+import org.testng.annotations.Test;
+
+import com.ning.billing.jaxrs.json.AccountJson;
+import com.ning.billing.jaxrs.json.AccountTimelineJson;
+import com.ning.billing.jaxrs.json.AuditLogJson;
+import com.ning.billing.jaxrs.json.ChargebackJson;
+import com.ning.billing.jaxrs.json.CreditJson;
+import com.ning.billing.jaxrs.json.InvoiceJsonSimple;
+import com.ning.billing.jaxrs.json.PaymentJsonSimple;
+import com.ning.billing.jaxrs.json.PaymentJsonWithBundleKeys;
+import com.ning.billing.jaxrs.json.RefundJson;
+import com.ning.billing.util.ChangeType;
+import com.ning.billing.util.api.AuditLevel;
+
+public class TestAccountTimeline extends TestJaxrsBase {
+
+    private static final String PAYMENT_REQUEST_PROCESSOR = "PaymentRequestProcessor";
+    private static final String TRANSITION = "Transition";
+
+    @Test(groups = "slow")
+    public void testAccountTimelineWithAudits() throws Exception {
+        final DateTime startTime = clock.getUTCNow();
+        final AccountJson accountJson = createAccountWithPMBundleAndSubscriptionAndWaitForFirstInvoice();
+        final DateTime endTime = clock.getUTCNow();
+
+        // Add credit
+        final InvoiceJsonSimple invoice = getInvoicesForAccount(accountJson.getAccountId()).get(1);
+        final DateTime creditEffectiveDate = clock.getUTCNow();
+        final BigDecimal creditAmount = BigDecimal.ONE;
+        createCreditForInvoice(accountJson.getAccountId(), invoice.getInvoiceId(),
+                               creditAmount, clock.getUTCNow(), creditEffectiveDate);
+
+        // Add refund
+        final PaymentJsonSimple postedPayment = getPaymentsForAccount(accountJson.getAccountId()).get(0);
+        final BigDecimal refundAmount = BigDecimal.ONE;
+        createRefund(postedPayment.getPaymentId(), refundAmount);
+
+        // Add chargeback
+        final BigDecimal chargebackAmount = BigDecimal.ONE;
+        createChargeBack(postedPayment.getPaymentId(), chargebackAmount);
+
+        // Verify payments
+        verifyPayments(accountJson.getAccountId(), startTime, endTime, refundAmount, chargebackAmount);
+
+        // Verify invoices
+        verifyInvoices(accountJson.getAccountId(), startTime, endTime);
+
+        // Verify credits
+        verifyCredits(accountJson.getAccountId(), startTime, endTime, creditAmount);
+
+        // Verify bundles
+        verifyBundles(accountJson.getAccountId(), startTime, endTime);
+    }
+
+    private void verifyPayments(final String accountId, final DateTime startTime, final DateTime endTime,
+                                final BigDecimal refundAmount, final BigDecimal chargebackAmount) throws Exception {
+        for (final AuditLevel auditLevel : AuditLevel.values()) {
+            final AccountTimelineJson timeline = getAccountTimelineWithAudits(accountId, auditLevel);
+
+            // Verify payments
+            Assert.assertEquals(timeline.getPayments().size(), 1);
+            final PaymentJsonWithBundleKeys paymentJson = timeline.getPayments().get(0);
+
+            // Verify refunds
+            Assert.assertEquals(paymentJson.getRefunds().size(), 1);
+            final RefundJson refundJson = paymentJson.getRefunds().get(0);
+            Assert.assertEquals(refundJson.getPaymentId(), paymentJson.getPaymentId());
+            Assert.assertEquals(refundJson.getRefundAmount().compareTo(refundAmount), 0);
+
+            // Verify chargebacks
+            Assert.assertEquals(paymentJson.getChargebacks().size(), 1);
+            final ChargebackJson chargebackJson = paymentJson.getChargebacks().get(0);
+            Assert.assertEquals(chargebackJson.getPaymentId(), paymentJson.getPaymentId());
+            Assert.assertEquals(chargebackJson.getChargebackAmount().compareTo(chargebackAmount), 0);
+
+            // Verify audits
+            final List<AuditLogJson> paymentAuditLogs = paymentJson.getAuditLogs();
+            final List<AuditLogJson> refundAuditLogs = refundJson.getAuditLogs();
+            final List<AuditLogJson> chargebackAuditLogs = chargebackJson.getAuditLogs();
+            if (AuditLevel.NONE.equals(auditLevel)) {
+                // Audits for payments
+                Assert.assertEquals(paymentAuditLogs.size(), 0);
+
+                // Audits for refunds
+                Assert.assertEquals(refundAuditLogs.size(), 0);
+
+                // Audits for chargebacks
+                Assert.assertEquals(chargebackAuditLogs.size(), 0);
+            } else if (AuditLevel.MINIMAL.equals(auditLevel)) {
+                // Audits for payments
+                Assert.assertEquals(paymentAuditLogs.size(), 1);
+                verifyAuditLog(paymentAuditLogs.get(0), ChangeType.INSERT, null, null, PAYMENT_REQUEST_PROCESSOR, startTime, endTime);
+
+                // Audits for refunds
+                Assert.assertEquals(refundAuditLogs.size(), 1);
+                verifyAuditLog(refundAuditLogs.get(0), ChangeType.INSERT, reason, comment, createdBy, startTime, endTime);
+
+                // Audits for chargebacks
+                Assert.assertEquals(chargebackAuditLogs.size(), 1);
+                verifyAuditLog(chargebackAuditLogs.get(0), ChangeType.INSERT, reason, comment, createdBy, startTime, endTime);
+            } else {
+                // Audits for payments
+                Assert.assertEquals(paymentAuditLogs.size(), 2);
+                verifyAuditLog(paymentAuditLogs.get(0), ChangeType.INSERT, null, null, PAYMENT_REQUEST_PROCESSOR, startTime, endTime);
+                verifyAuditLog(paymentAuditLogs.get(1), ChangeType.UPDATE, null, null, PAYMENT_REQUEST_PROCESSOR, startTime, endTime);
+
+                // Audits for refunds
+                Assert.assertEquals(refundAuditLogs.size(), 3);
+                verifyAuditLog(refundAuditLogs.get(0), ChangeType.INSERT, reason, comment, createdBy, startTime, endTime);
+                verifyAuditLog(refundAuditLogs.get(1), ChangeType.UPDATE, reason, comment, createdBy, startTime, endTime);
+                verifyAuditLog(refundAuditLogs.get(2), ChangeType.UPDATE, reason, comment, createdBy, startTime, endTime);
+
+                // Audits for chargebacks
+                Assert.assertEquals(chargebackAuditLogs.size(), 1);
+                verifyAuditLog(chargebackAuditLogs.get(0), ChangeType.INSERT, reason, comment, createdBy, startTime, endTime);
+            }
+        }
+    }
+
+    private void verifyInvoices(final String accountId, final DateTime startTime, final DateTime endTime) throws Exception {
+        for (final AuditLevel auditLevel : AuditLevel.values()) {
+            final AccountTimelineJson timeline = getAccountTimelineWithAudits(accountId, auditLevel);
+
+            // Verify invoices
+            Assert.assertEquals(timeline.getInvoices().size(), 2);
+
+            // Verify audits
+            final List<AuditLogJson> firstInvoiceAuditLogs = timeline.getInvoices().get(0).getAuditLogs();
+            final List<AuditLogJson> secondInvoiceAuditLogs = timeline.getInvoices().get(1).getAuditLogs();
+            if (AuditLevel.NONE.equals(auditLevel)) {
+                Assert.assertEquals(firstInvoiceAuditLogs.size(), 0);
+                Assert.assertEquals(secondInvoiceAuditLogs.size(), 0);
+            } else {
+                Assert.assertEquals(firstInvoiceAuditLogs.size(), 1);
+                verifyAuditLog(firstInvoiceAuditLogs.get(0), ChangeType.INSERT, null, null, TRANSITION, startTime, endTime);
+                Assert.assertEquals(secondInvoiceAuditLogs.size(), 1);
+                verifyAuditLog(secondInvoiceAuditLogs.get(0), ChangeType.INSERT, null, null, TRANSITION, startTime, endTime);
+            }
+        }
+    }
+
+    private void verifyCredits(final String accountId, final DateTime startTime, final DateTime endTime, final BigDecimal creditAmount) throws Exception {
+        for (final AuditLevel auditLevel : AuditLevel.values()) {
+            final AccountTimelineJson timeline = getAccountTimelineWithAudits(accountId, auditLevel);
+
+            // Verify credits
+            final List<CreditJson> credits = timeline.getInvoices().get(1).getCredits();
+            Assert.assertEquals(credits.size(), 1);
+            Assert.assertEquals(credits.get(0).getCreditAmount().compareTo(creditAmount.negate()), 0);
+
+            // Verify audits
+            final List<AuditLogJson> creditAuditLogs = credits.get(0).getAuditLogs();
+            if (AuditLevel.NONE.equals(auditLevel)) {
+                Assert.assertEquals(creditAuditLogs.size(), 0);
+            } else {
+                Assert.assertEquals(creditAuditLogs.size(), 1);
+                verifyAuditLog(creditAuditLogs.get(0), ChangeType.INSERT, reason, comment, createdBy, startTime, endTime);
+            }
+        }
+    }
+
+    private void verifyBundles(final String accountId, final DateTime startTime, final DateTime endTime) throws Exception {
+        for (final AuditLevel auditLevel : AuditLevel.values()) {
+            final AccountTimelineJson timeline = getAccountTimelineWithAudits(accountId, auditLevel);
+
+            // Verify bundles
+            Assert.assertEquals(timeline.getBundles().size(), 1);
+            Assert.assertEquals(timeline.getBundles().get(0).getSubscriptions().size(), 1);
+            Assert.assertEquals(timeline.getBundles().get(0).getSubscriptions().get(0).getEvents().size(), 2);
+
+            // Verify audits
+            final List<AuditLogJson> bundleAuditLogs = timeline.getBundles().get(0).getAuditLogs();
+            final List<AuditLogJson> subscriptionAuditLogs = timeline.getBundles().get(0).getSubscriptions().get(0).getAuditLogs();
+            final List<AuditLogJson> subscriptionEvent1AuditLogs = timeline.getBundles().get(0).getSubscriptions().get(0).getEvents().get(0).getAuditLogs();
+            final List<AuditLogJson> subscriptionEvent2AuditLogs = timeline.getBundles().get(0).getSubscriptions().get(0).getEvents().get(1).getAuditLogs();
+            if (AuditLevel.NONE.equals(auditLevel)) {
+                // Audits for bundles
+                Assert.assertEquals(bundleAuditLogs.size(), 0);
+
+                // Audits for subscriptions
+                Assert.assertEquals(subscriptionAuditLogs.size(), 0);
+
+                // Audit for subscription events
+                Assert.assertEquals(subscriptionEvent1AuditLogs.size(), 0);
+                Assert.assertEquals(subscriptionEvent2AuditLogs.size(), 0);
+            } else if (AuditLevel.MINIMAL.equals(auditLevel)) {
+                // Audits for bundles
+                Assert.assertEquals(bundleAuditLogs.size(), 1);
+                verifyAuditLog(bundleAuditLogs.get(0), ChangeType.INSERT, reason, comment, createdBy, startTime, endTime);
+
+                // Audits for subscriptions
+                Assert.assertEquals(subscriptionAuditLogs.size(), 1);
+                verifyAuditLog(subscriptionAuditLogs.get(0), ChangeType.INSERT, reason, comment, createdBy, startTime, endTime);
+
+                // Audit for subscription events
+                Assert.assertEquals(subscriptionEvent1AuditLogs.size(), 1);
+                verifyAuditLog(subscriptionEvent1AuditLogs.get(0), ChangeType.INSERT, reason, comment, createdBy, startTime, endTime);
+                Assert.assertEquals(subscriptionEvent2AuditLogs.size(), 1);
+                verifyAuditLog(subscriptionEvent2AuditLogs.get(0), ChangeType.INSERT, reason, comment, createdBy, startTime, endTime);
+            } else {
+                // Audits for bundles
+                Assert.assertEquals(bundleAuditLogs.size(), 3);
+                verifyAuditLog(bundleAuditLogs.get(0), ChangeType.INSERT, reason, comment, createdBy, startTime, endTime);
+                verifyAuditLog(bundleAuditLogs.get(1), ChangeType.UPDATE, null, null, TRANSITION, startTime, endTime);
+                verifyAuditLog(bundleAuditLogs.get(2), ChangeType.UPDATE, null, null, TRANSITION, startTime, endTime);
+
+                // Audits for subscriptions
+                Assert.assertEquals(subscriptionAuditLogs.size(), 3);
+                verifyAuditLog(subscriptionAuditLogs.get(0), ChangeType.INSERT, reason, comment, createdBy, startTime, endTime);
+                verifyAuditLog(subscriptionAuditLogs.get(1), ChangeType.UPDATE, null, null, TRANSITION, startTime, endTime);
+                verifyAuditLog(subscriptionAuditLogs.get(2), ChangeType.UPDATE, null, null, TRANSITION, startTime, endTime);
+
+                // Audit for subscription events
+                Assert.assertEquals(subscriptionEvent1AuditLogs.size(), 1);
+                verifyAuditLog(subscriptionEvent1AuditLogs.get(0), ChangeType.INSERT, reason, comment, createdBy, startTime, endTime);
+                Assert.assertEquals(subscriptionEvent2AuditLogs.size(), 1);
+                verifyAuditLog(subscriptionEvent2AuditLogs.get(0), ChangeType.INSERT, reason, comment, createdBy, startTime, endTime);
+            }
+        }
+    }
+
+    private void verifyAuditLog(final AuditLogJson auditLogJson, final ChangeType changeType, @Nullable final String reasonCode,
+                                @Nullable final String comments, @Nullable final String changedBy,
+                                final DateTime startTime, final DateTime endTime) {
+        Assert.assertEquals(auditLogJson.getChangeType(), changeType.toString());
+        Assert.assertFalse(auditLogJson.getChangeDate().isBefore(startTime));
+        // Flaky
+        //Assert.assertFalse(auditLogJson.getChangeDate().isAfter(endTime));
+        Assert.assertEquals(auditLogJson.getReasonCode(), reasonCode);
+        Assert.assertEquals(auditLogJson.getComments(), comments);
+        Assert.assertEquals(auditLogJson.getChangedBy(), changedBy);
+    }
+}
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 c8941c2..01d4f46 100644
--- a/server/src/test/java/com/ning/billing/jaxrs/TestJaxrsBase.java
+++ b/server/src/test/java/com/ning/billing/jaxrs/TestJaxrsBase.java
@@ -86,6 +86,7 @@ import com.ning.billing.payment.provider.MockPaymentProviderPluginModule;
 import com.ning.billing.server.ServerTestSuiteWithEmbeddedDB;
 import com.ning.billing.server.listeners.KillbillGuiceListener;
 import com.ning.billing.server.modules.KillbillServerModule;
+import com.ning.billing.util.api.AuditLevel;
 import com.ning.billing.util.clock.Clock;
 import com.ning.billing.util.clock.ClockMock;
 import com.ning.billing.util.email.EmailModule;
@@ -364,17 +365,17 @@ public class TestJaxrsBase extends ServerTestSuiteWithEmbeddedDB {
     }
 
     protected AccountTimelineJson getAccountTimeline(final String accountId) throws Exception {
-        return doGetAccountTimeline(accountId, false);
+        return doGetAccountTimeline(accountId, AuditLevel.NONE);
     }
 
-    protected AccountTimelineJson getAccountTimelineWithAudits(final String accountId) throws Exception {
-        return doGetAccountTimeline(accountId, true);
+    protected AccountTimelineJson getAccountTimelineWithAudits(final String accountId, final AuditLevel auditLevel) throws Exception {
+        return doGetAccountTimeline(accountId, auditLevel);
     }
 
-    private AccountTimelineJson doGetAccountTimeline(final String accountId, final Boolean withAudits) throws Exception {
+    private AccountTimelineJson doGetAccountTimeline(final String accountId, final AuditLevel auditLevel) throws Exception {
         final String uri = JaxrsResource.ACCOUNTS_PATH + "/" + accountId + "/" + JaxrsResource.TIMELINE;
 
-        final Response response = doGet(uri, ImmutableMap.<String, String>of(JaxrsResource.QUERY_AUDIT, withAudits.toString()), DEFAULT_HTTP_TIMEOUT_SEC);
+        final Response response = doGet(uri, ImmutableMap.<String, String>of(JaxrsResource.QUERY_AUDIT, auditLevel.toString()), DEFAULT_HTTP_TIMEOUT_SEC);
         Assert.assertEquals(response.getStatusCode(), Status.OK.getStatusCode());
 
         final String baseJson = response.getResponseBody();
@@ -384,10 +385,17 @@ public class TestJaxrsBase extends ServerTestSuiteWithEmbeddedDB {
         return objFromJson;
     }
 
-    protected AccountJson createAccountWithDefaultPaymentMethod(final String name, final String key, final String email) throws Exception {
+    protected AccountJson createAccountWithDefaultPaymentMethod() throws Exception {
+        final AccountJson input = createAccount();
+        return doCreateAccountWithDefaultPaymentMethod(input);
+    }
 
+    protected AccountJson createAccountWithDefaultPaymentMethod(final String name, final String key, final String email) throws Exception {
         final AccountJson input = createAccount(name, key, email);
+        return doCreateAccountWithDefaultPaymentMethod(input);
+    }
 
+    protected AccountJson doCreateAccountWithDefaultPaymentMethod(final AccountJson input) throws Exception {
         final String uri = JaxrsResource.ACCOUNTS_PATH + "/" + input.getAccountId() + "/" + JaxrsResource.PAYMENT_METHODS;
         final PaymentMethodJson paymentMethodJson = getPaymentMethodJson(input.getAccountId(), null);
         String baseJson = mapper.writeValueAsString(paymentMethodJson);
@@ -466,7 +474,9 @@ public class TestJaxrsBase extends ServerTestSuiteWithEmbeddedDB {
 
     protected SubscriptionJsonNoEvents createSubscription(final String bundleId, final String productName, final String productCategory, final String billingPeriod, final boolean waitCompletion) throws Exception {
 
-        final SubscriptionJsonNoEvents input = new SubscriptionJsonNoEvents(null, bundleId, null, productName, productCategory, billingPeriod, PriceListSet.DEFAULT_PRICELIST_NAME, null, null);
+        final SubscriptionJsonNoEvents input = new SubscriptionJsonNoEvents(null, bundleId, null, productName, productCategory,
+                                                                            billingPeriod, PriceListSet.DEFAULT_PRICELIST_NAME,
+                                                                            null, null, null);
         String baseJson = mapper.writeValueAsString(input);
 
         final Map<String, String> queryParams = waitCompletion ? getQueryParamsForCallCompletion("5") : DEFAULT_EMPTY_QUERY;
@@ -492,11 +502,11 @@ public class TestJaxrsBase extends ServerTestSuiteWithEmbeddedDB {
     //
 
     protected AccountJson createAccountWithPMBundleAndSubscriptionAndWaitForFirstInvoice() throws Exception {
-        final AccountJson accountJson = createAccountWithDefaultPaymentMethod("nohup", "shtergyhwF", "nohup@yahoo.com");
+        final AccountJson accountJson = createAccountWithDefaultPaymentMethod();
         assertNotNull(accountJson);
 
         // Add a bundle, subscription and move the clock to get the first invoice
-        final BundleJsonNoSubscriptions bundleJson = createBundle(accountJson.getAccountId(), "391193");
+        final BundleJsonNoSubscriptions bundleJson = createBundle(accountJson.getAccountId(), UUID.randomUUID().toString());
         assertNotNull(bundleJson);
         final SubscriptionJsonNoEvents subscriptionJson = createSubscription(bundleJson.getBundleId(), "Shotgun", ProductCategory.BASE.toString(), BillingPeriod.MONTHLY.toString(), true);
         assertNotNull(subscriptionJson);
@@ -508,11 +518,11 @@ public class TestJaxrsBase extends ServerTestSuiteWithEmbeddedDB {
 
     protected AccountJson createAccountNoPMBundleAndSubscriptionAndWaitForFirstInvoice() throws Exception {
         // Create an account with no payment method
-        final AccountJson accountJson = createAccount("eraahahildo", "sheqrgfhwe", "eraahahildo@yahoo.com");
+        final AccountJson accountJson = createAccount();
         assertNotNull(accountJson);
 
         // Add a bundle, subscription and move the clock to get the first invoice
-        final BundleJsonNoSubscriptions bundleJson = createBundle(accountJson.getAccountId(), "317199");
+        final BundleJsonNoSubscriptions bundleJson = createBundle(accountJson.getAccountId(), UUID.randomUUID().toString());
         assertNotNull(bundleJson);
         final SubscriptionJsonNoEvents subscriptionJson = createSubscription(bundleJson.getBundleId(), "Shotgun", ProductCategory.BASE.toString(), BillingPeriod.MONTHLY.toString(), true);
         assertNotNull(subscriptionJson);
diff --git a/server/src/test/java/com/ning/billing/jaxrs/TestSubscription.java b/server/src/test/java/com/ning/billing/jaxrs/TestSubscription.java
index 9465e90..298370c 100644
--- a/server/src/test/java/com/ning/billing/jaxrs/TestSubscription.java
+++ b/server/src/test/java/com/ning/billing/jaxrs/TestSubscription.java
@@ -78,7 +78,7 @@ public class TestSubscription extends TestJaxrsBase {
                                                                                newProductName,
                                                                                subscriptionJson.getProductCategory(),
                                                                                subscriptionJson.getBillingPeriod(),
-                                                                               subscriptionJson.getPriceList(), null, null);
+                                                                               subscriptionJson.getPriceList(), null, null, null);
         baseJson = mapper.writeValueAsString(newInput);
 
         final Map<String, String> queryParams = getQueryParamsForCallCompletion(CALL_COMPLETION_TIMEOUT_SEC);
@@ -119,7 +119,7 @@ public class TestSubscription extends TestJaxrsBase {
     public void testWithNonExistentSubscription() throws Exception {
         final String uri = JaxrsResource.SUBSCRIPTIONS_PATH + "/" + UUID.randomUUID().toString();
         final SubscriptionJsonNoEvents subscriptionJson = new SubscriptionJsonNoEvents(null, UUID.randomUUID().toString(), null, "Pistol", ProductCategory.BASE.toString(), BillingPeriod.MONTHLY.toString(),
-                                                                                       PriceListSet.DEFAULT_PRICELIST_NAME, null, null);
+                                                                                       PriceListSet.DEFAULT_PRICELIST_NAME, null, null, null);
         final String baseJson = mapper.writeValueAsString(subscriptionJson);
 
         Response response = doPut(uri, baseJson, DEFAULT_EMPTY_QUERY, DEFAULT_HTTP_TIMEOUT_SEC);
@@ -166,7 +166,8 @@ public class TestSubscription extends TestJaxrsBase {
                                                                                BillingPeriod.MONTHLY.toString(),
                                                                                subscriptionJson.getPriceList(),
                                                                                subscriptionJson.getChargedThroughDate(),
-                                                                               subscriptionJson.getCancelledDate());
+                                                                               subscriptionJson.getCancelledDate(),
+                                                                               null);
         baseJson = mapper.writeValueAsString(newInput);
         final Map<String, String> queryParams = getQueryParamsForCallCompletion(CALL_COMPLETION_TIMEOUT_SEC);
         queryParams.put(JaxrsResource.QUERY_POLICY, "immediate");
diff --git a/usage/src/main/resources/com/ning/billing/usage/ddl.sql b/usage/src/main/resources/com/ning/billing/usage/ddl.sql
index fab0ce2..b424075 100644
--- a/usage/src/main/resources/com/ning/billing/usage/ddl.sql
+++ b/usage/src/main/resources/com/ning/billing/usage/ddl.sql
@@ -9,11 +9,11 @@ create table sources (
 , account_record_id int(11) unsigned default null
 , tenant_record_id int(11) unsigned default null
 , primary key(record_id)
-, index created_dt_record_id_dx (created_dt, record_id)
+, index created_date_record_id_dx (created_date, record_id)
 ) engine = innodb default charset = latin1;
 
 create table event_categories (
-  event_category_id integer not null auto_increment
+  record_id integer not null auto_increment
 , event_category varchar(256) not null
 , tenant_record_id int(11) unsigned default null
 , primary key(record_id)
@@ -51,7 +51,7 @@ create table last_start_times (
 , start_times mediumtext not null
 ) engine = innodb default charset = latin1;
 
-insert ignore into timeline_chunks(chunk_id, source_id, metric_id, sample_count, start_time, end_time, in_row_samples, blob_samples)
+insert ignore into timeline_chunks(record_id, source_id, metric_id, sample_count, start_time, end_time, in_row_samples, blob_samples)
                            values (0, 0, 0, 0, 0, 0, null, null);
 
 create table timeline_rolled_up_chunk (
diff --git a/util/src/main/java/com/ning/billing/util/audit/api/DefaultAuditUserApi.java b/util/src/main/java/com/ning/billing/util/audit/api/DefaultAuditUserApi.java
index 14ca318..7ced15e 100644
--- a/util/src/main/java/com/ning/billing/util/audit/api/DefaultAuditUserApi.java
+++ b/util/src/main/java/com/ning/billing/util/audit/api/DefaultAuditUserApi.java
@@ -23,12 +23,15 @@ import java.util.UUID;
 
 import javax.inject.Inject;
 
-import com.ning.billing.entitlement.api.user.SubscriptionBundle;
+import com.ning.billing.entitlement.api.timeline.BundleTimeline;
+import com.ning.billing.entitlement.api.timeline.SubscriptionTimeline;
+import com.ning.billing.entitlement.api.timeline.SubscriptionTimeline.ExistingEvent;
 import com.ning.billing.invoice.api.Invoice;
 import com.ning.billing.invoice.api.InvoiceItem;
 import com.ning.billing.invoice.api.InvoicePayment;
 import com.ning.billing.payment.api.Payment;
 import com.ning.billing.payment.api.Refund;
+import com.ning.billing.util.api.AuditLevel;
 import com.ning.billing.util.api.AuditUserApi;
 import com.ning.billing.util.audit.AuditLog;
 import com.ning.billing.util.audit.AuditLogsForBundles;
@@ -57,53 +60,61 @@ public class DefaultAuditUserApi implements AuditUserApi {
     }
 
     @Override
-    public AuditLogsForBundles getAuditLogsForBundles(final List<SubscriptionBundle> bundles) {
+    public AuditLogsForBundles getAuditLogsForBundles(final List<BundleTimeline> bundles, final AuditLevel auditLevel) {
         final Map<UUID, List<AuditLog>> bundlesAuditLogs = new HashMap<UUID, List<AuditLog>>();
-        for (final SubscriptionBundle bundle : bundles) {
-            bundlesAuditLogs.put(bundle.getId(), getAuditLogs(bundle.getId(), ObjectType.BUNDLE));
+        final Map<UUID, List<AuditLog>> subscriptionsAuditLogs = new HashMap<UUID, List<AuditLog>>();
+        final Map<UUID, List<AuditLog>> subscriptionEventsAuditLogs = new HashMap<UUID, List<AuditLog>>();
+        for (final BundleTimeline bundle : bundles) {
+            bundlesAuditLogs.put(bundle.getBundleId(), getAuditLogs(bundle.getBundleId(), ObjectType.BUNDLE, auditLevel));
+            for (final SubscriptionTimeline subscriptionTimeline : bundle.getSubscriptions()) {
+                subscriptionsAuditLogs.put(subscriptionTimeline.getId(), getAuditLogs(subscriptionTimeline.getId(), ObjectType.SUBSCRIPTION, auditLevel));
+                for (final ExistingEvent event : subscriptionTimeline.getExistingEvents()) {
+                    subscriptionEventsAuditLogs.put(event.getEventId(), getAuditLogs(event.getEventId(), ObjectType.SUBSCRIPTION_EVENT, auditLevel));
+                }
+            }
         }
 
-        return new DefaultAuditLogsForBundles(bundlesAuditLogs);
+        return new DefaultAuditLogsForBundles(bundlesAuditLogs, subscriptionsAuditLogs, subscriptionEventsAuditLogs);
     }
 
     @Override
-    public AuditLogsForInvoicePayments getAuditLogsForInvoicePayments(final List<InvoicePayment> invoicePayments) {
+    public AuditLogsForInvoicePayments getAuditLogsForInvoicePayments(final List<InvoicePayment> invoicePayments, final AuditLevel auditLevel) {
         final Map<UUID, List<AuditLog>> invoicePaymentsAuditLogs = new HashMap<UUID, List<AuditLog>>();
         for (final InvoicePayment invoicePayment : invoicePayments) {
-            invoicePaymentsAuditLogs.put(invoicePayment.getId(), getAuditLogs(invoicePayment.getId(), ObjectType.INVOICE_PAYMENT));
+            invoicePaymentsAuditLogs.put(invoicePayment.getId(), getAuditLogs(invoicePayment.getId(), ObjectType.INVOICE_PAYMENT, auditLevel));
         }
 
         return new DefaultAuditLogsForInvoicePayments(invoicePaymentsAuditLogs);
     }
 
     @Override
-    public AuditLogsForRefunds getAuditLogsForRefunds(final List<Refund> refunds) {
+    public AuditLogsForRefunds getAuditLogsForRefunds(final List<Refund> refunds, final AuditLevel auditLevel) {
         final Map<UUID, List<AuditLog>> refundsAuditLogs = new HashMap<UUID, List<AuditLog>>();
         for (final Refund refund : refunds) {
-            refundsAuditLogs.put(refund.getId(), getAuditLogs(refund.getId(), ObjectType.REFUND));
+            refundsAuditLogs.put(refund.getId(), getAuditLogs(refund.getId(), ObjectType.REFUND, auditLevel));
         }
 
         return new DefaultAuditLogsForRefunds(refundsAuditLogs);
     }
 
     @Override
-    public AuditLogsForPayments getAuditLogsForPayments(final List<Payment> payments) {
+    public AuditLogsForPayments getAuditLogsForPayments(final List<Payment> payments, final AuditLevel auditLevel) {
         final Map<UUID, List<AuditLog>> paymentsAuditLogs = new HashMap<UUID, List<AuditLog>>();
         for (final Payment payment : payments) {
-            paymentsAuditLogs.put(payment.getId(), getAuditLogs(payment.getId(), ObjectType.PAYMENT));
+            paymentsAuditLogs.put(payment.getId(), getAuditLogs(payment.getId(), ObjectType.PAYMENT, auditLevel));
         }
 
         return new DefaultAuditLogsForPayments(paymentsAuditLogs);
     }
 
     @Override
-    public AuditLogsForInvoices getAuditLogsForInvoices(final List<Invoice> invoices) {
+    public AuditLogsForInvoices getAuditLogsForInvoices(final List<Invoice> invoices, final AuditLevel auditLevel) {
         final Map<UUID, List<AuditLog>> invoiceAuditLogs = new HashMap<UUID, List<AuditLog>>();
         final Map<UUID, List<AuditLog>> invoiceItemsAuditLogs = new HashMap<UUID, List<AuditLog>>();
         for (final Invoice invoice : invoices) {
-            invoiceAuditLogs.put(invoice.getId(), getAuditLogs(invoice.getId(), ObjectType.INVOICE));
+            invoiceAuditLogs.put(invoice.getId(), getAuditLogs(invoice.getId(), ObjectType.INVOICE, auditLevel));
             for (final InvoiceItem invoiceItem : invoice.getInvoiceItems()) {
-                invoiceItemsAuditLogs.put(invoiceItem.getId(), getAuditLogs(invoiceItem.getId(), ObjectType.INVOICE_ITEM));
+                invoiceItemsAuditLogs.put(invoiceItem.getId(), getAuditLogs(invoiceItem.getId(), ObjectType.INVOICE_ITEM, auditLevel));
             }
         }
 
@@ -111,13 +122,18 @@ public class DefaultAuditUserApi implements AuditUserApi {
     }
 
     @Override
-    public List<AuditLog> getAuditLogs(final UUID objectId, final ObjectType objectType) {
+    public List<AuditLog> getAuditLogs(final UUID objectId, final ObjectType objectType, final AuditLevel auditLevel) {
+        // Optimization - bail early
+        if (AuditLevel.NONE.equals(auditLevel)) {
+            return ImmutableList.<AuditLog>of();
+        }
+
         final TableName tableName = getTableNameFromObjectType(objectType);
         if (tableName == null) {
             return ImmutableList.<AuditLog>of();
         }
 
-        return auditDao.getAuditLogsForId(tableName, objectId);
+        return auditDao.getAuditLogsForId(tableName, objectId, auditLevel);
     }
 
     private TableName getTableNameFromObjectType(final ObjectType objectType) {
diff --git a/util/src/main/java/com/ning/billing/util/audit/dao/AuditDao.java b/util/src/main/java/com/ning/billing/util/audit/dao/AuditDao.java
index 4244ddc..3f0e485 100644
--- a/util/src/main/java/com/ning/billing/util/audit/dao/AuditDao.java
+++ b/util/src/main/java/com/ning/billing/util/audit/dao/AuditDao.java
@@ -19,10 +19,11 @@ package com.ning.billing.util.audit.dao;
 import java.util.List;
 import java.util.UUID;
 
+import com.ning.billing.util.api.AuditLevel;
 import com.ning.billing.util.audit.AuditLog;
 import com.ning.billing.util.dao.TableName;
 
 public interface AuditDao {
 
-    public List<AuditLog> getAuditLogsForId(final TableName tableName, final UUID objectId);
+    public List<AuditLog> getAuditLogsForId(final TableName tableName, final UUID objectId, final AuditLevel auditLevel);
 }
diff --git a/util/src/main/java/com/ning/billing/util/audit/dao/DefaultAuditDao.java b/util/src/main/java/com/ning/billing/util/audit/dao/DefaultAuditDao.java
index 73f82ec..c70b99c 100644
--- a/util/src/main/java/com/ning/billing/util/audit/dao/DefaultAuditDao.java
+++ b/util/src/main/java/com/ning/billing/util/audit/dao/DefaultAuditDao.java
@@ -24,6 +24,8 @@ import javax.inject.Inject;
 
 import org.skife.jdbi.v2.IDBI;
 
+import com.ning.billing.util.ChangeType;
+import com.ning.billing.util.api.AuditLevel;
 import com.ning.billing.util.audit.AuditLog;
 import com.ning.billing.util.dao.AuditSqlDao;
 import com.ning.billing.util.dao.TableName;
@@ -40,25 +42,25 @@ public class DefaultAuditDao implements AuditDao {
     }
 
     @Override
-    public List<AuditLog> getAuditLogsForId(final TableName tableName, final UUID objectId) {
+    public List<AuditLog> getAuditLogsForId(final TableName tableName, final UUID objectId, final AuditLevel auditLevel) {
         if (tableName.hasHistoryTable()) {
-            return doGetAuditLogsViaHistoryForId(tableName, objectId);
+            return doGetAuditLogsViaHistoryForId(tableName, objectId, auditLevel);
         } else {
-            return doGetAuditLogsForId(tableName, objectId);
+            return doGetAuditLogsForId(tableName, objectId, auditLevel);
         }
     }
 
-    private List<AuditLog> doGetAuditLogsForId(final TableName tableName, final UUID objectId) {
+    private List<AuditLog> doGetAuditLogsForId(final TableName tableName, final UUID objectId, final AuditLevel auditLevel) {
         // Look at the table and gather all record_id for that objectId
         final Long recordId = auditSqlDao.getRecordIdForTable(tableName.getTableName().toLowerCase(), objectId.toString());
         if (recordId == null) {
             return ImmutableList.<AuditLog>of();
         } else {
-            return auditSqlDao.getAuditLogsForRecordId(tableName, recordId);
+            return getAuditLogsForRecordId(tableName, recordId, auditLevel);
         }
     }
 
-    private List<AuditLog> doGetAuditLogsViaHistoryForId(final TableName tableName, final UUID objectId) {
+    private List<AuditLog> doGetAuditLogsViaHistoryForId(final TableName tableName, final UUID objectId, final AuditLevel auditLevel) {
         final List<AuditLog> auditLogs = new ArrayList<AuditLog>();
 
         // Look at the history table and gather all the history_record_id for that objectId
@@ -68,10 +70,29 @@ public class DefaultAuditDao implements AuditDao {
             return auditLogs;
         } else {
             for (final Long recordId : recordIds) {
-                auditLogs.addAll(auditSqlDao.getAuditLogsForRecordId(tableName.getHistoryTableName(), recordId));
+                auditLogs.addAll(getAuditLogsForRecordId(tableName.getHistoryTableName(), recordId, auditLevel));
             }
 
             return auditLogs;
         }
     }
+
+    private List<AuditLog> getAuditLogsForRecordId(final TableName tableName, final Long recordId, final AuditLevel auditLevel) {
+        final List<AuditLog> allAuditLogs = auditSqlDao.getAuditLogsForRecordId(tableName, recordId);
+        if (AuditLevel.FULL.equals(auditLevel)) {
+            return allAuditLogs;
+        } else if (AuditLevel.MINIMAL.equals(auditLevel) && allAuditLogs.size() > 0) {
+            if (ChangeType.INSERT.equals(allAuditLogs.get(0).getChangeType())) {
+                return ImmutableList.<AuditLog>of(allAuditLogs.get(0));
+            } else {
+                // We may be coming here via the history code path - only a single mapped history record id
+                // will be for the initial INSERT
+                return ImmutableList.<AuditLog>of();
+            }
+        } else if (AuditLevel.NONE.equals(auditLevel)) {
+            return ImmutableList.<AuditLog>of();
+        } else {
+            return allAuditLogs;
+        }
+    }
 }
diff --git a/util/src/main/java/com/ning/billing/util/audit/DefaultAuditLogsForBundles.java b/util/src/main/java/com/ning/billing/util/audit/DefaultAuditLogsForBundles.java
index 4e35a2d..c47e44f 100644
--- a/util/src/main/java/com/ning/billing/util/audit/DefaultAuditLogsForBundles.java
+++ b/util/src/main/java/com/ning/billing/util/audit/DefaultAuditLogsForBundles.java
@@ -23,9 +23,15 @@ import java.util.UUID;
 public class DefaultAuditLogsForBundles implements AuditLogsForBundles {
 
     private final Map<UUID, List<AuditLog>> bundlesAuditLogs;
+    private final Map<UUID, List<AuditLog>> subscriptionsAuditLogs;
+    private final Map<UUID, List<AuditLog>> subscriptionEventsAuditLogs;
 
-    public DefaultAuditLogsForBundles(final Map<UUID, List<AuditLog>> bundlesAuditLogs) {
+    public DefaultAuditLogsForBundles(final Map<UUID, List<AuditLog>> bundlesAuditLogs,
+                                      final Map<UUID, List<AuditLog>> subscriptionsAuditLogs,
+                                      final Map<UUID, List<AuditLog>> subscriptionEventsAuditLogs) {
         this.bundlesAuditLogs = bundlesAuditLogs;
+        this.subscriptionsAuditLogs = subscriptionsAuditLogs;
+        this.subscriptionEventsAuditLogs = subscriptionEventsAuditLogs;
     }
 
     @Override
@@ -34,9 +40,13 @@ public class DefaultAuditLogsForBundles implements AuditLogsForBundles {
     }
 
     @Override
+    public Map<UUID, List<AuditLog>> getSubscriptionsAuditLogs() {
+        return subscriptionsAuditLogs;
+    }
+
+    @Override
     public Map<UUID, List<AuditLog>> getSubscriptionEventsAuditLogs() {
-        // TODO
-        return null;
+        return subscriptionEventsAuditLogs;
     }
 
     @Override
@@ -44,6 +54,8 @@ public class DefaultAuditLogsForBundles implements AuditLogsForBundles {
         final StringBuilder sb = new StringBuilder();
         sb.append("DefaultAuditLogsForBundles");
         sb.append("{bundlesAuditLogs=").append(bundlesAuditLogs);
+        sb.append(", subscriptionsAuditLogs=").append(subscriptionsAuditLogs);
+        sb.append(", subscriptionEventsAuditLogs=").append(subscriptionEventsAuditLogs);
         sb.append('}');
         return sb.toString();
     }
@@ -62,12 +74,21 @@ public class DefaultAuditLogsForBundles implements AuditLogsForBundles {
         if (bundlesAuditLogs != null ? !bundlesAuditLogs.equals(that.bundlesAuditLogs) : that.bundlesAuditLogs != null) {
             return false;
         }
+        if (subscriptionEventsAuditLogs != null ? !subscriptionEventsAuditLogs.equals(that.subscriptionEventsAuditLogs) : that.subscriptionEventsAuditLogs != null) {
+            return false;
+        }
+        if (subscriptionsAuditLogs != null ? !subscriptionsAuditLogs.equals(that.subscriptionsAuditLogs) : that.subscriptionsAuditLogs != null) {
+            return false;
+        }
 
         return true;
     }
 
     @Override
     public int hashCode() {
-        return bundlesAuditLogs != null ? bundlesAuditLogs.hashCode() : 0;
+        int result = bundlesAuditLogs != null ? bundlesAuditLogs.hashCode() : 0;
+        result = 31 * result + (subscriptionsAuditLogs != null ? subscriptionsAuditLogs.hashCode() : 0);
+        result = 31 * result + (subscriptionEventsAuditLogs != null ? subscriptionEventsAuditLogs.hashCode() : 0);
+        return result;
     }
 }
diff --git a/util/src/main/java/com/ning/billing/util/dao/TableName.java b/util/src/main/java/com/ning/billing/util/dao/TableName.java
index 7aec216..5bbf68c 100644
--- a/util/src/main/java/com/ning/billing/util/dao/TableName.java
+++ b/util/src/main/java/com/ning/billing/util/dao/TableName.java
@@ -36,7 +36,7 @@ public enum TableName {
     PAYMENT_METHOD_HISTORY("payment_method_history"),
     PAYMENT_METHODS("payment_methods", ObjectType.PAYMENT_METHOD, PAYMENT_METHOD_HISTORY),
     SUBSCRIPTIONS("subscriptions", ObjectType.SUBSCRIPTION),
-    SUBSCRIPTION_EVENTS("subscription_events"),
+    SUBSCRIPTION_EVENTS("subscription_events", ObjectType.SUBSCRIPTION_EVENT),
     REFUND_HISTORY("refund_history"),
     REFUNDS("refunds", ObjectType.REFUND, REFUND_HISTORY),
     TAG_DEFINITIONS("tag_definitions", ObjectType.TAG_DEFINITION),
diff --git a/util/src/main/resources/com/ning/billing/util/dao/AuditSqlDao.sql.stg b/util/src/main/resources/com/ning/billing/util/dao/AuditSqlDao.sql.stg
index c8d64bb..20cd42f 100644
--- a/util/src/main/resources/com/ning/billing/util/dao/AuditSqlDao.sql.stg
+++ b/util/src/main/resources/com/ning/billing/util/dao/AuditSqlDao.sql.stg
@@ -20,7 +20,8 @@ getAuditLogsForRecordId() ::= <<
   SELECT <fields()>
   FROM audit_log
   WHERE record_id = :recordId
-  AND table_name = :tableName;
+  AND table_name = :tableName
+  ORDER BY change_date ASC
 >>
 
 getRecordIdForTable(tableName) ::= <<
diff --git a/util/src/test/java/com/ning/billing/util/audit/api/TestDefaultAuditUserApi.java b/util/src/test/java/com/ning/billing/util/audit/api/TestDefaultAuditUserApi.java
index 9c58442..f4a79d1 100644
--- a/util/src/test/java/com/ning/billing/util/audit/api/TestDefaultAuditUserApi.java
+++ b/util/src/test/java/com/ning/billing/util/audit/api/TestDefaultAuditUserApi.java
@@ -26,12 +26,13 @@ import org.testng.Assert;
 import org.testng.annotations.BeforeTest;
 import org.testng.annotations.Test;
 
-import com.ning.billing.entitlement.api.user.SubscriptionBundle;
+import com.ning.billing.entitlement.api.timeline.BundleTimeline;
 import com.ning.billing.invoice.api.Invoice;
 import com.ning.billing.invoice.api.InvoiceItem;
 import com.ning.billing.invoice.api.InvoicePayment;
 import com.ning.billing.payment.api.Payment;
 import com.ning.billing.payment.api.Refund;
+import com.ning.billing.util.api.AuditLevel;
 import com.ning.billing.util.api.AuditUserApi;
 import com.ning.billing.util.audit.AuditLog;
 import com.ning.billing.util.audit.AuditLogsForBundles;
@@ -70,36 +71,47 @@ public class TestDefaultAuditUserApi extends AuditLogsTestBase {
 
     @Test(groups = "fast")
     public void testForBundles() throws Exception {
-        final List<SubscriptionBundle> bundles = createMocks(SubscriptionBundle.class);
-
-        // TODO check SubscriptionEventsAuditLogs
+        final List<BundleTimeline> bundles = new ArrayList<BundleTimeline>();
+        for (final UUID objectId : objectIds) {
+            final BundleTimeline entity = Mockito.mock(BundleTimeline.class);
+            Mockito.when(entity.getBundleId()).thenReturn(objectId);
+            bundles.add(entity);
+        }
 
-        final AuditLogsForBundles auditLogsForBundles = auditUserApi.getAuditLogsForBundles(bundles);
-        verifyAuditLogs(auditLogsForBundles.getBundlesAuditLogs());
+        for (final AuditLevel level : AuditLevel.values()) {
+            final AuditLogsForBundles auditLogsForBundles = auditUserApi.getAuditLogsForBundles(bundles, level);
+            verifyAuditLogs(auditLogsForBundles.getBundlesAuditLogs(), level);
+        }
     }
 
     @Test(groups = "fast")
     public void testForInvoicePayments() throws Exception {
         final List<InvoicePayment> invoicePayments = createMocks(InvoicePayment.class);
 
-        final AuditLogsForInvoicePayments auditLogsForInvoicePayments = auditUserApi.getAuditLogsForInvoicePayments(invoicePayments);
-        verifyAuditLogs(auditLogsForInvoicePayments.getInvoicePaymentsAuditLogs());
+        for (final AuditLevel level : AuditLevel.values()) {
+            final AuditLogsForInvoicePayments auditLogsForInvoicePayments = auditUserApi.getAuditLogsForInvoicePayments(invoicePayments, level);
+            verifyAuditLogs(auditLogsForInvoicePayments.getInvoicePaymentsAuditLogs(), level);
+        }
     }
 
     @Test(groups = "fast")
     public void testForRefunds() throws Exception {
         final List<Refund> refunds = createMocks(Refund.class);
 
-        final AuditLogsForRefunds auditLogsForRefunds = auditUserApi.getAuditLogsForRefunds(refunds);
-        verifyAuditLogs(auditLogsForRefunds.getRefundsAuditLogs());
+        for (final AuditLevel level : AuditLevel.values()) {
+            final AuditLogsForRefunds auditLogsForRefunds = auditUserApi.getAuditLogsForRefunds(refunds, level);
+            verifyAuditLogs(auditLogsForRefunds.getRefundsAuditLogs(), level);
+        }
     }
 
     @Test(groups = "fast")
     public void testForPayments() throws Exception {
         final List<Payment> payments = createMocks(Payment.class);
 
-        final AuditLogsForPayments auditLogsForPayments = auditUserApi.getAuditLogsForPayments(payments);
-        verifyAuditLogs(auditLogsForPayments.getPaymentsAuditLogs());
+        for (final AuditLevel level : AuditLevel.values()) {
+            final AuditLogsForPayments auditLogsForPayments = auditUserApi.getAuditLogsForPayments(payments, level);
+            verifyAuditLogs(auditLogsForPayments.getPaymentsAuditLogs(), level);
+        }
     }
 
     @Test(groups = "fast")
@@ -110,24 +122,46 @@ public class TestDefaultAuditUserApi extends AuditLogsTestBase {
             Mockito.when(invoice.getInvoiceItems()).thenReturn(invoiceItems);
         }
 
-        final AuditLogsForInvoices auditLogsForInvoices = auditUserApi.getAuditLogsForInvoices(invoices);
-        verifyAuditLogs(auditLogsForInvoices.getInvoiceAuditLogs());
-        verifyAuditLogs(auditLogsForInvoices.getInvoiceItemsAuditLogs());
+        for (final AuditLevel level : AuditLevel.values()) {
+            final AuditLogsForInvoices auditLogsForInvoices = auditUserApi.getAuditLogsForInvoices(invoices, level);
+            verifyAuditLogs(auditLogsForInvoices.getInvoiceAuditLogs(), level);
+            verifyAuditLogs(auditLogsForInvoices.getInvoiceItemsAuditLogs(), level);
+        }
     }
 
     @Test(groups = "fast")
     public void testForObject() throws Exception {
         for (final ObjectType objectType : ObjectType.values()) {
             for (final UUID objectId : objectIds) {
-                Assert.assertEquals(auditUserApi.getAuditLogs(objectId, objectType), auditLogs);
+                for (final AuditLevel level : AuditLevel.values()) {
+                    if (AuditLevel.NONE.equals(level)) {
+                        Assert.assertEquals(auditUserApi.getAuditLogs(objectId, objectType, level).size(), 0);
+                    } else if (AuditLevel.MINIMAL.equals(level)) {
+                        Assert.assertEquals(auditUserApi.getAuditLogs(objectId, objectType, level), ImmutableList.<AuditLog>of(auditLogs.get(0)));
+                    } else {
+                        Assert.assertEquals(auditUserApi.getAuditLogs(objectId, objectType, level), auditLogs);
+                    }
+                }
             }
         }
     }
 
-    private void verifyAuditLogs(final Map<UUID, List<AuditLog>> objectsAuditLogs) {
+    private void verifyAuditLogs(final Map<UUID, List<AuditLog>> objectsAuditLogs, final AuditLevel level) {
         Assert.assertEquals(objectsAuditLogs.size(), objectIds.size());
-        for (final UUID objectId : objectIds) {
-            Assert.assertEquals(objectsAuditLogs.get(objectId), auditLogs);
+
+        if (AuditLevel.NONE.equals(level)) {
+            for (final UUID objectId : objectIds) {
+                Assert.assertEquals(objectsAuditLogs.get(objectId).size(), 0);
+            }
+        } else if (AuditLevel.MINIMAL.equals(level)) {
+            for (final UUID objectId : objectIds) {
+                Assert.assertEquals(objectsAuditLogs.get(objectId).size(), 1);
+                Assert.assertEquals(objectsAuditLogs.get(objectId).get(0), auditLogs.get(0));
+            }
+        } else {
+            for (final UUID objectId : objectIds) {
+                Assert.assertEquals(objectsAuditLogs.get(objectId), auditLogs);
+            }
         }
     }
 
diff --git a/util/src/test/java/com/ning/billing/util/audit/dao/MockAuditDao.java b/util/src/test/java/com/ning/billing/util/audit/dao/MockAuditDao.java
index 7af195c..daee3e8 100644
--- a/util/src/test/java/com/ning/billing/util/audit/dao/MockAuditDao.java
+++ b/util/src/test/java/com/ning/billing/util/audit/dao/MockAuditDao.java
@@ -22,6 +22,7 @@ import java.util.List;
 import java.util.Map;
 import java.util.UUID;
 
+import com.ning.billing.util.api.AuditLevel;
 import com.ning.billing.util.audit.AuditLog;
 import com.ning.billing.util.dao.TableName;
 
@@ -49,13 +50,22 @@ public class MockAuditDao implements AuditDao {
     }
 
     @Override
-    public List<AuditLog> getAuditLogsForId(final TableName tableName, final UUID objectId) {
+    public List<AuditLog> getAuditLogsForId(final TableName tableName, final UUID objectId, final AuditLevel auditLevel) {
         final Map<UUID, List<AuditLog>> auditLogsForTableName = auditLogsForTables.get(tableName);
         if (auditLogsForTableName == null) {
             return ImmutableList.<AuditLog>of();
         }
 
         final List<AuditLog> auditLogsForObjectId = auditLogsForTableName.get(objectId);
-        return Objects.firstNonNull(auditLogsForObjectId, ImmutableList.<AuditLog>of());
+        final List<AuditLog> allAuditLogs = Objects.firstNonNull(auditLogsForObjectId, ImmutableList.<AuditLog>of());
+        if (AuditLevel.FULL.equals(auditLevel)) {
+            return allAuditLogs;
+        } else if (AuditLevel.MINIMAL.equals(auditLevel) && allAuditLogs.size() > 0) {
+            return ImmutableList.<AuditLog>of(allAuditLogs.get(0));
+        } else if (AuditLevel.NONE.equals(auditLevel)) {
+            return ImmutableList.<AuditLog>of();
+        } else {
+            return allAuditLogs;
+        }
     }
 }
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 e4abf3c..220e564 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
@@ -31,6 +31,7 @@ import org.testng.annotations.Test;
 
 import com.ning.billing.util.ChangeType;
 import com.ning.billing.util.UtilTestSuiteWithEmbeddedDB;
+import com.ning.billing.util.api.AuditLevel;
 import com.ning.billing.util.api.TagApiException;
 import com.ning.billing.util.api.TagDefinitionApiException;
 import com.ning.billing.util.audit.AuditLog;
@@ -95,16 +96,20 @@ public class TestDefaultAuditDao extends UtilTestSuiteWithEmbeddedDB {
         final String tagHistoryString = (String) handle.select("select id from tag_history limit 1").get(0).get("id");
         handle.close();
 
-        final List<AuditLog> auditLogs = auditDao.getAuditLogsForId(TableName.TAG_HISTORY, UUID.fromString(tagHistoryString));
-        verifyAuditLogsForTag(auditLogs);
+        for (final AuditLevel level : AuditLevel.values()) {
+            final List<AuditLog> auditLogs = auditDao.getAuditLogsForId(TableName.TAG_HISTORY, UUID.fromString(tagHistoryString), level);
+            verifyAuditLogsForTag(auditLogs, level);
+        }
     }
 
     @Test(groups = "slow")
     public void testRetrieveAuditsViaHistory() throws Exception {
         addTag();
 
-        final List<AuditLog> auditLogs = auditDao.getAuditLogsForId(TableName.TAG, tagId);
-        verifyAuditLogsForTag(auditLogs);
+        for (final AuditLevel level : AuditLevel.values()) {
+            final List<AuditLog> auditLogs = auditDao.getAuditLogsForId(TableName.TAG, tagId, level);
+            verifyAuditLogsForTag(auditLogs, level);
+        }
     }
 
     private void addTag() throws TagDefinitionApiException, TagApiException {
@@ -124,7 +129,12 @@ public class TestDefaultAuditDao extends UtilTestSuiteWithEmbeddedDB {
         tagId = tag.getId();
     }
 
-    private void verifyAuditLogsForTag(final List<AuditLog> auditLogs) {
+    private void verifyAuditLogsForTag(final List<AuditLog> auditLogs, final AuditLevel level) {
+        if (AuditLevel.NONE.equals(level)) {
+            Assert.assertEquals(auditLogs.size(), 0);
+            return;
+        }
+
         Assert.assertEquals(auditLogs.size(), 1);
         Assert.assertEquals(auditLogs.get(0).getUserToken(), context.getUserToken().toString());
         Assert.assertEquals(auditLogs.get(0).getChangeType(), ChangeType.INSERT);
diff --git a/util/src/test/java/com/ning/billing/util/audit/TestDefaultAuditLogsForBundles.java b/util/src/test/java/com/ning/billing/util/audit/TestDefaultAuditLogsForBundles.java
index 5ba4a40..1b84c96 100644
--- a/util/src/test/java/com/ning/billing/util/audit/TestDefaultAuditLogsForBundles.java
+++ b/util/src/test/java/com/ning/billing/util/audit/TestDefaultAuditLogsForBundles.java
@@ -28,7 +28,22 @@ public class TestDefaultAuditLogsForBundles extends AuditLogsTestBase {
     @Test(groups = "fast")
     public void testEquals() throws Exception {
         final Map<UUID, List<AuditLog>> bundlesAuditLogs = createAuditLogsAssociation();
-        Assert.assertEquals(new DefaultAuditLogsForBundles(bundlesAuditLogs).getBundlesAuditLogs(), bundlesAuditLogs);
-        Assert.assertNotEquals(new DefaultAuditLogsForBundles(createAuditLogsAssociation()).getBundlesAuditLogs(), bundlesAuditLogs);
+        final Map<UUID, List<AuditLog>> subscriptionsAuditLogs = createAuditLogsAssociation();
+        final Map<UUID, List<AuditLog>> subscriptionEventsAuditLogs = createAuditLogsAssociation();
+        Assert.assertEquals(new DefaultAuditLogsForBundles(bundlesAuditLogs, subscriptionsAuditLogs, subscriptionEventsAuditLogs).getBundlesAuditLogs(), bundlesAuditLogs);
+        Assert.assertEquals(new DefaultAuditLogsForBundles(bundlesAuditLogs, subscriptionsAuditLogs, subscriptionEventsAuditLogs).getSubscriptionsAuditLogs(), subscriptionsAuditLogs);
+        Assert.assertEquals(new DefaultAuditLogsForBundles(bundlesAuditLogs, subscriptionsAuditLogs, subscriptionEventsAuditLogs).getSubscriptionEventsAuditLogs(), subscriptionEventsAuditLogs);
+
+        Assert.assertNotEquals(new DefaultAuditLogsForBundles(createAuditLogsAssociation(), subscriptionsAuditLogs, subscriptionEventsAuditLogs).getBundlesAuditLogs(), bundlesAuditLogs);
+        Assert.assertEquals(new DefaultAuditLogsForBundles(createAuditLogsAssociation(), subscriptionsAuditLogs, subscriptionEventsAuditLogs).getSubscriptionsAuditLogs(), subscriptionsAuditLogs);
+        Assert.assertEquals(new DefaultAuditLogsForBundles(createAuditLogsAssociation(), subscriptionsAuditLogs, subscriptionEventsAuditLogs).getSubscriptionEventsAuditLogs(), subscriptionEventsAuditLogs);
+
+        Assert.assertEquals(new DefaultAuditLogsForBundles(bundlesAuditLogs, createAuditLogsAssociation(), subscriptionEventsAuditLogs).getBundlesAuditLogs(), bundlesAuditLogs);
+        Assert.assertNotEquals(new DefaultAuditLogsForBundles(bundlesAuditLogs, createAuditLogsAssociation(), subscriptionEventsAuditLogs).getSubscriptionsAuditLogs(), subscriptionsAuditLogs);
+        Assert.assertEquals(new DefaultAuditLogsForBundles(bundlesAuditLogs, createAuditLogsAssociation(), subscriptionEventsAuditLogs).getSubscriptionEventsAuditLogs(), subscriptionEventsAuditLogs);
+
+        Assert.assertEquals(new DefaultAuditLogsForBundles(bundlesAuditLogs, subscriptionsAuditLogs, createAuditLogsAssociation()).getBundlesAuditLogs(), bundlesAuditLogs);
+        Assert.assertEquals(new DefaultAuditLogsForBundles(bundlesAuditLogs, subscriptionsAuditLogs, createAuditLogsAssociation()).getSubscriptionsAuditLogs(), subscriptionsAuditLogs);
+        Assert.assertNotEquals(new DefaultAuditLogsForBundles(bundlesAuditLogs, subscriptionsAuditLogs, createAuditLogsAssociation()).getSubscriptionEventsAuditLogs(), subscriptionEventsAuditLogs);
     }
 }